Functional APIモデルを利用して実現できます.
Python
1import tensorflow as tf
2from tensorflow.python import keras
3from keras.models import Model
4from keras.layers import Conv2D, Input, Flatten, Dense, MaxPool2D, Dropout, concatenate
5from keras.optimizers import Adam
6import numpy as np
7
8image_input = Input(shape = (256, 128, 1), name = "image_input")
9append_input = Input(shape = (2,), name = "feature_input") # 追加情報の特徴量の数だけ次元数を指定する
10
11params = { # 同一のパラメータは まとめて書いておく
12 "kernel_size": (3, 3),
13 "strides": (1, 1),
14 "padding": "same",
15 "activation": "swish", # 連続関数を利用する
16 "kernel_initializer": "he_normal" # ReLUファミリ用の活性化関数を利用する
17}
18
19x = Conv2D(filters=32, **params)(image_input)
20x = MaxPool2D(pool_size=(2,2), strides=None, padding='same')(x)
21x = Conv2D(filters=23, **params)(x)
22x = MaxPool2D(pool_size=(2,2), strides=None, padding='same')(x)
23x = Conv2D(filters=16, **params)(x)
24x = MaxPool2D(pool_size=(2,2), strides=None, padding='same')(x)
25x = Conv2D(filters=11, **params)(x)
26x = MaxPool2D(pool_size=(2,2), strides=None, padding='same')(x)
27x = Conv2D(filters=8, **params)(x)
28x = MaxPool2D(pool_size=(2,2), strides=None, padding='same')(x)
29
30x = Flatten()(x)
31x = concatenate([x, append_input])
32x = Dropout(0.5)(x)
33x = Dense(128, activation='swish', kernel_initializer = 'he_uniform')(x)
34x = Dense(10, activation='softmax')(x)
35
36network = Model(inputs = [image_input, append_input], outputs = x)
37
38network.compile(
39 optimizer = 'adam',
40 loss = 'categorical_crossentropy',
41 metrics=['accuracy']
42)
43
44network.summary()
45from keras.utils.vis_utils import plot_model
46plot_model(network, to_file = "CNN.png", rankdir = "LR", show_shapes = True, show_layer_names = True, show_layer_activations = True)
47
48# 擬似データを用意
49# 擬似画像 32枚解像度256x128のグレースケール画像
50train_img = np.random.randn(32, 256, 128, 1)
51# train_feautre = np.array([ [x0, y0], [x1, y1], [x2, y2], ..., [xn, yn] ]) となるように与える
52train_feature = np.random.randn(32, 2)
53# モデルに出力してほしい値.One-Hot Encoding済であること.
54train_y = np.abs(np.random.randn(32, 10))
55
56batch_size = 32
57epochs = 10
58
59network.fit(
60 x = { # keyはレイヤの名前と一致させる
61 "image_input": train_img,
62 "feature_input": train_feature
63 },
64 y = train_y,
65 batch_size = batch_size,
66 epochs = epochs
67)
基本,分類問題を解かせる場合はTrainable paramsやユニット数を出力側に行くにつれ減少させるのが常套手段です.カーネルの枚数を徐々に減少させるようにしておきました.また,活性化関数もELUを上回ったSwishを推奨しておきます.さらに,カーネルの初期値はglorot_uniform
なので,ELUやSwishのようなReLUファミリ用のhe_uniform
を推奨します.
Python:network.summary()
1Model: "model"
2__________________________________________________________________________________________________
3 Layer (type) Output Shape Param # Connected to
4==================================================================================================
5 image_input (InputLayer) [(None, 256, 128, 1 0 []
6 )]
7
8 conv2d (Conv2D) (None, 256, 128, 32 320 ['image_input[0][0]']
9 )
10
11 max_pooling2d (MaxPooling2D) (None, 128, 64, 32) 0 ['conv2d[0][0]']
12
13 conv2d_1 (Conv2D) (None, 128, 64, 23) 6647 ['max_pooling2d[0][0]']
14
15 max_pooling2d_1 (MaxPooling2D) (None, 64, 32, 23) 0 ['conv2d_1[0][0]']
16
17 conv2d_2 (Conv2D) (None, 64, 32, 16) 3328 ['max_pooling2d_1[0][0]']
18
19 max_pooling2d_2 (MaxPooling2D) (None, 32, 16, 16) 0 ['conv2d_2[0][0]']
20
21 conv2d_3 (Conv2D) (None, 32, 16, 11) 1595 ['max_pooling2d_2[0][0]']
22
23 max_pooling2d_3 (MaxPooling2D) (None, 16, 8, 11) 0 ['conv2d_3[0][0]']
24
25 conv2d_4 (Conv2D) (None, 16, 8, 8) 800 ['max_pooling2d_3[0][0]']
26
27 max_pooling2d_4 (MaxPooling2D) (None, 8, 4, 8) 0 ['conv2d_4[0][0]']
28
29 flatten (Flatten) (None, 256) 0 ['max_pooling2d_4[0][0]']
30
31 feature_input (InputLayer) [(None, 2)] 0 []
32
33 concatenate (Concatenate) (None, 258) 0 ['flatten[0][0]',
34 'feature_input[0][0]']
35
36 dropout (Dropout) (None, 258) 0 ['concatenate[0][0]']
37
38 dense (Dense) (None, 128) 33152 ['dropout[0][0]']
39
40 dense_1 (Dense) (None, 10) 1290 ['dense[0][0]']
41
42==================================================================================================
43Total params: 47,132
44Trainable params: 47,132
45Non-trainable params: 0
46__________________________________________________________________________________________________
個人的には,CNNだけを分類予測学習した後,CNNを学習しないようにして特徴量マップ出力と追加情報を合併して予測/分類する方が良いと思います.