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

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

FPGAの部屋

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

SqueezeNet for MNIST 1

Squeezenet をFPGA に実装したいので、重みとバイアスを C のヘッダにしたいと思っているのだが、ImagkeNetの画像を使って学習するのも大変だけど、ImagkeNetの画像を集めて学習する方法を探っていた。その時に、SqueezeNet for MNIST を見つけた。とりあえず、MNISTのデータだったらKeras に標準で付いているし、手始めにこれをやってみることにした。それにLicense も Apache License 2.0 なので、都合が良い。
なお、統計情報を取る必要性から Activation を分けた。ReLU は独立した Activation に分けてある。
変更したSqueezeNet for MNISTを示す。なお、こちらの環境に合わせてある。
squeezenet4mnist_1_180811.png
squeezenet4mnist_2_180811.png
squeezenet4mnist_3_180811.png
squeezenet4mnist_5_180811.png

98.2 % の精度が出ている。

# SqueezeNet for MNIST
# 2018/08/02 by marsee
# Keras / Tensorflowで始めるディープラーニング入門 https://qiita.com/yampy/items/706d44417c433e68db0d
# のPythonコードを再利用させて頂いている
# https://www.kaggle.com/somshubramajumdar/squeezenet-for-mnist (Apache License 2.0)を引用して
# Keras 2に変更し独自のコードを加えた

import keras
from keras.datasets import mnist
from keras import backend as K
import pandas as pd
import numpy as np 
from keras.models import Model, Input
from keras.layers import Dense, Dropout, Flatten, Concatenate
from keras.layers import Conv2D, MaxPooling2D, Activation, AveragePooling2D
import keras.utils.np_utils as kutils

batch_size = 128
num_classes = 10
epochs = 5

img_rows, img_cols = 28, 28

(x_train, y_train), (x_test, y_test) = mnist.load_data()

#Kerasのバックエンドで動くTensorFlowとTheanoでは入力チャンネルの順番が違うので場合分けして書いています
if K.image_data_format() == 'channels_first':
    x_train = x_train.reshape(x_train.shape[0], 1, img_rows, img_cols)
    x_test = x_test.reshape(x_test.shape[0], 1, img_rows, img_cols)
    input_shape = (1, img_rows, img_cols)
else:
    x_train = x_train.reshape(x_train.shape[0], img_rows, img_cols, 1)
    x_test = x_test.reshape(x_test.shape[0], img_rows, img_cols, 1)
    input_shape = (img_rows, img_cols, 1)

x_train = x_train.astype('float32')
x_test = x_test.astype('float32')
x_train /= 255
x_test /= 255
print('x_train shape:', x_train.shape)
print(x_train.shape[0], 'train samples')
print(x_test.shape[0], 'test samples')

y_train = y_train.astype('int32')
y_test = y_test.astype('int32')
y_train = keras.utils.np_utils.to_categorical(y_train, num_classes)
y_test =  keras.utils.np_utils.to_categorical(y_test, num_classes)

# Setup of SqueezeNet (http://arxiv.org/abs/1602.07360), which offers similar performance
# to AlexNet, while using drastically fewer parameters. Tested on CIFAR10, it also performs
# well on MNIST problem

# Uses the latest keras 1.0.2 Functional API

input_layer = Input(shape=(28, 28, 1), name="input")

#conv 1
conv1 = Conv2D(96, (3, 3), padding="valid", kernel_initializer="glorot_uniform", strides=(2, 2))(input_layer)
relu1 = Activation(activation='relu')(conv1)

#maxpool 1
maxpool1 = MaxPooling2D(pool_size=(2,2))(relu1)

#fire 1
fire2_squeeze = Conv2D(16, (1, 1), padding="same", kernel_initializer="glorot_uniform")(maxpool1)
relu2_squeeze = Activation(activation='relu')(fire2_squeeze)

fire2_expand1 = Conv2D(64, (1, 1), padding="same", kernel_initializer="glorot_uniform")(relu2_squeeze)
relu2_expand1 = Activation(activation='relu')(fire2_expand1)
fire2_expand2 = Conv2D(64, (3, 3), padding="same", kernel_initializer="glorot_uniform")(relu2_squeeze)
relu2_expand2 = Activation(activation='relu')(fire2_expand2)

merge1 = Concatenate()([relu2_expand1, relu2_expand2])
fire2 = Activation("linear")(merge1)

#fire 2
fire3_squeeze = Conv2D(16, (1, 1),  padding="same", kernel_initializer="glorot_uniform")(fire2)
relu3_squeeze = Activation(activation='relu')(fire3_squeeze)

