Подтвердить что ты не робот

Застревание реализации простой нейронной сети

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

Ответ 1

ОК, вот предложение. В векторном случае, если у вас есть x длины вектора n, то g(x) также является вектором длины n. Однако g'(x) не является вектором, он якобианной матрицей и будет иметь размер 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,)

Широковещательное вещание означает, что вам не нужно изменять ваш расчет 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)

Это работает для вас?

Edit

Я решил, что я вовсе не уверен, что 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)