人工ニューラルネットワークで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種類だけなので、とりあえず生成する程度です。)
