神经网络模型基础与简单实现
一、什么是模型(Model)
1.1 模型的本质
模型是现实世界中复杂关系的简化数学表示。在机器学习中,模型是一个从输入到输出的映射函数:
f: X → Y
输入特征 → 预测输出
1.2 模型的组成要素
# 机器学习模型的三个核心组件:
1. 结构(Architecture):如何组织计算(如线性模型、神经网络)
2. 参数(Parameters):需要学习的变量(如权重w)
3. 超参数(Hyperparameters):训练前设定的参数(如学习率)
1.3 模型的作用
- 描述关系:揭示变量之间的数学关系
- 预测未知:基于历史数据预测未来
- 决策支持:为决策提供量化依据
二、最简单的神经网络:y = w*x
2.1 单神经元神经网络
这是最简单的神经网络形式,只有一个神经元、一个权重参数:
import numpy as np
import matplotlib.pyplot as plt
plt.rcParams['font.family'] = 'SimHei'
# 1. 生成模拟数据
np.random.seed(42)
x = np.random.rand(100) * 10 # 输入特征,范围0-10
y = 2.5 * x + np.random.randn(100) * 2 # 真实关系:y = 2.5*x + 噪声
# 2. 定义模型
class SingleNeuronNN:
def __init__(self):
self.w = np.random.randn() # 随机初始化权重
def forward(self, x):
"""前向传播:计算预测值"""
return self.w * x
def loss(self, y_pred, y_true):
"""损失函数:均方误差"""
return np.mean((y_pred - y_true) ** 2)
def gradient(self, x, y_pred, y_true):
"""计算梯度:∂Loss/∂w = 2*(y_pred-y_true)*x"""
return 2 * np.mean((y_pred - y_true) * x)
def update(self, grad, lr=0.01):
"""更新权重:w = w - lr * gradient"""
self.w -= lr * grad
2.2 训练过程
# 3. 初始化模型和训练参数
model = SingleNeuronNN()
epochs = 100
learning_rate = 0.01
loss_history = []
# 4. 训练循环
for epoch in range(epochs):
# 前向传播
y_pred = model.forward(x)
# 计算损失
loss = model.loss(y_pred, y)
loss_history.append(loss)
# 计算梯度
grad = model.gradient(x, y_pred, y)
# 更新权重
model.update(grad, learning_rate)
# 每10轮打印一次
if epoch % 10 == 0:
print(f"Epoch {epoch}: w={model.w:.4f}, Loss={loss:.4f}")
print(f"最终权重: {model.w:.4f} (真实值: 2.5)")
# 5. 可视化结果
fig, axes = plt.subplots(1, 2, figsize=(12, 5))
# 预测结果
axes[0].scatter(x, y, label='真实数据', alpha=0.6)
axes[0].plot(x, model.forward(x), 'r-', label=f'预测: y={model.w:.2f}*x')
axes[0].set_xlabel('x')
axes[0].set_ylabel('y')
axes[0].set_title('模型预测结果')
axes[0].legend()
axes[0].grid(True, alpha=0.3)
# 损失曲线
axes[1].plot(loss_history)
axes[1].set_xlabel('Epoch')
axes[1].set_ylabel('Loss')
axes[1].set_title('训练损失变化')
axes[1].grid(True, alpha=0.3)
plt.tight_layout()
plt.show()
三、归一化(Normalization)
3.1 为什么要归一化
# 问题:数据尺度不一致导致的问题
x_large = np.random.rand(100) * 1000 # 范围: 0-1000
x_small = np.random.rand(100) # 范围: 0-1
# 如果直接使用这些特征:
# 1. 梯度爆炸/消失:梯度 = error * x,x大的特征梯度会非常大
# 2. 收敛缓慢:不同特征需要不同的学习率
# 3. 数值不稳定:可能导致浮点数溢出
3.2 常见的归一化方法
class Normalization:
"""归一化方法"""
@staticmethod
def min_max_normalize(data):
"""最小-最大归一化:缩放到[0,1]范围"""
min_val = np.min(data)
max_val = np.max(data)
return (data - min_val) / (max_val - min_val + 1e-8), min_val, max_val
@staticmethod
def z_score_normalize(data):
"""Z-score标准化:均值为0,标准差为1"""
mean = np.mean(data)
std = np.std(data)
return (data - mean) / (std + 1e-8), mean, std
@staticmethod
def reverse_min_max(norm_data, min_val, max_val):
"""反归一化:恢复原始数据"""
return norm_data * (max_val - min_val) + min_val
@staticmethod
def reverse_z_score(norm_data, mean, std):
"""反标准化:恢复原始数据"""
return norm_data * std + mean
3.3 归一化后的完整训练流程
# 1. 数据准备(含异常值)
np.random.seed(42)
x_original = np.random.rand(100) * 100 # 0-100的范围
# 添加一些异常值
x_original[10] = 500
x_original[20] = -100
y_original = 2.5 * x_original + np.random.randn(100) * 20
# 2. 归一化处理
norm = Normalization()
x_norm, x_mean, x_std = norm.z_score_normalize(x_original)
y_norm, y_mean, y_std = norm.z_score_normalize(y_original)
print(f"原始数据 - x范围: [{x_original.min():.2f}, {x_original.max():.2f}]")
print(f"归一化后 - x范围: [{x_norm.min():.2f}, {x_norm.max():.2f}]")
print(f"归一化后 - x均值: {x_norm.mean():.2f}, 标准差: {x_norm.std():.2f}")
# 3. 创建归一化感知的神经网络
class NormalizedNeuronNN:
def __init__(self):
self.w = np.random.randn() # 归一化数据上的权重
self.x_mean = 0
self.x_std = 1
self.y_mean = 0
self.y_std = 1
def set_normalization_params(self, x_mean, x_std, y_mean, y_std):
"""设置归一化参数"""
self.x_mean = x_mean
self.x_std = x_std
self.y_mean = y_mean
self.y_std = y_std
def forward_norm(self, x_norm):
"""在归一化空间前向传播"""
return self.w * x_norm
def forward_original(self, x_original):
"""在原始空间前向传播"""
# 先归一化输入
x_norm = (x_original - self.x_mean) / self.x_std
# 在归一化空间预测
y_pred_norm = self.forward_norm(x_norm)
# 反归一化到原始空间
return y_pred_norm * self.y_std + self.y_mean
def train(self, x_norm, y_norm, epochs=100, lr=0.1):
"""训练模型"""
loss_history = []
for epoch in range(epochs):
# 前向传播
y_pred = self.forward_norm(x_norm)
# 计算损失
loss = np.mean((y_pred - y_norm) ** 2)
loss_history.append(loss)
# 计算梯度
grad = 2 * np.mean((y_pred - y_norm) * x_norm)
# 更新权重
self.w -= lr * grad
if epoch % 20 == 0:
print(f"Epoch {epoch}: w={self.w:.4f}, Loss={loss:.4f}")
return loss_history
# 4. 训练归一化模型
model_norm = NormalizedNeuronNN()
model_norm.set_normalization_params(x_mean, x_std, y_mean, y_std)
loss_history_norm = model_norm.train(x_norm, y_norm, epochs=200, lr=0.1)
# 5. 结果对比
fig, axes = plt.subplots(2, 2, figsize=(14, 10))
# 原始数据与模型预测
y_pred_original = model_norm.forward_original(x_original)
axes[0, 0].scatter(x_original, y_original, alpha=0.6, label='原始数据')
axes[0, 0].plot(x_original, y_pred_original, 'r-', linewidth=2,
label='模型预测')
axes[0, 0].set_xlabel('x (原始)')
axes[0, 0].set_ylabel('y (原始)')
axes[0, 0].set_title('原始空间:模型预测')
axes[0, 0].legend()
axes[0, 0].grid(True, alpha=0.3)
# 归一化数据与模型预测
y_pred_norm = model_norm.forward_norm(x_norm)
axes[0, 1].scatter(x_norm, y_norm, alpha=0.6, label='归一化数据')
axes[0, 1].plot(x_norm, y_pred_norm, 'r-', linewidth=2,
label='模型预测')
axes[0, 1].set_xlabel('x (归一化)')
axes[0, 1].set_ylabel('y (归一化)')
axes[0, 1].set_title('归一化空间:模型预测')
axes[0, 1].legend()
axes[0, 1].grid(True, alpha=0.3)
# 损失曲线
axes[1, 0].plot(loss_history_norm)
axes[1, 0].set_xlabel('Epoch')
axes[1, 0].set_ylabel('Loss')
axes[1, 0].set_title('归一化训练损失')
axes[1, 0].grid(True, alpha=0.3)
# 权重转换
# 在归一化空间:y_norm = w * x_norm
# 在原始空间: (y-y_mean)/y_std = w * (x-x_mean)/x_std
# 转换后:y = (w * y_std/x_std) * x + (y_mean - w * y_std * x_mean / x_std)
w_original = model_norm.w * y_std / x_std
b_original = y_mean - w_original * x_mean
axes[1, 1].text(0.1, 0.9, f'归一化空间模型: y_norm = {model_norm.w:.4f} * x_norm',
fontsize=12, transform=axes[1, 1].transAxes)
axes[1, 1].text(0.1, 0.7, f'原始空间模型: y = {w_original:.4f} * x + {b_original:.4f}',
fontsize=12, transform=axes[1, 1].transAxes)
axes[1, 1].text(0.1, 0.5, f'真实关系: y = 2.5 * x',
fontsize=12, transform=axes[1, 1].transAxes, color='red')
axes[1, 1].axis('off')
plt.tight_layout()
plt.show()
print(f"\n总结:")
print(f"1. 归一化权重: {model_norm.w:.4f}")
print(f"2. 原始权重: {w_original:.4f} (接近真实值2.5)")
print(f"3. 偏置: {b_original:.4f}")

总结:
1. 归一化权重: 0.9916
2. 原始权重: 2.5004 (接近真实值2.5)
3. 偏置: -0.0398
本文来自博客园,作者:ffff5,转载请注明原文链接:https://www.cnblogs.com/ffff5/p/19592775

浙公网安备 33010602011771号