にほんごのれんしゅう

日本語として伝えるための訓練を兼ねたテクログ

Gradient Boosting Machineで特徴量を非線形化

Gradient Boosting Machineで特徴量を非線形

Practical Lessons from Predicting Clicks on Ads at Facebook

Facebook社のGradient Boosting Machineで特徴量を非線形化して、CTRを予想するという問題の論文からだいぶ時間が立っていますが、その論文のユニークさは私の中では色あせることなくしばらく残っています。

原理的には、単純でGrandient Boosting Machineの特徴量で複数の特徴量を選択して決定木で一つの非線形な状態にして、数値にすることでより高精度でリニアレグレッションなどで予想できるようになります。私の雑な解釈では、GBMがその誤差を最小化しようと試みる時に、複数の特徴量を選んで木を作成するのですが、この時の木がうまく特徴量の相関を捉えて、結果として特徴量の圧縮として働いているという理解です。

では、これは、どのような時に有益でしょうか。

CTR予想はアドテクの重要な基幹技術の一つですが、リアルタイムで計算して、ユーザにマッチした結果を返す必要がある訳ですが、何も考えずに自然言語やユーザ属性を追加していくと、特徴量の数が50万から100万を超えるほどになり、さらに増えると1000万を超えることがあります

GBM系のアルゴリズムの一種であるLightGBMを用いることで、LightGBMで特徴量を500個程度の非線形化した特徴量にして、これ単独でやるより各々の木の出力値をLinear Regressionにかけるだけで性能が同等になるか、向上するとのことです   

図示

図1. FBの論文の引用

GBMで特徴量を非線形化して、その非線形になった特徴量の係数をLinear Regressionで計算します

問題設定

映画.comのレビューのテキストを形態素解析してBoWのベクトルを作り、そのベクトル値から、星の数をレグレッションで当てます
単語は多様性があるので、とても高次元になりますが、1. 単純なLinear Regression2. LightGBM3. LightGBMで非線形化+Linear Regressionで比較します

全体の流れ

  1. 映画.comの映画のレビュー情報を取得します
  2. レビューの星の数と、形態素解析してベクトル化したテキストのBoWと星の数を表現したペア情報を作ります
  3. これをそのままLightGBMで学習させます
  4. LightGBMで作成したモデル情報を解析し、木構造の粒度に分解します
  5. 2のベクトル情報を作成した木構造非線形化します
  6. ScikitLearnで非線形化した特徴でLinear Regressionを行い、星の数を予想します 

データセット

作成したコーパスはここからダウンロードができます

1. Linear Regressionのみの精度

Linear Regressionより性能が高くなると期待できるので比較検討します
今回の使用したデータセットは50万程度の特徴量ですので、単純にLinear Regressionで計算したものと比較します

$ ./train -s 11 ../xgb_format 
iter  1 act 7.950e+06 pre 7.837e+06 delta 1.671e+00 f 9.896e+06 |g| 2.196e+07 CG   2
cg reaches trust region boundary
iter  2 act 3.798e+05 pre 3.755e+05 delta 6.685e+00 f 1.946e+06 |g| 8.440e+05 CG   5
cg reaches trust region boundary
iter  3 act 2.320e+05 pre 2.300e+05 delta 2.674e+01 f 1.566e+06 |g| 1.298e+05 CG  12
cg reaches trust region boundary
iter  4 act 2.481e+05 pre 2.476e+05 delta 1.070e+02 f 1.334e+06 |g| 4.600e+04 CG  28
cg reaches trust region boundary
iter  5 act 3.378e+05 pre 3.489e+05 delta 4.278e+02 f 1.086e+06 |g| 4.329e+04 CG 104
iter  6 act 1.306e+05 pre 1.698e+05 delta 4.278e+02 f 7.481e+05 |g| 9.367e+04 CG 180
iter  7 act 4.090e+04 pre 1.129e+05 delta 1.117e+02 f 6.175e+05 |g| 2.774e+04 CG 419

学習が完了しました

$ ./predict ../xgb_format_test xgb_format.model result
Mean squared error = 0.785621 (regression)
Squared correlation coefficient = 0.424459 (regression)

