7D-AI系列:神经网络的具体实现

文章目录

概述

神经网络其实并不像听起来那么复杂。这份学习笔记面向完全初学者,假设对机器学习没有任何先验知识。我们将通过理解神经网络的工作原理,并用Python从零开始实现一个简单的神经网络。

1. 基础构建块:神经元

神经元的工作原理

神经元是神经网络的基本单元。一个神经元的工作过程包括:

  1. 接收输入:神经元接收多个输入值
  2. 加权处理:每个输入乘以对应的权重
  3. 求和加偏置:将所有加权输入相加,再加上偏置项
  4. 激活函数:将结果通过激活函数处理得到最终输出

输入神经元结构图

复制代码
输入层        权重        求和+偏置      激活函数      输出
 x₁  ────────→ w₁ ──┐
                    ├──→ Σ + b ────→ f() ────→ y
 x₂  ────────→ w₂ ──┘

该结构包含核心要素:

  • 两个输入 x 1 x_1 x1 和 x 2 x_2 x2
  • 对应的权重 w 1 w_1 w1 和 w 2 w_2 w2
  • 求和节点将加权输入相加并加上偏置 b b b
  • 激活函数 f ( ) f() f() 处理结果产生输出 y y y

数学表示

对于一个2输入神经元:

  • 输入: x 1 , x 2 x_1, x_2 x1,x2
  • 权重: w 1 , w 2 w_1, w_2 w1,w2
  • 偏置: b b b
  • 输出: f ( ( x 1 × w 1 ) + ( x 2 × w 2 ) + b ) f((x_1 × w_1) + (x_2 × w_2) + b) f((x1×w1)+(x2×w2)+b)

其中 f f f是激活函数,常用的是sigmoid函数:
s i g m o i d ( x ) = 1 / ( 1 + e − x ) sigmoid(x) = 1 / (1 + e^{-x}) sigmoid(x)=1/(1+e−x)

Sigmoid激活函数图像

复制代码
 1.0 ┤               ╭─────
     │              ╭─╯
 0.8 ┤            ╭─╯
     │           ╭─╯
 0.6 ┤         ╭─╯
     │        ╭─╯
 0.4 ┤      ╭─╯
     │     ╭─╯
 0.2 ┤  ╭─╯
     │╭╯
 0.0 ┼─────────────────────
    -6  -4  -2   0   2   4   6

Sigmoid函数将任何实数输入压缩到 ( 0 , 1 ) (0,1) (0,1)区间内,形成S型曲线。

Python实现示例

python 复制代码
import numpy as np

def sigmoid(x):
    """Sigmoid激活函数"""
    return 1 / (1 + np.exp(-x))

class Neuron:
    def __init__(self, weights, bias):
        self.weights = weights
        self.bias = bias
    
    def feedforward(self, inputs):
        """前向传播计算"""
        total = np.dot(self.weights, inputs) + self.bias
        return sigmoid(total)

# 示例使用
weights = np.array([0, 1])
bias = 4
neuron = Neuron(weights, bias)
x = np.array([2, 3])
output = neuron.feedforward(x)
print(f"神经元输出: {output}")

2. 构建神经网络

网络结构

一个简单的神经网络包含:

  • 输入层:接收原始数据
  • 隐藏层:进行特征处理(可以有多层)
  • 输出层:产生最终结果

简单神经网络结构图

复制代码
输入层     隐藏层      输出层
 x₁ ──┐   ┌─ h₁ ──┐
      ├───┤       ├─── o₁
 x₂ ──┘   └─ h₂ ──┘

详细连接图

复制代码
     输入层        隐藏层         输出层
       x₁ ────w₁───→ h₁ ────w₅───┐
        │    w₃───→ h₂ ────w₆───┼──→ o₁
       x₂ ────w₂─────┘           │
        └────w₄─────────────────┘

