Я бил головой о эту кирпичную стену для того, что кажется вечностью, и я просто не могу обернуть вокруг себя голову. Я пытаюсь реализовать autoencoder, используя только numpy и матричное умножение. Никаких тэков anano или keras не разрешено.Застрявшая реализация простой нейронной сети
Опишу проблему и все ее детали. Сначала это немного сложно, так как существует много переменных, но это довольно просто.
Что мы знаем
1) X
является m
по n
матрицы, наши входы. Входы представляют собой строки этой матрицы. Каждый вход представляет собой размерный вектор строки n
, и у нас есть m
из них.
2) Количество нейронов в нашем (единственном) скрытом слое, который составляет k
.
3) Функция активации наших нейронов (сигмы, будет обозначаться как g(x)
) и ее производная g'(x)
То, что мы не знаем, и хотим, чтобы найти
В целом наша цель состоит в том, чтобы найти 6 матриц: w1
, который n
по k
, b1
которое m
по k
, w2
которое k
по n
, b2, который является m
путем n
, w3
, который составляет n
, по n
и b3
, который составляет m
по n
.
Они инициализируются случайным образом, и мы находим лучшее решение с использованием градиентного спуска.
Процесс
Весь процесс выглядит примерно так
Сначала вычислим z1 = Xw1+b1
. Это m
от k
и является вкладом в наш скрытый слой. Затем мы вычисляем h1 = g(z1)
, который просто применяет сигмоидную функцию ко всем элементам z1
. естественно, это также m
от k
и является результатом нашего скрытого слоя.
Затем мы вычисляем z2 = h1w2+b2
, который является m
по n
и является входным для выходного слоя нашей нейронной сети. Затем мы вычисляем h2 = g(z2)
, который, естественно, также является m
на n
и является результатом нашей нейронной сети.
Наконец, мы берем этот вывод и выполняем на нем линейный оператор: Xhat = h2w3+b3
, который также является m
от n
и является нашим окончательным результатом.
Где я застрял
Функция затрат Я хочу, чтобы минимизировать средний квадрат ошибки. Я уже реализовал ее в Numpy код
def cost(x, xhat):
return (1.0/(2 * m)) * np.trace(np.dot(x-xhat,(x-xhat).T))
Задача нахождения производных стоимости по w1,b1,w2,b2,w3,b3
. Назовем стоимость S
.
После получения самого и проверяя себя численно, я установил следующие факты:
1) dSdxhat = (1/m) * np.dot(xhat-x)
2) dSdw3 = np.dot(h2.T,dSdxhat)
3) dSdb3 = dSdxhat
4) dSdh2 = np.dot(dSdxhat, w3.T)
Но я не могу для жизни меня выяснить dSdz2. Это кирпичная стена.
Из правила цепи должно быть, что dSdz2 = dSdh2 * dh2dz2, но размеры не совпадают.
Какова формула для вычисления производной от S по z2?
Редактировать - Это мой код для всей операции форвардинга автокодера.
import numpy as np
def g(x): #sigmoid activation functions
return 1/(1+np.exp(-x)) #same shape as x!
def gGradient(x): #gradient of sigmoid
return g(x)*(1-g(x)) #same shape as x!
def cost(x, xhat): #mean squared error between x the data and xhat the output of the machine
return (1.0/(2 * m)) * np.trace(np.dot(x-xhat,(x-xhat).T))
#Just small random numbers so we can test that it's working small scale
m = 5 #num of examples
n = 2 #num of features in each example
k = 2 #num of neurons in the hidden layer of the autoencoder
x = np.random.rand(m, n) #the data, shape (m, n)
w1 = np.random.rand(n, k) #weights from input layer to hidden layer, shape (n, k)
b1 = np.random.rand(m, k) #bias term from input layer to hidden layer (m, k)
z1 = np.dot(x,w1)+b1 #output of the input layer, shape (m, k)
h1 = g(z1) #input of hidden layer, shape (m, k)
w2 = np.random.rand(k, n) #weights from hidden layer to output layer of the autoencoder, shape (k, n)
b2 = np.random.rand(m, n) #bias term from hidden layer to output layer of autoencoder, shape (m, n)
z2 = np.dot(h1, w2)+b2 #output of the hidden layer, shape (m, n)
h2 = g(z2) #Output of the entire autoencoder. The output layer of the autoencoder. shape (m, n)
w3 = np.random.rand(n, n) #weights from output layer of autoencoder to entire output of the machine, shape (n, n)
b3 = np.random.rand(m, n) #bias term from output layer of autoencoder to entire output of the machine, shape (m, n)
xhat = np.dot(h2, w3)+b3 #the output of the machine, which hopefully resembles the original data x, shape (m, n)
Вы уверены, что ваши размеры не выровнены просто потому, что вы добавили единицы смещения в список единиц h2? Производное кажется мне хорошим. – Paul
Ну, разница в формах больше 1, поэтому он не может быть предвзятым термином. И я также беру во внимание термин смещения в своих деривативах. –
Говоря о ваших условиях смещения - обычно вы применяете постоянное смещение (и узнаете его значение), а не разные на каждой итерации (т.е. они должны иметь форму (k) и (n,). Существует не так много, что вы можете обобщить, когда оно изменится для каждого входа. Что-то еще меня смущает, так это то, что у вас явно есть 2 скрытых слоя, но говорите, что у вас есть только один. Я думаю, было бы полезно, если бы вы предоставили код для полная реализация - тогда мы можем видеть, какие другие махинации вы делаете. – Paul