MNISTを例にWolfram Lanuageによる深層学習入門

Mathematicaで深層学習 deep learning の基礎を学ぶことができます。ここでは Wolfram Languageだけを使い、実装してみます。

学習データの用意

深層学習には学習データが必要です。ここでは手書き数字データMNISTを例として使いますが、Mathematicaが計算可能データとして予め用意しているものをResourceDataから取得します。なお、TrainingDataは学習用データ、TestDataは学習結果の精度検証validationに使用します。

In [ ]:
trainingData = ResourceData["MNIST", "TrainingData"];
testData = ResourceData["MNIST", "TestData"];
In [ ]:
trainingData  // Length
testData // Length
Out[ ]:
Out[3]:
60000
Out[4]:
10000

Mathematicaでは学習データは以下の例でも分かるように、画像とラベルの連想形式(Rule関数使用)を用いています。逆にいえば、自前でデータを用意するときは、連想形式で用意する形になります。

In [ ]:
SeedRandom[1234]; data =RandomSample[trainingData, 20]
Out[ ]:
Output
In [ ]:
SeedRandom[1234]; testdata =RandomSample[testData, 20]
Out[ ]:
Output

データを1つ取り出し、内容を確認してみます。学習データの最初([[1]])の連想部分を取り出し、ついでその前半([[1]][[1]]、つまり画像)をimg9として定義します。

In [ ]:
img9 = data[[1]][[1]]
Out[ ]:
Output
In [ ]:
testimg5  = testdata[[1]][[1]]
Out[ ]:
Output

画像 img9 は 0. 以上、1.未満の値を要素に持つ 28x28 サイズの配列からなります。

In [ ]:
Information[img9]
ImageData[img9]
Out[ ]:
Out[7]:
Output
Out[8]:
Output
In [ ]:
ArrayPlot[ImageData[img9]]
Out[ ]:
Output

一層の全結合層

encoder

学習対象データがなんであれ、ニューロン層に入力する際は、数値列に変換する必要があります。データの数値列への変換をencodingと呼びます。

In [ ]:
enc = NetEncoder[{"Image", {28, 28}, "Grayscale"}]
Out[ ]:
Output

Wolfram Language の出力は、たとえば、このJupyter Notebookの場合、画像として出力されます。したがってMathematicaのノートブックでは可能はインタラクティブな操作、たとえば+ボタンを押し、中身を見るようなことはできません。幸い、表示は画像でも実態はオブジェクトとして情報操作対象となります。ここではencがオブジェクト情報を持っています。中身を開く一番簡単な方法は Normal 関数を使うことです。

ただし、理由は不明ですが、Wolfram Languageでは表示情報はここまでで、一方、同様の操作をMathematicaで行うと、以下のようにもっと詳細な情報が得られます。