fire3_expand1 = Conv2D(64, (1, 1), padding="same", kernel_initializer="glorot_uniform")(relu3_squeeze)
relu3_expand1 = Activation(activation='relu')(fire3_expand1)
fire3_expand2 = Conv2D(64, (3, 3),  padding="same", kernel_initializer="glorot_uniform")(relu3_squeeze)
relu3_expand2 = Activation(activation='relu')(fire3_expand2)

merge2 = Concatenate()([relu3_expand1, relu3_expand2])
fire3 = Activation("linear")(merge2)

#fire 3
fire4_squeeze = Conv2D(32, (1, 1), padding="same", kernel_initializer="glorot_uniform")(fire3)
relu4_squeeze = Activation(activation='relu')(fire4_squeeze)

fire4_expand1 = Conv2D(128, (1, 1), padding="same", kernel_initializer="glorot_uniform")(relu4_squeeze)
relu4_expand1 = Activation(activation='relu')(fire4_expand1)
fire4_expand2 = Conv2D(128, (3, 3), padding="same", kernel_initializer="glorot_uniform")(relu4_squeeze)
relu4_expand2 = Activation(activation='relu')(fire4_expand2)

merge3 = Concatenate()([relu4_expand1, relu4_expand2])
fire4 = Activation("linear")(merge3)

#maxpool 4
maxpool4 = MaxPooling2D((2,2))(fire4)

#fire 5
fire5_squeeze = Conv2D(32, (1, 1), padding="same", kernel_initializer="glorot_uniform")(maxpool4)
relu5_squeeze = Activation(activation='relu')(fire5_squeeze)

fire5_expand1 = Conv2D(128, (1, 1), padding="same", kernel_initializer="glorot_uniform")(relu5_squeeze)
relu5_expand1 = Activation(activation='relu')(fire5_expand1)
fire5_expand2 = Conv2D(128, (3, 3), padding="same", kernel_initializer="glorot_uniform")(relu5_squeeze)
relu5_expand2 = Activation(activation='relu')(fire5_expand2)

merge5 = Concatenate()([relu5_expand1, relu5_expand2])
fire5 = Activation("linear")(merge5)

#fire 6
fire6_squeeze = Conv2D(48, (1, 1), padding="same", kernel_initializer="glorot_uniform")(fire5)
relu6_squeeze = Activation(activation='relu')(fire6_squeeze)

fire6_expand1 = Conv2D(192, (1, 1), padding="same", kernel_initializer="glorot_uniform")(relu6_squeeze)
relu6_expand1 = Activation(activation='relu')(fire6_expand1)
fire6_expand2 = Conv2D(192, (3, 3), padding="same", kernel_initializer="glorot_uniform")(relu6_squeeze)
relu6_expand2 = Activation(activation='relu')(fire6_expand2)

merge6 = Concatenate()([relu6_expand1, relu6_expand2])
fire6 = Activation("linear")(merge6)

#fire 7
fire7_squeeze = Conv2D(48, (1, 1), padding="same", kernel_initializer="glorot_uniform")(fire6)
relu7_squeeze = Activation(activation='relu')(fire7_squeeze)

fire7_expand1 = Conv2D(192, (1, 1), padding="same", kernel_initializer="glorot_uniform")(relu7_squeeze)
relu7_expand1 = Activation(activation='relu')(fire7_expand1)
fire7_expand2 = Conv2D(192, (3, 3), padding="same", kernel_initializer="glorot_uniform")(relu7_squeeze)
relu7_expand2 = Activation(activation='relu')(fire7_expand2)

merge7 = Concatenate()([relu7_expand1, relu7_expand2])
fire7 =Activation("linear")(merge7)

#fire 8
fire8_squeeze = Conv2D(64, (1, 1), padding="same", kernel_initializer="glorot_uniform")(fire7)
relu8_squeeze = Activation(activation='relu')(fire8_squeeze)

fire8_expand1 = Conv2D(256, (1, 1), padding="same", kernel_initializer="glorot_uniform")(relu8_squeeze)
relu8_expand1 = Activation(activation='relu')(fire8_expand1)
fire8_expand2 = Conv2D(256, (3, 3), padding="same", kernel_initializer="glorot_uniform")(relu8_squeeze)
relu8_expand2 = Activation(activation='relu')(fire8_expand2)

merge8 = Concatenate()([relu8_expand1, relu8_expand2])
fire8 = Activation("linear")(merge8)

#maxpool 8
maxpool8 = MaxPooling2D((2,2))(fire8)

#fire 9
fire9_squeeze = Conv2D(64, (1, 1),  padding="same", kernel_initializer="glorot_uniform")(maxpool8)
relu9_squeeze = Activation(activation='relu')(fire9_squeeze)

