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

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

FPGAの部屋

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

Anaconda でインストールしたJupyter Notebookを任意のフォルダから実行する方法

Windows 10 の Anaconda でインストールしたJupyter Notebookを任意のフォルダから実行したい。特に C: ドライブにSSD が入っているとあまり容量に余裕がない場合は、D: ドライブで思う存分、学習用の画像ファイルを扱いたい(GBオーダーの容量を必要とするため)。という欲求があるので、C: ドライブじゃないところから起動したい。

PowerShell を立ち上げて jupyter notebook で起動するとKeras が使えなかった。

Jupyter Notebook のプロパティを立ち上げると、リンク先が

D:\Anaconda3\python.exe D:\Anaconda3\cwp.py D:\Anaconda3 D:\Anaconda3\python.exe D:\Anaconda3\Scripts\jupyter-notebook-script.py %USERPROFILE%

になっていた。
Anaconda_d_drive_1_181019.png

C:\Users\<ユーザー名>フォルダに jupyter-notebook_d.bat を作った。
jupyter-notebook_d.bat の中身を示す。

D:\Anaconda3\python.exe D:\Anaconda3\cwp.py D:\Anaconda3 D:\Anaconda3\python.exe D:\Anaconda3\Scripts\jupyter-notebook-script.py D:\User


これをPowerShell で起動すれば、Jupyter Notebook で、D:\User から表示された。
Anaconda_d_drive_3_181019.png

これで、Windows 10 の Anaconda でインストールしたJupyter Notebookを任意のフォルダから実行することができる。
  1. 2018年10月19日 12:50 |
  2. DNN
  3. | トラックバック:0
  4. | コメント:0

トランジスタ技術2018年11月号に記事を書きました

トランジスタ技術2018年11月号「第4章 MNIST向け固定小数点CNNの設計から,各種シミュレーション,実装まで 手書き数字認識用FPGAニューラル・ネットワーク・システムの製作」という記事を書きました。

MNIST を推論する畳み込みニューラル・ネットワークをFPGA で作ったという記事です。28 x 28 ピクセルの四角枠をキーボードで動かして、中に収めた手書き数字を判定するという回路です。ZYBO Z7-20 に実装しました。
ただし、カメラのMT9D111メガピクセルカメラモジュールが在庫切れです。
FPGAの部屋のブログの「2 Mega pixel Camera Module MT9D111 JPEG Out + HQ lens」2 Mega pixel Camera Module MT9D111 JPEG Out + HQ lensは在庫があるようです。

なお、第1章から第3章まではなひたふさんが記事を書かれていて、SDSoC を使ったニューラル・ネットワークの実装の記事もありますので、とてもおもしろいと思います。

Vivado HLSのソースコードがDVDに搭載されていませんでしたので、私のGitHubに上げておきました。
「トランジスタ技術2018年11月号の第4章「手書き数字認識用FPGAニューラル・ネットワーク・システムの製作」のVivado HLSのソースコードです」
よろしくお願いいたします。
  1. 2018年10月14日 04:58 |
  2. DNN
  3. | トラックバック:0
  4. | コメント:0

SqueezeNet for MNIST で層の数を減らして、各層の出力をC のヘッダに出力

今まで SqueezeNet for MNIST をやってきたが、MNIST の手書き数字の分類を行うのにフルのSqueezeNet は大きすぎると思う。
そこで、SqueezeNet の特徴を残しながら、fire 層を 1 層にしたモデルをやってみた。

それとこれが重要なのだが、私は、Vivado HLS で畳み込み層などをC++ で独自に書く訳なのだが、そのコードが正しいという確証が現在、どこからも得られないという問題がある。これは重要な問題で、ニューラルネットワークはロバスト性がありすぎて、途中でコードが間違っていても、あまり結果が変わらないことがよくある。コレを解消するためにKeras で最初の1個のデータだけだが、各層の出力をヘッダとして出力するPython コードを開発した。このデータを使用して、自分で作ったC++ コードの出力するデータと比較することができる。
Jupyter Notebook のファイル名は、squeezenet4mnist2.ipynb

# SqueezeNet for MNIST
https://www.kaggle.com/somshubramajumdar/squeezenet-for-mnist
(Apache License 2.0)を引用してKeras 2に変更し独自のコードを加えた by marsee


