最後は学習の実行
学習が実行されると、次の図のような出力が画面に表示される。横軸はエポックであり、縦軸は左がロス(正解と比較した誤差)、右が精度(Accuracy)である。右下がりの2本のグラフはロス(誤差)で、青線が訓練時のロス、赤線が検証データを認識した時のロスである。そして、緑の線は検証データセットを認識させて検証した精度である。当然であるが、学習に使用するデータのロスを小さくするように学習するので、青線のロスは小さくなる。一方、学習には使っていない検証データのロスは、それよりも多くなるが、4~5エポック目までは順調に減少している。
そして、認識精度は4エポック目には96%程度に達し、それ以降はフラットで改善は見られないということになっている。
この結果は、検証用データすべての画像を認識させた場合のものであるので、次は選択した1つの画像だけを認識させてみる。Image Classificationタブで、Image Pathに「/home/ubuntu/data/test_small/2/img_4415.png」という画像を指定する。そして、show visualization and statisticsにチェックを入れ、Classify Oneボタンを押す。
この画像は、次の写真のMNISTの文字の下にある手書きの2で、この写真では小さくて読み取れないが、2の出力が99.14%、0の出力が0.85%となっている。
そして、各層の出力などの詳細を見ることもできる。次の図は、「conv2」という層のWeightとActivationの分布を示すもので、右側の細かい格子状の図はそれぞれのフィルタの情報を示している。
次に、次の図に示す現実の画像の認識を行ってみる。3、8は綺麗な数字であるが、他の数字は図案化されていたり、背景にノイズが載っていたりしている。
この7枚の画像ファイルのフルパス名を書いたイメージリストファイル「an_image.list」を指定してClassify Manyボタンを押す。
最初のsmallデータセットで訓練を行ったモデルに加えて、6倍のデータを含む「/home/ubuntu/data/train_full」と「/home/ubuntu/data/test_full」を使って学習したMNIST_fullモデルを作って、この7枚の画像を認識させたのが次の結果である。
スモールデータセットで学習したMNIST_smallの場合、1の画像は1の出力が99.9%であるが、2の画像は69.03%で、2がトップの候補ではあるが、1ほど高い確度ではない。3、4の画像は、8が第一候補と誤判定している。最後のニコニコマークが2つつながったような画像は54.75%で8と判定している。
6倍の画像を含むラージデータセットで学習したMNIST_fullの場合は、検証データでは99%の精度となったが、7枚の画像に関しては、2と8の画像の確度は上がったが、3、4、7の画像の誤判定は変わらず、ニコニコマークは2と判定している。ということで、ラージデータセットを使った学習では、現実世界の7枚の画像の認識では、改善がないという結果である。
データセットのサイズを増やすだけでは改善しないので、次は、画像を反転したイメージを入力データセットに追加してみる。これもすでに作られており、実習ではフォルダ名を入力するだけである。
このように収集した画像を元に加工した画像を作って追加することを「Data Augmentation」と言い、ディープラーニングの学習の場合、良く用いられている手法である。
この反転画像を追加したデータセットで学習させたモデルの認識結果を次の図に示している。この追加により、3、4、7の画像は、高い確度で正しく認識されるようになった。ただし、ニコニコマークは、相変わらず2と判定されている。
大幅な改善が得られたが、まだ完全ではないので、今度は、ネットワークを強化してみる。強化点は、次の図に赤字で書かれているように、第2、3層のフィルタを20枚から75枚に増やし、第3層の次に「ReLU関数」を入れ、さらに75枚の8×8のフィルタを追加し、新たな第5層のフィルタ枚数を50枚から100枚に増加するというものである(ただし、この後のソース編集を見ると、追加されたのはReLU関数だけで、黄色で書かれたフィルタ層は入っていないと思われる)。
そのためにはNew ModelのタブでLeNetを選び、Customizeをクリックする。そして、次の画面でVisualizeボタンをクリックするとLeNetのソースコードが表示される。
このソースを編集して、次の図の左側のソースに示すようにReLUレイヤの追加の行の後の赤字で書かれた6行を追加する。さらに、右側のソースのように、conv1層のnum_output:を75に変更し、conv2層のnum_output:を100に変更する。
この変更を行ってからVisualizeボタンを押すと、次の図のようにネットワークの図が表示されるので、conv1とconv2のフィルタ数が増えていることと、reluP1という新しい層が追加されていることを確認する。
このように強化されたネットワークでの7枚の画像の認識結果は、次の図の右端の列のようになった。ニコニコマークは8と認識されるようになったが、今度は7の画像が2と判定されてしまっているし、1の画像も確度59.18%でちょっとスコアが低い。
ということで、手書き数字の分類でも、なかなか、一筋縄では行かない。学習をさせれば、半自動的に、正しい認識システムが作れるという訳ではなく、色々と試行錯誤が必要ということが分かったのも収穫であった。
なお、この結果は30エポックまで学習を行った結果であるが、筆者が実習で行った10エポックの学習では、次の図のような結果になった。7の画像を確度61.25%で2と判定しているのはほぼ同じ結果であるが、第2候補は確度22.1%で7となっている。
ディープラーニングによる画像分類実習の感想
DIGITSを操作するのが初めてで、メニューの体系に関する知識が無く、どこに何を入力する欄があるのかも知らないので、操作に時間が掛かって、講師についていくのが大変であったり、取材のための作業もする必要があるなどハンデもあったため、講師に置いて行かれて迷子になって、NVIDIAのヘルプエンジニアの方にたくさん助けていただくこととなった。
この実習ではNVIDIAの若いエンジニアの方が多数会場に配置されていて、分からないところがあると呼んで教えてもらえるという態勢がとられていた。おかげで、筆者も何とか終わりまで実習を行うことができた。
しかし、実習が終わった時点では、言われた通りにキーボードを叩いたら、言われた通りの画面が出たという感じで、キーボード上のハンズオンであり、脳の方は追いついていないという状態であった。その後、本稿を執筆するに至って、ディープラーニングのワークフローを理解し、CNNのセットアップとトレーニングができるという受講目的がある程度達成されたという感じである。