はじめに
みなさん、こんにちは。メイビスデザインのtatoshiです。
主に画像処理とSAMACT(サマクト)の組み合わせについて研究をしています。
そこで、今回はCNNの全結合層にSAMACTを使用する方法を紹介します。
SAMACTとは
知らない人が大多数だと思うので、軽くSAMACTについて紹介します。
SAMACTはメイビスデザインが独自開発したAI IPコアです。
エンドポイントAIとしての設計思想を持ち、デバイス上で学習まで完結させるのが特徴になっています。
詳しくは次の記事を参照してください。
CNN(Convolutional Neural Network)とは
次にCNNとはなんぞやという話をします。知っている方は次の章へと読み飛ばして下さい。
CNNは日本語にすると、畳み込みニューラルネットワークと呼ばれます。メジャーな機械学習モデルの1つです。
画像認識のタスクを行う場合、このモデルの選択が最適解となる場合が多く、用途は多岐にわたります。
下記の上側の図がよくあるニューラルネットワークの形。下側がCNNと呼ばれるネットワークの形です。平面状のデータを立体的に圧縮しているのが分かると思います。
具体的な説明は詳しく説明している方がいらっしゃったのでそちらを参考にしてください。
CNNとSAMACTの結合
次にCNNとSAMACTの結合について概要を説明します。まずはメジャーなCNNモデルの構成について紹介します。

注目していただきたいのが水色の部分です。ここは全結合層と呼ばれ、畳み込まれたデータから特徴を学習する部分になります。この個所は通常のニューラルネットワークが使われるため、ニューラルネットワークの一種であるSAMACTを適応することができます。

