FC2カウンター FPGAの部屋 finn
fc2ブログ

FPGAやCPLDの話題やFPGA用のツールの話題などです。 マニアックです。 日記も書きます。

FPGAの部屋

FPGAの部屋の有用と思われるコンテンツのまとめサイトを作りました。Xilinx ISEの初心者の方には、FPGAリテラシーおよびチュートリアルのページをお勧めいたします。

finn をやってみる14(tfc_end2end_example.ipynb その9)

finn をやってみる13(tfc_end2end_example.ipynb その8)”の続き。

前回は、Vivado 2019.1 を使用して、もう一度、end2end_example の tfc_end2end_example.ipynb をやり直したところ、 4. PYNQ hardware generation and deployment の Inserting the IP into a PYNQ Overlay Shell で Vivado プロジェクトが生成された。今回は、 4. PYNQ hardware generation and deployment の Driver Generation からやってみよう。

今回も end2end_example の tfc_end2end_example.ipynb の図や文章の翻訳、コードを引用して勉強していく。

Driver Generation
ネットワークのビットファイルを合成したので、このビットファイルのドライバーとして機能するPYNQのPythonコードを生成し、すべてを展開フォルダーにパッケージ化して、PYNQボードにコピーする。
finn_100_200609.png

生成されたドライバーは、pynq_driver_dirトップレベルメタデータで示されるフォルダーに配置される。生成されたPYNQ Pythonドライバーコードを次のように確認できる。
finn_101_200609.png

実際のドライバコードは、/tmp/finn_dev_masaaki/pynq_deployment_0fgmr9qo にあって、そのディレクトリには、 driver.py, finn ディレクトリ、 input.npy, resizer.bit, resizer.hwh ファイルがある。
finn_102_200609.png

driver.py を引用する。

import argparse

from pynq import Overlay
import numpy as np
from pynq import allocate
import time
from finn.util.data_packing import (
    finnpy_to_packed_bytearray,
    packed_bytearray_to_finnpy
)
from finn.core.datatype import DataType

class FINNAccelDriver():
    def __init__(self, N, bitfile):
        """Instantiate the FINN accelerator driver.
        Gets batchsize (N) as integer and path to bitfile as string."""
        self.N = N
        # input FINN DataType
        self.idt = DataType.BINARY
        # output FINN DataType
        self.odt = DataType.UINT32
        # input and output shapes
        self.ishape_normal = (N, 784)
        self.oshape_normal = (N, 10)
        self.ishape_folded = (N, 16, 49)
        self.oshape_folded = (N, 1, 10)
        self.ishape_packed = (N, 16, 7)   # datatype np.uint8
        self.oshape_packed = (N, 1, 40)  # datatype np.uint8
        # load bitfile and set up accelerator
        self.ol = Overlay(bitfile)
        self.dma = self.ol.axi_dma_0
        self.ctrl_regs = self.ol.resize_accel_0
        # neuron folding factor of output = iterations per sample
        self.itersPerSample = self.oshape_packed[-2]
        # AXI lite register offset for number of iterations
        # used by TLastMarker to signal end of transmission for AXI CDMA
        self.REG_OFFSET_NUM_ITERS = 0x10
        # set up TLastMarker with correct num. samples
        self.ctrl_regs.write(self.REG_OFFSET_NUM_ITERS, self.N*self.itersPerSample)

        # allocate a PYNQ buffer for the packed input and buffer
        self.ibuf_packed_device = allocate(shape=self.ishape_packed, dtype=np.uint8)
        self.obuf_packed_device = allocate(shape=self.oshape_packed, dtype=np.uint8)

    def fold_input(self, ibuf_normal):
        """Reshapes input in desired shape.
        Gets input data (ibuf_normal), checks if data is in expected normal shape.
        Returns folded input."""
        # ensure that shape is as expected
        assert ibuf_normal.shape == self.ishape_normal
        # convert to folded form
        ibuf_folded = ibuf_normal.reshape(self.ishape_folded)
        return ibuf_folded

    def pack_input(self, ibuf_folded):
        """Packs folded input and reverses both SIMD dim and endianness.
        Gets input data in folded shape and returns packed input data."""
        ibuf_packed = finnpy_to_packed_bytearray(
            ibuf_folded, self.idt, reverse_endian=True, reverse_inner=True
        )
        return ibuf_packed

    def unpack_output(self, obuf_packed):
        """Unpacks the packed output buffer from accelerator.
        Gets packed output and returns output data in folded shape."""
        obuf_folded = packed_bytearray_to_finnpy(
            obuf_packed, self.odt, self.oshape_folded, reverse_endian=True, reverse_inner=True
        )
        return obuf_folded

    def unfold_output(self, obuf_folded):
        """Unfolds output data to normal shape.
        Gets folded output data and returns output data in normal shape."""
        obuf_normal = obuf_folded.reshape(self.oshape_normal)
        return obuf_normal

    def copy_input_data_to_device(self, data):
        """Copies given input data to PYNQ buffer."""
        np.copyto(self.ibuf_packed_device, data)

    def execute(self):
        """Executes accelerator by setting up the DMA and
        waiting until all transfers complete. Uses only member variables and
        returns nothing."""
        dma = self.dma
        dma.sendchannel.transfer(self.ibuf_packed_device)
        dma.recvchannel.transfer(self.obuf_packed_device)
        dma.sendchannel.wait()
        dma.recvchannel.wait()


if __name__ == "__main__":
    parser = argparse.ArgumentParser(description='Set exec mode, batchsize N, bitfile name, inputfile name and outputfile name')
    parser.add_argument('--exec_mode', help='Please select functional verification ("execute") or throughput test ("throughput_test")', default="execute")
    parser.add_argument('--batchsize', help='number of samples for inference', type=int, default=1)
    parser.add_argument('--bitfile', help='name of bitfile (i.e. "resizer.bit")', default="resizer.bit")
    parser.add_argument('--inputfile', help='name of input npy file (i.e. "input.npy")', default="input.npy")
    parser.add_argument('--outputfile', help='name of output npy file (i.e. "output.npy")', default="output.npy")
    # parse arguments
    args = parser.parse_args()
    exec_mode = args.exec_mode
    N = args.batchsize
    bitfile = args.bitfile
    inputfile = args.inputfile
    outputfile = args.outputfile

    # instantiate FINN accelerator driver and pass batchsize and bitfile
    finnDriver = FINNAccelDriver(N, bitfile)

    # for the remote execution the data from the input npy file has to be loaded,
    # packed and copied to the PYNQ buffer
    if exec_mode == "execute":
        # load desired input .npy file
        ibuf_normal = np.load(inputfile)
        ibuf_folded = finnDriver.fold_input(ibuf_normal)
        ibuf_packed = finnDriver.pack_input(ibuf_folded)
        finnDriver.copy_input_data_to_device(ibuf_packed)
    elif exec_mode != "throughput_test":
        raise Exception("Exec mode has to be set to remote_pynq or throughput_test")

    # for the throughput test the runtime of the network has to be measured
    if exec_mode == "throughput_test":
        # measure runtime of network
        start = time.time()
        # dictionary for results of throughput test
        res={}

    # execute accelerator
    finnDriver.execute()

    # measure run time and fill dictionary with results of the throughput test
    if exec_mode == "throughput_test":
        end = time.time()
        runtime = end - start
        res["runtime[ms]"] = runtime*1000
        res["throughput[images/s]"] = N / runtime
        res["DRAM_in_bandwidth[Mb/s]"] = np.prod(finnDriver.ishape_packed)*0.000001 / runtime
        res["DRAM_out_bandwidth[Mb/s]"] = np.prod(finnDriver.oshape_packed)*0.000001 / runtime
        file = open("nw_metrics.txt", "w")
        file.write(str(res))
        file.close()

    # if execution is selected unpack, unfold and save output to output npy file
    else:
        obuf_folded = finnDriver.unpack_output(finnDriver.obuf_packed_device)
        obuf_normal = finnDriver.unfold_output(obuf_folded)
        np.save(outputfile, obuf_normal)


