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

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

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

PyTorchは、オープンソースのPython向けの機械学習ライブラリ。Facebookの人工知能研究グループが開発を主導しています。強力なGPUサポートを備えたテンソル計算、テープベースの自動微分による柔軟なニューラルネットワークの記述が可能です。

CNN (Convolutional Neural Network)

CNN (Convolutional Neural Network)は、全結合層のみではなく畳み込み層とプーリング層で構成されるニューラルネットワークです。画像認識において優れた性能を持ち、畳み込みニューラルネットワークとも呼ばれています。

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

受付中

PyTorchで構築したCNNにおける推論の結果がすべて同じになる

Daiking0215
Daiking0215

総合スコア0

PyTorch

PyTorchは、オープンソースのPython向けの機械学習ライブラリ。Facebookの人工知能研究グループが開発を主導しています。強力なGPUサポートを備えたテンソル計算、テープベースの自動微分による柔軟なニューラルネットワークの記述が可能です。

CNN (Convolutional Neural Network)

CNN (Convolutional Neural Network)は、全結合層のみではなく畳み込み層とプーリング層で構成されるニューラルネットワークです。画像認識において優れた性能を持ち、畳み込みニューラルネットワークとも呼ばれています。

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

1回答

0グッド

0クリップ

323閲覧

投稿2022/11/04 13:03

編集2022/11/07 02:52

前提

研究で画像からその物体の固有値を算出するCNNの構築を試みています.入力として224*224ixelの画像を,出力として一次モードの固有値をもつネットワークです.構造はVGG19を参考に作り,損失関数にはMAEを使用しています.損失関数のhistoryを見る限り学習が進んでいるようにみえるのですが,学習終了後にいくつかのデータを与えても同じ出力しか返ってきません.おそらく重みパラメータが更新されていないorどこかでリセット(すべての重みが0でその先の出力が同じになっている)のではないかと疑っています.
試しに

model.state_dict()

でパラメータの中身を確認してみましたが,原因が見つかりませんでした...

実現したいこと

各入力に対して異なる出力値を受け取ること.

発生している問題・エラーメッセージ

以下はいくつかのデータを使って推論した出力です.複数のデータに対して同じ出力となっています.

>>> y_eval tensor([[-0.0040], [-0.0040], [-0.0040], [-0.0040], 中略 [-0.0040], [-0.0040], [-0.0040], [-0.0040]], device='cuda:0', grad_fn=<AddmmBackward0>)

該当のソースコード

ベタ付ですみません..

Python

