Help us understand the problem. What is going on with this article?

CNTK(Cognitive Tool Kit)によるBinary Convolution Neural Network

More than 1 year has passed since last update.

CNNを二値化する取り組みは制限のきついハードウエアでのCNNの実行が主な目的です
二値化することにより、下記のようなメリットが得られます。
-ハードウエア化を簡単にする
-コンパクトかつ高速化を行う

CNTKでBNNをトレーニングして実行する部分については、下記の記事を参照ください。BNNはMicrosoft Embedded Learning Libraryに付属しているモジュールを使用しています。
https://qiita.com/yasukit/items/a5507e131583d2fca490

コードやモデルは以下のサイトにまとめています。
https://github.com/yasukit1414/binaryconv

実際に、CNTKを使って、CNNとBNNを比較してみました。

BNNの作成と学習

    scaled_input = C.element_times(C.constant(0.00390625), feature_var)


    z = C.layers.Convolution((3, 3), 32, pad=True, activation=C.relu)(scaled_input)
    z = C.layers.MaxPooling((3,3), strides=(2,2))(z)

    z = C.layers.BatchNormalization(map_rank=1)(z)
    z = BinaryConvolution((3,3), 128, channels=32, pad=True)(z)

    z = C.layers.MaxPooling((3,3), strides=(2,2))(z)

    z = C.layers.BatchNormalization(map_rank=1)(z)
    z = BinaryConvolution((3,3), 128, channels=128, pad=True)(z)
    z = C.layers.MaxPooling((3,3), strides=(2,2))(z)

    z = C.layers.BatchNormalization(map_rank=1)(z)
    z = BinaryConvolution((1,1), num_classes, channels=128, pad=True)(z)
    z = C.layers.AveragePooling((z.shape[1], z.shape[2]))(z)
    z = C.reshape(z, (num_classes,))


    SP = C.parameter(shape=z.shape, init=0.001)
    z = C.element_times(z, SP)

下記がBNNの各オペレーションになります。

ElementTimes : 32x32x3 -> 34x34x3 | input padding 0 output padding 1
Convolution (ReLU) : 34x34x3 -> 32x32x32 | input padding 1 output padding 0
MaxPooling : 32x32x32 -> 15x15x32 | input padding 0 output padding 0
BatchNormalization : 15x15x32 -> 17x17x32 | input padding 0 output padding 1
BinaryConvolution : 17x17x32 -> 15x15x128 | input padding 1 output padding 0
Plus : 15x15x128 -> 15x15x128 | input padding 0 output padding 0
PReLU : 15x15x128 -> 15x15x128 | input padding 0 output padding 0
MaxPooling : 15x15x128 -> 7x7x128 | input padding 0 output padding 0
BatchNormalization : 7x7x128 -> 9x9x128 | input padding 0 output padding 1
BinaryConvolution : 9x9x128 -> 7x7x128 | input padding 1 output padding 0
Plus : 7x7x128 -> 7x7x128 | input padding 0 output padding 0
PReLU : 7x7x128 -> 7x7x128 | input padding 0 output padding 0
MaxPooling : 7x7x128 -> 3x3x128 | input padding 0 output padding 0
BatchNormalization : 3x3x128 -> 3x3x128 | input padding 0 output padding 0
BinaryConvolution : 3x3x128 -> 3x3x10 | input padding 0 output padding 0
Plus : 3x3x10 -> 3x3x10 | input padding 0 output padding 0
PReLU : 3x3x10 -> 3x3x10 | input padding 0 output padding 0
AveragePooling : 3x3x10 -> 1x1x10 | input padding 0 output padding 0
ElementTimes : 1x1x10 -> 1x1x10 | input padding 0 output padding 0
Softmax : 1x1x10 -> 1x1x10 | input padding 0 output padding 0

CNNの作成と学習

基本のCNNにBatch Normalizationを入れた形になっています。BNNと構成を合わせるように作成しています。

    scaled_input = C.element_times(C.constant(0.00390625), feature_var)

    # first layer is ok to be full precision
    z = C.layers.Convolution((3, 3), 32, pad=True, activation=C.relu)(scaled_input)
    z = C.layers.MaxPooling((3,3), strides=(2,2))(z)

    z = C.layers.BatchNormalization(map_rank=1)(z)
    z = C.layers.Convolution((3,3), 128, pad=True)(z)
    z = C.layers.MaxPooling((3,3), strides=(2,2))(z)

    z = C.layers.BatchNormalization(map_rank=1)(z)
    z = C.layers.Convolution((3,3), 128,  pad=True)(z)
    z = C.layers.MaxPooling((3,3), strides=(2,2))(z)

    z = C.layers.BatchNormalization(map_rank=1)(z)
    z = C.layers.Convolution((1,1), num_classes,  pad=True)(z)
    z = C.layers.AveragePooling((z.shape[1], z.shape[2]))(z)
    z = C.reshape(z, (num_classes,))



    SP = C.parameter(shape=z.shape, init=0.001)
    z = C.element_times(z, SP)

実際のオペレーションの中身になります。

ElementTimes : 32x32x3 -> 34x34x3 | input padding 0 output padding 1
Convolution (ReLU) : 34x34x3 -> 32x32x32 | input padding 1 output padding 0
MaxPooling : 32x32x32 -> 15x15x32 | input padding 0 output padding 0
BatchNormalization : 15x15x32 -> 17x17x32 | input padding 0 output padding 1
Convolution : 17x17x32 -> 15x15x128 | input padding 1 output padding 0
MaxPooling : 15x15x128 -> 7x7x128 | input padding 0 output padding 0
BatchNormalization : 7x7x128 -> 9x9x128 | input padding 0 output padding 1
Convolution : 9x9x128 -> 7x7x128 | input padding 1 output padding 0
MaxPooling : 7x7x128 -> 3x3x128 | input padding 0 output padding 0
BatchNormalization : 3x3x128 -> 3x3x128 | input padding 0 output padding 0
Convolution : 3x3x128 -> 3x3x10 | input padding 0 output padding 0
AveragePooling : 3x3x10 -> 1x1x10 | input padding 0 output padding 0
ElementTimes : 1x1x10 -> 1x1x10 | input padding 0 output padding 0
Softmax : 1x1x10 -> 1x1x10 | input padding 0 output padding 0

結果

GPUが搭載されていれば、通常のConvlutionの方がGPUの実行効率が高く、計算速度も高い結果になります。またmetrixも5%程度通常のConvotluionの方が有利になります。

Binary Convolutionはやはりハードウエアが制限された環境で、うまくチューニングして使用するか、FPGA等で直接ハードウエア化を行なわなければ、通常のGPU付きの環境ではあまりメリットがないです。

CPUの環境であれば、2-3割程度実行速度が上がります。Batch Normalizationを減らすと認識率は下がりますが実行速度は上がります。最終はそのトレードオフではないかと思います。

yasukit
最近は機械学習とその周辺の話に興味をもっている
https://analyticsai.wordpress.com
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした