Нейронная сеть для цифр MNIST не учится вообще - проблема с обратным распространением - PullRequest
3 голосов
/ 22 января 2020

через долгое время я все еще не могу запустить свой nn без каких-либо ошибок. Точность этой игрушки составляет удивительные 1-2% (60 нейронов в скрытом слое, 100 эпох, скорость обучения 0,3, активация tanh, набор данных MNIST, загруженный через TF) - так что в основном это не обучение вообще. После всего этого времени, просматривая видео / пост о обратном распространении, я все еще не могу это исправить. Так что моя ошибка должна быть между частью, отмеченной двумя линиями #####. Я думаю, что мое понимание деривативов в целом хорошее, но я просто не могу связать это знание с обратным распространением. Если база обратного распространения верна, то ошибка должна быть на axis = 0/1, потому что я также не могу понять, как определить, по какой оси я буду работать.

Кроме того, у меня есть сильное чувство, что dZ2 = A2 - Y может быть не так, это должно быть dZ2 = Y - A2, но после этого исправления nn начинает угадывать только одно число.

(и да, самого обратного распространения я не написал, я нашел его на inte rnet)

#importing data and normalizing it
#"x_test" will be my X
#"y_test" will be my Y

import tensorflow as tf
(traindataX, traindataY), (testdataX, testdataY) = tf.keras.datasets.mnist.load_data()
x_test = testdataX.reshape(testdataX.shape[0], testdataX.shape[1]**2).astype('float32')
x_test = x_test / 255

y_test = testdataY
y_test = np.eye(10)[y_test]
#Activation functions:
def tanh(z):
    a = (np.exp(z)-np.exp(-z))/(np.exp(z)+np.exp(-z))
    return a
###############################################################################START
def softmax(z):
    smExp = np.exp(z - np.max(z, axis=0))
    out = smExp / np.sum(smExp, axis=0)
    return out
###############################################################################STOP
def neural_network(num_hid, epochs, 
                  learning_rate, X, Y):
    #num_hid - number of neurons in the hidden layer
    #X - dataX - shape (10000, 784)
    #Y - labels - shape (10000, 10)

    #inicialization
    W1 = np.random.randn(784, num_hid) * 0.01
    W2 = np.random.randn(num_hid, 10) * 0.01
    b1 = np.zeros((1, num_hid))
    b2 = np.zeros((1, 10))
    correct = 0

    for x in range(1, epochs+1):
        #feedforward
        Z1 = np.dot(X, W1) + b1
        A1 = tanh(Z1)
        Z2 = np.dot(A1, W2) + b2
        A2 = softmax(Z2)


        ###############################################################################START
        m = X.shape[1] #-> 784
        loss = - np.sum((Y * np.log(A2)), axis=0, keepdims=True)
        cost = np.sum(loss, axis=1) / m

        #backpropagation
        dZ2 = A2 - Y
        dW2 = (1/m)*np.dot(A1.T, dZ2)
        db2 = (1/m)*np.sum(dZ2, axis = 1, keepdims = True)
        dZ1 = np.multiply(np.dot(dZ2, W2.T), 1 - np.power(A1, 2))
        dW1 = (1/m)*np.dot(X.T, dZ1)
        db1 = (1/m)*np.sum(dZ1, axis = 1, keepdims = True)
        ###############################################################################STOP


        #parameters update - gradient descent
        W1 = W1 - dW1*learning_rate
        b1 = b1 - db1*learning_rate
        W2 = W2 - dW2*learning_rate
        b2 = b2 - db2*learning_rate


        for i in range(np.shape(Y)[1]):
            guess = np.argmax(A2[i, :])
            ans = np.argmax(Y[i, :])
            print(str(x) + " " + str(i) + ". " +"guess: ", guess, "| ans: ", ans)
            if guess == ans:
                correct = correct + 1;

    accuracy = (correct/np.shape(Y)[0]) * 100

Ответы [ 3 ]

2 голосов
/ 31 января 2020

Лукас, Хорошая проблема, чтобы обновить sh основы. Я сделал несколько исправлений в вашем коде:

  • вычисление m
  • Переставил все веса и уклоны (не могу правильно объяснить, но он не работал иначе).
  • изменен расчет точности (и потери, которые не используются).

См. Исправленный код ниже. Он достигает точности 90% с вашими исходными параметрами:

def neural_network(num_hid, epochs, learning_rate, X, Y):
#num_hid - number of neurons in the hidden layer
#X - dataX - shape (10000, 784)
#Y - labels - shape (10000, 10)

#inicialization
# W1 = np.random.randn(784, num_hid) * 0.01
# W2 = np.random.randn(num_hid, 10) * 0.01
# b1 = np.zeros((1, num_hid))
# b2 = np.zeros((1, 10))
W1 = np.random.randn(num_hid, 784) * 0.01
W2 = np.random.randn(10, num_hid) * 0.01
b1 = np.zeros((num_hid, 1))
b2 = np.zeros((10, 1))

