花了大半天时间完成了手推反向和找bug,不得不说这个反向是真的恶心,特别要注意维数的变化。
DeepLearning学习又前进一大步。
这次作业要求:
构建具有单隐藏层的二分类神经网络。
使用具有非线性激活功能激活函数 计算交叉熵损失(损失函数)。
实现向前和向后传播
正式开始首先,导入数据和包:
导入包
import planar_utils
import testCases
#以上是作业提供的py文件
import numpy as np
import matplotlib.pyplot as plt
import sklearn
x_raw,y_raw=planar_utils.load_planar_dataset()#作业中的数据集
利用sklearn自带的逻辑回归来验证上节课的方法准确度(只有53%):
#使用sklearn的logsticRegression训练
clf=sklearn.linear_model.LogisticRegressionCV()#导入模型
clf.fit(x_raw.T,y_raw.T)#训练模型
pred=clf.predict(x_raw.T)#预测
pred.reshape(y_raw.shape)
print("accuracy of logistic: ",100-np.sum(np.abs(pred/1-y_raw))/4,"%")#使用sigma激活函数准确率只有47%
开始构建神经网络,第一步:随机初始化权重系数w和偏移量b
#第一步:随机初始化权重系数w和偏移量b
def init_wb(input_dim,hidden_num,output_dim):
np.random.seed(2) # 设置随机数种子
w1=np.random.randn(input_dim,hidden_num)*0.01#输入层维度*隐藏层节点个数
b1=np.zeros((hidden_num,1))#维度等于隐藏层节点个数*1
w2=np.random.randn(output_dim,hidden_num)*0.01#输出层维度*隐藏层节点个数
b2 = np.zeros((output_dim,1)) # 维度等于输出层维度*1
param={
"w1" : w1,
"b1" : b1,
"w2" : w2,
"b2" : b2
}
return param
第二步构造前向
#第二步构造前向
#隐藏层
def cal_z1(w1,x,b1):#w1维度:x.shape[0]*hidden_num b1维度:hidden_num*1
return np.dot(w1.T,x)+b1 #返回维度hidden_num*x.shape[1]
def cal_tanh(z1):#z1维度hidden_num*x.shape[1]
return np.tanh(z1)
#输出层
def cal_z2(w2,a1,b2):#w2维度:输出层维度*hidden_num a1维度:hidden_num*x.shape[1] b2维度:输出层维度
return np.dot(w2,a1)+b2 #返回维度 输出层维度*x.shape[1]
def cal_sigma(z2):#z2维度 输出层维度*x.shape[1]
return 1/(1+np.exp(-z2))
#前向
def propagation(p,x):
z1=cal_z1(p["w1"],x,p["b1"])
a1=cal_tanh(z1)
z2=cal_z2(p["w2"],a1,p["b2"])
a2=cal_sigma(z2)
return z1,a1,z2,a2
第三步计算损失
def cost_f(a2,y):
m=y.shape[1]#数据个数
return -np.sum(y*np.log(a2)+(1-y)*np.log((1-a2)))/m #这边需要y和a2按位乘,因此不能用np.dot
第四步最变态的后向,就是这里害我卡了一个下午找问题。
看完视频我建议大家手推一遍就能很好理解后向原理了。
还有这里计算dz1为什么用*而不是用np.dot还是不太明白。
#第四步:后向(地狱级难度)视频看了3遍,建议手推计算一遍就很容易理解
def cal_dz2(a2,y): #a2维度:输出层维度*x.shape[1]
return a2-y #a2使用的是σ函数
def cal_dw2_db2(dz2,a1,m):#dz2维度:输出层维度*x.shape[1] a1维度:hidden_num*x.shape[1]
return np.dot(dz2,a1.T)/m,np.sum(dz2,axis=1,keepdims=True)/m#按第2维度求和
def cal_da1(dz2,w2): #dz2维度:输出层维度*x.shape[1] w2维度:输出层维度*hidden_num
return np.dot(dz2.T,w2)
def cal_dz1(da1,a1):#da1维度:x.shape[1]*hidden_num a1维度:hidden_num*x.shape[1]
return da1*(1-(a1*a1)).T#tanh'(z)=1-tanh(z)^2
def cal_dw1_db1(dz1,x,m):#dz1维度: x.shape[1]*hidden_num
return np.dot(x,dz1)/m,np.sum(dz1,axis=0,keepdims=True)/m#按第一维度求和
def backward(x,y,w1,w2,a1,a2,m):
dz2=cal_dz2(a2,y)
dw2,db2=cal_dw2_db2(dz2,a1,m)#dw2维度:输出层维度*hidden_num db2维度:输出层维度*1
da1=cal_da1(dz2,w2)
dz1=cal_dz1(da1,a1)
dw1,db1=cal_dw1_db1(dz1,x,m)#dw1维度:x.shape[0]*hidden_num db1维度: 1*hidden_num
return dw1,db1.T,dw2,db2
第五步更新参数
#第五步:执行梯度下降
def grad_decent(w1,b1,w2,b2,dw1,db1,dw2,db2,learn_rate):
param = {
"w1": w1-learn_rate*dw1,
"b1": b1-learn_rate*db1,
"w2": w2-learn_rate*dw2,
"b2": b2-learn_rate*db2
}
return param
第
六、七步整合训练模型
#第六步:训练模型
def model(learn_rate,loop_num,x,y,input_dim,hidden_num,output_dim):
p=init_wb(input_dim,hidden_num,output_dim)
cost=[]
for i in range(loop_num):
z1,a1,z2,a2=propagation(p,x)
l=cost_f(a2,y)
if i%100==0:
cost.append(l)
dw1,db1,dw2,db2=backward(x,y,p["w1"],p["w2"],a1,a2,x.shape[1])
p=grad_decent(p["w1"],p["b1"],p["w2"],p["b2"],dw1,db1,dw2,db2,learn_rate)
return p,cost
#第七步:预测模型
def predict(p,x):
z1,a1,z2,a2=propagation(p,x)
return np.round(a2)
这里是参数的设置:
#搭建神经网络:设定双层(一个隐藏层4个节点和一个输出层)
#隐藏层激活函数:tanh(z),输出层:σ(z)
#定义神经网络参数
input_dim=x_raw.shape[0]#输入层维数
hidden_num=4#隐藏层节点数
output_dim=y_raw.shape[0]#输出层维数
p,cost=model(1,20000,x_raw,y_raw,input_dim,hidden_num,output_dim)
a2=predict(p,x_raw)
print("准确度为:",100*(1-np.sum(np.abs(a2-y_raw))/x_raw.shape[1]),"%")
plt.plot(cost)
plt.show()
能清楚反映损失函数下降曲线:
隐藏层节点数为4,准确率为90.75%
隐藏层节点数为5,准确率为91%
隐藏层节点数为6,准确率为91.75%
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)