Have an amazing solution built in RAD Studio? Let us know. Looking for discounts? Visit our Special Offers page!
DelphiRAD Studio

Tensorflowで数字の分類器を構築する方法

how-to-build-a-digit-classifier

この記事は、Muminjon 氏のブログの抄訳です

MNIST (Modified National Institute of Standards and Technologyの略)は、包括的なコンピュータビジョンデータベースのるつぼです。1999年のリリース以来、MNISTの古典的な手書きのイメージのデータセットは、分類アルゴリズムのベンチマークの基盤として受け入れられてきました。

mnist-7851794-2
画像のソース元: researchgate.net

ほとんどの場合、はじめて学習する方はMNISTで与えられた数字を分類することから始めます。このブログでは、RAD Studio(Delphi)とTensorFlowを使用して、数字の分類を行なう方法を紹介いたします。

このチュートリアルで学べることは?

  • 簡単なニューラルネットワークを含むコンピュータビジョンの基礎
  • 分類する方法

MNISTとは?

MNISTは、0から9までの手書きの1桁の数字で、28×28ピクセルの範囲に収まるようにサイズが正規化されたグレースケール画像 6万枚のデータセットです。20年以上の歴史があるため、様々なトップパフォーマンスのモデルがディープラーニングの畳み込みニューラルネットワークの分野で、99%以上の分類精度を達成しています。

画像内の手書きの数字を認識するには?

「TensorFlow」は、Google Brainラボが開発した深層学習研究のためのオープンソースのライブラリです。通常、プロジェクトの新しいモデルをトレーニングするのに時間がかかりますが、物体やパターンなどを検出するための学習済みモデルがすでに存在するため、モデルをロードし、データを入力するだけで簡単に高い結果が得られます。

TensorFlow Liteモデルとは?

TensorFlow Liteモデルは、「FlatBuffers」と呼ばれる独特の効率的なポータブルフォーマットで提供される。このTensorFlow Liteモデルは、開発者がモバイル デバイス、組み込みデバイス、IoT デバイス上でモデルを実行できるようにすることで、デバイス上の機械学習を可能にするツールセットです。
TensorFlow Liteモデルについては、こちらで紹介しています。

DelphiでTensorFlowを使用するには?

DelphiおよびC++開発者の素晴らしいコミュニティのおかげで、現在 TensorFlow LiteはDelphiで利用可能で、こちらのリンクから「TensorFlow Lite Model for Delphi」のリポジトリにアクセスできます。

TFLITEダイナミックリンクライブラリ(DLL)は、TensorFlow Liteのモデル機能を利用する際に役立ちます。TensorFlow Lite全体で使用される共通の列挙型、型、およびメソッドが含まれています。これには、エラーコードからカーネルおよびデリゲートAPIなど全ての機能が含まれています。

tensorflow-lite-delphi-delphi-machine-learning-machine-learning-in-delphi-programming-language-1730262-2

プロジェクト全体をダウンロードしてテストすることができます。下図のように、手書きの数字を描くと、TensorFlowはそのデータを28×28ピクセルの画像として取得し、それを変換して0から9までの数字として返します。

machine-learning-in-delphi-digit-classification-in-delphi-tensorflow-lite-model-7445733-2

実際の画像を再現するために、28×28ピクセルの入力は、784ピクセルの1次元ベクトルにフラット化しています。つまり、画像を構成する784ピクセルのそれぞれは、0〜255のの範囲の値として格納されます。これは、画像が白黒で表示されるため、ピクセルのグレースケールを判断するのに役立ちます。入力画像の黒いピクセルは255で表され、白いピクセルは0で表されます。

digit-classifier-for-delphi-tensorflow-lite-for-delphi-delphi-machine-learning-building-neural-networks-with-delphi-3493358-2
digit-classifier-for-delphi-tensorflow-lite-model-for-delphi-machine-learning-in-delphi-programming-language-3221555-2
procedure TForm1.Button2Click(Sender: TObject);
var
  i, X, Y: DWORD;
 
  fLibrary: HMODULE;
  fModel: Pointer;
  fInterpreterOptions: Pointer;
  fInterpreter: Pointer;
  fStatus: TfLiteStatus;
  fInputTensorCount, fOutputTensorCount, fNumDims: Int32;
  fInputTensor, fOutputTensor: Pointer;
  fInputDims: Integer;
  fTensorName: PAnsiChar;
  fTensorType: TfLiteType;
  fTensorByteSize: SIZE_T;
 
  // 28x28 pixel image as input
  fInput: array [0 .. 28 * 28 - 1] of Float32;
 
  // output 0 to 9
  fOutput: array [0 .. 10 - 1] of Float32;
 
  fValue: Extended;
