MNISTの0〰9数字を分類で学習がうまくいかないです。
解決したいこと
Python3でDL(おそらく初歩的な)をスクラッチで書いています。
softmax関数のコードが間違っているのか、学習が進みません。
どなたか教えていただけませんでしょうか。
初心者ですので、まるまるコードを載せます。
発生している問題・エラー
RuntimeWarning: invalid value encountered in subtract x = x-np.max(x,axis=0)
該当するソースコード
import csv
import os
import pickle
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import cv2
from sklearn import datasets
from sklearn.model_selection import train_test_split
%matplotlib inline
np.random.seed(seed=0)
#ここでエラーが出ているようです。
def softmax(x):
x = x.T
x = x-np.max(x,axis=0)
x = np.exp(x)/np.sum(np.exp(x))
return x.T
# mnistデータセット
mnist = datasets.fetch_openml('mnist_784', as_frame=False)
# 画像とラベルを取得
X, T = mnist.data, mnist.target
# 訓練データとテストデータに分割
X_train, X_test, T_train, T_test = train_test_split(X, T, test_size=0.2)
T_train = np.eye(10)[T_train.astype("int")]
T_test = np.eye(10)[T_test.astype("int")]
def cross_entropy_error(t, y):
delta = 1e-8
error = -np.mean(t * np.log(y + delta))
return error
class SoftmaxCrossEntropyLoss():
def __init__(self):
self.y = None
self.t = None
self.loss = None
def __call__(self, t, y):
self.y = softmax(y)
self.t = t.copy()
self.loss = cross_entropy_error(self.t, self.y)
return self.loss
def backward(self):
batch_size = self.t.shape[0]
dy = self.y - self.t
dy /= batch_size
return dy
class FullyConnectedLayer():
def __init__(self, input_shape, output_shape):
self.w = np.random.randn(input_shape, output_shape) * 0.01
self.b = np.zeros(output_shape, dtype=np.float)
self.x = None
self.dw = None
self.db = None
def __call__(self, x):
self.x = x
out = np.dot(x,self.w)+self.b
return out
def backward(self, dout):
dx = np.dot(dout,np.transpose(self.w))
batch_size = dx.shape[0]
self.dw = np.dot(np.transpose(self.x),dout)
self.db = np.sum(dout,axis=0)
return dx
class ReLU():
def __init__(self):
self.mask = None
def __call__(self, x):
self.mask = (x <= 0)
out = x.copy()
out[self.mask]=0
return out
def backward(self, dout):
dout[self.mask]=0
dx = dout
return dx
class MLP_classifier():
def __init__(self):
'''
x -> fc(784, 256) -> relu -> fc(256, 256) -> relu -> fc(256, 10) -> out
'''
# 層
self.fc1 = FullyConnectedLayer(784, 256)
self.relu1 = ReLU()
self.fc2 = FullyConnectedLayer(256, 256)
self.relu2 = ReLU()
self.fc3 = FullyConnectedLayer(256, 10)
self.out = None
# 損失関数の定義
self.criterion = SoftmaxCrossEntropyLoss()
def forward(self, x):
'''
順伝播
'''
x = self.relu1(self.fc1(x))
x = self.relu2(self.fc2(x))
self.out = self.fc3(x)
return self.out
def backward(self, t):
'''
逆伝播
'''
# 誤差を計算
loss = self.criterion(t, self.out)
# 勾配を逆伝播
d = self.criterion.backward()
d = self.fc3.backward(d)
d = self.relu2.backward(d)
d = self.fc2.backward(d)
d = self.relu1.backward(d)
d = self.fc1.backward(d)
return loss
def optimize_GradientDecent(self, lr):
'''
勾配降下法による全層のパラメータの更新
'''
for fc in [self.fc1, self.fc2, self.fc3]:
fc.w -= lr * fc.dw
fc.b -= lr * fc.db
# モデルの宣言
model = MLP_classifier()
# 学習率
lr = 0.005
# 学習エポック数
n_epoch = 20
for n in range(n_epoch):
# 訓練
y = model.forward(X_train)
loss = model.backward(T_train)
model.optimize_GradientDecent(lr)
# テスト
y = model.forward(X_test)
test_loss = model.backward(T_test)
pred = softmax(y)
accuracy = np.mean(np.equal(np.argmax(y, axis=1), np.argmax(T_test, axis=1)))
print(f'EPOCH {n + 1} | TRAIN LOSS {loss:.5f} | TEST LOSS {test_loss:.5f} | ACCURACY {accuracy:.2%}')
classification_accuracy = accuracy
自分で試したこと
例題を元に作っており、正直どこをどう直していいのか分からないです。
softmaxの中は、axisを変えたり、計算を一つづつ書きくださしたりしましたが、
学習が進まないことに変わりありませんでした。