ソースコード
全体
このコードではMNISTの手書き文字データセットの分類を行っています。CNNのライブラリとしてはkerasを用います。
必要なライブラリをインストールして、べた張りで動くと思います。私のノートパソコンだと3時間ほどかかりましたので、実行する際は注意してください。
全体コードの後にブロック毎に解説を行います。コードを読んだだけで分かるよって人は結果まで飛ばしてください。
import keras
from keras.models import Sequential
from keras.layers import Dense, Dropout, Flatten
from keras.layers import Conv2D, MaxPooling2D
from keras.datasets import mnist
import time
from samact.SAMACTProperty.LearningProperty import LearningProperty
from samact.UserInterfaceLayers.NeuralLayer.SAMLayer import SAMLayer
from samact.UserInterfaceLayers.CodingLayer.EncodeLayer.RateEncodeLayer import RateEncodeLayer
from samact.UserInterfaceLayers.CodingLayer.DecodeLayer.MajorityDecodeLayer import MajorityDecodeLayer
from samact.SAMACTProperty.LayerProperty import LayerProperty
from samact.UserInterfaceActivateFunction.ActivateFunction import Step, Linear
from samact.Models.Sequential import Sequential as SequentialM
def main():
# CNN
# 入力と出力を指定 --- (*1)
im_rows = 28 # 画像の縦ピクセルサイズ
im_cols = 28 # 画像の横ピクセルサイズ
im_color = 1 # 画像の色空間/グレイスケール
in_shape = (im_rows, im_cols, im_color)
num_classes = 10
# MNISTのデータを読み込み
(X_train, y_train), (X_test, y_test) = mnist.load_data()
# 読み込んだデータをの三次元配列に変換 --- (*1a)
X_train = X_train.reshape(-1, im_rows, im_cols, im_color)
X_train = X_train.astype('int32') / 255
X_test = X_test.reshape(-1, im_rows, im_cols, im_color)
X_test = X_test.astype('int32') / 255
# ラベルデータをone-hotベクトルに直す
y_train_one_hot = keras.utils.to_categorical(y_train.astype('int32'),10)
y_test_one_hot = keras.utils.to_categorical(y_test.astype('int32'),10)
# CNNモデル構造を定義 --- (*2)
model = Sequential()
model.add(Conv2D(10,kernel_size=(3, 3),activation="relu", input_shape=in_shape))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Conv2D(10,kernel_size=(3, 3),activation="relu", input_shape=in_shape))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Flatten())
model.add(Dropout(0.5)),
model.add(Dense(num_classes, activation="softmax"))
batch_size = 128
epochs = 15
# モデルのコンパイルと学習
model.compile(loss="categorical_crossentropy", optimizer="adam", metrics=["accuracy"])
model.fit(X_train, y_train_one_hot, batch_size=batch_size, epochs=epochs, validation_split=0.1)
# 結果の表示
score = model.evaluate(X_test, y_test_one_hot, verbose=0)
print("Test loss:", score[0])
print("Test accuracy:", score[1])
model.pop()
model.pop()
trainData=model(X_train)
print(trainData.shape)
trainLabel = y_train
# ここからSAMACT
start = time.time()
# region 2. ニューラルネットワークの構築
# 250-192-10のネットワークを構成
nN1 = 250
nN2 = 192
nN3 = 10
## 2-1. エンコーダの設定
# SAMACTは主にRateCodingを採用。
inputLayer = RateEncodeLayer(nN1)
## 2-2. SAMレイヤーの設定
# ハイパーパラメータa=3, p=0.75を指定。
# 重みの逆伝搬時の活性化関数にStep関数を指定。
# 教師信号生成時の活性化関数にStep関数を指定。(前段はエンコーダなので利用されない)
hiddenLayer = SAMLayer(nN2, LayerProperty(a=3, p=0.75), Step(), Step())
# ハイパーパラメータa=3, p=0.75を指定。
# 重みの逆伝搬時の活性化関数にStep関数を指定。
# 教師信号生成時の活性化関数に恒等関数を指定。(特許)
outputLayer = SAMLayer(nN3, LayerProperty(a=3, p=0.75), Step(), Linear())
## 2-3. デコーダの設定
# 分類問題なので、出力パルスを多数決するデコーダを指定。
decoder = MajorityDecodeLayer()
## 2-4. ニューラルネットワークの生成
# 上記layerを渡してモデルを構築
sam_model = SequentialM(inputLayer, decoder, [hiddenLayer, outputLayer])
# 1データを32サイクルで処理するように設定。(ハイパーパラメータ)
sam_model.Compile(32)
# endregion
# region 3. 学習
## 3-1. 学習プロパティの設定
# 学習率eta, iotaの初期値を5, 2に設定。2エポックごとに1減衰する。
learnProperty = LearningProperty(eta=5, iota=2, decayPeriod=1)
## 3-2. 学習の実施
# 学習エポック数は5に設定。
fitResult = sam_model.Fit(trainData, trainLabel, 5, learnProperty)
## 3-3. 学習結果の保存
# パラメータの学習結果を保存
dumpName = f"digits_{nN1}_{nN2}_{nN3}_ntd{len(trainData)}_step.npz"
sam_model.Save(dumpName)
# 学習にかかった時間
print("fit time")
print(time.time()-start)
# 1epoch目から20epochまでのの学習精度(正解率)のリスト
print(fitResult.metrics)
# endregion
# region 4. 推論
## 4-1. テスト用データセットをまとめて推論
# テストデータに対する正解率
testData = model(X_test)
evalResult = sam_model.Evaluate(testData, y_test)
print(evalResult.metrics)
## 4-2. 1データを推論
# 1データに対して予測するときのメソッド
# predict = sam_model.Predict(testData[0])
# # endregion
if __name__ == '__main__':
main()
ライブラリ
各種ライブラリを読み出します。ここでkerasのSequentialとSAMACTのSequentialが被っているため、kerasの方はそのままで、SAMACTの方はSequentialMと名前を変えています。
ここではSAMACTは必要なものだけを呼び出しています。
import keras
from keras.models import Sequential
from keras.layers import Dense, Dropout, Flatten
from keras.layers import Conv2D, MaxPooling2D
from keras.datasets import mnist
import time
from samact.SAMACTProperty.LearningProperty import LearningProperty
from samact.UserInterfaceLayers.NeuralLayer.SAMLayer import SAMLayer
from samact.UserInterfaceLayers.CodingLayer.EncodeLayer.RateEncodeLayer import RateEncodeLayer
from samact.UserInterfaceLayers.CodingLayer.DecodeLayer.MajorityDecodeLayer import MajorityDecodeLayer
from samact.SAMACTProperty.LayerProperty import LayerProperty
from samact.UserInterfaceActivateFunction.ActivateFunction import Step, Linear
from samact.Models.Sequential import Sequential as SequentialM
入力画像の情報を指定
MNISTの文字識別のパラメータを設定します。
MNISTは28x28のグレイスケール画像です。それぞれ変数化しin_shapeにまとめておきます。
num_classesは分類数です。MNISTは0~9の10分類であるため10を設定します。
# CNN
# 入力と出力を指定 --- (*1)
im_rows = 28 # 画像の縦ピクセルサイズ
im_cols = 28 # 画像の横ピクセルサイズ
im_color = 1 # 画像の色空間/グレイスケール
in_shape = (im_rows, im_cols, im_color)
num_classes = 10
MNISTデータの読み込み
MNISTのデータをそれぞれ
X_train:学習データ
y_train:学習データのラベル
X_test:推論データ
y_test:推論データのラベル
へと格納します。
このデータは一次元配列であり、CNNにそのまま利用できないため、三次元のデータへと変換を行います。
最後にラベルデータをone_hotベクトルにします。
これは0~9の数字を[1,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,0,0,0,1]のような形で表したものです。
# MNISTのデータを読み込み
(X_train, y_train), (X_test, y_test) = mnist.load_data()
# 読み込んだデータをの三次元配列に変換 --- (*1a)
X_train = X_train.reshape(-1, im_rows, im_cols, im_color)
X_train = X_train.astype('int32') / 255
X_test = X_test.reshape(-1, im_rows, im_cols, im_color)
X_test = X_test.astype('int32') / 255
# ラベルデータをone-hotベクトルに直す
y_train_one_hot = keras.utils.to_categorical(y_train.astype('int32'),10)
y_test_one_hot = keras.utils.to_categorical(y_test.astype('int32'),10)
CNNの構築
ここからはCNNのモデルを構築していきます。それぞれ何をしているか大まかに説明します。詳しく知りたい人はkerasの公式ドキュメントを参照して下さい。
まずmodelをSequentialにて定義します。そのあとConv2Dで畳み込み層を追加、MaxPooling2Dで圧縮層を追加します。次にFlattenにて全結合層に食わせるためのデータ形式へと変換。最後にDropoutで全結合層を構築し、Denseで分類層をおしりに付けます。
次にモデルをコンパイルして、fitにて学習を開始します。
最後に学習結果をscoreへと格納して結果を出力して完了です。
# CNNモデル構造を定義 --- (*2)
model = Sequential()
model.add(Conv2D(10,kernel_size=(3, 3),activation="relu", input_shape=in_shape))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Conv2D(10,kernel_size=(3, 3),activation="relu", input_shape=in_shape))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Flatten())
model.add(Dropout(0.5)),
model.add(Dense(num_classes, activation="softmax"))
batch_size = 128
epochs = 15
# モデルのコンパイルと学習
model.compile(loss="categorical_crossentropy", optimizer="adam", metrics=["accuracy"])
model.fit(X_train, y_train_one_hot, batch_size=batch_size, epochs=epochs, validation_split=0.1)
# 結果の表示
score = model.evaluate(X_test, y_test_one_hot, verbose=0)
print("Test loss:", score[0])
print("Test accuracy:", score[1])
CNNをSAMACTと結合できるように再構築
ここではCNNのモデルで使用した全結合層をpop()をつかって削除します。DenseとDropoutの2層ですので2回叩きます。
その後、学習データ(X_train)をCNNのmodelに通すことで、SAMACTに入る形で畳み込まれたデータを取得できます。
model.pop()
model.pop()
trainData=model(X_train)
print(trainData.shape)
trainLabel = y_train
SAMACTの基本設定
ここからSAMACTの設定を行っています。各種何を設定しているかはコード内に記載していますので確認して下さい。nN1のみ前段のCNNの構造によっては変化します。print(trainData.shape)にて出力された右側の値を設定して下さい。
それ以外の各種パラメータはえいやッと決めています。
# ここからSAMACT
start = time.time()
# region 2. ニューラルネットワークの構築
# 250-192-10のネットワークを構成
nN1 = 250
nN2 = 192
nN3 = 10
## 2-1. エンコーダの設定
# SAMACTは主にRateCodingを採用。
inputLayer = RateEncodeLayer(nN1)
## 2-2. SAMレイヤーの設定
# ハイパーパラメータa=3, p=0.75を指定。
# 重みの逆伝搬時の活性化関数にStep関数を指定。
# 教師信号生成時の活性化関数にStep関数を指定。(前段はエンコーダなので利用されない)
hiddenLayer = SAMLayer(nN2, LayerProperty(a=3, p=0.75), Step(), Step())
# ハイパーパラメータa=3, p=0.75を指定。
# 重みの逆伝搬時の活性化関数にStep関数を指定。
# 教師信号生成時の活性化関数に恒等関数を指定。(特許)
outputLayer = SAMLayer(nN3, LayerProperty(a=3, p=0.75), Step(), Linear())
## 2-3. デコーダの設定
# 分類問題なので、出力パルスを多数決するデコーダを指定。
decoder = MajorityDecodeLayer()
## 2-4. ニューラルネットワークの生成
# 上記layerを渡してモデルを構築
sam_model = SequentialM(inputLayer, decoder, [hiddenLayer, outputLayer])
# 1データを32サイクルで処理するように設定。(ハイパーパラメータ)
sam_model.Compile(32)
# endregion
SAMACTの学習
SAMACTの学習を行い、学習結果を表示します。エポック数5としていますが、かなり時間がかかりますので調整してください。
# region 3. 学習
## 3-1. 学習プロパティの設定
# 学習率eta, iotaの初期値を5, 2に設定。2エポックごとに1減衰する。
learnProperty = LearningProperty(eta=5, iota=2, decayPeriod=1)
## 3-2. 学習の実施
# 学習エポック数は5に設定。
fitResult = sam_model.Fit(trainData, trainLabel, 5, learnProperty)
## 3-3. 学習結果の保存
# パラメータの学習結果を保存
dumpName = f"digits_{nN1}_{nN2}_{nN3}_ntd{len(trainData)}_step.npz"
sam_model.Save(dumpName)
# 学習にかかった時間
print("fit time")
print(time.time()-start)
# 1epoch目から20epochまでのの学習精度(正解率)のリスト
print(fitResult.metrics)
# endregion
SAMACTの推論
最後にテストデータの推論を行って結果を確認します。
# region 4. 推論
## 4-1. テスト用データセットをまとめて推論
# テストデータに対する正解率
testData = model(X_test)
evalResult = sam_model.Evaluate(testData, y_test)
print(evalResult.metrics)
結果まとめ
| 名称 | 構成 | CNNの学習 | 1層目フィルタ数 | 2層目フィルタ数 | 活性化関数 | 後処理 | ニューロン構成 | 推論精度 |
|---|---|---|---|---|---|---|---|---|
| CNNサンプル | CNN-ANN | あり | 32 | 64 | ReLU | Softmax | - | 99.15 |
| SAMACT実績 | Pol-SNN | なし | - | - | - | 多数決回路 | 100-192-10 | 89.75 |
| 有効性検討 | CNN-SNN | あり | 10 | 10 | 無し | 多数決回路 | 250-192-10 | 96.92 |
上記の表は現実的なニューロン構成に収まる範囲で記録したものです。SAMACTはエンドポイントAIであるため、入力層が膨大なネットワークなどは想定される使い方ではなく、250に収まるようにしました。それで推論精度は 96.92% と好成績を記録しています。もしかすると、大きなGPUや、CPUなどなくとも画像認識ができる時代がくるかもしれませんね。
リンク集
| リソース | URL |
|---|---|
| GitHub(サンプル・ドキュメント・フォーラム) | https://github.com/maviss-design/SAMACT |
| PyPI(パッケージ) | https://pypi.org/project/samact/ |
| APIドキュメント | https://maviss-design.github.io/SAMACT/ |
| 弊社Webサイト | https://maviss-design.com/ |
| お問い合わせ | https://maviss-design.com/contact/ |
ライセンス
AGPLv3 を採用しています。研究・検証目的での利用を歓迎しますが、商用利用や量産用途をご検討の場合は別途お問い合わせください。