MSE(Mean Squared Error)は0.78という感じで、星半分以上間違えています

2. LightGBMのみでの精度

LightGBM単体での精度はどうか検討します。

このようなパラメータで学習を行いました。

task = train
boosting_type = gbdt
objective = regression
metric_freq = 1
is_training_metric = true
max_bin = 255
data = misc/xgb_format
valid_data = misc/xgb_format_test
num_trees = 500
learning_rate = 0.30
num_leaves = 100
tree_learner = serial
feature_fraction = 0.9
bagging_fraction = 0.8
min_data_in_leaf = 100
min_sum_hessian_in_leaf = 5.0
is_enable_sparse = true
use_two_round_loading = false
output_model = misc/LightGBM_model.txt
convert_model=misc/gbdt_prediction.cpp
convert_model_language=cpp

50万次元程度のスパースベクトルなので、numpyなどのアレーにせず、そのままバイナリのLightGBMに投入します

$ lightgbm config=config/train.lightgbm.conf  
...
[LightGBM] [Info] 47.847420 seconds elapsed, finished iteration 499
[LightGBM] [Info] Iteration:500, training l1 : 0.249542

テストデータに置ける誤差は先ほどより小さく、0.25程度ということになりました

LightGBMでの非線形化の前処理

出力したC++のモデルを非線形化するPythonのコードに変換

$ cd misc
$ python3 formatter.py > f.py
...(適宜取りこぼしたエラーをvimやEmacs等で修正してください)

特徴量を非線形化したデータセットに変換

$ python3 test.py > ../shrinkaged/shrinkaged.jsonp

3. LightGBMで非線形化 + Linear Regressionでの精度

$ cd shrinkaged
$ python3 linear_reg.py --data_gen
$ python3 linear_reg.py --fit
train mse: 0.24
test mse: 0.21

testデータセットで0.21の平均絶対誤差と、LightGBM単体での性能に逼迫し、上回っているとわかりました

精度などの比較

単純なACCURACYという意味での精度であれば、以下の関係が成り立っていそうです

LightGBM = LinearRegression(NonLinear) > LinearRegression(Native)

では、最初からLightGBMだけで計算すればいいじゃんという話がありましたが、これは多分、特徴量を非線形化しておいて少ない次元で取り扱うことで、CTR予想を行いすぐ計算結果を返すなどの、用途に向いているのだと思います

コード

コードはこちらにあります。C++のモデルをPythonの決定木の構造に変換するのが大変でした。。。

まとめ

これに極めて特徴量が大きい問題に対して、決定木による非線形化と、非線形化した状態で保存することで、広告を配信する際など、計算時間がかなり短縮できることが期待できます(クリエイティブの特徴量とユーザ行動列の特徴量を別に非線形化して組み合わせてLRで予想するとか)

謝辞

SNSで理論をだらだら述べていた時に、先行して研究を行っていてそのノウハウや本質を伝えてくださった菜園さんに深く感謝しています。
より多角的な指標で検討されているので、ぜひ一読されると良いと思います。

Kerasを使ったGoogle VisionサービスのDistillation(蒸留)

Kerasを使ったGoogle VisionサービスのDistillation(蒸留)

Vision APIをVGGで蒸留する

Vision APIの出力は実はタグの値を予想する問題でしかない

出力するベクトルが任意の次元に収まっており、値の範囲を持つ場合には、特定の活性化関数で近似できる

例えば、Vision APIはメジャーなタグに限定すれば、5000個程度のタグの予想問題であり、5000個程度であればVGGを改良したモデルで近似できることを示す

(2017/11/08 データセットをスクリーニングして、問題のあるデータセット(一定の確率で特定のタグによってしまう)を排除したところ、だいぶ改善しました)

理論

去年の今頃、話題になっていたテクノロジーで、モデルのクローンが行えるとされているものである。
Google VISION APIなどの入出力がわかれば、特定のデータセットを用意することで、何を入力したら、何が得られるかの対応が得られる

この対応を元に、VISION APIの入出力と同等の値になるように、VGG16を学習させる

