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

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

FPGAの部屋

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

私の nngen の現在の状況

「ゼロから作るDeep Learning」のCNNをNNgenでハードウェア化する企画では、nngen での推論がうまく行かなかった。たぶん、「ゼロから作るDeep Learning」のCNNと NNgen はネットワークの構造の定義が何処か違うのではないかな?(”「ゼロから作るDeep Learning」のCNNをNNgenでハードウェア化する3”)
そこで onnx モデルから NNgen のモデルに実行しようとしたのだが、 onnx を動かそうとしているうちに NNgen も動作しなくなってしまった。やはり、Docker で構築したほうが良いかも知れない? Docker を使うとハードディスク容量が食われてしまうので、余り使いたくないのだが。。。

さて、以前ブログに書いた”TensorFlow + Kerasを使ってみた3(以前使用したCNNを使った学習)”の CNN を再度やってみよう。
ネットワークの学習をしたのだが、エラーで動作しなかった。エラーの部分はここだった。

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


Keras Documentation の to_categorical によると

keras.utils.to_categorical(y, num_classes=None, dtype='float32')

となったようで、 np_utils を抜かす様になったようだ。

y_train = keras.utils.to_categorical(y_train, num_classes)
y_test = keras.utils.to_categorical(y_test, num_classes)

に変更すると実行することができた。

TensorFlow + Keras の MNIST サンプルを学習した。
NNgen2_65_210403.png
NNgen2_66_210403.png

精度は 0.8668 だった。

Python コードを貼っておく。

# My Mnist CNN (Convolution layerの特徴マップは5個)
# Conv2D - ReLU - MaxPooling - Dence - ReLU - Dence
# 2018/05/25 by marsee
# Keras / Tensorflowで始めるディープラーニング入門 https://qiita.com/yampy/items/706d44417c433e68db0d
# のPythonコードを再利用させて頂いている

import keras
from keras.datasets import mnist
from keras.models import Sequential
from keras.layers import Dense, Dropout, Flatten
from keras.layers import Conv2D, MaxPooling2D, Activation
from keras import backend as K

batch_size = 128
num_classes = 10
epochs = 30

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.to_categorical(y_train, num_classes)
y_test =  keras.utils.to_categorical(y_test, num_classes)

model = Sequential()
model.add(Conv2D(10, kernel_size=(5, 5),
                 input_shape=input_shape))
