自作データで深層学習がしたい!

みなさんは、同じ文字を1000個連続で書いた経験はありますか?
私はあります。それも、10回。(謎マウント)

まえがき

春休みになって、ようやくゼロ作を読み進める時間ができたので、サポートページにありがたいソースコードは載っているけれど、実際に自分でも書いてみよう!ってやる気に満ち溢れた。

・・・のだが、その有り余るやる気は別方向へと向き始める。

「MNISTデータセットじゃ、なんかつまらなくね?」

いや、つまらなくはないんですけど、物足りないというかなんというか。まず先にやるべきことあるだろ!って感じなんですけど。

「自作データセットで同じこと、やりたいな〜」

長期休暇というものは、今後の人生でそう何回も訪れることはないだろう・・・
そんな悲しい現実に目を向けてしまったことも、こんなバカな発想を後押しした。

そんなわけで、0〜9の手書き(自筆)データをそれぞれ1000枚ずつ計10000枚を作成し、ゼロ作を読みながらお気持ち深層学習をしてみることになった。

自作データセット作成

どうやって自筆データセットを作ろう・・・
そう思った時に目に入ったのは、昨年12月に購入し、音ゲー(だいたいArcaea)専用機化しつつある iPad Air 4 の神々しい御姿である。
Apple Pencil もあるし、GoodNotes 5 も買ってあるし、いけるんちゃう?

とりあえず0を1000個書いてみるか〜って、書く。(所要時間約30分)
作り方だが、まず適当に正方形の真っ黒な画像を作成しておく。(次のコードでなんか作った。)

import numpy as np
from cv2 import imwrite

x = np.zeros((64, 64, 3))
imwrite("data/blackback.jpg", x)

それをテンプレートにしたうえで、白色のボールペンで1ページに1個ずつ、ひたすら0を書いていく。文字の太さはなんとなく選ぶ。次のページに進む感じでめっちゃスライドすると、現在のテンプレート(真っ黒な正方形)で新たにページを作成してくれるので、右手で文字を書きつつ、左手でスライド、という作業をひたすらやっていく。スライドするときの摩擦力で人差し指が痛くなったし、手首もめちゃくちゃ疲れた。

次の画像は書き終わった記念に撮ったものだが、MNISTの画像に比べるとキレイ(?)な文字な気がしてきた。あんまり学習する意味なかったら泣いちゃうな。(フラグを立てるのがお上手)

画像1

これをどうにかしてPC(私はMacbook Air)に送り届け、データの分類をするためにいろいろ名前を変えたりしなきゃいけないのだが、ここで私は、GoodNotes 5 のさらなる利便性に気がついてしまった。

「すべてを書き出す」の存在は前々から知っていたのだが、書き出しオプションで「イメージ」を選択し、オプションを開いてみると、zipファイルとして書き出す機能があったのだ。いや〜知らなかった〜。ページ背景もとりあえず含めて書き出し、AirDropで自分のMacBook Airを選択、送信完了!

知っていた方々はごめんなさい。私はこれでもちょっと感動したんですよ。

さて、残る課題はファイル名をなんとかして、正解のラベル作成を自動化できたら(流石に1つ1つ手作業は心が折れる)私の勝ち(?)である。送られてきたzipファイルを解凍して中身を見てみると・・・

あれ?GoodNotes 5 のファイル名の付け方天才じゃね???
そう、中身のファイル名が「(元のノート名)-(ページ数).jpg」となっていたのだ。これ元のノート名でどの文字か明示してしまえば、プログラムで画像読み込んでいく時に、ファイル名でラベルも作れちゃうじゃん!(小学生並の発想)

さっそくノート名を「0」とし、書き出し直してみると、「0」ファイルの中に「0-001.jpg」から「0-1000.jpg」まで、ズラ〜っと並んでいるのである。いやまじでGoodNotes 5 すごい。深層学習の記事じゃなくてGoodNotes 5 の宣伝記事なんじゃないか。