DeepLearning界の大御所のHinton先生の論文によると、モデルはより小さいモデルで近似することができて、性能はさほど落ちないし、同等の表現力を得られるとのことです[2]

(蒸留を行う上で重要な、仕組みはいくつかあるのですが、KL Divergenceという目的関数の作り方と、softmaxを逆算して値を出すことがポイントな気がしています)

イメージするモデル

図1. クローン対象のモデルをブラックボックスとして、任意のモデルで近似する

論文などによると、人間が真偽値を0,1で与えるのではなく、機械学習のモデルの出力値である 0.0 ~ 1.0までの連続値を与えることで、蒸留の対象もととなるモデルの癖や特徴量の把握の仕方まで仔細にクローンできるので効率的なのだそうです  

実験環境

  • pixabox.comという写真のデータセット200万枚を利用
  • 特徴しては5000個の頻出する特徴を利用
  • KL Divergenceではなく、Binary Cross Entropyを利用(Epoch 180時点においてこちらの方が表現力が良かった)
  • 事前に200万枚に対してGoogle Cloud Vision APIでデータセットを作成し、Distillationで使うデータセットに変換
  • AdamとSGDでAdamをとりあえず選択
  • 訓練用に195万枚を利用して、テスト用に5万枚を利用した

モデル

様々なパラメータ探索を行なったが、収束速度と学習の安定性の観点から学習済みのVGG16のモデルを改良して用いるとパフォーマンスが良かった

input_tensor = Input(shape=(224, 224, 3))
vgg_model = VGG16(include_top=False, weights='imagenet', input_tensor=input_tensor)
for layer in vgg_model.layers[:6]: # default 15
  layer.trainable = False
x = vgg_model.layers[-1].output
x = Flatten()(x)
x = BN()(x)
x = Dense(5000, activation='relu')(x)
x = Dropout(0.35)(x)
x = Dense(5000, activation='sigmoid')(x)
model = Model(inputs=vgg_model.input, outputs=x)
model.compile(loss='binary_crossentropy', optimizer='adam')

結果

スナップショットして250epoch時点の結果を載せる
まだ計算すれば性能は上がりそうである

図2. ざくろ
図3. ビーチと人と馬(馬が検出できていない) 
図4. ベトナムの夕日 
図5. アステカのデザインパターン
図6. 水と花の合成写真

学習時の注意点

膨大な検証と試行錯誤を行なったのですが、KL Divを最小化するのもいいですが、Binary Cross Entropyの最小化でもどうにかなります  

また、分布を真似するというタスクの制約からか、分布を似せようとしてくるので、必然的に頻出回数が多いSitiationに一致していまします。こういう時は単純な力技でデータ増やすこと汎化させているのですが、今回は100万枚を超えるデータセットが必要で大変データ集めに苦労しました(10万枚具体で見積もっていたら全然うまくいかなくて焦りました。。。)  

プロジェクトのコード

学習済みのモデル

minioの自宅サーバにおいておきます(常時起動している訳でないので、落ちてることもあります) [models0]http://121.2.69.245:10002/minio/google-vision-distillation/keras-distillation/

使用した学習データセット

minimize.zip vision.zip

データセットを集める

pixabayなどをスクレイピングしたスクレイパーが入っているgithubのプロジェクトです   pixabayはデフォルトではタグ情報がロシア語であってちょっと扱いにくいのですが、これはこれで何かできそうです (leveldbやBeautifulSoupなどの依存が必要です)
スクレイピング

$ python3 pixabay_downloader.py

Google Visonが認識できるサイズにリサイズする

$ python3 google_vision.py --minimize

GCPGoogle Visionのキーを環境変数に反映させる(Pythonスクリプトが認証に使用します)

export GOOGLE=AIzaSyDpuzmfCIAZPzug69****************

Google Visionによりなんのタグがどの程度の確率でつくか計算し、結果をjsonで保存

$ python3 google_vision.py --scan

学習に使用するデータセットを作ります

$ python3 --make_tag_index #<-タグ情報を作ります
$ python3 --make_pair #<-学習に使用するデータセットを作ります

学習

