人工ニューラルネットワークでFashion-MNISTを学習させ画像生成AI ~Delphiソースコード集
Fashion-MNISTは、オンラインショップ「Zalando」の画像から生成されたデータセットだそうで、。
28x28ピクセルの6万枚のモノクロ画像で、10種類に分類され、ラベル付けされているそうです。
https://github.com/zalandoresearch/fashion-mnist/tree/master/data/fashion
からダウンロードできます。
本来、画像データから画像を10種類に分類させる為のテストデータなので、「入力層が画像」で「出力層が分類」として扱うのですが、
本ソースコードでは「入力層を分類」にし「出力層が画像」としてAIに学習させて生成AIとして画像を出力させます。
よって、分類を10種類ではなく、もっと細かく「左向き」「右向き」や「柄あり」「柄なし」などの画像分類も用意すべきですが、あくまで画像生成AIのサンプルなのでご容赦ください。
分類は以下の10種類だそうです。
0 | Tシャツ |
1 | ズボン |
2 | セーター |
3 | ドレス |
4 | コート |
5 | サンダル |
6 | シャツ |
7 | スニーカー |
8 | 鞄 |
9 | ブーツ |
人工ニューラルネットワーク(Artificial Neural Network)を使用する為のファイルの準備
本ホームページのhttps://mam-mam.net/delphi/ann.htmlから
「UMamAnn.pas」ソースコード用意しプロジェクトフォルダ内に保存します。
また、
https://github.com/zalandoresearch/fashion-mnist/
の「Code」⇒「Download ZIP」をクリックして「fashion-mnist-master.zip」ファイルをダウンロードし、解凍します。
解凍したフォルダ内の[/data/fashion]フォルダ内にある
- train-images-idx3-ubyte.gz
- train-labels-idx1-ubyte.gz
- train-images-idx3-ubyte
- train-labels-idx1-ubyte
Delphiを起動して新規作成を行い、必要なコンポーネントをドラッグ&ドロップする
Delphi起動⇒ファイル⇒新規作成⇒WindowsVCLアプリケーション を選択します。
TButton×2個、TMemo×1個、TLabel×10個、TSpinEdit×10個、TImage×1個をフォームへドラッグ&ドロップします。
「ファイル」⇒「全て保存」でフォルダを作成して、プロジェクトとユニットを保存します。
プロジェクトフォルダ内に「UMamAnn.pas」ファイルと「train-images-idx3-ubyte」「train-labels-idx1-ubyte」ファイルを配置します。
ソースコードを記述する
Form1のOnCreateイベント、Form1のOnDestroyイベント、Button1のOnClickイベント、Button2のOnClickイベントに以下ソースコードを記述します。
unit Unit1; interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, UMamAnn, Vcl.Samples.Spin, Vcl.ExtCtrls; type //FashionMNISTの画像データ(28X28=784ピクセル モノクロ)を入れる構造体 TAnnData=packed record id:Cardinal; num:Integer; row:Integer; col:Integer; data:array of array of Byte; end; //FashionMNISTの分類データを入れる構造体 TAnnLabel=record id:Integer; num:Integer; data:array of Byte; end; TForm1 = class(TForm) Button1: TButton; Memo1: TMemo; Button2: TButton; Label1: TLabel; Label2: TLabel; Label3: TLabel; Label4: TLabel; Label5: TLabel; Label6: TLabel; Label7: TLabel; Label8: TLabel; Label9: TLabel; Label10: TLabel; SpinEdit1: TSpinEdit; SpinEdit2: TSpinEdit; SpinEdit3: TSpinEdit; SpinEdit4: TSpinEdit; SpinEdit5: TSpinEdit; SpinEdit6: TSpinEdit; SpinEdit7: TSpinEdit; SpinEdit8: TSpinEdit; SpinEdit9: TSpinEdit; SpinEdit10: TSpinEdit; Image1: TImage; procedure Button1Click(Sender: TObject); procedure Button2Click(Sender: TObject); procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); private { Private 宣言 } MamAnn: TMamAnn; //Artificial Neural Network AnnData:TAnnData; //FashionMNISTの画像データ AnnLabel:TAnnLabel;//FashionMNISTのラベル(分類) public { Public 宣言 } end; var Form1: TForm1; implementation {$R *.dfm} procedure TForm1.Button1Click(Sender: TObject); var i,j:Integer; epoch:Integer; inputs: TArray<Single>; outputs: TArray<Single>; begin //学習する for epoch := 1 to 1 do begin i:=0; while (i<(AnnData.num div 1)) do begin setlength(inputs,10); setlength(outputs,AnnData.row*AnnData.col); for j := 0 to AnnData.row*AnnData.col-1 do begin outputs[j]:=AnnData.data[i*1+0][j]/255; end; for j := 0 to 9 do inputs[j]:=0; inputs[AnnLabel.data[i*1+0]]:=1; MamAnn.Train(inputs,outputs); inc(i); end; end; //学習結果を保存する場合 MamAnn.SaveToFile('a.net'); //MSEの表示 Memo1.Lines.Add(FloatToStr(MamAnn.GetMSE)); end; procedure TForm1.Button2Click(Sender: TObject); var i,x,y:Integer; col:Integer; Inputs: TArray<Single>; Outputs: TArray<Single>; begin //■■■ANNに画像を生成させる■■■ //入力層10個 SetLength(inputs,10); //分類の値を正規化して入力層に設定 for i := 0 to 9 do begin inputs[i]:=TSpinEdit(FindComponent('SpinEdit'+IntToStr(i+1))).Value/100; end; //出力層28x28=784個 SetLength(Outputs,AnnData.row*AnnData.col); //画像生成させる MamAnn.Run(Inputs,Outputs); //生成した画像を表示する Image1.Picture.Bitmap.Width:=AnnData.col; Image1.Picture.Bitmap.Height:=AnnData.row; for y := 0 to AnnData.row-1 do begin for x := 0 to AnnData.col-1 do begin col:=Round(Outputs[y*AnnData.col+x]*255); if col>255 then col:=255; if col<0 then col:=0; Image1.Picture.Bitmap.Canvas.Pixels[x,y]:=col*$10000+col*$100+col; end; end; end; procedure TForm1.FormCreate(Sender: TObject); var i:Integer; strm:TFileStream; rbyte:array[0..3] of Byte; NeuronCountInLayers:TArray<Integer>; se:TSpinEdit; begin //FashionNMISTは28x28=784ピクセルのグレースケール画像で学習データは60000枚 //画像の読み込み strm:=TFileStream.Create('..\..\train-images-idx3-ubyte',fmOpenRead); strm.Position:=0; strm.Read(rbyte[0],4); AnnData.id :=(rbyte[0] shl 24)+(rbyte[1] shl 16)+(rbyte[2] shl 8)+rbyte[3]; strm.Read(rbyte[0],4); AnnData.num:=(rbyte[0] shl 24)+(rbyte[1] shl 16)+(rbyte[2] shl 8)+rbyte[3]; strm.Read(rbyte[0],4); AnnData.row:=(rbyte[0] shl 24)+(rbyte[1] shl 16)+(rbyte[2] shl 8)+rbyte[3]; strm.Read(rbyte[0],4); AnnData.col:=(rbyte[0] shl 24)+(rbyte[1] shl 16)+(rbyte[2] shl 8)+rbyte[3]; setlength(AnnData.data,AnnData.num); setlength(AnnData.data,AnnData.num); for i := 0 to AnnData.num-1 do begin setlength(AnnData.data[i],AnnData.row*AnnData.col); strm.Read(AnnData.data[i][0],AnnData.row*AnnData.col); end; strm.Free; //各画像のラベル(分類:10種類[0~9])の読み込み strm:=TFileStream.Create('..\..\train-labels-idx1-ubyte',fmOpenRead); strm.Position:=0; strm.Read(rbyte[0],4); AnnLabel.id :=(rbyte[0] shl 24)+(rbyte[1] shl 16)+(rbyte[2] shl 8)+rbyte[3]; strm.Read(rbyte[0],4); AnnLabel.num:=(rbyte[0] shl 24)+(rbyte[1] shl 16)+(rbyte[2] shl 8)+rbyte[3]; setlength(AnnLabel.data,AnnLabel.num); strm.Read(AnnLabel.data[0],AnnLabel.num); strm.Free; //TMamFannクラスのインスタンス化 SetLength(NeuronCountInLayers,4);//レイヤー(層)の数 //入力層のニューロン数 NeuronCountInLayers[0]:=10; //中間層のニューロン数 NeuronCountInLayers[1]:=100; //中間層のニューロン数 NeuronCountInLayers[2]:=200; //出力層のニューロン数(28x28=784ピクセル) NeuronCountInLayers[3]:=AnnData.row*AnnData.col; MamAnn:=TMamAnn.Create(NeuronCountInLayers, 0.02, TMamActivationFunc.ReLU); Label1.Caption:='Tシャツ'; Label2.Caption:='ズボン'; Label3.Caption:='セーター'; Label4.Caption:='ドレス'; Label5.Caption:='コート'; Label6.Caption:='サンダル'; Label7.Caption:='シャツ'; Label8.Caption:='スニーカー'; Label9.Caption:='鞄'; Label10.Caption:='ブーツ'; for i := 1 to 10 do begin se:=TSpinEdit(FindComponent('SpinEdit'+IntToStr(i))); se.MaxValue:=100; se.MinValue:=0; end; SpinEdit1.Value:=100; Image1.Proportional:=True; Image1.Stretch:=True; end; procedure TForm1.FormDestroy(Sender: TObject); begin if Assigned(MamAnn) then FreeAndNil(MamAnn); end; end.
実行する
実行ボタンを押して実行します。(デバッグ実行でもOK)
Button1をクリックすると学習します。学習が完了するまでしばらく時間がかかります。
学習が完了したらButton2をクリックすると、AIが画像を生成してImage1に表示します。
Tシャツ、ズボン等の分類パラメータを0~100の値に変更して、Button2をクリックすると、とりあえず画像を生成してくれます。
(冒頭に申し上げた通り、分類パラメータが10種類だけなので、とりあえず生成する程度です。)