生成されたドライバーには、FINNアクセラレーターを実装するクラスが実装されていることがわかる。コンストラクタは、バッチサイズ(N)を整数として、ビットファイルを文字列として取得する。また、予想される入力/出力形状も含まれており、ビットファイルをロードしてdmaとバッファーを設定することにより、アクセラレーターのインスタンス化を処理する。いくつかのメンバー関数がデータの折りたたみとパッキングを処理する。関数copy_input_data_to_deviceは、入力データをPYNQバッファーにコピーして実行し、dmaチャネルをセットアップして、転送が完了するまで待機する。このクラスはmain関数で使用される。ただし、最初に引数が解析され、スクリプトに渡される。このドライバーは、「execute」と「throughput_test」の2つのモードで使用できる。デフォルトでは、すべての引数が「execute」モードに設定されている。このモードでは、バッチサイズは1であり、渡されたファイルはFINN変換で使用される名前に設定される。

「execute」モードでは、次のように機能する。

1. データは 「inputfile」 からロードされる
2. データは fold_input を使用して折りたたまれる
3. データは pack_input を使用してパックされる
4. データは copy_input_data_to_device を使用してデバイスにコピーされる
5. FINNAccelDriver は、 execute で実行される
6. データは unpack_output で解凍される
7. データは unfold_output で展開される
8. データは 「outputfile」 に保存される

「throughput_test」がexec_modeとして選択されている場合、実際のデータをロードする必要はない。バッチサイズNは高い値(つまり1000)に設定する必要があり、時間測定はPythonで実装される。空の辞書(res)が作成され、測定されたランタイムでアクセラレーターを実行した後、メトリックが入力され、.txtファイルに保存される。

ドライバーを変更してアクセラレーターを中心に独自のアプリケーションを構築するか、FINNが提供するリモート実行機能を使用して、それが機能しているかどうかを確認することができる。
  1. 2020年06月10日 03:38 |
  2. finn
  3. | トラックバック:0
  4. | コメント:0

finn をやってみる13(tfc_end2end_example.ipynb その8)

”finn をやってみる12(tfc_end2end_example.ipynb その7)”の続き。

前回は、end2end_example の tfc_end2end_example.ipynb の 4. PYNQ hardware generation and deployment の Inserting the IP into a PYNQ Overlay Shell で Vivado プロジェクトが生成されていなかった。トラブルシューティングをしたところ、Vivado の 2019.2 バージョンを使用していてはダメで、 2019.1 を使う必要があるということが分かった。今回は、Vivado 2019.1 を使用して、もう一度、end2end_example の tfc_end2end_example.ipynb をやり直してみようと思う。

今回も end2end_example の tfc_end2end_example.ipynb の図や文章の翻訳、コードを引用して勉強していく。

まずは、docker image は finn_dev_masaaki という名前で 8.4 GB 程度消費している。それを削除した。
docker rmi <イメージID>

finn ディレクトリも一旦削除して、もう一度 git clone した。
rm -rf finn
git clone https://github.com/Xilinx/finn.git


VIVADO_PATH 環境変数には、Vivado 2019.1 のインストール・ディレクトリを指定した。
export VIVADO_PATH=/media/masaaki/Ubuntu_Disk/tools/Xilinx/Vivado/2019.1

Docker を走らせて finn のインストールを行った。
sh run-docker.sh

インストール後に exit してから、 Jupyter Notebook を起動した。
sh run-docker.sh notebook

end2end_example の tfc_end2end_example.ipynb を起動して、最初から実行して、 Inserting the IP into a PYNQ Overlay Shell まで実行すると、”何ということでしょう”(大改造!!劇的ビフォーアフター(TV番組)の真似です)、Vivado のプロジェクトが作成されていました。やはり、Vivado 2019.1 を使う必要があるんですね。。。
finn_91_200608.png

Docker コンテナから /tmp/finn_dev_masaaki ディレクトリをコピーした。
docker cp 4cd592793b01:/tmp/finn_dev_masaaki .
finn_92_200608.png

finn/finn_dev_masaaki/vivado_pynq_proj_4vynls70 の Vivado 2019.1 プロジェクトを開いた。
finn_93_200608.png

ブロックデザインを開いた。
resize_accel_0 が FINN 部分ということだ。DMA エンジンやデータ幅コンバーター等もある。なお、Run Block Automation が表示されているのは、ZYNQ7 Processing System の設定がされていないからだ。あとで設定するのだろうか?
finn_94_200608.png

Address Editor 画面を示す。
finn_95_200608.png

Synthesis, Place and Route
これで、FPGAビットファイルを生成するための合成、配置、配線の最後のハードウェア生成ステップの準備が整った。 これは、Docker内の生成されたVivado PYNQプロジェクトディレクトリで synth_project.sh スクリプトを実行するか、 SynthPYNQProject 変換を実行することで実行できる。 この手順では、合成のためにVivadoを起動する必要があり、数時間かかる場合がある。
モデルを tfc_w1_a1_post_synthesis.onnx にセーブした。
finn_96_200608.png

finn_dev_masaaki ディレクトリを削除して、もう一度、Docker コンテナから /tmp/finn_dev_masaaki ディレクトリをコピーした。
docker cp 4cd592793b01:/tmp/finn_dev_masaaki .

Vivado 2019.1 を起動して、 finn/finn_dev_masaaki/vivado_pynq_proj_4vynls70 の Vivado 2019.1 プロジェクトを開いた。
finn_97_200608.png

