FPGA開発日記

カテゴリ別記事インデックス https://msyksphinz.github.io/github_pages , English Version https://fpgadevdiary.hatenadiary.com/

RISC-VプロセッサHiFive1で機械学習コードを動作させる(1.MNISTのロード)

そろそろHiFive1ボードを活用しないと、、、

MNISTのデータは非常に巨大で、フラッシュなどに入れないとHiFive1のチップの中にはもちろん入らない。 まずはMNISTデータを小さくしてオブジェクトとして貼り付け、HiFive1のシリアルコンソールから出力するところから始めよう。

MNISTデータを小さくしてオブジェクトにする

前回も紹介したが、MNISTデータは巨大だし、組み込み向けボードはファイルI/Oという概念がないので、「ファイルを開いてロードする」という手法は使えない。 従って、ファイルは予めRISC-V互換のオブジェクトファイルに変換しておき、それを実行ファイルにリンクしておくということでデータを読み込む。

普通のやつらの下を行け: objcopy で実行ファイルにデータを埋め込む - bkブログ

msyksphinz.hatenablog.com

まずは、train-images-idx3-ubyteのデータから先頭を切り取って小さくする。次に、objcopyを使ってこれをオブジェクトに変換するというわけだ。

train-images-idx3-ubyte.100.o: train-images-idx3-ubyte
    head -c 4000000 $< > $<.100
    riscv64-unknown-elf-objcopy -I binary -O elf32-littleriscv -B riscv --rename-section .data=.rodata $<.100 $@


%-ubyte.o: %-ubyte
    $(OBJCOPY) -I binary -O elf32-littleriscv -B riscv --rename-section .data=.rodata $(notdir $<) $(notdir $@)

一応hexdumpでファイルの中身を確認してみる。

f:id:msyksphinz:20170819024907p:plain

これがちゃんとオブジェクトファイルに変換されていればよい。

MNISTデータを埋め込んでシリアルコンソールに表示する

github.com

MNISTは以下のように埋め込んでいる。これを1文字ずつ変換してシリアルコンソールに表示する。write()関数は、HiFive1のシリアルコンソールに出力させる。

const char* hex_enum[] = {"0", "1", "2", "3", "4", "5", "6", "7",
                          "8", "9", "a", "b", "c", "d", "e", "f"};

int main ()
{
  write (STDOUT_FILENO, message, strlen (message));

  int len = _binary_train_images_idx3_ubyte_100_end - _binary_train_images_idx3_ubyte_100_start;
  
  int i;
  const int offset = 0x12;
  for (i = 0; i < len; i++) {
    char hex_value = _binary_train_images_idx3_ubyte_100_start[i+offset];
    
    write (STDOUT_FILENO, hex_enum[(hex_value >> 4) & 0x0f], 2); 
    write (STDOUT_FILENO, hex_enum[(hex_value >> 0) & 0x0f], 2);

    if ((i % 28) == 27) { write (STDOUT_FILENO, "\r\n", 2); }
  }

これで生成したバイナリファイルをHiFive1に流し込んで、実行してみる。

f:id:msyksphinz:20170819024526p:plain

無事にMNISTのデータを表示させることができた。