该网络的参数构成:

  • 2个输入节点 ( x 1 , x 2 x_1, x_2 x1,x2)
  • 2个隐藏层节点 ( h 1 , h 2 h_1, h_2 h1,h2)
  • 1个输出节点 ( o 1 o_1 o1)
  • 6个权重参数 ( w 1 w_1 w1- w 6 w_6 w6)
  • 3个偏置参数 (每层一个)

前向传播过程

数据从输入层开始,逐层向前传递:

  1. 输入层接收数据
  2. 隐藏层处理特征
  3. 输出层产生预测结果
前向传播数据流图
复制代码
步骤1: 输入数据x₁ = 2, x₂ = 3
步骤2: 隐藏层计算
h₁ = sigmoid(x₁×w₁ + x₂×w₃ + b₁)
h₂ = sigmoid(x₁×w₂ + x₂×w₄ + b₂)
步骤3: 输出层计算  
o₁ = sigmoid(h₁×w₅ + h₂×w₆ + b₃)
数据流向:输入 → 加权求和 → 激活函数 → 下一层

网络实现示例

python 复制代码
class SimpleNeuralNetwork:
    def __init__(self):
        # 随机初始化权重和偏置
        self.w1 = np.random.normal()
        self.w2 = np.random.normal()
        self.w3 = np.random.normal()
        self.w4 = np.random.normal()
        self.w5 = np.random.normal()
        self.w6 = np.random.normal()
        
        self.b1 = np.random.normal()
        self.b2 = np.random.normal()
        self.b3 = np.random.normal()
    
    def feedforward(self, x):
        # 隐藏层计算
        h1 = sigmoid(self.w1 * x[0] + self.w2 * x[1] + self.b1)
        h2 = sigmoid(self.w3 * x[0] + self.w4 * x[1] + self.b2)
        
        # 输出层计算
        output = sigmoid(self.w5 * h1 + self.w6 * h2 + self.b3)
        return output

3. 训练神经网络

损失函数

训练的目标是最小化预测误差。常用**均方误差(MSE)**作为损失函数:
M S E = ( 1 / n ) × Σ ( y t r u e − y p r e d ) 2 MSE = (1/n) × \Sigma(y_{true} - y_{pred})^2 MSE=(1/n)×Σ(ytrue−ypred)2

其中:

  • n n n:样本数量
  • y t r u e y_{true} ytrue:真实值
  • y p r e d y_{pred} ypred:预测值

损失函数实现

python 复制代码
def mse_loss(y_true, y_pred):
    """计算均方误差"""
    return ((y_true - y_pred) ** 2).mean()

# 示例
y_true = np.array([1, 0, 0, 1])
y_pred = np.array([0.8, 0.2, 0.1, 0.9])
loss = mse_loss(y_true, y_pred)
print(f"损失值: {loss}")

训练数据示例

假设我们要根据身高体重预测性别,标准化后的数据集如下:

姓名 体重(标准化) 身高(标准化) 性别
Alice -2 -1 1 (女)
Bob 25 6 0 (男)
Charlie 17 4 0 (男)
Diana -15 -6 1 (女)

性别预测网络结构

复制代码
     体重(标准化)     隐藏层        性别预测
       weight ──┐   ┌─ h₁ ──┐
                ├───┤       ├─── gender
       height ──┘   └─ h₂ ──┘
     身高(标准化)                (0=男, 1=女)

网络学习从身高体重特征到性别标签的映射关系。

4. 反向传播算法

基本思想

反向传播用于计算损失函数相对于网络参数的梯度,从而指导参数更新的方向。

梯度计算

使用链式法则 计算偏导数:
∂ L / ∂ w = ∂ L / ∂ y p r e d × ∂ y p r e d / ∂ w ∂L/∂w = ∂L/∂y_{pred} × ∂y_{pred}/∂w ∂L/∂w=∂L/∂ypred×∂ypred/∂w

反向传播流程图

