LazyAdamOptimizerを見てみた
見てみた
概要
Adam Optimizerの sparse更新をより効率化したもの。
既存のAdamアルゴリズムは2つの移動平均の各train variableに対して行います。 計算はすべてのStepで更新されます。 このクラスは sparse variableに対して勾配更新の緩やかな処理を行います。 すべてのインデックスのアキュムレータを更新するのではなく、 現在のバッチに含まれるスパース変数インデックスの移動平均アキュムレータのみを更新します。
オリジナルのAdamオプティマイザと比較すると、一部のアプリケーションではモデルトレーニングのスループットが大幅に向上しています。
ただし、元のAdamアルゴリズムとはわずかに異なるセマンティクスが提供されているため、異なる経験的結果が生じる可能性があります。
詳細
lazy_adam_optimizer.py
では、Adam Optimizerから2つの関数のみoverrideしている。_apple_sparse
※こちらを例に以後違いを説明します。- _resource_apply_sparse
_apple_sparse
Adam Optimizerでは以下のように関数を呼んでいる。
LazyAdam Optimizerでは*\_shared
関数は呼んでいない
def _apply_sparse(self, grad, var): beta1_power, beta2_power = self._get_beta_accumulators() beta1_power = math_ops.cast(beta1_power, var.dtype.base_dtype) beta2_power = math_ops.cast(beta2_power, var.dtype.base_dtype) lr_t = math_ops.cast(self._lr_t, var.dtype.base_dtype) beta1_t = math_ops.cast(self._beta1_t, var.dtype.base_dtype) beta2_t = math_ops.cast(self._beta2_t, var.dtype.base_dtype) epsilon_t = math_ops.cast(self._epsilon_t, var.dtype.base_dtype) lr = (lr_t * math_ops.sqrt(1 - beta2_power) / (1 - beta1_power)) # \\(m := beta1 * m + (1 - beta1) * g_t\\) m = self.get_slot(var, "m") m_t = state_ops.scatter_update(m, grad.indices, beta1_t * array_ops.gather(m, grad.indices) + (1 - beta1_t) * grad.values, use_locking=self._use_locking) # \\(v := beta2 * v + (1 - beta2) * (g_t * g_t)\\) v = self.get_slot(var, "v") v_t = state_ops.scatter_update(v, grad.indices, beta2_t * array_ops.gather(v, grad.indices) + (1 - beta2_t) * math_ops.square(grad.values), use_locking=self._use_locking) # \\(variable -= learning_rate * m_t / (epsilon_t + sqrt(v_t))\\) m_t_slice = array_ops.gather(m_t, grad.indices) v_t_slice = array_ops.gather(v_t, grad.indices) denominator_slice = math_ops.sqrt(v_t_slice) + epsilon_t var_update = state_ops.scatter_sub(var, grad.indices, lr * m_t_slice / denominator_slice, use_locking=self._use_locking) return control_flow_ops.group(var_update, m_t, v_t)
の箇所だけを比較すると
- Adam Optimizer
# m_t = beta1 * m + (1 - beta1) * g_t m = self.get_slot(var, "m") m_scaled_g_values = grad * (1 - beta1_t) m_t = state_ops.assign(m, m * beta1_t, use_locking=self._use_locking) with ops.control_dependencies([m_t]): m_t = scatter_add(m, indices, m_scaled_g_values)
- LazyAdam Optimizer
# \\(m := beta1 * m + (1 - beta1) * g_t\\) m = self.get_slot(var, "m") m_t = state_ops.scatter_update(m, grad.indices, beta1_t * array_ops.gather(m, grad.indices) + (1 - beta1_t) * grad.values, use_locking=self._use_locking)
となっている。
LazyAdamで使っている scatter_update はindices
の部分(sparse)のみ更新する関数
そのあと v_t
も同じように計算し
m_t_slice = array_ops.gather(m_t, grad.indices) v_t_slice = array_ops.gather(v_t, grad.indices)
切り取って
denominator_slice = math_ops.sqrt(v_t_slice) + epsilon_t var_update = state_ops.scatter_sub(var, grad.indices, lr * m_t_slice / denominator_slice, use_locking=self._use_locking)
更新値を算出。
まとめ
Moving-Averageの計算において、部分な値にて計算しているだけみたい。
(一部 addから updateの変更も合っているけど)
参考
初Kaggle体験記
Kaggleのコンペを初めてやったので、その体験記。
参加したコンペは
結果は残念ながら、791/1304位(※現時点では未確定)ぐらい。
でも、初めてやったなりに面白かったので書きます。
※機械学習初心者です。
概要
↑こんな感じでスコア遷移してました。
最高が0.8892
だったので、公開Kernelより低いのでぉぃぉぃって感じですが
自分でやった際にはこんな感じでした。
やってきたトピックをあげるとすれば、以下のような感じです。
それぞれ書いていこうと思います。
- 1.CPU メモリの壁
- 2.GPU メモリの壁
- 3.実行時間の壁
実行環境
自分の手持ちパソコンのスペックが低すぎて、時間制限あるなかでの無料枠トライでした。
(次回はパソコン買って出直すぞ)
1.CPU メモリの壁
初めてなので、Kernel見ながらやり方を学んでた。
CNNで判別しようと考えていたので、データは simplifiedのほうを選択して、
csv→suffle→imageという流れでtrainデータを作ろうとしていたらメモリオーバー。。。
判別が340種類で、1種類あたり10万を超えるデータ数でsuffleする前からアウトオブメモリ
Kernelや自分も試してみてだいたい、3万くらいが上限だった。
Kernelでは suffleして tar.gzにしているやり方があったけど今にして思えば真似しとけばよかったかなと。
その当時はGoogle Colabのほうがメインで、Kaggle Kernelで人のデータを使えることを知らなかった。
最終的には、1種類あたり1-2万のデータ(計340-640万)で学習させました。
2.GPU メモリの壁
モデルはMobileNet v2を使用。
当初、画像サイズ64x64で 1種類当たり500のデータをtrainデータへ
batchsizeは32
→ ココらへんが最初の頃の50%前後の遷移。。。
認識率が上がらないので、どうしたものかと思っていた。
施策として
- データを変える
- データを増やす
- 画像サイズをを大きくする
- batchsizeを増やす
- モデルを変える
データを変える
データには「Recognized」というフィールドがあり、Trueでフィルタを変えたほうが良いというのがKernelに上がっていたので試した。
結果、あんまり変わらないかった。
データを増やす
trainデータ多くすると、メモリが溢れてしまった。。。
画像サイズを大きくする
trainデータ多くすると、メモリが溢れてしまった。。。
fit_generator との出会い
WebではClassを作るような記事が多かったが、私は関数のみで書いてた。
def data_generator(): while True: #なんかしらのデータ生成 yield x,y model.fit_generator(generator=data_generator(), ...
これでbatchsize分だけ容量となり、画像サイズ:128x128, batchsize=256までいけるようになった。
(Kaggle Kernel)
→ 最高70%近くまで遷移
3.実行時間の壁
Kaggle Kernelは 6h
Google Colabは 12h?
と時間制限があるので、どうしても長時間学習することが難しかった。
(つらい)
Google Colab(TPU)
11/8 に参加した TFUG 福岡 #2 (2018/11/08 19:30〜) で、TPUについてあったので試してみた。
コメント部分は、TPUにするために書き直した部分。
Kerasからの変換は制限があるもよう。
fit時のcallbacksも指定なしにしないといけなかった。
# TPU tpu_model = tf.contrib.tpu.keras_to_tpu_model( model, strategy=tf.contrib.tpu.TPUDistributionStrategy( tf.contrib.cluster_resolver.TPUClusterResolver(tpu='grpc://' + os.environ['COLAB_TPU_ADDR']) ) ) def top_3_accuracy(x,y): return keras.metrics.top_k_categorical_accuracy(x,y, 3) tpu_model.compile( # optimizer=tf.keras.optimizers.Adam(lr=0.002), optimizer=tf.train.AdamOptimizer(learning_rate=0.002, ), loss=tf.keras.losses.categorical_crossentropy, # metrics=['accuracy', top_3_accuracy] metrics=['accuracy'] )
TPUにしたことで、画像サイズも256x256にできbatchsizeも1024まで増やせた。
(今思うと画像サイズそこまで必要だったかは不明)
そのおかけで、認識率は 80%以上を超えて、90%近くまでいった。
それ以降、3epochぐらい実行するとcolabが再接続するという謎の現象にあってしまいスコアあがらず。。。
過学習にもなってきて、どうしたものかと思って試したのが、
ImageDataGenerator
教師データを水増ししてなんとかならないかと。。。
data_generatorに埋め込んだ。
datagen = ImageDataGenerator( rotation_range=20, width_shift_range=0.2, height_shift_range=0.2, horizontal_flip=True) def data_generator(batchsize): #なんかのコード for img in datagen.flow(x, batchsize=batchsize)
結果は後半の劣化の結果となってしまった。
Google Colabで再接続が頻繁に起こらなければ。。。と思いつつ無念な結果に。
やってた状況は 昼間はKaggleやれず、作業は夜のみで夜投入して朝確認の繰り返しだったので 途中エラーや再接続とかなると1日がパァーになった。
まとめ
- Kaggle楽しい
- KernelやDiscussion読んでて色々ためになった
- 自分で環境揃えないと厳しい><
- fit_generator 良い
- ImageDataGenerator 楽
- 高スコアのモデルや手法を知りたいので暫く待とう
- Kaggleも昼間にやれる職に変えたい
次回、別コンペでリベンジです!
UVMをRISC-Vプロセッサの検証に
AI/ML関連の気になったやつ(2018/06/06)
個人用メモで、気になったやつをリスト。
記事の日付などは気にしてません。
イベント&資料
News & Blog
「自分に合う靴」AIが提案 靴と足の3Dデータをマッチング
3Dスキャンした足のデータを基に、AI(人工知能)が自分に合う靴を選んでくれる――そんなサービスを可能にする技術を、フリックフィット(東京都目黒区)が開発した。
いいね。AIで女性の顔の“魅力”も数値化――東大で研究中の「魅力工学」とは?
VIMを使い...
学生(大,高,中)になりたい。東京都港区役所にAI音声認識活用の議事録作成支援システム - アドバンスト・メディア
アドバンスト・メディアは、同社のAI音声認識活用の議事録作成支援システムが東京都港区役所に採用
AI EXPOで気になってたやつだ。- AIベース車載SoCの開発を促進する、ASIL D対応ビジョンプロセッサを発表
シノプシス(Synopsys)は2018年5月17日、ADAS(先進運転支援システム)や自動運転車用SoCの開発向けに、自動車向け機能安全規格ISO 26262の安全要求レベルであるASIL(automotive safety integrity level)のB~Dまでに対応するビジョンプロセッサ「DesignWare EV6x Embedded Vision Processors with Safety Enhancement Package(EV6x Processors with SEP)」を発表した
arXiv.org > cs
その他
Google Colab:darknet/YOLOを動かす
Google Colaboratory で試してみたシリーズです。
今回は YOLO: Real-Time Object Detection の
フレームワークである darknetを動かします。
試したコードはこちらに公開しております。
今回、推論ですが学習もできるはず...ですよ!