fire9_expand1 = Conv2D(256, (1, 1), padding="same", kernel_initializer="glorot_uniform")(relu9_squeeze)
relu9_expand1 = Activation(activation='relu')(fire9_expand1)
fire9_expand2 = Conv2D(256, (3, 3), padding="same", kernel_initializer="glorot_uniform")(relu9_squeeze)
relu9_expand2 = Activation(activation='relu')(fire9_expand2)

merge8 = Concatenate()([relu9_expand1, relu9_expand2])
fire9 = Activation("linear")(merge8)
fire9_dropout = Dropout(0.5)(fire9)

#conv 10
conv10 = Conv2D(10, (1, 1), padding="valid", kernel_initializer="glorot_uniform")(fire9_dropout)

# The original SqueezeNet has this avgpool1 as well. But since MNIST images are smaller (1,28,28)
# than the CIFAR10 images (3,224,224), AveragePooling2D reduces the image size to (10,0,0), 
# crashing the script.

#avgpool 1
#avgpool10 = AveragePooling2D((13,13))(conv10)

flatten = Flatten()(conv10)

softmax = Dense(10, activation="softmax")(flatten)

model = Model(inputs=input_layer, outputs=softmax)


model.compile(loss=keras.losses.categorical_crossentropy,
              optimizer=keras.optimizers.Adadelta(),
              metrics=['accuracy'])
history = model.fit(x_train, y_train, batch_size=batch_size, epochs=epochs,
          verbose=1, validation_data=(x_test, y_test))

  1. 2018年08月11日 13:31 |
  2. DNN
  3. | トラックバック:0
  4. | コメント:0

Accelerating SqueezeNet on FPGAの構造について2

Accelerating SqueezeNet on FPGAの構造について”の続き。

前回は、Accelerating SqueezeNet on FPGAの構造でネットワークを構成する構造体を見ていった。今回は、そのlayer_t 構造体にどんな値が入力されているかを見ていこう。

network.cppのvoid set_layers(network_t* network)で設定される層構成

第1層目(ReLU+Max Pooling付CONV層)
1. 入力高さ - 224
2. 入力幅 - 224
3. 入力チャネル数 - 3
4. 出力チャネル数 - 64
5. カーネル数 - 3
6. ストライド数 - 2
7. パディング数 - 0
8. ReLU実装 - true
9. conv実装 - true
10. fire実装 - false
11. fire_t fire_params_one - 0、コンストラクタ
12. max_pool実装 - true
13. pooling_t pool_params_one
 1. カーネル数 - 3
 2. ストライド数 - 2
14. global_pool実装 - false
15. weight_offset – 0
16. num_weights – 1792
17. img_offset – 1235496 (すべてのWeightの数)
18. output_offset – 1386024 (画像の総ピクセル数 150528を足した数)
19. scratch_offset – 1586728

第2層目
1. 入力高さ - 56
2. 入力幅 - 56
3. 入力チャネル数 - 64
4. 出力チャネル数 - 128
5. カーネル数 - -1
6. ストライド数 - -1
7. パディング数 - 0
8. ReLU実装 - true
9. conv実装 - false
10. fire実装 - true
11. fire_t fire_params_two
 1. squeeze層カーネル数 - 1
 2. squeeze層ストライド数 - 1
 3. squeeze層出力チャネル数 - 16
 4. expand層e1カーネル数 - 1
 5. expand層e1ストライド数 - 1
 6. expand層e1出力チャネル数 - 64
 7. expand層e2カーネル数 - 3
 8. expand層e2ストライド数 - 3
 9. expand層e2出力チャネル数 - 64
12. max_pool実装 - false
13. pooling_t pool_params_two - 0, コンストラクタ
14. global_pool実装 - false
15. weight_offset – 1792
16. num_weights – 11408
17. img_offset – 1386024 (前の層の出力)
18. output_offset – 1586728 (前の層のscratch_offset の値)
19. scratch_offset – 1988136

第3層目
1. 入力高さ - 56
2. 入力幅 - 56
3. 入力チャネル数 - 128
4. 出力チャネル数 - 128
5. カーネル数 - -1
6. ストライド数 - -1
7. パディング数 - 0
8. ReLU実装 - true
9. conv実装 - false
10. fire実装 - true
11. fire_t fire_params_three
 1. squeeze層カーネル数 - 1
 2. squeeze層ストライド数 - 1
 3. squeeze層出力チャネル数 - 16
 4. expand層e1カーネル数 - 1
 5. expand層e1ストライド数 - 1
 6. expand層e1出力チャネル数 - 64
 7. expand層e2カーネル数 - 3
 8. expand層e2ストライド数 - 3
 9. expand層e2出力チャネル数 - 64
