2016-10-01 5 views
13

Я бил головой о эту кирпичную стену для того, что кажется вечностью, и я просто не могу обернуть вокруг себя голову. Я пытаюсь реализовать 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.

Они инициализируются случайным образом, и мы находим лучшее решение с использованием градиентного спуска.

Процесс

Весь процесс выглядит примерно так enter image description here

Сначала вычислим 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) 
+0

Вы уверены, что ваши размеры не выровнены просто потому, что вы добавили единицы смещения в список единиц h2? Производное кажется мне хорошим. – Paul

+0

Ну, разница в формах больше 1, поэтому он не может быть предвзятым термином. И я также беру во внимание термин смещения в своих деривативах. –

+1

Говоря о ваших условиях смещения - обычно вы применяете постоянное смещение (и узнаете его значение), а не разные на каждой итерации (т.е. они должны иметь форму (k) и (n,). Существует не так много, что вы можете обобщить, когда оно изменится для каждого входа. Что-то еще меня смущает, так это то, что у вас явно есть 2 скрытых слоя, но говорите, что у вас есть только один. Я думаю, было бы полезно, если бы вы предоставили код для полная реализация - тогда мы можем видеть, какие другие махинации вы делаете. – Paul

ответ

4

ОК, вот предложение. В векторном случае, если у вас есть x в качестве вектора длины n, то g(x) также является вектором длины n. Однако g'(x) не является вектором, это Jacobian matrix, и будет иметь размер n X n. Аналогичным образом, в случае мини-бара, где X является матрицей размера m X n, g(X) является m X n, но g'(X) является n X n. Попытайтесь:

def gGradient(x): #gradient of sigmoid 
    return np.dot(g(x).T, 1 - g(x)) 

@Paul прав, что условия смещения должны быть векторами, а не матрицами. Вы должны иметь:

b1 = np.random.rand(k) #bias term from input layer to hidden layer (k,) 
b2 = np.random.rand(n) #bias term from hidden layer to output layer of autoencoder, shape (n,) 
b3 = np.random.rand(n) #bias term from output layer of autoencoder to entire output of the machine, shape (n,) 

вещания Numpy означает, что вы не должны изменить свой расчет xhat.

Тогда (я думаю!), Вы можете вычислить производные, как это:

dSdxhat = (1/float(m)) * (xhat-x) 
dSdw3 = np.dot(h2.T,dSdxhat) 
dSdb3 = dSdxhat.mean(axis=0) 
dSdh2 = np.dot(dSdxhat, w3.T) 
dSdz2 = np.dot(dSdh2, gGradient(z2)) 
dSdb2 = dSdz2.mean(axis=0) 
dSdw2 = np.dot(h1.T,dSdz2) 
dSdh1 = np.dot(dSdz2, w2.T) 
dSdz1 = np.dot(dSdh1, gGradient(z1)) 
dSdb1 = dSdz1.mean(axis=0) 
dSdw1 = np.dot(x.T,dSdz1) 

ли эта работа для вас?

Редактировать

Я решил, что я не совсем уверен, что gGradient должна быть матрица.Как насчет:

dSdxhat = (xhat-x)/m 
dSdw3 = np.dot(h2.T,dSdxhat) 
dSdb3 = dSdxhat.sum(axis=0) 
dSdh2 = np.dot(dSdxhat, w3.T) 
dSdz2 = h2 * (1-h2) * dSdh2 
dSdb2 = dSdz2.sum(axis=0) 
dSdw2 = np.dot(h1.T,dSdz2) 
dSdh1 = np.dot(dSdz2, w2.T) 
dSdz1 = h1 * (1-h1) * dSdh1 
dSdb1 = dSdz1.sum(axis=0) 
dSdw1 = np.dot(x.T,dSdz1) 
+0

Я попробую, но я думаю, что есть проблема. посмотрите на строку z1 = np.dot (x, w1) + b1. точечное произведение x и w1 равно m на k, но b1 (согласно вам) k на 1. Добавление их невозможно. Возможно, вы имели в виду, что я должен повторить этот k на один вектор m раз? –

+0

Итак, [трансляция] (http://docs.scipy.org/doc/numpy/user/basics.broadcasting.html) означает, что numpy будет автоматически реплицировать вектор для вас. – wildwilhelm

+0

О, я вижу, большое спасибо, я этого не знал. Я обязательно проверю и опубликую результаты в ближайшее время! –

 Смежные вопросы

  • Нет связанных вопросов^_^