复制代码
前向传播:输入 → 隐藏层 → 输出 → 损失
 x      h       y      L
反向传播:∂L/∂x ← ∂L/∂h ← ∂L/∂y ← ∂L/∂L
梯度    梯度     梯度     损失
梯度计算顺序:
1. 计算输出层梯度: ∂L/∂w₅, ∂L/∂w₆, ∂L/∂b₃
2. 计算隐藏层梯度: ∂L/∂w₁, ∂L/∂w₂, ∂L/∂w₃, ∂L/∂w₄, ∂L/∂b₁, ∂L/∂b₂
3. 更新所有参数

参数更新

使用梯度下降 更新参数:
w n e w = w o l d − l e a r n i n g _ r a t e × ∂ L / ∂ w w_{new} = w_{old} - learning\_rate × ∂L/∂w wnew=wold−learning_rate×∂L/∂w

带权重标注的网络图

复制代码
输入层        隐藏层         输出层
 x₁ ──w₁──→ h₁ ──w₅──┐
  │   w₃──→ h₂ ──w₆──┼──→ o₁
 x₂ ──w₂────┘        │
  └──w₄──────────────┘
偏置: b₁(h₁), b₂(h₂), b₃(o₁)

该图明确了所有需要训练的参数:

  • 权重: w 1 , w 2 , w 3 , w 4 , w 5 , w 6 w_1, w_2, w_3, w_4, w_5, w_6 w1,w2,w3,w4,w5,w6
  • 偏置: b 1 , b 2 , b 3 b_1, b_2, b_3 b1,b2,b3

5. 完整训练示例

python 复制代码
class TrainableNetwork:
    def __init__(self):
        # 初始化参数
        self.w1 = np.random.normal()
        self.w2 = np.random.normal()
        # ... 其他权重和偏置
    
    def train(self, data, all_y_trues):
        """训练网络"""
        learn_rate = 0.1
        epochs = 1000
        
        for epoch in range(epochs):
            for x, y_true in zip(data, all_y_trues):
                # 前向传播
                y_pred = self.feedforward(x)
                
                # 计算损失
                loss = mse_loss(y_true, y_pred)
                
                # 反向传播(计算梯度)
                # ... 梯度计算代码
                
                # 更新参数
                # ... 参数更新代码
            
            # 每100轮输出一次损失
            if epoch % 100 == 0:
                print(f"Epoch {epoch}, Loss: {loss}")

6. 关键概念总结

重要术语

  • 前向传播:数据从输入到输出的计算过程
  • 反向传播:计算梯度并更新参数的过程
  • 激活函数:引入非线性的函数
  • 损失函数:衡量预测误差的函数
  • 梯度下降:优化算法,用于最小化损失

训练流程

  1. 初始化网络参数
  2. 前向传播计算预测
  3. 计算损失
  4. 反向传播计算梯度
  5. 更新参数
  6. 重复步骤2-5直到收敛

7. 实际应用建议

使用现有框架

在实际项目中,建议使用成熟的深度学习框架,提升开发效率:

  • TensorFlow:Google开发的开源框架
  • PyTorch:Facebook开发的动态图框架
  • Keras:高级API,易于使用

进一步学习

  • 了解不同类型的神经网络(CNN、RNN等)
  • 学习正则化技术防止过拟合
  • 掌握数据预处理和特征工程
  • 实践更复杂的实际项目

注:本文档基于学习目的整理,实际应用中请使用专业的深度学习框架。

8. 梯度下降详解

偏导数的意义

当我们计算 ∂ L / ∂ w 1 ∂L/∂w_1 ∂L/∂w1 时,核心是探究:如果改变 w 1 w_1 w1,损失 L L L 会如何变化?

  • 如果 ∂ L / ∂ w 1 ∂L/∂w_1 ∂L/∂w1 是正数,减小 w 1 w_1 w1 会使 L L L 减小
  • 如果 ∂ L / ∂ w 1 ∂L/∂w_1 ∂L/∂w1 是负数,增大 w 1 w_1 w1 会使 L L L 减小

