Keras ではConv2Dクラスが畳み込み層のクラスになります。
では早速、Conv2D クラスを使って前ページの例を演算してみましょう(ソース1)。
import tensorflow as tf ''' # CUDA を有効にしている時に「UnknownError: Failed to get convolution algorithm.」というエラーが # 出て動かない時はコメントアウトを外し、カーネルを再起動してから実行してください from tensorflow.compat.v1.keras.backend import set_session config = tf.compat.v1.ConfigProto() config.gpu_options.allow_growth = True config.log_device_placement = True sess = tf.compat.v1.Session(config=config) set_session(sess) ''' import numpy as np rows = 4 # 画像の高さ cols = 4 # 画像の幅 Cin = 2 # 入力画像のチャンネル数 Cout = 2 # 出力画像のチャンネル数 kernel_size = 3 # カーネルサイズ # 入力画像の 0 番目のチャンネル data_0 = np.array( [ [ 1, 2, 3, 0 ], [ 2, 0, 1, 2 ], [ 0, 1, 2, 0 ], [ 0, 0, 3, 1 ] ] ) # 入力画像の 1 番目のチャンネル data_1 = np.array( [ [ 0, 2, 1, 3 ], [ 1, 1, 0, 1 ], [ 2, 2, 3, 2 ], [ 3, 1, 0, 0 ] ] ) # 入力画像の 0 番目のチャンネルと出力画像の 0 番目のチャンネルに対するカーネル kernel_00 = np.array( [ [ 0, 1, 0 ], [ 2, 0, 3 ], [ 0, 4, 0 ] ] ) # 入力画像の 0 番目のチャンネルと出力画像の 1 番目のチャンネルに対するカーネル kernel_01 = np.array( [ [ 2, 0, 1 ], [ 0, 1, 0 ], [ 1, 0, 3 ] ] ) # 入力画像の 1 番目のチャンネルと出力画像の 0 番目のチャンネルに対するカーネル kernel_10 = np.array( [ [ 0, 0, 0 ], [ 0, 1, 0 ], [ 0, 0, 0 ] ] ) # 入力画像の 1 番目のチャンネルと出力画像の 1 番目のチャンネルに対するカーネル kernel_11 = np.array( [ [ 1, 0, 0 ], [ 0, 2, 3 ], [ 2, 0, 0 ] ] ) # 出力画像の 0 番目のチャンネルに対するバイアス b_0 = 1 # 出力画像の 1 番目のチャンネルに対するバイアス b_1 = -1 # 入力画像全体: shape = (データ数, rows, cols, Cin) の 4 階テンソル data = tf.constant( [ np.stack( [data_0,data_1], -1) ], dtype=tf.float32 ) # カーネル全体: shape = (kernel_size, kernel_size, Cin * Cout) の 3 階テンソル kernel = np.stack( [kernel_00,kernel_01,kernel_10,kernel_11], -1) # バイアス全体 : shape = (Cout) のベクトル b = [b_0, b_1] # モデル作成 model = tf.keras.Sequential() model.add( tf.keras.Input(shape=(rows,cols,Cin,))) model.add( tf.keras.layers.Conv2D( Cout, (kernel_size,kernel_size), kernel_initializer=tf.keras.initializers.Constant(kernel), bias_initializer=tf.keras.initializers.Constant(b) )) model.summary() # 畳み込み演算 y = model.predict( data ) print('') np.set_printoptions(precision=0, suppress=True) for i in range(Cin): print(f'data_{i}=') print( data[0,:,:,i].numpy()) print('') for i in range(Cin): for i2 in range(Cout): print(f'kernel_{i}{i2} = ') print(kernel[:,:,Cin*i+i2]) print('') for i in range(Cout): print(f'b_{i} = {b[i]}') print('') for i in range(Cout): print(f'y_{i} =') print(y[0,:,:,i]) print('')
基本的にはMLPと同様に Sequential モデルを作成し、predict メソッドで出力を求めますが、
model.add( tf.keras.layers.Conv2D( Cout, (kernel_size,kernel_size), kernel_initializer=tf.keras.initializers.Constant(kernel), bias_initializer=tf.keras.initializers.Constant(b) ))
の行で畳み込み層(Conv2Dクラス)をモデルに追加しています。
では上のソースの実行結果を以下に示します。
Model: "sequential_2" _________________________________________________________________ Layer (type) Output Shape Param # ================================================================= conv2d_2 (Conv2D) (None, 2, 2, 2) 38 ================================================================= Total params: 38 Trainable params: 38 Non-trainable params: 0 _________________________________________________________________ data_0= [[1. 2. 3. 0.] [2. 0. 1. 2.] [0. 1. 2. 0.] [0. 0. 3. 1.]] data_1= [[0. 2. 1. 3.] [1. 1. 0. 1.] [2. 2. 3. 2.] [3. 1. 0. 0.]] kernel_00 = [[0 1 0] [2 0 3] [0 4 0]] kernel_01 = [[2 0 1] [0 1 0] [1 0 3]] kernel_10 = [[0 0 0] [0 1 0] [0 0 0]] kernel_11 = [[1 0 0] [0 2 3] [2 0 0]] b_0 = 1 b_1 = -1 y_0 = [[15. 18.] [ 9. 19.]] y_1 = [[16. 14.] [34. 21.]]
ところでモデル概要を見るとパラメータの個数が Total param : 38 個となっています。
カーネル1つに含まれるパラメータ数は 9 個、カーネルは計 4 個、バイアスは計 2 個より、9*4+2=38 なので確かに合っています。