提要:

本文承接上篇《机器学习速通入门》,着重讲解深度学习的思想和特定算法。以理解和应用为主。

一、深度学习的基本理解

1.1深度学习与机器学习的区别

深度学习是机器学习的一个子集,使用深层神经网络做的机器学习。

机器学习是人为提取特征,深度学习是模型自行提取特征。

深度学习所需的数据量普遍较大。

深度学习是黑盒,不具备一般可解释性。

1.2核心思想与神经网络

1.2.1核心思想

深度学习通过神经网络,可以端到端(End-to-End)从数据中直接学习到有效的特征和决策函数。

深度学习构建了神经网络的层结构,每一层都会对前一层的输出归纳,进行进一步的抽象和组合,将结果作为本层的输出,前几层学习到简单、低级的特征,后面学的是复杂、高级的特征。

1.2.2神经网络的组成

神经网络由以下部分组成:

输入层:接受原始数据的输入。(只有一层)

隐藏层:提取和变换特征。(可以为多层)

输出层:产生最终结果。(只有一层)

每一层的每个节点称为神经元。

1.2.3神经网络的计算

神经元之间的联系:

a=f(z)a=f(z)a=f(z)

z=∑i=1n(wi⋅xi)+bz = \sum_{i=1}^n (w_i \cdot x_i) + bz=i=1n(wixi)+b

其中,xxx为输入,aaa为输出,fff为激活函数,www为权重,bbb为偏置。

具体计算过程如下:

从原始输入开始,经过网络每一层的加权和、偏置、激活函数计算,最终得到输出,这个过程叫前向传播

把输出和真实标签用损失函数算出误差,再通过链式求导,从输出层往回计算每个权重和偏置的梯度,这个过程叫反向传播

根据算出的梯度,在学习率等优化策略下,更新所有权重和偏置。这个过程是参数更新

这三步合起来,就是一批数据的完整训练过程。

二、深度学习的应用

2.1基本工具

PyTorch是目前适用范围最广的深度学习框架,本文以PyTorch为基础进一步介绍深度学习的具体应用。

PyTorch本质是一个工具包,用于搭建神经网络和训练模型。

核心数据结构:Tensor(张量),可以与numpy数组互相转化。可以进行array的相似数据处理操作,包含索引、维度调整、切片等等。

2.2应用示例

本节构建一个极简神经网络作为示例,逐个介绍神经网络的相关组件。

import torch
import torch.nn as nn
import torch.optim as optim

class SequentialMultiLayerNet(nn.Module):
    def __init__(self):
        super(SequentialMultiLayerNet, self).__init__()
        # 打包3层隐藏层
        self.layers = nn.Sequential(
            nn.Linear(1, 2),    # 隐藏层1:输入维度1,输出维度2
            nn.ReLU(),          # 激活函数
            nn.Linear(2, 3),    # 隐藏层2:输入维度2,输出维度3
            nn.ReLU(),          # 激活函数
            nn.Linear(3, 4),    # 隐藏层3:输入维度3,输出维度4
            nn.ReLU(),          # 激活函数
            nn.Linear(4, 1)     # 输出层:输入维度4,输出维度1
        )

    def forward(self, x):
        return self.layers(x)

# 实例化网络
model = SequentialMultiLayerNet()  
# 定义损失函数(均方误差)
criterion = nn.MSELoss()
# 定义优化器(SGD,负责参数更新,传入网络参数+学习率)
optimizer = optim.SGD(model.parameters(), lr=0.01)  
# 训练轮数
epochs = 5

# 输入(1个样本,维度1)
x_train = torch.tensor([[1.0]]) 
# 真实标签(label)
y_train = torch.tensor([[2.0]])  