Project Summary を示す。無事にビットストリームが生成されている。
finn_98_200608.png

ブロックデザインを見ると、まだ、Run Block Automation が表示されている。ZYNQ7 Processing System の設定がされないまま、ビットストリーム生成までできてしまったようだ。これで良いのだろうか?後で設定できるのかな?謎である。これができれば汎用にコンパイルしておいて、後で ZYNQ7 Processing System の設定だけ入れて使いまわすということができるはず。。。
finn_99_200608.png
  1. 2020年06月08日 04:27 |
  2. finn
  3. | トラックバック:0
  4. | コメント:0

finn をやってみる12(tfc_end2end_example.ipynb その7)

finn をやってみる11(tfc_end2end_example.ipynb その6)”の続き。

前回は、end2end_example の tfc_end2end_example.ipynb 3. Vivado HLS and IPI の IP Stitching をやって、Vivado のプロジェクトを確認した。今回は、end2end_example の tfc_end2end_example.ipynb の 4. PYNQ hardware generation and deployment からやってみよう。

今回も end2end_example の tfc_end2end_example.ipynb の図や文章の翻訳、コードを引用して勉強していく。

4. PYNQ hardware generation and deployment

・ Inserting the IP into a PYNQ Overlay Shell
・ Synthesis, Place and Route
・ Driver Generation
・ Deployment and Remote Execution
・ Throughput Test on PYNQ Board


ハードウェア設計の準備がほぼ完了した。次に、PYNQオーバーレイとしての使用に適した形式で配置し、合成して展開する。

Inserting the IP into a PYNQ Overlay Shell
アクセラレータをPYNQプラットフォームにデプロイするには、基盤となるシステムが公開するインターフェースとブリッジする適切なシェル内にアクセラレータを配置する必要がある。 FINNでは、MakePYNQProjectトランスフォーメーションを使用して適切なPYNQシェルにステッチされたIPを挿入することでPYNQ互換オーバーレイを簡単に作成し、metadata_propsを使用して作成されたPYNQシェルプロジェクトディレクトリを表示する。 これによりVivadoが起動し、実行に数分かかる場合がある。
finn_88_200607.png

Vivado のプロジェクトが生成されていない? たぶん、make_project.sh が実行されいないのではないだろうか?
もう一度やってみたが同じだった。さらにもう一度最初からやってみたがダメだった。

ちなみに、end2end_example の tfc_end2end_example.ipynb の結果を示す。

ip_config.tcl    resizer.cache        resizer.ip_user_files  resizer.xpr
make_project.sh  resizer.hw     resizer.srcs           synth_project.sh


このように Vivado プロジェクトのディレクトリが生成されている。

Docker 上の /tmp/finn_dev_masaaki ディレクトリを見ると、 vivado_pynq_proj_s42jfdkl が増えている。
finn_89_200607.png

作成したVivadoプロジェクト(.xpr)を上のvivado_pynq_projディレクトリの下で開くと、システムレベルのブロックデザインが次のように表示され、デザインのFINN生成部分が強調表示されている。 DMAエンジンやデータ幅コンバーターなど、他のさまざまなコンポーネントもインスタンス化されている。ということなので、Vivado プロジェクトを見てみよう。

前回 Docker コンテナからコピーした /tmp/finn_dev_masaaki ディレクトリを一旦削除した。
もう一度、Docker コンテナから /tmp/finn_dev_masaaki ディレクトリをコピーしよう。
docker cp 7b13e06d4195:/tmp/finn_dev_masaaki .

コピーされた finn_dev_masaaki ディレクトリの中に vivado_pynq_proj_s42jfdkl があって、やはり 3 個の tcl スクリプトしかない。
finn_90_200607.png

おかしいので検索してみると、FINN Community の記事が引っかかった。
それによると Vivado 2019.2 ではだめで、 2019.1 が必要ということだった。現在、Vivado 2019.2 を使用しているので、Vivado 2019.1 に変更する必要があるようだ。

もう一度、最初から Vivado 2019.1 でやり直してみよう。
  1. 2020年06月07日 04:42 |
  2. finn
  3. | トラックバック:0
  4. | コメント:0

finn をやってみる11(tfc_end2end_example.ipynb その6)

finn をやってみる10(tfc_end2end_example.ipynb その5)”の続き。

前回は、 end2end_example の tfc_end2end_example.ipynb の 3. Vivado HLS and IPI の Synthesizing HLS to IP Blocks まで実行して、docker でコンテナに入り、Vivado HLS プロジェクトをみた。今回は、続きの end2end_example の tfc_end2end_example.ipynb の 3. Vivado HLS and IPI の IP Stitching からやっていこう。

今回も end2end_example の tfc_end2end_example.ipynb の図や文章の翻訳、コードを引用して勉強していく。

IP Stitching
これで、各層にIPブロックがあり、それらをCreateStitchedIP 変換を使用してネットワーク全体を実装するより大きなIPにまとめる。 この変換は、すでに HLSSynthIP 変換を実行した HLS ノードのみを含むグラフにのみ適用できることに注意。これは、実行する最後のステップだ。 IPスティッチングを呼び出す前に、 ReplaceVerilogRelPaths 変換を使用して、生成されたIPブロック内の相対 $readmemhパスを絶対パスに変換します。これにより、後でエラーが発生しなくなる。 この手順によりVivadoが呼び出され、実行に数分かかる場合がある。
finn_80_200606.png

変換されたモデルのノード自体を調べる場合、IP Stitching がグラフにモデルレベルのメタデータを追加するため、違いはわからない。 これには、ModelWrapperの.model.metadata_props、get_metadata_prop関数を使用するか、Netronのグローバル入力/出力テンソルをクリックしてアクセスできる。
finn_81_200606.png

Docker コンテナ内の /tmp/finn_dev_masaaki に Vivado プロジェクトなどが入っている。それを Vivado でみられるはずなのだが、Docker で Vivado の GUI が動作しなかったので、後でコンテナからコピーしてやってみよう。

tfc_w1_a1_ipstitch.onnx としてモデルをセーブする。
finn_82_200606.png

ここで、Docker コンテナから /tmp/finn_dev_masaaki ディレクトリをローカルに保存して Vivado のプロジェクトを見てみよう。
Dockerコンテナからホストへファイルをコピーする”を参考にして、Docker コンテナから /tmp/finn_dev_masaaki ディレクトリをコピーしよう。
docker ps
docker cp 7b13e06d4195:/tmp/finn_dev_masaaki .

finn_83_200606.png

finn_dev_masaaki ディレクトリがコピーされた。
finn_84_200606.png

