import numpy as np
import matplotlib.pyplot as plt
from testCases import *
import sklearn #机器学习库,分类,聚类,回归,降维和加载或生成数据集
import sklearn.datasets
import sklearn.linear_model
from planar_utils import plot_decision_boundary, sigmoid, load_planar_dataset, load_extra_datasets
关于 testCases.py 以及 planar_utils.py如有需要可以留言。
np.random.seed(1) #指定固定随机数
调用其他的数据集
noisy_circles, noisy_moons, blobs, gaussian_quantiles, no_structure = load_extra_datasets()
以字典的方式来选择使用哪个数据集
datasets = {"noisy_circles": noisy_circles,
"noisy_moons": noisy_moons,
"blobs": blobs,
"gaussian_quantiles": gaussian_quantiles}
dataset = "noisy_circles" #选择有噪声的数据集
X, Y = datasets[dataset]
X, Y = X.T, Y.reshape(1, Y.shape[0])
if dataset == "blobs":
Y = Y % 2
plt.scatter(X[0, :], X[1, :], c=Y, s=40, cmap=plt.cm.Spectral)
plt.scatter(X[0, :], X[1, :], c=np.squeeze(Y), s=40, cmap=plt.cm.Spectral)
X[0, :]:散点图横坐标,X[1, :]:散点图纵坐标,C:色彩label标记,Spectral为不同的标记涂上不同的颜色(例如:0代表红,1代表蓝)
'''X,Y=load_planar_dataset();
plt.scatter(X[0,:],X[1,:],c=Y,s=40,cmap=plt.cm.Spectral)
绘制散点图
plt.scatter(X[0, :], X[1, :], c=np.squeeze(Y), s=40, cmap=plt.cm.Spectral)'''
shape_X=X.shape
shape_Y=Y.shape
m=Y.shape[1]
print("X的维度为:"+str(shape_X)) #(2,200,其中2代表横纵坐标数,200为数量)
print("Y的维度为:"+str(shape_Y)) #(1,200,200个0,1标记)
print("数据集里面的数据有:"+str(m)+"个")#200
--------使用逻辑回归分类器---------------
clf=sklearn.linear_model.LogisticRegressionCV()
clf.fit(X.T,Y.T) #进行训练
-------绘图
plot_decision_boundary(lambda x: clf.predict(x),X,Y) #绘制预测后的决策边缘
plt.title("Logistic Regression")
LR_predictions=clf.predict(X.T)
print ("逻辑回归的准确性: %d " % float((np.dot(Y, LR_predictions) +
np.dot(1 - Y,1 - LR_predictions)) / float(Y.size) * 100) +
"% " + "(预测出正确的0和1标记数据点所占的百分比)") #dot矩阵相乘,multiply,*对应元素相乘
------------定义神经网络结构-------
def layer_size(X,Y):
"""
参数:
X - 输入数据集,维度为(输入的数量,训练/测试的数量)2,200
Y - 标签,维度为(输出的数量,训练/测试数量)1,200
返回:
n_x - 输入层的数量
n_h - 隐藏层的数量
n_y - 输出层的数量
"""
n_x=X.shape[0] #输入层 2
n_h=4 #隐藏层,硬编码为4
n_y=Y.shape[0] #输出层 1
"""print("输入层: n_x = " + str(n_x))
print("隐藏层: n_h= " + str(n_h))
print("输出层: n_y = " + str(n_y))"""
return (n_x,n_h,n_y) #2,4,1
-----------测试layer sizes-----------
print("-------------测试layer sizes------------")
X_asses,Y_asses=layer_sizes_test_case();
(n_x,n_h,n_y)=layer_size(X_asses,Y_asses)
print("输入层的节点数量为: n_x = " + str(n_x))
print("隐藏层的节点数量为: n_h = " + str(n_h))
print("输出层的节点数量为: n_y = " + str(n_y))
-------------初始化模型参数----------------
def initialize_parameter(n_x,n_h,n_y):
"""
参数:
n_x - 输入层节点的数量
n_h - 隐藏层节点的数量
n_y - 输出层节点的数量
返回:
parameters - 包含参数的字典:
W1 - 权重矩阵,维度为(n_h,n_x)#设置这样的参数维度才能用于后面矩阵的计算
b1 - 偏向量,维度为(n_h,1)
W2 - 权重矩阵,维度为(n_y,n_h)
b2 - 偏向量,维度为(n_y,1)
维度:W1(4,2),b1(4,1) ,W2(1,4),b2(1,1)
"""
np.random.seed(2) #指定一个随机种子,以便你的输出与我们的一样。
W1=np.random.randn(n_h,n_x)*0.01 #随机初始化最初的参数值
b1=np.zeros(shape=(n_h,1))
W2=np.random.randn(n_y,n_h)*0.01
b2=np.zeros(shape=(n_y,1))
#使用断言确保我的数据格式是正确的
assert(W1.shape == ( n_h , n_x ))
assert(b1.shape == ( n_h , 1 ))
assert(W2.shape == ( n_y , n_h ))
assert(b2.shape == ( n_y , 1 ))
parameters={"W1":W1,
"b1":b1,
"W2":W2,
"b2":b2}
return parameters
-----------------测试初始化参数-----------
print("------------测试初始化参数-----------")
n_x,n_h,n_y= initialize_parameters_test_case()
parameters=initialize_parameter(n_x,n_h,n_y)
print("W1="+str(parameters["W1"]))
print("b1="+str(parameters["b1"]))
print("W2="+str(parameters["W2"]))
print("b2="+str(parameters["b2"]))
----------向前传播------------------------
def forward_propagation(X, parameters):
"""
参数:
X - 维度为(n_x,m)的输入数据。
parameters - 初始化函数(initialize_parameters)的输出
返回:
A2 - 使用sigmoid()函数计算的第二次激活后的数值
cache - 包含“Z1”,“A1”,“Z2”和“A2”的字典类型变量
"""
W1=parameters["W1"] #从字典中取出参数
b1=parameters["b1"]
W2=parameters["W2"]
b2=parameters["b2"]
#向前传播计算A2
Z1=np.dot(W1,X)+b1 #按照向前传播公式计算,维度(4,2).(2,200)=(4,200)
A1=np.tanh(Z1) #从输入层到隐藏层使用激活函数tanh(4,200)
Z2=np.dot(W2,A1)+b2 #继续向前传播(1,4).(4,200)=(1,200)
A2=sigmoid(Z2) #二分的 #从隐藏层到输出层使用激活函数sigmoid,特别适用于只有二分情况,A2即为向前传播时对数据的预测值,若A2值大于0.5即预测结果为标记1。(1,200)
#使用断言确保我的数据格式是正确的
assert(A2.shape == (1,X.shape[1]))
cache={"Z1":Z1,
"A1":A1,
"Z2":Z2,
"A2":A2}
return (A2,cache)
测试forward_propagation
print("=========================测试forward_propagation=========================")
X_assess, parameters = forward_propagation_test_case()
A2, cache = forward_propagation(X_assess, parameters)
print(np.mean(cache["Z1"]), np.mean(cache["A1"]), np.mean(cache["Z2"]), np.mean(cache["A2"]))
--------------计算cost(损失、成本)-----------------
计算交叉熵损失
def compute_cost(A2,Y,parameters):
"""
计算方程(6)中给出的交叉熵成本,
参数:
A2 - 使用sigmoid()函数计算的第二次激活后的数值
Y - "True"标签向量,维度为(1,数量)
parameters - 一个包含W1,B1,W2和B2的字典类型的变量
返回:
成本 - 交叉熵成本给出方程(13)
"""
m=Y.shape[1]
#计算成本
logprobs= logprobs=np.multiply(np.log(A2),Y)+np.multiply((1-Y),np.log(1-A2))
cost=-np.sum(logprobs)/m
cost=float(np.squeeze(cost))
assert(isinstance(cost,float))
return cost
测试compute_cost
print("=========================测试compute_cost=========================")
A2 , Y_assess , parameters = compute_cost_test_case()
print("cost = " + str(compute_cost(A2,Y_assess,parameters)))
--------------向后传播-------------------------------
def backward_propagation(parameters,cache,X,Y):
"""
使用上述说明搭建反向传播函数。
参数:
parameters - 包含我们的参数的一个字典类型的变量。
cache - 包含“Z1”,“A1”,“Z2”和“A2”的字典类型的变量。
X - 输入数据,维度为(2,数量)
Y - “True”标签,维度为(1,数量)
返回:
grads - 包含W和b的导数一个字典类型的变量。
"""
m=X.shape[1] #200
W1=parameters["W1"]
W2=parameters["W2"]
A1=cache["A1"]
A2=cache["A2"]
dZ2=A2-Y #维度(1,200)-(1-200),(1,200)
dW2=(1/m)*np.dot(dZ2,A1.T)#维度(1,200).(200,4)=(1,4)
db2=(1/m)*np.sum(dZ2,axis=1,keepdims=True) #axis=1指按行进行求和计算(1,1)
dZ1=np.multiply(np.dot(W2.T,dZ2),1-np.power(A1,2))#维度(4,1).(1,200)=(4,200),(4,200)
dW1=(1/m)*np.dot(dZ1,X.T)#维度(4,200).(200,2)=(4,2)
db1=(1/m)*np.sum(dZ1,axis=1,keepdims=True)#维度(4,1)
grads={"dW1":dW1,
"db1":db1,
"dW2":dW2,
"db2":db2}
return grads
测试backward_propagation
print("=========================测试backward_propagation===================")
parameters, cache, X_assess, Y_assess = backward_propagation_test_case()
grads = backward_propagation(parameters, cache, X_assess, Y_assess)
print ("dW1 = "+ str(grads["dW1"]))
print ("db1 = "+ str(grads["db1"]))
print ("dW2 = "+ str(grads["dW2"]))
print ("db2 = "+ str(grads["db2"]))
----------------更新参数----使用(dW1, db1, dW2, db2)来更新(W1, b1, W2, b2)
def update_parameters(parameters,grads,learning_rate=1.2):
"""
使用上面给出的梯度下降更新规则更新参数
参数:
parameters - 包含参数的字典类型的变量。
grads - 包含导数值的字典类型的变量。
learning_rate - 学习速率
返回:
parameters - 包含更新参数的字典类型的变量。
"""
W1,W2=parameters["W1"],parameters["W2"]
b1,b2=parameters["b1"],parameters["b2"]
dW1,dW2=grads["dW1"],grads["dW2"]
db1,db2=grads["db1"],grads["db2"]
W1=W1-learning_rate*dW1 #使用梯度下降法,循环num_iterations次
b1=b1-learning_rate*db1
W2=W2-learning_rate*dW2
b2=b2-learning_rate*db2
parameters = {"W1": W1,
"b1": b1,
"W2": W2,
"b2": b2}
return parameters
测试update_parameters
print("=========================测试update_parameters=========================")
parameters, grads = update_parameters_test_case()
parameters = update_parameters(parameters, grads)
print("W1 = " + str(parameters["W1"]))
print("b1 = " + str(parameters["b1"]))
print("W2 = " + str(parameters["W2"]))
print("b2 = " + str(parameters["b2"]))
---------------整合-------------
def nn_model(X,Y,n_h,num_iterations,print_cost=False): #程序的入口
"""
参数:
X - 数据集,维度为(2,示例数)
Y - 标签,维度为(1,示例数)
n_h - 隐藏层的数量
num_iterations - 梯度下降循环中的迭代次数
print_cost - 如果为True,则每1000次迭代打印一次成本数值
返回:
parameters - 模型学习的参数,它们可以用来进行预测。
"""
np.random.seed(3) #指定随机种子
n_x = layer_size(X, Y)[0] #取出返回参数的第一个值
n_y = layer_size(X, Y)[2] #取出返回参数的第三个值
parameters = initialize_parameter(n_x,n_h,n_y)
W1 = parameters["W1"]
b1 = parameters["b1"]
W2 = parameters["W2"]
b2 = parameters["b2"]
for i in range(num_iterations):
A2 , cache = forward_propagation(X,parameters)
cost = compute_cost(A2,Y,parameters)
grads = backward_propagation(parameters,cache,X,Y)
parameters = update_parameters(parameters,grads,learning_rate = 0.5)
if print_cost:
if i%1000 == 0:
print("第 ",i," 次循环,成本为:"+str(cost))
return parameters
测试nn_model
print("=========================测试nn_model=========================")
X_assess, Y_assess = nn_model_test_case()
parameters = nn_model(X_assess, Y_assess, 4, num_iterations=10000, print_cost=False)
print("W1 = " + str(parameters["W1"]))
print("b1 = " + str(parameters["b1"]))
print("W2 = " + str(parameters["W2"]))
print("b2 = " + str(parameters["b2"]))
--------------预测------------------------------------------------
def predict(parameters,X):
"""
使用学习的参数,为X中的每个示例预测一个类
参数:
parameters - 包含参数的字典类型的变量。
X - 输入数据(n_x,m)
返回
predictions - 我们模型预测的向量(红色:0 /蓝色:1)
"""
A2,cache=forward_propagation(X,parameters)
predictions=np.round(A2)
return predictions
测试predict
print("=========================测试predict=========================")
parameters, X_assess = predict_test_case()
predictions = predict(parameters, X_assess)
print("预测的平均值 = " + str(np.mean(predictions)))
-------------正式的运行---------------
parameters=nn_model(X,Y,n_h=4,num_iterations=10000,print_cost=True)
绘制边界
plot_decision_boundary(lambda x:predict(parameters,x.T),X,Y)
plt.title("Decision Boundary for hidden layer size " + str(4))
predictions=predict(parameters,X)
print('准确率:%d'%float((np.dot(Y,predictions.T)+np.dot(1-Y,1-predictions.T))/float(Y.size)*100)+'%')
--------------更深入的探讨-----------------
更改隐藏层节点数
plt.figure(figsize=(16,32))
hidden_layer_sizes=[1,2,3,4,5,20,50]
for i, n_h in enumerate(hidden_layer_sizes):
plt.subplot(5,2,i+1)
plt.title("Hidden Layer of size %d" %n_h)
parameters = nn_model(X,Y,n_h,num_iterations=8000)
plot_decision_boundary(lambda x:predict(parameters,x.T),X,Y)
predictions=predict(parameters,X)
accuracy=float((np.dot(Y,predictions.T)+np.dot(1-Y,1-predictions.T))/float(Y.size)*100)
#正确标记的数据点所占的百分比,正确标记的红色点和蓝色点数量之和
print("隐藏层的节点数量:{},准确率:{}%".format(n_h,accuracy))
---------------------------------------------对代码理解的总结---------------------------------------------------------
程序首先需要定义这种单隐层神经网络结构即每一层节点的数量,本次程序输入层数量为2,隐藏层数量为4,输出层数量为1。然后基于该结构来初始化模型的参数,一般会赋随机初始值。接着使用向前传播公式计算出Z1,使用激活函数计算出A1,再计算出Z2,再使用激活函数计算出A2,若A2大于0.5则,预测值为1。然后使用向后传播的方式,由A2算出dW2,db2,dW1,db1,通过回传的方式以梯度下降法来更新模型最开始设置的随机W1,b1,W2,b2的值,通过不断的迭代,最后训练出较好的W1,b1,W2,b2的值,来获得想要的A2预测值,计算出该模型的准确率。我们使用成本函数cost分别对参数Z2,W2,b2,Z1,W1,b1求偏导,经过计算简化后的等式如代码所列计算公式,包括对激活函数求导,使用不同的激活函数,最后求解的例如dZ2等参数值的导数值会不同,不再是代码所列公式。
---------------------------------------------------分割线(实验的结果)---------------------------------------------
可以看出该模型有一定的效果,相比逻辑回归效果好些。