--------------------------------------------------------------------
Interface2016年9月号に掲載したプログラムと簡単な説明
--------------------------------------------------------------------

1. はじめに
手書き数字認識MNISTデータセットをディープニューラルネットワークで学習します.
学習はオフライン(PC)で行います.
学習したディープニューラルネットワークの重みをCソースに読み込み, 
Vivado HLSを使ってRTLに高位合成した後, Vivado でFPGAのビットストリームに合成し,
FPGA(Nexys4 DDR)で認識を行います. 認識用の画像はPC上のUSBカメラを使って
Pythonで取得→リサイズ・グレースケール化を行います.
PCとFPGAの通信はUART-USBシリアル通信を使いました.

2. 動作環境
PC: 64ビットマシン, 以下のソフトウェアをインストールしておく
学習とCソース実行… Ubuntu14.04 LTS 64ビット版+gcc
高位合成　… Vivado2015.1
FPGAビットストリーム生成 … Vivado2015.1
PC上での制御　…　Python2.7 on Ubuntu14.04 LTS
              + OpenCV2.4 + pySerial

FPGAボード: Digilent社 Nexys4 DDR
USBカメラ

※Ubuntu14.04 LTS64ビット版をお勧めしますが, Windows+仮想環境(VMWare)でも
  動作を確認しています.

※プログラムは全てUTF-8でコーディングされています。Vivado HLSはWindows上だと
　デフォルトでSJISなのでVivado HLSやVivadoのGUI上では文字コードが化けます。
　文字コードをUTF-8に設定すると正しく読めました。

3. ファイル構成
Learning … MNISTデータセットを使って学習を行います（オプション）
Prediction_C … 学習した重み係数を読み込んで、Cソースで検証します（オプション）
Python_script … FPGAと通信して認識を行います. Python2.7, OpenCV v2.4, pySerialが必要. 
Vivado … Vivado HLSで合成したRTLとシリアル通信用RTL, トップモジュール, 及び制約ファイル.
         FPGA合成用のビットストリームを生成します.
Vivado_HLS … CソースからRTLを高位合成します. ビット数は調整していますが, パイプライン化等のpragmaは
　　　　　　　　　　　入れていません. 多重ループになっているので,　上手くpragmaを入れてループ展開すると
　　　　　　　　　　　認識時間を速くすることができます.

4. 実行方法（詳しくは紙面を見てください）
4.1 MNISTデータセットを学習する（オプション）
別途MNISTデータセットをダウンロード後解凍して, Learningフォルダに置いてください.
あらかじめUbuntu14.04 LTS用にコンパイルした BinNetTrain を実行します.
２０分ほどすると, LeNet_weight.txt が生成されます.
時間がかかるので, 予め用意しておきました.

次に, Printout_Coef.c をコンパイルし,　LeNet_weight.txt を読み込みます.
Cソースの１次元配列が生成されるので, Prediction_CフォルダにあるBinaryNet.cの
先頭の配列を書き換えてください.

4.2 Cソースで認識を検証する（オプション）
Prediction_Cフォルダ内のBinaryNet.cをコンパイルして実行します.
テストデータのコメントを入れ替えると様々な数字を認識できるようになっています.

4.3 CソースからRTLをVivado HLSで高位合成する
Vivado_HLSフォルダ内にBinaryNet.cをHLSで合成できるように書き換えた
Vivado_HLS_BinNet.c を置いています. VivadoHLSで読み込んで高位合成してください.
なお, テストベンチも入れていますので, C検証も可能です.

4.4 高位合成したRTLをVivadoで合成し, ビットストリームを生成
Vivado HLSで生成したRTLをコピーして合成します.
トップモジュール(BinNet_top.v), UARTコア(UART_RX_CTRL.vhd,UART_TX_CTRL.vhd), 
制約ファイル(Nexys4DDR_Master.xdc)は予め用意しておきました.

4.5 FPGAをコンフィギュレーションし, PCからPythonを使って制御（認識を実行）
予め以下をインストールしておきます.

OpenCV2.4のインストール
#sudo apt-get install python-opencv

PySerialのインストール
#pip install pyserial

そのうえで,
$lsusb
$ls /dev
として, USBカメラが認識されていること, UARTのポート番号を確認してください.

$python predict_script.py

として認識を実行します. "p"キーを押すと認識が始まります. その他のキーで終了です.

5. さいごに
編集上の都合で前編後編と別れており、コードと説明がバラバラでわかりづらかったと思います。
後日、時間が出きれは補足説明資料をアップロードしますので、twitter(@oboe7man)の
フォローをお願いします。また、質問やご意見をどんどんください！

また、８月に開催されるFPGAXでもBinary化したディープニューラルネットワークの
説明をしようと思っております。

-----------------------------------------------------------------
中原　啓貴(東京工業大学)