```python
# 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 = 10

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(20, (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(10, (1, 1), padding="same", kernel_initializer="glorot_uniform")(maxpool1)
relu2_squeeze = Activation(activation='relu')(fire2_squeeze)

fire2_expand1 = Conv2D(10, (1, 1), padding="same", kernel_initializer="glorot_uniform")(relu2_squeeze)
relu2_expand1 = Activation(activation='relu')(fire2_expand1)
fire2_expand2 = Conv2D(10, (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)

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

# 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))
```

    Using TensorFlow backend.


    x_train shape: (60000, 28, 28, 1)
    60000 train samples
    10000 test samples
    Train on 60000 samples, validate on 10000 samples
    Epoch 1/10
    60000/60000 [==============================] - 8s 128us/step - loss: 0.4393 - acc: 0.8600 - val_loss: 0.1674 - val_acc: 0.9492
    Epoch 2/10
    60000/60000 [==============================] - 7s 118us/step - loss: 0.1489 - acc: 0.9546 - val_loss: 0.1089 - val_acc: 0.9657
    Epoch 3/10
    60000/60000 [==============================] - 7s 118us/step - loss: 0.1123 - acc: 0.9660 - val_loss: 0.0884 - val_acc: 0.9727
    Epoch 4/10
    60000/60000 [==============================] - 7s 118us/step - loss: 0.0940 - acc: 0.9708 - val_loss: 0.0787 - val_acc: 0.9742
    Epoch 5/10
    60000/60000 [==============================] - 7s 120us/step - loss: 0.0820 - acc: 0.9753 - val_loss: 0.0665 - val_acc: 0.9794
    Epoch 6/10
    60000/60000 [==============================] - 7s 118us/step - loss: 0.0745 - acc: 0.9772 - val_loss: 0.0605 - val_acc: 0.9806
    Epoch 7/10
    60000/60000 [==============================] - 7s 119us/step - loss: 0.0689 - acc: 0.9793 - val_loss: 0.0637 - val_acc: 0.9816
    Epoch 8/10
    60000/60000 [==============================] - 7s 118us/step - loss: 0.0643 - acc: 0.9803 - val_loss: 0.0585 - val_acc: 0.9813
    Epoch 9/10
    60000/60000 [==============================] - 7s 117us/step - loss: 0.0600 - acc: 0.9814 - val_loss: 0.0569 - val_acc: 0.9809
    Epoch 10/10
    60000/60000 [==============================] - 7s 120us/step - loss: 0.0574 - acc: 0.9819 - val_loss: 0.0540 - val_acc: 0.9825



```python
# Keras / Tensorflowで始めるディープラーニング入門 https://qiita.com/yampy/items/706d44417c433e68db0d
# のPythonコードを再利用させて頂いている

%matplotlib inline
import pandas as pd
import matplotlib.pyplot as plt

plt.plot(history.history['acc'])
plt.plot(history.history['val_acc'])
plt.title('model accuracy')
plt.ylabel('accuracy')
plt.xlabel('epoch')
plt.legend(['train', 'test'], loc='upper left')
plt.show()

# plot the loss
plt.plot(history.history['loss'])
plt.plot(history.history['val_loss'])
plt.title('model loss')
plt.ylabel('loss')
plt.xlabel('epoch')
plt.legend(['train', 'test'], loc='upper left')
plt.show()
```

SqNet_181013_output_2_0.png SqNet_181013_output_2_1.png 


```python
# 学習済みモデルの保存

from keras.models import load_model

model.save('squeezenet4mnist_model.h5')  # creates a HDF5 file 'my_model.h5'
```


```python
# 学習済みモデルの読み込み

from keras.models import load_model

model = load_model('squeezenet4mnist_model.h5')
```

    Using TensorFlow backend.



```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 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)
```

    x_train shape: (60000, 28, 28, 1)
    60000 train samples
    10000 test samples



```python
model.summary()
```

    __________________________________________________________________________________________________
    Layer (type)                    Output Shape         Param #     Connected to                     
    ==================================================================================================
    input (InputLayer)              (None, 28, 28, 1)    0                                            
    __________________________________________________________________________________________________
    conv2d_1 (Conv2D)               (None, 13, 13, 20)   200         input[0][0]                      
    __________________________________________________________________________________________________
    activation_1 (Activation)       (None, 13, 13, 20)   0           conv2d_1[0][0]                   
    __________________________________________________________________________________________________
    max_pooling2d_1 (MaxPooling2D)  (None, 6, 6, 20)     0           activation_1[0][0]               
    __________________________________________________________________________________________________
    conv2d_2 (Conv2D)               (None, 6, 6, 10)     210         max_pooling2d_1[0][0]            
    __________________________________________________________________________________________________
    activation_2 (Activation)       (None, 6, 6, 10)     0           conv2d_2[0][0]                   
    __________________________________________________________________________________________________
    conv2d_3 (Conv2D)               (None, 6, 6, 10)     110         activation_2[0][0]               
    __________________________________________________________________________________________________
    conv2d_4 (Conv2D)               (None, 6, 6, 10)     910         activation_2[0][0]               
    __________________________________________________________________________________________________
    activation_3 (Activation)       (None, 6, 6, 10)     0           conv2d_3[0][0]                   
    __________________________________________________________________________________________________
    activation_4 (Activation)       (None, 6, 6, 10)     0           conv2d_4[0][0]                   
    __________________________________________________________________________________________________
    concatenate_1 (Concatenate)     (None, 6, 6, 20)     0           activation_3[0][0]               
                                                                     activation_4[0][0]               
    __________________________________________________________________________________________________
    activation_5 (Activation)       (None, 6, 6, 20)     0           concatenate_1[0][0]              
    __________________________________________________________________________________________________
    conv2d_5 (Conv2D)               (None, 6, 6, 10)     210         activation_5[0][0]               
    __________________________________________________________________________________________________
    flatten_1 (Flatten)             (None, 360)          0           conv2d_5[0][0]                   
    __________________________________________________________________________________________________
    dense_1 (Dense)                 (None, 10)           3610        flatten_1[0][0]                  
    ==================================================================================================
    Total params: 5,250
    Trainable params: 5,250
    Non-trainable params: 0
    __________________________________________________________________________________________________



