坚持实施简单的神经网络

Ori*_*ber 13 python algorithm numpy matrix derivative

我一直在抨击这堵砖墙,看起来像是永恒的,我似乎无法绕过它.我正在尝试仅使用numpy和矩阵乘法来实现自动编码器.没有theano或keras技巧允许.

我将描述问题及其所有细节.它起初有点复杂,因为有很多变量,但它确实非常简单.

我们知道什么

1)X是一种mn矩阵这是我们的输入.输入是该矩阵的行.每个输入都是一个n维度行向量,我们有m它们.

2)我们(单个)隐藏层中的神经元数量,即k.

3)我们的神经元(sigmoid,将表示为g(x))及其衍生物的激活功能g'(x)

我们不知道什么,想找到什么

总的来说,我们的目标是找到6个矩阵:w1这是n通过k,b1这是m通过k,w2这是kn,B2是m通过n,w3这是nnb3mn.

它们随机初始化,我们找到使用梯度下降的最佳解决方案.

这个过程

整个过程看起来像这样 在此输入图像描述

首先我们计算z1 = Xw1+b1.它是m通过k并输入到我们的隐藏层.然后我们计算h1 = g(z1),它只是将sigmoid函数应用于所有元素z1.当然它也是m通过k和我们的隐层的输出.

然后,我们计算z2 = h1w2+b2m通过n并输入到我们的神经网络的输出层.然后我们计算h2 = g(z2)这又是自然也m通过n与我们的神经网络的输出.

最后,我们借此输出,并执行它的一些线性算:Xhat = h2w3+b3这也是mn,是我们最终的结果.

我被卡住了

我想要最小化的成本函数是均方误差.我已经用numpy代码实现了它

def cost(x, xhat):
    return (1.0/(2 * m)) * np.trace(np.dot(x-xhat,(x-xhat).T))
Run Code Online (Sandbox Code Playgroud)

问题在于找到成本的衍生物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)
Run Code Online (Sandbox Code Playgroud)

wil*_*elm 4

好的,这是一个建议。在向量的情况下,如果x作为长度为 的向量n,则g(x)也是长度为 的向量n。然而,g'(x)不是向量,它是雅可比矩阵,并且大小为n X n。类似地,在小批量情况下,其中X大小为的矩阵m X ng(X)但是。尝试:m X ng'(X)n X n

def gGradient(x): #gradient of sigmoid
    return np.dot(g(x).T, 1 - g(x))
Run Code Online (Sandbox Code Playgroud)

@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,)
Run Code Online (Sandbox Code Playgroud)

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)
Run Code Online (Sandbox Code Playgroud)

这对你有用吗?

编辑

我决定我根本不确定这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)
Run Code Online (Sandbox Code Playgroud)