前提
現在,pythonを用いてResNet50v2 + ArcFaceの実装を行っています.
モデル構築自体はこちらを参考に行いました.
そこで,モデル構築を終えてoptunaを用いてパラメータチューニングを行おうとしたときに以下のようなエラーが発生しました.
発生している問題・エラーメッセージ
以下のエラーは毎回のtrial時に発生します.
[I 2022-12-24 03:55:03,912] A new study created in memory with name: no-name-3fb7ffc6-9bc1-4f30-aaec-3bf89cc9b1ce Epoch 1: LearningRateScheduler setting learning rate to 0.000911662180442363. Epoch 1/100 [W 2022-12-24 03:55:06,429] Trial 0 failed because of the following error: The value None could not be cast to float. モデル定義内でエラー:in user code: File "/usr/local/lib/python3.8/dist-packages/keras/engine/training.py", line 1021, in train_function * return step_function(self, iterator) File "/usr/local/lib/python3.8/dist-packages/keras/engine/training.py", line 1010, in step_function ** outputs = model.distribute_strategy.run(run_step, args=(data,)) File "/usr/local/lib/python3.8/dist-packages/keras/engine/training.py", line 1000, in run_step ** outputs = model.train_step(data) File "/usr/local/lib/python3.8/dist-packages/keras/engine/training.py", line 859, in train_step y_pred = self(x, training=True) File "/usr/local/lib/python3.8/dist-packages/keras/utils/traceback_utils.py", line 67, in error_handler raise e.with_traceback(filtered_tb) from None File "/usr/local/lib/python3.8/dist-packages/keras/engine/input_spec.py", line 200, in assert_input_compatibility raise ValueError(f'Layer "{layer_name}" expects {len(input_spec)} input(s),' ValueError: Layer "model" expects 2 input(s), but it received 1 input tensors. Inputs received: [<tf.Tensor 'IteratorGetNext:0' shape=(None, 110, 110, 1) dtype=float32>] が発生 ・ ・ ・
該当のソースコード
以下が実際にし使用した,パラメータチューニングに関係するソースコードです.
python
1# 総クラス数,エポック数,入力画像のサイズを指定 2num_classes = 29 3epochs = 100 4height = 110 # 像のピクセル数(縦) 5width = 110 # 像のピクセル数(横)
python
1# ArcFaceの処理を記述 2class Arcfacelayer(Layer): 3 # s:softmaxの温度パラメータ, m:margin 4 def __init__(self, output_dim, s, m, easy_margin=False): 5 self.output_dim = output_dim 6 self.s = s 7 self.m = m 8 self.easy_margin = easy_margin 9 super(Arcfacelayer, self).__init__() 10 11 # 重みの作成 12 def build(self, input_shape): 13 # Create a trainable weight variable for this layer. 14 self.kernel = self.add_weight(name='kernel', 15 shape=(input_shape[0][1], self.output_dim), 16 initializer='uniform', 17 trainable=True) 18 super(Arcfacelayer, self).build(input_shape) 19 20 21 # mainの処理 22 def call(self, x): 23 24 y = x[1] 25 x_normalize = tf.math.l2_normalize(x[0]) # x = x'/ ||x'||2 26 k_normalize = tf.math.l2_normalize(self.kernel) # Wj = Wj' / ||Wj'||2 27 28 cos_m = K.cos(self.m) 29 sin_m = K.sin(self.m) 30 th = K.cos(np.pi - self.m) 31 mm = K.sin(np.pi - self.m) * self.m 32 33 cosine = K.dot(x_normalize, k_normalize) # W.Txの内積 34 sine = K.sqrt(1.0 - K.square(cosine)) 35 36 phi = cosine * cos_m - sine * sin_m #cos(θ+m)の加法定理 37 38 if self.easy_margin: 39 phi = tf.where(cosine > 0, phi, cosine) 40 41 else: 42 phi = tf.where(cosine > th, phi, cosine - mm) 43 44 # 正解クラス:cos(θ+m) 他のクラス:cosθ 45 output = (y * phi) + ((1.0 - y) * cosine) 46 output *= self.s 47 48 return output 49 50 def compute_output_shape(self, input_shape): 51 return (input_shape[0][0], self.output_dim) #入力[x,y]のためx[0]はinput_shape[0][0]
python
1# ResNet50v2 + ArcFace定義 2# 学習に使用 3def create_arcface_with_resnet50v2(input_shape, s, m): 4 # ResNet50V2の入力層の前に独自の入力層を追加 5 input_tensor = input_shape 6 print(input_tensor) 7 8 input_model = Sequential() 9 input_model.add(InputLayer(input_shape=input_tensor)) 10 input_model.add(Conv2D(3, (7, 7), padding='same')) 11 input_model.add(BatchNormalization()) 12 input_model.add(Activation('relu')) 13 14 resnet50v2 = ResNet50V2(include_top=False, weights=None, input_tensor=input_model.output) 15 16# DLしてある重みの読み込み 17 resnet50v2.load_weights('save_model(weights_imagenet)/weights_imagenet.hdf5', by_name=True) 18 19 20 flat = Flatten()(resnet50v2.layers[-1].output) 21 dense = Dense(512, activation="relu", name="hidden")(flat) 22 23 x = BatchNormalization()(dense) 24 25 yinput = Input(shape=(num_classes,)) #ArcFaceで使用 26 27 s_cos = Arcfacelayer(num_classes, s, m)([x,yinput]) #outputをクラス数と同じ数に 28 prediction = Activation('softmax')(s_cos) 29 30 model = Model(inputs=[resnet50v2.input, yinput], outputs=prediction) 31 32 return model
python
1# 学習率を返す関数 2def lr_schedul(epoch, lr): 3 if epoch < 3: 4 new_lr = lr 5 else: 6 new_lr = lr * math.exp(-0.1) 7 return new_lr 8 9 10# モデル定義 11def trainer(**param): 12 lr = param['lr'] 13 batch_size = param['batch_size'] 14 s = param['s'] 15 m = param['m'] 16 17 model = create_arcface_with_resnet50v2(input_shape, s, m) 18 19 # 自動的に学習をやめる 20 early_stopping = EarlyStopping(monitor='val_loss', 21 min_delta=0.0, 22 patience=3, 23 mode='min' 24 ) 25 # 最良の重みとモデルを保存 26 fpath = 'Weight/{}/{}_{}_{}_{}_({{epoch:02d}}-{{loss:.2f}}-{{accuracy:.2f}}-{{val_loss:.2f}}-{{val_accuracy:.2f}}).hdf5'.format(f_elem, batch_size, lr, s, m) 27 model_checkpoint = ModelCheckpoint(filepath=fpath, monitor='val_loss', save_best_only=True, mode='min') 28 # 学習中に学習率を調整 29 lr_scheduler = LearningRateScheduler(lr_schedul, verbose=1) 30 31 adam = Adam(learning_rate=lr) 32 model.compile(loss='categorical_crossentropy', optimizer=adam, metrics=['accuracy']) 33 34 35 try: 36 # メモリ使用量はモデル構造、入力サイズ、バッチサイズに依存 37 H = model.fit(x_train, y_train, 38 epochs=epochs, 39 verbose=1, 40 steps_per_epoch = math.ceil(num_train/batch_size), 41 validation_data=(x_test, y_test), 42 callbacks=[early_stopping, model_checkpoint, lr_scheduler]) 43 44 part = f_elem.split('/')[1] 45 M_path = 'Model/{}/{}_{}_{}_{}_model_{}.h5'.format(f_elem, batch_size, lr, s, m, part) 46 model.save(M_path) 47 48 #テストデータで精度を確認 49 score = model.evaluate(x_test, y_test) 50 51 #score[0]はloss 52 return score[0] # val_lossが最小であるモデルを探す 53 54 except Exception as e: 55 print(f'モデル定義内でエラー:{e}が発生') 56 57 58def objective(trial): 59 param = { 60 'lr':trial.suggest_float('lr', 1e-6, 1e-2, log=True), 61 'batch_size':trial.suggest_categorical('batch_size', [16, 32, 64]), 62 's':trial.suggest_float('s', 10, 50, log=False), 63 'm':trial.suggest_float('m', 0.0, 1.0, log=False) 64 } 65 66 val_loss = trainer(**param) # 各実行結果のval_lossの値を返す 67 68 return val_loss
上記のプログラムの実行の後,以下を実行すると先ほどのエラーが発生しました.
python
1num_train = len(x_train) 2num_valid = len(x_test) 3 4y_train = tf.cast(y_train, dtype='float32') 5y_test = tf.cast(y_test, dtype='float32') 6 7# optunaによるパラメータの最適化 8study = optuna.create_study(direction="minimize") 9study.optimize(objective, n_trials=100) # 何回実行するか
なお使用しているデータのshapeは以下のようになっています.
x_train.shape → (1566, 110, 110, 1)
y_train.shape → (1566,)
x_test.shape → (88, 110, 110, 1)
y_test.shape → (88,)
input_shape → (110, 110, 1)
試したこと
現在model.fitでエラーが発生しており,私が作成したモデルは2つの入力を想定しているのに対し,受け取った入力は一つしかないためエラーが発生した,というところまでは分かっています.
しかし,model.fitに渡したデータはx_train, y_trainと,2つの入力を与えているのにこのようなエラーが発生しているため自分ではなぜこのようなエラーが発生したのかが分かりません.
どなたかこのエラーの原因と改善方法を教えていただけますと助かります.
どうかよろしくお願いします.
補足情報(FW/ツールのバージョンなど)
ubuntu 20.04
Python 3.8.10
tensorflow-gpu 2.5.3
keras 2.8.0
numpy 1.19.5
jupyter lab 2.3.2
回答1件
あなたの回答
tips
プレビュー