吴恩达深度学习(一)之神经网络和深度学习
第一周 深度学习概论
结构化与非结构化数据
结构化数据: 结构化数据意味着数据的基本数据库,即x(特征)和y都有一个很好的定义
非结构化数据: 比如音频,原始音频或者你想要识别的图像或文本中的内容。这里的特征可能是图像中的像素值或文本中的单个单词。(特征没有明确的定义)
深度学习快速发展的三大原因
1.更快的计算能力
2.更多的数据
3.更好的算法
联系方式
Contact us: feedback@deeplearning.ai
Companies: enterprise@deeplearning.ai
Universities: academic@deeplearning.ai
第二周 神经网络基础
神经网络矩阵设计准则
𝑥:表示一个𝑛𝑥维数据,为输入数据,维度为(𝑛𝑥, 1);
w:表示一个𝑛𝑥维数据,为参数数据,维度为(𝑛𝑥, 1)
𝑦:表示输出结果,取值为(0,1);
(𝑥(𝑖), 𝑦(𝑖)):表示第𝑖组数据,可能是训练数据,也可能是测试数据,此处默认为训练数
据;
𝑋 = [𝑥(1), 𝑥(2), . . . , 𝑥(𝑚)]:表示所有的训练数据集的输入值,放在一个 𝑛𝑥 × 𝑚的矩阵中,其中𝑚表示样本数目;
𝑌 = [𝑦(1), 𝑦(2), . . . , 𝑦(𝑚)]:对应表示所有训练数据集的输出值,维度为1 × 𝑚。
逻辑回归
定义法则
该课程用右侧定义法则,不用左侧的
代价函数
梯度下降运作机制
最低点左边的斜率<0,右边>0,注意自动迭代到最低点后就会停止迭代。红色部分代表代码中的表示准则
利用计算图计算逻辑回归的梯度下降
注意:计算图中的前向传播与反向传播都需要一步一步来,其实反向传播就是求导的链式法则
公式回顾:
a
=
σ
(
z
)
=
1
1
+
e
−
z
a = \sigma (z) = \frac{1}{{1 + {e^{ - z}}}}
a=σ(z)=1+e−z1
∂
σ
(
z
)
∂
z
=
−
(
−
e
(
−
z
)
)
(
1
+
e
−
z
)
2
=
1
1
+
e
−
z
×
e
(
−
z
)
1
+
e
−
z
=
a
×
(
1
−
a
)
\frac{{\partial \sigma (z)}}{{\partial z}} = - \frac{{( - {e^{( - z)}})}}{{{{(1 + {e^{ - z}})}^2}}} = \frac{1}{{1 + {e^{ - z}}}} \times \frac{{{e^{( - z)}}}}{{1 + {e^{ - z}}}} = a \times (1 - a)
∂z∂σ(z)=−(1+e−z)2(−e(−z))=1+e−z1×1+e−ze(−z)=a×(1−a)
单个训练样本
多个训练样本
非向量化(循环,能用向量就不用)
两重循环,第一重遍历每个输入(1:m),第二层,在每个输入中,都要更新所有参数的dw1,…,dwn,db(1:nx+1)
向量化(要远快于循环)
对比上文的循环
#迭代一千次
#维度说明:dw,db,Y,A,Z,W:(nx,1),X:(x(1),…,x(m)),
x(i) :(nx,1)
for iterator in range(1000):
𝑍 = 𝑤T𝑋 + 𝑏 = 𝑛𝑝. 𝑑𝑜𝑡(𝑤. 𝑇, 𝑋) + 𝑏
𝐴 = 𝜎(𝑍)
𝑑𝑍 = 𝐴 − 𝑌
𝑑𝑤 =1/𝑚∗ 𝑋 ∗ 𝑑z𝑇
𝑑𝑏 =1/𝑚∗ 𝑛𝑝. 𝑠𝑢𝑚(𝑑𝑍)
𝑤: = 𝑤 − 𝑎 ∗ 𝑑𝑤
𝑏: = 𝑏 − 𝑎 ∗ 𝑑b
Python/Numpy 广播机制
(1,n)复制m次,(m,1)复制n次
Python/Numpy 矩阵创建与维度验证准则
注意:第一种是完全错误的,永远不要用,因为它在python 中的维度是(5,),这种绝对不能用,因为可能会发生未知错误,第二种,第三种是可以用的,可以用assert检验维度,发现维度错误,可以多多使用reshape(o(1),非常快)
代码
参考的dalao.
注意,图片要归一化
结果中存在一定的过拟合现象,要加入正则化,以后再说
import numpy as np
import matplotlib.pyplot as plt
from lr_utils import load_dataset
#数据准备
train_set_x,train_set_y,test_set_x,test_set_y,classes=load_dataset()
#查看数据维度
print(train_set_x.shape)
print(train_set_y.shape)
print(test_set_x.shape)
print(test_set_y.shape)
#看一个小猫
plt.imshow(test_set_x_orig[2])
plt.show()
#将输入和标签设置成为你需要的输入维度,这两句一个意思
train_set_x=train_set_x.reshape(train_set_x.shape[0],-1).T
test_set_x=test_set_x.reshape(test_set_x.shape[0],test_set_x.shape[1]*test_set_x.shape[2]*test_set_x.shape[3]).T
print(train_set_x.shape)
print(test_set_x.shape)
#归一化
train_set_x=train_set_x/255
test_set_x=test_set_x/255
#sigmoid
def sigmoid(z):
return 1/(1+np.exp(-z))
#逻辑回归传播算法(一次迭代)
def propagate(X,Y,W,b):
#前向传播
m=X.shape[1]
A=sigmoid(np.dot(W.T,X)+b)#(1,12288)*(12288,209)->(1,209)
#代价函数
cost=(-1/m)*np.sum(np.multiply(Y,np.log(A))+np.multiply((1-Y),np.log(1-A)))
cost = np.squeeze(cost)
#反向传播
dz=A-Y
dw=(1/m)*np.dot(X,dz.T)#(12288,209)*(209,1)
db=(1/m)*np.sum(dz)
return dw,db,cost
#梯度下降
def Gradient_descent(X,Y,W,b,iteration,learning_rate):
costs=[]
for i in range(iteration):
dw,db,cost=propagate(X,Y,W,b)
W=W-learning_rate*dw
b=b-learning_rate*db
if i%100==0:
print("迭代{0}次,代价函数为{1}".format(i,cost))
costs.append(cost)
return W,b,costs
#预测结果
def prediction():
#初始化参数都为0
W=np.zeros((train_set_x.shape[0],1))#(12288,1)
b=0
W,b,costs=Gradient_descent(train_set_x,train_set_y,W,b,2000,0.005)
#展示代价变化
fig,ax=plt.subplots(figsize=(12,8))
ax.plot(np.arange(20), costs, 'r')
ax.set_xlabel("iteration(per hundred)")
ax.set_ylabel("cost")
plt.show()
#预测模型
predict_train_y=np.zeros_like(train_set_y)
predict_test_y=np.zeros_like(test_set_y)
A_train=sigmoid(np.dot(W.T,train_set_x)+b)
A_test=sigmoid(np.dot(W.T,test_set_x)+b)
for i in range(train_set_x.shape[1]):
predict_train_y[0,i]=1 if A_train[0,i]>0.5 else 0
for i in range(test_set_x.shape[1]):
predict_test_y[0,i]=1 if A_test[0,i]>0.5 else 0
#打印训练集与测试集准确率
print('训练集识别准确率:{0}%'.format(100-np.mean(abs(train_set_y-predict_train_y))*100))
print('测试集识别准确率:{0}%'.format(100-np.mean(abs(test_set_y-predict_test_y))*100))
prediction()
第三周 浅层神经网络
神经网络的表示
注意:这是一个两层神经网络,因为输入层不算(规定)
神经网络前向传播的输出
单个样本输入
注意
1.w[1],…,w[4]的维度都是(3,1),b就是ML中的那个偏执单元
2.对于w,可以理解为每一行有与输入相同数量(3个)的参数,如对于w[1][1] 便代表了w11,w21,w31因为输出有4个,所有共有4行
多样本输入
注意:
1.横向是训练样本,纵向是隐藏单元
2.z[1](i) 代表了第i个输入样本下的第一个隐藏层(未激活),so on…
激活函数
种类
规则:
1.默认选择Relu
2.sigmoid只用于二分类的输出层
3.不同的层次可以选择不同的非线性激活函数
激活函数对应的导数
1.sigmoid:
a
=
σ
(
z
)
=
1
1
+
e
−
z
a = \sigma (z) = \frac{1}{{1 + {e^{ - z}}}}
a=σ(z)=1+e−z1
∂
σ
(
z
)
∂
z
=
−
(
−
e
(
−
z
)
)
(
1
+
e
−
z
)
2
=
1
1
+
e
−
z
×
e
(
−
z
)
1
+
e
−
z
=
a
×
(
1
−
a
)
\frac{{\partial \sigma (z)}}{{\partial z}} = - \frac{{( - {e^{( - z)}})}}{{{{(1 + {e^{ - z}})}^2}}} = \frac{1}{{1 + {e^{ - z}}}} \times \frac{{{e^{( - z)}}}}{{1 + {e^{ - z}}}} = a \times (1 - a)
∂z∂σ(z)=−(1+e−z)2(−e(−z))=1+e−z1×1+e−ze(−z)=a×(1−a)
2.tanh:
a
=
g
(
z
)
=
tanh
(
z
)
=
e
z
−
e
−
z
e
z
+
e
−
z
a = g(z) = \tanh (z) = \frac{{{e^z} - {e^{ - z}}}}{{{e^z} + {e^{ - z}}}}
a=g(z)=tanh(z)=ez+e−zez−e−z
∂
g
(
z
)
∂
z
=
1
−
a
2
\frac{{\partial g(z)}}{{\partial z}} = 1 - {a^2}
∂z∂g(z)=1−a2
3.Relu:
a
=
g
(
z
)
=
m
a
x
(
0
,
z
)
a = g(z) = max(0,z)
a=g(z)=max(0,z)
∂
g
(
z
)
∂
z
=
{
0
,
i
f
z
<
0
1
,
i
f
z
≥
0
\frac{{\partial g(z)}}{{\partial z}} = \left\{ \begin{array}{l} 0{\rm{ , if z < 0}}\\ 1{\rm{ }},{\rm{ if z}} \ge {\rm{0 }} \end{array} \right.
∂z∂g(z)={0,ifz<01,ifz≥0
4.Leaky Relu:
a
=
g
(
z
)
=
m
a
x
(
0.01
z
,
z
)
a = g(z) = max(0.01z,z)
a=g(z)=max(0.01z,z)
∂
g
(
z
)
∂
z
=
{
0.01
,
i
f
z
<
0
1
,
i
f
z
≥
0
\frac{{\partial g(z)}}{{\partial z}} = \left\{ \begin{array}{l} 0.01{\rm{ , if z < 0}}\\ 1{\rm{ }},{\rm{ if z}} \ge {\rm{0 }} \end{array} \right.
∂z∂g(z)={0.01,ifz<01,ifz≥0
选择非线性激活函数的原因
来看看下图右边的推导:
我们可以发现,如果选择线性激活函数,那么最后的输出其实就是多个参数矩阵的线性组合,那么不如不要激活函数。
只有在一种情况下,神经元可以使用线性激活函数(g(z)=z):即回归问题里的输出层(如房价预测)
反向传播公式及其推导
这是个两层神经网络,n[0],n[1],n[2]=1分别代表输入层,隐藏层,输出层神经元个数
注意:反向传播一定要保证维度相同,然后只有符合计算图,自己调整维度,就不会有错
(1个输入样本的)维度,:
x,a[0]:(n[0],1)
dW[1],W[1]:(n[1],n[0]) ; db[1] ,b[1]:(n[1],1)
dz[1],z[1]:(n[1],1) ; da[1],a[1]:(n[1],1)
dW[2],W[2]:(n[2],n[1]) ; db[2] ,b[2]:(n[2],1)
dz[2],z[2]:(n[2],1) ; da[2],a[2],y:(n[2],1)
开始计算
L
(
a
[
2
]
,
y
)
=
−
y
∗
log
(
a
[
2
]
)
−
(
1
−
y
)
∗
log
(
1
−
a
[
2
]
)
d
a
[
2
]
=
∂
L
(
a
[
2
]
,
y
)
∂
a
[
2
]
=
(
−
y
a
[
2
]
+
y
1
−
a
[
2
]
)
d
z
[
2
]
=
∂
a
[
2
]
∂
z
[
2
]
∗
∂
L
(
a
[
2
]
,
Y
)
∂
a
[
2
]
=
a
[
2
]
(
1
−
a
[
2
]
)
∗
(
−
y
a
[
2
]
+
y
1
−
a
[
2
]
)
=
a
[
2
]
−
y
d
W
[
2
]
=
∂
z
[
2
]
∂
W
[
2
]
∗
d
z
[
2
]
=
d
z
[
2
]
a
[
1
]
T
d
b
[
2
]
=
∂
z
[
2
]
∂
b
[
2
]
∗
d
z
[
2
]
=
d
z
[
2
]
d
a
[
1
]
=
∂
z
[
2
]
∂
a
[
1
]
∗
d
z
[
2
]
=
W
[
2
]
T
∗
d
z
[
2
]
d
z
[
1
]
=
∂
a
[
1
]
∂
z
[
1
]
∗
d
a
[
1
]
=
W
[
2
]
T
∗
d
z
[
2
]
∗
g
[
1
]
′
(
z
[
1
]
)
d
W
[
1
]
=
∂
z
[
1
]
∂
W
[
1
]
∗
d
z
[
1
]
=
x
T
∗
d
z
[
1
]
d
b
[
1
]
=
∂
z
[
1
]
∂
b
[
1
]
∗
d
z
[
1
]
=
d
z
[
1
]
\begin{array}{l} L({a^{[2]}},y) = - y*\log ({a^{[2]}}) - (1 - y)*\log (1 - {a^{[2]}})\\ d{a^{[2]}} = \frac{{\partial L({a^{[2]}},y)}}{{\partial {a^{[2]}}}} = ( - \frac{y}{{{a^{[2]}}}} + \frac{y}{{1 - {a^{[2]}}}})\\ d{z^{[2]}} = \frac{{\partial {a^{[2]}}}}{{\partial {z^{[2]}}}} * \frac{{\partial L({a^{[2]}},Y)}}{{\partial {a^{[2]}}}} = {a^{[2]}}(1 - {a^{[2]}})*( - \frac{y}{{{a^{[2]}}}} + \frac{y}{{1 - {a^{[2]}}}}) = {a^{[2]}} - y\\ {\rm{d}}{W^{[2]}} = \frac{{\partial {z^{[2]}}}}{{\partial {W^{[2]}}}}*d{z^{[2]}} = d{z^{[2]}}{a^{{{[1]}^T}}}\\ {\rm{d}}{{\rm{b}}^{[2]}} = \frac{{\partial {z^{[2]}}}}{{\partial {b^{[2]}}}}*d{z^{[2]}} = d{z^{[2]}}\\ d{a^{[1]}} = \frac{{\partial {z^{[2]}}}}{{\partial {a^{[1]}}}}*d{z^{[2]}} = {W^{{{[2]}^T}}}*d{z^{[2]}}\\ d{z^{[1]}} = \frac{{\partial {a^{[1]}}}}{{\partial {z^{[1]}}}} * d{a^{[1]}} = {W^{{{[2]}^T}}}*d{z^{[2]}}*{g^{[1]'}}({z^{[1]}})\\ d{W^{[1]}} = \frac{{\partial {z^{[1]}}}}{{\partial {W^{[1]}}}}*d{z^{[1]}} = x^T*d{z^{[1]}}\\ d{b^{[1]}} = \frac{{\partial {z^{[1]}}}}{{\partial {b^{[1]}}}}*d{z^{[1]}} = d{z^{[1]}} \end{array}
L(a[2],y)=−y∗log(a[2])−(1−y)∗log(1−a[2])da[2]=∂a[2]∂L(a[2],y)=(−a[2]y+1−a[2]y)dz[2]=∂z[2]∂a[2]∗∂a[2]∂L(a[2],Y)=a[2](1−a[2])∗(−a[2]y+1−a[2]y)=a[2]−ydW[2]=∂W[2]∂z[2]∗dz[2]=dz[2]a[1]Tdb[2]=∂b[2]∂z[2]∗dz[2]=dz[2]da[1]=∂a[1]∂z[2]∗dz[2]=W[2]T∗dz[2]dz[1]=∂z[1]∂a[1]∗da[1]=W[2]T∗dz[2]∗g[1]′(z[1])dW[1]=∂W[1]∂z[1]∗dz[1]=xT∗dz[1]db[1]=∂b[1]∂z[1]∗dz[1]=dz[1]
接下来看m个输入样本(结合梯度下降思考)时
X,A[0]:(n[0],m)
dW[1],W[1]:(n[1],n[0]) ; db[1] ,b[1]:(n[1],m)
dZ[1],Z[1]:(n[1],m) ; dA[1],A[1]:(n[1],m)
dW[2],W[2]:(n[2],n[1]) ; db[2] ,b[2]:(n[2],m)
dZ[2],Z[2]:(n[2],m) ; dA[2],A[2],Y:(n[2],m)**
注意;不用keepdims也可以用reshape
神经网络参数随机初始化的原因
结合上图,如果所有的W都为0,那么所有的A也都为0,那么同一层的dZ将会相同,导致对应得dW里得数都相同,所有参数下降同样的步骤,非常不可取
因此,会有
W2=np.random.randn((n2,n1))*0.01
b2=np.zeros(n2,1)
注意,在神经网络中,如果你使用sigmoid 或者 tahn激活函数,那么W过大会导致Z过大,Z过大会导致激活函数梯度下降很慢(除了最后一层,dZ中有激活函数的导数),影响下降能力。
代码
对一朵画的二元分类,一个隐藏层
import matplotlib.pyplot as plt
import numpy as np
from planar_utils import load_planar_dataset,plot_decision_boundary,sigmoid
#加载并观察数据
X,Y=load_planar_dataset()
print(X.shape,Y.shape)
fig,ax=plt.subplots(figsize=(12,8))
ax.scatter(X[0,:], X[1,:] , c=np.squeeze(Y))#c=np.squeeze(Y),把Y的维度降至(400,)
ax.set_xlabel("x1")
ax.set_ylabel("x2")
plt.show()
初始化参数
def initialization(X,Y,h_number):
#X:(nx,m),Y;(1,m)
nx=X.shape[0]#每个输入的特征数
m=X.shape[1]#一共输入的样本数
n0,n1,n2=nx,h_number,1#神经元维度(nx,h_number,1)
#参数的随机初始化
np.random.seed(2)
W1=np.random.randn(n1,n0)*0.01#randn返回相应维度的标态分布
b1=np.zeros((n1,1))
W2=np.random.randn(n2,n1)*0.01
b2=np.zeros((n2,1))
return W1,b1,W2,b2,m
#传播(包含代价函数计算)
def propagate(X,Y,W1,b1,W2,b2,m):
#前向传播
A1=np.tanh(np.dot(W1,X)+b1)#(n1,m)
A2=sigmoid(np.dot(W2,A1)+b2)#(n2,m),二元分布时输出层可以使用sigmoid
#代价计算
cost= (-1/m)*np.sum(np.multiply(Y,np.log(A2))+np.multiply((1-Y),np.log(1-A2)))
#反向传播
dz2=A2-Y#(n2,m)
dw2=(1/m)*np.dot(dz2,A1.T)#(n2,m)*(m,n1)->(n2,n1)
db2=(1/m)*np.sum(dz2,axis=1,keepdims=True)#(n2,1),axis=1表示按行合并
dz1=np.multiply(np.dot(W2.T,dz2),1-(A1**2))#(n1,n2)*(n2,m)->(n1,m)
dw1=(1/m)*np.dot(dz1,X.T)
db1=(1/m)*np.sum(dz1,axis=1,keepdims=True)#(n1,1)
return dw2,db2,dw1,db1,cost
#构建nn模型
def nn_model(X,Y,h_number,learning_rate,iteration):
W1,b1,W2,b2,m=initialization(X,Y,h_number)
for i in range(1,iteration+1):
dw2,db2,dw1,db1,cost=propagate(X,Y,W1,b1,W2,b2,m)
W2=W2-learning_rate*dw2
b2=b2-learning_rate*db2
W1=W1-learning_rate*dw1
b1=b1-learning_rate*db1
#if i%1000==0:
#print('第{0}轮次的代价为{1}'.format(i,cost))
return W1,b1,W2,b2
#对数据进行预测
def predict(X,W1,b1,W2,b2):
A1=np.tanh(np.dot(W1,X)+b1)#(n1,m)
A2=sigmoid(np.dot(W2,A1)+b2)#(n2,m)
prediction=np.round(A2)#4舍5入,大于0.5为1,小于0.5为0
return prediction
#变换隐藏层来看看效果
plt.figure(figsize=(16, 32))
hidden=[4,7,9,50,78,100]
for i,e in enumerate(hidden):
W1,b1,W2,b2=nn_model(X,Y,e,0.5,10000)
#绘制边界
plt.subplot(5,2,i+1)
plt.title("Decision Boundary for hidden layer size " + str(e))
plot_decision_boundary(lambda x: predict(x.T,W1,b1,W2,b2), X, np.squeeze(Y))
pre_y=predict(X,W1,b1,W2,b2)
accuracy=np.squeeze((np.dot(Y,pre_y.T)+np.dot(1-Y,1-pre_y.T))/Y.shape[1]*100)
print('隐藏层数为{0}时,准确率为{1}%'.format(e,accuracy))
二元分类的边界代码:
二元分类代码精雕
def plot_decision_boundary(model, X, y):
# Set min and max values and give it some padding
x_min, x_max = X[0, :].min() - 1, X[0, :].max() + 1
y_min, y_max = X[1, :].min() - 1, X[1, :].max() + 1
h = 0.01
# Generate a grid of points with distance h between them,绘制出网格图,网格取小,因为更光滑
#若x为[1,2,3],y为[4,5],那么就会绘制出(1,4),(2,4),(3,4),(1,5),(2,5),(3,5),即xx=[[1,2,3],[1,2,3]],yy=[[4,4,4],[5,5,5]]
xx, yy = np.meshgrid(np.arange(x_min, x_max, h), np.arange(y_min, y_max, h))
# Predict the function value for the whole grid,np.c_:按列合并
Z = model(np.c_[xx.ravel(), yy.ravel()])
Z = Z.reshape(xx.shape)
# Plot the contour and training examples,针对每个输入的xx,yy,Z代表对应得高度,不同高度下会显示出不同得颜色
plt.contourf(xx, yy, Z, cmap=plt.cm.Spectral)
plt.ylabel('x2')
plt.xlabel('x1')
plt.scatter(X[0, :], X[1, :], c=y, cmap=plt.cm.Spectral)
第四周 深层神经网络
多层神经网络的传播算法及其各种参数的矩阵维度规则
参数规则
n[0]=2 , n[1]=3 , n[2]=5 , n[3]=4 , n[4]=2 , n[5]=1
l=for i in range(1,6),m:set of input
dW[l],W[l]:(n[l],n[l-1])
db[l],b[l]:(n[l],1)
dA[l],A[l]:(n[l],m)
dZ[l],Z[l]:(n[l],m)
前向传播规则
输入A[l],输出A[l]:
Z[l]=np.dot(W[l],A[l-1])+b[l]
A[l]=g[l](Z[l])
将输出可以保存至一个缓存中,后续继续使用
反向传播规则
时刻想计算图,就不会错
对于逻辑回归,使用交叉熵代价函数时
L:代表最后一层的层次,例如有3个隐藏层时,L=4
dA[L]即在代价函数中,对每一个a[L](i)求偏导
dA[L]=dL(Y,A[L])/dA[L]=(da[L](1),…,da[L](m))
da[L](1)=-y(1)/a[L](1)+(1-y(1))/(1-a[L](1)),依次。。。
就是说不同的代价函数时下你要自己算dA[L]
对于输出层时sigmoid激活函数的dZ[L]=A[L]-Y
推导:dZ[L]=np.multiply(dA[L],g[L]’(Z[L]))
da[L](1) * a[L](1)*(1-a[L](1)),…,da[L] * a[L](m) * (1-a[L](m))=( a[L](1) - y(1)),…,a[L](m) - y(m))
输入dA[l],输出dA[l-1]
dZ[l]=np.multiply(dA[l],g[l]’(Z[l]))
dW[l]=(1/m)*np.dot(dZ[l],A[l-1].T)
db[l]=(1/m)*np.sum(dZ[l],axis=1,keepdim=True)
dA[l-1]=np.dot(W[l].T,dZ[l])
如图所示:
代码(随机NN)
手写一个设计隐藏层列表,就可训练的NN(多层神经网络),识别小猫猫
#加载数据与预处理
import numpy as np
import matplotlib.pyplot as plt
from lr_utils import load_dataset
train_set_x, train_set_y, test_set_x, test_set_y, classes=load_dataset()
print(train_set_x.shape)
print(train_set_y.shape)
print(test_set_x.shape)
print(test_set_y.shape)
#print(test_set_y)
plt.imshow(test_set_x[2])
plt.show()
#我们输入数据,转化为合适的矩阵
train_set_x=train_set_x.reshape(train_set_x.shape[0],-1).T
test_set_x=test_set_x.reshape(test_set_x.shape[0],-1).T
print(train_set_x.shape)
print(test_set_x.shape)
#归一化
train_set_x=train_set_x / 255
test_set_x=test_set_x / 255
#为多个隐藏层的神经网络初始化参数
def initialization(X,Y,hidden_dim):
np.random.seed(3)
parameters={}
n=len(hidden_dim)
parameters['n0']=X.shape[0]
for i in range(1,n+1):
parameters['n'+str(i)]=hidden_dim[i-1]
parameters['W'+str(i)]=np.random.randn(parameters['n'+str(i)],parameters['n'+str(i-1)])/np.sqrt(parameters['n'+str(i-1)])
parameters['b'+str(i)]=np.zeros((parameters['n'+str(i)],1))
#输出层只有一个元素
parameters['n'+str(n+1)]=Y.shape[0]
parameters['W'+str(n+1)]=np.random.randn(parameters['n'+str(n+1)],parameters['n'+str(n)])/np.sqrt(parameters['n'+str(n)])
parameters['b'+str(n+1)]=np.zeros((parameters['n'+str(n+1)],1))
return parameters,n
#sigmoid激活函数
def sigmoid(x):
return 1/(1+np.exp(-x))
#Rele激活函数:
def relu(z):
return np.maximum(0,z)
#前向传播(计算代价函数),除了输出层以外(因为是二元分类,所以输出层可以用sidmoid),一律使用Relu激活单元
def forward_propogate(X,Y,hidden_dim,parameters,n):
cache={}
cache['A0']=X
for i in range(1,n+2):
cache['Z'+str(i)]=np.dot(parameters['W'+str(i)],cache['A'+str(i-1)])+parameters['b'+str(i)]
if i==n+1:
cache['A'+str(i)]=sigmoid(cache['Z'+str(i)])
else:
cache['A'+str(i)]=relu(cache['Z'+str(i)])
#交叉熵代价函数
cost=(-1/Y.shape[1])*np.sum(np.multiply(Y,np.log(cache['A'+str(n+1)]))+np.multiply((1-Y),np.log(1-cache['A'+str(n+1)])))
cost=np.squeeze(cost)
return cache,cost,parameters,n
#反向传播
def backward_propogate(X,Y,hidden_dim,parameters,n):
cache,cost,parameters,n=forward_propogate(X,Y,hidden_dim,parameters,n)
#注意:要倒序,reversed()一下
for i in reversed(range(1,n+2)):
if i==n+1:
cache['dA'+str(i)]=cache['A'+str(i)]-Y
cache['dZ'+str(i)]=np.multiply(cache['dA'+str(i)],np.multiply(cache['A'+str(i)],(1-cache['A'+str(i)])))
cache['dW'+str(i)]=(1/Y.shape[1])*np.dot(cache['dZ'+str(i)],cache['A'+str(i-1)].T)
cache['db'+str(i)]=(1/Y.shape[1])*np.sum(cache['dZ'+str(i)],axis=1,keepdims=True)
cache['dA'+str(i-1)]=np.dot(parameters['W'+str(i)].T,cache['dZ'+str(i)])
#不用求dA0
if i==1:
cache['dZ'+str(i)]=np.array(cache['dA'+str(i)],copy=True)
cache['dZ'+str(i)][cache['Z'+str(i)] <= 0]=0
cache['dW'+str(i)]=(1/Y.shape[1])*np.dot(cache['dZ'+str(i)],cache['A'+str(i-1)].T)
cache['db'+str(i)]=(1/Y.shape[1])*np.sum(cache['dZ'+str(i)],axis=1,keepdims=True)
else:
cache['dZ'+str(i)]=np.array(cache['dA'+str(i)],copy=True)
cache['dZ'+str(i)][cache['Z'+str(i)]<=0]=0
cache['dW'+str(i)]=(1/Y.shape[1])*np.dot(cache['dZ'+str(i)],cache['A'+str(i-1)].T)
cache['db'+str(i)]=(1/Y.shape[1])*np.sum(cache['dZ'+str(i)],axis=1,keepdims=True)
cache['dA'+str(i-1)]=np.dot(parameters['W'+str(i)].T,cache['dZ'+str(i)])
return cache,cost,parameters,n
#拥有了前向与反向传播算法,现在构建一个可以更新参数的函数
def update(X,Y,hidden_dim,learning_rate,parameters,n):
cache,cost,parameters,n=backward_propogate(X,Y,hidden_dim,parameters,n)
for i in range(1,n+2):
parameters['W'+str(i)]=parameters['W'+str(i)]-learning_rate*cache['dW'+str(i)]
parameters['b'+str(i)]=parameters['b'+str(i)]-learning_rate*cache['db'+str(i)]
return cache,cost,parameters,n
#ok,开始构建万能NN网络模型
def model_random_nn(X,Y,hidden_dim,learning_rate,iteration):
parameters,n=initialization(X,Y,hidden_dim)
for i in range(1,iteration+1):
cache,cost,parameters,n=update(X,Y,hidden_dim,learning_rate,parameters,n)
if i%100==0:
print('第{0}次迭代的代价为{1}'.format(i,cost))
return parameters,n
#模型构建好后,返回了梯度下降以后的参数,开始预测模型:
def predict(X,Y,hidden_dim,parameters,n):
cache,cost,parameters,n=forward_propogate(X,Y,hidden_dim,parameters,n)
pre_y=np.zeros_like(cache['A'+str(n+1)])
pre_y[cache['A'+str(n+1)]>0.5]=1
pre_y[cache['A'+str(n+1)]<=0.5]=0
precision=(np.sum(np.multiply(Y,pre_y))+np.sum(np.multiply((1-Y),(1-pre_y))))/Y.shape[1]
print('识别准确率为{0}%'.format(precision*100))
#开始干活吧![12,7]
hidden_dim=[29,9,7]
learning_rate=0.0075
iteration=2500
parameters,n=model_random_nn(train_set_x,train_set_y,hidden_dim,learning_rate,iteration)
predict(test_set_x,test_set_y,hidden_dim,parameters,n)