12. max_pool実装 - true
13. pooling_t pool_params_three
 1. カーネル数 - 3
 2. ストライド数 - 2
14. global_pool実装 - false
15. weight_offset – 13200
16. num_weights – 12432
17. img_offset – 1586728 (前の層の出力)
18. output_offset – 1988136 (前の層のscratch_offset の値)
19. scratch_offset – 2088488

第4層目
1. 入力高さ - 28
2. 入力幅 - 28
3. 入力チャネル数 - 128
4. 出力チャネル数 - 256
5. カーネル数 - -1
6. ストライド数 - -1
7. パディング数 - 0
8. ReLU実装 - true
9. conv実装 - false
10. fire実装 - true
11. fire_t fire_params_four
 1. squeeze層カーネル数 - 1
 2. squeeze層ストライド数 - 1
 3. squeeze層出力チャネル数 - 16
 4. expand層e1カーネル数 - 1
 5. expand層e1ストライド数 - 1
 6. expand層e1出力チャネル数 - 64
 7. expand層e2カーネル数 - 3
 8. expand層e2ストライド数 - 3
 9. expand層e2出力チャネル数 - 64
12. max_pool実装 - false
13. pooling_t pool_params_four - 0, コンストラクタ
14. global_pool実装 - false
15. weight_offset – 25632
16. num_weights – 45344
17. img_offset – 1988136 (前の層の出力)
18. output_offset – 2088488 (前の層のscratch_offset の値)
19. scratch_offset – 2289192

第5層目
1. 入力高さ - 28
2. 入力幅 - 28
3. 入力チャネル数 - 256
4. 出力チャネル数 - 256
5. カーネル数 - -1
6. ストライド数 - -1
7. パディング数 - 0
8. ReLU実装 - true
9. conv実装 - false
10. fire実装 - true
11. fire_t fire_params_five
 1. squeeze層カーネル数 - 1
 2. squeeze層ストライド数 - 1
 3. squeeze層出力チャネル数 - 32
 4. expand層e1カーネル数 - 1
 5. expand層e1ストライド数 - 1
 6. expand層e1出力チャネル数 - 128
 7. expand層e2カーネル数 - 3
 8. expand層e2ストライド数 - 3
 9. expand層e2出力チャネル数 - 128
12. max_pool実装 - true
13. pooling_t pool_params_five
 1. カーネル数 - 3
 2. ストライド数 - 2
14. global_pool実装 - false
15. weight_offset – 70976
16. num_weights – 49440
17. img_offset – 2088488 (前の層の出力)
18. output_offset – 2289192 (前の層のscratch_offset の値)
19. scratch_offset – 2339368

第6層目
1. 入力高さ - 14
2. 入力幅 - 14
3. 入力チャネル数 - 256
4. 出力チャネル数 - 384
5. カーネル数 - -1
6. ストライド数 - -1
7. パディング数 - 0
8. ReLU実装 - true
9. conv実装 - false
10. fire実装 - true
11. fire_t fire_params_six
 1. squeeze層カーネル数 - 1
 2. squeeze層ストライド数 - 1
 3. squeeze層出力チャネル数 - 48
 4. expand層e1カーネル数 - 1
 5. expand層e1ストライド数 - 1
 6. expand層e1出力チャネル数 - 192
 7. expand層e2カーネル数 - 3
 8. expand層e2ストライド数 - 3
 9. expand層e2出力チャネル数 - 192
12. max_pool実装 - false
13. pooling_t pool_params_six - 0, コンストラクタ
14. global_pool実装 - false
15. weight_offset – 120416
16. num_weights – 104880
17. img_offset – 2289192 (前の層の出力)
18. output_offset – 2339368 (前の層のscratch_offset の値)
19. scratch_offset – 2414632

第7層目
1. 入力高さ - 14
2. 入力幅 - 14
3. 入力チャネル数 - 384
4. 出力チャネル数 - 384
5. カーネル数 - -1
6. ストライド数 - -1
7. パディング数 - 0
8. ReLU実装 - true
9. conv実装 - false
10. fire実装 - true
11. fire_t fire_params_seven
 1. squeeze層カーネル数 - 1
 2. squeeze層ストライド数 - 1
 3. squeeze層出力チャネル数 - 48 
 4. expand層e1カーネル数 - 1
 5. expand層e1ストライド数 - 1
 6. expand層e1出力チャネル数 - 192
 7. expand層e2カーネル数 - 3
 8. expand層e2ストライド数 - 3
 9. expand層e2出力チャネル数 - 192