finn_dev_masaaki/vivado_stitch_proj_su3iq9q8 ディレクトリが Vivado のプロジェクト・ディレクトリとなる。 finn_vivado_stitch_proj.xpr を Vivado 2019.2 で開いた。
finn_86_200606.png

ブロックデザインを開くと、tfc_w1_a1_ipgen.onnx がブロックデザインに表現されていた。
finn_87_200606.png
  1. 2020年06月06日 20:33 |
  2. finn
  3. | トラックバック:0
  4. | コメント:0

finn をやってみる10(tfc_end2end_example.ipynb その5)

finn をやってみる9(tfc_end2end_example.ipynb その4)”の続き。

前回は、 end2end_example の tfc_end2end_example.ipynb の 3. Vivado HLS and IPI の Synthesizing HLS to IP Blocks まで実行して、docker でコンテナに入り、Vivado HLS プロジェクトを覗き始めた。今回は、その続きで、Vivado HLS のプロジェクトを見ていこう。

code_gen_ipgen_StreamingFCLayer_Batch_0_av35euos に入ったところからスタートだ。
sol1 ディレクトリに移動して、syn と syn/report ディレクトリの内容と impl_ip ディレクトリの内容を見た。
impl/ip ディレクトリには、IP の圧縮形式の xilinx_com_hls_StreamingFCLayer_Batch_0_1_0.zip が見えた。
finn_76_200604.png

syn/report の StreamingFCLayer_Batch_0_csynth.rpt を示す。

================================================================
== Vivado HLS Report for 'StreamingFCLayer_Batch_0'
================================================================
* Date:           Tue Jun  2 19:58:23 2020

* Version:        2019.2 (Build 2698951 on Thu Oct 24 19:15:34 MDT 2019)
* Project:        project_StreamingFCLayer_Batch_0
* Solution:       sol1
* Product family: zynq
* Target device:  xc7z020-clg400-1


================================================================
== Performance Estimates
================================================================
+ Timing: 
    * Summary: 
    +--------+----------+----------+------------+
    |  Clock |  Target  | Estimated| Uncertainty|
    +--------+----------+----------+------------+
    |ap_clk  | 10.00 ns | 8.488 ns |   1.25 ns  |
    +--------+----------+----------+------------+

+ Latency: 
    * Summary: 
    +---------+---------+----------+----------+-----+-----+---------+
    |  Latency (cycles) |  Latency (absolute) |  Interval | Pipeline|
    |   min   |   max   |    min   |    max   | min | max |   Type  |
    +---------+---------+----------+----------+-----+-----+---------+
    |       70|       70| 0.700 us | 0.700 us |   70|   70|   none  |
    +---------+---------+----------+----------+-----+-----+---------+

    + Detail: 
        * Instance: 
        +--------------------------------+----------------------+---------+---------+----------+----------+-----+-----+---------+
        |                                |                      |  Latency (cycles) |  Latency (absolute) |  Interval | Pipeline|
        |            Instance            |        Module        |   min   |   max   |    min   |    max   | min | max |   Type  |
        +--------------------------------+----------------------+---------+---------+----------+----------+-----+-----+---------+
        |grp_Matrix_Vector_Activa_fu_28  |Matrix_Vector_Activa  |       67|       67| 0.670 us | 0.670 us |   67|   67|   none  |
        +--------------------------------+----------------------+---------+---------+----------+----------+-----+-----+---------+

        * Loop: 
        N/A



================================================================
== Utilization Estimates
================================================================
* Summary: 
+-----------------+---------+-------+--------+-------+-----+
|       Name      | BRAM_18K| DSP48E|   FF   |  LUT  | URAM|
+-----------------+---------+-------+--------+-------+-----+
|DSP              |        -|      -|       -|      -|    -|
|Expression       |        -|      -|       0|      2|    -|
|FIFO             |        -|      -|       -|      -|    -|
|Instance         |        -|      -|    2530|  25464|    -|
|Memory           |        -|      -|       -|      -|    -|
|Multiplexer      |        -|      -|       -|     45|    -|
|Register         |        -|      -|       5|      -|    -|
+-----------------+---------+-------+--------+-------+-----+
|Total            |        0|      0|    2535|  25511|    0|
+-----------------+---------+-------+--------+-------+-----+
|Available        |      280|    220|  106400|  53200|    0|
+-----------------+---------+-------+--------+-------+-----+
|Utilization (%)  |        0|      0|       2|     47|    0|
+-----------------+---------+-------+--------+-------+-----+

+ Detail: 
    * Instance: 
    +--------------------------------+----------------------+---------+-------+-
-----+-------+-----+
    |            Instance            |        Module        | BRAM_18K| DSP48E| 
 FF  |  LUT  | URAM|
    +--------------------------------+----------------------+---------+-------+-
-----+-------+-----+
    |grp_Matrix_Vector_Activa_fu_28  |Matrix_Vector_Activa  |        0|      0| 
 2530|  25464|    0|
    +--------------------------------+----------------------+---------+-------+-
-----+-------+-----+
    |Total                           |                      |        0|      0| 
 2530|  25464|    0|
    +--------------------------------+----------------------+---------+-------+-
-----+-------+-----+

    * DSP48E: 
    N/A

    * Memory: 
    N/A

    * FIFO: 
    N/A

    * Expression: 
    +-----------------------------------------------+----------+-------+---+----
+------------+------------+
    |                 Variable Name                 | Operation| DSP48E| FF| LUT
| Bitwidth P0| Bitwidth P1|
    +-----------------------------------------------+----------+-------+---+----
+------------+------------+
    |grp_Matrix_Vector_Activa_fu_28_out_V_V_TREADY  |    and   |      0|  0|   2
|           1|           1|
    +-----------------------------------------------+----------+-------+---+----
+------------+------------+
    |Total                                          |          |      0|  0|   2
|           1|           1|
    +-----------------------------------------------+----------+-------+---+----
+------------+------------+

    * Multiplexer: 
    +------------------------+----+-----------+-----+-----------+
    |          Name          | LUT| Input Size| Bits| Total Bits|
    +------------------------+----+-----------+-----+-----------+
    |ap_NS_fsm               |  27|          5|    1|          5|
    |in0_V_V_TREADY_int      |   9|          2|    1|          2|
    |weights_V_V_TREADY_int  |   9|          2|    1|          2|
    +------------------------+----+-----------+-----+-----------+
    |Total                   |  45|          9|    3|          9|
    +------------------------+----+-----------+-----+-----------+

    * Register: 
    +---------------------------------------------+---+----+-----+-----------+
    |                     Name                    | FF| LUT| Bits| Const Bits|
    +---------------------------------------------+---+----+-----+-----------+
    |ap_CS_fsm                                    |  4|   0|    4|          0|
    |grp_Matrix_Vector_Activa_fu_28_ap_start_reg  |  1|   0|    1|          0|
    +---------------------------------------------+---+----+-----+-----------+
    |Total                                        |  5|   0|    5|          0|
    +---------------------------------------------+---+----+-----+-----------+



