02-深度学习入门-神经网络是如何思考的

0 阅读8分钟

深度学习入门:神经网络是如何"思考"的?

揭开神经网络的神秘面纱,用最直观的方式理解深度学习的核心原理。

前言

在上一篇文章中,我们了解了机器学习的基本概念。今天,我们将深入探索机器学习中最耀眼的技术——深度学习

你可能好奇:为什么叫"深度"学习?神经网络是怎么"思考"的?它和人脑有什么关系?这篇文章将为你一一解答。


一、从人脑到人工神经网络

人脑的启示

人脑大约有 860亿个神经元,每个神经元通过突触与其他神经元相连,形成复杂的网络。当我们学习新知识时,神经元之间的连接强度会发生变化。

        人脑神经元结构示意

    树突(接收信号)
        ↓
    ┌───────────┐
    │  细胞体   │ ← 处理信息
    └─────┬─────┘
          │
      轴突(传递信号)
          │
          ↓
      突触(连接其他神经元)

人工神经网络

人工神经网络是对人脑的简化模拟:

人脑神经元人工神经元
树突输入端
细胞体计算单元
轴突输出端
突触强度权重(Weight)

二、单个神经元的工作原理

一个神经元接收多个输入,进行加权求和,再经过激活函数输出结果。

数学表达

输入:x₁, x₂, x₃, ...
权重:w₁, w₂, w₃, ...
偏置:b

加权求和:z = w₁x₁ + w₂x₂ + w₃x₃ + ... + b
输出:y = 激活函数(z)

直观理解

想象你要决定周末是否去公园:

  • 输入1:天气好(1)或不好(0)
  • 输入2:朋友有空(1)或没空(0)
  • 输入3:心情好(1)或不好(0)

不同的因素对你决策的影响不同:

天气权重 w₁ = 0.5  (天气很重要)
朋友权重 w₂ = 0.3  (朋友因素次之)
心情权重 w₃ = 0.2  (心情影响较小)
偏置 b = -0.4      (你本身有点宅)

决策计算:
z = 0.5×1 + 0.3×1 + 0.2×1 + (-0.4) = 0.6

如果激活函数是:输出 = 1 if z > 0 else 0
那么输出 = 1,决定去公园!

三、激活函数:神经网络的灵魂

为什么需要激活函数?如果没有它,无论多少层神经网络,最终都等价于一个线性变换,无法处理复杂问题。

常见激活函数

1. Sigmoid 函数
import numpy as np

def sigmoid(x):
    return 1 / (1 + np.exp(-x))

特点:将任意输入压缩到 (0, 1) 之间

    1.0 ┤        ╭───────
        │      ╭
    0.5 ┤    ╭
        │  ╭
    0.0 ┤╭──────────────→ x
       -4  -2   0   2   4

缺点

  • 梯度消失问题(两端梯度接近0)
  • 输出不是以0为中心
2. ReLU(Rectified Linear Unit)
def relu(x):
    return np.maximum(0, x)

特点:简单高效,是目前最流行的激活函数

        │        ╱
        │       ╱
        │      ╱
    0.0 ┼──────────────→ x
        │
        │

优点

  • 计算简单
  • 缓解梯度消失
  • 稀疏激活
3. 其他常见激活函数
函数公式特点
Tanhtanh(x)输出在 (-1, 1)
Leaky ReLUmax(0.01x, x)解决ReLU"死亡"问题
GELUx·Φ(x)BERT等模型使用
Softmaxeˣᵢ/Σeˣⱼ多分类输出层

四、多层神经网络:深度学习的"深"

单层神经元只能解决简单的线性问题。要处理复杂任务,需要多层堆叠

输入层          隐藏层           输出层
  ○              ○
  ○    ────→     ○    ────→     ○
  ○              ○
  ○              ○

特征提取       特征变换        最终预测

为什么"深"很重要?

层次化特征学习

图像识别的层次特征:

第1层:边缘、线条
    ↓
第2层:纹理、简单形状
    ↓
第3层:部件(眼睛、耳朵、轮子)
    ↓
第4层:完整对象(人脸、汽车)
    ↓
输出层:分类结果

万能近似定理

一个具有足够多神经元的隐藏层的神经网络,理论上可以近似任何连续函数。这就是为什么深度学习能解决如此多的问题。


五、前向传播:信息流动

前向传播就是数据从输入层经过各层变换到达输出的过程。

代码实现

import numpy as np