12. max_pool実装 - false
13. pooling_t pool_params_seven - 0, コンストラクタ
14. global_pool実装 - false
15. weight_offset – 225296
16. num_weights – 111024
17. img_offset – 2339368 (前の層の出力)
18. output_offset – 2414632 (前の層のscratch_offset の値)
19. scratch_offset – 2489896

第8層目
1. 入力高さ - 14
2. 入力幅 - 14
3. 入力チャネル数 - 384
4. 出力チャネル数 - 512
5. カーネル数 - -1
6. ストライド数 - -1
7. パディング数 - 0
8. ReLU実装 - true
9. conv実装 - false
10. fire実装 - true
11. fire_t fire_params_eight
 1. squeeze層カーネル数 - 1
 2. squeeze層ストライド数 - 1
 3. squeeze層出力チャネル数 - 64
 4. expand層e1カーネル数 - 1
 5. expand層e1ストライド数 - 1
 6. expand層e1出力チャネル数 - 256
 7. expand層e2カーネル数 - 3
 8. expand層e2ストライド数 - 3
 9. expand層e2出力チャネル数 - 256
12. max_pool実装 - false
13. pooling_t pool_params_eight - 0, コンストラクタ
14. global_pool実装 - false
15. weight_offset – 336320
16. num_weights – 188992
17. img_offset – 2414632 (前の層の出力)
18. output_offset – 2489896 (前の層のscratch_offset の値)
19. scratch_offset – 2590248

第9層目
1. 入力高さ - 14
2. 入力幅 - 14
3. 入力チャネル数 - 512
4. 出力チャネル数 - 512
5. カーネル数 - -1
6. ストライド数 - -1
7. パディング数 - 0
8. ReLU実装 - true
9. conv実装 - false
10. fire実装 - true
11. fire_t fire_params_nine
 1. squeeze層カーネル数 - 1
 2. squeeze層ストライド数 - 1
 3. squeeze層出力チャネル数 - 64
 4. expand層e1カーネル数 - 1
 5. expand層e1ストライド数 - 1
 6. expand層e1出力チャネル数 - 256
 7. expand層e2カーネル数 - 3
 8. expand層e2ストライド数 - 3
 9. expand層e2出力チャネル数 - 256
12. max_pool実装 - false
13. pooling_t pool_params_nine - 0, コンストラクタ
14. global_pool実装 - false
15. weight_offset – 525312
16. num_weights – 197184
17. img_offset – 2489896 (前の層の出力)
18. output_offset – 2590248 (前の層のscratch_offset の値)
19. scratch_offset – 2690600

第10層目
1. 入力高さ - 14
2. 入力幅 - 14
3. 入力チャネル数 - 512
4. 出力チャネル数 - 1000
5. カーネル数 - 1
6. ストライド数 - 1
7. パディング数 - 0
8. ReLU実装 - true
9. conv実装 - true
10. fire実装 - false
11. fire_t fire_params_ten - 0, コンストラクタ
12. max_pool実装 - false
13. pooling_t pool_params_eight - 0, コンストラクタ
14. global_pool実装 - true
15. weight_offset – 722496
16. num_weights – 513000
17. img_offset – 2590248 (前の層の出力)
18. output_offset – 2690600 (前の層のscratch_offset の値)
19. scratch_offset – 2691600
  1. 2018年07月15日 05:30 |
  2. DNN
  3. | トラックバック:0
  4. | コメント:0

Accelerating SqueezeNet on FPGAの構造について

Accelerating SqueezeNet on FPGAを実装してみた5(Vivado 編 4)”で一応動いているように見えているのだが、画像はロードしていないし、重みもロードされいない気がする。
今回は、Accelerating SqueezeNet on FPGAの構造をメモしてみようと思う。
まずは、network構造体に層数や重みの数と層構成(layer_t 構造体の配列)のメンバがある。

Struct network_tのメンバーについて
1. int num_layers
 1. 層数
2. int num_weights
 1. 重みの数
3. layer_t* layers
 1. 層の構造体へのポインタ


network 構造体のlayer_t* layersにリンクされるのが、layer_t 構造体だ。

Struct layer_t のメンバーについて
1. int height (h)
 1. 入力の高さ
2. int width (w)
 1. 入力の幅
3. int channel_in (chan_in)
 1. 入力チャネル数
4. int channel_out (chan_out)
 1. 出力チャネル数
5. int kernel (k)
 1. カーネル数
6. int stride (stride)
 1. ストライド数
7. int padding (pad)
 1. パッディング数
8. bool relu (relu)
 1. ReLU実装
9. bool conv (conv)
 1. conv実装
10. bool fire (fire)
 1. fire実装
