一.所需包
numpy是用于Python科学计算的基础包。
sklearn提供了用于数据挖掘和数据分析的简单高效的工具。
matplotlib是一个用于在Python中绘制图形的库。
testCases提供了一些测试示例,用于评估您的函数的正确性。
planar_utils提供了在这个任务中使用的各种实用函数。
二.总体过程
-
加载数据
-
确定网络的输入,隐藏单元和输出大小
-
初始化参数
-
前向传播
-
计算代价函数
-
反向传播
-
更新参数
- 整合模型
- 进行预测
当模型接收到输入数据时,它会通过前向传播(forward propagation)的过程产生输出,这个输出就是对输入数据的预测结果
三.具体实现
1.导包
# 导入所需的包
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 # 用于绘制决策边界、加载数据集和其他实用函数
%matplotlib inline
np.random.seed(1) # 设置一个种子以确保结果的一致性
2.加载平面数据
# 加载平面数据集
X, Y = load_planar_dataset()
# 绘制散点图
plt.scatter(X[0, :], X[1, :], c=Y[0, :], s=40, cmap=plt.cm.Spectral)
#这行代码绘制了一个散点图,其中 X[0, :] 是数据集的第一个特征,X[1, :] 是数据集的第二个特征,Y[0, :] 是对应的标签。散点的颜色根据标签的值来确定,使用了Spectral色图。
3.获得训练集的特征数量
# 计算数据集的样本数量和特征维度
m = X.shape[1] # 样本数量
shape_X = X.shape # 特征矩阵的形状
shape_Y = Y.shape # 标签矩阵的形状
4.定义神经网络结构
def layer_sizes(X, Y):
"""
计算神经网络各层的大小
参数:
X -- 输入数据集的形状 (输入大小, 样本数量)
Y -- 标签的形状 (输出大小, 样本数量)
返回:
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)
5.模型参数初始化
def initialize_parameters(n_x, n_h, n_y):
"""
初始化神经网络的参数
参数:
n_x -- 输入层的大小
n_h -- 隐藏层的大小
n_y -- 输出层的大小
返回:
parameters -- 包含参数的Python字典:
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
b1 = np.zeros((n_h, 1))
W2 = np.random.randn(n_y, n_h) * 0.01
b2 = np.zeros((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
6.前向传播
def forward_propagation(X, parameters):
"""
前向传播
参数:
X -- 输入数据,大小为 (n_x, m)
parameters -- 包含参数的Python字典(初始化函数的输出)
返回:
A2 -- 第二个激活函数的S形输出
cache -- 包含 "Z1", "A1", "Z2" 和 "A2" 的字典
"""
# 从字典中获取每个参数
W1 = parameters["W1"]
b1 = parameters["b1"]
W2 = parameters["W2"]
b2 = parameters["b2"]
# 执行前向传播以计算 A2(概率)
Z1 = np.dot(W1, X) + b1
A1 = 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}
return A2, cache
7.计算成本函数
def compute_cost(A2, Y, parameters):
"""
计算交叉熵成本
参数:
A2 -- 第二个激活函数的S形输出,形状为 (1, 样本数量)
Y -- "true" 标签向量,形状为 (1, 样本数量)
parameters -- 包含参数的Python字典(W1, b1, W2 和 b2)
返回:
cost -- 根据公式 (13) 给出的交叉熵成本
"""
m = Y.shape[1] # 样本数量
# 计算交叉熵成本
logprobs = np.multiply(np.log(A2), Y) + np.multiply(np.log(1 - A2), (1 - Y))
cost = - np.sum(logprobs) / m
cost = np.squeeze(cost) # 确保成本是我们期望的维度。例如,将 [[17]] 转换为 17
assert(isinstance(cost, float))
return cost
8.反向传播
def backward_propagation(parameters, cache, X, Y):
"""
实现反向传播
参数:
parameters -- 包含参数的Python字典
cache -- 包含 "Z1", "A1", "Z2" 和 "A2" 的字典
X -- 输入数据,形状为 (2, 样本数量)
Y -- "true" 标签向量,形状为 (1, 样本数量)
返回:
grads -- 包含了相对于不同参数的梯度的Python字典
"""
m = X.shape[1]
# 首先,从字典 "parameters" 中检索 W1 和 W2。
W1 = parameters["W1"]
W2 = parameters["W2"]
# 从字典 "cache" 中检索 A1 和 A2。
A1 = cache["A1"]
A2 = cache["A2"]
# 反向传播: 计算 dW1, db1, dW2, db2.
dZ2 = A2 - Y
dW2 = np.dot(dZ2, A1.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
grads = {"dW1": dW1,
"db1": db1,
"dW2": dW2,
"db2": db2}
return grads
9.更新参数
def update_parameters(parameters, grads, learning_rate=1.2):
"""
使用梯度下降更新参数
参数:
parameters -- 包含参数的Python字典
grads -- 包含梯度的Python字典
learning_rate -- 学习率
返回:
parameters -- 更新后的参数字典
"""
# 从字典 "parameters" 中检索每个参数
W1 = parameters["W1"]
b1 = parameters["b1"]
W2 = parameters["W2"]
b2 = parameters["b2"]
# 从字典 "grads" 中检索每个梯度
dW1 = grads["dW1"]
db1 = grads["db1"]
dW2 = grads["dW2"]
db2 = 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
10.建立神经网络模型
def nn_model(X, Y, n_h, num_iterations=10000, 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]
# 初始化参数,然后检索 W1, b1, W2, b2。输入: "n_x, n_h, n_y"。输出 = "W1, b1, W2, b2, parameters"。
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(0, num_iterations):
# 前向传播。输入: "X, parameters"。输出: "A2, cache"。
A2, cache = forward_propagation(X, parameters)
# 成本函数。输入: "A2, Y, parameters"。输出: "cost"。
cost = compute_cost(A2, Y, parameters)
# 反向传播。输入: "parameters, cache, X, Y"。输出: "grads"。
grads = backward_propagation(parameters, cache, X, Y)
# 梯度下降参数更新。输入: "parameters, grads"。输出: "parameters"。
parameters = update_parameters(parameters, grads, learning_rate=1.2)
# 每1000次迭代打印成本
if print_cost and i % 1000 == 0:
print("迭代次数 %i 次后的成本: %f" % (i, cost))
return parameters
11.进行预测
def predict(parameters, X):
"""
使用学习到的参数,在X中预测每个样本的类别
参数:
parameters -- 包含参数的Python字典
X -- 输入数据,大小为 (n_x, m)
返回:
predictions -- 我们模型的预测向量(红色: 0 / 蓝色: 1)
"""
# 使用前向传播计算概率,并使用0.5作为阈值进行分类为0/1。
A2, cache = forward_propagation(X, parameters)
predictions = (A2 > 0.5).astype(int)
return predictions
12.运行模型
# 使用n_h维隐藏层构建模型
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[0, :])
plt.title("隐藏层大小为 " + str(4) + " 时的决策边界")
#输出准确率
predictions = predict(parameters, X)
print ('Accuracy: %d' % float((np.dot(Y,predictions.T) + np.dot(1-Y,1-predictions.T))/float(Y.size)*100) + '%')
13. 隐藏单元的数量对模型预测准确率的影响
# 设置图形大小
plt.figure(figsize=(16, 32))
# 不同的隐藏层大小
hidden_layer_sizes = [1, 2, 3, 4, 5, 10, 20]
# 遍历每个隐藏层大小
for i, n_h in enumerate(hidden_layer_sizes):
# 在子图中绘制决策边界
plt.subplot(5, 2, i+1)
plt.title('隐藏层大小为 %d' % n_h)
# 使用当前隐藏层大小构建模型并训练
parameters = nn_model(X, Y, n_h, num_iterations=5000)
# 绘制决策边界
plot_decision_boundary(lambda x: predict(parameters, x.T), X, Y[0, :])
# 进行预测并计算准确率
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))
四.总结
本文主要记录如何建立一个浅层的神经网络。