class NeuralNetwork:
    def __init__(self, layer_sizes):
        """
        layer_sizes: 各层神经元数量,如 [2, 3, 1] 表示
                     输入2个神经元,隐藏层3个,输出1个
        """
        self.weights = []
        self.biases = []

        # 随机初始化权重和偏置
        for i in range(len(layer_sizes) - 1):
            w = np.random.randn(layer_sizes[i], layer_sizes[i+1]) * 0.01
            b = np.zeros((1, layer_sizes[i+1]))
            self.weights.append(w)
            self.biases.append(b)

    def relu(self, z):
        return np.maximum(0, z)

    def sigmoid(self, z):
        return 1 / (1 + np.exp(-z))

    def forward(self, x):
        """前向传播"""
        activation = x

        for i in range(len(self.weights) - 1):
            z = np.dot(activation, self.weights[i]) + self.biases[i]
            activation = self.relu(z)  # 隐藏层用ReLU

        # 输出层用Sigmoid(二分类)
        z = np.dot(activation, self.weights[-1]) + self.biases[-1]
        output = self.sigmoid(z)

        return output

# 使用示例
nn = NeuralNetwork([2, 4, 1])  # 2输入 -> 4隐藏 -> 1输出
x = np.array([[0.5, 0.3]])
print(nn.forward(x))

六、反向传播:神经网络如何学习

反向传播是神经网络学习的核心算法,它的本质是链式法则的应用。

核心思想

前向传播:输入 → 隐藏层 → 输出 → 预测值
反向传播:损失 ← 计算梯度 ← 更新权重

           输入
            ↓
        ┌───────┐
        │ 隐藏层 │ ←─── 反向传播梯度
        └───┬───┘
            ↓
        ┌───────┐
        │ 输出层 │ ←─── 计算损失
        └───┬───┘
            ↓
          预测值 ─── 与真实值比较 ──→ 损失函数

损失函数

衡量预测值与真实值之间的差距:

# 均方误差(回归问题)
def mse_loss(y_pred, y_true):
    return np.mean((y_pred - y_true) ** 2)

# 交叉熵损失(分类问题)
def cross_entropy_loss(y_pred, y_true):
    epsilon = 1e-15  # 防止log(0)
    y_pred = np.clip(y_pred, epsilon, 1 - epsilon)
    return -np.mean(y_true * np.log(y_pred) + (1 - y_true) * np.log(1 - y_pred))

梯度下降

根据梯度更新权重:

# 权重更新公式
w = w - learning_rate * ∂Loss/∂w
b = b - learning_rate * ∂Loss/∂b

学习率的重要性:

学习率太小:收敛太慢
    ────────────────────────→ 时间
         ╱╲  ╱╲  ╱╲  ╱╲
        ╱  ╲╱  ╲╱  ╲╱  ╲

学习率太大:可能发散
    ────────────────────────→ 时间
         ╱      ╲
        ╱        ╲
       ╱          ╲  发散!

合适的学习率:平稳收敛
    ────────────────────────→ 时间
         ╲
          ╲
           ╲________________

七、完整训练示例:XOR问题

XOR(异或)问题是一个经典的非线性问题,单层感知器无法解决,但多层神经网络可以轻松搞定。

import numpy as np

# XOR数据
X = np.array([[0, 0], [0, 1], [1, 0], [1, 1]])
y = np.array([[0], [1], [1], [0]])

class XORNetwork:
    def __init__(self):
        # 初始化权重
        self.w1 = np.random.randn(2, 4)  # 输入层到隐藏层
        self.b1 = np.zeros((1, 4))
        self.w2 = np.random.randn(4, 1)  # 隐藏层到输出层
        self.b2 = np.zeros((1, 1))
        self.lr = 0.1

    def sigmoid(self, x):
        return 1 / (1 + np.exp(-x))

    def sigmoid_derivative(self, x):
        return x * (1 - x)

    def train(self, X, y, epochs=10000):
        for epoch in range(epochs):
            # 前向传播
            z1 = np.dot(X, self.w1) + self.b1
            a1 = self.sigmoid(z1)
            z2 = np.dot(a1, self.w2) + self.b2
            a2 = self.sigmoid(z2)

            # 反向传播
            error = y - a2
            d2 = error * self.sigmoid_derivative(a2)
            d1 = d2.dot(self.w2.T) * self.sigmoid_derivative(a1)

            # 更新权重
            self.w2 += a1.T.dot(d2) * self.lr
            self.b2 += np.sum(d2, axis=0, keepdims=True) * self.lr
            self.w1 += X.T.dot(d1) * self.lr
            self.b1 += np.sum(d1, axis=0, keepdims=True) * self.lr

            if epoch % 1000 == 0:
                loss = np.mean(error ** 2)
                print(f"Epoch {epoch}, Loss: {loss:.4f}")

        return a2