11. fire_t fire_params (fire_params)
 1. fireのパラメータ
12. bool max_pool (max_pool)
 1. max_pool実装
13. pooling_t pool_params (pool_params)
 1. pool_paramsのパラメータ
14. bool global_pool (global_pool)
 1. global_pool実装
15. offset_t weight_offset (weight_offset) (ここからオプション)
 1. weight_offset(重みのアドレスへのオフセット)
 重みは最初の層ですべての重みをロードできるスペースを確保して、その次からの層は最初の層の重みを使用する。weight_offsetは最初の層の重みへのオフセット値となる
16. int num_weights (num_weights)
 1. 重みの数
17. offset_t img_offset (img_offset)
 1. 画像のアドレスへのオフセット
18. offset_t output_offset (output_offset)
 1. 出力のアドレスへのオフセット
19. offset_t scratch_offset (scratch_offset)
 scratchのオフセット(そのレイヤのメモリのオフセットの終了値を表すようだ)


layer_t構造体にリンクされるのは、 pooling_t 構造体と fire_t 構造体だ。
最初に pooling_t 構造体を示す。

Struct pooling_tのメンバーについて
1. int k (k)
 1. カーネル数
2. int stride (stride)
 1. ストライド数


fire_t 構造体を示す。

Struct fire_tのメンバーについて
1. fire_t s_k
 1. squeeze層カーネル数 (1)
2. int s_stride
 1. squeeze層ストライド数 (1)
3. int s_chan_out
 1. squeeze層出力チャネル数
4. int e1_k
 1. expand層e1カーネル数 (1)
5. int e1_stride
 1. expand層e1ストライド数 (1)
6. int e1_chan_out
 1. expand層e1出力チャネル数
7. int e2_k
 1. expand層e2カーネル数 (3)
8. int e2_stride
 1. expand層e2ストライド数 (3)
9. int e2_chan_out
 1. expand層e2出力チャネル数

  1. 2018年07月13日 05:20 |
  2. DNN
  3. | トラックバック:0
  4. | コメント:0

Accelerating SqueezeNet on FPGAを実装してみた5(Vivado 編 4)

Accelerating SqueezeNet on FPGAを実装してみた4(Vivado 編 3)”の続き。

前回は、HDL Wrapper を作って、論理合成、インプリメンテーション、ビットストリームの生成を行った。今回は、ハードウェアをエクスポートして、SDKを起動して、アプリケーションソフトを起動してみよう。

最初にハードウェアをエクスポートしよう。
Vivado のFile メニューからExport -> Export Hardware... を選択する。
Export Hardware ダイアログが開く。
Inculde bitstream にチェックを入れてOK ボタンをクリックする。
squeezenet_54_180710.png

Vivado のFile メニューからLaunch SDK を選択する。
Launch SDK ダイアログが開く。
OK ボタンをクリックする。
squeezenet_55_180710.png

SDK が立ち上がった。
squeezenet_56_180710.png

SDK のFile メニューから New -> Application Project を選択する。
New Project ダイアログが開く。
Project name にsqueezenet_test と入力して、Next > ボタンをクリックする。
squeezenet_57_180710.png

次のTemplates でEmpty Application を選択する。Finish ボタンをクリックする。
squeezenet_58_180710.png

lankas/SqueezeNet”のCPU フォルダを用意する。
squeezenet_59_180710.png

lankas/SqueezeNet”のCPU フォルダのmain.cc をSDK の squeezenet_test プロジェクトの main.cc にコピーする。
squeezenet_60_180710.png

squeezenet_test -> src に、”lankas/SqueezeNet”のCPU フォルダの network.cpp, network.hpp, weight.hpp をドラックアンドドロップする。
すると、File Operation ダイアログが開くので、そのままOK ボタンをクリックする。
squeezenet_61_180710.png

コンパイル終了して、squeezenet_test.elf ができている。
squeezenet_62_180710.png

PYNQ ボードを接続して、電源ONする。
SDK のXilinx メニューからProgram FPGA を選択する。
Program FPGA ダイアログが開くので、Program ボタンをクリックする。
squeezenet_63_180710.png

FPGA をコンフィギュレーション中。
squeezenet_64_180710.png

gtkterm を sudo gtkterm で起動する。
起動したら、Configuration メニューから Port を選択する。
Configuration ダイアログで、Port を /dev/ttyUSB1に Baud Rate を 115200 に変更した。
squeezenet_66_180710.png

SDK で squeezenet_test.elf で右クリックして、右クリックメニューからRun As -> 1Launch on Hardware(System Debugger) を選択して、アプリケーションソフトを起動した。