1import numpy as np 2import torch 3import torch.nn as nn 4import torch.nn.functional as F 5import torch.optim as optim 6from torchsummary import summary 7import torchvision 8from sklearn.model_selection import train_test_split 9import matplotlib.pyplot as plt 10import time 11 12#Parameter 13DATA_DIR = "../../../pinn/data/supervised/" 14TEST_SIZE = 0.2 15BATCH_SIZE = 1 16LEARNING_RATE = 0.001 17EPOCH = 200 18PIXEL = 224 19 20#Select device 21def get_device(use_gpu): 22 if use_gpu and torch.cuda.is_available(): 23 torch.backends.cudnn.deterministic = True 24 return torch.device("cuda") 25 26 else: 27 return torch.device("cpu") 28device = get_device(use_gpu=True) 29 30 31#Input & Output 32X = np.load(DATA_DIR + "input.npy") 33X = np.reshape(X, (X.shape[0], 1, PIXEL, PIXEL)) 34X = torch.tensor(X, dtype=torch.float) 35y = np.load(DATA_DIR + "output.npy") 36y = np.reshape(y, (y.shape[0], 1)) 37y = torch.tensor(y, dtype=torch.float) 38X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=TEST_SIZE, random_state=0) 39 40train_dataset = torch.utils.data.TensorDataset(X_train, y_train) 41train_dataset = torch.utils.data.DataLoader(train_dataset, batch_size=BATCH_SIZE, shuffle=True) 42test_dataset = torch.utils.data.TensorDataset(X_test, y_test) 43test_dataset = torch.utils.data.DataLoader(test_dataset, batch_size=BATCH_SIZE, shuffle=True) 44 45#Make Model 46class VGG19(nn.Module): 47 def __init__(self, input_image_channels): 48 super(VGG19, self).__init__() 49 self.conv1 = nn.Conv2d(input_image_channels, 64, kernel_size=(3, 3), stride=(1, 1), padding=1) 50 self.conv2 = nn.Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=1) 51 self.conv3 = nn.Conv2d(64, 128, kernel_size=(3, 3), stride=(1, 1), padding=1) 52 self.conv4 = nn.Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=1) 53 self.conv5 = nn.Conv2d(128, 256, kernel_size=(3, 3), stride=(1, 1), padding=1) 54 self.conv6_1 = nn.Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=1) 55 self.conv6_2 = nn.Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=1) 56 self.conv6_3 = nn.Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=1) 57 self.conv7 = nn.Conv2d(256, 512, kernel_size=(3, 3), stride=(1, 1), padding=1) 58 self.conv8_1 = nn.Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=1) 59 self.conv8_2 = nn.Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=1) 60 self.conv8_3 = nn.Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=1) 61 self.conv8_4 = nn.Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=1) 62 self.conv8_5 = nn.Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=1) 63 self.conv8_6 = nn.Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=1) 64 self.conv8_7 = nn.Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=1) 65 66 self.max_pool_1 = nn.MaxPool2d(kernel_size=(2, 2), stride=(2, 2)) 67 self.max_pool_2 = nn.MaxPool2d(kernel_size=(2, 2), stride=(2, 2)) 68 self.max_pool_3 = nn.MaxPool2d(kernel_size=(2, 2), stride=(2, 2)) 69 self.max_pool_4 = nn.MaxPool2d(kernel_size=(2, 2), stride=(2, 2)) 70 self.max_pool_5 = nn.MaxPool2d(kernel_size=(2, 2), stride=(2, 2)) 71 72 # self.bn1 = nn.BatchNorm2d(64) 73 # self.bn2 = nn.BatchNorm2d(128) 74 # self.bn3 = nn.BatchNorm2d(256) 75 # self.bn4 = nn.BatchNorm2d(512) 76 77 self.fc1 = nn.Linear(56*56*128, 1000) 78 self.fc2 = nn.Linear(1000, 100) 79 self.fc3 = nn.Linear(100, 10) 80 self.fc4 = nn.Linear(10, 1) 81 # self.fc5 = nn.Linear(16, 1) 82 83 def forward(self, x): 84 x = F.relu(self.conv1(x)) 85 x = F.relu(self.conv2(x)) 86 x = self.max_pool_1(x) 87 88 x = F.relu(self.conv3(x)) 89 x = F.relu(self.conv4(x)) 90 x = self.max_pool_2(x) 91 92 x = F.relu(self.conv5(x)) 93 x = F.relu(self.conv6_1(x)) 94 x = F.relu(self.conv6_2(x)) 95 x = F.relu(self.conv6_3(x)) 96 x = self.max_pool_3(x) 97 98 x = F.relu(self.conv7(x)) 99 x = F.relu(self.conv8_1(x)) 100 x = F.relu(self.conv8_2(x)) 101 x = F.relu(self.conv8_3(x)) 102 x = self.max_pool_4(x) 103 104 x = F.relu(self.conv8_4(x)) 105 x = F.relu(self.conv8_5(x)) 106 x = F.relu(self.conv8_6(x)) 107 x = F.relu(self.conv8_7(x)) 108 x = self.max_pool_5(x) 109 110 x = x.view(-1, 56*56*128) 111 x = F.relu(self.fc1(x)) 112 x = F.relu(self.fc2(x)) 113 x = F.relu(self.fc3(x)) 114 x = self.fc4(x) 115 return x 116 117class MAELoss(nn.Module): 118 def __init__(self): 119 super(MAELoss, self).__init__() 120 121 def forward(self, outputs, targets): 122 123 loss = torch.mean(torch.abs(outputs - targets)) 124 return loss 125 126# Model Check 127model = VGG19(1).to(device) 128summary(model, input_size=(1, 224, 224)) 129 130# Loss & Optimizer 131loss_fn = MAELoss() 132optimizer = optim.SGD(model.parameters(), lr=LEARNING_RATE) 133 134train_loss_value=[] 135train_eval_value=[] 136test_loss_value=[] 137test_eval_value=[] 138 139# Compile 140for epoch in range(EPOCH): 141 model.train() 142 running_train_loss = 0.0 143 144 torch.cuda.synchronize() 145 start = time.time() 146 with torch.set_grad_enabled(True): 147 for (input, true) in train_dataset: 148 input, true = input.to(device), true.to(device) 149 optimizer.zero_grad() 150 output = model(input) 151 loss = loss_fn(output, true) 152 running_train_loss += loss.item() 153 loss.backward() 154 optimizer.step() 155 156 train_loss_value.append(running_train_loss * BATCH_SIZE / len(train_dataset)) 157 158 model.eval() 159 running_test_loss = 0.0 160 with torch.set_grad_enabled(False): 161 for (input, true) in test_dataset: 162 input, true = input.to(device), true.to(device) 163 optimizer.zero_grad() 164 output = model(input) 165 loss = loss_fn(output, true) 166 running_test_loss += loss.item() 167 168 test_loss_value.append(running_test_loss * BATCH_SIZE / len(test_dataset)) 169 170 torch.cuda.synchronize() 171 elapsed_time = time.time() - start 172 y_eval = model(X.to(device)) 173 print(y_eval) 174 print('#EPOCH:{}\ttrain loss: {}\tvalid loss: {}\ttime: {}'.format(epoch, running_train_loss * BATCH_SIZE / len(train_dataset), running_test_loss * BATCH_SIZE / len(test_dataset), elapsed_time)) 175 176model.eval() 177y_eval = model(X.to(device)) 178print(y_eval)