任意のデータセットを224x244にして255でノーマライズした状態Yvと、タグ情報のベクトルXvでタプルを作ります   タプルをpickleでシリアライズしてgzipで圧縮したファイル一つが一つの画像のデータセットになります

one_data = gzip.compress( pickle.dumps( (X, y) ) )

任意のデータセットでこのフォーマットが成り立つものをdatasetのディレクトリに納めていただき、次のコマンドで実行します

$ python3 distillation.py --train

予想

学習に使用したフォーマットを引数に指定して、predオプションをつけることで予想できます

$ python3 distillation.py --pred dataset/${WHAT_YOU_WANT_TO_PREDICT}.pkl
...
(タグの確率値が表示されます)

蒸留における法的な扱い

参考文献[1]に書いてある限りしか調査していないですが、蒸留や転移学習に関しては法的な解釈がまだ定まってないように見受けられました

既存の学習済みモデルのいわゆるデータコピーではないので,直ちに複製ということはできない。ただし,部分的に利用を行ったり,その結果を模したネットワークを再構築したりといった行為にあたるので,そもそも複製にあたるか否か,元の学習済みモデルの権利者(がもし存在すれば)との間でどのような利益の調整が行われるのか,許諾の要否,元のネットワークに課されていた権利上の制約(例えば,第 47 条の 7 の例外規定におけるデータベースの著作物の複製権の許諾等),といった論点がある。これらがどのように重み付けされて考慮されるかについては,文化的な側面,及び経済的な側面から,制度設計が必要であると考えられる。

ビジネスで使用するのは避けて、当面は、学術研究に留めておいた方が良さそうです。

コード

ライセンス

MIT

参考文献

勾配ブースティングを利用した教師あり形態素分析

勾配ブースティングを利用した教師あり形態素分析

辞書ファイルを必要とせず、C++用のモデル(データを入力すると、結果が返ってくるもの)が構築できるので、任意の言語、例えばRuby等でも分かち書きや品詞推定 を利用できる様になります

理論

ある文章の特定の文字と文字の間に分かち書きを行うべきかどうかの、二値分類問題として扱うことができると仮説を立てます
周辺の”文字”の分布から、そこが分かち書きを行うのに適切なのかどうかを、なんらかの方法で人間が用意したデータを用い教師あり学習で学習します

図1. 問題設定

この問題設定におけるベクトルを直列化して、スパースなベクトルとして表現すると、LIVSVM形式のフォーマットにすることができ、LightGBM, XGBoostなどで学習することが可能なフォーマットに変換できます

品詞の推定も同様の理論で行うことができ、分かち書きした結果を利用して、再び周辺の”単語”の散らばりから予想します。
単語も未知語である場合には不明ですが、周辺の既知の単語情報のみで品詞を推定することができます

前処理

githubのレポジトリには最初から学習済みのデータを用意していますが、自分で必要なデータを学習させる場合には以下のステップで行います

教師あり分かち書きなので、教師となる分かち書きの粒度を示したデータセットが必要となります

例えば、mecabの生成する分かち書きを教師データとする例を今回行います

映画.com様から取得した500MByte程度の映画のレビューデータを利用して、boosting-tree-tokenizerに学習させるデータセットを作成します

ダウンロード(20GByte程度あります)

$ cd misc
$ python3 downloader.py 

1. ポジティブデータ、ネガティブデータセットの作成

以下の様なデータを作成します

ポジティブ
[、今日は o 天気がい]
分かち書きがあり得る箇所にoが入ります
ネガティブ
[ベネチア x ンマスク]
分かち書きとしてありえないところにxが入ります

2. スパースマトリックスの作成

特徴量の作り方として、周辺の文字、単語とその距離の二つの軸で独立な特徴量とするため、まともにやろうとすると、大変高次元化して今います.
そのため、スパースマトリックスとして表現するために、まず、特徴量に対してユニークなインデックスを付与します

$ python3 wakati.py --make_sparse
$ python3 parts.py --make_sparse

付与したインデックスをもとに、スパースマトリックスを組み立てます

$ python3 wakati.py --make_sparse2 
$ python3 parts.py --make_sparse2

3. train, testデータの作成