================================================================
== Interface
================================================================
* Summary: 
+--------------------+-----+-----+--------------+--------------------------+----
----------+
|      RTL Ports     | Dir | Bits|   Protocol   |       Source Object      |    
C Type    |
+--------------------+-----+-----+--------------+--------------------------+----
----------+
|ap_clk              |  in |    1| ap_ctrl_none | StreamingFCLayer_Batch_0 | ret
urn value |
|ap_rst_n            |  in |    1| ap_ctrl_none | StreamingFCLayer_Batch_0 | ret
urn value |
|in0_V_V_TDATA       |  in |   56|     axis     |          in0_V_V         |    
pointer   |
|in0_V_V_TVALID      |  in |    1|     axis     |          in0_V_V         |    
pointer   |
|in0_V_V_TREADY      | out |    1|     axis     |          in0_V_V         |    
pointer   |
|weights_V_V_TDATA   |  in |  784|     axis     |        weights_V_V       |    
pointer   |
|weights_V_V_TVALID  |  in |    1|     axis     |        weights_V_V       |    
pointer   |
|weights_V_V_TREADY  | out |    1|     axis     |        weights_V_V       |    
pointer   |
|out_V_V_TDATA       | out |   16|     axis     |          out_V_V         |    
pointer   |
|out_V_V_TVALID      | out |    1|     axis     |          out_V_V         |    
pointer   |
|out_V_V_TREADY      |  in |    1|     axis     |          out_V_V         |    
pointer   |
+--------------------+-----+-----+--------------+--------------------------+----
----------+


次に、 /tmp/finn_dev_masaaki/code_gen_ipgen_StreamingFCLayer_Batch_0_av35euos の ソースコードの top_StreamingFCLayer_Batch_0.cpp の関数定義文を示す。

void StreamingFCLayer_Batch_0(
                    hls::stream<ap_uint<49>> &in0,
                    hls::stream<ap_uint<784>> &weights,
                    hls::stream<ap_uint<16>> &out
                    )


これを合成した HDL の内の VHDL ファイルを示す。
/tmp/finn_dev_masaaki/code_gen_ipgen_StreamingFCLayer_Batch_0_av35euos/project_StreamingFCLayer_Batch_0/sol1/syn/vhdl ディレクトリの StreamingFCLayer_Batch_0_StreamingFCLayer_Batch_0.vhd の entity 文だけを引用する。

entity StreamingFCLayer_Batch_0_StreamingFCLayer_Batch_0 is
port (
    ap_clk : IN STD_LOGIC;
    ap_rst_n : IN STD_LOGIC;
    in0_V_V_TDATA : IN STD_LOGIC_VECTOR (55 downto 0);
    in0_V_V_TVALID : IN STD_LOGIC;
    in0_V_V_TREADY : OUT STD_LOGIC;
    weights_V_V_TDATA : IN STD_LOGIC_VECTOR (783 downto 0);
    weights_V_V_TVALID : IN STD_LOGIC;
    weights_V_V_TREADY : OUT STD_LOGIC;
    out_V_V_TDATA : OUT STD_LOGIC_VECTOR (15 downto 0);
    out_V_V_TVALID : OUT STD_LOGIC;
    out_V_V_TREADY : IN STD_LOGIC );
end;


次に、 code_gen_ipgen_StreamingDataWidthConverter_Batch_0_nzm_awqb を見てみよう。
finn_77_200605.png

hls_syn_StreamingDataWidthConverter_Batch_0.tcl や ソースコードの top_StreamingDataWidthConverter_Batch_0.cpp などがある。

/tmp/finn_dev_masaaki/code_gen_ipgen_StreamingDataWidth
Converter_Batch_0_nzm_awqb/project_StreamingDataWidthConverter_Batch_0/sol1 に移動して、syn ディレクトリや syn/report ディレクトリを見た。
finn_78_200605.png

StreamingDataWidthConverter_Batch_0_csynth.rpt を見てみよう。

================================================================
== Vivado HLS Report for 'StreamingDataWidthConverter_Batch_0'
================================================================
* Date:           Tue Jun  2 19:55:07 2020

* Version:        2019.2 (Build 2698951 on Thu Oct 24 19:15:34 MDT 2019)
* Project:        project_StreamingDataWidthConverter_Batch_0
* Solution:       sol1
* Product family: zynq
* Target device:  xc7z020-clg400-1


================================================================
== Performance Estimates
================================================================
+ Timing: 
    * Summary: 
    +--------+----------+----------+------------+
    |  Clock |  Target  | Estimated| Uncertainty|
    +--------+----------+----------+------------+
    |ap_clk  | 10.00 ns | 5.723 ns |   1.25 ns  |
    +--------+----------+----------+------------+

+ Latency: 
    * Summary: 
    +---------+---------+-----------+-----------+-----+-----+---------+
    |  Latency (cycles) |   Latency (absolute)  |  Interval | Pipeline|
    |   min   |   max   |    min    |    max    | min | max |   Type  |
    +---------+---------+-----------+-----------+-----+-----+---------+
    |        7|        7| 70.000 ns | 70.000 ns |    7|    7|   none  |
    +---------+---------+-----------+-----------+-----+-----+---------+

    + Detail: 
        * Instance: 
        +----------------------------------+------------------------+---------+---------+-----------+-----------+-----+-----+---------+
        |                                  |                        |  Latency (cycles) |   Latency (absolute)  |  Interval | Pipeline|
        |             Instance             |         Module         |   min   |   max   |    min    |    max    | min | max |   Type  |
        +----------------------------------+------------------------+---------+---------+-----------+-----------+-----+-----+---------+
        |grp_StreamingDataWidthCo_1_fu_26  |StreamingDataWidthCo_1  |        4|        4| 40.000 ns | 40.000 ns |    4|    4|   none  |
        +----------------------------------+------------------------+---------+---------+-----------+-----------+-----+-----+---------+

        * Loop: 
        N/A



================================================================
== Utilization Estimates
================================================================
* Summary: 
+-----------------+---------+-------+--------+-------+-----+
|       Name      | BRAM_18K| DSP48E|   FF   |  LUT  | URAM|
+-----------------+---------+-------+--------+-------+-----+
|DSP              |        -|      -|       -|      -|    -|
|Expression       |        -|      -|       0|      2|    -|
|FIFO             |        -|      -|       -|      -|    -|
|Instance         |        -|      -|      65|    241|    -|
|Memory           |        -|      -|       -|      -|    -|
|Multiplexer      |        -|      -|       -|     36|    -|
|Register         |        -|      -|       5|      -|    -|
+-----------------+---------+-------+--------+-------+-----+
|Total            |        0|      0|      70|    279|    0|
+-----------------+---------+-------+--------+-------+-----+
|Available        |      280|    220|  106400|  53200|    0|
+-----------------+---------+-------+--------+-------+-----+
|Utilization (%)  |        0|      0|   ~0   |   ~0  |    0|
+-----------------+---------+-------+--------+-------+-----+