試したこと

構造を2層の全結合層からなる簡単なNNに変更したり,最適化手法・損失関数等を変更したりさまざまなパラメータをいじりましたが,出力値はすべてのデータに対して同じになってしまいました.そのときの重みやバイアスを見たところ最後のバイアスのみ値が変化し,それ以外の重みやバイアスは全て0となっていました.おそらく学習の過程でパラメータの更新がうまく行っていないのだと予測してはいますがどこで問題が起きているのか皆目検討も付きません.よろしくお願いいたします.

補足情報(FW/ツールのバージョンなど)

PyTorch 1.12.0+cu116
Python 3.8.10

以下のような質問にはグッドを送りましょう

  • 質問内容が明確
  • 自分も答えを知りたい
  • 質問者以外のユーザにも役立つ

グッドが多くついた質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

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

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

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

下記のような質問は推奨されていません。

  • 間違っている
  • 質問になっていない投稿
  • スパムや攻撃的な表現を用いた投稿

適切な質問に修正を依頼しましょう。

jbpb0

2022/11/04 13:19 編集

> 学習終了後にいくつかのデータを与えても同じ出力しか返ってきません. 学習に使った画像を入力したら、どうなるのでしょうか? もしそれでも出力が画像によらず同じなら、学習前のネットワークにも入力してみてください > 損失関数のhistoryを見る限り学習が進んでいるようにみえる ネットワークが学習前/後かに無関係に、学習に使った画像でも常に同じ値が出力されるのなら、historyと矛盾するので、評価の計算方法がおかしいのかもしれません ネットワークが学習前/後かで結果は変わるけど、学習後のネットワークだと学習に使った画像でも常に同じ値が出力されるのなら、学習がうまくいってないのかも でも、それだとhistoryで良くならないような (学習後ネットワークに学習画像を入力した時の出力から計算したlossと、historyの最終のlossは、だいたい一致するか?)
Daiking0215

2022/11/04 13:49

