質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Keras

Kerasは、TheanoやTensorFlow/CNTK対応のラッパーライブラリです。DeepLearningの数学的部分を短いコードでネットワークとして表現することが可能。DeepLearningの最新手法を迅速に試すことができます。

深層学習

深層学習は、多数のレイヤのニューラルネットワークによる機械学習手法。人工知能研究の一つでディープラーニングとも呼ばれています。コンピューター自体がデータの潜在的な特徴を汲み取り、効率的で的確な判断を実現することができます。

機械学習

機械学習は、データからパターンを自動的に発見し、そこから知能的な判断を下すためのコンピューターアルゴリズムを指します。人工知能における課題のひとつです。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

0回答

661閲覧

[ArcFace実装] Layerを削除したモデルを再構築したら出力結果が変わってしまった

harug

総合スコア28

Keras

Kerasは、TheanoやTensorFlow/CNTK対応のラッパーライブラリです。DeepLearningの数学的部分を短いコードでネットワークとして表現することが可能。DeepLearningの最新手法を迅速に試すことができます。

深層学習

深層学習は、多数のレイヤのニューラルネットワークによる機械学習手法。人工知能研究の一つでディープラーニングとも呼ばれています。コンピューター自体がデータの潜在的な特徴を汲み取り、効率的で的確な判断を実現することができます。

機械学習

機械学習は、データからパターンを自動的に発見し、そこから知能的な判断を下すためのコンピューターアルゴリズムを指します。人工知能における課題のひとつです。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

0クリップ

投稿2023/01/16 18:54

編集2023/01/17 14:08

前提

現在,pythonを用いてResNet50v2+ArcFaceのモデルを実装しています.
こちらのサイトと,こちらのコードを参考にしモデルを構築しました.

実現したいこと

いくつかありますので,要点を絞って説明します.

1, 学習は2入力,推論時は画像データのみの1入力のモデルに変更したい

→ 現在使用しているモデルでは学習データに,[画像データ,それに対応するone-hotベクトル化したクラスラベル]の2入力を必要とするモデルとなっているが,これでは推論時に,未知画像に対しそれに対応するクラスラベルもいちいち決めて入力しないといけない. そこで画像データのみの1入力のモデルに変更した方が利便性が向上すると考えたため,これを実現したい.

2, 距離学習によって学習された距離の値を取得したい

→ 入力画像に対し,それと一番類似する画像を距離学習によって得られた距離の値から取得したい. こちらに関して現在は,比較したい2つの画像をそれぞれ入力し,出力層手前の中間層からの出力(512次元の特徴量ベクトル)を用いてcos類似度によって類似度を定量的に評価することを考えている.
この方法よりも有用な方法があれば教えていただきたいです.

3, 入力画像に対する出力層のsoftmaxの値を取得したい

→ 最終的には推論時に正しいsoftmaxの値を取得したい.

該当のソースコード

現在使用しているソースコードを以下に示します.

python

1# 総クラス数,エポック数,入力画像のサイズを指定 2num_classes = 29 3epochs = 100 4height = 110 # 像のピクセル数(縦) 5width = 110 # 像のピクセル数(横)

python

1class Arcfacelayer(Layer): 2 # s:softmaxの温度パラメータ, m:margin 3 def __init__(self, output_dim, s, m, easy_margin=False): 4 self.output_dim = output_dim 5 self.s = s 6 self.m = m 7 self.easy_margin = easy_margin 8 super(Arcfacelayer, self).__init__() 9 10 def get_config(self): 11 config = { 12 "output_dim" : self.output_dim, 13 "s" : self.s, 14 "m" : self.m, 15 "easy_margin" : self.easy_margin 16 } 17 base_config = super().get_config() 18 return dict(list(base_config.items()) + list(config.items())) 19 20 21 # 重みの作成 22 def build(self, input_shape): 23 print(f'buildのinput_shape:{input_shape}') 24 # Create a trainable weight variable for this layer. 25 self.kernel = self.add_weight(name='kernel', 26 shape=(input_shape[0][1], self.output_dim), 27 initializer='uniform', 28 trainable=True) 29 super(Arcfacelayer, self).build(input_shape) 30 31 32 # mainの処理 33 def call(self, x): 34 35 y = x[1] 36 x_normalize = tf.math.l2_normalize(x[0]) # x = x'/ ||x'||2 37 k_normalize = tf.math.l2_normalize(self.kernel) # Wj = Wj' / ||Wj'||2 38 39 cos_m = K.cos(self.m) 40 sin_m = K.sin(self.m) 41 th = K.cos(np.pi - self.m) 42 mm = K.sin(np.pi - self.m) * self.m 43 44 cosine = K.dot(x_normalize, k_normalize) # W.Txの内積 45 sine = K.sqrt(1.0 - K.square(cosine)) 46 47 phi = cosine * cos_m - sine * sin_m #cos(θ+m)の加法定理 48 49 if self.easy_margin: 50 phi = tf.where(cosine > 0, phi, cosine) 51 52 else: 53 phi = tf.where(cosine > th, phi, cosine - mm) 54 55 # 正解クラス:cos(θ+m) 他のクラス:cosθ 56 output = (y * phi) + ((1.0 - y) * cosine) 57 output *= self.s 58 59 return output 60 61 def compute_output_shape(self, input_shape): 62 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", kernel_initializer="he_normal", 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 = Dense(num_classes, activation="softmax")(s_cos) 29 30 model = Model(inputs=[resnet50v2.input,yinput], outputs=prediction) 31 32 return model