<|"ColorChannels" -> 1, "ColorSpace" -> "Grayscale", 
 "DataTransposed" -> False, 
 "ImageSize" -> NeuralNetworks`ValidatedParameter[{28, 28}], 
 "Interleaving" -> False, "MeanImage" -> None, 
 "Output" -> {1, 28, 28}, "Type" -> "Image", "VarianceImage" -> None|>
In [ ]:
enc // Normal
Out[ ]:
Output

入力用encoderとしてencを指定し、出力ベクトル次数を3とした全結合層の重みweightsとバイアスbiasesを初期化したものを linear と定義します。

In [ ]:
linear = NetInitialize@LinearLayer[3, "Input" -> enc]
Out[ ]:
Output

初期化された重みとバイアスをそれぞれ weights、biases に取り出します。 Normal はMathemtica固有のオブジェクトを一般の数値データとして扱えるように変換するために利用しています。この際、weights は3x784(=28x28)の2次元配列となります。

In [ ]:
weights = NetExtract[linear, "Weights"]
weights = weights//Normal;
Out[ ]:
Output
In [ ]:
biases = NetExtract[linear, "Biases"]
biases = biases//Normal;
Out[ ]:
Output

サンプル画像 img9 をこの全結合層に入力したとき、エンコードされた出力として以下の3要素からなるベクトルが返ってきます。そして、これは img9 の内部データを一次元化したものに重み weights を掛け(内積)、結果に biases を足したものに等しいことがわかります。

In [ ]:
linear[img9]
Out[ ]:
{0.139886, 1.83387, 1.94142}
In [ ]:
Dot[weights, Flatten[ImageData[img9]]] + biases
Out[ ]:
{0.139885, 1.83387, 1.94142}

2層パーセプトロン

MNIST手書き数字分類器として、2つの全結合層 LnearLayer からなる多層パーセプトロンを考えます。2層間に活性化関数として Ramp 関数を置き、分類関数としてSofrmaxLayerを使います。1段目のLinearLayer内のニューロン数は100としていますが、2段目のニューロン数は空白となっています。この場合、文脈(学習データが持つクラス数)から自動的に10と決まります。

In [ ]:
mlp = NetChain[{
     LinearLayer[100], 
   Ramp, 
   LinearLayer[], 
   SoftmaxLayer[]}]
Out[ ]:
Output

学習時間はMacBook Air2019年モデル上のAnaconda Jupyter上で約145秒掛かっています。

In [ ]:
Timing[trained = 
    NetTrain[mlp,  trainingData,  MaxTrainingRounds -> 10]]
Out[ ]:
Output

ネットモデルmlpにおいて、明示的にInputおよびOutput層は指定されていません。当然、encoderおよびdecoderも省略されています。しかし、学習結果 trained と見ると、encoderは学習データを3x28x28の数値データに変換し、decoderは長さ10の確率ベクトルに変換していることがわかります。

In [ ]:
NetExtract[trained, "Input"]
Out[ ]:
Output
In [ ]:
NetExtract[trained, 1]
Out[ ]:
Output
In [ ]:
NetExtract[trained, 3]
Out[ ]:
Output
In [ ]:
NetExtract[trained, "Output"]
Out[ ]:
Output

学習済み分類器trained を使い、画像testimg5を確率込みで分類してみます。ラベルとしては5がほぼ一択0.99748で選ばれています。

In [ ]:
trained[testimg5, "Probabilities"]
Out[ ]:
                                   -7                 -8                                    -14                                -8                 -11                                  -8
<|0 -> 0.000672432, 1 -> 2.42617 10  , 2 -> 1.43475 10  , 3 -> 0.0000246978, 4 -> 3.85385 10   , 5 -> 0.997748, 6 -> 9.09311 10  , 7 -> 8.37954 10   , 8 -> 0.00155484, 9 -> 9.46248 10  |>
In [ ]:
trained[testimg5]
Out[ ]:
5

今度は同じモデルを使い、ValidationSetとしてテストデータを与え、再度学習させてみます。

In [ ]:
Timing[trained = NetTrain[
     mlp, trainingData, ValidationSet -> testData, MaxTrainingRounds -> 3]]
Out[ ]:
Output

分類測度を計算するClassifierMeasurementを用い、精度(確度)を計ってみます。

In [ ]:
Timing[
  cm = ClassifierMeasurements[trained, testData]]
Out[ ]:
Output
In [ ]:
cm["Accuracy"]
Out[ ]:
0.9094

精度比較を視覚的に見るConfusionMatrixを出力します。たとえば、数字3データは1010個のうち、869個が正解しましたが、たとえば88個も数字5と勘違いしました[偽陰性]。一方、本来、5でない数字283個(=1108-825)が5と勘違いされました[偽陽性]。

In [ ]:
cm["ConfusionMatrixPlot"]
Out[ ]:
Output

LeNet

一方、2層のConvolution層と2層の全結合層からなるLeNetを用いると、学習精度は98.98%にも上がることがわかります。

In [ ]:
lenetModel = NetModel["LeNet Trained on MNIST Data"]
Out[ ]:
Output
In [ ]:
NetExtract[lenetModel, All]
Out[ ]:
Output
In [ ]:
Timing[result = 
    NetTrain[lenetModel, trainingData, All,  ValidationSet -> testData]
]
Out[ ]:
Output
In [ ]:
trained = result["TrainedNet"];
cm = ClassifierMeasurements[trained, testData];
cm["Accuracy"]
Out[ ]:
0.9898
In [ ]:
trained[testimg5]
Out[ ]:
5
In [ ]:
NetInformation[trained]
Out[ ]:
Output
In [ ]:
NetInformation[trained, "SummaryGraphic"]
Out[ ]:
Output
In [ ]:
result["EvolutionPlots"]
Out[ ]:
Output
In [ ]:
NetTrain[
        lenetModel, trainingData, "RMSWeightsEvolutionPlot", 
        ValidationSet -> testData]
Out[ ]:
Output

The Wolfram Neural Net Repository

Mathematicaは各種ネットモデルを予め提供しています。

In [ ]:
NetModel[]
Out[ ]:
{2D Face Alignment Net Trained on 300W Large Pose Data, 3D Face Alignment Net Trained on 300W Large Pose Data, AdaIN-Style Trained on MS-COCO and Painter by Numbers Data, Ademxapp Model A1 Trained on ADE20K Data, Ademxapp Model A1 Trained on Cityscapes Data, Ademxapp Model A1 Trained on PASCAL VOC2012 and MS-COCO Data, Ademxapp Model A Trained on ImageNet Competition Data, Age Estimation VGG-16 Trained on IMDB-WIKI and Looking at People Data, Age Estimation VGG-16 Trained on IMDB-WIKI Data, BPEmb Subword Embeddings Trained on Wikipedia Data, CapsNet Trained on MNIST Data, Clinical Concept Embeddings Trained on Health Insurance Claims, Clinical Narratives from Stanford and PubMed Journal Articles, Colorful Image Colorization Trained on ImageNet Competition Data, ColorNet Image Colorization Trained on ImageNet Competition Data, ColorNet Image Colorization Trained on Places Data, ConceptNet Numberbatch Word Vectors V17.06, ConceptNet Numberbatch Word Vectors V17.06 (Raw Model), CREPE Pitch Detection Net Trained on Monophonic Signal Data, CycleGAN Apple-to-Orange Translation Trained on ImageNet Competition Data, CycleGAN Horse-to-Zebra Translation Trained on ImageNet Competition Data, CycleGAN Monet-to-Photo Translation, CycleGAN Orange-to-Apple Translation Trained on ImageNet Competition Data, CycleGAN Photo-to-Cezanne Translation, CycleGAN Photo-to-Monet Translation, CycleGAN Photo-to-Van Gogh Translation, CycleGAN Summer-to-Winter Translation, CycleGAN Winter-to-Summer Translation, CycleGAN Zebra-to-Horse Translation Trained on ImageNet Competition Data, Deep Speech 2 Trained on Baidu English Data, Dilated ResNet-105 Trained on Cityscapes Data, Dilated ResNet-22 Trained on Cityscapes Data, Dilated ResNet-38 Trained on Cityscapes Data, ELMo Contextual Word Representations Trained on 1B Word Benchmark, Enhanced Super-Resolution GAN Trained on DIV2K, Flickr2K and OST Data, Gender Prediction VGG-16 Trained on IMDB-WIKI Data, GloVe 100-Dimensional Word Vectors Trained on Tweets, GloVe 100-Dimensional Word Vectors Trained on Wikipedia and Gigaword 5 Data, GloVe 200-Dimensional Word Vectors Trained on Tweets, GloVe 25-Dimensional Word Vectors Trained on Tweets, GloVe 300-Dimensional Word Vectors Trained on Common Crawl 42B, GloVe 300-Dimensional Word Vectors Trained on Common Crawl 840B, GloVe 300-Dimensional Word Vectors Trained on Wikipedia and Gigaword 5 Data, GloVe 50-Dimensional Word Vectors Trained on Tweets, GloVe 50-Dimensional Word Vectors Trained on Wikipedia and Gigaword 5 Data, GPT Transformer Trained on BookCorpus Data, Inception V1 Trained on Extended Salient Object Subitizing Data, Inception V1 Trained on ImageNet Competition Data, Inception V1 Trained on Places365 Data, Inception V3 Trained on ImageNet Competition Data, LeNet, LeNet Trained on MNIST Data, MobileNet V2 Trained on ImageNet Competition Data, Multi-scale Context Aggregation Net Trained on CamVid Data, Multi-scale Context Aggregation Net Trained on Cityscapes Data, Multi-scale Context Aggregation Net Trained on PASCAL VOC2012 Data, OpenFace Face Recognition Net Trained on CASIA-WebFace and FaceScrub Data, Pix2pix Photo-to-Street-Map Translation, Pix2pix Street-Map-to-Photo Translation, Pose-Aware Face Recognition in the Wild Nets Trained on CASIA WebFace Data, ResNet-101 Trained on Augmented CASIA-WebFace Data, ResNet-101 Trained on ImageNet Competition Data, ResNet-101 Trained on YFCC100m Geotagged Data, ResNet-152 Trained on ImageNet Competition Data, ResNet-50 Trained on ImageNet Competition Data, Self-Normalizing Net for Numeric Data, Sentiment Language Model Trained on Amazon Product Review Data, Single-Image Depth Perception Net Trained on Depth in the Wild Data, Single-Image Depth Perception Net Trained on NYU Depth V2 and Depth in the Wild Data, Single-Image Depth Perception Net Trained on NYU Depth V2 Data, Sketch-RNN Trained on QuickDraw Data, Squeeze-and-Excitation Net Trained on ImageNet Competition Data, SqueezeNet V1.1 Trained on ImageNet Competition Data, SSD-MobileNet V2 Trained on MS-COCO Data, SSD-VGG-300 Trained on PASCAL VOC Data, SSD-VGG-512 Trained on MS-COCO Data, SSD-VGG-512 Trained on PASCAL VOC2007, PASCAL VOC2012 and MS-COCO Data, U-Net Trained on Glioblastoma-Astrocytoma U373 Cells on a Polyacrylamide Substrate Data, Unguided Volumetric Regression Net for 3D Face Reconstruction, Vanilla CNN for Facial Landmark Regression, Very Deep Net for Super-Resolution, VGG-16 Trained on ImageNet Competition Data, VGG-19 Trained on ImageNet Competition Data, VGGish Feature Extractor Trained on YouTube Data, Wide ResNet-50-2 Trained on ImageNet Competition Data, Wolfram AudioIdentify V1 Trained on AudioSet Data, Wolfram C Character-Level Language Model V1, Wolfram English Character-Level Language Model V1, Wolfram ImageIdentify Net V1, Wolfram JavaScript Character-Level Language Model V1, Wolfram LaTeX Character-Level Language Model V1, Wolfram Python Character-Level Language Model V1, Yahoo Open NSFW Model V1, YOLO V2 Trained on MS-COCO Data, YOLO V3 Trained on Open Images Data}

それらネットモデルを使った具体例が以下のサイトで紹介されています。なお、これらのモデルをそのままWolfram Engineで動作するかの確認は行っていません。

学習結果の保存

Mathematicaの場合、学習結果はMXNet形式で保存されます。ただし、上記サイトで紹介されている方法では、うまく行かず、ここでは以下のページの情報を参考に変更しています。

https://qiita.com/koshian2/items/b688bb8ac05e1c956e9f

In [ ]:
<< GeneralUtilities`
In [ ]:
jsonPath =   GeneralUtilities`MLExport[
  FileNameJoin[{$TemporaryDirectory, "net.json"}],
  result["TrainedNet"]]
Out[ ]:
/private/var/folders/q7/zg_4pvxd3h1d4l3rlyd80pb00000gn/T/net.json
In [ ]:
paramPath = 
   FileNameJoin[{DirectoryName[jsonPath], "net.params"}]
Out[ ]:
/private/var/folders/q7/zg_4pvxd3h1d4l3rlyd80pb00000gn/T/net.params
In [ ]:
FileByteCount[paramPath]
Out[ ]:
1724806
In [ ]:
imported =  GeneralUtilities`MLImport[jsonPath];
imported[testimg5]
Out[ ]:
5