セーターの備忘録

大学編入やIT関連の内容を記していく予定です

学内LT会で発表してきました

岩手県立大学で行われたLT会に参加し,自分も発表してきました. このLT会は主に学内の学生向けに行われているLT会で,月に1回程度行われています.

iwate-pu-lt.github.io

今回,自分は先日のブログでも書いた「Spotify APIを使って好きなアーティストの曲を分析する」について発表してきました.

発表資料

発表時の様子

感想

人前で発表するのは久々だったので緊張しました……ただ,発表して人から意見をもらうことで勉強になりました.他の人のLTを聞いてる中では,GPGPU入門の話やGitLabを研究室に導入する話あたりが興味深かったです.

Spotify APIを使って好きなアーティストの曲を分析する

普段から利用しているSpotifyAPIがあり,また全ての曲に様々な情報が付与されていることを知り,せっかくなので好きなアーティスト (TrySail) の分析をしてみることにしました.

目次

概要

Spotifyは定額制の音楽ストリーミングサービスです.登録されている曲にはそれぞれ多くの情報が付与されており,Spotify APIを使うことで情報を取得することができます.
他の方が行っている分析を見ると,多くがSpotiyの人気曲を見ることができるSpotify ChartsからCSVをダウンロードして行っていましたが,せっかくなので自分の好きなアーティストの分析を行うことにしました.

今回はTrySailに関する分析を行いました.TrySail麻倉ももさん,雨宮天さん,夏川椎菜さんの3人で構成されている声優ユニットで,ユニットの活動の他にそれぞれソロ活動でも多くの曲を提供されています. TrySailと3人それぞれのソロの曲を分析することで,それぞれの特徴やユニットとソロでの違いについて調査してみました.

手順

API keyの取得

API keyはSpotify for Developersから発行します.ページ内で事前に登録してあるSpotifyアカウントを用いてログインした上でDASHBOARDに行くと,CREATE A CLIENT IDというボタンがあるので,ここで必要な情報を入力することでOAuth2認証に必要となるCliend IDとClient Secretを取得することができます.

Spotipyのインストール

PythonSpotify APIの操作をできるようにするため,Python用ライブラリのSpotipyをインストールします.

$ pip install spotipy

アーティストの曲情報を取得

まず,下のような形でClient IDとClient Secretを記述し,Spotifyから情報を受け取れるようにします.

import pandas as pd
import spotipy
from spotipy.oauth2 import SpotifyClientCredentials
import json
import matplotlib.pyplot as plt
import seaborn as sns
sns.set()

client_id = 'xxxxxxxxxx'
client_secret = 'xxxxxxxxxx'

client_credentials_manager = spotipy.oauth2.SpotifyClientCredentials(client_id, client_secret)
spotify = spotipy.Spotify(client_credentials_manager=client_credentials_manager)

次に,任意のアーティストから曲情報を取得します.
まず# search artist and song idで任意のアーティストを検索し,そのtrack情報を取得します.次に取得した情報の中にある各曲が持つidを基に# get song informationで曲情報を取得します.# drop unnecessary informationでは後で分析しやすいように必要のない情報を削除しています.

# search artist and song id
search = spotify.search("[Artist name]", limit=50, offset=0, type='track', market=None)
song = pd.DataFrame.from_dict(search["tracks"]["items"])
song_name = pd.DataFrame(song["name"])
song = pd.DataFrame(song["id"])

# get song information
song_info = pd.DataFrame()
for url in song["id"]:
    df = pd.DataFrame.from_dict(spotify.audio_features(url))
    song_info = song_info.append(df)

# drop unnecessary information 
song_info = song_info.reset_index(drop=True)
song_info_all = pd.concat([song_name, song_info], axis=1)
song_info = song_info.drop(columns=["analysis_url","id","track_href","type","uri"])

Analysis

取得できる情報

各曲には,以下のような情報が付与されています(上で削除したidやurlなどを除く).今回はこれらの情報について分析を行いました.

KEY VALUE DESCRIPTION
acousticness 音響的かどうかの信頼度を0.0~1.0で表す.
danceability 踊りやすさに対する適合度を0.0~1.0で表す.
duration_ms 曲の長さ.
energy 1.0に近いほどエネルギッシュな曲であり,速く・大きく・騒々しく感じる.
instrumentalness 1.0に近いほどボーカルコンテンツが含まれていない可能性が高い.
key 12個の調性 (C, Db, D, ..., B) を0~11に表したもの.
liveness 曲のライブっぽさ.1に近いほどライブ音源の可能性がある.
loudness デジベル (dB).基本的に-60~0dBの範囲.
mode 長調なら1,単調なら0で表す.
speechiness ボーカルの話している感を表す.0.66以上なら話している感が強く,0.33~0.66なららっミュージックを含む会話と音楽の間,0.33未満なら音楽感が強い.
tempo BPM
time_signature 推定拍子
valence 感情軸の一つ.1.0に近いほど幸せ・陽気・幸福感などポジティブに聞こえ,0に近いほど悲しい・落ち込んでいる・怒っているなどネガティブに聞こえる.