現在は次のコードを用いてoptunaを使用し,val_lossを最適化した学習を行っています.

python

1# モデル定義 2def trainer(**param): 3 4 5 lr = param['lr'] 6 batch_size = param['batch_size'] 7 s = param['s'] 8 m = param['m'] 9 10 11 model = create_arcface_with_resnet50v2(input_shape, s, m) 12 13 14 # 自動的に学習をやめる 15 early_stopping = EarlyStopping(monitor='val_loss', 16 min_delta=0.0, 17 patience=3, 18 mode='min' 19 ) 20 # 最良の重みとモデルを保存 21 fpath = 'Weight/{}/{}_{}_{}_{}_({{epoch:02d}}-{{loss:.2f}}-{{accuracy:.2f}}-{{val_loss:.5f}}-{{val_accuracy:.2f}}).hdf5'.format(f_elem, batch_size, lr, s, m) 22 model_checkpoint = ModelCheckpoint(filepath=fpath, monitor='val_loss', save_best_only=True, mode='min') 23 # 学習中に学習率を調整 24 lr_scheduler = LearningRateScheduler(lr_schedul, verbose=1) 25 26 27 adam = Adam(learning_rate=lr) 28 model.compile(loss='categorical_crossentropy', optimizer=adam, metrics=['accuracy']) 29 30 31 32 try: 33 34 H = model.fit([x_train, y_train], y_train, # ここの[x_train, y_train]をx_trainにしたい 35 epochs=epochs, 36 verbose=1, 37 steps_per_epoch = math.ceil(len(x_train)/batch_size), 38 validation_data=([x_test, y_test], y_test), 39 callbacks=[early_stopping, model_checkpoint, lr_scheduler]) 40 41 part = f_elem.split('/')[1] 42 M_path = 'Model/{}/{}_{}_{}_{}_model_{}.h5'.format(f_elem, batch_size, lr, s, m, part) 43 model.save(M_path) 44 45 #テストデータで精度を確認 46 score = model.evaluate([x_test, y_test], y_test) 47 48 return score[0] # vall_lossが最小であるモデルを探すため 49 50 except Exception as e: 51 print(e)

なお使用しているデータのshapeは以下のようになっています.
x_train.shape → (1566, 110, 110, 1)
y_train.shape → (1566, 29) # one-hot

x_test.shape → (88, 110, 110, 1)
y_test.shape → (88, 29) # one-hot

input_shape → (110, 110, 1)

試したこと

推論時のモデルを画像データのみの1入力のモデルとするために,参考サイトを参考にモデルを再作成しました.
具体的には,以下のようにOputunaで最適化するために用いるモデルを,上記のモデルからArcFaceLayer以降の層を取り除いたモデルを推論用のモデルとしました.

python

1# 推論に使用 2def create_predict_model(input_shape): 3 # ResNet50V2の入力層の前に独自の入力層を追加 4 input_tensor = input_shape 5 print(input_tensor) 6 7 input_model = Sequential() 8 input_model.add(InputLayer(input_shape=input_tensor)) 9 input_model.add(Conv2D(3, (7, 7), padding='same')) 10 input_model.add(BatchNormalization()) 11 input_model.add(Activation('relu')) 12 13 resnet50v2 = ResNet50V2(include_top=False, weights=None, input_tensor=input_model.output) 14# DLしてある重みの読み込み 15 resnet50v2.load_weights('save_model(weights_imagenet)/weights_imagenet.hdf5', by_name=True) 16 17 18 flat = Flatten()(resnet50v2.layers[-1].output) 19 20 dense = Dense(512, activation="relu", kernel_initializer="he_normal", name="hidden")(flat) 21 22 x = BatchNormalization()(dense) 23 24 prediction = Dense(num_classes, activation="softmax")(x) 25 26 # ArcFaceLayerを削除 27 28 model = Model(inputs=resnet50v2.input, outputs=prediction) 29 30 return model

そしてこちらのモデルを用いて学習済みの重みをロード

python

1predict_model = create_predict_model(input_shape) 2predict_model.load_weights(W_path, by_name=True) # 一致する層だけ重みをロード(W_pathはcreate_arcface_with_resnet50v2()の学習で得た重みのパス)

predict_modelはcompileを行っていないためval_lossの値を取得することができないが

python

1y_pred = predict_model.predict(x_test) 2acc = tf.keras.metrics.categorical_accuracy(y_test, y_pred)

とすることで正解率を算出し,これをOputunaで最適化する指標とすることを考えました(できればval_lossが良いが..).
しかし,y_predの値はバラバラであり,predict_modelを用いて算出したこの正解率も0になってしまいました.

ちなみに,

python

1model = create_arcface_with_resnet50v2(input_shape, s=best_s, m=best_m) # best_sとbest_mはOputunaで最適化された値 2model.load_weights(W_path) # W_pathはcreate_arcface_with_resnet50v2()の学習で得た重みのパス 3 4y_pred = model.predict(x_test) 5acc = tf.keras.metrics.categorical_accuracy(y_test, y_pred)

で正解率を得るとほぼ100%の値が出力されます.

この原因として考えられることは,おそらく2入力のモデルを1入力に変更する過程で,create_predict_model() にロードした重みが正しくモデルに作用していないのではないかと考えますが,本当の原因が分かりません.

どなたか,create_predict_model()でcreate_arcface_with_resnet50v2() と同様に,正しくsoftmaxの値を取得できる方法を教えていただけますでしょうか.

補足情報(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

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだ回答がついていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問