```python
# 畳み込み層の重みをCヘッダファイルに書き出す
# 2018/05/31 by marsee

def fwrite_conv_weight(weight, wfile_name, float_wt_name, fixed_wt_name, MAGNIFICATION):
    import datetime
    import numpy as np
    
    f = open(wfile_name, 'w')
    todaytime = datetime.datetime.today()
    f.write('// '+wfile_name+'\n')
    strdtime = todaytime.strftime("%Y/%m/%d %H:%M:%S")
    f.write('// {0} by marsee\n'.format(strdtime))
    f.write("\n")
    
    f.write('const float '+float_wt_name+'['+str(weight.shape[0])+']['+str(weight.shape[1])+']['+str(weight.shape[2])+']['+str(weight.shape[3])+'] = \n{\n')
    for i in range(weight.shape[0]):
        f.write("\t{\n")
        for j in range(weight.shape[1]):
            f.write("\t\t{\n")
            for k in range(weight.shape[2]):
                f.write("\t\t\t{")
                for m in range(weight.shape[3]):
                    f.write(str(weight[i][j][k][m]))
                    if (m==weight.shape[3]-1):
                        f.write("}")
                    else:
                        f.write(",")
                
                if (k==weight.shape[2]-1):
                    f.write("\n\t\t}\n")
                else:
                    f.write(",\n")

            if (j==weight.shape[1]-1):
                f.write("\t}\n")
            else:
                f.write(",\n")
        
        
        if (i==weight.shape[0]-1):
            f.write("};\n")
        else:
            f.write("\t,\n")

    f.write("\n")
    f.write('const ap_fixed<'+str(int(np.log2(MAGNIFICATION))+1)+', 1, AP_TRN, AP_WRAP> '+fixed_wt_name+'['+str(weight.shape[0])+']['+str(weight.shape[1])+']['+str(weight.shape[2])+']['+str(weight.shape[3])+'] = \n{\n')
    for i in range(weight.shape[0]):
        f.write("\t{\n")
        for j in range(weight.shape[1]):
            f.write("\t\t{\n")
            for k in range(weight.shape[2]):
                f.write("\t\t\t{")
                for m in range(weight.shape[3]):
                    w_int = int(weight[i][j][k][m]*MAGNIFICATION+0.5)
                    if (w_int > MAGNIFICATION-1):
                        w_int = MAGNIFICATION-1
                    elif (w_int < -MAGNIFICATION):
                        w_int = -MAGNIFICATION
                    f.write(str(float(w_int)/float(MAGNIFICATION)))
                    if (m==weight.shape[3]-1):
                        f.write("}")
                    else:
                        f.write(",")
                
                if (k==weight.shape[2]-1):
                    f.write("\n\t\t}\n")
                else:
                     f.write(",\n")

            if (j==weight.shape[1]-1):
                f.write("\t}\n")
            else:
                f.write(",\n")
        
        
        if (i==weight.shape[0]-1):
            f.write("};\n")
        else:
            f.write("\t,\n")
 
    f.close()
```


```python
# 畳み込み層と全結合層のバイアスをCヘッダファイルに書き出す
# 2018/05/31 by marsee

def fwrite_bias(bias, wfile_name, float_b_name, fixed_wt_name, MAGNIFICATION):
    import datetime
    import numpy as np
    
    f = open(wfile_name, 'w')
    todaytime = datetime.datetime.today()
    f.write('// '+wfile_name+'\n')
    strdtime = todaytime.strftime("%Y/%m/%d %H:%M:%S")
    f.write('// {0} by marsee\n'.format(strdtime))
    f.write("\n")

    f.write('const float '+float_b_name+'['+str(bias.shape[0])+'] = {\n\t')
    for i in range(bias.shape[0]):
        f.write(str(bias[i]))
        if (i < bias.shape[0]-1):
            f.write(", ")
    f.write("\n};\n")

    f.write("\n")
    f.write('const ap_fixed<'+str(int(np.log2(MAGNIFICATION))+1)+', 1, AP_TRN, AP_WRAP> '+fixed_wt_name+'['+str(bias.shape[0])+'] = {\n\t')
    for i in range(bias.shape[0]):
        b_int = int(bias[i]*MAGNIFICATION+0.5)
        if (b_int > MAGNIFICATION-1):
            b_int = MAGNIFICATION-1
        elif (b_int < -MAGNIFICATION):
            b_int = -MAGNIFICATION
        f.write(str(float(b_int)/float(MAGNIFICATION)))
        if (i < bias.shape[0]-1):
            f.write(", ")
    f.write("\n};\n")

    f.close()
```


