3-уровневая нейронная сеть не учится должным образом - PullRequest
0 голосов
/ 10 мая 2018

Итак, я пытаюсь реализовать нейронную сеть с 3-мя слоями в python, однако я не самый умный человек, поэтому все, что имеет более 2-х слоев, для меня довольно сложно.Проблема с этим в том, что он застрял на .5 и не узнает, что я не имею ни малейшего понятия, где это пошло не так.Спасибо за всех, кто терпеливо объяснил мне ошибку.(Надеюсь, код имеет смысл)

import numpy as np

def sigmoid(x):
    return 1/(1+np.exp(-x))

def reduce(x):
    return x*(1-x)

l0=[np.array([1,1,0,0]),
np.array([1,0,1,0]),
np.array([1,1,1,0]),
np.array([0,1,0,1]),
np.array([0,0,1,0]),
]

output=[0,1,1,0,1]

syn0=np.random.random((4,4))
syn1=np.random.random((4,1))

for justanumber in range(1000):
    for i in range(len(l0)):

        l1=sigmoid(np.dot(l0[i],syn0))
        l2=sigmoid(np.dot(l1,syn1))

        l2_err=output[i]-l2
        l2_delta=reduce(l2_err)

        l1_err=syn1*l2_delta
        l1_delta=reduce(l1_err)

        syn1=syn1.T
        syn1+=l0[i].T*l2_delta
        syn1=syn1.T

        syn0=syn0.T
        syn0+=l0[i].T*l1_delta
        syn0=syn0.T
        print l2

PS.Я знаю, что это может быть кусок мусора как сценарий, но поэтому я попросил помощи

1 Ответ

0 голосов
/ 10 мая 2018
  1. Ваши вычисления не полностью верны.Например, reduce вызывается на l1_err и l2_err, где его следует вызывать на l1 и l2.
  2. Вы выполняете стохастический градиентный спуск.В этом случае при таких нескольких параметрах он сильно колеблется.В этом случае используйте полный градиентный спуск.
  3. Единицы смещения отсутствуют.Хотя вы все еще можете учиться без предвзятости, технически.

Я попытался переписать ваш код с минимальными изменениями.Я прокомментировал ваши строки, чтобы показать изменения.

#!/usr/bin/python3
import matplotlib.pyplot as plt
import numpy as np

def sigmoid(x):
    return 1/(1+np.exp(-x))

def reduce(x):
    return x*(1-x)

l0=np.array ([np.array([1,1,0,0]),
np.array([1,0,1,0]),
np.array([1,1,1,0]),
np.array([0,1,0,1]),
np.array([0,0,1,0]),
]);

output=np.array ([[0],[1],[1],[0],[1]]);

syn0=np.random.random((4,4))
syn1=np.random.random((4,1))
final_err = list ();
gamma = 0.05
maxiter = 100000
for justanumber in range(maxiter):
    syn0_del = np.zeros_like (syn0);
    syn1_del = np.zeros_like (syn1);
    l2_err_sum = 0;
    for i in range(len(l0)):
        this_data = l0[i,np.newaxis];

        l1=sigmoid(np.matmul(this_data,syn0))[:]
        l2=sigmoid(np.matmul(l1,syn1))[:]

        l2_err=(output[i,:]-l2[:])
        #l2_delta=reduce(l2_err)
        l2_delta=np.dot (reduce(l2), l2_err)

        l1_err=np.dot (syn1, l2_delta)
        #l1_delta=reduce(l1_err) 
        l1_delta=np.dot(reduce(l1), l1_err)

        # Accumulate gradient for this point for layer 1
        syn1_del += np.matmul(l2_delta, l1).T;
        #syn1=syn1.T
        #syn1+=l1.T*l2_delta
        #syn1=syn1.T

        # Accumulate gradient for this point for layer 0
        syn0_del += np.matmul(l1_delta, this_data).T;
        #syn0=syn0.T
        #syn0-=l0[i,:].T*l1_delta
        #syn0=syn0.T

        # The error for this datpoint. Mean sum of squares
        l2_err_sum += np.mean (l2_err ** 2);

    l2_err_sum /= l0.shape[0]; # Mean sum of squares
    syn0 += gamma * syn0_del;
    syn1 += gamma * syn1_del;

    print ("iter: ", justanumber, "error: ", l2_err_sum);
    final_err.append (l2_err_sum);


# Predicting
l1=sigmoid(np.matmul(l0,syn0))[:]# 1 x d * d x 4 = 1 x 4;
l2=sigmoid(np.matmul(l1,syn1))[:] # 1 x 4 * 4 x 1 = 1 x 1

print ("Predicted: \n", l2)
print ("Actual: \n", output)

plt.plot (np.array (final_err));
plt.show ();

Вывод, который я получаю:

Predicted: 
 [[0.05214011]
 [0.97596354]
 [0.97499515]
 [0.03771324]
 [0.97624119]]
Actual: 
 [[0]
 [1]
 [1]
 [0]
 [1]]

Поэтому сеть смогла предсказать все примеры обучения игрушкам.(Обратите внимание, что в реальных данных вы не хотели бы соответствовать данным в лучшем виде, поскольку это приводит к переобучению).Обратите внимание, что вы можете получить немного другой результат, так как инициализация веса отличается.Кроме того, попробуйте инициализировать вес между [-0.01, +0.01], как правило, когда вы не работаете над конкретной проблемой и вам конкретно известна инициализация.

Вот график конвергенции. enter image description here

Обратите внимание, что вам не нужно фактически выполнять итерации по каждому примеру, вместо этого вы можете выполнять матричное умножение сразу, что намного быстрее.Кроме того, приведенный выше код не имеет единицы смещения.При повторной реализации кода убедитесь, что у вас есть единицы смещения.

Я бы порекомендовал вам пройти через нейронные сети Рауля Рохаса , систематическое введение , главы 4, 6 и 7.Глава 7 расскажет вам, как реализовать более глубокие сети простым способом.

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