model.add(Activation(activation='relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Flatten())
model.add(Dense(100))
model.add(Activation(activation='relu'))
model.add(Dense(num_classes))
model.add(Activation(activation='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))


精度とロスのグラフを書いた。
NNgen2_67_210403.png
NNgen2_68_210403.png

keras2onnx で onnx モデルに変換できた。
NNgen で onnx モデルを nngen モデルに変換しようとしたら

ModuleNotFoundError: No module named 'nngen'

と言われてしまった。
NNgen2_69_210403.png

いろいろと onnx 動かそうとしているうちに、 NNgen の必要とするライブラリがアップデートされてしまったようだ。
Docker を使ったほうが良さそうだ。
とりあえず、他のやりたいことがあるので、NNgen はとりあえず休止しようと思う。そして、チュートリアルができたら再開してみよう。
今まで、サポートしていただいた作者の shtaxxx さん、ありがとうございました。そして、NNgen をうまく試すことができなくて、申し訳ありません。
  1. 2021年04月03日 05:05 |
  2. NNgen
  3. | トラックバック:0
  4. | コメント:0

「ゼロから作るDeep Learning」のCNNをNNgenでハードウェア化する5

「ゼロから作るDeep Learning」のCNNをNNgenでハードウェア化する4”の続き。

2017年の 6 月にやってみたオライリー出版社の”「ゼロから作るDeep Learning」”の deep-learning-from-scratch/ch07/ の畳み込みニューラルネットワーク(CNN)を NNgen でハードウェア化してみることにしたということで、前回は、オライリー出版社の”「ゼロから作るDeep Learning」”の deep-learning-from-scratch/ch07/ の畳み込みニューラルネットワーク(CNN)に NNgen での整数(と同等)の重みとバイアスにして推論してみたが、うまく行った。今回は、Jupyter Notebook の今までの記述をまとめて貼っておこうと思う。
次やるときは、Keras の MNIST の実装を ONNX のモデルに変換してから NNgen に取り込んでみようと思う。

nngen_example_mnist_cnn.ipynb の内容を貼っておく。

# 「ゼロから作るDeep Learning」のCNNをNNgenでハードウェア化する

参照URL”「ゼロから作るDeep Learning」の畳み込みニューラルネットワークのハードウェア化1”
https://marsee101.blog.fc2.com/blog-entry-3829.html

NNgen/nngen https://github.com/NNgen/nngen

”「ゼロから作るDeep Learning」の畳み込みニューラルネットワークのハードウェア化1”のMNIST CNNをもう一度やってみる


```python
# train_convnet.py
# 2017/06/06 FPGAによるハードウェア化をにらんで、量子化を行う by marsee
# 元になったコードは、https://github.com/oreilly-japan/deep-learning-from-scratch にあります。
# 改変したコードもMITライセンスとします。 2017/06/19 by marsee

# coding: utf-8
import sys, os
sys.path.append(os.pardir)  # 親ディレクトリのファイルをインポートするための設定
import numpy as np
import matplotlib.pyplot as plt
from dataset.mnist import load_mnist
from trainer_int import Trainer
from simple_convnet_int import SimpleConvNet

# データの読み込み
(x_train, t_train), (x_test, t_test) = load_mnist(flatten=False)

# 処理に時間のかかる場合はデータを削減 
#x_train, t_train = x_train[:5000], t_train[:5000]
#x_test, t_test = x_test[:1000], t_test[:1000]

#max_epochs = 5
max_epochs = 20

network = SimpleConvNet(input_dim=(1,28,28), 
                        conv_param = {'filter_num': 10, 'filter_size': 5, 'pad': 0, 'stride': 1},
                        #conv_param = {'filter_num': 30, 'filter_size': 5, 'pad': 0, 'stride': 1},
                        hidden_size=100, output_size=10, weight_init_std=0.01)
                        
trainer = Trainer(network, x_train, t_train, x_test, t_test,
                  epochs=max_epochs, mini_batch_size=100,
                  optimizer='Adam', optimizer_param={'lr': 0.001},
                  evaluate_sample_num_per_epoch=1000)
trainer.train()

'''x_testn, t_testn = x_test[:500], t_test[:500]
test_accn = network.accuracy_msg(x_testn, t_testn)
print(test_accn)'''

'''train_acc = network.accuracy(x_train, t_train)
test_acc = network.accuracy(x_test, t_test)
print(train_acc, test_acc)
train_acc_int = network.accuracy_int(x_train, t_train)'''
#test_acc_int = network.accuracy_int(x_test, t_test)
#print(test_acc_int)

# パラメータの保存
network.save_params("params.pkl")
print("Saved Network Parameters!")

# グラフの描画
markers = {'train': 'o', 'test': 's'}
x = np.arange(max_epochs)
plt.plot(x, trainer.train_acc_list, marker='o', label='train', markevery=2)
plt.plot(x, trainer.test_acc_list, marker='s', label='test', markevery=2)
plt.xlabel("epochs")
plt.ylabel("accuracy")
plt.ylim(0, 1.0)
plt.legend(loc='lower right')
plt.show()
```

    train loss:2.301385118388284
    === epoch:1, train acc:0.184, test acc:0.188 ===
    train loss:2.300783416724263
    train loss:2.2985280211636856


    train loss:0.0014416474424052506
    train loss:0.00029753533974773714
    train loss:0.0024815949870809124
    train loss:0.001080201861468442
    train loss:0.009542414638567448
    train loss:0.0003716470091183171
    train loss:0.0010014160283579254
    train loss:0.000636980396385224
    train loss:0.0007263677665641715
    train loss:0.0025971938006329677
    train loss:0.003134432045827001
    train loss:0.0030433384352522848
    train loss:0.0016623108178602428
    train loss:0.004724656919902167
    train loss:0.002754500627006845
    train loss:0.00028287348906820743
    train loss:0.0020828163320118203
    train loss:0.0031006529569975816
    train loss:0.005907909665949748
    train loss:0.0037946706647029875
    train loss:0.0007289706523717551
    train loss:0.0006987468668795674
    train loss:0.0027144383364796636
    train loss:0.006576938863826107
    =============== Final Test Accuracy ===============
    test acc:0.9877
    Saved Network Parameters!



    
![png](output_3_1.png)
    


一旦落としてからもう一度やる時のロード関数


```python
# coding: utf-8
import sys, os
sys.path.append(os.pardir)  # 親ディレクトリのファイルをインポートするための設定
import numpy as np
import matplotlib.pyplot as plt
from dataset.mnist import load_mnist
from trainer_int import Trainer
from simple_convnet_int import SimpleConvNet

# データの読み込み
(x_train, t_train), (x_test, t_test) = load_mnist(flatten=False)

# 処理に時間のかかる場合はデータを削減 
#x_train, t_train = x_train[:5000], t_train[:5000]
#x_test, t_test = x_test[:1000], t_test[:1000]

#max_epochs = 5
max_epochs = 20

network = SimpleConvNet(input_dim=(1,28,28), 
                        conv_param = {'filter_num': 10, 'filter_size': 5, 'pad': 0, 'stride': 1},
                        #conv_param = {'filter_num': 30, 'filter_size': 5, 'pad': 0, 'stride': 1},
                        hidden_size=100, output_size=10, weight_init_std=0.01)
network.load_params("params.pkl")
```


```python
test_acc_int = network.accuracy_int(x_test, t_test)
print(test_acc_int)
```

    0.9833


「ゼロから作るDeep Learning」のMNIST CNNの重みやバイアスの配列の形状を見て、reshapeでNNgenに合わせる


```python
print(network.params['W1'].shape)
print(network.params['b1'].shape)
print(network.params['W2'].shape)
print(network.params['b2'].shape)
print(network.params['W3'].shape)
print(network.params['b3'].shape)

W1n = network.params['W1'].transpose(0,2,3,1)
print(W1n.shape)
print(np.max(W1n))
print(np.min(W1n))
B1n = network.params['b1']
print(np.max(B1n))
print(np.min(B1n))
W2n=network.params['W2'].transpose(1,0)
print(W2n.shape)
print(np.max(W2n))
print(np.min(W2n))
B2n = network.params['b2']
print(np.max(B2n))
print(np.min(B2n))
W3n=network.params['W3'].transpose(1,0)
print(W3n.shape)
print(np.max(W3n))
print(np.min(W3n))
B3n = network.params['b3']
print(np.max(B3n))
print(np.min(B3n))
```

    (10, 1, 5, 5)
    (10,)
    (1440, 100)
    (100,)
    (100, 10)
    (10,)
    (10, 5, 5, 1)
    0.6205409499741875
    -0.9768615311384286
    0.001046327841590367
    -0.43582685576224633
    (100, 1440)
    0.8932422073086069
    -0.9514574018404229
    0.17520125723869304
    -0.12940758873286193
    (10, 100)
    0.3224653381346921
    -0.6238471654267962
    0.09732122727552153
    -0.07801633865297178


NNgenのオペレータを使用したMNIST CNNの実装


```python
from __future__ import absolute_import
from __future__ import print_function

import sys
import os

import nngen as ng


# data types
act_dtype = ng.int32
weight_dtype = ng.int8
bias_dtype = ng.int16
scale_dtype = ng.int8
batchsize = 1

# input
input_layer = ng.placeholder(dtype=ng.int32,
                             shape=(batchsize, 28, 28, 1),  # N, H, W, C
                             name='input_layer')

# layer 0: conv2d (with bias and scale (= batchnorm)), relu, max_pool
wn0 = ng.variable(dtype=weight_dtype,
                 shape=(10, 5, 5, 1),  # Och, Ky, Kx, Ich
                 name='wn0')
bn0 = ng.variable(dtype=bias_dtype,
                 shape=(wn0.shape[0],), name='bn0')
sn0 = ng.variable(dtype=scale_dtype,
                 shape=(wn0.shape[0],), name='sn0')

a0 = ng.conv2d(input_layer, wn0,
               strides=(1, 1, 1, 1),
               bias=bn0,
               scale=sn0,
               padding='VALID',
               act_func=ng.relu,
               dtype=act_dtype,
               sum_dtype=ng.int32)

a0p = ng.max_pool_serial(a0,
                         ksize=(1, 2, 2, 1),
                         strides=(1, 2, 2, 1))

a0r = ng.reshape(a0p, [batchsize, -1])

# layer 1: full-connection, relu
wn1 = ng.variable(weight_dtype,
                 shape=(100, a0r.shape[-1]),
                 name='wn1')
bn1 = ng.variable(bias_dtype,
                 shape=(wn1.shape[0],),
                 name='bn1')
sn1 = ng.variable(scale_dtype,
                 shape=(wn1.shape[0],),
                 name='sn1')

a1 = ng.matmul(a0r, wn1,
               bias=bn1,
               scale=sn1,
               transposed_b=True,
               act_func=ng.relu,
               dtype=act_dtype,
               sum_dtype=ng.int32)

# layer 2: full-connection, relu
wn2 = ng.variable(weight_dtype,
                 shape=(10, a1.shape[-1]),
                 name='wn2')
bn2 = ng.variable(bias_dtype,
                 shape=(wn2.shape[0],),
                 name='bn2')
sn2 = ng.variable(scale_dtype,
                 shape=(wn2.shape[0],),
                 name='sn2')

# output
output_layer = ng.matmul(a1, wn2,
                         bias=bn2,
                         scale=sn2,
                         transposed_b=True,
                         name='output_layer',
                         dtype=act_dtype,
                         sum_dtype=ng.int32)
```

NNgenのMIST CNNの重みやバイアスの配列の形状を確認する


```python
print(wn0.shape)
print(bn0.shape)
print(wn1.shape)
print(bn1.shape)
print(wn2.shape)
print(bn2.shape)
print(a0.shape)
print(a0p.shape)
print(a0r.shape)
```

    (10, 5, 5, 1)
    (10,)
    (100, 1440)
    (100,)
    (10, 100)
    (10,)
    (1, 24, 24, 10)
    (1, 12, 12, 10)
    (1, 1440)


「ゼロから作るDeep Learning」のMNIST CNNの重みやバイアスを整数化するために128を乗算するためのテスト


```python
print(W1n[0][0][0][0])
print(W1n[0][0][1][0])
W1n2 = W1n * 127.9
print(W1n2[0][0][0][0])
print(W1n2[0][0][1][0])
```

    0.10187240072522206
    0.08383048453038348
    13.029480052755902
    10.721918971436049


「ゼロから作るDeep Learning」のMNIST CNNの重みやバイアスを整数化するために128を乗算する


```python
W1n2 = W1n * 127.9
print(np.max(W1n2))
print(np.min(W1n2))
B1n2 = B1n * 16383.9
print(np.max(B1n2))
print(np.min(B1n2))
W2n2 = W2n * 127.9
B2n2 = B2n * 16383.9
W3n2 = W3n * 127.9
B3n2 = B3n * 16383.9
```

    79.36718750169858
    -124.94058983260501
    17.142930723832414
    -7140.5436221230675


NNgenのMIST CNNの重みやバイアスに「ゼロから作るDeep Learning」のMNIST CNNの重みやバイアスの値を代入する
Aout = ((Ain * W + bias) * scale) >> rshift_out だそうなので、scaleは要素がすべて1の配列とする


```python
wn0_value = W1n2.astype(np.int8)
wn0.set_value(wn0_value)
print(wn0_value[0][0][0][0])
print(wn0_value[0][0][1][0])
bn0_value = B1n2.astype(np.int16)
bn0.set_value(bn0_value)
sn0_value = np.ones(sn0.shape, dtype=np.int8)
sn0.set_value(sn0_value)
print(sn0_value[0])

wn1_value = W2n2.astype(np.int8)
wn1.set_value(wn1_value)
bn1_value = B2n2.astype(np.int16)
bn1.set_value(bn1_value)
sn1_value = np.ones(sn1.shape, dtype=np.int8)
sn1.set_value(sn1_value)

wn2_value = W3n2.astype(np.int8)
wn2.set_value(wn2_value)
bn2_value = B3n2.astype(np.int16)
bn2.set_value(bn2_value)
sn2_value = np.ones(sn2.shape, dtype=np.int8)
sn2.set_value(sn2_value)
```

    13
    10
    1


ハードウェア属性の割当


```python
# conv2d, matmul
# par_ich: parallelism in input-channel
# par_och: parallelism in output-channel
# par_col: parallelism in pixel column
# par_row: parallelism in pixel row
# cshamt_out: right shift amount after applying bias/scale

par_ich = 2
par_och = 2
cshamt_out = weight_dtype.width - 1

a0.attribute(par_ich=par_ich, par_och=par_och,
             cshamt_out=0)
a1.attribute(par_ich=par_ich, par_och=par_och,
             cshamt_out=0)
output_layer.attribute(par_ich=par_ich, par_och=par_och,
                       cshamt_out=weight_dtype.width +7)

# max_pool
# par: parallelism in in/out channel

par = par_och

a0p.attribute(par=par)
```

NNgenデータフローをソフトウェアとして実行して、DNNモデルの動作を確認


```python
print(t_test[0])
print(t_test[1])
print(t_test[2])
print(t_test[3])
print(t_test[4])
print(x_test[0].shape)
```

    7
    2
    1
    0
    4
    (1, 28, 28)



```python
input_layer_value = x_test[1].transpose(1,2,0)
input_layer_value = input_layer_value.reshape(input_layer.shape)
print(input_layer_value.shape)
input_layer_value = input_layer_value * 127.9
input_layer_value = input_layer_value.astype(np.int8)
eval_outs = ng.eval([output_layer], input_layer=input_layer_value)
output_layer_value = eval_outs[0]

print(output_layer_value)
```

    (1, 28, 28, 1)
    [[-112 -155  -19    7  -57   29  -42 -275   37 -118]]



```python
print(t_test[0:5])
print(network.predict_int(x_test[0:5]))
```

    [7 2 1 0 4]
    [[ -8.59375 -12.0625   -5.34375  -2.25    -29.25    -12.09375 -30.8125
       16.65625  -9.90625  -1.1875 ]
     [ -8.59375   3.25     18.0625   -4.59375 -32.      -12.375    -7.40625
      -23.46875 -12.3125  -23.75   ]
     [-14.15625   4.71875  -5.96875  -8.21875  -3.84375  -9.8125  -11.34375
       -3.90625  -0.375    -5.53125]
     [ 15.25    -12.4375   -6.40625  -6.8125  -16.84375  -5.03125  -0.3125
        0.625   -10.71875  -5.84375]
     [-20.28125 -13.0625   -9.3125  -10.84375  12.5      -6.03125  -9.46875
       -6.5625   -5.375     2.28125]]


「ゼロから作るDeep Learning」の畳み込みニューラルネットワークでNNgen用に変換した重みとバイアスを使って正しい推論ができるかどうか?を検証する


```python
network.params['W1'] = np.int32(network.params['W1'] * 127.9)
network.params['b1'] = np.int32(network.params['b1'] * 16383.9)
network.params['W2'] = np.int32(network.params['W2'] * 127.9)
network.params['b2'] = np.int32(network.params['b2'] * 16383.9)
network.params['W3'] = np.int32(network.params['W3'] * 127.9)
network.params['b3'] = np.int32(network.params['b3'] * 16383.9)
```


```python
print(np.max(network.params['W1']))
print(np.min(network.params['W1']))
print(np.max(network.params['b1']))
print(np.min(network.params['b1']))
print(np.max(network.params['W2']))
print(np.min(network.params['W2']))
print(np.max(network.params['b2']))
print(np.min(network.params['b2']))
print(np.max(network.params['W3']))
print(np.min(network.params['W3']))
print(np.max(network.params['b3']))
print(np.min(network.params['b3']))
```

    79
    -124
    17
    -7140
    114
    -121
    2870
    -2120
    41
    -79
    1594
    -1278



```python
print(t_test[0:5])
x_test_rshft7 = np.int32(x_test * 127.9)
predict_result = network.predict(x_test_rshft7[0:5])/512
predict_result = np.int32(predict_result)
print(predict_result)
```

    [7 2 1 0 4]
    [[-2 -3 -1 -1 -8 -4 -9  5 -3  0]
     [-2  0  4 -2 -9 -3 -1 -8 -2 -6]
     [-3  1 -1 -2 -1 -3 -3 -1  0 -2]
     [ 4 -3 -2 -1 -4 -1  0  0 -2 -1]
     [-4 -3 -2 -3  4 -2 -3 -1 -1  0]]


output_3_1.png
  1. 2021年04月01日 04:46 |
  2. NNgen
  3. | トラックバック:0
  4. | コメント:0

「ゼロから作るDeep Learning」のCNNをNNgenでハードウェア化する4

「ゼロから作るDeep Learning」のCNNをNNgenでハードウェア化する3”の続き。

2017年の 6 月にやってみたオライリー出版社の”「ゼロから作るDeep Learning」”の deep-learning-from-scratch/ch07/ の畳み込みニューラルネットワーク(CNN)を NNgen でハードウェア化してみることにしたということで、前回は、「ゼロから作るDeep Learning」のCNN の重みとバイアスを与えて、 NNgenデータフローをソフトウェアとして実行して、DNNモデルの動作を確認したが、データがおかしいということになった。今回は、オライリー出版社の”「ゼロから作るDeep Learning」”の deep-learning-from-scratch/ch07/ の畳み込みニューラルネットワーク(CNN)に NNgen での整数(と同等)の重みとバイアスにして推論してみよう。

まずは、現状の重みとバイアスのビット長と演算長を規制した状態で推論してみよう。
x_test の最初から 5 個を推論した。
t_test が正解の数字だ。推論の値の最大値を見ていくと正解の数字+1 番目となっているのが分かる。これは 0 からカウントしているからだ。
NNgen2_51_210331.png

print(t_test[0:5])
print(network.predict_int(x_test[0:5]))


次に、NNgen の時と同様に重みは 127.9 倍、バイアスは 16383.9 倍した。
NNgen2_52_210331.png

network.params['W1'] = network.params['W1'] * 127.9
network.params['b1'] = network.params['b1'] * 16383.9
network.params['W2'] = network.params['W2'] * 127.9
network.params['b2'] = network.params['b2'] * 16383.9
network.params['W3'] = network.params['W3'] * 127.9
network.params['b3'] = network.params['b3'] * 16383.9


新しい値の重みとバイアスの最大値、最小値を見ると、それらしき値になっている。
NNgen2_53_210331.png

print(np.max(network.params['W1']))
print(np.min(network.params['W1']))
print(np.max(network.params['b1']))
print(np.min(network.params['b1']))
print(np.max(network.params['W2']))
print(np.min(network.params['W2']))
print(np.max(network.params['b2']))
print(np.min(network.params['b2']))
print(np.max(network.params['W3']))
print(np.min(network.params['W3']))
print(np.max(network.params['b3']))
print(np.min(network.params['b3']))


入力値を 127.9 倍して推論を行って、結果を 1/512 倍して表示したところ、以前の重みとバイアスのビット長と演算長を規制した状態で推論した結果と一致した。
NNgen2_54_210331.png

print(t_test[0:5])
x_test_rshft7 = x_test * 127.9
predict_result = network.predict(x_test_rshft7[0:5])/512
predict_result = np.int32(predict_result)
print(predict_result)


やり方としては問題ないようなのだが。。。
  1. 2021年03月31日 05:17 |
  2. NNgen
  3. | トラックバック:0
  4. | コメント:0

「ゼロから作るDeep Learning」のCNNをNNgenでハードウェア化する3

「ゼロから作るDeep Learning」のCNNをNNgenでハードウェア化する2”の続き。

2017年の 6 月にやってみたオライリー出版社の”「ゼロから作るDeep Learning」”の deep-learning-from-scratch/ch07/ の畳み込みニューラルネットワーク(CNN)を NNgen でハードウェア化してみることにしたということで、前回は、NNgen のデータフローを使用した CNN として書き直した MNIST CNN を示した。しかし、これを NNgenデータフローをソフトウェアとして実行して、DNNモデルの動作を確認すると出力データが同じになってしまった。よって今回はそれを書き換えた。そして、「ゼロから作るDeep Learning」のCNN の重みとバイアスを与えて、 NNgenデータフローをソフトウェアとして実行して、DNNモデルの動作を確認したが、データがおかしい。

まずは、NNgenのオペレータを使用したMNIST CNNの実装を示す。

from __future__ import absolute_import
from __future__ import print_function

import sys
import os

import nngen as ng


# data types
act_dtype = ng.int32
weight_dtype = ng.int8
bias_dtype = ng.int8
scale_dtype = ng.int8
batchsize = 1

# input
input_layer = ng.placeholder(dtype=ng.int8,
                             shape=(batchsize, 28, 28, 1),  # N, H, W, C
                             name='input_layer')

# layer 0: conv2d (with bias and scale (= batchnorm)), relu, max_pool
wn0 = ng.variable(dtype=weight_dtype,
                 shape=(10, 5, 5, 1),  # Och, Ky, Kx, Ich
                 name='wn0')
bn0 = ng.variable(dtype=bias_dtype,
                 shape=(wn0.shape[0],), name='bn0')
sn0 = ng.variable(dtype=scale_dtype,
                 shape=(wn0.shape[0],), name='sn0')

a0 = ng.conv2d(input_layer, wn0,
               strides=(1, 1, 1, 1),
               bias=bn0,
               scale=sn0,
               padding='VALID',
               act_func=ng.relu,
               dtype=act_dtype,
               sum_dtype=ng.int32)

a0p = ng.max_pool_serial(a0,
                         ksize=(1, 2, 2, 1),
                         strides=(1, 2, 2, 1))

a0r = ng.reshape(a0p, [batchsize, -1])

# layer 1: full-connection, relu
wn1 = ng.variable(weight_dtype,
                 shape=(100, a0r.shape[-1]),
                 name='wn1')
bn1 = ng.variable(bias_dtype,
                 shape=(wn1.shape[0],),
                 name='bn1')
sn1 = ng.variable(scale_dtype,
                 shape=(wn1.shape[0],),
                 name='sn1')

a1 = ng.matmul(a0r, wn1,
               bias=bn1,
               scale=sn1,
               transposed_b=True,
               act_func=ng.relu,
               dtype=act_dtype,
               sum_dtype=ng.int32)

# layer 2: full-connection, relu
wn2 = ng.variable(weight_dtype,
                 shape=(10, a1.shape[-1]),
                 name='wn2')
bn2 = ng.variable(bias_dtype,
                 shape=(wn2.shape[0],),
                 name='bn2')
sn2 = ng.variable(scale_dtype,
                 shape=(wn2.shape[0],),
                 name='sn2')

# output
output_layer = ng.matmul(a1, wn2,
                         bias=bn2,
                         scale=sn2,
                         transposed_b=True,
                         name='output_layer',
                         dtype=act_dtype,
                         sum_dtype=ng.int32)


NNgenのMIST CNNの重みやバイアスに「ゼロから作るDeep Learning」のMNIST CNNの重みやバイアスの値を代入する
Aout = ((Ain * W + bias) * scale) >> rshift_out だそうなので、scaleは要素がすべて1の配列とする

wn0_value = W1n2.astype(np.int8)
wn0.set_value(wn0_value)
bn0_value = B1n2.astype(np.int8)
bn0.set_value(bn0_value)
sn0_value = np.ones(sn0.shape, dtype=np.int8)
sn0.set_value(sn0_value)
print(sn0_value[0])

wn1_value = W2n2.astype(np.int8)
wn1.set_value(wn1_value)
bn1_value = B2n2.astype(np.int8)
bn1.set_value(bn1_value)
sn1_value = np.ones(sn1.shape, dtype=np.int8)
sn1.set_value(sn1_value)

wn2_value = W3n2.astype(np.int8)
wn2.set_value(wn2_value)
bn2_value = B3n2.astype(np.int8)
bn2.set_value(bn2_value)
sn2_value = np.ones(sn2.shape, dtype=np.int8)
sn2.set_value(sn2_value)


ハードウェア属性の割当

# conv2d, matmul
# par_ich: parallelism in input-channel
# par_och: parallelism in output-channel
# par_col: parallelism in pixel column
# par_row: parallelism in pixel row
# cshamt_out: right shift amount after applying bias/scale

par_ich = 2
par_och = 2
cshamt_out = weight_dtype.width - 1

a0.attribute(par_ich=par_ich, par_och=par_och,
             cshamt_out=0)
a1.attribute(par_ich=par_ich, par_och=par_och,
             cshamt_out=0)
output_layer.attribute(par_ich=par_ich, par_och=par_och,
                       cshamt_out=weight_dtype.width +7)

# max_pool
# par: parallelism in in/out channel

par = par_och

a0p.attribute(par=par)


NNgenデータフローをソフトウェアとして実行して、DNNモデルの動作を確認

input_layer_value = x_test[0].reshape(input_layer.shape)
input_layer_value = input_layer_value * 127.9
input_layer_value = input_layer_value.astype(np.int8)
eval_outs = ng.eval([output_layer], input_layer=input_layer_value)
output_layer_value = eval_outs[0]

print(output_layer_value)


NNgen2_50_210330.png

7 の出力が最大にならない。
  1. 2021年03月30日 04:36 |
  2. NNgen
  3. | トラックバック:0
  4. | コメント:0

「ゼロから作るDeep Learning」のCNNをNNgenでハードウェア化する2

「ゼロから作るDeep Learning」のCNNをNNgenでハードウェア化する1”の続き。

2017年の 6 月にやってみたオライリー出版社の”「ゼロから作るDeep Learning」”の deep-learning-from-scratch/ch07/ の畳み込みニューラルネットワーク(CNN)を NNgen でハードウェア化してみることにしたということで、前回は、”「ゼロから作るDeep Learning」の畳み込みニューラルネットワークのハードウェア化1”の量子化ビット数を変更して MNIST CNN を学習した。今回は、NNgen の hello_nngen.py の CNN を参考に、前回学習した MNIST CNN を NNgen のデータフローを使用した CNN として書き直した。そして、「ゼロから作るDeep Learning」のMNIST CNNの重みやバイアスの配列の形状を見て、reshapeでNNgenに合わせた。

前回学習した MNIST CNN を NNgen のデータフローを使用した CNN として書き直すにあって問題となるのは、hello_nngen.py の CNN の conv2d はパッディングがされているのだが、MNIST CNN はパッディングなしということだった。
そこで、ツィッターで NNgen の作者にお聞きしたところ、

padding='VALID'を指定するか、padding=0とすれば良いはずです

ということだったので、conv2d に”padding='VALID'”を追加した。
NNgen のデータフローを使用した CNN として書き直した MNIST CNN を示す。
NNgen2_46_210329.png
NNgen2_47_210329.png

from __future__ import absolute_import
from __future__ import print_function

import sys
import os

import nngen as ng


# data types
act_dtype = ng.int8
weight_dtype = ng.int8
bias_dtype = ng.int8
scale_dtype = ng.int8
batchsize = 1

# input
input_layer = ng.placeholder(dtype=act_dtype,
                             shape=(batchsize, 28, 28, 1),  # N, H, W, C
                             name='input_layer')

# layer 0: conv2d (with bias and scale (= batchnorm)), relu, max_pool
wn0 = ng.variable(dtype=weight_dtype,
                 shape=(10, 5, 5, 1),  # Och, Ky, Kx, Ich
                 name='wn0')
bn0 = ng.variable(dtype=bias_dtype,
                 shape=(wn0.shape[0],), name='bn0')
sn0 = ng.variable(dtype=scale_dtype,
                 shape=(wn0.shape[0],), name='sn0')

a0 = ng.conv2d(input_layer, wn0,
               strides=(1, 1, 1, 1),
               bias=bn0,
               scale=sn0,
               padding='VALID',
               act_func=ng.relu,
               dtype=act_dtype,
               sum_dtype=ng.int16)

a0p = ng.max_pool_serial(a0,
                         ksize=(1, 2, 2, 1),
                         strides=(1, 2, 2, 1))

a0r = ng.reshape(a0p, [batchsize, -1])

# layer 1: full-connection, relu
wn1 = ng.variable(weight_dtype,
                 shape=(100, a0r.shape[-1]),
                 name='wn1')
bn1 = ng.variable(bias_dtype,
                 shape=(wn1.shape[0],),
                 name='bn1')
sn1 = ng.variable(scale_dtype,
                 shape=(wn1.shape[0],),
                 name='sn1')

a1 = ng.matmul(a0r, wn1,
               bias=bn1,
               scale=sn1,
               transposed_b=True,
               act_func=ng.relu,
               dtype=act_dtype,
               sum_dtype=ng.int16)

# layer 2: full-connection, relu
wn2 = ng.variable(weight_dtype,
                 shape=(10, a1.shape[-1]),
                 name='wn2')
bn2 = ng.variable(bias_dtype,
                 shape=(wn2.shape[0],),
                 name='bn2')
sn2 = ng.variable(scale_dtype,
                 shape=(wn2.shape[0],),
                 name='sn2')

# output
output_layer = ng.matmul(a1, wn2,
                         bias=bn2,
                         scale=sn2,
                         transposed_b=True,
                         name='output_layer',
                         dtype=act_dtype,
                         sum_dtype=ng.int16)


NNgenのMIST CNNの重みやバイアスの配列の形状を確認する
NNgen2_48_210329.png

print(wn0.shape)
print(bn0.shape)
print(wn1.shape)
print(bn1.shape)
print(wn2.shape)
print(bn2.shape)
print(a0.shape)
print(a0p.shape)
print(a0r.shape)


「ゼロから作るDeep Learning」のMNIST CNNの重みやバイアスの配列の形状を見て、reshape transpose でNNgenに合わせる (2021/04/01 :修正)
NNgen2_49_210329.png

print(network.params['W1'].shape)
print(network.params['b1'].shape)
print(network.params['W2'].shape)
print(network.params['b2'].shape)
print(network.params['W3'].shape)
print(network.params['b3'].shape)

W1n = network.params['W1'].transpose(0,2,3,1)
print(W1n.shape)
print(np.max(W1n))
print(np.min(W1n))
B1n = network.params['b1']
print(np.max(B1n))
print(np.min(B1n))
W2n=network.params['W2'].transpose(1,0)
print(W2n.shape)
print(np.max(W2n))
print(np.min(W2n))
B2n = network.params['b2']
print(np.max(B2n))
print(np.min(B2n))
W3n=network.params['W3'].transpose(1,0)
print(W3n.shape)
print(np.max(W3n))
print(np.min(W3n))
B3n = network.params['b3']
print(np.max(B3n))
print(np.min(B3n))

  1. 2021年03月29日 04:43 |
  2. NNgen
  3. | トラックバック:0
  4. | コメント:0

「ゼロから作るDeep Learning」のCNNをNNgenでハードウェア化する1

前回の”「ゼロから作るDeep Learning」の2層ニューラルネットワークをNNgenでハードウェア化する2”の全結合層 2 層のニューラルネットワークの NNgen での書き方がよく分からないので、今回は CNN でやってみることにした。

2017年の 6 月にやってみたオライリー出版社の”「ゼロから作るDeep Learning」”の deep-learning-from-scratch/ch07/ の畳み込みニューラルネットワーク(CNN)を NNgen でハードウェア化してみることにした。
その CNN を FPGAの部屋に書いた時の記事は”「ゼロから作るDeep Learning」の畳み込みニューラルネットワークのハードウェア化1”だった。今回は、int8, int16 に寄せるということで、量子化ビット数を変更した。

AF_OUT_MAG = 2 ** 5 # 出力の小数部
AF_OUT_INT = 2 ** 11 # 出力の整数部(+符号1ビットされている)
AF_WB_MAG = 2 ** 7 # 重みとバイアスの小数部
AF_WB_INT = 2 ** 1 # 重みとバイアスの整数部(+符号1ビットされている)

COV_OUT_MAG = 2 ** 7 # 出力の小数部
COV_OUT_INT = 2 ** 9 # 出力の整数部(+符号1ビットされている)
COV_WB_MAG = 2 ** 7 # 重みとバイアスの小数部
COV_WB_INT = 2 ** 1 # 重みとバイアスの整数部(+符号1ビットされている)


オライリー出版社の”「ゼロから作るDeep Learning」”の deep-learning-from-scratch/ch07/から一部変更した layers_int.py を引用する。
NNgen2_42_210327.png

ネットワークの構成を示す。
畳み込みーReluーマックス・プーリングー全結合層ーReluー全結合層だ。
オライリー出版社の”「ゼロから作るDeep Learning」”の deep-learning-from-scratch/ch07/から一部変更した simple_convnet_int.py を引用する。
NNgen2_43_210327.png

Jupyter Notebook で学習を行った。
このコードもオライリー出版社の”「ゼロから作るDeep Learning」”の deep-learning-from-scratch/ch07/から一部変更した。
NNgen2_44_210328.png
NNgen2_45_210328.png

精度は 0.9877 だった。
  1. 2021年03月28日 06:56 |
  2. NNgen
  3. | トラックバック:0
  4. | コメント:0

「ゼロから作るDeep Learning」の2層ニューラルネットワークをNNgenでハードウェア化する2

2017年の 6 月にやってみたオライリー出版社の”「ゼロから作るDeep Learning」”の deep-learning-from-scratch/ch05/ を使用した MNIST の 全結合層2層のニューラルネットワークをやってみたことがある。(”「ゼロから作るDeep Learning」の2層ニューラルネットワークのハードウェア化1”参照) 今回、それを NNgen でハードウェア化してみたいということで、前回は、以前の”「ゼロから作るDeep Learning」の2層ニューラルネットワークのハードウェア化1”の 2 層全結合ニューラルネットワークを再びやってみた。今回は、”「ゼロから作るDeep Learning」の2層ニューラルネットワークのハードウェア化1”の 2 層全結合ニューラルネットワークをNNgenのオペレータを使ってMNISTの2層全結合ニューラルネットワークの実装を行った。まだ進捗が少ないが書いておく。

前回の”「ゼロから作るDeep Learning」の2層ニューラルネットワークのハードウェア化1”の 2 層全結合ニューラルネットワークは Ubuntu 18.04 を再起動してしまったので再学習した。結果を示す。

0.16073333333333334 0.1679
0.90385 0.908
0.9256 0.9275
0.9395666666666667 0.9399
0.9454666666666667 0.9456
0.9488333333333333 0.9487
0.9575166666666667 0.955
0.9614833333333334 0.9589
0.9640333333333333 0.9614
0.9659833333333333 0.9606
0.9692 0.9624
0.9713333333333334 0.965
0.97315 0.9664
0.9748 0.9688
0.9768333333333333 0.9693
0.9778833333333333 0.969
0.9779666666666667 0.9704

(60000, 784)
np.max(x) = 1.0
np.min(x) = 0.0
(784, 50)
np.max(self.W) = 0.3671875
np.min(self.W) = -0.5625
(50,)
np.max(self.b) = 0.296875
np.min(self.b) = -0.171875
(60000, 50)
np.max(out) = 12.23468143302307
np.min(out) = -13.189215710841381
np.max(out2) = 12.234375
np.min(out2) = -13.1796875
(60000, 50)
np.max(x) = 12.234375
np.min(x) = 0.0
(50, 10)
np.max(self.W) = 0.9921875
np.min(self.W) = -1.0
(10,)
np.max(self.b) = 0.453125
np.min(self.b) = -0.3203125
(60000, 10)
np.max(out) = 29.58172607421875
np.min(out) = -25.99884033203125
np.max(out2) = 29.578125
np.min(out2) = -25.9921875
(10000, 784)
np.max(x) = 1.0
np.min(x) = 0.0
(784, 50)
np.max(self.W) = 0.3671875
np.min(self.W) = -0.5546875
(50,)
np.max(self.b) = 0.296875
np.min(self.b) = -0.1640625
(10000, 50)
np.max(out) = 12.447242664638907
np.min(out) = -10.870925284420082
np.max(out2) = 12.4453125
np.min(out2) = -10.859375
(10000, 50)
np.max(x) = 12.4453125
np.min(x) = 0.0
(50, 10)
np.max(self.W) = 0.9921875
np.min(self.W) = -0.9921875
(10,)
np.max(self.b) = 0.453125
np.min(self.b) = -0.3125
(10000, 10)
np.max(out) = 30.97119140625
np.min(out) = -24.920166015625
np.max(out2) = 30.96875
np.min(out2) = -24.9140625
0.9736166666666667 0.9559


今回の精度は 0.9559 で少し精度が上がった。

2 層全結合ニューラルネットワークをNNgenのオペレータを使ってMNISTの2層全結合ニューラルネットワークの実装を行った。そのソースコードを示す。
なお、このコードは、hello_nngen.py のコードを変更して作成した。

from __future__ import absolute_import
from __future__ import print_function

import sys
import os

import nngen as ng


# data types
act_dtype = ng.int8
weight_dtype = ng.int8
bias_dtype = ng.int8
scale_dtype = ng.int16

# input
input_layer = ng.placeholder(dtype=act_dtype,
                             shape=(1, 28, 28, 1),  # N, H, W, C
                             name='input_layer')

# layer 1: full-connection, relu
w_ng1 = ng.variable(weight_dtype,
                 shape=(784, input_layer.shape[-1]),
                 name='w_ng1')
b_ng1 = ng.variable(bias_dtype,
                 shape=(w_ng1.shape[0],),
                 name='b_ng1')
s_ng1 = ng.variable(scale_dtype,
                 shape=(w_ng1.shape[0],),
                 name='s_ng1')

a1 = ng.matmul(input_layer, w_ng1,
               bias=b_ng1,
               scale=s_ng1,
               transposed_b=True,
               act_func=ng.relu,
               sum_dtype=ng.int16)

# layer 2: full-connection, relu
w_ng2 = ng.variable(weight_dtype,
                 shape=(10, a1.shape[-1]),
                 name='w_ng2')
b_ng2 = ng.variable(bias_dtype,
                 shape=(w_ng2.shape[0],),
                 name='b_ng2')
s_ng2 = ng.variable(scale_dtype,
                 shape=(w_ng2.shape[0],),
                 name='s_ng2')

# output
output_layer = ng.matmul(a1, w_ng2,
                         bias=b_ng2,
                         scale=s_ng2,
                         transposed_b=True,
                         name='output_layer',
                         sum_dtype=ng.int16)


(2021/03/28:追記)
上の NNgen の書き方は間違っているようです。
全結合層スタートのニューラルネットワークの NNgen での書き方がよく分からないので、CNN でやってみることにしました。
  1. 2021年03月26日 05:12 |
  2. NNgen
  3. | トラックバック:0
  4. | コメント:0
»