+ Detail: 
    * Instance: 
    +----------------------------------+------------------------+---------+-------+----+-----+-----+
    |             Instance             |         Module         | BRAM_18K| DSP48E| FF | LUT | URAM|
    +----------------------------------+------------------------+---------+-------+----+-----+-----+
    |grp_StreamingDataWidthCo_1_fu_26  |StreamingDataWidthCo_1  |        0|      0|  65|  241|    0|
    +----------------------------------+------------------------+---------+-------+----+-----+-----+
    |Total                             |                        |        0|      0|  65|  241|    0|
    +----------------------------------+------------------------+---------+-------+----+-----+-----+

    * DSP48E: 
    N/A

    * Memory: 
    N/A

    * FIFO: 
    N/A

    * Expression: 
    +-------------------------------------------------+----------+-------+---+----+------------+------------+
    |                  Variable Name                  | Operation| DSP48E| FF| LUT| Bitwidth P0| Bitwidth P1|
    +-------------------------------------------------+----------+-------+---+----+------------+------------+
    |grp_StreamingDataWidthCo_1_fu_26_out_V_V_TREADY  |    and   |      0|  0|   2|           1|           1|
    +-------------------------------------------------+----------+-------+---+----+------------+------------+
    |Total                                            |          |      0|  0|   2|           1|           1|
    +-------------------------------------------------+----------+-------+---+----+------------+------------+

    * Multiplexer: 
    +--------------------+----+-----------+-----+-----------+
    |        Name        | LUT| Input Size| Bits| Total Bits|
    +--------------------+----+-----------+-----+-----------+
    |ap_NS_fsm           |  27|          5|    1|          5|
    |in0_V_V_TREADY_int  |   9|          2|    1|          2|
    +--------------------+----+-----------+-----+-----------+
    |Total               |  36|          7|    2|          7|
    +--------------------+----+-----------+-----+-----------+

    * Register: 
    +-----------------------------------------------+---+----+-----+-----------+
    |                      Name                     | FF| LUT| Bits| Const Bits|
    +-----------------------------------------------+---+----+-----+-----------+
    |ap_CS_fsm                                      |  4|   0|    4|          0|
    |grp_StreamingDataWidthCo_1_fu_26_ap_start_reg  |  1|   0|    1|          0|
    +-----------------------------------------------+---+----+-----+-----------+
    |Total                                          |  5|   0|    5|          0|
    +-----------------------------------------------+---+----+-----+-----------+



================================================================
== Interface
================================================================
* Summary: 
+----------------+-----+-----+--------------+-------------------------------------+--------------+
|    RTL Ports   | Dir | Bits|   Protocol   |            Source Object            |    C Type    |
+----------------+-----+-----+--------------+-------------------------------------+--------------+
|ap_clk          |  in |    1| ap_ctrl_none | StreamingDataWidthConverter_Batch_0 | return value |
|ap_rst_n        |  in |    1| ap_ctrl_none | StreamingDataWidthConverter_Batch_0 | return value |
|in0_V_V_TDATA   |  in |   16|     axis     |               in0_V_V               |    pointer   |
|in0_V_V_TVALID  |  in |    1|     axis     |               in0_V_V               |    pointer   |
|in0_V_V_TREADY  | out |    1|     axis     |               in0_V_V               |    pointer   |
|out_V_V_TDATA   | out |    8|     axis     |               out_V_V               |    pointer   |
|out_V_V_TVALID  | out |    1|     axis     |               out_V_V               |    pointer   |
|out_V_V_TREADY  |  in |    1|     axis     |               out_V_V               |    pointer   |
+----------------+-----+-----+--------------+-------------------------------------+--------------+


project_StreamingDataWidthConverter_Batch_0 は 7 クロックしかかかっていない。
たしかこれは、ストリームの幅を変えると言っていたので、ソースコードの top_StreamingDataWidthConverter_Batch_0.cpp の関数宣言部分を見てみよう。

void StreamingDataWidthConverter_Batch_0(hls::stream > &in0, hls::stream > &out)


16 ビット幅から 8 ビット幅に変換しているようだ。

合成された VHDL ファイルの StreamingDataWidthConverter_Batch_0_StreamingDataWidthConverter_Batch_0.vhd の entity 部分を見てみよう。

entity StreamingDataWidthConverter_Batch_0_StreamingDataWidthConverter_Batch_0 i
s
port (
    ap_clk : IN STD_LOGIC;
    ap_rst_n : IN STD_LOGIC;
    in0_V_V_TDATA : IN STD_LOGIC_VECTOR (15 downto 0);
    in0_V_V_TVALID : IN STD_LOGIC;
    in0_V_V_TREADY : OUT STD_LOGIC;
    out_V_V_TDATA : OUT STD_LOGIC_VECTOR (7 downto 0);
    out_V_V_TVALID : OUT STD_LOGIC;
    out_V_V_TREADY : IN STD_LOGIC );
end;


in0_V_V_TDATA が 16 ビット幅で、out_V_V_TDATA が 8 ビット幅だった。

/tmp/finn_dev_masaaki/code_gen_ipgen_StreamingDataWidthConverter_Batch_0_nzm_awqb/project_StreamingDataWidthConverter_Batch_0/sol1/impl/ip ディレクトリに行くと、IP の ZIP 圧縮ファイルの xilinx_com_hls_StreamingDataWidthConverter_Batch_0_1_0.zip が生成されていた。
finn_79_200605.png
  1. 2020年06月05日 06:23 |
  2. finn
  3. | トラックバック:0
  4. | コメント:0

finn をやってみる9(tfc_end2end_example.ipynb その4)

finn をやってみる8(tfc_end2end_example.ipynb その3)”の続き。

前回は、end2end_example の tfc_end2end_example.ipynb の Conversion to HLS layers, Creating a Dataflow Partition, Folding and Datawidth Converter, FIFO and TLastMarker Insertion をやってみた。今回は、end2end_example の tfc_end2end_example.ipynb の 3. Vivado HLS and IPI からやってみよう。

今回も end2end_example の tfc_end2end_example.ipynb の図や文章の翻訳、コードを引用して勉強していく。

3. Vivado HLS and IPI
・ Generating HLS Code
・ Synthesizing HLS to IP Blocks
・ IP Stitching