gtkterm にメッセージが表示された。
squeezenet_67_180710.png

動いているようだが、どうも画像がロードされていない気がする。
  1. 2018年07月12日 05:18 |
  2. DNN
  3. | トラックバック:0
  4. | コメント:0

Accelerating SqueezeNet on FPGAを実装してみた4(Vivado 編 3)

Accelerating SqueezeNet on FPGAを実装してみた3(Vivado 編 2)”の続き。

前回は、SqueezeNet の IP を使用した回路をVivado で作成した。今回は、HDL Wrapper を作って、論理合成、インプリメンテーション、ビットストリームの生成を行う。

まずは、Flow Navigator の横の上のウインドウのSources タブをクリックする。
pynq_sqznet_bd_i を右クリックして、右クリックメニューから、Create HDL Wrapper を選択し、pynq_sqznet_bd_wrapper を作成する。出てくるダイアログはデフォルトでOKだ。
squeezenet_68_180711.png

これで、準備が整った。なお、SqueezeNet の IP の入出力が外部に出ないのと、クロックはPS のクロックを使用していて、そのクロック制約はPS のクロックから回ってくるので、今回の制約ファイルは必要がない。

Flow Navigator のPROGRAM AND DEBUG -> Generate Bitstream をクリックする。
squeezenet_47_180710.png

No Implementation Results Available ダイアログが開く。OK ボタンをクリックする。
squeezenet_48_180710.png

Lanuch Runs ダイアログが開く。デフォルトでOK ボタンをクリックする。
squeezenet_49_180710.png

論理合成が始まる。途中でLaunch Run Critical Message が出るが気にしないで、OK ボタンをクリックする。
squeezenet_50_180710.png

ビットストリームの生成まで終了すると、Bitstream Generation Completed ダイアログが開く。Cancel ボタンをクリックする。
squeezenet_51_180710.png

結果を見てみよう。
Project Summary ボタンをクリックする。
squeezenet_52_180710.png

Project Summary を示す。
squeezenet_53_180710.png

Timing もメットしている。リソース使用量は多い。これは、float でハードウェアでも計算しているので、致し方ない。
  1. 2018年07月11日 05:08 |
  2. DNN
  3. | トラックバック:0
  4. | コメント:0

Accelerating SqueezeNet on FPGAを実装してみた3(Vivado 編 2)

Accelerating SqueezeNet on FPGAを実装してみた2(Vivado 編 1)”の続き。

前回は、SqueezeNet の IP を使用するVivado 2018.2 のプロジェクトを作成しSqueezeNet の compute IP をIP Catalog に登録した。今回は、Vivado でブロックデザインを作成し、回路を作っていく。

まずは、ブロックデザインを作成する。
PROJECT MANAGER のIP INTEGRATOR のCreate Block Desgin をクリックする。
squeezenet_15_180709.png

Create Block Desgin ダイアログが開く。
Design name に pynq_sqznet_bd と入力した。OK ボタンをクリックする。
squeezenet_16_180709.png

Diagram ウインドウが立ち上がるので、中央の「+」ボタンをクリックして、IP をAdd IP する。
squeezenet_17_180709.png

選択ダイアログが開く。Search に「z」と入れると下にZYNQ7 Processing System が出てくるので、ダブルクリックしてDiagram に追加する。
squeezenet_18_180709.png

Diagram に Processing_system7_0 が追加された。
Processing_system7_0 をダブルクリックして設定を行う。
squeezenet_19_180709.png

ZYNQ7 Proessing System (5.5) が立ち上がる。
Presets をクリックして、Apply Configuration... を選択する。
squeezenet_20_180709.png

ダイアログが開く。前回ダウンロードした pynq_revC.tcl を選択して、OK ボタンをクリックする。
squeezenet_22_180709.png

すると、I/O Peripherals にチェックが入ったのがわかると思う。これで、PYNQ ボードの設定が行われた。
squeezenet_23_180709.png

左のPage Navigator からPS-PL Configuration をクリックし、AXI Non Secure Enablement -> GP Master AXI Interface -> M AXI GP0 interface にチェックを入れる。これは、compute IP のレジスタ設定用だ。
ACP Slave AXI Interface -> S AXI ACP interface にチェックを入れる。こちらはcompute IP のDMA 用のAXI Master を接続するためだ。
squeezenet_24_180709.png

Page Navigator からClock Configuration をクリックし、PL Fabric Clocks を展開してFCLK_CLK0 のRequested Freqency を 100 MHzから 85 MHz に変更する。85 MHz にしても、PLL の関係上、83.333336 MHz となる。これは、前々回、Vivado HLS のExport RTL のCP achieved post-implementation が 11.528 ns で、100 MHz で動作しないためだ。
squeezenet_25_180709.png