お使いのマシンのスペックに依存しますが、trainデータで100万, testデータで10万データセットを利用する際には、この様にしまします

$ head -n 50000000 ./misc/download/dataset.txt > train
$ head -n 3000000 ./misc/download/dataset_parts.txt > train_parts
$ tail -n 10000000 ./misc/download/dataset.txt > test
$ tail -n 100000 ./misc/download/dataset_parts.txt > test_parts

LightGBMでの学習

binary-classificationでの二値分類の問題としてみなします
具体的には、ある文字と文字の間に、分かち書きすべきかどうかの確率値を計算します
50%を超えると、分かち書きを有効にし、50%未満では分かち書きを行いません

有名な勾配ブースティングライブラリにはXGBoostとLightGBMとCatBoostなどがあるのですが、スパースマトリックスの扱いやすさからLightGBMを使います

1. LightGBMのインストール

cmakeでビルドとインストールできます(要:GNU make, gcc, cmake)

$ git clone https://github.com/Microsoft/LightGBM
$ cd LightGBM
$ mkdir build
$ cd build
$ cmake ..
$ make -j16
$ sudo make install

これでlightgbmコマンドがシステムに追加されました

2. LightGBMで学習する

学習に使うパラメータを記述したconfがあるので、必要に応じでパラメータを変更して用いてください

$ lightgbm config=train.conf
$ lightgbm config=train.parts.conf

学習したモデルで分かち書き、品詞推定をしてみる

映画.comさんのレビューをランダムサンプルして適当に分かち書きしてみています

$ python3 intractive.py --test

出力はこの様になり、概ね、期待通りの分かち書きになっていることが確認できるかと思います

- 調子/に/乗り/過ぎ/て/いる/感/が/嫌い/だ/が/、/この/作品/は/見/て/よかっ/た
- はじめ/と/する/役者/さん/たち/の/演技/に/泣か/さ/れ/た/。/小林武史/の/音楽/も/素晴らしく/て/サントラ/を/買っ/て/しまっ/た/。/原作/も/読み/た
- 読ん/で/で/、/これ/を/見/た/が/とく/に/違和感/なく/見れ/た/。/多分/、/原作/は/もっと/色々命/と/の/引き換え/を/考え/て/た/気/も/する/けど/、/これ/は/これ/で/よい/。
- 映画/は/苦手/だっ/た/の/です/が/、/母/の/誘い/で/見/に/行き/まし/た/。/後半部分/が/良い/です/。/自分/で/も/なん/で/泣い/て/いる/か分から/ない/ほど/涙/が/出まし/た/。
- 目/が/真っ赤/だ/けど/大丈夫/?/!/と/言わ/れ/まし/た/.../。/今/に/なっ/て/、/あぁ/良い/映画/だっ/た/。/と/思っ/た/ので/レビュー/し/て/み/まし/た/。/命より/大切/な/もの/は/あり/ます/。
- スケジュール/が/合わ/なく/て/見/に/行け/なかっ/た/が/、/近場/の/IMAX上映館/が/今週末/から/箱割/を/大幅/に/カット/する/こと/が/わかり/、/慌て/て/見/に/行っ/た/。/IMAX上映/を/前提/と/し/た/映像/凄い/迫力/と/臨場感/だっ/た/が/、/人物/や/物語/は/平板/な/もので/、/特別/感動/も/なく/終了/。/欧州戦史/に対する/ある/程度/の/前提/知識/が/必要/だっ/た/の/かも/しれ/ない/と/思っ/て/パンフ/を/購入し/た/が/、/これ/が/凄い/情報量/だっ/た/。
- 今/に/なっ/て/、/あぁ/良い/映画/だっ/た/。/と/思っ/た/ので/レビュー/し/て/み/まし/た/。/命/より/大切なもの/は/あり/ます/。/
- 大切なもの/と/の/思い出/が/消え/た/中/で/1/人/で/生きる/なんて/つら/すぎ/ます/。/改めて/、/それ/に/気づけ/て/良かっ/た/。/周り/の/人/を/大切/に/しよう/と/思う/映画/。

品詞推定の例
実行時にオプションをつける必要があります