jbpb0さん ありがとうございます. 学習後に,学習で使った画像を入力したところ同様に同じ結果が返ってきました. また学習前にモデルに入れても同じ出力が返ってきました.(それぞれ別の値) なので学習で何かしらパラメータは変化している一方で,どこかでリセット(パラメータが全部0など?)されてしまっているのかなと思います. >ネットワークが学習前/後かに無関係に、学習に使った画像でも常に同じ値が出力されるのなら、historyと矛盾するので、評価の計算方法がおかしいのかもしれません そこで評価関数をPyTorchの組み込みの関数L1Loss()で試してみても学習が進んでいるように見えました... >学習後ネットワークに学習画像を入力した時の出力から計算したlossと、historyの最終のlossは、だいたい一致するか? 全く同じ値になりました..
PondVillege

2022/11/04 14:06

self.conv6とself.conv8は重み共有しまくっていますが,ここをちゃんと分けたら治る,わけではないのですか? 特にself.conv8を何度も通してしまったがため,このレイヤで同じ入出力に収束した説が考えられます.
Daiking0215

2022/11/04 14:12

ps_aux_grepさん ありがとうございます. 盲点でした.. self.conv8_1,self.conv8_2...などと再定義し直してもう一度試してみましたが,結果は変わりませんでした.しかし,どちらにせよ重みを共有しまくっているのは初歩的な大問題でした..ありがとうございます.
jbpb0

2022/11/04 14:29

> 学習前にモデルに入れても同じ出力が返ってきました. 学習する前からそうなら、変な学習がされてるのではなく、画像の違いが消えてしまうような処理が(学習とは無関係に)どこかでされてる、ってことですかね
Daiking0215

2022/11/04 15:38

もしかしたらそうかもしれません 教師データのところから見直してみる必要があるかもですね.. ありがとうございます.
PondVillege

2022/11/04 16:40

conv8に関して直したとおっしゃってましたが,conv6も直したってことで間違いないですか?
Daiking0215

2022/11/05 06:54

はい,直しました. そののち,構造をCNNでなく全結合の単純な構造で試したところすべての重みが0になっていて,最後のバイアスのみ値が更新されているようでした.. なので構造に問題があるわけではなさそうです...
Daiking0215

2022/11/05 08:03

conv6,8がやはり怪しいと思いこれらの層を消しconv4までで試してみたところ正常に学習が進みました(予測の結果がデータによって変わりました.) ps_aux_grepさんがおっしゃっていたようにconv6で収束してしまっていたようです.しかしconv6_1,conv_2..と変更しても未だに収束してしまうのはなぜなのでしょうか...
jbpb0

2022/11/05 11:12 編集

> conv4までで試してみたところ正常に学習が進みました(予測の結果がデータによって変わりました.) のコードと、 > conv6_1,conv_2..と変更しても未だに収束してしまう の(直したはずなのにうまくいかない)コードを、質問を編集して追記してください (全部じゃなくて、変更点のみでもいいです) 上記の「直したはずなのにうまくいかないコード」で学習前の状態では、別の入力データでの出力は同じ/違うのどちらでしょうか? > 構造をCNNでなく全結合の単純な構造で試した のコードでは、別の入力データでの出力は同じ/違うのどちらでしょうか? (学習前/後のそれぞれで)
PondVillege

2022/11/05 10:55

PyTorchのMaxPooling2Dの動作は存じ上げませんが,もしかしたらMaxPool2Dも1つしか用意していないのが悪い,とかもあり得そうですね.対応するMaxUnPool2Dのために保持する情報とかもあったりするので,ここも使うだけ用意するなどやってみる必要がありそうですね.
jbpb0

2022/11/07 00:37

> 重みやバイアスを見たところ最後のバイアスのみ値が変化し,それ以外の重みやバイアスは全て0となっていました.おそらく学習の過程でパラメータの更新がうまく行っていないのだと予測してはいます 学習の問題なら、学習前のネットワークでは問題は起きないと思うのですが、 > 学習前にモデルに入れても同じ出力が返ってきました. ですよね ネットワークを定義しただけで学習してない状態では、重みやバイアスはランダムに初期化されてると思うのですが、実際はそうなってないのでしょうか?
jbpb0

2022/11/07 00:46

