【机器学习】任务十:从函数分析到机器学习应用与BP神经网络
目录
1.从函数分析到机器学习应用
1.1 3D曲面图可视化报告
1.1.1 目标
本次代码的目标是生成一个3D曲面图,用于展示数学函数 f(x,y)=−(x2+y2)的特性。通过在指定范围内绘制该函数,直观展示其三维空间中的变化情况。
1.1.2 代码分析
(1)函数定义:
def fun(x, y):
return -(np.power(x, 2) + np.power(y, 2))
函数 fun(x, y)
用于计算 −(x2+y2)的值,这是一种二次函数,其结果用于生成曲面图的Z轴值,构成抛物面。
(2)3D图表设置:
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
通过 plt.figure()
初始化图表,并添加了一个3D子图(projection='3d')用于绘制三维曲面。
(3)数据生成:
X0 = np.arange(-3, 3, 0.25)
X1 = np.arange(-3, 3, 0.25)
X0, X1 = np.meshgrid(X0, X1)
Z = fun(X0, X1)
使用 np.arange
生成从-3到3的范围,步长为0.25的数列。np.meshgrid
将生成的X0和X1网格化,形成二维坐标平面,随后通过 fun(X0, X1)
计算Z轴值。
(4)曲面绘制:
surf = ax.plot_surface(X0, X1, Z, cmap=plt.cm.winter)
使用 plot_surface
绘制曲面图,并通过 cmap=plt.cm.winter
设置了颜色映射,以便通过颜色反映Z值的大小。
(5)坐标轴标签:
ax.set_xlabel('X0', color='r')
ax.set_ylabel('X1', color='g')
ax.set_zlabel('f(x)', color='b')
设置了每个坐标轴的标签,并分别使用红色(X轴)、绿色(Y轴)和蓝色(Z轴)标注,增强了图表的可视化效果。
(6)颜色条:
fig.colorbar(surf)
添加了颜色条,帮助解释图表中颜色和Z值的对应关系。
(7)总体代码:
import numpy as np
import matplotlib.pyplot as plt
# 定义函数
def fun(x, y):
return -(np.power(x, 2) + np.power(y, 2))
# 创建 3D 图形对象
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d') # 添加3D子图
# 生成数据
X0 = np.arange(-3, 3, 0.25)
X1 = np.arange(-3, 3, 0.25)
X0, X1 = np.meshgrid(X0, X1)
Z = fun(X0, X1)
# 绘制曲面图,并使用 cmap 着色
surf = ax.plot_surface(X0, X1, Z, cmap=plt.cm.winter)
ax.set_xlabel('X0', color='r')
ax.set_ylabel('X1', color='g')
ax.set_zlabel('f(x)', color='b') # 给三个坐标轴注明坐标名称
# 添加颜色条
fig.colorbar(surf)
plt.show()
1.1.3 结果分析
生成的图表展示了函数 f(x,y)=−(x2+y2)的抛物面特性,呈现一个以原点为中心的对称碗状结构。颜色从蓝到绿,代表Z值从低到高的变化。右侧的颜色条清晰标注了每种颜色对应的具体值范围。
1.1.4 观察与总结
- 图表清晰地展示了函数的形态,其对称性和凹形特性一目了然。
- 使用颜色渐变提高了数据的直观表现能力,有助于快速理解函数的深度和高度变化。
- 坐标轴的颜色标注增强了可读性,使得三个维度的意义更加明确。
1.1.5 结论
该3D曲面图成功地将数学函数的空间特性可视化,为多变量函数的探索提供了直观的工具。类似的图表对于研究函数的分布特性、对称性或寻找极值点具有重要意义。
1.2 一元函数梯度计算报告
1.2.1 目标
本次代码的目标是通过TensorFlow框架,计算函数 f(x)=x2+2x−1 在指定点 x=2 处的一阶梯度(即导数)。
1.2.2 代码分析
(1)函数定义:
def func(x):
return x ** 2 + 2 * x - 1
定义了一元二次函数 f(x)=x2+2x−1。该函数的导数可通过自动微分工具计算,或手动计算为 f′(x)=2x+2。
(2)自动梯度计算:
with tf.GradientTape() as tape:
tape.watch(x)
y = func(x)
使用 TensorFlow 的 tf.GradientTape
实现自动梯度计算。tape.watch(x)
监测变量 x
的变化,确保其参与梯度计算。
(3)梯度提取:
order_1 = tape.gradient(target=y, sources=x)
调用 tape.gradient
方法,计算目标函数 y
对变量 x
的一阶梯度。
(4)输出结果:
print("函数 x ** 2 + 2 * x - 1 在 x = 2 处的梯度为: ", order_1.numpy())
将计算出的梯度转为NumPy数组,并在终端打印结果。
1.2.4 计算结果
根据代码执行,函数 f(x)=x2+2x−1 在 x=2 处的一阶导数为: f′(x)=2x+2代入 x=2,可得: f′(2)=2×2+2=6
程序输出与手动计算一致,验证了代码的正确性。
1.2.5 优势与意义
(1)代码优势:
- 利用 TensorFlow 自动微分机制,无需手动推导导数公式,适合复杂函数梯度计算。
- 可扩展至更高维度、多变量函数的梯度和偏导数计算。
(2)应用场景:
- 自动梯度计算在机器学习中十分重要,广泛应用于反向传播算法中优化模型参数。
- 数学建模或科学计算中,也可用于快速验证导数或梯度公式的正确性。
1.2.6 结论
本代码成功计算了一元二次函数在给定点的梯度,结果准确无误。TensorFlow 的自动梯度工具不仅提升了计算效率,也大幅减少了手动推导的可能错误。
1.3 一元函数梯度和二阶导数计算报告
1.3.1 目标
本次代码的目标是通过TensorFlow框架,计算函数 f(x)=x2+2x−1 在指定点 x=2 处的一阶梯度和二阶导数,验证自动微分机制的准确性。
1.3.2 代码分析
(1)变量定义:
x = tf.Variable(2.0, trainable=True)
定义变量 xxx,设置其值为 2.0,并声明其为可训练变量,以便被 GradientTape
监测并参与梯度计算。
(2)嵌套的梯度计算:
with tf.GradientTape() as tape1:
with tf.GradientTape() as tape2:
y = x ** 2 + 2 * x - 1
order_1 = tape2.gradient(y, x)
order_2 = tape1.gradient(order_1, x)
- 第一层
tape2
负责计算目标函数 f(x)f(x)f(x) 的一阶梯度。 - 第二层
tape1
监测一阶梯度的变化,计算其对 xxx 的导数,从而得到函数的二阶导数。
(3)结果输出:
print("在 x = 2 处的一阶梯度为: ", order_1.numpy())
print("在 x = 2 处的二阶梯度为: ", order_2.numpy())
将一阶梯度和二阶梯度的计算结果打印出来。
1.3.3 计算结果
根据程序输出:
- 一阶梯度(导数):f′(x)=2x+2,在 x=2 时,f′(2)=2×2+2=6。
- 二阶导数:f′′(x)=2,为常数。在 x=2 时,f′′(2)=2。
两项结果与手动计算完全一致,验证了代码的正确性。
1.3.4 优势与意义
代码优势:
- 利用
GradientTape
实现嵌套梯度计算,无需显式推导复杂函数的二阶导数,尤其适用于多变量函数的高阶导数计算。 - 灵活性高,可扩展至任意阶梯度计算。
应用场景:
- 高阶导数计算在物理建模(如加速度计算)和机器学习优化中(如Hessian矩阵计算)具有广泛应用。
- 自动微分降低了复杂计算的门槛,适合分析函数的曲率和极值点。
1.3.5 结论
本代码成功计算了一元二次函数在指定点的梯度和二阶导数,结果精确,充分体现了 TensorFlow 自动微分工具的强大功能。代码逻辑清晰,适合作为高阶导数计算的模板。
1.4 多元函数梯度计算报告
1.4.1 目标
本次代码的目标是利用 TensorFlow 框架,计算多元函数
在点 x=[1.0,2.0,3.0] 处的梯度。
1.4.2 代码分析
(1)函数定义:
def func(x):
return x[0] ** 2 + 3 * x[0] * x[1] + x[1] ** 2 + x[2] ** 3
定义了一个多元函数 f(x)f(x)f(x),其中 xxx 是一个三维张量。该函数包含二次项和三次项的组合。
(2)自动梯度计算:
x = tf.Variable([1.0, 2.0, 3.0], dtype=tf.float32)
with tf.GradientTape() as tape:
tape.watch(x)
y = func(x)
- 变量
x
被定义为可训练张量,初值为 [1.0,2.0,3.0]。 - 通过
GradientTape
监控张量x
,对其参与的运算生成梯度。
(3)梯度提取:
order_1 = tape.gradient(target=y, sources=x)
print("多元函数 x = [1.0, 2.0, 3.0] 的梯度为:", [grad.numpy() for grad in order_1])
- 使用
tape.gradient
方法计算目标函数 f(x) 对x
的一阶梯度。 - 因为
x
是一个张量列表,其梯度也是一个张量列表,逐项提取值后输出。
(4)输出结果: 程序输出:
多元函数 x = [1.0, 2.0, 3.0] 的梯度为: [8.0, 7.0, 27.0]
1.4.3 梯度计算解析
多元函数的梯度为:
在 x=[1.0,2.0,3.0]x = [1.0, 2.0, 3.0]x=[1.0,2.0,3.0] 处,逐项计算:
程序计算的结果与手动推导一致,验证了代码的正确性。
1.4.4 优势与意义
(1)代码优势:
- 自动计算多元函数的梯度,无需手动推导偏导数公式。
- 对任意维度和复杂度的函数,均能通过
GradientTape
快速计算梯度。
(2)应用场景:
- 梯度计算在机器学习中至关重要,用于优化目标函数。
- 多元函数梯度计算也适用于科学计算、最优控制和物理建模等领域。
1.4.5 结论
本代码准确计算了多元函数在指定点的梯度,结果精确,代码结构清晰,体现了 TensorFlow 自动微分的高效性和灵活性。代码适用于复杂多维问题的梯度计算,是学习和实践自动微分的优秀示例。
1.5 线性回归模型训练报告
1.5.1 目标
通过 TensorFlow 框架实现一个简单的线性回归模型,拟合目标函数 y=10x+5。最终验证模型对新输入数据的预测能力。
1.5.2 代码分析
(1)损失函数定义:
def loss(y_true, y_pred):
return tf.keras.losses.MeanSquaredError()(y_true, y_pred)
使用均方误差(MSE)作为损失函数,衡量预测值 ypred 和真实值 ytrue 的差距。
(2)训练数据生成:
x_train_inch = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11], dtype=np.float32)
y_train_price = np.array([10 * num + 5 for num in x_train_inch], dtype=np.float32)
模拟生成线性关系的数据:输入 x 为从 1 到 11 的整数,目标输出 y 通过公式 y=10x+5 计算。
(3)模型参数初始化:
w1 = tf.Variable(random.random(), trainable=True, dtype=tf.float32)
w0 = tf.Variable(random.random(), trainable=True, dtype=tf.float32)
初始化两个可训练参数 w1 和 w0 ,分别对应线性回归模型的斜率和截距。
(4)梯度下降更新函数:
def step_gradient(real_x, real_y, learning_rate):
with tf.GradientTape() as tape:
pred_y = w1 * real_x + w0
reg_loss = loss(real_y, pred_y)
w1_gradients, w0_gradients = tape.gradient(reg_loss, (w1, w0))
w1.assign_sub(w1_gradients * learning_rate)
w0.assign_sub(w0_gradients * learning_rate)
- 使用
GradientTape
计算损失函数对 w1 和 w0 的梯度。 - 更新规则:参数值减去学习率乘以梯度。
(5)训练循环:
learning_rate = 0.01
num_iterations = 1000
for _ in range(num_iterations):
step_gradient(tf.convert_to_tensor(x_train_inch), tf.convert_to_tensor(y_train_price), learning_rate)
通过 1000 次迭代,不断更新模型参数,最终使其拟合数据分布。
(6)模型评估:
wheat = 0.9
price = w1 * wheat + w0
print("price = {:.2f}".format(price.numpy()))
使用训练好的模型预测 x=0.9 对应的 y 值,并输出预测结果。
1.5.3 结果分析
拟合的模型: 程序输出:
拟合得到的模型近似为: y ≈ 10.005026817321777x + 4.961641311645508
说明模型基本收敛,参数 w1 和 w0 的值非常接近目标函数的真实值 w1=10、w0=5。
预测结果: 对于输入 x=0.9,程序输出:
price = 13.97
预测结果接近真实值 y=10×0.9+5=14,误差很小,说明模型拟合效果良好。
1.5.4 优势与意义
(1)代码优势:
- 使用 TensorFlow 的自动微分和变量更新功能,简化了梯度计算过程。
- 代码清晰明了,易于理解和扩展。
(2)应用场景:
- 线性回归模型是数据建模的基础,可扩展至多元线性回归、逻辑回归等。
- 适用于简单预测任务或作为复杂模型的初步验证工具。
1.5.5 结论
本代码成功实现了线性回归模型的训练,最终模型参数与真实目标函数参数非常接近,预测结果准确,证明了模型的拟合能力和代码的有效性。
2.基于BP神经网络的鸢尾花分类任务
2.1神经网络
2.1.1 BP神经
BP神经网络(Back Propagation Neural Network,反向传播神经网络)是一种前馈神经网络,通过误差反向传播算法来训练模型权重和偏置。它是人工神经网络中最常见的模型之一,特别适用于非线性函数的拟合和分类问题。
(1)BP神经网络的基本组成
- 输入层:负责接收输入数据,每个节点对应一个特征。
- 隐藏层:通过权重和激活函数进行非线性变换,可以有一层或多层。
- 输出层:生成预测结果,节点数由任务的输出维度决定(如分类问题中类别数,回归问题中输出值数)。
(2)BP神经网络的特点
- 基于误差反向传播算法,即将输出误差反向传播,调整网络参数(权重和偏置)。
- 可以处理多维输入和非线性问题。
- 通过梯度下降法或其变种来优化目标函数。
2.1.2 BP神经网络的工作流程
BP神经网络主要包括两个阶段:前向传播(Forward Propagation) 和 反向传播(Backward Propagation)。
(1)前向传播
- 输入数据通过输入层传递到隐藏层,再通过激活函数变换,最终传递到输出层。
- 计算输出值 ypred。
- 如果输出值与实际值(目标值)不符,计算误差(损失函数)。
计算公式:
- 假设权重矩阵为 W,偏置为 b,激活函数为 f(⋅),则:
- 其中 l表示第 l层,a(l−1)是上一层的输出。
(2)误差计算
- 定义损失函数 L,例如平方误差:
(3)反向传播
通过链式法则计算每个参数对损失函数的梯度,调整参数以减少误差。
步骤:
1.输出层误差:
其中 z(L)是输出层的输入,f′(z)是激活函数的导数。
2.隐藏层误差:
3.梯度更新: 使用梯度下降法调整权重和偏置:
其中 η是学习率。
(4)参数更新
- 通过多次迭代(Epoch)优化损失函数,直到达到期望的精度或停止条件。
2.1.3 总结
(1)BP神经网络的核心思想是:
- 前向传播:计算预测值。
- 误差计算:定义损失函数。
- 反向传播:计算梯度并更新参数。
- 迭代训练:通过多轮训练优化模型。
(2)优点:
- 能有效处理复杂的非线性问题。
- 在适当设置网络结构和参数时,具有很强的拟合能力。
(3)缺点:
- 容易陷入局部最优。
- 梯度消失问题影响深层网络训练。
为了改进其性能,可以结合改进优化算法(如Adam、RMSProp)或使用更深层的网络架构(如卷积神经网络、深度学习网络)。
2.1.4 任务目标
使用BP(反向传播)神经网络实现对鸢尾花数据集的分类,主要包括以下步骤:
- 数据加载与预处理。
- 自定义BP神经网络的实现,包括前向传播、反向传播和梯度更新。
- 训练模型并在测试集上评估分类性能。
2.2 实验过程
2.2.1 数据加载与预处理
(1)代码
# 1.加载和预处理数据
import numpy as np
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import OneHotEncoder, StandardScaler
# 加载鸢尾花数据集
iris = load_iris()
X, y = iris.data, iris.target
# 数据标准化和独热编码
# 标准化:将每个特征的值调整到均值为0,标准差为1
scaler = StandardScaler()
X = scaler.fit_transform(X)
# 独热编码:将类别标签转化为独热向量 (如 0 -> [1, 0, 0])
encoder = OneHotEncoder()
y = encoder.fit_transform(y.reshape(-1, 1)).toarray()
# 划分训练集和测试集
# 将80%的数据用于训练,20%用于测试
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
(2)分析
- 标准化处理:使用
StandardScaler
将特征数据的均值调整为0,标准差调整为1,提升训练的稳定性。 - 独热编码:将分类标签(0, 1, 2)转为独热向量形式,便于多分类任务的神经网络训练。
- 数据划分:将数据集按8:2比例划分为训练集和测试集。
2.2.2 激活函数及其导数
(1)代码
# 2.定义激活函数和导数
# Sigmoid 激活函数
def sigmoid(x):
"""
将输入值压缩到 (0, 1) 范围,用于激活神经元。
"""
return 1 / (1 + np.exp(-x))
# Sigmoid 激活函数的导数
def sigmoid_derivative(x):
"""
用于计算反向传播中的梯度。
对 Sigmoid 函数求导的结果是 f'(x) = f(x) * (1 - f(x))。
"""
return x * (1 - x)
(2)解析
- Sigmoid激活函数:将输入值映射到(0, 1)范围,用于神经元的激活操作。 f(x)=11+e−x
- Sigmoid函数的导数:用于反向传播中梯度计算: f′(x)=f(x)⋅(1−f(x))
2.2.3 BP神经网络实现
(1)代码
# 3.定义 BP 神经网络类
class BPNeuralNetwork:
def __init__(self, input_size, hidden_size, output_size, learning_rate=0.01):
"""
初始化神经网络参数,包括权重、偏置和学习率。
参数:
- input_size: 输入层节点数
- hidden_size: 隐藏层节点数
- output_size: 输出层节点数
- learning_rate: 学习率,控制梯度更新步长
"""
# 输入层到隐藏层的权重矩阵,初始化为随机值
self.weights_input_hidden = np.random.uniform(-1, 1, (input_size, hidden_size))
# 隐藏层的偏置
self.bias_hidden = np.zeros((1, hidden_size))
# 隐藏层到输出层的权重矩阵,初始化为随机值
self.weights_hidden_output = np.random.uniform(-1, 1, (hidden_size, output_size))
# 输出层的偏置
self.bias_output = np.zeros((1, output_size))
# 学习率
self.learning_rate = learning_rate
def forward(self, X):
"""
执行前向传播,计算隐藏层和输出层的激活值。
参数:
- X: 输入数据
返回:
- final_output: 网络的最终输出
"""
# 计算隐藏层的加权输入 (Z = X * W + b)
self.hidden_input = np.dot(X, self.weights_input_hidden) + self.bias_hidden
# 隐藏层的激活输出 (A = Sigmoid(Z))
self.hidden_output = sigmoid(self.hidden_input)
# 计算输出层的加权输入 (Z = H * W + b)
self.final_input = np.dot(self.hidden_output, self.weights_hidden_output) + self.bias_output
# 输出层的激活输出 (A = Sigmoid(Z))
self.final_output = sigmoid(self.final_input)
return self.final_output
def backward(self, X, y, output):
"""
执行反向传播,计算误差并更新权重和偏置。
参数:
- X: 输入数据
- y: 实际标签
- output: 模型输出
"""
# 输出层误差 (Error = y - output)
output_error = y - output
# 输出层梯度 (Delta = Error * f'(output))
output_delta = output_error * sigmoid_derivative(output)
# 隐藏层误差 (传播到隐藏层的误差)
hidden_error = np.dot(output_delta, self.weights_hidden_output.T)
# 隐藏层梯度 (Delta = Error * f'(hidden_output))
hidden_delta = hidden_error * sigmoid_derivative(self.hidden_output)
# 更新隐藏层到输出层的权重和偏置
self.weights_hidden_output += self.learning_rate * np.dot(self.hidden_output.T, output_delta)
self.bias_output += self.learning_rate * np.sum(output_delta, axis=0, keepdims=True)
# 更新输入层到隐藏层的权重和偏置
self.weights_input_hidden += self.learning_rate * np.dot(X.T, hidden_delta)
self.bias_hidden += self.learning_rate * np.sum(hidden_delta, axis=0, keepdims=True)
def train(self, X, y, epochs):
"""
训练神经网络。
参数:
- X: 训练数据
- y: 训练标签
- epochs: 训练的迭代次数
"""
for epoch in range(epochs):
# 前向传播
output = self.forward(X)
# 反向传播
self.backward(X, y, output)
# 每隔100个 epoch 打印一次损失值
if epoch % 100 == 0:
loss = np.mean(np.square(y - output)) # 均方误差
print(f"Epoch {epoch}, Loss: {loss}")
def predict(self, X):
"""
使用训练好的网络进行预测。
参数:
- X: 测试数据
返回:
- 预测类别(最大概率对应的索引)
"""
output = self.forward(X)
return np.argmax(output, axis=1) # 返回概率最大的类别索引
(2)详细解析
1. 初始化网络参数
- 输入层到隐藏层、隐藏层到输出层的权重和偏置分别初始化。
- 使用随机值初始化权重,偏置初始化为0,学习率控制参数更新步长。
2. 前向传播
- 隐藏层计算:
- 输出层计算:
3. 反向传播
- 输出层误差:
- 隐藏层误差:
4. 权重更新
2.2.4 模型训练与测试
(1)代码
# 4.训练和评估模型
# 4.1 初始化神经网络
input_size = X_train.shape[1] # 输入层节点数:特征数量
hidden_size = 2 # 隐藏层节点数:可以调节
output_size = y_train.shape[1] # 输出层节点数:类别数量
learning_rate = 0.1 # 学习率
# 创建网络实例
bp_nn = BPNeuralNetwork(input_size, hidden_size, output_size, learning_rate)
# 训练神经网络
bp_nn.train(X_train, y_train, epochs=1000)
# 使用测试集进行预测
predictions = bp_nn.predict(X_test)
# 计算准确率
accuracy = np.mean(predictions == np.argmax(y_test, axis=1))
print(f"Test Accuracy: {accuracy * 100:.2f}%")
(2)实验结果
1.训练过程:
Epoch 0, Loss: 0.22128556516365086 Epoch 100, Loss: 0.021410587809142765 Epoch 200, Loss: 0.013800814452345782 Epoch 300, Loss: 0.012100929959213873 Epoch 400, Loss: 0.011392964488187917 Epoch 500, Loss: 0.011017511806778143 Epoch 600, Loss: 0.010790199253609335 Epoch 700, Loss: 0.010640489751476679 Epoch 800, Loss: 0.010535921139959336 Epoch 900, Loss: 0.01045957534860003
测试集准确率:
Test Accuracy: 100.00%
2.3 总结与改进建议
(1)模型表现:
- BP神经网络成功实现对鸢尾花数据的分类,测试集准确率达到100%。
(2)改进建议:
- 非线性激活函数:可尝试ReLU等激活函数,加速训练。
- 优化算法:引入Adam等优化算法提升收敛速度。
- 正则化:通过Dropout或L2正则防止过拟合。
原文地址:https://blog.csdn.net/FHY26828/article/details/143653445
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!