取得した曲

上記の手法で曲の取得を行いましたが,上手く全ての曲を取得することができませんでした.なんでだ…… 今回取得・分析した曲は以下の通りです.特に雨宮天さんに関しては曲の被りが入ってしまったほか,本人名義ではなく声優としてのキャラ名義の曲が多くなってしまいました.
また,TrySail麻倉もも夏川椎菜さんの曲は英語またはローマ字に変換されて管理されていた一方,雨宮さんの曲は日本語で管理されていました.
麻倉さんのエイムや雨宮さんの曲から予想すると,本人名義ではなく声優のキャラとして歌っている曲は日本語で管理されている,もしくは本人名義の曲は英語・ローマ字で管理されているような気がします.曲提供元のレーベルなんかも関係しているのでしょうか……?

Num. TrySail Shiina Natsukawa Momo Asakura Sora Amamiya
0 Adrenaline!!! gravity - Album Mix エイム 最高速 Fall in Love
1 High Free Spilits Labli-Lubla Koino Prelude 奏(かなで)
2 Azure Cheer Me Cheer You Fanfare!! Da-Da-Dash!
3 Senpai Daisy Days - Album Mix Travely Time 最高速 Fall in Love - ミーアver.
4 Original Parade Tokubetsu Ichiban!! 最高速Fall in Love
5 Kakawari Yellow Flag Hanani Akai Ito My Sweet Feelings
6 Truth. Sutetekureba Run for You キスミーだぁりん▽
7 BraveSail Kimitoglide Pumpkin Meat Pie My Sweet Feelings
8 Tail Wind Naimonobakari No Distance Da-Da-Dash!
9 Coding Shimaebaii Colorful 最高速 Fall in Love - I strumental
10 Wanted Girl Fuwari, Korori, Karan, Koron Ashitawa Kimito キスミーだぁりん▽
11 Try Again First Plot Zuttokimino kotogasukinandesu. キスミーだぁりん▽
12 Chip Log Grapefruit Moon - Album Mix Hoshizorao Omoeba キスミーだぁりん▽ - Instrumental
13 Disco Good Job! Da-Da-Dash! - Instrumental
14 Bang!Bang!Banzai!!! 奏(かなで) - TV size ver.
15 Make Me Happy? 奏(かなで) - Instrumental
16 Bokurano Symphony Skyreach (Originally Performed by 雨宮天アカメが斬る!...
17 Take a Step Forward
18 Sunset Kung Fu
19 Journey
20 Believe
21 Mirai Curation
22 Sampomichi
23 Matane.
24 High Free Spirits (Originally Performed by Try...)

相関分析

まず,ピアソンの相関係数を用いてそれぞれ相関分析を行いました.

f:id:resweater:20190712105341p:plain
Trysail
f:id:resweater:20190712105406p:plain
3人それぞれの分析
ソロの分析では,麻倉さんと雨宮さんはいずれもすべての曲の拍子が同じだったため,time_signatureは空白になっています. 結果を比較すると,強弱の差はありますがユニット・ソロ問わず似た傾向が見受けられました.例として,

正の相関

  • danceability × valence
  • acousticness × instrumentalness
  • energy × loudness

負の相関

  • danceability × tempo
  • danceability × speechiness
  • acousticness × energy

などが挙げられます.エネルギッシュさと力強さなど,言われればその通りだなというような関係が正しく示されていることが確認できました.
また,TrySailのユニットとしての分析結果を見ると,強い相関が表れている部分が左上に偏っていることが分かります.

ヒストグラム

次に,ヒストグラムでそれぞれの分布を見てみました.

f:id:resweater:20190712124545p:plain
Trysailヒストグラム
f:id:resweater:20190712134441p:plain
3人それぞれのヒストグラム

結果として,それぞれ個性の出る結果となりました.
まずTrySailの結果を見ると,先ほど負の相関が確認できたacousticnessが0に近いものが多く,energyが1に近いものが多いという結果が見られました.また,loudnessは0に近いものが多くなっています.このことから,TrySailとしての曲にはアコースティック感が弱く,にぎやかでエネルギッシュな曲が多いと言えます.また,valenceは幅広く分布しており,様々な感情的印象を与える曲があるということが言えます.

次にソロの結果を見ると,3人ともTrySailと同様acousticnessが0に近いものが多く,energyが1に近いものが多く,Loudnessは-5より大きいものが多いという傾向が見られました.
個別で見ると夏川さんは独自性が強く,実際にはInstrumentalの曲は存在しませんが,instrumentalnessでは幅広く分布しており,歌としてよりも音楽としての傾向が強い曲も多いのではないかと考えられます.また,dancebilitylivenessは高いものが多く,tempoもBPM125~200前後と比較的早いことから,ライブ向きのノリやすい曲が多いのではないかと推測できます. さらに,valenceは0.6前後に集中して分布しており,感情軸で見たとき中性的な曲が多いと推測できます.
麻倉さんや雨宮さんはspeechinessが非常に小さい範囲に分布しており,喋りっぽさが非常に小さい曲が多いことが分かります.また,valenceは広く分布しており,様々な感情的印象を与える曲があることがわかります.

各曲のvalenceの分析

それぞれの曲についても分析を行いました.ここでは,valenceの結果について記載します.

f:id:resweater:20190712141005p:plain
TrySailの曲のvalence
f:id:resweater:20190712141052p:plain
夏川椎菜さんの曲のvalence
f:id:resweater:20190712141123p:plain
麻倉ももさんの曲のvalence
f:id:resweater:20190712141145p:plain
雨宮天さんの曲のvalence

曲ごと見てみましたが,こういう曲がvalence値高いみたいな傾向を見つけることはできませんでした……ただ,やはり夏川さんはユニットの時や他の二人と比べて値が低いネガティブな曲が無いようです.どうやってvalence値を決めているのか気になる……

上記以外の分析結果

ここに載せた以外に大きく見られた特徴として,以下のようなことが分かりました.

  • TrySailの「またね。」はacousticnessが0.528と高い.
  • TrySailの「Truth.」はlivenessが0.8000と高い.
  • 夏川さんのステテクレバーはlivenessが0.87と高い.
  • 夏川さんのラブリリブラ・ナイモノバカリ・シマエバイイはinstrumentalnessが0.6以上で高い.

まとめ

分析の結果をまとめると,以下のことが言えます.

  • TrySailはユニット・ソロ問わずアコースティックが弱く,エネルギッシュな曲が多い.
  • 夏川椎菜さんの曲は他の二人やユニットの曲に対して比較的独自性が強く,ライブ向きの曲が多い.

ユニットとソロを比較した際,それぞれ傾向や特徴が出るのかと思っていましたが,予想に反して2人はユニット時と近い傾向という結果になりました.
ただ,これはあくまでSpotifyが用意したデータでの評価であり,実際聞いていると麻倉ももさんと雨宮天さんも大きく異なる曲を持っているように感じるので,評価指標や評価方法によって結果が変わることが予想されます.
さらに,今回取得できなかった曲が多くあったほか,雨宮天さんだけ声優としてのキャラ名義の曲が多くなってしまったなど,正確な比較検証ができたとは言いにくい結果であったため,そのあたりも改善できれば良かったかなと思います.

プログラム・分析詳細

今回のプログラム及び細かい分析データはGitHubに記載しています.

github.com

参考文献

GitHubの使い方メモ -レポジトリ作成やチーム開発のときの手順-

GitやGitHubは普段から利用していますが,特に普段あまり使わないbranch操作などチーム開発をするときの手順について,忘れがちなので記しておくことにしました.

目次

レポジトリ作成~masterへのpush

主に一人で作業を行うときは,branch切り替えを行うことは少ないかと思います.なので,最低限レポジトリ作成からmasterへのpushができれば十分だと思います.

レポジトリ作成~初回push手順

  1. GitHubのページで 'Repositories' → 'New' からレポジトリ作成
  2. 作成時に表示されるRepository URLをコピー
  3. 以下のコマンドを実行する
$ cd {work repository}
$ git init
$ git add {file}
$ git commit -m '{comment}'
$ git remote add origin {Repository URL}
$ git push -u origin master

ここまででGitHubの作成したレポジトリを更新すればpushした内容が反映されているはずです.

2回目以降のcommit手順

2回目以降commitする場合は,

$ git add {file}
$ git commit -m '{comment}'
$ git push -u origin master

だけで大丈夫です.また,

$ git add --all

でaddすると,まだ更新が反映されていないファイルが全てcommitされます.ただし,レポジトリ内に反映したくないファイル(データセット,パスワードファイルなど)があるとそれらも反映されてしまうので気をつけてください.

チーム開発を行うときの手順

チーム開発を行う場合,レポジトリをcloneした上でbranchを切り替えて作業したりする必要があります.mergeの辺りちょっと理解が不十分なところもありますが現状は以下のように行っています.

開発開始からの主な流れ

以下の手順を行うことで,自分の作業環境を構築し,開発を行っていきます.

  1. 代表者がレポジトリを作成
  2. 他の作業者は,代表者が作成したGitHubのレポジトリ上の 'fork' ボタンからレポジトリをfork
  3. forkしたレポジトリ上の 'clone' ボタンからURLをコピーし,作業を行うディレクトリで$ git clone {clone URL}を実行
  4. $ git remote add {remote name} {Git URL of fork destination}でfork元を自分のレポジトリに登録
  5. 下に記す手順でbranchを作成,切り替え
  6. 作業branch上でcommitしつつ,下に記すpull, mergeを行った上で必要に応じてGitHubサイトのレポジトリ内からmaster branchにPull Requestを送る
  7. 管理者はPull Requestを承認することでmaster branchに変更を反映
  8. 作業中は適宜masterの更新に合わせてmerge

branchの作成と切り替え

「開発開始からの主な流れ」の5.に記したbranchの作成は以下のコマンドで行います.

$ git branch -a
$ git checkout master
$ git checkout -b {branch name to make}
$ git branch -a
$ git push -u origin {branch name}

$ git branch -aで今あるbranchを確認しています.checkoutはbranchの移動コマンドであり,オプションで-bをつけることでbranchの作成コマンドになります.

git pull, merge

開発中やmaster branchにPull Requestを送るときは,以下のコマンドで最新のmaster branchの内容を作業中のbranchにmergeします.

$ git checkout master
$ git pull
$ git checkout {branch name}
$ git merge master
$ git push origin {branch name}

まとめ

現在は記したような形でGitHubを利用しています.間違いや変更があれば気が向いたときに修正します……

参考

チーム開発 GitHubの使い方 - Qiita

データサイエンティスト・機械学習エンジニア志望で就活した20卒の話

自分はデータサイエンティスト・機械学習エンジニア志望で就活を行っていました.多くの企業の方と面談・面接をさせていただき,その中で見えてきた今のAI分野での就活などについて自分なりにまとめてみました.

簡単な自己紹介

自分は地方の大学院で機械学習分野の研究をしている修士学生です.Kaggleや小規模なハッカソンには何回か参加したことがありますが,特別スキルが高いわけでもないです.なので,Kaggleつよつよマンとかトップカンファレンスに論文出してますみたいな人は参考にならないと思います.というかそのレベルの人は就活しなくても声かかるんじゃないですかね(適当).

AI分野で就活するにあたっての企業の見方

最近はよくAI人材が~とか言われてたりしますが,実際AI分野で働きたいと言っても非常に曖昧なので,自分の中でざっくり分けて考えてみました.

データサイエンティストか機械学習エンジニアか

データサイエンティストとして働くか機械学習エンジニアとして働くかによって,仕事内容が大きく変わってきます.2つの違いについては色々言われてたりしますが,自分の場合は

・データサイエンティスト:アナリストの発展版.データの分析と提案など幅広く.
・機械学習エンジニア:エンジニアの発展版.データの処理や分析について深く.

みたいなイメージで分類しました.TJOさんの考え方を参考にしています*1.あとはshakezoさんの記事なんかも参考になるかと思います*2.まず自分がどちらよりで働きたいかによって選ぶ企業も変わってくると思いますが,企業によって言葉の意味合いが違っていたので面談などで確認するといいかと思います.

IT企業かそれ以外か

IT企業以外でもデータサイエンティストや機械学習エンジニアを求めている企業が多いようです.例としてコンサルティング系やメーカー系などが挙げられるかと思います.自分も何社かIT企業以外を見ましたが,所属する業界などによって雰囲気が違ったりするのかなという印象を持ちました.

事業会社かベンダーか

事業会社で働くかベンダーで働くかによって,仕事で触れるデータが変わってきます.
事業会社で働く場合,その企業が開発しているシステムやサービスから得られるデータを用いて分析を行うことがメインになるため,企業としても事業分野のドメイン知識を持っており,特定の分野により詳しくなれるかと思います.ただし,触れることのできるデータや分野はある程度限られます.一方,ベンダーの場合は様々な業界・分野のデータを扱うため,幅広いデータに触れることができます.ただし,企業として特定の分野に特化しているわけではないので,1つの案件ごとに見た場合,事業会社と比べると弱いという課題があるかと思います.
個人的には,しっかりとした技術力のあるエンジニアを目指すのであれば事業会社の方がいいのかなと思います.

いつ就活するか

最近は就活の時期について色々ニュースになってたりしますが,ほかの業界と比べるとIT業界はちょっと特殊な印象を持ちました.IT企業の場合,早いところで10月頃には面接が始まっており,5月には採用が終わっている企業もありました.一方,IT業界以外(メーカー系とか)だと3月とか4月頃に面接を始めた企業が多い印象を持ちました.

就活でやったこと

逆求人系のサービスをフル活用した

サポーターズさん,キャリアセレクトさん,逆求人ナビさんには逆求人イベントなどで大変お世話になりました.また,サポーターズさんとキャリアセレクトさんでは,担当の人と面談をした上でオススメの複数の企業を紹介していただき,その中で関心を持った企業との面談や面接をセッティングしていただきました.それ以外にもイベント参加時の交通費支援など,地方学生の強い味方でした.というかこのサービスがなかったらお金的な都合で就活成り立たなかった……

インターンシップに参加した

就活を始める前の夏,逆求人系のサービスや魔法のスプレッドシート*3などを通していくつかのインターンシップに参加しました.実際に参加した企業や選考過程でお会いした企業とはその後の就活でも何かと縁があったりしたので,余裕があれば参加するといいかと思います.
ちなみにデータサイエンスインターンシップに参加した時の記事もあるのでぜひ.楽しかったです(小並).

resweater.hatenablog.com

いろんな企業の方と面談した

上記逆求人系のサービスを介して,いろんな企業の方と面談しました.就活の時ほど多くの企業を見る機会ってなかなかないと思うので,色々見てみると面白い&勉強になるかと思います.

ポートフォリオサイトを作った

自分の場合これまでハッカソンや趣味などで作ってきたものがあったので,簡単なポートフォリオサイトを作成しました.サイトはWeb上から閲覧できるように公開した上で,リンクを上記逆求人系サービスのプロフィールなどにも貼っておきました.実際,「ポートフォリオサイト見ました.ぜひ一度面談を~」と声を掛けていただいた企業もあったので,作った意味はあったのかなと思います.

まとめ

ざっくりですが上記のような形で就活を行いました.自分は来年以降はデータ分析に関する事業部がある企業で働く予定です(正式配属は入社後なのでどうなるか分かりませんが……).今後この分野で就活をする人の参考になれば幸いです.

Chaotic PSO でベンチマーク関数を評価する

概要

カオス粒子群最適化法 (CPSO, Chaotic Particle Swarm Optimization) とは,鳥や魚などの群れの行動をヒントにしたメタヒューリスティックアルゴリズムの一つであるPSOにカオスを組み込んだ最適化アルゴリズムです.他のPSOアルゴリズムと同様多くの変形モデルがありますが,大元となるモデルの論文は2005年に発表されました*1

CPSOをPythonで実装した上で,ベンチマーク関数で評価を行ったのでまとめます.

実装内容

CPSOは大まかに下のような手順で実装していきます.

  1. PSOの実行(慣性係数においてAIWF*を使用)
  2. 上位1/5のParticleを抽出
  3. 抽出したParticleに対してCLS*を行い,位置を更新
  4. CLSを行ったParticleの位置情報を基に探索範囲を削減
  5. 新しい探索範囲内で下位4/5のParticleをランダムに再生成
  6. 各Particleの評価を行い,停止条件を満たしていれば終了,満たしていなければ1.に戻る

*AIWF (Adaptive inertia weight factor): 適応慣性荷重係数.PSOにおけるパラメータの一つである慣性係数に対する提案手法.

*CLS (Chaotic local search): カオス的局所探索.PSO実行後,局所探索のために用いる提案手法.

1. PSOの実行

まず,PSOを実行します.パラメータである慣性係数にはAIWFを使い,加速係数には一般に多く用いられている2.0の定数を指定しています. 特に慣性係数は結果に大きく影響を与えると言われており,値を大きくするほど大域探索に有効ですが,局所探索には向かないという課題があります.そこで,AIWFではParticleごとに毎回値を変えることで課題に対応しています.AIWFにおける慣性係数wは以下の式で求めることができます.


w=
\left\{
\begin{array}{}
\frac{(w_{max} - w_{min})(f-f_{min})}{(f_{avg}-f_{min})},  ( f \leq f_{avg}) \\
w_{max},  ( f > f_{avg})
\end{array}
\right.

AIWFのコード

# Adaptive Inertia Weight Factor (AIWF) 関数
def aiwf(scores, W):
    for s in range(SWARM_SIZE):
        if scores[s] <= np.mean(scores):
            W[s] = (np.min(W) + (((np.max(W) - np.min(W)) * (scores[s] - np.min(scores))) / 
                    (np.mean(scores) - np.min(scores))))
        else:
            W[s] = np.max(W)
    return W

2. 上位1/5のParticleを抽出

CLSを行うParticleを決めるため,PSOの結果Scoreの良かった上位1/5を抽出します.

3. 抽出したParticleに対してCLSを行い,位置を更新

CLSによって局所探索を行います.CLSは以下の手順で行います.

1.\(cx_{i}^{(k)}\)を求める


\displaystyle  cx_i^{(k)}=
\frac{x_{i}-x_{max,i}}{x_{max,i}-x_{min,i}}

2.\(cx_{i}^{(k)}\)を基に\(cx_{i}^{(k+1)}\)を求める


cx_{i}^{(k+1)}=
4cx_{i}^{(k)}(1-4cx_{i}^{(k)})

3.\(cx_{i}^{(k+1)}\)を基に位置\(x_{i}^{(k+1)}\)を求め,評価する


x_{i}^{(k+1)}=
x_{min,i}+cx_{i}^{(k+1)}(x_{max,i}-x_{min,i})

4.新しい評価結果が\(X^{(0)}=[x_{1}^{0},...,x_{n}^{0}]\)より良い場合,または最大反復数に達した場合,結果を出力.それ以外の場合は2.に戻る

CLSのコード

# Chaotic Local Search (CLS)
def cls(top_scores, top_positions):
    cx, cy = [], []

    min_x, min_y = min(top["x"] for top in top_positions), min(top["y"] for top in top_positions)
    max_x, max_y = max(top["x"] for top in top_positions), max(top["y"] for top in top_positions)
    
    for i in range(len(top_scores)):
        cx.append((top_positions[i]["x"] - min_x) / (max_x - min_x))
        cy.append((top_positions[i]["y"] - min_y) / (max_y - min_y))

    for i in range(K):
        logistic_x = []
        logistic_y = []
        chaotic_scores = []
        chaotic_positions = []
        for j in range(len(top_scores)):
            logistic_x.append(4 * cx[j] * (1 - cx[j]))
            logistic_y.append(4 * cy[j] * (1 - cy[j]))
            # 位置の更新
            chaotic_x, chaotic_y = chaotic_update_position(logistic_x[j], logistic_y[j], min_x, min_y, max_x, max_y)
            chaotic_positions.append({"x": chaotic_x, "y": chaotic_y})
            # score評価
            chaotic_scores.append(evaluation(chaotic_x, chaotic_y))
        # 新しいscoreが前より優れていれば値を返し,それ以外はcx, cyを更新して繰り返す
        if min(chaotic_scores) < min(top_scores):
            print("Better Chaotic Particle found")
            return chaotic_scores, chaotic_positions
        cx = logistic_x
        cy = logistic_y
    return chaotic_scores, chaotic_positions

# Chaotic position更新
def chaotic_update_position(x, y, min_x, min_y, max_x, max_y):
    new_x = min_x + x * (max_x - min_x)
    new_y = min_y + y * (max_y - min_y)
    return new_x, new_y

4. CLSを行ったParticleの位置情報を基に探索範囲を削減

CLSの結果を基に次の探索範囲を削減します.CLSで用いたParticleの位置情報を基に,以下の式を用いて探索範囲を再指定します.

ただし,実際の実装では最小値に対して複数の最小値の中の最大値を用い,最大値に対して複数の最小値の中の最小値を用いると最小値と最大値が逆転してしまったため,最小値には最小値,最大値には最大値を用いて探索範囲を広く取りました(この辺ちょっと理解が怪しい……).

探索範囲削減のコード

# 探索範囲縮小
def search_space_reduction(top_positions):
    min_x, min_y, max_x, max_y = [], [], [], []

    min_x.append(min(top["x"] for top in top_positions))
    min_y.append(min(top["y"] for top in top_positions))
    max_x.append(max(top["x"] for top in top_positions))
    max_y.append(max(top["y"] for top in top_positions))
    x = [top.get("x") for top in top_positions]
    y = [top.get("y") for top in top_positions]
    
    for i in range(len(top_positions)):
        min_x.append(x[i] - R * (max_x[0] - min_x[0]))
        min_y.append(y[i] - R * (max_y[0] - min_y[0]))
        max_x.append(x[i] + R * (max_x[0] - min_x[0]))
        max_y.append(y[i] + R * (max_y[0] - min_y[0]))
    
    # 論文通り new_min_x = max(min_x) などにすると最小値と最大値が逆転してしまうので,修正
    new_min_x, new_min_y = min(min_x), min(min_y)
    new_max_x, new_max_y = max(max_x), max(max_y)
    search_space_x = {"min": new_min_x, "max": new_max_x}
    search_space_y = {"min": new_min_y, "max": new_max_y}

    return search_space_x, search_space_y

5. 新しい探索範囲内で下位4/5のParticleをランダムに再生成

削減した新しい探索範囲内には下位4/5のParticleが入らないので,範囲内に収まるように新しく生成します.Particleの生成に関しては初期設定と同様ランダムに生成しています.

6. 各Particleの評価を行い,停止条件を満たしていれば終了,満たしていなければ1.に戻る

各Particleに対して評価を行います.この時,事前に閾値として設定したScoreより良かった場合,または最大探索回数に達した場合は探索を終了し,結果を出力します.条件を満たしていない場合は1.に戻り,またPSOから実行して探索を継続します.

ベンチマーク関数での評価結果

最適化アルゴリズムを評価するための関数として,多くのベンチマーク関数が存在します.ベンチマーク関数が詳しく紹介されているものとして@tomitomi3さんの記事*2があります. 今回はこの中でも紹介されているSphere functionを用いました.この関数の最適解は \(f_{min}(0,...,0)=0\) となっています.

今回は \(Score < 1.000e-15\) または反復回数10回を終了条件としました.結果として,グラフのように収束していく様子が観測できました.

f:id:resweater:20190602063036j:plain
CPSO (1, 2, 3 lap)

また,画像の描画無しで実行した場合及びPSOのみを実行した場合の結果は以下のようになりました.CLSによって精度が向上した場合はScoreも更新され,精度が向上しなかった場合はCLS前のScoreが引き継がれています.探索範囲は毎回削減され,Scoreも向上していることが確認できます.また,下のPSOのみを実行した結果と比較すると,精度が向上している反面,時間が掛かっていることが分かります.

CPSO log and result

Lap: 1
CLS:
before: 1.856166459555566e-09
after: 1.7476630375799616e-07
Search Area:
before
x: {'min': -5.0, 'max': 5.0}
y: {'min': -5.0, 'max': 5.0}
after
x: {'min': -0.0010838869646188037, 'max': 0.0013954791030881871}
y: {'min': -0.001201690486501598, 'max': 0.0016078160576153975}
Score: 1.856166459555566e-09

Lap: 2
CLS:
before: 2.0926627088682597e-13
Better Chaotic Particle found
after: 7.821496571701076e-14
Search Area:
before
x: {'min': -0.0010838869646188037, 'max': 0.0013954791030881871}
y: {'min': -0.001201690486501598, 'max': 0.0016078160576153975}
after
x: {'min': -7.880347663659637e-06, 'max': 1.5561134225910913e-05}
y: {'min': -1.83517959693168e-05, 'max': 1.853229861175588e-05}
Score:   7.821496571701076e-14

Lap: 3
CLS:
before: 6.562680339774457e-17
Better Chaotic Particle found
after: 5.0984844476716916e-17
Search Area:
before
x: {'min': -7.880347663659637e-06, 'max': 1.5561134225910913e-05}
y: {'min': -1.83517959693168e-05, 'max': 1.853229861175588e-05}
after
x: {'min': -3.794413350751951e-07, 'max': 1.6057623588141383e-07}
y: {'min': -2.7039514283878003e-07, 'max': 8.373690854089289e-08}
Score:   5.0984844476716916e-17

Best Position: {'x': 6.92085226884776e-09, 'y': 1.7568859807915068e-09}
Score: 5.0984844476716916e-17
time: 0.7126889228820801

PSO result

Best Position: {'x': -0.23085945825227583, 'y': -0.13733679597570791}
Score: 4.218973135139706e-06
time: 0.006306886672973633

まとめと反省

今回実験してみて,CPSOの精度のと実行時間について知ることができました.今回は最適解が一つ(単峰性)のシンプルな関数で評価しましたが,多峰性の関数などで評価した場合などについても機会があれば調べたいと思います.

反省として,元々は今後活用するために実装していましたが,拡張性のないプログラムになってしまいました……また,一部不安なところもあるのでもし間違っているところがあればご指摘お願いします.

CPSOソースコード

github.com

参考文献

*1:Bo Liu, Ling Wang, Yi-Hui Jin, Fang Tang, De-Xian Huang, "Improved particle swarm optimization combined with chaos", Chaos, Solitons & Fractals, Vol. 25, Issue 5, p.p. 1261-1271, (2005).

*2:最適化アルゴリズムを評価するベンチマーク関数まとめ - Qiita

2018年の振り返りと成果物

今年は自分にとっても転機となる年でした。夏に参加したFJCTのデータサイエンスインターンシップ以降、毎日GitHubにPushすることを目標に多くのことに取り組んできました。

 

 

1~3月

学部卒論

http://www.kansei.soft.iwate-pu.ac.jp/abstract/2017/abstract0312016305.pdf

今年は学部を卒業したので、その際に卒業研究の論文を提出しました。学部時代は音声系の研究室に所属し、専門的な音声認識システムの言語モデルに関する研究に取り組みました。編入生で講義を多く受けながらの卒研だったこともあり、いろんな意味で苦しい卒論でした💦

 

8, 9月

インターンシップ

エイチームコンテスト型インターンシップ:Sembatsu

エイチームさんのコンテスト型インターンシップゲームプログラマーコースで参加しました。

これまで使う機会のなかったUnityやC#を初めて触り、試行錯誤しながら取り組んだインターンシップでした。

 

Wanoハッカソンインターンシップ

Wanoさんのハッカソンインターンシップに参加し、「mixme」というクリエイター向けWebサービスを提案、制作しました。

この開発ではチーム内でフロントエンド・バックエンド・機械学習・Webデザインの4つに分かれて開発を行いました。 自分は機械学習班で小説のレコメンド機能の構築に関わり、プロトタイプ用学習データ構築のためのWebスクレイピングプログラムや 文章をベクトル化する上で必要な形態素解析のプログラムの作成を行いました。

この開発を通じて、これまで意識することのなかった機械学習をシステムに組み込む場合になってくるバックエンドの知識などについて学ぶ機会になりました。

 

富士通クラウドテクノロジーズ:データサイエンスインターンシップ

resweater.hatenablog.com

富士通クラウドテクノロジーズ (FJCT) さんで行われたデータサイエンスインターンシップに参加し、データ分析の手法から結果を活用した提案まで一通りの流れを学びました。このインターンシップを通じて学ぶことが多くあり、これ以降の開発のモチベーションに繋がりました。

 

イベント

manifes2018

resweater.hatenablog.com

ローカルイノベーションさんが主催されたmanifes2018というLTイベントに参加しました。この時にエンジニアの方と話したことがきっかけで、アウトプットの方法の一つとしてブログを書くようになりました。

 

Kaggle

titanicコンペ

resweater.hatenablog.com

resweater.hatenablog.com

FJCTで学んだことを実践するため、タイタニックコンペに取り組みました。この中で、特徴エンジニアリングの重要性や自分で作った特徴量で精度が上がった時の楽しさなどを学びました。

 

10, 11, 12月

コンペ

SIGNATE:Jリーグコンペ(学生コンペ)

SIGNATEでマイナビ主催で行われたJリーグコンペに取り組みました。後半は研究が忙しくなりあまり取り組めなかったのですが、1週間取り組まないだけで一気に順位が下がるというコンペの怖さを知りました(;´・ω・)

 

Kaggle:MNISTコンペ

resweater.hatenablog.com

研究でCNNを使うため、CNNの実装について学ぶためにMNISTのコンペに取り組みました。

 

研究

resweater.hatenablog.com

大学院での研究が忙しくなり、そちらがメインになってきました。その中で、論文のまとめ方なども試行錯誤しながら形ができてきました。

 

その他

TrySail分類器

TrySailという3人組の声優グループがあります。ナンスが可愛い (*>△<)

そんな彼女たちを画像から自動で分類できるようにしたいなと思い、制作しました。

シンプルなCNNを使って実装し、結果としてtestデータで7割くらいは分類できるようになりました。

 

サンタさん生成

resweater.hatenablog.com

クリスマスに院生2人で勢いで制作しました。GANを使ってサンタさんの画像生成をしています。

 

まとめ

f:id:resweater:20181230233903p:plain

夏以降ペースを上げてデータ分析や開発に取り組み、GitHubにも反映出来ました(/・ω・)/

来年以降、特に機械学習についてもう少し理論的なところも重視して理解しながら取り組んでいければと思います。

 

github.com

クリスマスなのでGANでサンタさん作ってみた

クリスマスの夜、なんとかの6時間っていうのがあるらしいんですけど、6時間もあったら何か作れるんじゃね?ということで何か作ってみることにしました。

 

作ったもの

クリスマス、情報系ならサンタさん作るところからやるべきだよなぁ?ってことでGANを使ってサンタクロースの画像を生成することにしました。ソースはGitHubに公開しています。

github.com

 

手順

今回は同じ研究室の方と2人で取り組んだので、画像収集と前処理を自分が、学習と画像生成の部分をもう一人が担当しました。

画像収集と前処理

Googleの画像検索から「サンタクロース」とか「Santa Claus」とかでスクレイピングしてきて、約500枚集めました (scraping.py)。このとき、ぱっと見で全く関係なさそうな画像は手作業で削除しました。

次に、集めた画像に対してエッジ抽出したり回転させたりして1万5千枚程度まで水増しさせ (padded.py)、その上で64x64のサイズに統一させました (resize.py)。

f:id:resweater:20181226161628p:plain

集めて処理したサンタたち

学習と画像生成

ぶっちゃけGANよく知らないのでラボの方が作ってるのを見ながら学んでました……(;´・ω・)

学習ではKerasを使って書いています (train.py)。ネットワーク構造に関しては参考論文で使われてる構造をそのまま用いたとか。

画像生成で一番エラー吐いて四苦八苦してました (gen.py)。

 

 生成されたサンタたち

f:id:resweater:20181226162950j:plain

クリぼっち学生によって生み出されたサンタ

 クリぼっちな学生の怨念を感じるサンタさんが生み出されました。

画像によってはそれっぽい形をしてるのもあり、予想より上手く出来たなーという所感です。

ちなみに学習のlossはこんな感じでした。

f:id:resweater:20181226163242j:plain

 

改善点

今回は夜中の数時間でやろうとしたのでゴリ押しのところがいくつもありました。

まず、収集した画像が500枚程度なのに対して水増しさせた最終的な画像が1万5千枚の時点でちょっと強引すぎました……

また、生成された画像からも分かる通り、画像水増しで行った回転がそのまま生成にも反映されてしまっているので、回転とかは使わないほうが良かったです。水増し手法はCNNとかで認識させるときと同じ方法をそのまま用いましたが、GANのような画像を生成させる場合使い方を変える必要があるなと気づきました。

あとは学習部分を担当した方曰く、GAN特有のオーバーフィッティングが起きてるかもとのことなのでその辺も要改善です。

 

その他

クリぼっちの院生二人で過ごすステキな夜でした☆