# 训练
nn = XORNetwork()
output = nn.train(X, y)

print("\n最终预测结果:")
for i in range(4):
    print(f"{X[i]} -> {output[i][0]:.4f} (期望: {y[i][0]})")

输出:

Epoch 0, Loss: 0.2500
Epoch 1000, Loss: 0.1250
Epoch 2000, Loss: 0.0821
...

最终预测结果:
[0 0] -> 0.0231 (期望: 0)
[0 1] -> 0.9782 (期望: 1)
[1 0] -> 0.9784 (期望: 1)
[1 1] -> 0.0217 (期望: 0)

八、深度学习框架:让训练更简单

实际项目中,我们很少手写神经网络,而是使用成熟的框架:

PyTorch 示例

import torch
import torch.nn as nn

# 定义模型
class SimpleNN(nn.Module):
    def __init__(self):
        super().__init__()
        self.layer1 = nn.Linear(2, 4)
        self.layer2 = nn.Linear(4, 1)
        self.relu = nn.ReLU()
        self.sigmoid = nn.Sigmoid()

    def forward(self, x):
        x = self.relu(self.layer1(x))
        x = self.sigmoid(self.layer2(x))
        return x

# 创建模型
model = SimpleNN()
criterion = nn.BCELoss()
optimizer = torch.optim.Adam(model.parameters(), lr=0.01)

# 训练数据
X = torch.FloatTensor([[0, 0], [0, 1], [1, 0], [1, 1]])
y = torch.FloatTensor([[0], [1], [1], [0]])

# 训练
for epoch in range(1000):
    optimizer.zero_grad()
    outputs = model(X)
    loss = criterion(outputs, y)
    loss.backward()
    optimizer.step()

    if epoch % 200 == 0:
        print(f"Epoch {epoch}, Loss: {loss.item():.4f}")

# 预测
print("\n预测结果:")
print(model(X).detach().numpy())

九、经典网络架构

1. MLP(多层感知器)

最基础的神经网络,全连接结构。

输入层 → 隐藏层1 → 隐藏层2 → ... → 输出层
  ○        ○          ○              ○
  ○   →    ○     →    ○     →   ...   ○
  ○        ○          ○

应用:表格数据分类、回归任务

2. CNN(卷积神经网络)

专为图像设计,通过卷积核提取局部特征。

输入图像 → 卷积层 → 池化层 → 卷积层 → 全连接层 → 输出
[图片]    [特征图]  [压缩]   [高级特征]  [分类]

关键组件

  • 卷积层:提取局部特征
  • 池化层:降维,减少计算
  • 卷积核:可学习的特征检测器

3. RNN(循环神经网络)

处理序列数据,具有"记忆"能力。

时刻 t-1    时刻 t    时刻 t+1
   ○    →     ○    →     ○
   ↓          ↓          ↓
  输出       输出       输出

应用:文本处理、语音识别、时间序列预测


十、深度学习为什么成功?

因素说明
数据量大数据为深度学习提供了充足的训练样本
算力GPU并行计算让训练深层网络成为可能
算法ReLU、BatchNorm、Adam等技巧解决了训练难题
架构CNN、RNN、Transformer等架构设计合理
开源生态PyTorch、TensorFlow降低了使用门槛

小结

让我们回顾今天学习的核心概念:

概念一句话理解
神经元加权求和 + 激活函数
激活函数引入非线性,让网络能学习复杂模式
前向传播数据从输入到输出的流动过程
反向传播根据损失函数计算梯度,更新权重
深度网络层数越多,能学习的特征越抽象、越高级
学习率控制参数更新的步长

思考与练习

  1. 思考题

    • 为什么激活函数必不可少?如果去掉会怎样?
    • 深度神经网络为什么比浅层网络更强大?
  2. 动手练习

    • 修改XOR网络的隐藏层神经元数量,观察训练效果
    • 尝试用PyTorch构建一个MNIST手写数字识别模型
  3. 延伸阅读


下期预告

下一篇文章,我们将探讨:从RNN到Transformer:序列建模的演进之路

会解答这些问题:

  • RNN如何处理变长序列?
  • LSTM如何解决长距离依赖?
  • Transformer为什么能取代RNN?
  • 注意力机制的原理是什么?

关注专栏,不错过后续更新!


作者:ECH00O00 本文首发于掘金专栏《AI科普实验室》 欢迎评论区交流讨论,点赞收藏就是最大的鼓励 ❤️