# 模型训练
for epoch in range(epochs):
    model.train()  # 训练模式
    
    # 前向传播
    y_pred = model(x_train)  # 调用forward方法,得到预测值
    loss = criterion(y_pred, y_train)  # 计算损失
    
    # 反向传播
    optimizer.zero_grad()  # 必须!清空优化器的梯度缓存
    loss.backward()  # 自动反向传播,计算所有参数的梯度

    # 参数更新
    optimizer.step()  # 优化器自动更新所有参数
    
    # 每1轮打印训练进度
    print(f"Epoch [{epoch+1}/{epochs}], Loss: {loss.item():.6f}")

# 训练完成后保存模型
torch.save({
    'model_state_dict': model.state_dict(),  # 模型参数
    'epoch': epochs,                         # 保存训练轮数
    'last_loss': loss.item()                 # 保存最后一轮损失
}, 'simple_regression_model.pth')  # 保存路径
print("\n模型已保存为:simple_regression_model.pth")

# 模型推理
print("\n开始加载模型并推理...")
# 新建模型实例
infer_model = SequentialMultiLayerNet() 
# 加载保存的模型参数
checkpoint = torch.load('simple_regression_model.pth')
infer_model.load_state_dict(checkpoint['model_state_dict'])

# 推理准备
infer_model.eval()  # 推理模式
# 推理输入
test_tensor = torch.tensor([[6.0]])
true_value = 12.0  # 真实标签

# 核心推理逻辑
with torch.no_grad():
    outputs = infer_model(test_tensor)  # 获取回归预测值
    pred_value = outputs.item()        # 取出数值结果

# 打印结果
print(f"真实标签: {true_value}") 
print(f"预测结果: {pred_value:.4f}")
2.3.1模型定义

模型定义有以下两种方式:

class SequentialMultiLayerNet(nn.Module):
    def __init__(self):
        super(SequentialMultiLayerNet, self).__init__()
        # 打包3层隐藏层
        self.layers = nn.Sequential(
            nn.Linear(1, 2),    # 隐藏层1:输入维度1,输出维度2
            nn.ReLU(),          # 激活函数
            nn.Linear(2, 3),    # 隐藏层2:输入维度2,输出维度3
            nn.ReLU(),          # 激活函数
            nn.Linear(3, 4),    # 隐藏层3:输入维度3,输出维度4
            nn.ReLU(),          # 激活函数
            nn.Linear(4, 1)     # 输出层:输入维度4,输出维度1
        )

    def forward(self, x):
        return self.layers(x)
class ManualMultiLayerNet(nn.Module):
    def __init__(self):
        super(ManualMultiLayerNet, self).__init__()
        # 完全手动定义每一层
        self.hidden1 = nn.Linear(1, 2)   # 第1层隐藏层
        self.hidden2 = nn.Linear(2, 3)   # 第2层隐藏层
        self.hidden3 = nn.Linear(3, 4)   # 第3层隐藏层
        self.output = nn.Linear(4, 1)    # 输出层

    # 前向传播
    def forward(self, x):
        # 输入 → 隐藏层1(线性计算 + ReLU激活)
        x = self.hidden1(x)
        x = torch.relu(x)
        
        # 隐藏层1 → 隐藏层2(线性计算 + ReLU激活)
        x = self.hidden2(x)
        x = torch.relu(x)
        
        # 隐藏层2 → 隐藏层3(线性计算 + ReLU激活)
        x = self.hidden3(x)
        x = torch.relu(x)
        
        # 隐藏层3 → 输出层(仅线性计算,回归任务无激活)
        x = self.output(x)
        
        # 返回最终预测值
        return x

其中,Module是所有模型的父类,管理整个模型框架。使模型定义、训练时快捷、方便。

ReLU是一个激活函数,用于赋予非线性变化,可以拟合复杂情况。

2.3.2关键组件
# 实例化网络
model = SequentialMultiLayerNet()  
# 定义损失函数(均方误差)
criterion = nn.MSELoss()
# 定义优化器(SGD,负责参数更新,传入网络参数+学习率)
optimizer = optim.SGD(model.parameters(), lr=0.01)  
# 训练轮数
epochs = 5

