ストライクウィッチーズ判別器の更新

【はじめに】

以前Tensorflowのdeep mnistモデルを基にしてストライクウィッチーズの判別器を作ったことがある。

 

この時の学習データでの精度が99.77%、汎化性能が87.87%だった。また、この時の問題点として顔が斜めになっていたりすると正しく認識されなかった。

akikanr.hatenablog.com

 

【やること】

つい先日ResNetを実装した。

akikanr.hatenablog.com

 

なんの工夫もなく作ったものより、ResNetを用いる方が精度が高そうということでResNetを用いたものに更新しようというお話。後、学習データの画像を回転させたりしてデータ数を増やすとかしていなかったので今回はそれもついでに行う。

ちなみに以前のものと今回のResNetを使ってアンサンブル学習的なことはしない。

 

【結果】

学習データでの精度
99.92% 

汎化性能
97.86%

 

汎化性能がほぼ10%向上するという驚くべき結果になった。まだまだpspnetのあのモジュールとかつけたいと思っているのに既にこの精度とは…

 

コードはgitにあげておく

github.com

ResNetを実装しました。

ResNetとは

「Deep Residual Learning for Image Recognition」という論文で提案されているネットワーク

 

下図のような構成のものを作り、入力値を出力値に足し合わせて学習を行う。

                                       f:id:akikanR:20180429020015p:plain

詳細な情報は日本語の優良記事が非常に多いのでそちらを参照してほしい。

ResNetをベースとして多くの○○Netが提案されており、画像認識系をやるなら押さえておいたほうがいいことは間違いない。

 

ResNetの登場以前、画像認識では層の深さを増すと精度が良くなることが知られていた。しかし、あるラインを越えると勾配が消失し、精度が上がりづらくなってしまっていた。その時点で精度と層の深さを高いレベルで両立させていたのがILSVRC2014で優勝したGoogLeNet(22層)である。

その翌年、ResNetが152層という圧倒的な層構造をひっさげやってきて、GoogLeNetの「誤差6.66%」を大きく引き離す「誤差3.57%」を叩き出して優勝した。

ここで問題なのが何故152層も作って勾配が消失しないのかだ。勾配消失問題に対するResNetの対策は入力を出力に足すというもの(上記画像の右側のライン)でうまいこと回避しているらしい(これも続けすぎるといずれ消失してしまうのではないか…?)

 

 

ResNetのアーキテクチャの詳細

正直上記画像は簡略すぎて実装なんてとてもできないので詳細をここに書いておく。

 

f:id:akikanR:20180429025639p:plain

畳み込みのフィルタ数とウィンドウサイズは論文に記載されているのでそれを見てほしい。バッチ正規化なんて文言はどっから来たんだ・・・という方は論文の3.4を見てほしい。一文でしれっと書いてある。

 

実装

ResNetをkerasで実装したのでgithubにあげた。cifar-10を分類するようにしている(平均色を引くとかはしていない)

github.com

 

 

 

 

MemGENを実装しました(半ギレ)

MemGENとは

機械学習の生成系のタスクを行うアプローチとして、人が暗記する方法を提案した論文である

https://arxiv.org/pdf/1803.11203.pdf


識者たちからは

「さながら魚拓」

「まさかこうくるとは思わなかった」

「応用のできない人を完全に模倣している」

と様々なごくじょうのコメントを得ている

 

この手法は実装が非常に容易かつ生成速度が高速であるという特徴を持つ

 

アルゴリズム

learn

1.L ← []

2. for i in data:

    L.append( i )

 

generate

1. i ← randint( len(L)) 

2. output ← L[i]

 

上記の非常に完結なアルゴリズムで書かれている

 

生成例

input

f:id:akikanR:20171031225510j:plain

output

f:id:akikanR:20171031225510j:plain

 

Gihubにおいた

github.com

 

最後に

ここまで読んでくれた皆さんにこの論文から引用してこの言葉を贈ろうと思う

「あなたが見つけた全ての欠点は気のせいです」

python速度比較用プログラムを書いた

題字どうり

 

pythonは高速化を求めることがちょくちょくある。
bit演算と普通の演算子どっちがいいの?とか
内包表記でのリスト作成と普通のリスト作成どっちが速いの?とか
はたまた環境によって違うんじゃないの?とか

 

そんな疑問を解消するべく、githubにコードを書いた。

github.com

Visual Attribute Transfer through Deep Image Analogyの解説

はじめに

 「Visual Attribute Transfer through Deep Image Analogyの解説」と銘打ってはいますがあくまで私が読んで理解した内容を記述いたします。
つまるところ私の誤解による間違いが混入する可能性があります。
予めご了承ください。

 

Visual Attribute Transfer through Deep Image Analogyについて

