Я пытался создать трехслойную (1 вход - 2 скрытый - 1 выход) нейронную сеть с нуля, используя numpy. Выходной слой имеет только 1 нейрон. Я пытаюсь использовать стохастический градиентный спуск с мини-партиями. Что я сделал до сих пор, так это:
N1 = 50 # number of neurons in the first hidden layer
N2 = 20 # number of neurons in the second hidden layer
for n in range(10000):
weight_increment2 = 0
weight_increment1 = 0
weight_increment0 = 0
for j in range( batch_size):
# choose a sample randomly from training set
index = np.random.randint( trainims.shape[2] - 1)
layer0 = trainims[:,:,index]
# convert it to a column vector and add 1 for bias
layer0 = layer0.flatten()
layer0 = np.append( layer0, 1)
layer0 = layer0.reshape((1025,1))
# feed forward
layer1 = np.tanh( np.dot( w0.T, layer0))
layer1 = np.append( layer1, 1)
layer1 = layer1.reshape((N1+1,1))
layer2 = np.tanh( np.dot( w1.T, layer1))
layer2 = np.append( layer2, 1)
layer2 = layer2.reshape((N2+1,1))
layer3 = math.tanh( np.dot( w2.T, layer2))
# backpropagation
layer3_error = trainlbls[0,index] - layer3
layer3_gradient = 1 - layer3 * layer3
layer3_delta = layer3_error * layer3_gradient
layer2_error = layer3_delta * w2
layer2_gradient = 1 - np.multiply(layer2, layer2)
layer2_delta = np.multiply(layer2_error, layer2_gradient)
strippedlayer2delta = layer2_delta[0:N2,:]
layer1_error = strippedlayer2delta.T * w1
layer1_gradient = 1 - np.multiply( layer1, layer1)
layer1_delta = np.multiply( layer1_error, layer1_gradient)
strippedlayer1delta = layer1_delta[0:N1,:]
weight_increment2 = weight_increment2 + learning_rate * layer2 * layer3_delta
weight_increment1 = weight_increment1 + learning_rate * np.dot( layer1, strippedlayer2delta.T)
weight_increment0 = weight_increment0 + learning_rate * np.dot( layer0, strippedlayer1delta.T)
# update the weights
w2 = w2 + weight_increment2
w1 = w1 + weight_increment1
w0 = w0 + weight_increment0
w0
- входные веса: 1025x50 (1024 = вход, +1 - член смещения)
w1
- первый вес скрытого слоя: 51x20 (50 = количество нейронов первого скрытого слоя, +1 - термин смещения)
w2
- вес второго скрытого слоя: 21x1 (20 = количество вторых скрытых нейронов Лайера, +1 - термин смещения)
layer0
- это вектор входного слоя: входная выборка (1024x1) и 1
, добавленные в конец, что делает layer0
вектором 1025x1.
layer1
- это первый вектор скрытого слоя: после вычисления tanh( np.dot( w0.T, layer0))
я добавляю 1
в конец, что дает вектор 51x1
layer2
- второй вектор скрытого слоя: после вычисления tanh( np.dot( w1.T, layer1))
я добавляю 1
в конец, что приводит к вектору 21x1
layer3
- выходной вектор: tanh( np.dot( w2.T, layer2))
, который является просто nunmber
trainims
- это тренировочный набор размером 32x32x1900, что означает 1900 изображений 32x32
При обратном распространении я опускаю последние строки layer2_delta
и layer1_delta
, но я точно не знаю, почему я это делаю. Я предполагаю, что это из-за пропуска 1
терминов, которые я добавляю к layer1
и layer2
.
При попытке запустить код выдает следующую ошибку:
ValueError Traceback (most recent call last)
<ipython-input-11-98c3beb3b346> in <module>()
62 print( "weight_increment1:", weight_increment1.shape)
63
---> 64 weight_increment0 = weight_increment0 + learning_rate * np.dot( layer0, strippedlayer1delta.T)
65 print( "weight_increment0:", weight_increment0.shape)
66
ValueError: shapes (1025,1) and (20,50) not aligned: 1 (dim 1) != 20 (dim 0)
Я знаю, что размеры должны совпадать, чтобы получить матрицу 1025x50 и обновить w0
, но я не смог найти решение. Может быть, я делаю обратное распространение неправильно, я не знаю. Кто-нибудь может предложить решение этой проблемы?
Edit:
ОК, я заметил мою ошибку. Раньше я делал
layer1_error = strippedlayer2delta.T * w1
, который давал матрицу, но ошибка должна быть вектором для слоя, а не матрицей. Изменив эту строку на
layer1_error = np.dot( w1, strippedlayer2delta)
исправлена ошибка формы.
Но все же, кто-нибудь может проверить, правильны ли мои реализации стохастического градиентного спуска с мини-пакетами и обратным распространением?