随机梯度下降(SGD)训练流程

  1. 选择样本:从数据集中选择一个样本(这就是"随机"的含义)
  2. 计算梯度:计算损失相对于所有权重和偏置的偏导数
  3. 更新参数:使用更新方程调整每个权重和偏置
  4. 重复:返回步骤1继续训练

参数更新公式

w n e w = w o l d − l e a r n i n g _ r a t e × ∂ L / ∂ w w_{new} = w_{old} - learning\_rate × ∂L/∂w wnew=wold−learning_rate×∂L/∂w

其中 l e a r n i n g _ r a t e learning\_rate learning_rate(学习率)控制每次更新的步长,是训练的关键超参数。

9. 完整神经网络实现

完整训练代码

python 复制代码
import numpy as np

def sigmoid(x):
    """Sigmoid激活函数"""
    return 1 / (1 + np.exp(-x))

def deriv_sigmoid(x):
    """Sigmoid导数"""
    fx = sigmoid(x)
    return fx * (1 - fx)

def mse_loss(y_true, y_pred):
    """均方误差损失"""
    return ((y_true - y_pred) ** 2).mean()

class NeuralNetwork:
    def __init__(self):
        # 随机初始化权重
        self.w1 = np.random.normal()
        self.w2 = np.random.normal()
        self.w3 = np.random.normal()
        self.w4 = np.random.normal()
        self.w5 = np.random.normal()
        self.w6 = np.random.normal()
        
        # 随机初始化偏置
        self.b1 = np.random.normal()
        self.b2 = np.random.normal()
        self.b3 = np.random.normal()
    
    def feedforward(self, x):
        """前向传播"""
        h1 = sigmoid(self.w1 * x[0] + self.w2 * x[1] + self.b1)
        h2 = sigmoid(self.w3 * x[0] + self.w4 * x[1] + self.b2)
        o1 = sigmoid(self.w5 * h1 + self.w6 * h2 + self.b3)
        return o1
    
    def train(self, data, all_y_trues):
        """
        训练神经网络
        - data: (n x 2) numpy数组,n为样本数
        - all_y_trues: 包含n个元素的numpy数组
        """
        learn_rate = 0.1
        epochs = 1000 # 训练轮数
        
        for epoch in range(epochs):
            for x, y_true in zip(data, all_y_trues):
                # === 前向传播 ===
                sum_h1 = self.w1 * x[0] + self.w2 * x[1] + self.b1
                h1 = sigmoid(sum_h1)
                
                sum_h2 = self.w3 * x[0] + self.w4 * x[1] + self.b2
                h2 = sigmoid(sum_h2)
                
                sum_o1 = self.w5 * h1 + self.w6 * h2 + self.b3
                o1 = sigmoid(sum_o1)
                y_pred = o1
                
                # === 计算偏导数 ===
                d_L_d_ypred = -2 * (y_true - y_pred)
                
                # 输出层神经元 o1
                d_ypred_d_w5 = h1 * deriv_sigmoid(sum_o1)
                d_ypred_d_w6 = h2 * deriv_sigmoid(sum_o1)
                d_ypred_d_b3 = deriv_sigmoid(sum_o1)
                
                d_ypred_d_h1 = self.w5 * deriv_sigmoid(sum_o1)
                d_ypred_d_h2 = self.w6 * deriv_sigmoid(sum_o1)
                
                # 隐藏层神经元 h1
                d_h1_d_w1 = x[0] * deriv_sigmoid(sum_h1)
                d_h1_d_w2 = x[1] * deriv_sigmoid(sum_h1)
                d_h1_d_b1 = deriv_sigmoid(sum_h1)
                
                # 隐藏层神经元 h2
                d_h2_d_w3 = x[0] * deriv_sigmoid(sum_h2)
                d_h2_d_w4 = x[1] * deriv_sigmoid(sum_h2)
                d_h2_d_b2 = deriv_sigmoid(sum_h2)
                
                # === 更新权重和偏置 ===
                # 神经元 h1
                self.w1 -= learn_rate * d_L_d_ypred * d_ypred_d_h1 * d_h1_d_w1
                self.w2 -= learn_rate * d_L_d_ypred * d_ypred_d_h1 * d_h1_d_w2
                self.b1 -= learn_rate * d_L_d_ypred * d_ypred_d_h1 * d_h1_d_b1
                
                # 神经元 h2
                self.w3 -= learn_rate * d_L_d_ypred * d_ypred_d_h2 * d_h2_d_w3
                self.w4 -= learn_rate * d_L_d_ypred * d_ypred_d_h2 * d_h2_d_w4
                self.b2 -= learn_rate * d_L_d_ypred * d_ypred_d_h2 * d_h2_d_b2
                
                # 神经元 o1
                self.w5 -= learn_rate * d_L_d_ypred * d_ypred_d_w5
                self.w6 -= learn_rate * d_L_d_ypred * d_ypred_d_w6
                self.b3 -= learn_rate * d_L_d_ypred * d_ypred_d_b3
            
            # 每10轮输出一次损失
            if epoch % 10 == 0:
                y_preds = np.apply_along_axis(self.feedforward, 1, data)
                loss = mse_loss(all_y_trues, y_preds)
                print(f"Epoch {epoch} loss: {loss:.3f}")

