このチュートリアルでは、Darknet YoloV3-tiny推論をVTAアクセラレータデザイン上で実行し、画像検出タスクを実行する方法について、エンドツーエンドデモを提供します。このチュートリアルでは、量子化(VTAはint8/32推論のみをサポート)とグラフパッキング(コアでのテンソル化を可能にするため)を行い、ハードウェアターゲット向けに計算グラフを調整するフロントエンドコンパイラとしてのRelayを紹介します。
cfg_path = /home/masaaki/.tvm_test_data/darknet/yolov3-tiny.cfg
weights_path = /home/masaaki/.tvm_test_data/darknet/yolov3-tiny.weights
coco_path = /home/masaaki/.tvm_test_data/data/coco.names
font_path = /home/masaaki/.tvm_test_data/data/arial.ttf
Gluon model zooからVisionモデルを取得し、Relayでコンパイルします。コンパイルの手順は
1. フロントエンドはMxNetからRelayモジュールに変換。
2. 8ビット量子化の適用:ここでは、CPUのfp32で実行される最初のconv層とdense層をスキップしています。
3. グラフパッキングを行い、テンソル化するためのデータレイアウトを変更する。
4. 定数折りたたみを行い、演算子の数を減らす(例:バッチノルム乗算をなくす)。
5. オブジェクトファイルへのリレービルドを行う。
6. オブジェクトファイルをリモート(FPGAデバイス)にロードする。
7. グラフエクゼキュータmを生成する。
(base) masaaki@masaaki-H110M4-M01:/media/masaaki/Ubuntu_Disk/DNN/tvm$ python3 vta/tests/python/pynq/test_program_rpc.py
(base) masaaki@masaaki-H110M4-M01:/media/masaaki/Ubuntu_Disk/DNN/tvm$ python3 vta/tests/python/integration/deploy_detection.py
cfg_path = /home/masaaki/.tvm_test_data/darknet/yolov3-tiny.cfg
weights_path = /home/masaaki/.tvm_test_data/darknet/yolov3-tiny.weights
coco_path = /home/masaaki/.tvm_test_data/data/coco.names
font_path = /home/masaaki/.tvm_test_data/data/arial.ttf
Reconfigured FPGA and RPC runtime in 3.17s!
/media/masaaki/Ubuntu_Disk/DNN/tvm/python/tvm/driver/build_module.py:263: UserWarning: target_host parameter is going to be deprecated. Please pass in tvm.target.Target(target, host=target_host) instead.
warnings.warn(
[04:32:33] /media/masaaki/Ubuntu_Disk/DNN/tvm/src/tir/transforms/arg_binder.cc:95: Warning: Trying to bind buffer to another one with lower alignment requirement required_alignment=256, provided_alignment=128
[04:32:33] /media/masaaki/Ubuntu_Disk/DNN/tvm/src/tir/transforms/arg_binder.cc:95: Warning: Trying to bind buffer to another one with lower alignment requirement required_alignment=256, provided_alignment=128
[04:32:33] /media/masaaki/Ubuntu_Disk/DNN/tvm/src/tir/transforms/arg_binder.cc:95: Warning: Trying to bind buffer to another one with lower alignment requirement required_alignment=256, provided_alignment=128
[04:32:33] /media/masaaki/Ubuntu_Disk/DNN/tvm/src/tir/transforms/arg_binder.cc:95: Warning: Trying to bind buffer to another one with lower alignment requirement required_alignment=256, provided_alignment=128
[04:32:34] /media/masaaki/Ubuntu_Disk/DNN/tvm/src/tir/transforms/arg_binder.cc:95: Warning: Trying to bind buffer to another one with lower alignment requirement required_alignment=256, provided_alignment=128
[04:32:34] /media/masaaki/Ubuntu_Disk/DNN/tvm/src/tir/transforms/arg_binder.cc:95: Warning: Trying to bind buffer to another one with lower alignment requirement required_alignment=256, provided_alignment=128
[04:32:34] /media/masaaki/Ubuntu_Disk/DNN/tvm/src/tir/transforms/arg_binder.cc:95: Warning: Trying to bind buffer to another one with lower alignment requirement required_alignment=256, provided_alignment=128
[04:32:34] /media/masaaki/Ubuntu_Disk/DNN/tvm/src/tir/transforms/arg_binder.cc:95: Warning: Trying to bind buffer to another one with lower alignment requirement required_alignment=256, provided_alignment=128
[04:32:35] /media/masaaki/Ubuntu_Disk/DNN/tvm/src/tir/transforms/arg_binder.cc:95: Warning: Trying to bind buffer to another one with lower alignment requirement required_alignment=256, provided_alignment=128
[04:32:35] /media/masaaki/Ubuntu_Disk/DNN/tvm/src/tir/transforms/arg_binder.cc:95: Warning: Trying to bind buffer to another one with lower alignment requirement required_alignment=256, provided_alignment=128
[04:32:35] /media/masaaki/Ubuntu_Disk/DNN/tvm/src/tir/transforms/arg_binder.cc:95: Warning: Trying to bind buffer to another one with lower alignment requirement required_alignment=256, provided_alignment=128
yolov3-tiny inference graph built in 19.06s!
Performed inference in 658.92ms (std = 0.37) for 1 samples
Average per sample inference time: 658.92ms
(base) masaaki@masaaki-H110M4-M01:/media/masaaki/Ubuntu_Disk/DNN/tvm$ python3 vta/tests/python/integration/deploy_detection.py
Reconfigured FPGA and RPC runtime in 2.88s!
/media/masaaki/Ubuntu_Disk/DNN/tvm/python/tvm/driver/build_module.py:263: UserWarning: target_host parameter is going to be deprecated. Please pass in tvm.target.Target(target, host=target_host) instead.
warnings.warn(
[04:24:30] /media/masaaki/Ubuntu_Disk/DNN/tvm/src/tir/transforms/arg_binder.cc:95: Warning: Trying to bind buffer to another one with lower alignment requirement required_alignment=256, provided_alignment=128
[04:24:30] /media/masaaki/Ubuntu_Disk/DNN/tvm/src/tir/transforms/arg_binder.cc:95: Warning: Trying to bind buffer to another one with lower alignment requirement required_alignment=256, provided_alignment=128
[04:24:30] /media/masaaki/Ubuntu_Disk/DNN/tvm/src/tir/transforms/arg_binder.cc:95: Warning: Trying to bind buffer to another one with lower alignment requirement required_alignment=256, provided_alignment=128
[04:24:30] /media/masaaki/Ubuntu_Disk/DNN/tvm/src/tir/transforms/arg_binder.cc:95: Warning: Trying to bind buffer to another one with lower alignment requirement required_alignment=256, provided_alignment=128
[04:24:30] /media/masaaki/Ubuntu_Disk/DNN/tvm/src/tir/transforms/arg_binder.cc:95: Warning: Trying to bind buffer to another one with lower alignment requirement required_alignment=256, provided_alignment=128
[04:24:31] /media/masaaki/Ubuntu_Disk/DNN/tvm/src/tir/transforms/arg_binder.cc:95: Warning: Trying to bind buffer to another one with lower alignment requirement required_alignment=256, provided_alignment=128
[04:24:31] /media/masaaki/Ubuntu_Disk/DNN/tvm/src/tir/transforms/arg_binder.cc:95: Warning: Trying to bind buffer to another one with lower alignment requirement required_alignment=256, provided_alignment=128
[04:24:31] /media/masaaki/Ubuntu_Disk/DNN/tvm/src/tir/transforms/arg_binder.cc:95: Warning: Trying to bind buffer to another one with lower alignment requirement required_alignment=256, provided_alignment=128
[04:24:31] /media/masaaki/Ubuntu_Disk/DNN/tvm/src/tir/transforms/arg_binder.cc:95: Warning: Trying to bind buffer to another one with lower alignment requirement required_alignment=256, provided_alignment=128
[04:24:32] /media/masaaki/Ubuntu_Disk/DNN/tvm/src/tir/transforms/arg_binder.cc:95: Warning: Trying to bind buffer to another one with lower alignment requirement required_alignment=256, provided_alignment=128
[04:24:32] /media/masaaki/Ubuntu_Disk/DNN/tvm/src/tir/transforms/arg_binder.cc:95: Warning: Trying to bind buffer to another one with lower alignment requirement required_alignment=256, provided_alignment=128
yolov3-tiny inference graph built in 18.91s!
Performed inference in 660.54ms (std = 2.14) for 1 samples
Average per sample inference time: 660.54ms
xilinx@pynq:~$ cd tvm
xilinx@pynq:~/tvm$ sudo ./apps/vta_rpc/start_rpc_server.sh
INFO:RPCServer:bind to 0.0.0.0:9091
INFO:RPCServer:connection from ('192.168.3.10', 43720)
INFO:root:Program FPGA with 1x16_i8w8a32_15_15_18_17.bit
INFO:RPCServer:Finish serving ('192.168.3.10', 43720)
INFO:RPCServer:connection from ('192.168.3.10', 43722)
INFO:root:Skip reconfig_runtime due to same config.
INFO:RPCServer:Finish serving ('192.168.3.10', 43722)
INFO:RPCServer:connection from ('192.168.3.10', 43724)
INFO:root:Skip reconfig_runtime due to same config.
INFO:root:Program FPGA with 1x16_i8w8a32_15_15_18_17.bit
INFO:root:Loading VTA library: /home/xilinx/tvm/vta/python/vta/../../../build/libvta.so
INFO:RPCServer:load_module /tmp/tmp9vv5ioxf/graphlib.tar
このチュートリアルでは、ImageNet分類推論をVTAアクセラレータ上で実行し、ImageNet分類タスクを実行する方法について、エンドツーエンド・デモを提供します。このチュートリアルでは、量子化(VTAはint8/32推論のみをサポート)とグラフパッキング(コアでのテンソル化を可能にするため)を行い、ハードウェアターゲットに合わせた計算グラフを作成するフロントエンドコンパイラとしてRelayが紹介されています。
Gluon model zooからVisionモデルを取得し、Relayでコンパイルします。コンパイルの手順は
1. フロントエンドはMxNetからRelayモジュールに変換。
2. 8ビット量子化の適用:ここでは、CPUのfp32で実行される最初のconv層とdense層をスキップしています。
3. グラフパッキングを行い、テンソル化するためのデータレイアウトを変更する。
4. 定数折りたたみを行い、演算子の数を減らす(例:バッチノルム乗算をなくす)。
5. オブジェクトファイルへのリレービルドを行う。
6. オブジェクトファイルをリモート(FPGAデバイス)にロードする。
7. グラフエクゼキュータmを生成する。
resnet18_v1 inference graph built in 26.26s!
Performed inference in 408.14ms (std = 2.18) for 1 samples
Average per sample inference time: 408.14ms
resnet18_v1 prediction for sample 0
#1: tiger cat
#2: Egyptian cat
#3: tabby, tabby cat
#4: lynx, catamount
#5: weasel
(base) masaaki@masaaki-H110M4-M01:/media/masaaki/Ubuntu_Disk/DNN/tvm$ python3 vta/tests/python/integration/deploy_classification.py
Reconfigured FPGA and RPC runtime in 2.89s!
Downloading /home/masaaki/.mxnet/models/resnet18_v1-a0666292.zipefe2e9c7-23b8-4e5f-9eb8-62f6771a59a7 from https://apache-mxnet.s3-accelerate.dualstack.amazonaws.com/gluon/models/resnet18_v1-a0666292.zip...
/media/masaaki/Ubuntu_Disk/DNN/tvm/python/tvm/driver/build_module.py:263: UserWarning: target_host parameter is going to be deprecated. Please pass in tvm.target.Target(target, host=target_host) instead.
warnings.warn(
[04:08:34] /media/masaaki/Ubuntu_Disk/DNN/tvm/src/tir/transforms/arg_binder.cc:95: Warning: Trying to bind buffer to another one with lower alignment requirement required_alignment=256, provided_alignment=128
[04:08:34] /media/masaaki/Ubuntu_Disk/DNN/tvm/src/tir/transforms/arg_binder.cc:95: Warning: Trying to bind buffer to another one with lower alignment requirement required_alignment=256, provided_alignment=128
[04:08:34] /media/masaaki/Ubuntu_Disk/DNN/tvm/src/tir/transforms/arg_binder.cc:95: Warning: Trying to bind buffer to another one with lower alignment requirement required_alignment=256, provided_alignment=128
[04:08:34] /media/masaaki/Ubuntu_Disk/DNN/tvm/src/tir/transforms/arg_binder.cc:95: Warning: Trying to bind buffer to another one with lower alignment requirement required_alignment=256, provided_alignment=128
[04:08:34] /media/masaaki/Ubuntu_Disk/DNN/tvm/src/tir/transforms/arg_binder.cc:95: Warning: Trying to bind buffer to another one with lower alignment requirement required_alignment=256, provided_alignment=128
[04:08:34] /media/masaaki/Ubuntu_Disk/DNN/tvm/src/tir/transforms/arg_binder.cc:95: Warning: Trying to bind buffer to another one with lower alignment requirement required_alignment=256, provided_alignment=128
[04:08:35] /media/masaaki/Ubuntu_Disk/DNN/tvm/src/tir/transforms/arg_binder.cc:95: Warning: Trying to bind buffer to another one with lower alignment requirement required_alignment=256, provided_alignment=128
[04:08:35] /media/masaaki/Ubuntu_Disk/DNN/tvm/src/tir/transforms/arg_binder.cc:95: Warning: Trying to bind buffer to another one with lower alignment requirement required_alignment=256, provided_alignment=128
[04:08:35] /media/masaaki/Ubuntu_Disk/DNN/tvm/src/tir/transforms/arg_binder.cc:95: Warning: Trying to bind buffer to another one with lower alignment requirement required_alignment=256, provided_alignment=128
[04:08:35] /media/masaaki/Ubuntu_Disk/DNN/tvm/src/tir/transforms/arg_binder.cc:95: Warning: Trying to bind buffer to another one with lower alignment requirement required_alignment=256, provided_alignment=128
[04:08:35] /media/masaaki/Ubuntu_Disk/DNN/tvm/src/tir/transforms/arg_binder.cc:95: Warning: Trying to bind buffer to another one with lower alignment requirement required_alignment=256, provided_alignment=128
[04:08:35] /media/masaaki/Ubuntu_Disk/DNN/tvm/src/tir/transforms/arg_binder.cc:95: Warning: Trying to bind buffer to another one with lower alignment requirement required_alignment=256, provided_alignment=128
[04:08:35] /media/masaaki/Ubuntu_Disk/DNN/tvm/src/tir/transforms/arg_binder.cc:95: Warning: Trying to bind buffer to another one with lower alignment requirement required_alignment=256, provided_alignment=128
[04:08:36] /media/masaaki/Ubuntu_Disk/DNN/tvm/src/tir/transforms/arg_binder.cc:95: Warning: Trying to bind buffer to another one with lower alignment requirement required_alignment=256, provided_alignment=128
[04:08:36] /media/masaaki/Ubuntu_Disk/DNN/tvm/src/tir/transforms/arg_binder.cc:95: Warning: Trying to bind buffer to another one with lower alignment requirement required_alignment=256, provided_alignment=128
[04:08:36] /media/masaaki/Ubuntu_Disk/DNN/tvm/src/tir/transforms/arg_binder.cc:95: Warning: Trying to bind buffer to another one with lower alignment requirement required_alignment=256, provided_alignment=128
vta/tests/python/integration/deploy_classification.py:212: DeprecationWarning: legacy graph executor behavior of producing json / lib / params will be removed in the next release. Please see documents of tvm.contrib.graph_executor.GraphModule for the new recommended usage.
graph, lib, params = relay.build(
resnet18_v1 inference graph built in 27.19s!
resnet18_v1 inference graph built in 26.26s!
Performed inference in 408.14ms (std = 2.18) for 1 samples
Average per sample inference time: 408.14ms
resnet18_v1 prediction for sample 0
#1: tiger cat
#2: Egyptian cat
#3: tabby, tabby cat
#4: lynx, catamount
#5: weasel
モジュールを実行する手順
1. リモート・コンテキストを作成する(Pynq でもリモート実行用)
2. tvm.nd.array でデータをフォーマットする
3. f() で計算を実行する
4. numpy()は結果の配列を解釈可能な形式にコピーして返す
と表示された。乗算は正しい。Successful matrix multiply test!
C_nd.numpy().shape = (1, 16, 1, 16)
[[[[ -98 45 -126 8 101 -6 -124 82 -19 -39 47 53 -74
-76 -4 84]]
[[ 120 -69 -106 89 -121 -3 125 103 -51 61 -42 -54 127
-80 -103 -1]]
[[ 17 103 63 -8 -126 9 -79 -112 -118 17 104 -14 -69
62 -100 -38]]
[[ 125 -82 95 115 27 0 -19 21 -8 -28 35 101 -109
-27 -72 -123]]
[[ 72 -26 34 101 -64 29 -83 8 23 -62 111 52 -117
-46 50 -118]]
[[ 58 -47 -113 62 29 -78 -101 62 -116 -25 22 -84 37
-40 -65 4]]
[[-109 52 -33 -114 -118 -93 106 73 102 -122 -88 -98 64
-44 -36 -52]]
[[ 84 33 -17 -19 -71 104 67 7 -102 90 91 8 -111
4 -91 48]]
[[ -20 116 79 41 8 8 62 -71 -64 -25 -78 13 -72
-75 -88 -56]]
[[-110 11 -38 -58 -77 -34 42 69 98 -51 -95 -53 -21
75 -81 3]]
[[ 78 102 91 -73 -69 -47 -86 16 122 91 -105 -8 106
37 82 -103]]
[[ -87 84 116 -25 -64 67 -70 85 36 -3 65 59 14
26 93 -16]]
[[ 11 -37 -104 -5 43 -94 -78 -71 37 -44 -37 -103 -34
110 84 -83]]
[[ 109 81 63 65 -44 122 -77 -57 -24 -72 -4 -99 95
-26 86 46]]
[[ 92 -127 -55 -1 -46 -79 -18 114 46 64 55 -90 -83
-93 -79 -77]]
[[ -32 -31 8 21 -43 -71 50 -126 59 63 69 43 -78
112 18 116]]]]
これで行列の乗算の結果テンソルCを別の計算操作で記述する準備が整った。計算関数はテンソルの形と、テンソルの各位置の計算規則を記述したラムダ関数を受け取る。
行列の乗算を実装するために、ラムダ関数には入力チャンネルの次元軸に対する縮小式が必要である。削減式を作成するには,te.reduce_axisで削減軸を宣言し,削減範囲を取り込みます.te.sumは削減する式と削減軸を取り込み,宣言した範囲内のすべてのkに対する値の総和を計算します.
このリダクションは32ビットenv.acc_dtypeアキュムレータデータ型に対して実行される必要があることに注意してください。
このフェーズでは,計算をどのように行うかを宣言しているだけなので,計算は行われません.
C_buf = Tensor(shape=[1, 16, 1, 16], op.name=C_buf)
スケジュールとは、元の計算に対する変換の集合であり、正しさに影響を与えることなく計算の実装を変換するものである。この簡単なVTAプログラミングのチュートリアルは、元のスケジュールをVTAハードウェアプリミティブにマップダウンする基本的なスケジュール変換を示すことを目的としています。
@main = primfn(A_1: handle, B_1: handle, C_1: handle) -> ()
attr = {"from_legacy_te_schedule": True, "global_symbol": "main", "tir.noalias": True}
buffers = {A: Buffer(A_2: Pointer(int8), int8, [256], []),
B: Buffer(B_2: Pointer(int8), int8, [65536], []),
C: Buffer(C_2: Pointer(int8), int8, [256], [])}
buffer_map = {A_1: A, B_1: B, C_1: C}
preflattened_buffer_map = {A_1: A_3: Buffer(A_2, int8, [1, 16, 1, 16], []), B_1: B_3: Buffer(B_2, int8, [16, 16, 16, 16], []), C_1: C_3: Buffer(C_2, int8, [1, 16, 1, 16], [])} {
allocate(A_buf: Pointer(global int8), int8, [256]), storage_scope = global;
allocate(B_buf: Pointer(global int8), int8, [65536]), storage_scope = global;
allocate(C_buf: Pointer(global int32), int32, [256]), storage_scope = global {
for (i1: int32, 0, 16) {
for (i3: int32, 0, 16) {
let cse_var_1: int32 = ((i1*16) + i3)
A_buf_1: Buffer(A_buf, int8, [256], [])[cse_var_1] = A[cse_var_1]
}
}
for (i0: int32, 0, 16) {
for (i1_1: int32, 0, 16) {
for (i2: int32, 0, 16) {
for (i3_1: int32, 0, 16) {
let cse_var_2: int32 = ((((i0*4096) + (i1_1*256)) + (i2*16)) + i3_1)
B_buf_1: Buffer(B_buf, int8, [65536], [])[cse_var_2] = B[cse_var_2]
}
}
}
}
for (co: int32, 0, 16) {
for (ci: int32, 0, 16) {
C_buf_1: Buffer(C_buf, int32, [256], [])[((co*16) + ci)] = 0
for (ko: int32, 0, 16) {
for (ki: int32, 0, 16) {
let cse_var_3: int32 = ((co*16) + ci)
C_buf_1[cse_var_3] = (C_buf_1[cse_var_3] + (cast(int32, A_buf_1[((ko*16) + ki)])*cast(int32, B_buf_1[((((co*4096) + (ko*256)) + (ci*16)) + ki)])))
}
}
}
}
for (i1_2: int32, 0, 16) {
for (i3_2: int32, 0, 16) {
let cse_var_4: int32 = ((i1_2*16) + i3_2)
C[cse_var_4] = cast(int8, C_buf_1[cse_var_4])
}
}
}
}
このスケジュールは理にかなっていますが、VTAにコンパイルすることはできません。正しいコード生成のためには、スケジューリングプリミティブとコードアノテーションを適用して、スケジュールをVTAのハードウェアイントリニックスに直接落とせるようなものに変換する必要があるのです。それらは以下の通りです。
・DMAコピーオペレーションは、グローバルにスコープされたテンソルを受け取り、それをローカルにスコープされたテンソルにコピーする。
・行列の乗算を実行するテンソル演算。
VTAのオンチップSRAM
VTAは3種類のメモリスコープを持ち、それぞれが異なるオンチップSRAMバッファに対応しています。
env.inp_scope : 入力バッファ。env.inp_dtype型の形状(env.BATCH, env.BLOCK_IN)の入力マトリクスを格納するリードオンリーのSRAMバッファです。入力バッファには、2 ^ LOG_INP_BUFF_SIZE行列要素(vta_config.jsonファイルで指定されたもの)が格納されます。
env.wgt_scope : env.wgt_dtype 型の形状 (env.BLOCK_OUT, env.BLOCK_IN) のウェイト行列を格納する読み込み専用の SRAM バッファです。ウェイトバッファは2 ^ LOG_WGT_BUFF_SIZE行列要素を含みます。
env.acc_scope : env.acc_dtype 型の形状 (env.BATCH, env.BLOCK_OUT) のアキュムレータ行列を格納するリード/ライト SRAM バッファです。アキュムレータバッファはVTAの汎用レジスタファイルであり,畳み込みや行列の乗算の中間結果や,プーリング,バッチ正規化,活性化レイヤの中間結果などを保持します.アキュムレータバッファは、2 ^ LOG_ACC_BUFF_SIZE の行列要素を含みます。
スケジュール変換の最後のステップは、スケジュールにテンソル化を適用することである。テンソル化はベクトル化に類似しているが、その概念をより高次元の計算単位に拡張するものである。その結果、テンソル化はデータレイアウトの入力プレースホルダーを宣言するときに説明したように、データレイアウトの制約を課すことになる。我々はすでにテンソルをタイル状に配置したので、次に行うべきことはテンソル化に対応するためのループの再順序付けである。
ここでは、一番外側の縮小軸をずっと外側に移動することにした。このため、まず入力チャネル、次にバッチ次元、最後に出力チャネルを反復処理することになる。最後に、テンソル化スケジューリングプリミティブtensorizeを、最内周の行列乗算テンソルブロックの外軸に沿って適用する。最終的なスケジュールはVTAランタイムJITコンパイラによるコード生成に対応できるように出力される。
@main = primfn(A_1: handle, B_1: handle, C_1: handle) -> ()
attr = {"from_legacy_te_schedule": True, "global_symbol": "main", "tir.noalias": True}
buffers = {A: Buffer(A_2: Pointer(int8), int8, [256], []),
B: Buffer(B_2: Pointer(int8), int8, [65536], []),
C: Buffer(C_2: Pointer(int8), int8, [256], [])}
buffer_map = {A_1: A, B_1: B, C_1: C}
preflattened_buffer_map = {A_1: A_3: Buffer(A_2, int8, [1, 16, 1, 16], []), B_1: B_3: Buffer(B_2, int8, [16, 16, 16, 16], []), C_1: C_3: Buffer(C_2, int8, [1, 16, 1, 16], [])} {
allocate(C_buf: Pointer(local.acc_buffer int32), int32, [256]), storage_scope = local.acc_buffer;
allocate(A_buf: Pointer(local.inp_buffer int8), int8, [16]), storage_scope = local.inp_buffer;
allocate(B_buf: Pointer(local.wgt_buffer int8), int8, [16]), storage_scope = local.wgt_buffer {
for (co: int32, 0, 16) {
for (ci: int32, 0, 16) {
C_buf_1: Buffer(C_buf, int32, [256], [], scope="local.acc_buffer", align=16)[((co*16) + ci)] = 0
for (ko: int32, 0, 16) {
attr [IterVar(i0: int32, (nullptr), "DataPar", "")] "pragma_dma_copy" = 1;
for (i3: int32, 0, 16) {
A_buf_1: Buffer(A_buf, int8, [16], [], scope="local.inp_buffer", align=16)[i3] = A[((ko*16) + i3)]
}
attr [IterVar(i0_1: int32, (nullptr), "DataPar", "")] "pragma_dma_copy" = 1;
for (i3_1: int32, 0, 16) {
B_buf_1: Buffer(B_buf, int8, [16], [], scope="local.wgt_buffer", align=256)[i3_1] = B[((((co*4096) + (ko*256)) + (ci*16)) + i3_1)]
}
for (ki: int32, 0, 16) {
let cse_var_1: int32 = ((co*16) + ci)
C_buf_1[cse_var_1] = (C_buf_1[cse_var_1] + (cast(int32, A_buf_1[ki])*cast(int32, B_buf_1[ki])))
}
}
}
}
attr [IterVar(i0_2: int32, (nullptr), "DataPar", "")] "pragma_dma_copy" = 1;
for (i1: int32, 0, 16) {
for (i3_2: int32, 0, 16) {
let cse_var_2: int32 = ((i1*16) + i3_2)
C[cse_var_2] = cast(int8, C_buf_1[cse_var_2])
}
}
}
}
アクセラレータをターゲットとするとき、複雑さの原因の一つは、データレイアウトがアクセラレータ設計によって課されるレイアウトと一致することを確認することです。VTAは、下図に示すように、活性化行列と重み行列の間で1サイクルあたり1回の行列-行列演算を行い、その結果行列をアキュムレータ行列に追加するテンソルコアを中心に設計されている。
その行列と行列の掛け算の次元は、設定ファイル vta_config.json で指定される。活性化行列は(BATCH, BLOCK_IN)、転置ウエイト行列は(BLOCK_OUT, BLOCK_IN)の形状をしており、結果として出力行列は(BATCH, BLOCK_OUT)の形状をしていると推察される。従って、VTAが処理する入力テンソルおよび出力テンソルは、前述の次元に従ってタイリングされる必要がある。
下図は、元々(4, 8)の形状を持つ行列に対して、データのタイリングを行った場合の影響を示している。(2,2)のタイル形状でタイル化することで、各タイル内のデータが連続することが保証される。その結果、タイル化されたテンソルは(2, 4, 2, 2)の形状を持つことになる。
env.BATCH = 1
env.BLOCK_OUT = 16
env.BLOCK_IN = 16
A = Tensor(shape=[1, 16, 1, 16], op.name=A)
B = Tensor(shape=[16, 16, 16, 16], op.name=B)
A_buf = Tensor(shape=[1, 16, 1, 16], op.name=A_buf)
B_buf = Tensor(shape=[16, 16, 16, 16], op.name=B_buf)
C_buf = Tensor(shape=[1, 16, 1, 16], op.name=C_buf)
日 | 月 | 火 | 水 | 木 | 金 | 土 |
---|---|---|---|---|---|---|
- | - | - | - | - | 1 | 2 |
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
31 | - | - | - | - | - | - |