一个浅层的神经网络
上图是一个,3层的神经网络,2个隐藏层+1个输出层;输入层 特征维度为3。
上图时一个神经元的结构,有一个线性函数 和 一个非线性的激活函数组成。
z
=
w
T
x
+
b
z=w^Tx+b
z=wTx+b
a
=
σ
(
z
)
=
1
/
(
1
+
e
−
z
)
a=\sigma(z)= 1/(1+e^{-z})
a=σ(z)=1/(1+e−z)
式中的激活函数采用的时 sigmoid 函数,可以使用其他函数进行代替。
参数和中间变量解释
若使用,
n
x
n_x
nx 表示输入数据的特征维度,如上图
n
x
=
3
n_x=3
nx=3, 使用 m表示单次输入的的样本个数。 则:
X
X
X: 表示输入数据矩阵 , shape 为
(
n
x
,
m
)
(n_x, m)
(nx,m)
W
[
1
]
W^{[1]}
W[1]: 表示第一层的 权重参数, shape 为
(
4
,
n
x
)
(4, n_x)
(4,nx)
Z
[
1
]
Z^{[1]}
Z[1]、
A
[
1
]
A^{[1]}
A[1]: 表示第一层 的线性函数 和 激活函数的输出结果, shape 为(4,m)
W
[
2
]
W^{[2]}
W[2]: shape 为 (3, 4)
Z
[
2
]
Z^{[2]}
Z[2]、
A
[
2
]
A^{[2]}
A[2]: shape 为(3, m)
W
[
3
]
W^{[3]}
W[3]: shape 为 (1, 3)
Z
[
3
]
Z^{[3]}
Z[3]、
A
[
3
]
A^{[3]}
A[3]: shape 为(1, m)
一般的,如果
L
[
i
]
L^{[i]}
L[i] 表示i 层的神经元个数,则:
W
[
i
]
W^{[i]}
W[i]: shape 为
(
L
[
i
]
,
L
[
i
−
1
]
)
(L^{[i]} , L^{[i-1]})
(L[i],L[i−1])
b
[
i
]
b^{[i]}
b[i]: shape 为
(
L
[
i
]
,
1
)
(L^{[i]}, 1)
(L[i],1)
Z
[
i
]
Z^{[i]}
Z[i]、
A
[
i
]
A^{[i]}
A[i]: shape 为
(
L
[
i
]
,
m
)
(L^{[i]},m)
(L[i],m)
前向传播
Z
[
1
]
=
W
[
1
]
X
Z^{[1]}= W^{[1]}X
Z[1]=W[1]X
A
[
1
]
=
σ
(
Z
[
1
]
)
A^{[1]}=\sigma(Z^{[1]})
A[1]=σ(Z[1])
Z
[
2
]
=
W
[
2
]
A
[
1
]
Z^{[2]}= W^{[2]}A^{[1]}
Z[2]=W[2]A[1]
A
[
2
]
=
σ
(
Z
[
2
]
)
A^{[2]}=\sigma(Z^{[2]})
A[2]=σ(Z[2])
Z
[
3
]
=
W
[
3
]
A
[
2
]
Z^{[3]}= W^{[3]}A^{[2]}
Z[3]=W[3]A[2]
A
[
3
]
=
σ
(
Z
[
3
]
)
A^{[3]}=\sigma(Z^{[3]})
A[3]=σ(Z[3])
一般的:
Z
[
i
]
=
W
[
i
]
A
[
i
−
1
]
Z^{[i]}= W^{[i]}A^{[i-1]}
Z[i]=W[i]A[i−1]
A
[
i
]
=
σ
(
Z
[
i
]
)
A^{[i]}=\sigma(Z^{[i]})
A[i]=σ(Z[i])
反向传播
假设,上图中3层的神经网络用于 二分类,则 我们在最后一层,activation function可以使用sigmoid 函数,
σ
3
(
z
)
=
g
(
x
)
\sigma^3(z)=g(x)
σ3(z)=g(x)
反向传播的目的,就是通过链式法则,求得各层的参数梯度,进行优化求解。
为简化表示,使用dvar 对变量 var 的偏导。
cost function:
J
=
−
1
m
∑
i
=
1
m
y
l
o
g
y
^
+
(
1
−
y
)
l
o
g
(
1
−
y
^
)
J=-\frac 1m\sum_{i=1}^{m}ylog\hat{y}+(1-y)log(1-\hat{y})
J=−m1i=1∑mylogy^+(1−y)log(1−y^)
y
^
=
a
[
3
]
\hat{y}=a^{[3]}
y^=a[3] 第三层的激励函数 输出。
d A [ 3 ] = 1 − Y 1 − A [ 3 ] − Y A [ 3 ] dA^{[3]} = \frac{1-Y}{1-A^{[3]}}-\frac{Y}{A^{[3]}} dA[3]=1−A[3]1−Y−A[3]Y … 此处的一个数字减一个矩阵,是对矩阵中的每一个元素都和该常数操作
d
Z
[
3
]
=
d
A
[
3
]
g
′
=
(
1
−
Y
1
−
A
[
3
]
−
Y
A
[
3
]
)
(
A
[
3
]
(
1
−
A
[
3
]
)
)
=
A
[
3
]
−
Y
dZ^{[3]}=dA^{[3]}g^{'}=( \frac{1-Y}{1-A^{[3]}}-\frac{Y}{A^{[3]}})(A^{[3]}(1-A^{[3]}))=A^{[3]}-Y
dZ[3]=dA[3]g′=(1−A[3]1−Y−A[3]Y)(A[3](1−A[3]))=A[3]−Y
d
W
[
3
]
=
1
m
d
Z
[
3
]
A
[
2
]
T
dW^{[3]}=\frac{1}{m}dZ^{[3]}A^{[2]^T}
dW[3]=m1dZ[3]A[2]T
d
b
[
3
]
=
1
m
n
p
.
s
u
m
(
d
Z
[
3
]
,
a
x
i
s
=
1
)
db^{[3]}=\frac{1}{m}np.sum(dZ^{[3]},axis=1)
db[3]=m1np.sum(dZ[3],axis=1)
d
Z
[
2
]
=
W
[
3
]
T
d
Z
[
3
]
∗
σ
[
2
]
′
Z
[
2
]
dZ^{[2]}=W^{{[3]}^T}dZ^{[3]}*\sigma^{[2]^{'}}Z^{[2]}
dZ[2]=W[3]TdZ[3]∗σ[2]′Z[2]
d
W
[
2
]
=
1
m
d
Z
[
2
]
A
[
1
]
T
dW^{[2]}=\frac{1}{m}dZ^{[2]}A^{[1]^T}
dW[2]=m1dZ[2]A[1]T
d
b
[
2
]
=
1
m
n
p
.
s
u
m
(
d
Z
[
2
]
,
a
x
i
s
=
1
)
db^{[2]}=\frac{1}{m}np.sum(dZ^{[2]},axis=1)
db[2]=m1np.sum(dZ[2],axis=1)
d
Z
[
1
]
=
W
[
2
]
T
d
Z
[
2
]
∗
σ
[
1
]
′
Z
[
1
]
dZ^{[1]}=W^{{[2]^T}}{dZ^{[2]}}*\sigma^{[1]^{'}}Z^{[1]}
dZ[1]=W[2]TdZ[2]∗σ[1]′Z[1]
d
W
[
1
]
=
1
m
d
Z
[
1
]
X
T
dW^{[1]}=\frac{1}{m}dZ^{[1]}X^T
dW[1]=m1dZ[1]XT
d
b
[
1
]
=
1
m
n
p
.
s
u
m
(
d
Z
[
1
]
,
a
x
i
s
=
1
)
db^{[1]}=\frac{1}{m}np.sum(dZ^{[1]},axis=1)
db[1]=m1np.sum(dZ[1],axis=1)
一般的对于第i层:
d
Z
[
i
]
=
W
[
i
+
1
]
T
d
Z
[
i
+
1
]
∗
σ
[
i
]
′
Z
[
i
]
dZ^{[i]}=W^{{[i+1]^T}}{dZ^{[i+1]}}*\sigma^{[i]^{'}}Z^{[i]}
dZ[i]=W[i+1]TdZ[i+1]∗σ[i]′Z[i]
d
W
[
i
]
=
1
m
d
Z
[
i
]
X
T
dW^{[i]}=\frac{1}{m}dZ^{[i]}X^T
dW[i]=m1dZ[i]XT
d
b
[
i
]
=
1
m
n
p
.
s
u
m
(
d
Z
[
i
]
,
a
x
i
s
=
1
)
db^{[i]}=\frac{1}{m}np.sum(dZ^{[i]},axis=1)
db[i]=m1np.sum(dZ[i],axis=1)
代码示例
本代码将以上图的3层神经网络为例,进行说明反向传播和链式法则。
```python
# 在这里插入代码片
import numpy as np
np.random.seed(1)
# 定义层级大小,并初始化参数
def layer_sizes(X,Y):
'''
X: input dataset ,shape (n_x, number of examples m)
Y: labels , shape (output size 1 , m number of examples)
return: the struct of Neural Network
n_L: a list ,n_L[i]: the size of ith layer
i =0 is the input layer
'''
n_L=[3,4,3,1] # n_l[0] = n_x 特征维度
assert(n_l[0]==X.shape[0] and n_L[-1]==Y.shape[0])
# 初始化参数
parameters={}
for i in range(1,4):
Wi = np.random.randn(n_L[i],n_L[i-1])*0.01
bi = np.random.randn(n_L[i],1)*0.01
str = "layer%d"%(i)
parameters[str]={"W%d"%(i): wi, "W%d"%(i): bi}
return n_L,parameters
# 前向传播函数,中间层tanh作为激活函数,输出层使用 sigmoid ,也可以尝试其他
def forward_propagation(X,parameters):
'''
parameters:
'''
# 需要缓存的中间变量, 用于反向传播
cache = {}
Alast =[]
for i in range(1,4):
L = "layer%d"%(i)
W = parameters[L]["W%d"%(i)]
b = parameters[L]["b%d"%(i)]
Z = np.dot(W,b)
A = np.tanh(Z)
if i==3:
A= 1/(1+np.exp(-Z))
Alast = A
assert(A.shape == (1,X.shape[1]))
cache[L] = {"Z%d"%(i):Z, "A%d"%(i):A}
return Alast,cache
# compute_cost 计算代价
def compute_cost(Alast , Y, parameters):
'''
Alast: 输出层 激活函数的输出
'''
m = Y.shape[1] # the number of example
# Comput the cost
loss = Y*np.log(Alast)+(1-Y)*np.log(1-Alast)
cost = -np.sum(loss)
cost = np.squeeze(cost)
assert(isinstance(cost,float))
return cost
# 反向传播函数
def backward_propagation(parameters, cache ,X, Y):
"""
cache : 缓存的中间变量
"""
m = X.shape[1]
W1 = parameters["layer1"]["W1"]
W2 = parameters["layer2"]["W2"]
W3 = parameters["layer3"]["W3"]
A1 = cache["layer1"]["A1"]
A2 = cache["layer2"]["A2"]
A3 = cache["layer3"]["A3"]
dZ3 = A3-Y
dW3 = np.dot(dZ3,A2.T)/m
db3 = np.sum(dZ3,axis=1,keepdims=True)/m
dZ2 = np.dot(W2.T,dZ3)*(1-np.power(A2,2))
dW2 = np.dot(dZ2,X.T)/m
db2 = np.sum(dZ2,axis=1,keepdims=True)/m
dZ1 = np.dot(W2.T,dZ2)*(1-np.power(A1,2))
dW1 = np.dot(dZ1,X.T)/m
db1 = np.sum(dZ1,axis=1,keepdims=True)/m
return {"dW1":dW1,"db1":db1,"dW2":dW2,"db2":db2,"dW3":dW3,"db3":db3}
一个简单的浅层神经网络 所需的函数 已经完成,应当关注 在计算过程中需要缓存的 数据有哪些,因为在大型深度神经网络中需要分析,中间变量的所占内存的情况。