# 准备数据集
data = np.array([
    [-2, -1],   # Alice
    [25, 6],    # Bob
    [17, 4],    # Charlie
    [-15, -6],  # Diana
])
all_y_trues = np.array([
    1,  # Alice (女)
    0,  # Bob (男)
    0,  # Charlie (男)
    1,  # Diana (女)
])

# 训练网络
network = NeuralNetwork()
network.train(data, all_y_trues)

训练结果

随着训练的进行,损失会稳步下降,网络逐步学习到数据的规律:

复制代码
Epoch 0 loss: 0.350
Epoch 10 loss: 0.221
Epoch 20 loss: 0.149
...
Epoch 990 loss: 0.003

训练损失下降曲线

复制代码
损失值
0.35 ┤●
     │ ●
0.30 ┤  ●
     │   ●
0.25 ┤    ●
     │     ●●
0.20 ┤       ●●
     │         ●●
0.15 ┤           ●●●
     │              ●●●
0.10 ┤                  ●●●●
     │                      ●●●●●
0.05 ┤                          ●●●●●●●●●
     │                               ●●●●●●●●●●●
0.00 ┼─────────────────────────────────────────────────→
     0   100  200  300  400  500  600  700  800  900  1000
                训练轮数 (Epochs)

图中显示损失函数随训练轮数逐渐减小,表明网络正在有效学习特征映射关系。

使用训练好的网络进行预测

python 复制代码
# 进行预测
emily = np.array([-7, -3])  # 128磅,63英寸
frank = np.array([20, 2])   # 155磅,68英寸
print(f"Emily: {network.feedforward(emily):.3f}")  # 0.951 - 女性
print(f"Frank: {network.feedforward(frank):.3f}")  # 0.039 - 男性

10. 总结与展望

我们学到了什么

通过本教程,完成了神经网络从基础到实现的核心学习:

  1. 神经元基础:理解了神经网络的基本构建块
  2. 激活函数:学习了sigmoid激活函数的作用
  3. 网络结构:了解了如何将神经元连接成网络
  4. 数据准备:创建了包含特征和标签的数据集
  5. 损失函数:学习了均方误差(MSE)损失
  6. 训练目标:理解了训练就是最小化损失
  7. 反向传播:使用反向传播计算偏导数
  8. 优化算法:使用随机梯度下降(SGD)训练网络

完整的神经网络学习流程图