> 構造を2層の全結合層からなる簡単なNNに変更したり, の状態では、cnnではないのだから、 > self.conv6とself.conv8は重み共有しまくっています とか、 > MaxPool2Dも1つしか用意していない とかは、(全結合層だけなので)その時には発生してないはずですが、その場合でも、 > 出力値はすべてのデータに対して同じになってしまいました. となるなら、 > conv4までで試してみたところ正常に学習が進みました(予測の結果がデータによって変わりました.) となるのが不思議です cnnなら「conv4まで」で大丈夫だけど、cnnではない「2層の全結合層だけ」だとダメ?
Daiking0215

2022/11/07 03:09

> cnnなら「conv4まで」で大丈夫だけど、cnnではない「2層の全結合層だけ」だとダメ? まさにこの通りで何が原因なのか全く分からなくなってしまいました. 他のデータセットで試した(以前kerasで開発していた時のデータセット)際にも同じようにうまく行きませんでした.
PondVillege

2022/11/07 03:26

入力画像のレンジが広すぎる,というのはどうでしょうか 画像の前処理が不明なので推測で話しますが,もし0~255の値域の画像データXならカーネルの感度が高くなって異常な学習になるかと思いました. np.reshape前後で X = X / 127.5 - 1 とすると値域を[-1, 1]にできます. ネットワークサイズ増大で予測値が収束してしまう,という観点からだと,VGG16が大きすぎて,メモリの範囲外参照による0値取得が生じ,計算不可で予測値が同じになった説とかも考えられます. 使われているGPUのメモリサイズの確認をお願いします. いずれにせよ,コードからはわからない別要因の可能性が高くなってきました
Daiking0215

2022/11/07 04:37

画像データは/255.0で[0,1]の値域を持つグレースケール画像です. GPUはGeForce RTX3090でメモリサイズは24GBです. そうですね..1から全部戻って確認してみます..
jbpb0

2022/11/07 04:57 編集

現在の質問のコードで、 X = np.load(DATA_DIR + "input.npy") X = np.reshape(X, (X.shape[0], 1, PIXEL, PIXEL)) ↓ 変更 X = np.random.rand(10, 1, PIXEL, PIXEL) y = np.load(DATA_DIR + "output.npy") y = np.reshape(y, (y.shape[0], 1)) ↓ 変更 y = np.random.rand(10, 1) としてデータをでっち上げて、学習前の状態でどうなるのか確認しようと、 > # Compile for epoch in range(EPOCH): のforループを全部削除して、google colabでgpu有りで実行したら、 > RuntimeError Traceback (most recent call last) <ipython-input-4-dd543cf6ed01> in <module> 129 # Model Check 130 model = VGG19(1).to(device) --> 131 summary(model, input_size=(1, 224, 224)) 132 133 # Loss & Optimizer 2 frames <ipython-input-4-dd543cf6ed01> in forward(self, x) 111 x = self.max_pool_5(x) 112 --> 113 x = x.view(-1, 56*56*128) 114 x = F.relu(self.fc1(x)) 115 x = F.relu(self.fc2(x)) RuntimeError: shape '[-1, 401408]' is invalid for input of size 50176 というエラーになります データの作り方が間違えてますか? 質問者さんの環境では、現在の質問のコードで、上記のエラーは出ないのですよね?
Daiking0215

2022/11/07 04:51 編集

すみません. x = x.view(-1, 56*56*128) を x = x.view(-1, 7*7*512) に, self.fc1 = nn.Linear(56*56*128, 1000) を self.fc1 = nn.Linear(7*7*512, 1000) に変更していただきますと動くと思います.
jbpb0

2022/11/07 07:27 編集