これらのタスクではFPGA合成ツールを扱うので、ターゲットとするザイリンクスFPGAパーツ名とPYNQボード名を記述する2つのヘルパー変数を定義する。
finn_61_200602.png

クロック周期は 10 ns つまり 100 MHz のようだ。

Generating HLS Code
このセクションでは、さまざまなレイヤーからのIPブロックの生成について説明する。これらは、完全なモデルに対応するブロックデザインを作成できる。IPブロックへの単一の変換により、優れた透過性が得られ、各IPブロックの機能をチェックして、対応するONNXノードの動作と比較できる。

各層のHLS IPブロックを生成するには、2つの変換が必要となる。

・ PrepareIP ノードのHLS C ++コードと、HLS合成を開始してデザインをIPとしてエクスポートするtclスクリプトを生成する。
・ HLSSynthIP tclスクリプトをVivado HLSに渡し、実際のIP生成を実行する。

まず、基本的な変換 GiveUniqueNodeNames を使用して一意のノード名を指定し、次に PrepareIP を使用してHLS C ++コード生成を続行する。
finn_62_200602.png

Synthesizing HLS to IP Blocks
各レイヤーのHLSコードを生成したので、HLSSynthIP変換を呼び出して、生成されたHLSをVivado IPブロックに変換できる。これにはHLS合成の呼び出しが含まれるため、この変換はしばらく(うちでは10分ほど)実行される。
finn_63_200602.png

各 StreamingFCLayer_Batch ノードには、netronでより詳細に検査できる新しい属性がある。

finn_64_200602.png

最初の StreamingFCLayer_Batch ノードを見てみると、たくさんの属性が増えている。
finn_65_200602.png
finn_66_200602.png
finn_67_200602.png

tfc_w1_a1_ipgen.onnx のグラフ全体を示す。
finn_68_200603.png

属性が 2 つ追加されている。
・ code_gen_dir_ipgen ipgen変換によって生成されたすべてのファイルが格納されるディレクトリパス
・ ipgen_path 生成されたIPブロックが保存されているプロジェクトディレクトリへのパス

このディレクトリを確認することで、どのファイルが生成されるかをさらに調査できる。たとえば、最初の StreamingFCLayer_Batch ノードの場合を示す。
finn_69_200602.png

ディレクトリ project_StreamingFCLayer_Batch_0 には、IP ブロックがエクスポートされる Vivado HLS によって作成されたプロジェクトと、 Vivado HLS によって生成された他のファイルが含まれる。上記の netron によるネットワークの視覚化と比較すると、これは正確にノード属性 ipgen_path に格納されているフォルダーの名前ということだ。 Vivado HLS に渡される.cppコードは、 top_StreamingFCLayer_Batch_0.cpp ファイルにある。 thresh.h ファイルもそれに属し、しきい値の値が含まれている。重みは .npy ファイルおよび .dat ファイル(memblock_0.dat)として保存される。 vivado_hls.log は、Vivado HLS からのログファイルだ。これらのファイルに加えて、フォルダーには ipgen.sh および hls_syn_StreamingFCLayer_Batch_0.tcl が含まれる。また、StreamingFCLayer を「decoupled」モードで使用するため、verilog ラッパー(StreamingFCLayer_Batch_0_memstream.v)が生成される。「decoupled」および「const」モードの詳細については、 FINN readthedocs Web サイトの Internals に書いてある。

以下では、生成された2つのスクリプトを詳しく見ていく。 ipgen.sh から始める。
finn_69_200602.png

/tmp/finn_dev_masaaki/code_gen_ipgen_StreamingFCLayer_Batch_0_av35euos に cd して、 Vivado HLS の TCL ファイルを StreamingFCLayer_Batch_0.tcl を起動する。終わったら、/workspace/finn に戻る(これは私の解説)。

hls_syn_StreamingFCLayer_Batch_0.tcl を表示する。
finn_70_200602.png

Vivado HLS のプロジェクトを作って、xc7z020clg400-1、クロック 10 ns 、-cflags "-std=c++0x -I$config_bnnlibdir" 、axi_addr64 で合成して、IP としてエクスポートしている(これは私の解説)。

すべてのIPブロックが配置されたので、それらを一緒にステッチして、ONNXモデルに一致するIPデザインを作成できる。 これについては、次のセクションで説明する。

ここで、Vviado HLS のプロジェクトができているということで、起動中の docker コンテナに入って、実際のファイルを見てみよう。
起動中の docker コンテナのシェルに入る”を参考にして、起動中の docker コンテナを見る。docker ps
docker ps
docker exec -i -t 7b069b1e1356 /bin/bash

finn_71_200603.png

/workspace/finn に入れた。
ls をした。
finn_72_200603.png

今まで Jupyter Notebook で生成した onnx モデルが入っている。

/tmp/finn_dev_masaaki に行ってみると、今作った tfc_w1_a1_ipgen.onnx の各ノードがあった。
ls -alt
finn_74_200603.png

ノードを示す。

drwx------  3 masaaki docker 4096 Jun  2 19:55 code_gen_ipgen_StreamingFCLayer_Batch_0_av35euos
drwx------  3 masaaki docker 4096 Jun  2 19:54 code_gen_ipgen_StreamingDataWidthConverter_Batch_0_nzm_awqb
drwx------  3 masaaki docker 4096 Jun  2 19:53 code_gen_ipgen_StreamingFCLayer_Batch_1_ze13mbt0
drwx------  3 masaaki docker 4096 Jun  2 19:52 code_gen_ipgen_StreamingFCLayer_Batch_2_cc9g0rxo
drwx------  3 masaaki docker 4096 Jun  2 19:51 code_gen_ipgen_StreamingFCLayer_Batch_3_8fn3j9gt
drwx------  3 masaaki docker 4096 Jun  2 19:50 code_gen_ipgen_TLastMarker_0_dkbjhrkw
drwx------  3 masaaki docker 4096 Jun  2 19:46 code_gen_ipgen_StreamingFIFO_5_rpmfwai3
drwx------  3 masaaki docker 4096 Jun  2 19:46 code_gen_ipgen_StreamingFIFO_4_hkgtx9lw
drwx------  3 masaaki docker 4096 Jun  2 19:46 code_gen_ipgen_StreamingFIFO_3_iz1kpch8
drwx------  3 masaaki docker 4096 Jun  2 19:46 code_gen_ipgen_StreamingFIFO_2_7lkicamh
drwx------  3 masaaki docker 4096 Jun  2 19:46 code_gen_ipgen_StreamingFIFO_1_eimmu84e
drwx------  3 masaaki docker 4096 Jun  2 19:46 code_gen_ipgen_StreamingFIFO_0_qnzwb_sa
drwx------  2 masaaki docker 4096 Jun  1 19:27 dataflow_partition_evha3xbg