2つの似ている画像を入力として与え、互いの画風を転写しあったような画像を出力するものです。
論文はこちら

[1705.01088] Visual Attribute Transfer through Deep Image Analogy

 

処理概要
 

f:id:akikanR:20171112001900p:plain

論文より画像を参照

1. 学習済みのVGG19に画像Aと画像B'を与えて各層のreluの出力を5つずつ取得する。(画像左側のPreprocessingに相当)

2. 2枚のn層目(初回ならn=5)の出力結果にパッチマッチを行い、近いところに写像されるような対応マップを作成する。その後、処理した層が1層目なら8を実行する。

3. 作成した対応マップを用いて画像A風の画像B'(画像A'とよぶ)と画像B'風の画像A(画像Bとよぶ)を作成する。

4. 3で作成した画像をデコンボリューションして一つ上の層の画像を予測して画像を作成する。(画像B'を用いてデコンボリューションされた画像をRA, もう一方をRBとする)

5. 2で処理した層の1つ上の重みを計算する。(1つ上の画像Aを用いて計算された重みをWA,もう一方をWBとする)

6. RAとWAを用いて2で処理した層の1つ上の画像A'を作成する。(Bの方も同様)

7. 2で作成した対応マップを2で処理した層の1つ上の画像と同じ縦横が同じサイズになるように最近傍補間を使って拡大する。その後2に戻る。

8. 対応マップを用いて画像Aと画像B'から画像A'と画像Bを作成して終了する。

 

 

ざっくり言うとVGG19に画像を入れて特徴マップを持ってきた後に抽出された層ごとに似ている場所を探していって対応マップを作り、それを基に大元の画像のピクセルを対応する場所にコピーして画風を転写しあうってことを実現している。

 

処理順1 前処理(特徴マップの取得と初期対応マップ作製)

 処理概要の1にある通りVGG19に画像を入れて中間データを取得する。
この時中間データを取得する場所は5層に分かれているVGG19の各層の第1のreluをかけた直後のデータとなる。得られたデータは縦*横*チャネル数の形になっている。

 初期対応マップとはパッチマッチを行う際に必要となるものだ。初回は完全にランダムの場所に対応したものを用いる。初回以降は処理概要7で作成した対応マップを用いる。対応マップの形式はパッチマッチを適用する画像と縦横が同じサイズでチャネル数は3の一般的な画像の形式とする(描画する都合上この形)。Rに対応する座標のx値,Bに対応する座標のy値が入る。

 

処理順2 パッチマッチ

パッチマッチについては2つの画像の各ウィンドウが(近似的に)最も近い場所を探すアルゴリズムである。詳細は以下のURLを参考にしてほしい。

http://vis.berkeley.edu/courses/cs294-69-fa11/wiki/images/1/18/05-PatchMatch.pdf

ウィンドウサイズは層毎に決められており、5層から3層目まで3*3ピクセル、2,1層は5*5である。また探索する範囲は4層,3層目まで半径6*6ピクセル、2,1層は4*4である。
ここで作成される対応マップは2枚あり、画像Aから画像B'への対応マップをΦLBA、画像B'から画像Aへの対応マップをΦLABと呼ぶ。

距離の定義は以下の式のΣである。

f:id:akikanR:20171112025128p:plain

表記が難しいのでFL-A(x)と書かせてもらう。

これは画像Aを画像Aのノルムで割って正規化したものを指す。

N(p)は指定された座標pを中心として構成されるウィンドウの座標集合である。

 

処理順3 画像A'と画像Bの作成

論文中ではwarpと表記されている。

画像A’を作る例を出す。
画像B’の左上のピクセル(0,0)座標をwarpすることを考える。
この時画像B'の座標と対応するΦLABの座標を参照し、参照したピクセル内のRGB値(処理順1でRにx値、Bにy値を入れている)の(R, B)座標に現在のピクセルのデータをコピーする。これを全ての画像B'の座標に行うことで画像A'は作成される。
画像Bに関しても同様である。

 

処理順4 画像のデコンボリューション

画像を与えるとその画像が畳み込まれる前の層を復元するCNNを作成する。
初期値として値がランダムになった画像、正解データとして処理3で生成した画像を入れる。

ロス関数の定義は以下の式である。

f:id:akikanR:20171112121037p:plain

右辺第一項はデコンボリューションで生成された画像を示しており、
右辺第二項は正解データを示している。
論文中ではオプティマイザーはlbfgsを使用しているようだ。
この時作成される画像をRB', RAと呼ぶ(ここでRB'は画像B'と似た形状になっているのではなく画像B'を基にしているということを示すためにRB'となっているだけなので誤解なきよう・・・)


ここでワープ後の画像が存在するならば畳み込まれる前の画像としてどんなものがふさわしいかを出力する。本来存在しないものに言うのもおかしな話だが画像を復元している。

 

処理順5 重み計算

次の層で重要となる部分を重みをつけて取り出すための重みを出力する。

重みの定義は以下の式

f:id:akikanR:20171112122418p:plain

f:id:akikanR:20171112122436p:plain

Lは処理順2で処理した層を示している。
αは層ごとに値が決められており、4層から1層目まで順に書くと0.8,0.7,0.6,0.1となっている。
κ=300
τ = 0.05
|FL-1A(x)|^2 だがこれは0から1の間で正規化しておかなくてはいけないようだ。

画像Aの重みをWA、画像B'の重みをWB'とする

 

処理順6 重みと復元画像の合体

以下の式を用いて一つ上の層の画像A'を求める。

f:id:akikanR:20171112123552p:plain

A〇B の演算だが特徴マップFL-1Aの座標(0,0)の全てのチャネルに対してWL-1Aの座標(0,0)の値をかけるということを意味している。

なお論文中でWL-1Aは0~1の値を持つと書いているがシグモイド関数に1未満をかけている時点でそもそも1には成りえないので0~1の範囲に落とし込む操作が必要であると思われる(私は最大値で割って0~1の範囲にした)

 

処理順7 対応マップの拡大

処理順2で作成した対応マップを処理順2で処理した層の1つ上の画像と縦横が同じサイズになるように最近傍補間を使って拡大する。その後処理順2に戻る。

 

処理順8 転写しあう画像の作成

対応マップを用いて画像Aと画像B'から画像A'と画像Bを作成して終了する。

以下の式で行う。

f:id:akikanR:20171112124910p:plain

Φ1abというのは最終的に出てくる対応マップのことを指している

Nは5*5のウィンドウサイズ(パッチマッチの処理手順を参照のこと)

 

おわりに

処理手順だらけになって申し訳ないが言うは簡単だがやるとめんどくさいというのがこの論文を実装しての感想だ。
そんな感じがにじみ出てしまっていたらまことに申し訳ない。
何か疑問点があれば質問して頂けるともしかしたらこたえられるかもしれない(たぶん自分で論文読んだ方が早い)

Visual Attribute Transfer through Deep Image Analogyを実装してbot化した話

はじめに

Visual Attribute Transfer through Deep Image Analogy(https://arxiv.org/pdf/1705.01088.pdf)

これは画風を転写しあうような論文。

例えばモナリザアバターを与えるとモナリザ風のアバターアバターモナリザを出力するような奴

f:id:akikanR:20171031223904p:plain

これは実際に作ったやつで論文のはちゃんとすごい

 

今回はこれをbot化して2枚の画像を与えたら画風を転写しあった画像を返すシステムを作った

 

 

動作事例

2人やってくれた方がいたので両方とも結果を張る

1.富士山を与えた例

入力

f:id:akikanR:20171031224329j:plainf:id:akikanR:20171031224334j:plain

出力結果

f:id:akikanR:20171031224542j:plainf:id:akikanR:20171031224546j:plain

 

2.仏像と人

入力

f:id:akikanR:20171031224725j:plainf:id:akikanR:20171031224722j:plain

出力結果

f:id:akikanR:20171031224902j:plainf:id:akikanR:20171031224905j:plain

 

 

うまくいくこともある

f:id:akikanR:20171031225343j:plainf:id:akikanR:20171031225340j:plain

f:id:akikanR:20171031225510j:plainf:id:akikanR:20171031225440j:plain

 

コード

コードはgithubにあがってるので酔狂な人はやってみてほしい

なおコードのリファクタリングなどはしていない

github.com

 

 

特徴ベクトルを作成する手間を減らすプログラムを作成した

特徴量の選択は実に重要な要素である。
しかし、特徴量一つごとに特徴量化するプログラムを書くのは大変手間であるし、そんなところに時間を使うのは勿体ない。
そんな時間を減らすためにプログラムを作成した。

特徴量にしなくてはいけないものにはいくつか種類があると思う。(他にあったら順次追加していく)

  • 連続値
  • 複数選択肢がある中で一つだけを選ぶもの
  • 複数選択肢がある中で複数を選ぶもの
  • 文章などのテキストデータ


本プログラムではテキストデータ以外の3つを簡略化する。

プログラムと使用方法はgithubにあげたのでリンクを貼っておく。

 

github.com

 

概要としては

連続値は標準化する

複数選択肢があって一つだけ選択する場合は選択肢の分だけ次元を作って特定の部分にのみ1、それ以外は0にして返す

複数選択肢があって複数選択する場合は上記と同様に次元を作り、選択された分だけ特定の場所に1、それ以外を0で返すようにした。