Скорость обучения нейронной сети, ошибка деления, если слишком большая, не улучшение, если слишком маленькая
После написания простой нейронной сети я столкнулся с такой проблемой со скоростью обучения (я думаю, это вызвано lr). Для скорости обучения, меньшей или равной 10e-6, я быстро получаю ошибку "деление с плавающей запятой на ноль" - я предполагаю, что веса обновляются быстро, когда я пытался проверить минимальное значение для y_pred, я получил значение, равное 0 до 5 итераций (возможно, тогда мой код неверен). С другой стороны, как только я поставил скорость обучения равной 10e-7, ошибка с делением исчезла, однако теперь нет роста точности, а также потери меняются очень медленно, начиная с 3, 4 итерации.
Я попытался разделить наборы данных на обучающие / проверочные, также без разделения, но результат все еще очень похож. Найдите мой код ниже и сообщите, если я где-то ошибся или возникла другая проблема:
class Net:
def __init__(self, X, y, neurons, n_epochs):
self.X = X
self.y = y
self.neurons = neurons
self.n_epochs = n_epochs
self.learning_rate = 10e-6
def train_val_split(self, X, y, val_size):
perm = list(np.random.permutation(X.shape[0]))
split_index = int(X.shape[0] * val_size)
val_idxs = perm[:split_index]
train_idxs = perm[split_index:]
self.X_train = X[train_idxs]
self.y_train = y[train_idxs]
self.X_val = X[val_idxs]
self.y_val = y[val_idxs]
def weights(self):
np.random.seed(42)
self.weights = np.random.rand(self.neurons, 1)
self.bias = np.random.rand(1)
def sigmoid(self, x):
return 1/(1 + np.exp(-x.astype('float64')))
def sigmoid_deriv(self, x):
return self.sigmoid(x) * (1 - self.sigmoid(x))
def loss(self, y_pred, y):
nsample = len(y)
loss = -1/nsample * (np.sum(np.multiply(np.log(y_pred), y) + np.multiply((1 - y), np.log(1 - y_pred))))
return loss
def forward_step(self, X, y):
self.X_forward = X
self.y_forward = y
layer = self.X_forward.dot(self.weights) + self.bias
y_pred = self.sigmoid(layer)
loss = self.loss(y_pred, self.y_forward)
return y_pred, loss
def backpropagation_step(self, y_pred):
dloss_dy_pred = - (np.divide(self.y_forward, y_pred) - np.divide((1 - self.y_forward), (1 - y_pred)))
dy_pred_dlayer = self.sigmoid_deriv(y_pred)
dloss_dlayer = dloss_dy_pred.dot(dy_pred_dlayer)
X_T = self.X_forward.T
self.weights = self.weights - self.learning_rate * np.dot(X_T, dloss_dlayer)
self.bias = self.bias - self.learning_rate * np.sum(dloss_dlayer, axis=0)
def predict(self, X):
val_layer = X.dot(self.weights) + self.bias
val_y_pred = self.sigmoid(val_layer)
return val_y_pred
def train(self):
self.acc_sum = []
self.loss_sum = []
self.weights()
self.train_val_split(self.X, self.y, .1)
for i in range(self.n_epochs):
self.corr = []
y_pred, loss = self.forward_step(self.X_train, self.y_train)
self.backpropagation_step(y_pred)
self.loss_sum.append(loss)
self.pred = self.predict(self.X_val)
for j in range(len(self.pred)):
if np.round(self.pred)[j] == self.y_val[j]:
self.corr.append(1)
self.acc = str(np.round(np.sum(self.corr) / len(self.y_val) * 100, 2)) + "%"
if i % 10 == 0:
print("Epoch:", i, ", loss equal to:", loss, ". Accuracy: ", self.acc)
После 100 итераций я получил, например:
Epoch: 0 , loss equal to: 1029.0477736265436 . Accuracy: 69.12%
Epoch: 10 , loss equal to: 405.3760319047782 . Accuracy: 69.12%
Epoch: 20 , loss equal to: 402.94596804012343 . Accuracy: 69.12%
Epoch: 30 , loss equal to: 401.5770287877523 . Accuracy: 69.12%
Epoch: 40 , loss equal to: 400.77963764085007 . Accuracy: 69.12%
Epoch: 50 , loss equal to: 400.3190949247666 . Accuracy: 69.12%
Epoch: 60 , loss equal to: 400.05193343787334 . Accuracy: 69.12%
Epoch: 70 , loss equal to: 399.8951929684591 . Accuracy: 69.12%
Epoch: 80 , loss equal to: 399.80154758461305 . Accuracy: 69.12%
Epoch: 90 , loss equal to: 399.74405181305343 . Accuracy: 69.12%
или:
Epoch: 0 , loss equal to: 739.883461574974 . Accuracy: 92.65%
Epoch: 10 , loss equal to: 405.4500566401914 . Accuracy: 73.53%
Epoch: 20 , loss equal to: 401.95904155878173 . Accuracy: 70.59%
Epoch: 30 , loss equal to: 401.3946991504089 . Accuracy: 70.59%
Epoch: 40 , loss equal to: 401.09437273541636 . Accuracy: 70.59%
Я потратил несколько часов, чтобы найти решение, но не нашел. Я пробовал также библиотеки:
from fraction import Fraction
from decimal import *
чтобы справиться с меньшими темпами обучения, но они требуют числа в качестве аргумента, а не массива, поэтому я тоже потерпел неудачу.
Буду рад любым советам,
Заранее спасибо!