Нейронная сеть с нуля не сходится - PullRequest
0 голосов
/ 30 января 2020

Я пытаюсь внедрить нейронную сеть с нуля, чтобы лучше понять ее, и я столкнулся со странной проблемой. Когда я использую функцию Relu для скрытых слоев в качестве функции активации, модель не сходится, тогда как она сходится после использования сигмоидальной функции. Вот мой ванильный код: когда вы меняете функцию активации первых двух слоев с relu на sigmoid, вы можете видеть, что она сходится, хотя иногда она может иметь проблему. Где может быть проблема? Прошло три дня, и я все еще не мог найти его, хотя я нашел несколько небольших ошибок. Заранее спасибо. Вот набор данных игрушек, который я использовал (просто вставьте его туда, где находится этот код). Набор данных

import numpy as np
import pandas as pd


class NeuralNetwork():


def __init__(self, epoch=10000, alpha=0.075, algorithm="gradient_descent"):
    # hyperparameters
    self.epoch = epoch
    self.alpha = alpha
    self.algorithm = algorithm
    # parameters
    self.params = {}
    self.layer_no = 1
    # logs
    self.cost_vals = []


def createLayer(self, size, activation_func, randomness=True):        
    if randomness == True:
        self.params["W" + str(self.layer_no)] = np.random.randn(size[0], size[1]) * 0.01
    else:
        self.params["W" + str(self.layer_no)] = np.zeros(size)

    self.params["b" + str(self.layer_no)] = np.zeros((size[0], 1))
    self.params["func" + str(self.layer_no)] = activation_func
    self.layer_no += 1


def sigmoid(self, X):
    return 1 / (1 + np.exp(-X))


def relu(self, X):
    return np.maximum(X, 0) * 0.01


def tanh(self, X):
    return (np.exp(X) - np.exp(-X)) / (np.exp(X) + np.exp(-X))


def derivative_sigmoid(self, X):
    der_x = self.sigmoid(X)
    return der_x * (1 - der_x)


def derivative_relu(self, X):
    X[X<=0] = 0
    X[X>0] = 1
    return X


def derivative_tanh(self, X):
    tanhx = self.tanh(X)
    return 1 - np.power(tanhx, 2)


def activation_function(self, Zl, act_func_name):
    if act_func_name == "sigmoid":
        return self.sigmoid(Zl)
    elif act_func_name == "relu":
        return self.relu(Zl)
    elif act_func_name == "tanh":
        return self.tanh(Zl)


def derivative_activation_function(self, Zl, act_func_name):
    if act_func_name == "sigmoid":
        return self.derivative_sigmoid(Zl)
    elif act_func_name == "relu":
        return self.derivative_relu(Zl)
    elif act_func_name == "tanh":
        return self.derivative_tanh(Zl)


def train(self, X, Y):
    m = Y.shape[0] # number of training examples
    self.params["A0"] = X
    self.params["Z0"] = None
    for i in range(self.epoch):
        # forward prop
        for l in range(1, self.layer_no): # 1,2,3
            Zl = np.dot(self.params["W" + str(l)], self.params["A" + str(l - 1)]) + self.params["b" + str(l)] # linear function of a layer with vectorization
            Al = self.activation_function(Zl, self.params["func" + str(l)]) # activated form of Zl
            self.params["Z" + str(l)] = Zl
            self.params["A" + str(l)] = Al
        # cost function
        cost_val = - 1 / m * np.sum(np.multiply(Y, np.log(Al)) + np.multiply((1 - Y), np.log(1 - Al)))
        cost_val = np.squeeze(cost_val)  
        if i % 500 == 0:
            print(cost_val)
            self.cost_vals.append(cost_val)
        # backward prop
        dAl = - (np.divide(Y, Al) - np.divide(1 - Y, 1 - Al)) # gradiant of last layer of A
        for l in reversed(range(1, self.layer_no)): # 3,2,1
            # backward prop
            dZl = np.multiply(dAl, 
                self.derivative_activation_function(self.params["Z" + str(l)], self.params["func" + str(l)])) # gradient of layer l of Z
            dAl1 = np.dot(self.params["W" + str(l)].T, dZl) # gradient of previous layer of A
            dWl = 1 / m * np.dot(dZl, self.params["A" + str(l - 1)].T) # gradient of parameters W in layer l
            dbl = 1 / m * np.sum(dZl, axis=1, keepdims=True) # gradient of parameters b in layer l
            # update parameters
            self.params["W" + str(l)] -= self.alpha * dWl
            self.params["b" + str(l)] -= self.alpha * dbl
            dAl = dAl1 # assign gradient of previous layer of A to the current one so as to use it while back-propagation




def iris_data():
    from sklearn.model_selection import train_test_split
    datas = pd.read_csv('iris_nn.data').to_numpy()
    X = datas[:, 0:4].astype(float) 
    Y = datas[:, 4:5]
    Y = np.asarray([1 if (y == 'Iris-setosa') else 0 for y in Y]).reshape((Y.shape[0], 1))
    X_train, X_test, Y_train, Y_test = train_test_split(X, Y, test_size=0.25, random_state=0)
    return X_train.T, Y_train.T




X, Y = iris_data()
model = NeuralNetwork()
model.createLayer((5,4), "relu")
model.createLayer((7,5), "relu")
model.createLayer((1,7), "sigmoid")
model.train(X,Y)
#
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...