$ python3 intractive.py --test --hinshi

出力はこのようになります

本文/に/ネタバレ/が/あり/ます/。
本文 43 名詞-一般
に 33 助詞-格助詞-一般
ネタバレ 59 名詞-固有名詞-一般
が 33 助詞-格助詞-一般
あり 67 動詞-自立
ます 4 助動詞
。 12 記号-句点

Pure C++で記述されたモデルを得る

まだLightGBMの実験的な機能だということですが、C++で記述されたモデルを出力可能です。
具体的には、決定木の関数オブジェクトのリストを返してくれて、自分でアンサンブルを組むことができるようになっているようです
Pure C++なので、C++バインディングできるRubyなどの言語は、別途MeCab等を利用しなくても辞書がなくても、形態素解析できるようになるという感じです
(モデルをどう使うのかよくわからないのですが、知ってる人Twitter等でサンプルコード等教えていただけませんか。。。)

C++形式のモデルを出力する

traon.confの以下のコメントアウトを外すと、C++で直接コンパイルできて判別できるモデルができあがあります

convert_model=gbdt_prediction.cpp
convert_model_language=cpp

feature_index.pklのC++

pickle形式の特徴量の対応表はC++には読めないので、cppのファイルに変換します

$ python3 intractive.py --make_cpp

実装

感想とか印象とか

このネタはもともと、何か論文書けこのやろうと詰められる機運が高まってきたので、何か自然言語処理で論文になるようなネタを探していた時にふと、勾配ブースティングの性質であればできるんじゃないのかな、しかもこの場合、辞書なしでできる、という気づきがあり、やってみました
うまくいったので、なんらか形態素という人間が考える意味粒度を与えるデータセットさえあれば、傾向を一般化して、形態素解析として働きうることを示せたかと思います
私のC++力が足りないので、C++の実装がうまくいかなったですが、仮に実装したとなると、モデルのみのインプリテーションで済むので、辞書ファイル等の更新が必要なくなるという大きなメリットがあります

Twitterで報告したところ、TinySegmenter(AdaBoostでの機械学習)という似たようなアプローチを知ったのですが、数パーセントですが、こっちの方が分かち書きの性能はよかったです。あと、TinySegmenterでは品詞の推定ができませんが、これはできることが強みでしょうか

名称について

色々な名称の形態素解析器がありますが、このプロジェクトから派生した今回の一連のコードを珊瑚(sango)としたいと思います

理由は一部のサンゴが、任意の海流の流れ(とはいっても多分その海域での特徴とかあると思うんですが)を、任意の方向に整流することができます。これは、サンゴの中に複雑な微小な穴があって、穴はツリー状に内部で経路を構築しており、この穴をどこからでも海水が通ると、不思議なことに一定の方向性を持って海水が出てきます

あたかも乱雑な情報から秩序と法則性を取り出すことができる勾配ブースティングの動作に似ていることから、この名前をつけたいと考えています

ライセンス 

MIT

Alternative Implementation Of Illustration2Vec Ver2.

Alternative Implementation Of Illustration2Vec Ver2.

Alternative Illustration2Vec Ver2の概要

  • 画像をタグ等の特定の特徴量に従ってベクトル化できる
  • このベクトルとは通常画像分類で用いられるsoftmaxなどのマルチクラスではなく、softprobの(*1)問題として捉えることができる

Version2の改善、変更点

  • Ver1に比べて探索的であって割とひどいコードを修正して、わかりやすく変えました
  • 150x150の画像のサイズから、224x224にスケールアップしました
  • BatchNormalizationだけでなく、DropOutも併用してネットワークのスパース性を高めました
  • Msgpackを用いたKVSをやめて、ただのPickleで画像のシリアライズをする様になりました
  • Keras V2のインターフェースに合わせました

*1 softprobはxgboostの用語でありますが、各クラスに該当するものが、その確率値を返すものです

VGG16の転移学習

VGG16の評価モデルはよくチューニングされており、別段何かしなくても良いパフォーマンスが出せます
そのため、VGG16の評価モデルを転移学習することでそのチューニングされた良い状態を保存しつつ、softprobに該当する部分を付け足すことで、illustration2vecに該当する機能を付与させます