code_gen_ipgen_StreamingFCLayer_Batch_0_av35euos に入ってみる。
cd code_gen_ipgen_StreamingFCLayer_Batch_0_av35euos
finn_75_200604.png

ipgen.sh, hls_syn_StreamingFCLayer_Batch_0.tcl などが見える。
  1. 2020年06月04日 04:48 |
  2. finn
  3. | トラックバック:0
  4. | コメント:0

finn をやってみる8(tfc_end2end_example.ipynb その3)

finn をやってみる7(tfc_end2end_example.ipynb その2)”の続き。

前回は、end2end_example の tfc_end2end_example.ipynb の 2. Network preparation の FINN-style Dataflow Architectures, Tidy-up transformations, Streamlining をやってみた。今回は、end2end_example の tfc_end2end_example.ipynb の Conversion to HLS layers, Creating a Dataflow Partition, Folding and Datawidth Converter, FIFO and TLastMarker Insertion をやってみた。

今回も end2end_example の tfc_end2end_example.ipynb の図や文章の翻訳、コードを引用して勉強していく。

Conversion to HLS layers
finn-hls library の関数に対応する HLS レイヤーに変換する。今回の変換では、バイナリXnorPopcountMatMulレイヤーのペアをStreamingFCLayer_Batchレイヤーに変換する。直後のMultiThresholdレイヤーもMVTUに吸収される。
StreamingFCLayer_Batch、finn-hlslibライブラリからの関数呼び出しに対応するノードを含む新しい構造を作成する。
注:変換でto_hls.InferBinaryStreamingFCLayerは、引数として "decoupled" という文字列を取得する。これは、重みの mem_mode を示す。FINNには、重みの保存方法とアクセス方法を設定するためのさまざまなオプションがある。 FINN readthedocs website を参照のこと。
finn-hlslib ライブラリの StreamingFCLayer_Batch 関数はここにある。
finn_49_200602.png

tfc_w1_a1_hls_layers.onnx の全体を示す。
finn_50_200602.png

各StreamingFCLayer_Batchノードには、フォールディングの度合いを指定する2つの属性、PEとSIMDがある。すべてのノードで、これらの属性の値はデフォルトで1に設定される。これは、最大のフォールディング(時間多重化)に対応し、したがってパフォーマンスが最小になる。これらをどのように調整できるかについては後ほど説明するが、最初に、このネットワークでHLSレイヤーを非HLSレイヤーから分離したい。

Creating a Dataflow Partition
上のグラフでは、FINN HLSレイヤー(StreamingFCLayer_Batch)と通常のONNXレイヤー(Reshape、Mul、Add)が混在していることがわかります。ビットストリームを作成するには、FINNはHLSレイヤーのみのモデルを必要とします。これを実現するために、 CreateDataflowPartition 変換を使用してこのグラフに "dataflow partition" を作成し、HLSレイヤーを別のモデルに分離し、それらを StreamingDataflowPartition と呼ばれる 1 つの placeholder layer に置き換える。
finn_51_200602.png

StreamingDataflowPartition のプロパティを示す。
finn_52_200602.png

tfc_w1_a1_dataflow_parent.onnx 全体を示す。
finn_53_200602.png

StreamingFCLayerインスタンスがすべて、HLSデータフローのみのグラフとして抽出された属性モデルを持つ単一のStreamingDataflowPartitionに置き換えられていることが分かる。
finn_54_200602.png

df_model.onnx 全体を示す。
finn_55_200602.png

抽出されたすべてのStreamingFCLayerインスタンスが子(データフロー)モデルに移動されていることが分かる。子モデルを ModelWrapper で読み込んで作業を続ける。

Folding and Datawidth Converter, FIFO and TLastMarker Insertion
FINNの折りたたみ(Folding in FINN)は、実行リソースの観点からレイヤーが時間多重化される量を表す。元のFINN論文で説明されているように、PE(出力での並列化)およびSIMD(入力での並列化)パラメーターによって制御される、各レイヤーにはいくつかの折りたたみ係数がある。PE値とSIMD値の設定が高いほど、生成されたアクセラレータの実行が速くなり、消費するFPGAリソースが増える。
折りたたみパラメータはノード属性であるため、ModelWrapperのヘルパー関数を使用して簡単にアクセスおよび変更できる。最初に、StreamingFCLayer_Batch操作を実装するノードの1つを詳しく見ていく。これは、Netronの視覚化が役立つ。上の図では、最初の4つのノードがStreamingFCLayer_Batchであることが分かる。例として、最初のノードを抽出する。

このノードには、より高レベルのHLSCustomOpラッパーを使用できる。これらのラッパーは、folding factors (PEおよびSIMD)など、これらのノードの特定のプロパティへの簡単なアクセスを提供します。 CustomOp ラッパーで定義されているノード属性を見て、SIMD属性とPE属性を調整してみよう。
finn_56_200602.png

PEとSIMDがノード属性としてリストされており、連続するレイヤーの間に挿入されるFIFOの深さも表示されている。また、set_nodeattrを使用して、特定の制約に従ってすべてを調整できる。
このノートブックでは、folding factors とFIFOの深さを手動で設定しているが、将来のバージョンでは、FINN-Rペーパーの分析モデルに従って、FPGAリソースバジェットを考慮して folding factors を決定できるようにする予定だそうだ。
finn_57_200602.png

PEとSIMDを設定して、各レイヤーの合計フォールディングが16になるようにする。
PEとSIMDの他に、3つのノード属性が設定されている。 ram_style は重みの格納方法を指定する(BRAM, LUTRAM など) auto にすると Vivado が決定する。 inFIFODepth and outFIFODepth はノード間に適切な FIFO の深さを指定する。
ただし、FIFOを追加する前に、データ幅コンバーター(DWC)が必要かどうかを判断し、それらを正しく挿入する必要がある。フォールディングを設定すると、あるノードのフォールド出力形状が次のノードのフォールド入力形状と一致しない場合があるためだ。
以下では、最初にDWC、次にFIFOがFINNの対応する変換を使用して挿入される。
finn_58_200602.png

最後に、InsertTLastMarker変換を実行して、このグラフの出力でTLastMarkerノードを入れる。これは、DMAエンジンを正しく実行するために必要ということだ。 netronを使用すると、ノードにFIFOが挿入され、必要に応じてDWCが挿入されたセットフォールディングがノードに含まれていることが分かる。
finn_59_200602.png

tfc_w1_a1_set_folding_factors.onnx のグラフを示す。
finn_60_200602.png

これでネットワークの準備が完了し、ネットワークを次のブロックVivado HLSおよびIPIに渡すことができる。
  1. 2020年06月03日 04:12 |
  2. finn
  3. | トラックバック:0
  4. | コメント:0
»