for x in range(1, epochs+1):
    correct = 0  # moved inside cycle
    #feedforward
    # Z1 = np.dot(X, W1) + b1
    Z1 = np.dot(W1, X.T) + b1
    A1 = tanh(Z1)
    # Z2 = np.dot(A1, W2) + b2
    Z2 = np.dot(W2, A1) + b2
    A2 = softmax(Z2)

    ###############################################################################START
    m = X.shape[0] #-> 784  # SHOULD BE NUMBER OF SAMPLES IN THE BATCH
    # loss = - np.sum((Y * np.log(A2)), axis=0, keepdims=True)
    loss = - np.sum((Y.T * np.log(A2)), axis=0, keepdims=True)
    cost = np.sum(loss, axis=1) / m

    #backpropagation
    # dZ2 = A2 - Y
    # dW2 = (1/m)*np.dot(A1.T, dZ2)
    # db2 = (1/m)*np.sum(dZ2, axis = 1, keepdims = True)
    # dZ1 = np.multiply(np.dot(dZ2, W2.T), 1 - np.power(A1, 2))
    # dW1 = (1/m)*np.dot(X.T, dZ1)
    dZ2 = A2 - Y.T
    dW2 = (1/m)*np.dot(dZ2, A1.T)
    db2 = (1/m)*np.sum(dZ2, axis = 1, keepdims = True)
    dZ1 = np.multiply(np.dot(W2.T, dZ2), 1 - np.power(A1, 2))
    dW1 = (1/m)*np.dot(dZ1, X)

    db1 = (1/m)*np.sum(dZ1, axis = 1, keepdims = True)
    ###############################################################################STOP

    #parameters update - gradient descent
    W1 = W1 - dW1*learning_rate
    b1 = b1 - db1*learning_rate
    W2 = W2 - dW2*learning_rate
    b2 = b2 - db2*learning_rate

    guess = np.argmax(A2, axis=0)  # axis fixed
    ans = np.argmax(Y, axis=1)  # axis fixed
    # print (guess.shape, ans.shape)
    correct += sum (guess==ans)

    #     #print(str(x) + " " + str(i) + ". " +"guess: ", guess, "| ans: ", ans)
    #     if guess == ans:
    #         correct = correct + 1;
    accuracy = correct / x_test.shape[0]
    print (f"Epoch {x}. accuracy = {accuracy*100:.2f}%")


neural_network (64, 100, 0.3, x_test, y_test)

Epoch 1. accuracy = 14.93%
Epoch 2. accuracy = 34.70%
Epoch 3. accuracy = 47.41%
(...)
Epoch 98. accuracy = 89.29%
Epoch 99. accuracy = 89.33%
Epoch 100. accuracy = 89.37%
2 голосов
/ 24 января 2020

Это может быть связано с тем, что вы должны нормализовать свои входные значения между значениями от 0 до 1, разделив X на 255 (255 - максимальное значение пикселя). Вы также должны иметь Y один горячий код в виде серии векторов размером 10. Я думаю, что ваш backprop правильный, но вы должны реализовать градиентную проверку для двойной проверки.

1 голос
/ 30 января 2020

Вы неверно рассчитываете точность. Первая правильная переменная должна быть инициализирована в 0 для каждой итерации эпохи, во-вторых, если y.shape равен (10000, 10), то для вычисления точности, l oop должно быть for i in range(np.shape(Y)[0]), а не for i in range(np.shape(Y)[1]), первая будет повторять 10 000 раз, второй повторять 10 раз.

Лучшим подходом будет использование NumPy для вычисления количества правильных догадок correct = np.sum(np.argmax(A2,axis=1) == np.argmax(Y,axis=1))

Ваша скорость обучения слишком велика высокая, я смог достичь 50% точности, установив скорость обучения 0,003 для 50 эпох и 60 скрытых нейронов

def neural_network(num_hid, epochs, 
                  learning_rate, X, Y):
    #num_hid - number of neurons in the hidden layer
    #X - dataX - shape (10000, 784)
    #Y - labels - shape (10000, 10)

    #inicialization
    W1 = np.random.randn(784, num_hid) * 0.01
    W2 = np.random.randn(num_hid, 10) * 0.01
    b1 = np.zeros((1, num_hid))
    b2 = np.zeros((1, 10))
    correct = 0

    for x in range(1, epochs+1):
        #feedforward
        Z1 = np.dot(X, W1) + b1
        A1 = tanh(Z1)
        Z2 = np.dot(A1, W2) + b2
        A2 = softmax(Z2)


        ###############################################################################START
        m = X.shape[1] #-> 784
        loss = - np.sum((Y * np.log(A2)), axis=0, keepdims=True)
        cost = np.sum(loss, axis=1) / m

        #backpropagation
        dZ2 = A2 - Y
        dW2 = (1/m)*np.dot(A1.T, dZ2)
        db2 = (1/m)*np.sum(dZ2, axis = 1, keepdims = True)
        dZ1 = np.multiply(np.dot(dZ2, W2.T), 1 - np.power(A1, 2))
        dW1 = (1/m)*np.dot(X.T, dZ1)
        db1 = (1/m)*np.sum(dZ1, axis = 1, keepdims = True)
        ###############################################################################STOP


        #parameters update - gradient descent
        W1 = W1 - dW1*learning_rate
        b1 = b1 - db1*learning_rate
        W2 = W2 - dW2*learning_rate
        b2 = b2 - db2*learning_rate

        correct = 0
        for i in range(np.shape(Y)[0]):
            guess = np.argmax(A2[i, :])
            ans = np.argmax(Y[i, :])
#             print(str(x) + " " + str(i) + ". " +"guess: ", guess, "| ans: ", ans)
            if guess == ans:
                correct = correct + 1

#         correct = np.sum(np.argmax(A2,axis=1) == np.argmax(Y,axis=1))
#         print(correct)
        accuracy = (correct/np.shape(Y)[0]) * 100
        print(accuracy)

Вы должны быть экспериментальными, для хорошей точности, попробуйте настроить количество скрытых слоев, эпох и скорость обучения.

...