OK ボタンをクリックして終了すると、Processing_system7_0 の設定は終了した。
Diagram に戻って、Run Block Automation をクリックする。
squeezenet_26_180709.png

Run Block Automation ダイアログが開く。そのままOK ボタンをクリックする。
squeezenet_27_180709.png

DDR とFIXED_IO のポートが追加された。
「+」ボタンをクリックして、compute IP をAdd IP しよう。
squeezenet_28_180709.png

Search に 「comp」と入力して、Compute をダブルクリックして、Add IP する。
squeezenet_36_180709.png

compute_0 がAdd IP された。
squeezenet_37_180709.png

compute_0 をダブルクリックして設定を行う。
ダイアログが開く。CACHE value を "1111" に変更し、OK ボタンをクリックする。
squeezenet_46_180710.png

Run Block Automation をクリックする。
Run Block Automation ダイアログが開く。
All Automation にチェックを入れて、OK ボタンをクリックする。
squeezenet_41_180709.png

配線が完了した。
squeezenet_42_180709.png

Validate Design をクリックして、回路の整合性をチェックする。
squeezenet_43_180709.png

warning が出ているが、DDR のパラメータに関することやAXI ACP ポートのことなので問題ない。OK ボタンをクリックする。
squeezenet_44_180709.png

最後にRegenerate Layout をクリックしてレイアウトを最適にする。
squeezenet_45_180709.png

最終形態。(ゴジラじゃないってか?)
squeezenet_38_180709.png

Address Editor 画面を示す。
squeezenet_39_180709.png

セーブアイコンをクリックして、ブロックデザインをセーブしておく。
  1. 2018年07月10日 04:55 |
  2. DNN
  3. | トラックバック:0
  4. | コメント:0

Accelerating SqueezeNet on FPGAを実装してみた2(Vivado 編 1)

Accelerating SqueezeNet on FPGAを実装してみた1(Vivado HLS編)”の続き。

前回は、”lankas/SqueezeNet”のFPGA フォルダの内容をVivado HLS 2018.2 でプロジェクトを作って確かめ、IP 化を行った。今回は、SqueezeNet の IP を使用するVivado 2018.2 のプロジェクトを作成しよう。

Vivado 2018.2 の PYNQ_squeezenet プロジェクトを作成する。
Vivado 2018.2 のWelcome 画面からCreate Project を指定して新規プロジェクトを作成した。
squeezenet_9_180709.png

新規プロジェクト作成のダイアログが開く。
Project name で、新規プロジェクトの名前を入力する。PYNQ_squeezenet にした。
squeezenet_11_180709.png


RTL プロジェクトとして作成した。
squeezenet_12_180709.png

Default Part では、Zynq-7000 の xc7z020clg400-1 を選択した。
squeezenet_13_180709.png

New Project Summary が出てFinish ボタンをクリックしてプロジェクト新規作成が終了する。
squeezenet_14_180709.png

Vivado 2018.2 のPYNQ_squeezenet プロジェクトが作成された。
squeezenet_15_180709.png

まずは、PYNQのZynq のPS のPeset 設定をダウンロードする。
PYNQ-Z1 のページに行って、Zynq Presets をダウンロードする。そしてZIP ファイルがダウンロードできるので、それを解凍しておく。pynq_revC.tcl という名前になる。
squeezenet_21_180709.png

次に、IP Catalog に Vivado HLS で作成したCompute IP を登録しよう。
もうすでに、PYNQ_squeezenet ディレクトリができているはずなので、その下に squeezenet ディレクトリを作成する。
squeezenet ディレクトリの下に、~/Vivado_HLS/PYNQ/squeezenet/solution1/impl/ip/xilinx_com_hls_compute_1_0.zip の内容をすべてコピーする。
squeezenet_29_180709.png

PROJECT MANAGER から IP Catalog をクリックする。
squeezenet_30_180709.png

IP Catalog が開いた。
squeezenet_31_180709.png

IP Catalog で右クリックし、右クリックメニューからAdd Repository... を選択する。

Repositories ダイアログで、 ~/HDL/PYNQ/PYNQ_squeezenet/squeezenet を選択して、Select ボタンをクリックする。
squeezenet_32_180709.png

Compute IP が追加された。ダイアログでOK ボタンをクリックする。
squeezenet_33_180709.png

squeezenet_34_180709.png

これで、ブロックデザインで Compute IP を使うことができる。

今日はここまでとする。
  1. 2018年07月09日 04:03 |
  2. DNN
  3. | トラックバック:0
  4. | コメント:0
»