モデル図

毎回気持ちですみません(しかし、なんらかの活性化関数の新規のものの提案というスタイルではないので、雑でいいという思いがあります)

図1. モデルのイメージ

転移学習時のネットワーク設計

今回は過去最大の5000次元を予想するというタスクであったので、全結合層をReLuで結合していきます
前回はBatchNormalizationのみでやったのですが、これだけを用いうることに少し不安があったので、DropOutを30%のデータを入れるようにしました
ReLu, DropOutともネットワークを疎結合にする役割が期待できますので、ネットワークの意味のクラスタが獲得しやすくなると期待できます

オプティマイザと損失関数

これ系のタスクではAdamかSGDが良い成績をいつも収めることが期待されていますので、何も考えず、Adamで決め打ちです
- オプティマイザ、Adam : LearningRate 0.001 - 損失関数、BINARY CROSS ENTROPY

使ったデータセット

Safebooruさんからダウンロードさせていただきました
タグとURLと画像の三つの情報を保存し、学習用のデータセット1,500,000枚、テスト様に20,000枚用意します

データがメモリに乗り切らないときに使ったアプローチ

メモリに乗らないときは、最近いつも使うのですが、データセットを分割読み込みまします
ソフトウェア工学者にとっては一般的なアプローチですが、Epochと対応させて学習すると、なんとかスケジューリングできます(ちゃんとKerasのインターフェースの中にはgeneratorというデータセットを切り出す仕組みがありますが、私はこれを操作が複雑になりすぎると感じているであまり用いていません)

具体的には、15000枚の画像をオンメモリに保持 -> 1Epoch回す -> 別の150000枚の画像をオンメモリに保持 -> 1Epoch回す -> ...

ということを続けていきます

全てが一回のみスキャンされます

転移学習の例

前処理

make_datapairディレクトリ内のmake_datapair.pyを"--make_tag_index"オプションをつけて実行すると、特定のディレクトリの内部の画像とタグ情報に対して、よく頻出するタグ5000個に対して、タグとそのインデックスを記述します

make_dataset.pyを"--make_pair"のオプションをつけて実行することで、実行することで、タグとインデックスをもとに、画像のベクトル情報 Xとそのタグ情報をベクトル化した情報yのペアを作ります。一つの画像に対して、Piar(X,y)となる情報をpickle形式のファイルで出力します

学習

alt_i2v_V2.pyに"--train"オプションをつけて実行することで、学習します。15000枚の画像のデータセットラウンドロビンで切り替えながら学習しますが、メモリ64GByteマシンの基準でやっていますので、必要に応じて、サイズを小さくするか、ランダムサンプルに切り替えるか、Epoch数を変化させるなどすると良いでしょう

予想

alt_i2v_V2.pyに"--pred"オプションをつけて実行することで予想が可能です

評価

定量的なMSEの他に、定性的なみんなが好きそうな結果を載せておきます
結果は概ね、良好で、画像識別は本当に今や簡単になりましたね、という印象があります

KPI予想としてのIllustration2Vec

Practical Lessons from Predicting Clicks on Ads at Facebookという論文があります

趣旨としては、テキストや画像やなんらかを特徴量の集合としてみなして、CTR予想などのKPI予想問題を行う際、特徴量が極めて高次元である際、アルゴリズム(この場合、勾配ブースティングの木の出力値)を特徴量とすることで、これを元にLinear Regressionをかけることで、より実践的な速度で、より高精度で予想できるという趣旨でした

勾配ブースティングはそのアルゴリズムから残渣となる誤差を最小化する様に特徴量を選択しますが、例えば、これがIllustration2Vecの出力次元値ではどうでしょうか。アルゴリズムが自動で獲得した粒度の特徴量ではないですが、同様の圧縮された特徴量の空間と見做すことができます。(LDA的な自動でクラスタを獲得させる方法も筋が良さそうです)

データが十分に手元にないので、検証は今現在、簡単に行えそうにはありませんが、できそうなことなのでいずれチャレンジしたいと考えています

コード

こちらからダウンロード可能です

ライセンス

MIT