手書き数式認識ソフト、tegashiki開発その6
前スレ
- 手書き数式認識ソフト、tegashiki開発その1
- 手書き数式認識ソフト、tegashiki開発その2
- 手書き数式認識ソフト、tegashiki開発その3
- 手書き数式認識ソフト、tegashiki開発その4
- 手書き数式認識ソフト、tegashiki開発その5
ここでやった事概要
- これまでより複雑な、データセットパターン2を作る
- 線形計画法の勉強をする時に出てきそうな数式の多くをサポートする事を目指す
\mathbb{R}
のデータセットを(頑張って手作業で)作る- データセット生成の為のパーサーコンビネータスタイルのDSLをPython上に作る
- BatchNormalizationの移動平均が更新されてないバグを直し、ブログにやり方をまとめる
- L2 Regularizationが効いてない事をつきとめ、修正の方法をブログにまとめる
- Conv S2Sベースのモデルでそれなりに動くものが出来たので実機に載せる
- layer_normの指定で教師データの未来の入力をカンニングしていた事を突き止め修正
- Transformerを自力で書いて実機に載せる
- アプリの側にクリップボードへのコピーを実装した
いろいろと問題を突き止めて修正する、という事をしていた期間だった。
2019/07/05
次のデータの生成はなかなか考えるべき事が多い事に気づく。 手を動かす前に何が要るかをもう少し考えるか。 とりあえずここまでをブログにして公開しておこう。
見直していたらkotlinのテンソル処理のブログをもうちょっとちゃんと書き直したくなったので書き直しておく。
2019/07/07
二日くらい考えてみて自分の中でやる事を整理した。 まずmathbb Rのトレーニングデータを作る為のアプリを作ろう。
これはとりあえず入力の楽さが最優先、ただ今後も発展させていく前提な感じで作りたい。 とりあえずファイル名のprefixを書いて、あとはひたすら入力していく、みたいなUIにするかな。
出来た。17件ほど入力してみて結果を見てみたが悪くなさそう。
細かいUIの調整をして、とりあえずこんなもんか、という物までは出来る。 我ながらこういうの作るのめっちゃうまいな。
ひとまずmathbbなRをひたすら入力していこう。 100件くらいあればいいか?
とりあえずmathbbはRでしか使わないので、\mathbb{R}
全体で一つのトークンとみなそう。
一日他の事をやりつつたまの息抜きで入力してみた。たぶん70件くらい作ったかな。 アプリの出来が良いので(自画自賛)、1000件くらいは頑張れる気もするが、まぁ足りないと思ったら足そう。
2019/07/08
mathbb Rの前処理をしてcloud storageに置いて、データ生成でもするか?という段になり、 ここらでfeature extractorも作り直しておくか?という気分になる。 tensorflowが前のバージョンなのとis_trainingのハンドリングを間違えていたのを直したいので。 直すか。
一通り直してfeature extractorのトレーニングを走らせ直す。 feature extractorはシンボル一つを予測するモデルで作っているのだが、本来はmathbb Rも混ぜるべきなのだろうな。 面倒なのでそのままで流したが。
少しcolabが混乱しているので軽く整理しつつ進める。
あれ?BatchNormalizationにis_trainingを立てるようにしたら初期のスコアが以前より悪くなった。 どういう事だろう?別にNoneでtrainingしてもいいんだが、理由は知りたいな。
ただ回しているとロスは落ちていってるようなので、しばらく流してみるか。
fe_trainifix_v1_14 acc 0.51 https://bit.ly/2LflqcL
ダメそう。コードを読んでいると、分散回りでNoneの時は挙動が違いそうだな。 そうか、バッチサイズはper coreで動くのか。 とググってると、そんな記述を発見。
https://cloud.google.com/tpu/docs/troubleshooting
1024くらいあれば大丈夫、と言っているが、とりあえず8x256にしてみよう。2048か?メモリ足りるか分からんが。
fe_trainifix_batch8x256 acc 0.5
ダメらしい。うーん。
なんかTPU用のBatchNormalizationにはfusedというのがある。 これはパフォーマンスに良いとの事だが、TPU用なんだから動作的にも良く検証されているんじゃないか。 TOCOで動くかはなんかググった感じ動きそうだが良く分からないのであとで試すとして、これもやってみるか。 batch sizeは大きいままで。
と思って引数を確認すべくドキュメントを見てたら、BatchNormalizeの移動平均はkerasのfit使わない時は自分でやれ、と書いてある! https://www.tensorflow.org/api_docs/python/tf/layers/BatchNormalization
あれ?前見た時はそんなの書いてなかったぞ?とみてみたら、こっちには書いてない…
https://www.tensorflow.org/api_docs/python/tf/keras/layers/BatchNormalization
まぢか!?
tf.contrib.training.create_train_opを使えば良い、という例をちらほら見かけるな。例えばここ。
https://colab.research.google.com/github/tensorflow/tpu/blob/master/tools/colab/mnist_tpuestimator.ipynb?hl=id#scrollTo=M9s9yHq7jMCV
まぁいい。やってみよう。
fe_movingavg_fix acc 0.42
まったく変わらない。 コードを読んでると、tf.layers.BatchNormalizationとtf.keras.layers.BatchNormalizationは結構コードが違うな。
GRUとかはtf.keras.layers下を使わせるくせにBatchNormalizationはこっちのを使っちゃダメとかあるのか?もしあったらそれは酷い罠だなぁ。 とりあえずtf.layersの下のBatchNormalizationを使ってやってみよう。
fe_layersbatchnorm acc 0.85
https://bit.ly/2NPyxDc
よし、改善した。しかも劇的に。これは酷いなぁ。まぁ原因が分かれば回避は出来るので良しとしよう。
TPUEstimatorを使ったBatchNormalization回りの注意まとめ
- kerasのconvertは入力回りで柔軟性に欠けるので現時点では使わない方が無難
- ただしtf.keras.layers自体はtensorlfowの関数として使っていける。tf.placeholderを食わせてfunction APIっぽく使っていく。RNNとかはこれを使っていく。
- しかしBatchNormalizationはfitの処理にmoving averageの更新が依存していて、これは上記の使い方では動かない
- だからtf.keras.layers下では無くてtf.layers下のBatchNormalizationを使う
- さらにtrain_opを作る所でこれを更新する処理も追加で行う、tf.contrib.training.create_train_opを使う
create_train_opの例はtpu_model_fnで以下みたいな感じにする。
train_op = tf.contrib.training.create_train_op(loss, optimizer)
return tf.contrib.tpu.TPUEstimatorSpec(mode, loss=loss, train_op=train_op)
2019/07/09
昨晩流したfeature extractorのトレーニング、微妙にスコアが改善し続けている。 傾き的には無視出来るのでもう止めてもいいのだけど、feature extractorは使い続けるものなのでもうちょっと回しておくかなぁ。
なんかさっきから、トレーニングが途中で無限ループに入る?ステップが3000くらい進んだ所で進まなくなる。 なんだろう?止めて流しなおすとまた3000くらい進むがそこで同じ現象になる。 まぁいいや。流したままで掛けよう。 スコア的にはもう十分なので、このまま止まってたらそこまでにしておくか。
帰って来たら止まってたが、献血帰りでちょっと休憩したかったのでもう一回流す。今度はうまく行く。なんかcolab側が不調だったっぽいな。
散歩しつつ、データ生成にはそろそろDSLを作りたいな、と結論づける。 とりあえず作ってみつつどんなのがいいか考えてみよう。
NumCharF = OrF([0.8, Char], [0.2, NumF])
TwoTermF = SeqF(NonZeroNumF, NumCharF)
SubTermF = SubF(CharF, NumCharF)
SupTermF = SupF(CharF, NumCharF)
OneTermF = OrF(
[0.3, TwoTermF],
[0.3, SubTermF],
[0.3, SupTermF]
)
TrainingSetF = OrF(
[0.6, EqF(BinF(OnTermF, OneTermF))],
[0.1, SupTermF]
[0.1, SubTermF]
[0.1, TwoTermF]
[0.1, OneTermF]
)
こんな感じで書けるようにしたいな。 最後にTrainingSetFをどう実行するかは良く分からんな。
終端記号との区別は必要そうな気もするな。
2019/07/10
とりあえず数字二つ並べる、というケースを作ってみて、DSLの仕様を固めた。 サンプルを一つ返す関数と、その関数を生成する関数は区別する必要があり、前者をxxS、後者をxxFと呼ぶ事にした。 Sはsampler、Fはfactory。
出来上がれば良さそうだが、用意するのはまぁまぁかったるいな。 ただ今回生成するトレーニングセットは結構複雑だからなぁ。この位作っても同じくらいの労力か。 次回以降を考えればここで作っておくのは妥当な気がする。
とりあえず前回作ったデータセットに関しては作ったコードがある、というのは大きいな。 これをDSL化していく形で進められるのは、何を作るのか分からない状態でこの辺整備してしまうリスクを回避出来ている。
イコールとかまで作ってみたがちょっとこれは人間でも辛い感じのデータだな。 やはり記号は小さくないとなぁ。あとイコールとかは項と等間隔だと認識しづらいな。普通は少し離れてるんだろうな。
そしてなんかたまに項の大きさが結構違うデータが出てるな。normalizeしてるんじゃなかったっけ? >してなかった
ちょっとこの辺考える所から始めよう。
2019/07/11
センタリングするのと、少し横にずらすのと、演算子は60%のサイズにする、という変更を入れたら割と読めるようになる。
コードを整理して実際に書いてみる。
うーん、+-の頻度が高すぎるな。レアな物の出現頻度はもっと低くていいよなぁ。 mathbb Rが指数の肩に乗るケースとか無いよなぁ。 mathbb Rは特別扱いするか。
不等号よりは等号の方が多い方がいいよな。この辺の分布は細かく制御するか。
500kほど生成してみて、4分くらいでハードディスクは800Mbとか。結構でかいな。 TF Recordに変換するのは明日にするか。
2019/07/12
データをチェックしつつTF Recordに変換する。途中numpy arrayをがばっと取ってた所でメモリ不足で落ちるので、 最初は二分割にしてみたが、素直にgeneratorに直す方が後の手順が楽だな、と思いgeneratorに直す。
一通り変換も出来たのでトレーニングしてみよう。初のpattern 2。
新しいfeature extractorでのトレーニングも初なので初めてづくしだな。 新パターン用のハイパーパラメータを考えよう。
MAX_TOKEN_LENが12なのでデコーダーのカーネルのサイズを12にする。 MAX_STROKE_NUMが22なので、エンコーダーは5層になってるのでカーネルサイズは5にすれば5*5で22より大きくなるな。
ベースラインとしてはこれが一番シンプルなモデルだよな。
plain_encdecatten_pat2
https://bit.ly/2G9Xgfj
データ数増えたのでトレーニングにかかる時間が増えたなぁ。データ数は倍だが、なんか倍以上かかってるような? まぁシャッフルされているので別に1 epochで進む量も増えているはずだから、多すぎて困る事も無いはずだ。
これでそこそこのスコアが出せれば最初の最低限ドッグフード出来ない事も無いモデルとなる。 そこそこのスコア出すのも大変だろうが、それでも最低限使えない事も無い程度の限定された物、というのが道のりの長さを表しているな。 むしろこのサブセットを切るあたりはプログラマとしての腕だよな、と自画自賛。
ちょっとここまでやった事を整理しないとなぁ。 この整理の手間、もうちょっと減らせないかねぇ?
モデルとDSLのgistを作る、というのがやらなきゃいけない事なのだが。
おっと、train_opのmoving average更新fixするの忘れてた。やり直し。(モデルは一緒)
plain_encdecatten_pat2_trainopfix acc 0.882
帰って来たらまだインスタンスが落とされてない。珍しい。そして現在のacc 0.796。結構いいね。 まだ改善しているので0.8は超えそう。とりあえず動かす事は出来るレベルだな。 これは想像以上のスコア。よしよし。
dataset pattern 2
https://bit.ly/2XDweTy
比率としては以下。
- other 0.5
- OneBinopOneS 0.2
- EqExpS 0.3
EqExpSが一番複雑な式でこれさえ解ければ全部解けるだろうが少し難しすぎる気もする。という事でこの比率。
otherは以下の比率。
- OneSymbolIS 0.3
- SubS 0.2
- SupS 0.2
- TwoTermS 0.2
- RnS 0.05
足して1になってないがそれは構わない仕様となっている。(あくまでsamlingのweightなので)
2019/07/13
なんか昨日流したモデル、まだ微妙にロスが下がっているなぁ。 データセットが増えたのでオーバーフィッティングしづらくなった結果か。 ここまで長いと毎回限界まで回すのは辛いな。 今回は初なのでしばらく回してどこまで行くか調べたい。 なお、現在のaccは0.82。まぁまぁ良い。
ついでにバッチサイズ増やし忘れてたのでこっそり今朝から8x64に増やしておく(前は8x32)。 移動平均の計算に影響があるが、まぁ大した事無いはずなのでよかろう。
ふと思ったが、 a + b = c
はあっても b = c
が無い気がするな。
これも入れておかなきゃいけなかった気がする。
まぁ一シンボルがあるのでとりあえず一文字ずつ書く、でなんとかやれるか。
一日回しているがまだ収束しない。現在accは0.837。あんまり改善幅も無視できないよなぁ。
2019/07/14
一晩回したらさらに傾きが急になって改善が続いてる!まぢかー。 現在のaccは0.856。0.9くらいまで行けばこの問題は解けたと言って良いと思う(データセットの質が悪いのでその位は人間でも解けないのが混じってる)。 思ったよりこのモデルで行けるもんだな。
暇なので今回のデータ生成DSLをネタにブログを書く。
Pythonでトレーニングセット生成にコンビネータスタイルの言語内DSLを作る
2019/07/15
まだ上がっているので流しておく。スコア的にはこの位ならもうドッグフード出来そうね。 試行錯誤で毎回これだけ流すのは無理だが、一回どこまで行けるか見ておく必要はあるだろう。
ようやく止まった風味だが、もう夜だしもうちょっと回して確かに下げ止まっているのを確認したいのでもうちょっと流しておく。
Tensorboardをcloud shellから見る、という作戦を思いつき実行中。これはいいね。colabからよりも断然快適だな。
2019/07/16
二日流して1.5M epocくらいでようやく収束。(1.15Mくらいで収束している) スコアはacc 0.88くらい。なかなか良いね。
実機に載せてみたら全然ダメ。まずはデバッグだな。
実機ではまずかなり遅くなった。原因は理解しておきたい。
colab上のTFLiteでは正しいpredictが出来ているな。
なんかdecoder_inputで未来の値が悪影響を与えている?causal paddingになってないのだろうか。 試しに0で埋めてみよう。治った。
うーん、コードを見直すがやはりデコーダーはcausalになってるけどな。 attentionで未来が染み出しているのか? モデルがバグっているんだろうが、とりあえず動いてはいるのでもう少しつついて挙動を見てみよう。
トレーニングセットで見た事無いものはpredict出来ないな。 例えば3x+yはpredict出来るが3x+はpredict出来ない。 ちょっと面白い。
この速度では使い物にならないので非同期化をやらんと試す気が起こらないな。
2019/07/18
昨日は期日前投票に行ったりしていたのとflow関連のドキュメントを読んだりしてお休み。
今日は非同期化を実装してみる。 flowで実装しようとしてみたが、結局UIのイベントは本質的にhotなストリームなのでflowは使う意味がない、という結論になって素のチャンネルの実装になった。
無駄な時間は過ごしたが、flowの現状は理解出来たので良しとする。 非同期にするだけだと計算中かどうかが分からないのでいまいちだが、とりあえず使えはするのでこれで良しか。
2019/07/19
pattern 2の問題点もいろいろ分かってきたが、とりあえずモデルの方も少し他のを試してみよう。 とりあえずencoderをself attentionにしてみる。
encselfattn_pat2 0.78
https://bit.ly/2xVqqua
6時間経過してacc 0.78。まだ伸びそう。ペース的にはCNNのencoderとあまり変わらないな。
2019/07/20
なんと、オーバーフィッティングしてしまった。training lossは同じくらいの水準により早く到達しているのだが。
トレーニングのデータセットの性質上、どうやったらオーバーフィット出来るのかがいまいちよく分からない。 データ数は結構多いし、texのパターンは単純なのでトレーニングセットもvalidation setも同じ物がたくさん出てくるだろうし。
実装としては、公式との違いは
- dropoutが無い
- multiheadじゃない
- decoderがConv
くらい。三つ目が一番怪しいがちょっと実装が大変。 オーバーフィットという事でまずdropoutを試すか。drooutはrateが0.1と言っているので、あんま効かなさそうな気もするが。
encself_dropout01 0.811
https://bit.ly/32FaIld
ついでにdecoderの未来の入力が効いてしまっている問題、activity_regularizerじゃないかな、という気がしてきた。 ただこの辺いじるとオーバーフィットには影響があるはずなので、今のself attention回りのトライアンドエラーが終わってから試す。
世の中のtransformerの実装を見てると、paddingを無視するマスクも作っているな。 RNNなんかだと経験上別にそういう特別扱いしなくても勝手によきにはからってくれるので不要と思うんだが。 トランスフォーマーだと違うかもしれないし、どちらにせよそろそろDecoder側も用意したいのでマスク処理は必要になるから、その辺入れてみてもいいかもしれない。
2019/07/21
結局encoderをself attentionにしたバージョンは0.81くらいで落ち着いた。 convolutionが0.88くらいまで行った事を思うと大分低い。 dropoutは効いている気もする。
勉強会でなんかオーバーフィットするんですよね~といったら、self attentionの方がパラメータ数多いんじゃないか?と言われて、コードを見直す。 自分の認識では系列の長さが効かないのでパラメータ数は減ると思っていたのだが、コードを見直すとdenseになっている。
あれ?確かにこれではパラメータ多いが、atetntionってそういう物だっけ?と元論文とか見ると、 attentionのコードがバグっている気がしてきた。 conv1Dをかませるべき所で、Denseをかませてしまっている気がする。
いや、やっぱりあってた。
https://stackoverflow.com/questions/54805345/can-i-use-a-3d-input-on-a-keras-dense-layer
flattenは最初の方の次元に適用されるのでこのコードであってるね。
とりあえずdropout 0.5で流しておこう。
encself_dropout05 0.789
2019/07/22
どうもソースコードを読んでいたら、regularizerのlossはadd_lossが呼ばれるだけで、これをminimizeしてないから効いてない気がしてきた。 そしてtf.keras下では適当なコレクションに追加してないので、lossを集める方法も無さそう。 一方でtf.layersの下の方はadd_lossを細工してコレクションに追加している。
という事で、tf.layersの下を使ってこのロスを加えないと、regularizationは効いていない(!)という結論に。 これまで試していたのは無駄だったか。
あと、decoder_CnnWithAttentionBlockの最後にカーネルサイズ1のConv1Dをかませているが、これはようするにDenseだよなぁ。 さらにこのDense、要らない気もする(そのあとにDenseがあるから)。 同じセットアップで無くしてスコアが変わらないのを確認したら、直そう。
2019/07/23
dropout 0.5はまだ微妙にスコアが改善しているのでもう少し流してみる。 ただだいたい0.78くらいに収束しそうなのでやはりこれはダメだね。
2019/07/26
dropout 0.5は結局 0.78くらいに落ち着いた。 ダメ。
今日はself attentionの前に、convの方で気づいたregularization効いてない問題を直してみるか。
まずブログにここまで調べた内容を書いてみる。 このレベルの内容を日本語で書いても読む人いない気はするが、自分の為のメモという事で。
TPUEstimatorでのregularizationとtf.layersとtf.kerasについて
ちょっとregularization効きすぎな気がするなぁ。L2 regularizationは0.01にしてみよう。 パラメータ数に依存しているならこれでもダメな気がするが(長さで割る方がいいか?)
ついでにdecoderのactivationのregularizerは外しておこう。未来の物の影響がしみだしたりしたら嫌なので。
plain_encdecatten_pat2_regfix_reg001 https://bit.ly/2Y90bjB
あまり変わらないなぁ。とりあえずしばらく回してみよう。
やはり最初のロスがでかすぎるな。やはりパラメータ数で割る必要はあるよな。 とりあえず開幕のロスがこれまでのロスの近くになるように、1e-5をregularization lossに掛けてみよう。
plain_encdecatten_pat2_regfix_reg001_div1e5 0.868
2019/07/27
regularizationを入れたらいい感じに学習の速度が改善している。 まだ回し足りないが限界まで回してみるべきか、この辺で終わりにして違うモデルに進むべきかはよく分からないな。 とりあえずもう少し回して様子を見るか。
2019/07/28
まだ回し足りないが、だいたい同じくらいは行きそうなのが分かったのでここで止めるか。 0.868くらい。
regularizationは動かせそうなので、次はmultiheadのattentionを実装してみようか、という気になる。 例によってencoderだけ。 既存の実装はたくさんあってコピれば使えそうではあるが、微妙に取り回しが悪いのが多いので自分で作ろう、という気にはなっている。
ついでにL2は全体に1e-5を掛けたりする小細工は無くして、個々のを1e-6とかを指定するように変更。
とりあえずencoderだけmultihead attentionにするモデルが出来た。
encself_multihead
https://bit.ly/2OnYtXb
なんか学習が全然進まないな。マスクがバグってるか?公式実装と少し違う所があるので公式実装と同じにしてみよう。
encself_multihead2 acc 0.86
https://bit.ly/2LM68w5
お、なんか進み始めた。なんでこれが正しいのか良く分かってないがまぁいいか。進めてみよう。
2019/07/29
convよりちょっと悪いくらいで落ち着きつつあるが、まだ微妙に改善していそうなのでもう少し回す。
考えてみると、self attentionでもmask要りそうだな。これまで無しだったのは間違いか。
夜まで回してオーバーフィットを確認。 微妙にconvより悪いがdropoutとか工夫すれば同じくらいまではなりそう。 それなりに悪くは無いが、良くも無い、くらい。頑張ればconvは超えられそうだがこれを超えても仕方ないので頑張る必要は無いかな。 ただself attentionは動いてそうな気はした。
次はdecoderもtransformer型にしよう。 ついでにDenseで良い所はDenseに直そう(bertの実装にあわせる)。 bertは素直な実装でいいね。
2019/07/31
どうもdecoder_inputの未来のトークンを見てしまう、という事でデバッグをしていくと、 layer_normでやはり未来の入力の影響がしみだす。
bertも同じ事は起きているはずなので本家のtensor2tensorの実装を見直そう、と見直す事に。
transformerは以下で、decoderもここにある。
https://github.com/tensorflow/tensor2tensor/blob/95866303475da15ca30366a9266041504a63fc62/tensor2tensor/models/transformer.py
decoderを先頭から追う。
transformer_decoderがdeocderで、そこでは単純にtransformer_decoder_layerがレイヤーの数だけ呼ばれている。 transformer_decoder_layerではmultihead_attentionしてlayer_post_processが呼ばれている。
mask用のbiasは最終的には以下で用意されている。
https://github.com/tensorflow/tensor2tensor/blob/95866303475da15ca30366a9266041504a63fc62/tensor2tensor/layers/common_attention.py#L917
query_segment_idに何が入るかは追ってないが、0, 1, 2, 3…という数字が入るのかな。
layer_post_processは以下だが、 https://github.com/tensorflow/tensor2tensor/blob/95866303475da15ca30366a9266041504a63fc62/tensor2tensor/layers/common_layers.py#L862
引数で文字列で渡された物に応じて行う。nが行われるかが焦点か?
tensor2tensorでのtransformerはたとえば以下か?
https://cloud.google.com/tpu/docs/tutorials/transformer
translate_ende_wmt32k_packedというのを指定している。 だがそんなものは検索したら無いな。なんか組み立てられるのか?
hparamsのlayer_postprocess_sequenceで指定されるっぽくて、それはこの辺で入っている。
https://github.com/tensorflow/tensor2tensor/blob/099cec7c23169145fa026472f7037a85fc4afd7f/tensor2tensor/layers/common_hparams.py
transformer_base_v1とかにはnは入ってそうかなぁ。 ちょっとnの処理を追うか。
apply_normが呼ばれるが、これに渡すnorm_typeが重要そう。これはhparamsのnorm_typeだな。 これはlayerか。
layer_normはこれか。 https://github.com/tensorflow/tensor2tensor/blob/95866303475da15ca30366a9266041504a63fc62/tensor2tensor/layers/common_layers.py#L716
layer_norm_computeが呼ばれて、結局activationのreduce_meanとvarianceのreduce_meanを計算しているように見える。 https://github.com/tensorflow/tensor2tensor/blob/95866303475da15ca30366a9266041504a63fc62/tensor2tensor/layers/common_layers.py#L698
うーん、maskっぽい処理をしているようには見えないけどなぁ。
自分のコードを確認していった所、layer_normの手前まではちゃんとマスクが効いている。 layer_normを入れるだけのself attentionのみで満点が取れてしまうので、やはりこれで未来の情報が漏れているっぽい。
ただ、attentionの後はembedで元に戻している。ここはTimeDistributedなDenseを挟んでたがこれはやりすぎかもしれない。 という事でこれはTransformerに合わせておく。
やっぱり治らないので、layer_normに、Tensorflowオフィシャルの実装を持ってきて試したら、なんかそれっぽいスコアになった?
お、答え無しのケースでもちゃんと動いているな。よしよし。 ただスコアはConvS2Sとそんな変わらんね。もう少し回してみる。
transformer_laynorm acc 0.86 https://bit.ly/2YAD2pE
オーバーフィットを確認したので止めておく。 スコア的にはConvS2Sに負けているが、向こうはバグで未来のトークンをカンニングしている可能性があるので、一旦これを実機に載せて評価してみるか。
実機で試したら一気に良くなった。やはりConvS2Sは未来のトークン見ちゃってた感じだな。 という事でスコア的にはこちらが低いが、向こうのスコアは間違っていたので実際はこちらが最強モデルという事になった。 この精度なら十分実用になるね。
モデル的にはこれでいいかな。 もうちょっと段数減らして速度上げられないか、とか試したい事もあるが、まぁとりあえず今のモデルで使っていこう。
データセットを作り直せば実用になるレベルでは動いているな。 使ってみたいが、最近数式書く物読んでないんだよなぁ。
2019/08/01
layer_normのコードを見直していると、どこのdimに対してとるかが指定できるな。 bertのコードを見直してみると、これを最後に指定している。真似してみよう。
transformer_laynorm2 acc 0.862
https://bit.ly/33elLSG
だいたい良さそう。やはりそういう問題か。 そしてTransformerは圧倒的に学習が早いな。性能もいいし学習も早いしシンプルだし、いう事無いな。 いや、サイズがちょっと大きいか(TFLiteで47MBとか)。4MBくらいになると嬉しいんだけどなぁ。
ついでにアプリの方も、入力のトークンと同じ所までは確定として扱うように直してみよう。 こうする事で、追記していく時のpredictの回数を減らせられると期待出来る。
まぁまぁ早くなったな。
次はコピーとundoを実装か。そこまで行けばとりあえず使う事は出来るな。 最終的にはライブラリとして作ってノート取りアプリに組み込むつもりだが、まずは単独アプリで使ってみる所からか。
クリップボードを実装した。 undoはやる気が出ないので静岡から帰ってきてからにしよう。
明日から静岡に遊びに行くので、その前にここまでをブログに公開しておこう。
Quantized Transformerというのがあるのか。帰ってきたら試そう。
2019/08/02
cloud shellからtensorboard使うとinter regionのコストがかかっていて8USDくらいとられてる。めちょっく!(元ネタ知らんけど) 当分はngrokで頑張るかねぇ。
当初は今日の午前中に出発予定だったが、なんか連れの出発が遅れるとの事で午前中が暇になった。 undoの実装に取り掛かるかなぁ。
途中までやったが、思ったよりも戻すべき状態が多いので、StrokeTrackerのundo-redoのロジックを書いた所で中断しておく。 帰って来たらPredictAnalyzerのあたりのundo-redoを書こう。
2019/08/07
別件をやってたので少し日があいた。思い出しながら続きをやっていこう。undoを作ってたらしい。
だいたい構成要素のundoの実装が終わったので全体をつなげようと思ったら、非同期な場所が多くて意外と難しい。 ストロークが終わった時点で保存すべき事と、predictを行う時点で保存すべき事がある。 間をチャンネルでつないでて多対1で、あまり裏のスレッドで動くものを安全でない所で触りたくはない。
本質的にはストロークの情報だけちゃんと保存しておけばpredictはやり直す事は出来るのだが、ちょっと待つんだよなぁ。
何にせよ、ストロークの情報の頻度とpredictの結果の頻度は違うので、UndoListに入れる時には区別しないといけないんだな。
少しやってみてが非同期の所が複雑になりすぎる。無理だ。 諦めて毎回predictしなおすようにしよう。これならstrokeと同じタイミングでundo-redoの状態が確定するので難しい事は無い。 >出来た
2019/08/08
今日はアプリに組み込むべくライブラリ化の作業をしよう。 PopupWindowとして使うのかな? 少し過去コードを見直した所、AlertDialogを使っている事が多いな。 公式のTimePickerDialogもAlertDialogだし、これを真似するのがいいか。
dialogでは一番上のviewのmatch_parentがうまく効かないので少し苦戦する。 効かせる方法は分かったがそれよりはちゃんと内部のコンテンツがサイズを申告する方が正しいと思いなおしそういうコードになおす。 なんか毎回同じような所でハマって同じような結論の結果解決策は別の物になるんだよなぁ。
あとはこれをライブラリにして、MeatPieDayに組み込むコード書けばとりあえずは完成か。
ライブラリのバージョン違いとかいろいろはまって結構時間を食ってしまったが、無事実機に組み込み成功。 ついでにデモ動画を作ってtwitterに上げたりする。