トップへ(mam-mam.net/)

人工ニューラルネットワークでFashion-MNISTを学習させ画像生成AI ~Delphiソースコード集

検索:

人工ニューラルネットワークでFashion-MNISTを学習させ画像生成AI ~Delphiソースコード集

Fashion-MNISTは、オンラインショップ「Zalando」の画像から生成されたデータセットだそうで、。
28x28ピクセルの6万枚のモノクロ画像で、10種類に分類され、ラベル付けされているそうです。
https://github.com/zalandoresearch/fashion-mnist/tree/master/data/fashion からダウンロードできます。

Delphiで人工ニューラルネットワーク(Artificial Neural Network)を使用し日経平均株価終値を「回帰問題」として学習します

本来、画像データから画像を10種類に分類させる為のテストデータなので、「入力層が画像」で「出力層が分類」として扱うのですが、
本ソースコードでは「入力層を分類」にし「出力層が画像」としてAIに学習させて生成AIとして画像を出力させます。
よって、分類を10種類ではなく、もっと細かく「左向き」「右向き」や「柄あり」「柄なし」などの画像分類も用意すべきですが、あくまで画像生成AIのサンプルなのでご容赦ください。

Delphiで人工ニューラルネットワーク(Artificial Neural Network)を使用する

分類は以下の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]フォルダ内にある

ファイルをgz解凍し、 ファイルをプロジェクトフォルダに入れる必要があります。

Delphiを起動して新規作成を行い、必要なコンポーネントをドラッグ&ドロップする

Delphi起動⇒ファイル⇒新規作成⇒WindowsVCLアプリケーション を選択します。
TButton×2個、TMemo×1個、TLabel×10個、TSpinEdit×10個、TImage×1個をフォームへドラッグ&ドロップします。

Delphiで人工ニューラルネットワーク(Artificial Neural Network)を使用する

「ファイル」⇒「全て保存」でフォルダを作成して、プロジェクトとユニットを保存します。
プロジェクトフォルダ内に「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をクリックすると学習します。学習が完了するまでしばらく時間がかかります。

Delphiで人工ニューラルネットワーク(Artificial Neural Network)を使用しFashion-MNISTで生成AI

学習が完了したらButton2をクリックすると、AIが画像を生成してImage1に表示します。

Delphiで人工ニューラルネットワーク(Artificial Neural Network)を使用しFashion-MNISTで生成AI

Tシャツ、ズボン等の分類パラメータを0~100の値に変更して、Button2をクリックすると、とりあえず画像を生成してくれます。
(冒頭に申し上げた通り、分類パラメータが10種類だけなので、とりあえず生成する程度です。)