```python
# 層のデータを取得してCのヘッダ・ファイルに出力する(float)
# 2018/09/20 by marsee

def fwrite_layer_output(layer_out, wfile_name, layer_output_name):
    import datetime
    import numpy as np
    
    f = open(wfile_name, 'w')
    todaytime = datetime.datetime.today()
    f.write('// '+wfile_name+'\n')
    strdtime = todaytime.strftime("%Y/%m/%d %H:%M:%S")
    f.write('// {0} by marsee\n'.format(strdtime))
    f.write("\n")
    
    f.write('const float '+layer_output_name+'['+str(layer_out.shape[0])+']['+str(layer_out.shape[1])+']['+str(layer_out.shape[2])+']['+str(layer_out.shape[3])+'] = \n{\n')
    for i in range(layer_out.shape[0]):
        f.write("\t{\n")
        for j in range(layer_out.shape[1]):
            f.write("\t\t{\n")
            for k in range(layer_out.shape[2]):
                f.write("\t\t\t{")
                for m in range(layer_out.shape[3]):
                    f.write(str(layer_out[i][j][k][m]))
                    if (m==layer_out.shape[3]-1):
                        f.write("}")
                    else:
                        f.write(",")
                
                if (k==layer_out.shape[2]-1):
                    f.write("\n\t\t}\n")
                else:
                    f.write(",\n")

            if (j==layer_out.shape[1]-1):
                f.write("\t}\n")
            else:
                f.write(",\n")
        
        
        if (i==layer_out.shape[0]-1):
            f.write("};\n")
        else:
            f.write("\t,\n")

    f.write("\n")
    f.close()
```