ただ、書き出した画像はカラー画像となっているので、グレースケールにした画像を作って(方法はGoogle先生に聞いた)、それらを"""食わせて"""、自分だけの自分だけによる自分だけのための深層学習の完成である。

まぁその前に残りの9000字を書き続けないといけないんだけどね。
0とか1はまだ単純な文字なので、比較的楽なのだが、2あたりからゲシュタルト崩壊的な何かを引き起こし始め、5あたりで心が折れかける。
学期中は忙しくて読めなかった『安達としまむら』を読んでメンタルリセットしつつ、なんとか10000字を書き上げたのである。この記事(約3000字)よりも字数的には多いじゃん。

深層学習フェーズ

ゼロ作に沿って説明すると、TwoLayerNet を使用した。画像はcv2.resizeとかつかって64×64のサイズ(つまり要素数4096個のベクトル)にして、バッチサイズ100で学習率を0.001とし、5000回くらいループを回す。中間層のサイズはなんとなく200に決定。(だいたい100と4096の間くらいだし)ところどころ複数次元に対応させなきゃいけない関数があり、自力では無理だったので、サポートページのコードを拝借。実装力も知識も無くて情けないなぁ・・・

学習データ(というかパラメータ)も記録しておきたいな〜と思い、またGoogle先生の力を借りてみると、np.ndarrayを読み書きできる.npy、.npzフォーマットなるものが存在することが分かった。さっそくセーブ機能とロード機能を追加して、計算開始。

trainのループ回してる時は、tqdmとか使って進捗みるのも楽しい。(し、計算時間がどんな感じなのかが分かって便利。)

結果

TimesNewRomanで書いてある0〜9の画像各1枚ずつ(0(~9)-001.jpg)と、教師データとはさらに別に自筆で書いた0〜9の画像各1枚ずつ(0(~9)-002.jpg)、そして、母親に書いてもらった0〜9の画像各1枚ずつ(0(~9)-003.jpg)を、どの文字が書いてあるか予想させた結果が、以下の通りである。

スクリーンショット 2021-02-09 9.27.53

意外と合わないものですね・・・(正解率は24/30で80%)
自分の書いた文字は(怪しさを残しつつも)百発百中なのに、他だと間違ってるのがチラホラとありますね。これが過学習ってやつなのでしょうか。
本当に"""自分だけのための"""深層学習になってしまった。ぐぅ〜
MNISTデータセットじゃつまらないとか言ってしまい、本当にすみませんでした。

あとがき

深層学習、マジむず〜〜〜〜〜〜!!!

コーディングとかそこらへんの仕組みは、全くの素人だった私でも、本読んで少し知っただけでそれっぽいのが出来たのですが、用いる手法を決めたり、層構造をどうするか決めたり、パラメータを適切に決めていったりして、精度を高めるところが非常に厳しい。過学習とかも怖いね。

努力する方向が間違っている気がするけど、自筆の文字データが大量にあるって、なんかワクワクしませんか?
役立つ場面は?とか言われると、将来私が遺言状を書いた時に、本物かどうか筆跡鑑定してもらう時に役立ちそう(苦し紛れ)って感じなのですが。

数字に加えてアルファベット(a〜z、A〜Z)も作ったら面白そうだな〜とも思ったのですが、oとOと0の区別とかどうすんねんって感じだし、何よりあと52000字も書かなきゃいけないのが絶望すぎる。まず過学習をなんとかしなきゃいけないんですけど。
世間に広まってる深層学習を作る人ってすごいな〜って改めて感じますね。(データ作る人もすごく偉い。ありがたい存在だと思います。)

ゼロ作②も買ってあるので、のんびりまた読み進めていって、いろんな手法を知って、どんどん認識精度を高めていって、‪✝︎‬高度AI人材‪✝︎‬とかいうのになれたらいいですね。よく知らないですけど。

次の記事はまたいつ書くか知らないですけど、お目にかかる機会があればぜひ、よろしくお願いします。

この記事が気に入ったらサポートをしてみませんか?