begin
  fLibrary := LoadLibrary(LibraryName);
 
  if fLibrary = 0 then
  begin
    ShowMessage('Error: Load tensorflow lite library ' + LibraryName + ' - ' +
      SysErrorMessage(GetLastError));
    Exit;
  end;
 
  try
    fModel := TfLiteModelCreateFromFile(PAnsiChar(AnsiString(Edit1.Text)));
 
    if fModel = nil then
    begin
      ShowMessage('Error: Create model from file - ' +
        SysErrorMessage(GetLastError));
      Exit;
    end;
 
    fInterpreterOptions := TfLiteInterpreterOptionsCreate;
 
    if fInterpreterOptions <> nil then
    begin
      TfLiteInterpreterOptionsSetNumThreads(fInterpreterOptions, 2);
 
      fInterpreter := TfLiteInterpreterCreate(fModel, fInterpreterOptions);
 
      // parameters / model can be removed immediately after the interpreter is created
      TfLiteInterpreterOptionsDelete(fInterpreterOptions);
      TfLiteModelDelete(fModel);
 
      if fInterpreter <> nil then
      begin
        fStatus := TfLiteInterpreterAllocateTensors(fInterpreter);
 
        fInputTensorCount := TfLiteInterpreterGetInputTensorCount(fInterpreter);
        fOutputTensorCount := TfLiteInterpreterGetOutputTensorCount
          (fInterpreter);
 
        // fLiteTensor* TfLiteInterpreterGetInputTensor(const TfLiteInterpreter* interpreter, int32_t input_index);
        // returned structure TfLiteTensor
        // an example is simple, there is no need to translate everything from the
        // in general, the source of the: https://github.com/tensorflow/tensorflow/tree/master/tensorflow/lite/c
        { typedef struct TfLiteTensor {
          TfLiteType type;
          TfLitePtrUnion data;
          TfLiteIntArray* dims;
          TfLiteQuantizationParams params;
          TfLiteAllocationType allocation_type;
          size_t bytes;
          const void* allocation;
          const char* name;
          struct TfLiteDelegate* delegate;
          TfLiteBufferHandle buffer_handle;
          bool data_is_stale;
          bool is_variable;
          TfLiteQuantization quantization;
          TfLiteSparsity* sparsity;
          const TfLiteIntArray* dims_signature; }
        fInputTensor := TfLiteInterpreterGetInputTensor(fInterpreter, 0);
        fOutputTensor := TfLiteInterpreterGetOutputTensor(fInterpreter, 0);
 
        if fInputTensor <> nil then
        begin
          // info about tensor
          // fNumDims := TfLiteTensorNumDims(fInputTensor);
          // fTensorName := TfLiteTensorName(fInputTensor);
          // fTensorType := TfLiteTensorType(fInputTensor);
          fTensorByteSize := TfLiteTensorByteSize(fInputTensor);
 
          // writing pixels to fInput, top to bottom, left to right
          for Y := 0 to Image1.Picture.Bitmap.Height - 1 do
          begin
            for X := 0 to Image1.Picture.Bitmap.Width - 1 do
            begin
              if (Image1.Canvas.Pixels[X, Y] > 0) then
                fInput[X + (Y * Image1.Picture.Bitmap.Width)] := 1
              else
                fInput[X + (Y * Image1.Picture.Bitmap.Width)] := 0;
            end;
          end;
 
          // fTensorByteSize = Length(fInput) * SizeOf(Float32)
          fStatus := TfLiteTensorCopyFromBuffer(fInputTensor, @fInput,
            fTensorByteSize);
 
          fStatus := TfLiteInterpreterInvoke(fInterpreter);
 
          if fStatus = kTfLiteOk then
          begin
            for i := 0 to High(fOutput) do
              fOutput[i] := 0;
 
            fOutputTensor := TfLiteInterpreterGetOutputTensor(fInterpreter, 0);
 
            // info about tensor
            // fNumDims := TfLiteTensorNumDims(fOutputTensor);
            // fTensorName := TfLiteTensorName(fOutputTensor);
            // fTensorType := TfLiteTensorType(fOutputTensor);
            fTensorByteSize := TfLiteTensorByteSize(fOutputTensor);
 
            if fOutputTensor <> nil then
            begin
              // fTensorByteSize = Length(fOutput) * SizeOf(Float32)
              fStatus := TfLiteTensorCopyToBuffer(fOutputTensor, @fOutput,
                fTensorByteSize);
 
              if fStatus = kTfLiteOk then
              begin
                ListView1.Items.Clear;
 
                for i := 0 to Length(fOutput) - 1 do
                begin
                  // ingenious solution, coolest conversion
                  fValue := StrToFloat(Copy(FloatToStr(fOutput[i]), 1, 17));
 
                  if fValue <= 1 then
                  begin
                    with ListView1.Items.Add do
                    begin
                      Caption := FloatToStrF(fValue, ffNumber, 17, 17);
                      SubItems.Add(IntToStr(i));
                    end;
                  end;
                end;
 
                ListView1.AlphaSort;
 
                Beep;
              end;
            end;
          end;
        end;
      end;
    end;
  finally
    FreeLibrary(fLibrary);
  end;
end;

下記のリンクにアクセスしてサンプルコードをダウンロードし、実際に試してみてください。

https://github.com/qq33095304/TensorFlow-Lite-Delphi

RAD Studio 13.2 Florence Now Available! Kai 1.1.1 Now Available! What's Coming in RAD Studio 13.2 Florence

Reduce development time and get to market faster with RAD Studio, Delphi, or C++Builder.
Design. Code. Compile. Deploy.

Start Free Trial   Upgrade Today

   Free Delphi Community Edition   Free C++Builder Community Edition

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.

IN THE ARTICLES