Почему градиентный спуск не работает должным образом? - PullRequest
0 голосов
/ 28 января 2019

Это моя первая попытка кодирования многослойной нейронной сети в Python (код прилагается ниже).Я с трудом пытаюсь использовать частные производные градиентного спуска, потому что кажется, что веса не обновляются должным образом.Когда я пытаюсь предсказать вывод новой выборки, я всегда получаю неправильный ответ (должно быть два выходных значения и вероятность, связанная с ними; например: если новая выборка принадлежит классу 1, ее вероятность должна быть больше чем0.5 (prob_class1), и, следовательно, класс 2 имеет (1-prob_class1), но код просто выдает [1,1] или [-1, -1] для любого образца).Я дважды проверил все линии, и я почти уверен, что это связано с некоторыми проблемами при использовании градиентного спуска.Кто-нибудь может мне помочь, пожалуйста?Заранее спасибо.

import numpy as np
import sklearn 
from sklearn.linear_model import LogisticRegressionCV
from sklearn.datasets import make_moons
import matplotlib.pyplot as plt

np.random.seed(0)
x, y = sklearn.datasets.make_moons(200, noise=0.20)
plt.scatter(x[:,0], x[:,1], s=40, c=y, cmap=plt.cm.Spectral)
y = y.reshape(-1,1)
N = x.shape[0]

n_input = min(x.shape)
n_output = 2
n_hidden = max(n_input,n_output) + 20 # 20 is arbitrary
n_it = 10000 
alpha = 0.01

def predict(model,xn):
    W1, b1, W2, b2, W3, b3 = model['W1'], model['b1'], model['W2'], model['b2'],model['W3'], model['b3']
    z1 = W1.dot(xn) + b1
    a1 = np.tanh(z1)
    z2 = a1.dot(W2) + b2
    a2 = np.tanh(z2)
    z3 = a2.dot(W3) + b3
    a3 = np.tanh(z3)

    return a3

model = {}

W1 = np.random.randn(n_input,n_input)
b1 = np.random.randn(1,n_input)
W2 = np.random.randn(n_input,n_hidden)
b2 = np.random.randn(1,n_hidden)
W3 = np.random.randn(n_hidden,n_output)
b3 = np.random.randn(1,n_output)

for i in range(n_it):

    # Feedforward:
    z1 = x.dot(W1) + b1
    a1 = np.tanh(z1)
    z2 = a1.dot(W2) + b2
    a2 = np.tanh(z2)
    z3 = a2.dot(W3) + b3
    a3 = np.tanh(z3)


    # Loss function:
    # f(w,b) = (y - (w*x + b)^2)
    # df/dw = -2*(1/N)*x*(y - (w*x + b))
    # df/db = -2*(1/N)*(y - (w*x + b))

    # Backpropagation:
    dW3 = -2*(1/N)*(a2.T).dot(y-a3)
    db3 = -2*(1/N)*sum(y-a3)
    db3 = db3.reshape(-1,1)
    db3 = db3.T
    dW2 = -2*(1/N)*a1.T.dot(a2)
    db2 = -2*(1/N)*sum(a2)
    db2 = db2.reshape(-1,1)
    db2 = db2.T
    dW1 = -2*(1/N)*(x.T).dot(a1)
    db1 = -2*(1/N)*sum(dW1)
    db1 = db1.reshape(-1,1)
    db1 = db1.T

    # Updating weights
    W3 += alpha*dW3
    b3 += alpha*db3
    W2 += alpha*dW2
    b2 += alpha*db2
    W1 += alpha*dW1
    b1 += alpha*db1

model = { 'W1': W1, 'b1': b1, 'W2': W2, 'b2': b2, 'W3':W3, 'b3':b3}
test = np.array([2,0])
prediction = predict(model,test)

1 Ответ

0 голосов
/ 30 января 2019

Несколько вещей, которые приходят мне в голову, глядя на ваш код:

Во-первых, вы не используете правило цепочки для вычисления обратного распространения.Если вам нужно некоторое интуитивное понимание этого, вы можете посмотреть этот замечательный урок Андрея Карпати https://www.youtube.com/watch?v=i94OvYb6noo,, но в Интернете также есть множество ресурсов.Возможно, начните с 1 скрытого слоя (у вас есть 2 здесь), так как это значительно упрощает процесс.

Во-вторых, вы также должны использовать производную вашего tanh в backprop (вы делаете это в прямом распространении, поэтомуэто также должно быть сделано наоборот).

Наконец, зачем вам два выходных узла?Мне кажется, что в этом случае output_1 = 1 - output_2.Или, если вы хотите, чтобы два выходных сигнала были рассчитаны отдельно, вам нужно было бы нормализовать их в конце, чтобы получить вероятность принадлежности к классу 1 или 2.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...