实例化是根据class图纸构建真实模型。

损失函数是用于计算模型输出和真实值的差距,本示例使用均方误差。

优化器用于更新参数,沿着损失变小的方向一点点修改权重和偏置。其中,常用的Adam优化器还有自适应步长等更新策略。

2.3.3数据输入
# 输入(1个样本,维度1)
x_train = torch.tensor([[1.0]]) 
# 真实标签(label)
y_train = torch.tensor([[2.0]])  

本例于此生造数据,在真实神经网络情况中,传入训练集的数据和标签。

2.3.4模型训练
# 模型训练
for epoch in range(epochs):
    model.train()  # 训练模式
    
    # 前向传播
    y_pred = model(x_train)  # 调用forward方法,得到预测值
    loss = criterion(y_pred, y_train)  # 计算损失
    
    # 反向传播
    optimizer.zero_grad()  # 必须!清空优化器的梯度缓存
    loss.backward()  # 自动反向传播,计算所有参数的梯度

    # 参数更新
    optimizer.step()  # 优化器自动更新所有参数
    
    # 每1轮打印训练进度
    print(f"Epoch [{epoch+1}/{epochs}], Loss: {loss.item():.6f}")
    
# 训练完成后保存模型
torch.save({
    'model_state_dict': model.state_dict(),  # 模型参数
    'epoch': epochs,                         # 保存训练轮数
    'last_loss': loss.item()                 # 保存最后一轮损失
}, 'simple_regression_model.pth')  # 保存路径
print("\n模型已保存为:simple_regression_model.pth")

通过“前向传播计算预测值与误差→反向传播计算参数梯度→利用梯度更新权重和偏置” 的迭代循环,模型的参数会不断优化,最终能够胜任实际任务的需求。

2.3.5模型推理与实践
# 模型推理
print("\n开始加载模型并推理...")
# 新建模型实例
infer_model = SequentialMultiLayerNet() 
# 加载保存的模型参数
checkpoint = torch.load('simple_regression_model.pth')
infer_model.load_state_dict(checkpoint['model_state_dict'])

# 推理准备
infer_model.eval()  # 推理模式
# 推理输入
test_tensor = torch.tensor([[6.0]])
true_value = 12.0  # 真实标签

# 核心推理逻辑
with torch.no_grad():
    outputs = infer_model(test_tensor)  # 获取回归预测值
    pred_value = outputs.item()        # 取出数值结果

# 打印结果
print(f"真实标签: {true_value}") 
print(f"预测结果: {pred_value:.4f}")

新创建一个模型示例并读取之前的训练结果,然后用这个训练好的模型进行实际任务工作。

三、深度学习基础通用算法

3.1卷积神经网络CNN

3.1.1CNN的简介

卷积神经网络常应用于图像识别领域(不局限于图像领域),基础组件包括卷积层、池化层、全连接层。

卷积层用于提取特征,用卷积核(一个张量)对特征图进行局部加权求和,类似“在图片上滑动”,完成特征提取。卷积核的参数是训练出来的,在训练过后的不同卷积核拥有提取不同特征的能力,每个卷积核意味着一个特征的提取。

池化层用于压缩图片和降维,常见的有最大池化和平均池化两种,池化层的采样方式由人工设定,无可学习参数,可以压缩信息的同时和保留关键信息,并防止过拟合。

感受野是指输出特征图上一个点对应原始图片的区域大小。如下图,顶层的一个点的感受野是7*7。

全连接层是把提取好的特征用来完成最终任务。

权值共享:一个卷积核在图上滑动,参数极少。

局部感受野:只看局部区域,再拼起来理解整体。

下采样:把图变小,丢掉细节,保留整体信息。

上采样:把图变大,恢复分辨率。

3.1.2卷积操作的分类
1.普通卷积

比如,处理一个66的3通道彩色图(RGB),设定卷积核大小为33,卷积核个数为4,步长(卷积核单次滑动的距离)为1,填充为1(让输出尺寸不变)。