```python
# 層の出力データを取得する(conv2d_1だけのテスト用)
from keras.models import Model

conv_layer_name = 'conv2d_1'

conv_layer = model.get_layer(conv_layer_name)
conv_layer_wb = conv_layer.get_weights()

conv_layer_model = Model(inputs=model.input,
                                 outputs=model.get_layer(conv_layer_name).output)
x_test_limit = x_test[:1]
y_test_limit = y_test[:10]
print(y_test_limit)
conv_output = conv_layer_model.predict(x_test_limit, verbose=1)
print(conv_output.shape)
fwrite_layer_output(conv_output, 'conv2d_1_output.h', 'conv2d_1_output')
```

    [[0. 0. 0. 0. 0. 0. 0. 1. 0. 0.]
     [0. 0. 1. 0. 0. 0. 0. 0. 0. 0.]
     [0. 1. 0. 0. 0. 0. 0. 0. 0. 0.]
     [1. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
     [0. 0. 0. 0. 1. 0. 0. 0. 0. 0.]
     [0. 1. 0. 0. 0. 0. 0. 0. 0. 0.]
     [0. 0. 0. 0. 1. 0. 0. 0. 0. 0.]
     [0. 0. 0. 0. 0. 0. 0. 0. 0. 1.]
     [0. 0. 0. 0. 0. 1. 0. 0. 0. 0.]
     [0. 0. 0. 0. 0. 0. 0. 0. 0. 1.]]
    1/1 [==============================] - 0s 74ms/step
    (1, 13, 13, 20)


# 層の統計情報


```python
# Convolution layerの中間出力を取り出す 
from keras.models import Model
import numpy as np

x_test_limit = x_test[:1]
for num in range(1, 6):
    conv_layer_name = 'conv2d_' + str(num)

    conv_layer = model.get_layer(conv_layer_name)
    conv_layer_wb = conv_layer.get_weights()

    conv_layer_model = Model(inputs=model.input,
                                     outputs=model.get_layer(conv_layer_name).output)
    conv_output = conv_layer_model.predict(x_test, verbose=1)

    conv_layer_weight = conv_layer_wb[0]
    conv_layer_bias = conv_layer_wb[1]

    print(conv_layer_name)
    print(conv_layer_weight.shape)
    print(conv_layer_weight.transpose(3,2,0,1).shape)
    print(conv_layer_bias.shape)
    print(conv_output.shape)

    print("np.max(conv_layer_weight) = {0}".format(np.max(conv_layer_weight)))
    print("np.min(conv_layer_weight) = {0}".format(np.min(conv_layer_weight))) 
    abs_conv_layer_weight = np.absolute(conv_layer_weight)
    print("np.max(abs_conv_layer_weight) = {0}".format(np.max(abs_conv_layer_weight)))
    print("np.min(abs_conv_layer_weight) = {0}".format(np.min(abs_conv_layer_weight))) 

    print("np.max(conv_layer_bias) = {0}".format(np.max(conv_layer_bias)))
    print("np.min(conv_layer_bias) = {0}".format(np.min(conv_layer_bias))) 
    abs_conv_layer_bias = np.absolute(conv_layer_bias)
    print("np.max(abs_conv_layer_bias) = {0}".format(np.max(abs_conv_layer_bias)))
    print("np.min(abs_conv_layer_bias) = {0}".format(np.min(abs_conv_layer_bias))) 

    print("conv_output = {0}".format(conv_output.shape))
    print("np.std(conv_output) = {0}".format(np.std(conv_output)))
    print("np.max(conv_output) = {0}".format(np.max(conv_output)))
    print("np.min(conv_output) = {0}".format(np.min(conv_output))) 

    abs_conv_output = np.absolute(conv_output)
    print("np.max(abs_conv) = {0}".format(np.max(abs_conv_output)))
    print("np.min(abs_conv) = {0}".format(np.min(abs_conv_output))) 
    print("")
    
    # 2018/06/05 修正 畳み込み層の重みの配列は(カーネルサイズh,カーネルサイズw, 入力チャネル, 出力チャネル)ということなので、Pythonコードを修正した。@NORA__0013 さんありがとうございました。

    MAGNIFICATION_CONV = 2 ** (9-1)
    fwrite_conv_weight(conv_layer_weight.transpose(3,2,0,1), 'conv'+str(num)+'_weight.h', 'conv'+str(num)+'_fweight', 'conv'+str(num)+'_weight', MAGNIFICATION_CONV)

    fwrite_bias(conv_layer_bias, 'conv'+str(num)+'_bias.h', 'conv'+str(num)+'_fbias', 'conv'+str(num)+'_bias', MAGNIFICATION_CONV)
    
    conv_output = conv_layer_model.predict(x_test_limit, verbose=1)
    fwrite_layer_output(conv_output, 'conv'+str(num)+'_output.h', 'conv'+str(num)+'output')
```

    10000/10000 [==============================] - 0s 38us/step
    conv2d_1
    (3, 3, 1, 20)
    (20, 1, 3, 3)
    (20,)
    (10000, 13, 13, 20)
    np.max(conv_layer_weight) = 0.4946177303791046
    np.min(conv_layer_weight) = -0.5343244671821594
    np.max(abs_conv_layer_weight) = 0.5343244671821594
    np.min(abs_conv_layer_weight) = 0.00023465760750696063
    np.max(conv_layer_bias) = 0.057732950896024704
    np.min(conv_layer_bias) = -0.08072157949209213
    np.max(abs_conv_layer_bias) = 0.08072157949209213
    np.min(abs_conv_layer_bias) = 2.5581393856555223e-05
    conv_output = (10000, 13, 13, 20)
    np.std(conv_output) = 0.303703248500824
    np.max(conv_output) = 1.8376622200012207
    np.min(conv_output) = -1.7203431129455566
    np.max(abs_conv) = 1.8376622200012207
    np.min(abs_conv) = 4.842877388000488e-08
    
    1/1 [==============================] - 0s 0us/step
    10000/10000 [==============================] - 0s 40us/step
    conv2d_2
    (1, 1, 20, 10)
    (10, 20, 1, 1)
    (10,)
    (10000, 6, 6, 10)
    np.max(conv_layer_weight) = 0.913070023059845
    np.min(conv_layer_weight) = -0.9718273878097534
    np.max(abs_conv_layer_weight) = 0.9718273878097534
    np.min(abs_conv_layer_weight) = 0.0080069899559021
    np.max(conv_layer_bias) = 0.10839419811964035
    np.min(conv_layer_bias) = -0.04171771556138992
    np.max(abs_conv_layer_bias) = 0.10839419811964035
    np.min(abs_conv_layer_bias) = 0.010898223146796227
    conv_output = (10000, 6, 6, 10)
    np.std(conv_output) = 0.9102568626403809
    np.max(conv_output) = 4.971376895904541
    np.min(conv_output) = -2.940309762954712
    np.max(abs_conv) = 4.971376895904541
    np.min(abs_conv) = 1.1175870895385742e-08
    
    1/1 [==============================] - 0s 0us/step
    10000/10000 [==============================] - 0s 44us/step
    conv2d_3
    (1, 1, 10, 10)
    (10, 10, 1, 1)
    (10,)
    (10000, 6, 6, 10)
    np.max(conv_layer_weight) = 0.8710610270500183
    np.min(conv_layer_weight) = -0.6806471347808838
    np.max(abs_conv_layer_weight) = 0.8710610270500183
    np.min(abs_conv_layer_weight) = 0.0008496924419887364
    np.max(conv_layer_bias) = 0.1616363525390625
    np.min(conv_layer_bias) = -0.11668514460325241
    np.max(abs_conv_layer_bias) = 0.1616363525390625
    np.min(abs_conv_layer_bias) = 0.0003539775207173079
    conv_output = (10000, 6, 6, 10)
    np.std(conv_output) = 1.006908655166626
    np.max(conv_output) = 4.752679347991943
    np.min(conv_output) = -3.4257307052612305
    np.max(abs_conv) = 4.752679347991943
    np.min(abs_conv) = 2.9848888516426086e-07
    
    1/1 [==============================] - 0s 999us/step
    10000/10000 [==============================] - 1s 56us/step
    conv2d_4
    (3, 3, 10, 10)
    (10, 10, 3, 3)
    (10,)
    (10000, 6, 6, 10)
    np.max(conv_layer_weight) = 0.6119384765625
    np.min(conv_layer_weight) = -0.6267021894454956
    np.max(abs_conv_layer_weight) = 0.6267021894454956
    np.min(abs_conv_layer_weight) = 0.000530939141754061
    np.max(conv_layer_bias) = 0.09105820208787918
    np.min(conv_layer_bias) = -0.13521511852741241
    np.max(abs_conv_layer_bias) = 0.13521511852741241
    np.min(abs_conv_layer_bias) = 0.000247095333179459
    conv_output = (10000, 6, 6, 10)
    np.std(conv_output) = 1.4005329608917236
    np.max(conv_output) = 7.894415378570557
    np.min(conv_output) = -7.611080169677734
    np.max(abs_conv) = 7.894415378570557
    np.min(abs_conv) = 6.484333425760269e-08
    
    1/1 [==============================] - 0s 0us/step
    10000/10000 [==============================] - 1s 63us/step
    conv2d_5
    (1, 1, 20, 10)
    (10, 20, 1, 1)
    (10,)
    (10000, 6, 6, 10)
    np.max(conv_layer_weight) = 1.1239129304885864
    np.min(conv_layer_weight) = -0.9796998500823975
    np.max(abs_conv_layer_weight) = 1.1239129304885864
    np.min(abs_conv_layer_weight) = 0.0004102856619283557
    np.max(conv_layer_bias) = 0.3322758972644806
    np.min(conv_layer_bias) = -0.23224467039108276
    np.max(abs_conv_layer_bias) = 0.3322758972644806
    np.min(abs_conv_layer_bias) = 0.021110178902745247
    conv_output = (10000, 6, 6, 10)
    np.std(conv_output) = 1.4941357374191284
    np.max(conv_output) = 9.327534675598145
    np.min(conv_output) = -11.037702560424805
    np.max(abs_conv) = 11.037702560424805
    np.min(abs_conv) = 1.5832483768463135e-07
    
    1/1 [==============================] - 0s 999us/step



DNN/Keras/squeezenet4mnist2 ディレクトリの内容を示す。層ごとの出力ファイルの conv?_output.h ができているのが分かる。
squeezenet_69_181013.png

1層目の出力ファイルの conv1_output.h の一部を示す。
squeezenet_70_181013.png
  1. 2018年10月13日 06:55 |
  2. DNN
  3. | トラックバック:0
  4. | コメント:0

icrawler で学習用画像を収集する

機械学習用の画像を集めるのにicrawlerが便利だった”で icrawler を使って学習用画像を収集していたが、なかなかうまく行かなかったので、顛末を書く。

icrawler のインストールはAnaconda の場合は、conda でインストール出来て、そちらはWindows だったが、動作して問題なかった。
pip の場合は、
pip install icrawler
でインストールを行った。
cralwer_1_180929.png
cralwer_2_180929.png

機械学習用の画像を集めるのにicrawlerが便利だった”のコードを少し変えて試してみたが、"Couldn't find a tree builder with the features you requested: lxml."というエラーだった。
cralwer_3_180929.png

色々と調べたところ、”BeautifulSoup4でlxmlが使えない”で、

lxmlのバージョンを3.7.3まで下げるとエラーは消えます。(3.8.0だとNG)

ということだったので、lxml の 3.7.3 をインストールした。
sudo pip install 'lxml==3.7.3'
cralwer_5_180929.png

cralwer_6_180929.png

これで、icrawler を動作させると動いた。
cralwer_4_180929.png

もう一度、
sudo pip install 'lxml==4.2.5'
で戻しても動作したのはなぜだろうか?

icrawler でグーグルを使って収集した猫の写真を示す。
cralwer_7_180929.png
  1. 2018年09月29日 11:40 |
  2. DNN
  3. | トラックバック:0
  4. | コメント:0

SqueezeNet for MNIST のVivado HLS での試行3

SqueezeNet for MNIST のVivado HLS での試行2”の続き。

前回はSqueezeNet for MNISTで、どのくらいのリソースが必要なのかを探ってみようということで、C コードの合成を行って、結果を調べた。今回は、Vivado synthesis, place and route にチェックを入れてExport RTL を行い、合成結果と比較した。

Vivado synthesis, place and route にチェックを入れて、Vivado 2017.4 のインプリメンテーションを行って、レポートを確認した。結果を示す。
squeezenet_vhls_12_180908.png

その結果は LUT が 26930 個で、FF が 30836 個、DSP が 194 個、BRAM が 3 個だった。
CP achieved post-implementation は 10.283 ns だった。

C コードの合成時のレポートを示す。
squeezenet_vhls_2_180906.png

まずは、BRAM 3 個と DSP 194 個は変化が無い。FF はC コードの合成時が 33233 個に対して、Vivado 合成時には 30836 個だった。Vivado 合成時の使用率のパーセンテージは、約 29 % だった。C コードの合成時が 31 % だったので、それほどの変更はない。
LUT はどうかというと、C コードの合成時には、66650 個で、Vivado 合成時には、26930 個だった。Vivado 合成時のパーセンテージは、約 51 % だった。C コードの合成時には、125 % だったので、大幅に低下して実装可能となった。
しかし、これだけでは SqueezeNet のほんの一部分しか実装できていないので、無理そうだ。

次回は、今はチャネル数分の幅のHLS ストリームを使用しているが、チャネルの幅を変更できるように、すでにテンプレートを書き換えてあるので、それについてブログに書いてみたい。
  1. 2018年09月08日 06:43 |
  2. DNN
  3. | トラックバック:0
  4. | コメント:0

SqueezeNet for MNIST のVivado HLS での試行2

SqueezeNet for MNIST のVivado HLS での試行1”の続き。

SqueezeNet for MNIST 3(層の統計情報とC ヘッダ・ファイルへの出力)”で層の統計情報と重みやバイアスの C ヘッダ・ファイルを出力したので、それらを使用して、SqueezeNet for MNISTで、どのくらいのリソースが必要なのかを探ってみようということで、前回はソースコードを示した。今回はC コードの合成結果を示す。

さて、都合(reVISION-ZYBO-Z7-20 を動かす関係上)により、Vivado HLS 2017.4 で合成した時の結果を示す。
squeezenet_vhls_2_180906.png

Estimated は 11.46 ns で Target の 10.00 ns をオーバーしている。
Latency は 63527 クロックだった。
Instance は conv_layer1_U0 、 max_pooling_U0 、 relu_conv1_U0 のインスタンスがある。
リソース使用量は BRAM_18K が 3 個、DSP48E が 194 個、FF が 33233 個、LUT が 66650 個だった。
LUT が 125 % でオーバーしている。やはり、出力ストームの 96 チャネルを並列に計算しているので、リソースが足りない。

次に、Instance の conv_layer1_U0 をクリックして、畳み込み層の合成結果を見てみよう。
squeezenet_vhls_3_180906.png

Estimated は 11.46 ns で畳み込み層が全体の足を引っ張っていることがわかる。
ここでのLatency は 63527 クロックで、全体のレイテンシと同じだ。
BRAM_18K は 1 個、 DSP48E は 194 個、FF は 14752 個、 FF は 37433 個使用している。
FF は全体の 70 % を使用している。

次に conv_layer_template.h のリソース使用量を確認するために、Detail -> Instance の grp_conv_layer_template_fu_1426 をクリックした。
squeezenet_vhls_4_180906.png

Latency は 63526 クロックだった。
Detail -> Loop を見ると、Loop_y_Loop_pix_mat_nd の Initiation Interval の achieved が 81 クロックで Target の 1 から大きくかけ離れている。
やはり、96 Channel を一度に実装するのは無理があるようだ。
BRAM_18K は 1 個、 DSP48E は 194 個、FF は 14747 個、 FF は 36483 個使用している。

最初のレポートに戻って、max_pooling_U0 をクリックした。今度はマックス・プーリングを見ていこう。
squeezenet_vhls_8_180907.png

こちらのEstimated は 6.89 ns だった。これは要求を満たしている。
Latency は 16278 クロックだった。
リソース使用量は、BRAM_18K は 1 個、 DSP48E は 0 個、FF は 8986 個、 FF は 13993 個使用している。
マックス・プーリングも結構リソースを消費している。

max_pooling_template.h の状況を見るために grp_max_pooling_template_fu_2756 を見ていこう。
squeezenet_vhls_9_180907.png

Detail -> Loop を見ると、Loop1 の Initiation Interval の achieved が 48 クロックで、Loop2_Loop3 のそれが、96 クロックだった。Loop2_Loop3 は チャネルごとにシリアライズされている感じだ。

最後に、最初のレポートに戻って、relu_conv1_U0 をクリックして見てみよう。
squeezenet_vhls_10_180907.png

Estimated は 6.89 ns だった。
Latency は 16445 クロックで、マックス・プーリングよりも使用クロック数が少し多い。
リソース使用量は、BRAM_18K が 1 個、DSP48E が 0 個、FF が 8447 個、LUT が 10632 個使用してる。

relu_template.h のリソース使用量を確認するために、Detail -> Instance の grp_relu_template_fu_2756 をクリックした。
squeezenet_vhls_11_180907.png

Detail -> Loop を見ると、Loop1 の Initiation Interval の achieved が 48 クロックで、Loop2_Loop3 のそれが、97 クロックだった。こちらの Loop2_Loop3 もチャネルごとにシリアライズされている感じだ。

C コードの合成結果からは、SqueezeNet for MNIST の 96 チャネル並列演算でZYBO Z7-20 では使い物にならないことが分かった。リソース使用量が大きすぎる。
だが、テンプレートを使用するとVivado HLS はリソース使用量の見積もりが甘くなることはすでに経験済みだ。よって、次回はExport RTL をやってみて、どのくらいの変化があるかを検証してみよう。
  1. 2018年09月07日 07:08 |
  2. DNN
  3. | トラックバック:0
  4. | コメント:0

SqueezeNet for MNIST のVivado HLS での試行1

SqueezeNet for MNIST 3(層の統計情報とC ヘッダ・ファイルへの出力)”で層の統計情報と重みやバイアスの C ヘッダ・ファイルを出力したので、それらを使用して、SqueezeNet for MNISTで、どのくらいのリソースが必要なのかを探ってみた。
とりあえずは、層の内の第1層目の畳み込み層、ReLU, MaxPooling の 3 つを実装してみよう。
なお、実装には、conv_layer_template.h, relu_template.h, max_pooling_template.h を使用している。

最初に conv_layer1.cpp を示す。

// conv_layer1.cpp
// 2018/08/22 by marsee
// conv layer1 for squeeze4mnist
//

#include "conv_layer_template.h"
#include "conv1_weight.h"
#include "conv1_bias.h"

int conv_layer1(hls::stream<ap_fixed_axis<9,1,1,1> >& ins,
        hls::stream<ap_fixed_axis<11,1,96,1> >& outs){
//#pragma HLS DATA_PACK variable=outs
//#pragma HLS DATA_PACK variable=ins
    return(conv_layer_template<9,1,16,2,11,1,9,1,1,96,3,3,0,0,2,28,28>(ins, outs, conv1_weight, conv1_bias));
}


次に、relu_conv1.cpp を示す。

// relu_conv1.cpp
// 2018/05/06 by marsee
// relu after conv1
//

#include "relu_template.h"

int relu_conv1(hls::stream<ap_fixed_axis<11,1,96,1> >& ins,
        hls::stream<ap_fixed_axis<11,1,96,1> >& outs){
//#pragma HLS DATA_PACK variable=outs
//#pragma HLS DATA_PACK variable=ins
    return(relu_template<11,1,96,13,13>(ins, outs));
}


max_pooling.cpp を示す。

// max_pooling.cpp
// 2018/05/10 by marsee
//

#include "max_pooling_template.h"

int max_pooling(hls::stream<ap_fixed_axis<11,1,96,1> >& ins,
        hls::stream<ap_fixed_axis<11,1,96,1> >& outs){
//#pragma HLS DATA_PACK variable=outs
//#pragma HLS DATA_PACK variable=ins
    return(max_pooling_template<11,1,96,2,2,2,13,13>(ins, outs));
}


squeezenet4mnist1.cpp を示す。

// squeezenet4mnist1.cpp
// 2018/08/28 by marsee
//

#include <ap_int.h>
#include <hls_stream.h>
#include <ap_axi_sdata.h>
#include <hls_video.h>

#include "layer_general.h"

int conv_layer1(hls::stream<ap_fixed_axis<9,1,1,1> >& ins,
    hls::stream<ap_fixed_axis<11,1,96,1> >& outs);
int relu_conv1(hls::stream<ap_fixed_axis<11,1,96,1> >& ins,
    hls::stream<ap_fixed_axis<11,1,96,1> >& outs);
int max_pooling(hls::stream<ap_fixed_axis<11,1,96,1> >& ins,
    hls::stream<ap_fixed_axis<11,1,96,1> >& outs);

int squeezenet4mnist1(hls::stream<ap_fixed_axis<9,1,1,1> >& ins, hls::stream<ap_fixed_axis<11,1,96,1> >& outs){
#pragma HLS INTERFACE s_axilite port=return
#pragma HLS DATAFLOW
    hls::stream<ap_fixed_axis<11,1,96,1> > outs_conv_layer1;
    hls::stream<ap_fixed_axis<11,1,96,1> > outs_relu_conv1;

    conv_layer1(ins, outs_conv_layer1);
    relu_conv1(outs_conv_layer1, outs_relu_conv1);
    max_pooling(outs_relu_conv1, outs);

    return(0);
}


Vivado HLS 2017.4 で squeezenet4mnist1 プロジェクトを作成した。
squeezenet_vhls_1_180906.png
  1. 2018年09月06日 05:06 |
  2. DNN
  3. | トラックバック:0
  4. | コメント:0
»