前提
初心者です。
MNISTの0〰9数字を分類するコードをスクラッチで書いています。
実現したいこと
softmax関数の計算がおかしいようで学習が進ません。
class SoftmaxCrossEntropyLoss()の中で使っています。
softmaxの書き方が悪いのか、層の計算が間違っているのかも分かりません。
何んとなく怪しい箇所は、#怪しい と記載しました。
発生している問題・エラーメッセージ
RuntimeWarning: invalid value encountered in subtract x = x-np.max(x,axis=0)
該当のソースコード
Python3.9
1import csv 2import os 3import pickle 4import numpy as np 5import matplotlib.pyplot as plt 6from mpl_toolkits.mplot3d import Axes3D 7import cv2 8from sklearn import datasets 9from sklearn.model_selection import train_test_split 10%matplotlib inline 11np.random.seed(seed=0) 12 13 14#怪しい 15def softmax(x): 16 x = x.T 17 x = x-np.max(x,axis=0) 18 x = np.exp(x)/np.sum(np.exp(x)) 19 return x.T 20 21# mnistデータセット 22mnist = datasets.fetch_openml('mnist_784', as_frame=False) 23# 画像とラベルを取得 24X, T = mnist.data, mnist.target 25# 訓練データとテストデータに分割 26X_train, X_test, T_train, T_test = train_test_split(X, T, test_size=0.2) 27 28T_train = np.eye(10)[T_train.astype("int")] 29T_test = np.eye(10)[T_test.astype("int")] 30 31def cross_entropy_error(t, y): 32 delta = 1e-8 33 error = -np.mean(t * np.log(y + delta)) 34 return error 35 36class SoftmaxCrossEntropyLoss(): 37 def __init__(self): 38 self.y = None 39 self.t = None 40 self.loss = None 41 42 def __call__(self, t, y): 43 self.y = softmax(y) 44 self.t = t.copy() 45 self.loss = cross_entropy_error(self.t, self.y) 46 return self.loss 47 48 def backward(self): 49 batch_size = self.t.shape[0] 50 dy = self.y - self.t 51 dy /= batch_size 52 return dy 53 54class FullyConnectedLayer(): 55 def __init__(self, input_shape, output_shape): 56 self.w = np.random.randn(input_shape, output_shape) * 0.01 57 self.b = np.zeros(output_shape, dtype=np.float) 58 self.x = None 59 self.dw = None 60 self.db = None 61 62#怪しい 63 def __call__(self, x): 64 self.x = x 65 out = np.dot(x,self.w)+self.b 66 return out 67#怪しい 68 def backward(self, dout): 69 dx = np.dot(dout,np.transpose(self.w)) 70 batch_size = dx.shape[0] 71 self.dw = np.dot(np.transpose(self.x),dout) 72 self.db = np.sum(dout,axis=0) 73 return dx 74 75class ReLU(): 76 def __init__(self): 77 self.mask = None 78#怪しい 79 def __call__(self, x): 80 self.mask = (x <= 0) 81 out = x.copy() 82 out[self.mask]=0 83 return out 84#怪しい 85 def backward(self, dout): 86 dout[self.mask]=0 87 dx = dout 88 89 return dx 90 91class MLP_classifier(): 92 93 def __init__(self): 94 ''' 95 96 x -> fc(784, 256) -> relu -> fc(256, 256) -> relu -> fc(256, 10) -> out 97 ''' 98 99 # 層 100 self.fc1 = FullyConnectedLayer(784, 256) 101 self.relu1 = ReLU() 102 self.fc2 = FullyConnectedLayer(256, 256) 103 self.relu2 = ReLU() 104 self.fc3 = FullyConnectedLayer(256, 10) 105 self.out = None 106 107 # 損失関数の定義 108 self.criterion = SoftmaxCrossEntropyLoss() 109 110 def forward(self, x): 111 ''' 112 順伝播 113 ''' 114 115 x = self.relu1(self.fc1(x)) 116 x = self.relu2(self.fc2(x)) 117 self.out = self.fc3(x) 118 119 120 return self.out 121 122 def backward(self, t): 123 ''' 124 逆伝播 125 ''' 126 127 # 誤差を計算 128 loss = self.criterion(t, self.out) 129 # 勾配を逆伝播 130 d = self.criterion.backward() 131 d = self.fc3.backward(d) 132 d = self.relu2.backward(d) 133 d = self.fc2.backward(d) 134 d = self.relu1.backward(d) 135 d = self.fc1.backward(d) 136 137 return loss 138 139 def optimize_GradientDecent(self, lr): 140 ''' 141 勾配降下法による全層のパラメータの更新 142 ''' 143 for fc in [self.fc1, self.fc2, self.fc3]: 144 fc.w -= lr * fc.dw 145 fc.b -= lr * fc.db 146 147# モデルの宣言 148model = MLP_classifier() 149 150# 学習率 151lr = 0.005 152# 学習エポック数 153n_epoch = 20 154 155 156for n in range(n_epoch): 157 # 訓練 158 159 y = model.forward(X_train) 160 loss = model.backward(T_train) 161 model.optimize_GradientDecent(lr) 162 163 # テスト 164 y = model.forward(X_test) 165 test_loss = model.backward(T_test) 166 pred = softmax(y) 167 accuracy = np.mean(np.equal(np.argmax(y, axis=1), np.argmax(T_test, axis=1))) 168 print(f'EPOCH {n + 1} | TRAIN LOSS {loss:.5f} | TEST LOSS {test_loss:.5f} | ACCURACY {accuracy:.2%}') 169classification_accuracy = accuracy 170
試したこと
エラーがdef softmax()の中なので、その中はいくつか試しました。
補足情報(FW/ツールのバージョンなど)
初心者ですので、質問の仕方が不適切かと思いますが、
助けてください。
まずは順伝播の計算が合っていることを単純なデータで確認するのが先かと思います。あと、エラーではなくウォーニングかと思いますが。
https://teratail.com/help#posted-otherservice
に、
「解決した際には必ずteratail及びすべての投稿に解決した旨と、どのように解決したかを記載してください。」
と書かれてますので、
https://qiita.com/kobaq/questions/f2b8aa13f6d4d54669e9
の回答で解決したなら、その内容をこちらの回答に書いて「自己解決」にしてください
ご指導ありがとうございます。ルールを把握しておらず申し訳ありません。
正直、解決したか自信ありませんが、学習は完了できたので、その内容を投稿しておきます。

回答1件
あなたの回答
tips
プレビュー