原始数据的输入维度是(3,6,6)。

单个卷积核需要处理三个通道每个通道3*3的内容,所以是(3,3,3)。

四个卷积核所以卷积整层权重维度为(4,3,3,3)。

输出四个特征图,所以是(4,6,6)。

2.逐通道卷积

相比于普通卷积,逐通道卷积采用单通道卷积核。

仍然以6*6原始图片为例,若采用3个卷积核分别处理3个通道,参数会大大减少。注意,该方法当前阶段的通道间融合的信息丢失了。

3.逐点卷积

在逐点卷积中,一个(3,1,1)的卷积核可以将输入的三通道信息进行融合,若采用四个这样的卷积核,即可提取原图片的四个特征。

4.深度可分离卷积

不难发现,逐通道卷积+逐点卷积可以大大减少参数量,逐点卷积也弥补了逐通道卷积没有融合通道间信息的缺点,这种方法叫做深度可分离卷积。

5.组卷积

为了减少参数量,需要对普通卷积做优化,而深度可分离卷积又会一定程度上掉精度,所以需要一个折中办法。

所以,普通卷积和深度可分离卷积是组卷积的极端情况,普通卷积的组数为1,所有输入通道一起卷积。深度可分离卷积组数等于输入通道,每个通道逐个卷积。而组卷积可以折中,比如四个输入通道,可以两个一组,每组单独卷积。

6.空间可分离卷积

对输入特征图在横向和纵向分别进行一维卷积操作,减少计算量。

7.膨胀卷积

用于增加感受野。

8.转置卷积

可以放大特征图尺寸,相当于卷积反过来做:

输入→扩散→加权求和

9.一维卷积

通常用于处理序列数据,在单个维度上滑动卷积核,提取列内局部特征和模式。

3.2循环神经网络RNN

3.2.1RNN的简介

RNN常用于处理有顺序、有先后关系的数据。(如文本,语音等等)

RNN的结构最主要有三个:输入,隐藏状态(记忆),输出。

ht=tanh⁡(Wihxt+Whhht−1+bh)h_t = \tanh\left(W_{ih} x_t + W_{hh} h_{t-1} + b_h\right)ht=tanh(Wihxt+Whhht1+bh)

yt=Whoht+boy_t = W_{ho} h_t + b_oyt=Whoht+bo

hhh代表某时刻的记忆,xxx代表当前时刻的输入,yyy代表当前时刻的输出,bbb为偏置,WWW为权重。

ihihih代表输入→隐藏。hhhhhh代表隐藏→隐藏。hohoho代表隐藏→输出。

即:

当前记忆=新输入+上一刻的记忆

输出=根据当前记忆预测

3.2.2RNN经典变体
1.BRNN

双向RNN,接受上下文信息:接受当前输入、下一刻隐藏状态、上一刻隐藏状态。

2.DRNN

深度RNN,用多层来堆叠,越深层特征越高级。输出只由最深层决定。

3.2.3长短期记忆LSTM

由于RNN的信息存储量过大导致的信息冗余、遗忘等问题,发明了LSTM。

遗忘门:xxxht−1h_{t-1}ht1决定Ct−1C_{t-1}Ct1遗忘多少长期记忆。

输入门:xxxht−1h_{t-1}ht1决定Ct−1C_{t-1}Ct1储存多少新信息。

输出门:xxxht−1h_{t-1}ht1决定Ct−1C_{t-1}Ct1有多少输出给hth_tht

3.3Transformer

Transformer是当前流行、强大的模型基础架构,要谈Transformer,我们先从注意力机制(Attention)开始。

3.3.1Attention机制

在日常信息传递中,经常有重点信息和废物信息,注意力机制可以舍弃一些没用的特征,对关键语义进行捕捉。