質問のコードが動いたので、 X = np.random.rand(10, 1, PIXEL, PIXEL) X[0] = np.zeros((1, PIXEL, PIXEL)) X[0, 0, :, :int(PIXEL/2)] = 1 X[1] = np.zeros((1, PIXEL, PIXEL)) X[1, 0, :int(PIXEL/2), :] = 1 として最初の2枚を特徴的な画像にして、それと3枚目(乱数)が、学習前の各層の出力でどうなるのかを、 https://pystyle.info/pytorch-extract-intermediate-layer-output/ のコードを使って目視比較確認しました 以下、上記Webページのコードの引用部分を説明します 「In [4]:」はそのまま 「In [5]:」は下記を変更 target_module = model.features[3] ↓ 変更 (「conv1」のところをいろいろ変える) target_module = model.conv1 features = extract(target_module, inputs) ↓ 変更 features = extract(target_module, X.to(device)) 「In [6]:」は下記を変更 (3枚の入力画像の、先頭の4つのフィルタでの出力結果を目視比較) img = feature_to_img(features[0][:16]) img ↓ 変更 img = feature_to_img(features[0][:4]) display(img) img = feature_to_img(features[1][:4]) display(img) img = feature_to_img(features[2][:4]) display(img) 実行結果ですが、「target_module = model.conv1」では3枚の違いがはっきりと分かりますが、「target_module = model.conv6_3」では違いが分かりにくくなり、「target_module = model.conv7」では目視では違いがほとんど分かりません(よーく見たらうっすら分かる) 「target_module = model.conv8_1」ではよーく見ても違いが分かりません 厳密な数値比較ではなく目視比較レベルですが、ネットワークの後段の層では、かなり違う入力画像でも層の出力が同じになってます 上記は全て、学習前の、重みやバイアスはランダムに初期化されてる状態です 念の為に、下記を実行して確認したら、ランダムな数値が入ってました for param in model.parameters(): print(param)
PondVillege

2022/11/07 06:39

レイヤごとに値が減少している,という状態なら,コメントアウトしているバッチ正規化を畳み込み直後に挿入するのはどうでしょう. 他の実装例を見ると https://blog.paperspace.com/vgg-from-scratch-pytorch/ https://github.com/msyim/VGG16/blob/master/VGG16.py#L42 https://github.com/pytorch/vision/blob/main/torchvision/models/vgg.py#L82 <- これに関してはtorchvisionから利用できるので使ってみると良い. 一旦,フルスクラッチVGGをやめて,torchvisionのVGG16 https://pytorch.org/vision/master/models/generated/torchvision.models.vgg16.html を使って異常がないことを確認することで,モデルが悪いのか,学習方法やデータセットが悪いのかなど,原因の切り分けができると思います.
jbpb0

2022/11/07 09:28 編集

> 一旦,フルスクラッチVGGをやめて,torchvisionのVGG16 https://pytorch.org/vision/master/models/generated/torchvision.models.vgg16.html を使って異常がないことを確認する X = np.random.rand(10, 3, PIXEL, PIXEL) として3chのデータをでっち上げて、 model = VGG19(1).to(device) ↓ 変更 model = torchvision.models.vgg19(num_classes=1, init_weights=False).to(device) summary(model, input_size=(1, 224, 224)) ↓ 変更 (こちらも3chに) summary(model, input_size=(3, 224, 224)) として、学習前の状態で推論実行したら、入力によらず同じ出力になりました X = np.random.rand(10, 3, PIXEL, PIXEL) X[0] = np.zeros((3, PIXEL, PIXEL)) X[0, :, :, :int(PIXEL/2)] = 1 X[1] = np.zeros((3, PIXEL, PIXEL)) X[1, :, :int(PIXEL/2), :] = 1 として最初の2枚を特徴的な画像にした場合でも、その2枚も出力は同じでした 各層の出力を目視比較すると、「target_module = model.features[20]」までは違いが分かりましたが、「target_module = model.features[21]」以降は違いが分かりませんでした
Daiking0215

2022/11/07 08:48

ps_aux_grepさんが教えてくださったurlの https://github.com/msyim/VGG16/blob/master/VGG16.py#L42 で実行してみたところおそらく正常に動き,出力値が一定になる問題が解決しました. やはり構造の定義に問題があったようです.正直まだ原因はわかりきっていませんが,やはり重みパラメータが共有されてしまっていたのかと思います.それと近い理由で単純な全結合層でもパラメータがすべて0になるという減少が発生していたようです. みなさまありがとうございました.
jbpb0

2022/11/07 09:29 編集

