神经网络模型基础与简单实现

一、什么是模型(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}")

Pasted image 20260208211607

总结:
1. 归一化权重: 0.9916
2. 原始权重: 2.5004 (接近真实值2.5)
3. 偏置: -0.0398
posted @ 2026-02-08 21:18  ffff5  阅读(6)  评论(0)    收藏  举报