复制代码
数据准备 → 网络初始化 → 前向传播 → 损失计算 → 反向传播 → 参数更新
  ↑                                       ↓
  └──────────────────── 重复训练过程 ←─────────────────────────┘

详细训练流程

  1. 准备训练数据
  2. 随机初始化权重和偏置
  3. 前向传播计算预测值
  4. 计算损失函数
  5. 反向传播计算梯度
  6. 使用梯度下降更新参数
  7. 重复步骤3-6直到收敛

下一步学习方向

深入学习
  • 探索更多激活函数(ReLU、Tanh、Softmax等)
  • 学习不同的优化器(Adam、RMSprop等)
  • 了解正则化技术(Dropout、L2正则化)
  • 研究批量归一化(Batch Normalization)
实践项目
  • 使用Keras构建第一个神经网络
  • 尝试TensorFlow或PyTorch框架
  • 在TensorFlow Playground中实验
  • 处理真实世界的数据集
高级主题
  • 卷积神经网络(CNN):用于图像处理和计算机视觉
  • 循环神经网络(RNN):用于序列数据和自然语言处理
  • 生成对抗网络(GAN):用于生成新数据
  • 迁移学习:利用预训练模型

实用建议

  1. 从简单开始:先掌握基础概念,再处理复杂问题
  2. 动手实践:理论结合实践,多写代码
  3. 使用框架:实际项目中使用成熟的深度学习框架
  4. 持续学习:机器学习领域发展迅速,保持学习热情
  5. 参与社区:加入开源项目,与他人交流学习

常见问题解答

Q: 为什么要使用激活函数?

A: 激活函数引入非线性,使神经网络能够学习复杂的模式。没有激活函数,多层网络等价于单层线性模型。

Q: 如何选择学习率?

A: 学习率太大可能导致训练不稳定,太小则训练缓慢。通常从0.001或0.01开始尝试,根据训练效果调整。

Q: 需要多少训练数据?

A: 这取决于问题的复杂度。一般来说,数据越多越好,但也要注意数据质量和多样性。

Q: 如何避免过拟合?

A: 使用正则化技术、增加训练数据、使用Dropout、早停法等方法可以帮助避免过拟合。

Q: 神经网络适合所有问题吗?

A: 不是。对于简单问题,传统机器学习方法可能更合适。神经网络在处理大规模、高维度、非线性问题时表现出色。

相关推荐
九.九10 小时前
ops-transformer:AI 处理器上的高性能 Transformer 算子库
人工智能·深度学习·transformer
春日见10 小时前
拉取与合并:如何让个人分支既包含你昨天的修改,也包含 develop 最新更新
大数据·人工智能·深度学习·elasticsearch·搜索引擎
恋猫de小郭10 小时前
AI 在提高你工作效率的同时,也一直在增加你的疲惫和焦虑
前端·人工智能·ai编程
deephub10 小时前
Agent Lightning:微软开源的框架无关 Agent 训练方案,LangChain/AutoGen 都能用
人工智能·microsoft·langchain·大语言模型·agent·强化学习
偷吃的耗子11 小时前
【CNN算法理解】:三、AlexNet 训练模块(附代码)
深度学习·算法·cnn
大模型RAG和Agent技术实践11 小时前
从零构建本地AI合同审查系统:架构设计与流式交互实战(完整源代码)
人工智能·交互·智能合同审核
老邋遢11 小时前
第三章-AI知识扫盲看这一篇就够了
人工智能
互联网江湖11 小时前
Seedance2.0炸场:长短视频们“修坝”十年,不如AI放水一天?
人工智能
PythonPioneer11 小时前
在AI技术迅猛发展的今天,传统职业该如何“踏浪前行”?
人工智能
冬奇Lab11 小时前
一天一个开源项目(第20篇):NanoBot - 轻量级AI Agent框架,极简高效的智能体构建工具
人工智能·开源·agent