【数据集的处理】
import numpy as np
import matplotlib.pyplot as plt
m = 400 # number of examples
N = int(m / 2) # number of points per class
D = 2 # dimensionality
X = np.zeros((m,D)) # data matrix where each row is a single example 400*2
Y = np.zeros((m,1), dtype='uint8') # labels vector (0 for red, 1 for blue) uint8 无符号整数 400*1
a = 4 # maximum ray of the flower
for j in range(2):
ix = range(N * j, N * (j + 1))
t = np.linspace(j * 3.12, (j + 1) * 3.12, N) + np.random.randn(N) * 0.2 # theta
#numpy.linspace 函数用于创建一个一维数组,数组是一个等差数列构成的
r = a * np.sin(4 * t) + np.random.randn(N) * 0.2 # radius
X[ix] = np.c_[r * np.sin(t), r * np.cos(t)] #rsint rcost 对应坐标
Y[ix] = j
X = X.T # x 2*400
Y = Y.T # 一半red 一半blue 1*400
plt.scatter(X[0, :], X[1, :], c=Y, s=40, cmap=plt.cm.Spectral) #绘制散点图
# c=Y Y存放标签
# s=40 点的大小
# cmap = plt.cm.Spectral实现的功能是给label为1的点一种颜色,给label为0的点另一种颜色。
plt.show()
【加载数据】
X, Y = load_planar_dataset()
costs = [] # 用于绘制成本函数
引用:搭建神经网络模型
【定义结构】
# 定义神经网络的结构
def layer_sizes(X, Y):
"""
参数:
X - 输入数据集,维度为(输入的数量,训练/测试的数量) 2*400
Y - 标签,维度为(输出的数量,训练/测试数量) 1*400
返回:
n_x - 输入层的数量
n_h - 隐藏层的数量
n_y - 输出层的数量
"""
n_x = X.shape[0] # 输入层
n_h = 4 # ,隐藏层,硬编码为4
n_y = Y.shape[0] # 输出层
return (n_x, n_h, n_y)
【初始化参数】
# 初始化模型参数
def initialize_parameters(n_x, n_h, n_y):
"""
参数:
n_x - 输入层节点的数量 X每个样本的特征数 2
n_h - 隐藏层节点的数量
n_y - 输出层节点的数量
返回:
parameters - 包含参数的字典:
W1 - 权重矩阵,维度为(n_h,n_x)
b1 - 偏向量,维度为(n_h,1)
W2 - 权重矩阵,维度为(n_y,n_h)
b2 - 偏向量,维度为(n_y,1)
"""
np.random.seed(2) # 指定一个随机种子,以便输出一样。
W1 = np.random.randn(n_h, n_x) * 0.01 # 0.01参数 权重不能太大 w1不能全为0
b1 = np.zeros(shape=(n_h, 1)) # b参数可以为0
W2 = np.random.randn(n_y, n_h) * 0.01
b2 = np.zeros(shape=(n_y, 1))
# 使用断言确保数据格式是正确的
assert (W1.shape == (n_h, n_x)) # 4 2
assert (b1.shape == (n_h, 1)) # 2 1
assert (W2.shape == (n_y, n_h)) # 1 2
assert (b2.shape == (n_y, 1)) # 1 1
parameters = {"W1": W1,
"b1": b1,
"W2": W2,
"b2": b2}
return parameters
【前向传播】
# 前向传播
def forward_propagation(X, parameters):
"""
参数:
X - 维度为(n_x,m)的输入数据。 2 400
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 # Z1=W1 * X + b1 == WX * A0 + b1
# np.dot()函数主要有两个功能,向量点积和矩阵乘法
A1 = np.tanh(Z1) # 采用tanh()作为激活函数 优于sigmoid()
# 传入矩阵 对Z1中每个元素做 np.tanh(Z1)
Z2 = np.dot(W2, A1) + b2
A2 = sigmoid(Z2)
# 使用断言确保我的数据格式是正确的
assert (A2.shape == (1, X.shape[1]))
cache = {"Z1": Z1,
"A1": A1,
"Z2": Z2,
"A2": A2}
'''
参数维度
W1: (4, 2) ----4个隐藏单元,2个输入的特征
X: (2, 400) ----A0 2个输入特征,400个样本
b1: (4, 1) ----4个隐藏单元,每个有1个b1值
Z1: (4, 400)----Z1
A1: (4, 400) A1 = np.tanh(Z1)
W2: (1, 4) ----1个隐藏单元,4个输入特征(由4个隐藏单元输入)
b2: (1, 1) ----1个单元,1个b2
Z2: (1, 400)----(1,4)*(4,400)-->(1,400)
A2: (1, 400)----A2=sigmoid(Z2)
'''
return (A2, cache)
# 计算成本
def compute_cost(A2, Y, parameters):
"""
计算方程中给出的交叉熵成本,
参数:
A2 - 使用sigmoid()函数计算的第二次激活后的数值
Y - "True"标签向量,维度为(1,数量)
parameters - 一个包含W1,B1,W2和B2的字典类型的变量
返回:
成本 - 交叉熵成本给出方程
"""
m = Y.shape[1]
# 计算成本
cost = (- 1 / m) * np.sum(Y * np.log(A2+10**-10) + (1 - Y) * np.log(1 - A2+10**-10))
# +10**-10 防止极小值被识别为/0
# (1,400) * (1,400)->(1,400) 对应列元素相乘
# np.sum是NumPy中的聚合函数,可用于对矩阵的某一个维度求和,axis=1对矩阵的每一行求和;
# keepdims=True,如果聚合函数返回的是一个向量(返回标量就无所谓了),该参数的作用是保持维度,
# 用2维数组(n,1)表示该向量,避免产生一维数组(n,)表示向量;
# 也可以不使用该参数,把计算出的结果再调用reshape(-1,1)函数调整为2维数组表示该向量。
cost = float(np.squeeze(cost))
assert (isinstance(cost, float))
return cost
【后向传播】
主要是参数的推导和维度确认
# 反向传播
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]
W1 = parameters["W1"]
W2 = parameters["W2"]
A1 = cache["A1"]
A2 = cache["A2"]
dZ2 = A2 - Y
dW2 = (1 / m) * np.dot(dZ2, A1.T)
db2 = (1 / m) * np.sum(dZ2, axis=1, keepdims=True)
# axis = 1横轴,左到右 axis = 0 纵轴,上到下
dZ1 = np.multiply(np.dot(W2.T, dZ2), 1 - np.power(A1, 2))
dW1 = (1 / m) * np.dot(dZ1, X.T)
db1 = (1 / m) * np.sum(dZ1, axis=1, keepdims=True)
grads = {"dW1": dW1,
"db1": db1,
"dW2": dW2,
"db2": db2}
return grads
【更新参数】
# 更新参数
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
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
【建立模型】
# 建立模型
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_sizes(X, Y)[0]
n_y = layer_sizes(X, Y)[2]
parameters = initialize_parameters(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)
costs.append(cost)
if i%1000 == 0 :
if print_cost:
print("第 ", i, " 次循环,成本为:" + str(cost))
return parameters
【预测】
# 预测模型
def predict(parameters, X):
"""
使用学习的参数,为X中的每个示例预测一个类
参数:
parameters - 包含参数的字典类型的变量。
X - 输入数据(n_x,m)
返回
predictions - 我们模型预测的向量(红色:0 /蓝色:1)
"""
# 前向传播一次 输出A2,cache
A2, cache = forward_propagation(X, parameters)
# np.round() 四舍五入A2
predictions = np.round(A2)
return predictions
【生成】
# 模型生成参数
parameters = nn_model(X, Y, n_h = 4, num_iterations=10000, print_cost=True)
# 成本函数
plt.plot(costs) #取COSTS
plt.xlabel(['per iter'])
plt.ylabel(['cost'])
plt.show()
# 绘制边界
plot_decision_boundary(lambda x: predict(parameters, x.T), X, Y)
plt.title("Decision Boundary for hidden layer size " + str(4))
plt.show()
predictions = predict(parameters, X)
# 预测标签与真实标签
print ('准确率: %d' % float((np.dot(Y, predictions.T) + np.dot(1 - Y, 1 - predictions.T)) / float(Y.size) * 100) + '%')