注意力计算中,将每个输入向量(词的特征表示,张量形式)通过线性变换映射为Q(Query)查询向量,K(Key)键向量,V(Value)值向量三个新向量,然后针对一个词的Q,计算与其所有K的相似度(包括本身)得到相关性分数,然后进行分数加权求和(各个词相关性权重与V)得到该词的新表示形式,这种形式融合了全局的信息。

之后可将该全局信息进行下一步处理。

多头注意力机制:多组并行的自注意力,多组QKV(单头维度=总维数÷头数),最终输出由多组拼接而成,可以捕捉多维度的信息。

3.3.2编码与解码
1.编码器(Encoder)

编码器的核心在于:看懂输入。主要采用自注意力机制。

Transformer的编码器主要根据注意力机制完成,但是注意,针对文本需要添加位置编码,否则没有位置信息。

2.解码器(Decoder)

解码器的核心在于:根据已知输入生成输出。主要采用掩码自注意力机制和交叉注意力机制。

逐字生成

要理解解码器,我们要知道一个前提:直接让模型生成一整句话,然后看与理想结果的误差之后反向传播更新参数是不可行的!!因为过于复杂,模型输出的东西也千奇百怪,很难正确反向传播。所以Transformer的解码器是逐字输出,只需要通过单字误差来反向传播,这样才能保证可行、有效。

又由于逐字生成,模型在训练的时候必须看到当前预测位置及之前的答案而又不能看完整的标准答案,因此,Transformer有掩码(mask)自注意力机制,用于遮住当前预测位置之后的答案。

最后生成结束之后计算总损失,进行反向传播和更新参数。

交叉注意力

交叉注意力机制应用两个信息:其一是已知的编码器输入,其二是目前已知的答案(推理时第二个信息是已生成的内容),交叉注意力机制会将已生成内容的全局信息Q去询问编码器全局信息的K和V,得到一个带着原文信息的新向量,用这个信息去预测下一个词。

图片来源:Attention Is All You Need, Vaswani et al., 2017

3.3.3实际应用

本节我们用轻松有趣的心态,聊一聊 Transformer 和大语言模型到底是怎么 “干活” 的。
前面说到,Transformer 的核心逻辑很朴素:
对照编码器的输入,再结合已经输出的内容,一步步预测下一个输出。
那科学家们是怎么让这个 “不停猜下一个词” 的机制,变得真正有用呢?
其实 Transformer 最早就是为机器翻译设计的。
输入一句中文,输出一句英文,两段话语义几乎完全一样,只是语言不同。
所以编码器负责 “读懂原句”,解码器负责 “用另一种语言复刻原句”,本质就是:
理解 → 转述,实际上只是模型抓住了英文与中文的对应关系,见到中文就输出英文而已。
那它又是怎么从 “翻译” 进化到能问答、聊天、写文案的呢?
答案其实很简单:
现在能做问答的大模型,只是在训练时见过海量的「问题 → 答案」对。
它这次学会了问题和回答之间的对应关系,所以当你抛出一个问题,它就顺着规律,输出最像 “答案” 的内容。
写诗、写邮件、日常聊天也是同理:
模型只是学会了 “指令 → 对应输出” 的模式匹配。
更进一步,你可能会好奇:
像 GPT、DeepSeek 这类大语言模型,为什么能同时做翻译、写代码、讲故事、做数学题?
关键就在于:
现代 LLM 在训练时,会把指令和任务一起喂给模型。
比如同样是 “十进制” 这个主题:
指令是 “写一首诗”,模型就输出诗歌
指令是 “讲数学知识”,模型就走讲解逻辑
它学会了根据不同指令,切换不同任务模式。
这就是让大模型变得 “全能” 的核心。
再往后发展,研究者又把语音、图像、视频也加进来,
让模型不只懂文字,还能看图、听话、唱歌、绘画,甚至接入自动驾驶、机器人等真实场景。
这种 “一种模型理解多种模态” 的思路,就是我们常说的多模态,
也让 AI 真正一步步走进了日常生活。

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