> https://github.com/msyim/VGG16/blob/master/VGG16.py#L42 で実行してみたところおそらく正常に動き,出力値が一定になる問題が解決しました. vgg19じゃなくてvgg16だと大丈夫なのかな? と思って model = torchvision.models.vgg16(num_classes=1, init_weights=False).to(device) でやってみましたが(入力データは3ch)、こちらも学習前のネットワークでの推論はダメで、データによらず同じ出力になりました
jbpb0

2022/11/07 09:56 編集

これではないですか? https://qiita.com/siruku6/items/5435f4e52c9cfa6cdda4 試しに「init_weights=True」を付けたら、下記のどちらでも大丈夫でした (入力データで出力が変わる) model = torchvision.models.vgg19(num_classes=1, init_weights=True).to(device) model = torchvision.models.vgg16(num_classes=1, init_weights=True).to(device) 質問者さんのコードも、上記Webページで解説されてるような重み初期化のコードを追加したら、うまくいくかもしれません 【追記】 この質問のコードの、「class VGG19(nn.Module):」の「def __init__(self, input_image_channels):」の最後に、 https://github.com/pytorch/vision/blob/main/torchvision/models/vgg.py#L53-L63 の53〜63行目の「for m in self.modules():」のforループ for m in self.modules(): if isinstance(m, nn.Conv2d): nn.init.kaiming_normal_(m.weight, mode="fan_out", nonlinearity="relu") if m.bias is not None: nn.init.constant_(m.bias, 0) elif isinstance(m, nn.BatchNorm2d): nn.init.constant_(m.weight, 1) nn.init.constant_(m.bias, 0) elif isinstance(m, nn.Linear): nn.init.normal_(m.weight, 0, 0.01) nn.init.constant_(m.bias, 0) を、インデントだけ合わせてそのまま追加して、学習前のネットワークで推論させたら、入力データで出力が変わりました そこからスタートしたら、学習もできるかも
Daiking0215

2022/11/08 01:26

皆様ありがとうございます. 皆様の意見および下記URLを参考に,初期値と構造を見直したところ無事エラーなく動きました!精度に課題はあるものの推論もできていそうです.ありがとうございます. https://pystyle.info/pytorch-vgg/#outline__2
jbpb0

2022/11/22 07:48 編集

ニューラルネットがディープな場合は、重みの初期値が不適切だとうまく学習できない(場合がある)ということは、知識はありましたが、今回の質問で確かにそうなんだなと実感しました
PondVillege

2022/11/08 03:34 編集

初期値によってはレイヤごとに分散が増大/減少するのでHe Kaimingの初期値を利用しなければならないのかなと思ってググッてはみたものの,既に適用されてるみたいな記事を見つけてそのまま鵜呑みにした私も悪かったですね,まさかデフォルトでLeCunの初期値だとは… https://discuss.pytorch.org/t/how-are-layer-weights-and-biases-initialized-by-default/13073 LeCunの初期値 → カンで経験的に決めた適当な重み分散 GlolotXavierの初期値 → 活性化関数tanh用に論理的に求めた重み分散 HeKaimingの初期値 → 活性化関数LeRU用に論理的に求めた重み分散 であること覚えておくと良いでしょう

回答1

良いと思った回答にはグッドを送りましょう。
グッドが多くついた回答ほどページの上位に表示されるので、他の人が素晴らしい回答を見つけやすくなります。

下記のような回答は推奨されていません。

  • 間違っている回答
  • 質問の回答になっていない投稿
  • スパムや攻撃的な表現を用いた投稿

このような回答には修正を依頼しましょう。

まだベストアンサーが選ばれていません

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

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

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

ただいまの回答率
86.12%

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

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

質問する

関連した質問

同じタグがついた質問を見る

PyTorch

PyTorchは、オープンソースのPython向けの機械学習ライブラリ。Facebookの人工知能研究グループが開発を主導しています。強力なGPUサポートを備えたテンソル計算、テープベースの自動微分による柔軟なニューラルネットワークの記述が可能です。

CNN (Convolutional Neural Network)

CNN (Convolutional Neural Network)は、全結合層のみではなく畳み込み層とプーリング層で構成されるニューラルネットワークです。画像認識において優れた性能を持ち、畳み込みニューラルネットワークとも呼ばれています。

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。