大模型基本原理完全教程(入门到专家)
在大模型出现之前,我们解决问题的方式是"写程序":程序员需要明确告诉计算机每一步该做什么,计算机严格按照程序执行。收集大量正面和负面的词汇写规则:如果句子中正面词汇多,就判断为正面;负面词汇多,就判断为负面不断调试规则,直到效果满意规则很难覆盖所有情况语言是灵活的,同样的意思可以有不同的表达方式规则维护成本很高大模型的出现改变了这一切。准备大量的文本数据让大模型"学习"这些数据大模型自动学会理解语
教程定位:从零开始系统学习大模型原理,兼顾专业性与通俗性
适用人群:零基础学习者、传统IT从业者、AI爱好者
学习周期:建议3-6个月系统学习
目录
- 开篇:大模型时代的到来
- 基础篇:机器学习与深度学习入门
- 核心篇:Transformer架构详解
- 进阶篇:注意力机制深度解析
- 训练篇:大模型预训练与微调
- 优化篇:模型压缩与推理加速
- 应用篇:大模型的实际应用
- 代码篇:从零实现大模型核心组件
- 展望篇:大模型的未来发展
- 附录:学习资源与工具推荐
1. 开篇:大模型时代的到来
1.1 什么是大模型?
1.1.1 从"程序"到"模型"的转变
在大模型出现之前,我们解决问题的方式是"写程序":程序员需要明确告诉计算机每一步该做什么,计算机严格按照程序执行。
比如,我们要做一个"判断一句话是正面还是负面"的程序,需要:
- 收集大量正面和负面的词汇
- 写规则:如果句子中正面词汇多,就判断为正面;负面词汇多,就判断为负面
- 不断调试规则,直到效果满意
但这种方式有很大的局限性:
- 规则很难覆盖所有情况
- 语言是灵活的,同样的意思可以有不同的表达方式
- 规则维护成本很高
大模型的出现改变了这一切。我们不再需要写复杂的规则,只需要:
- 准备大量的文本数据
- 让大模型"学习"这些数据
- 大模型自动学会理解语言、完成任务
1.1.2 大模型的定义
大模型(Large Language Model,简称LLM),也叫"大语言模型",是一种基于深度学习的人工智能系统,它通过学习海量的文本数据,能够理解和生成人类语言。
简单来说,大模型就像一个"超级语言学习者":
- 它"读"过的书比人类一辈子读的还要多得多
- 它能理解语言的含义、语法、逻辑
- 它能根据输入的内容,生成连贯、有意义的回答
1.1.3 大模型的"大"体现在哪里?
大模型的"大"主要体现在三个方面:
- 参数量大:
-
- 参数量是模型中可学习参数的数量,类似于人类大脑中的神经元连接
-
- 早期的小模型可能只有几百万、几千万参数
-
- 现在的大模型通常有几十亿、几百亿甚至上千亿参数
-
- 比如:GPT-3有1750亿参数,通义千问有上千亿参数
- 训练数据量大:
-
- 大模型需要学习海量的文本数据
-
- 这些数据包括:书籍、网页、文章、代码等
-
- 总数据量可能达到几十TB甚至几百TB
-
- 相当于"读"了几百万本书
- 计算量大:
-
- 训练大模型需要大量的计算资源
-
- 通常需要成百上千张GPU(图形处理器)同时工作
-
- 训练一次可能需要几周、几个月甚至更长时间
-
- 电费、硬件成本可能达到几百万、几千万
小白问答
问:参数量是什么?为什么参数量越大,模型越"聪明"?
答:你可以把参数量想象成模型的"大脑容量"。
就像人类大脑一样,神经元连接越多,能记住和理解的东西就越多。
参数量大的模型:
- 能记住更多的知识
- 能理解更复杂的语言
- 能完成更困难的任务
- 但这也不是绝对的,参数量只是衡量模型能力的一个指标,不是唯一指标。
问:大模型是怎么"学习"的?它真的"理解"了吗?
答:这是一个很好的问题!
大模型的"学习"和人类的学习不太一样:
- 人类学习是理解概念、建立逻辑
- 大模型学习是"统计"语言的规律
- 比如,当大模型看到"天空是___"时,它会根据统计规律,知道"蓝色"出现的概率最高,所以会填"蓝色"。
- 从这个角度说,大模型可能没有真正"理解",但它通过统计规律,表现得像是理解了。
1.2 大模型的发展历程
1.2.1 早期的自然语言处理(2010年之前)
在大模型出现之前,自然语言处理(NLP)领域经历了几个阶段:
- 规则-based时代(1950s-1990s):
-
- 完全依靠人工编写规则
-
- 比如:语法规则、词典规则
-
- 局限性:规则很难覆盖所有情况
- 统计机器学习时代(1990s-2010s):
-
- 使用统计方法,让模型从数据中学习规律
-
- 常用方法:朴素贝叶斯、支持向量机(SVM)、隐马尔可夫模型(HMM)
-
- 局限性:需要大量人工标注数据,模型能力有限
1.2.2 深度学习时代(2010-2017)
2010年之后,深度学习开始应用于自然语言处理:
- 循环神经网络(RNN):
-
- 能够处理序列数据(比如句子)
-
- 有"记忆"能力,能记住之前的信息
-
- 局限性:难以处理长序列,训练困难
- 长短期记忆网络(LSTM):
-
- RNN的改进版,能更好地处理长序列
-
- 在很多任务上取得了不错的效果
-
- 局限性:并行计算困难,训练速度慢
- 注意力机制的萌芽:
-
- 2014年,注意力机制(Attention)被提出
-
- 让模型能够"关注"输入中的重要部分
-
- 为后来的Transformer奠定了基础
1.2.3 Transformer时代(2017-2020)
2017年是大模型发展史上的里程碑:
- Transformer架构的提出:
-
- 2017年,Google发表论文《Attention Is All You Need》
-
- 提出了Transformer架构
-
- 完全基于注意力机制,不再使用RNN
-
- 优势:并行计算能力强,能处理长序列
- 预训练模型的兴起:
-
- 2018年,OpenAI提出GPT(Generative Pre-trained Transformer)
-
- 2018年,Google提出BERT(Bidirectional Encoder Representations from Transformers)
-
- 这些模型通过"预训练+微调"的方式,在很多任务上取得了最好效果
1.2.4 大模型时代(2020年至今)
2020年之后,大模型进入爆发期:
- GPT-3的发布:
-
- 2020年,OpenAI发布GPT-3,1750亿参数
-
- 展示了大模型的惊人能力:写文章、写代码、翻译等
-
- 让人们意识到大模型的巨大潜力
- ChatGPT的爆发:
-
- 2022年11月,OpenAI发布ChatGPT
-
- 对话式交互,使用门槛大大降低
-
- 迅速火遍全球,引发了大模型热潮
- 国内大模型的发展:
-
- 2023年,国内大模型如雨后春笋般涌现
-
- 通义千问、文心一言、智谱AI、Llama等
-
- 大模型技术快速普及
1.2.5 大模型发展时间线
timeline
title 大模型发展时间线
2017 : Transformer架构提出
2018 : GPT-1发布<br>BERT发布
2019 : GPT-2发布
2020 : GPT-3发布(1750亿参数)
2021 : 国内大模型开始起步
2022 : ChatGPT发布<br>引发全球热潮
2023 : 国内大模型爆发<br>通义千问、文心一言等
2024 : 多模态大模型兴起<br>小模型性能提升
1.3 大模型的核心特性
1.3.1 语言理解能力
大模型最核心的能力是理解人类语言:
- 语义理解:
-
- 理解词语、句子的含义
-
- 理解上下文、语境
-
- 理解隐含的意思、言外之意
- 语法理解:
-
- 理解语法规则
-
- 识别句子结构
-
- 纠正语法错误
- 逻辑理解:
-
- 理解因果关系
-
- 理解推理过程
-
- 进行简单的逻辑推理
1.3.2 语言生成能力
大模型不仅能理解,还能生成语言:
- 文本生成:
-
- 写文章、写故事、写诗歌
-
- 写邮件、写报告、写总结
-
- 内容连贯、语法正确
- 对话生成:
-
- 进行多轮对话
-
- 理解对话上下文
-
- 给出合适的回应
- 代码生成:
-
- 根据需求写代码
-
- 解释代码含义
-
- 修复代码bug
1.3.3 知识存储与应用
大模型在训练过程中学习了大量知识:
- 知识存储:
-
- 存储了海量的事实性知识
-
- 存储了语言知识、常识知识
-
- 存储了专业领域知识
- 知识应用:
-
- 回答问题
-
- 解释概念
-
- 提供建议
- 知识更新:
-
- 传统大模型的知识是"静态"的,训练截止后知识就固定了
-
- 现在可以通过RAG(检索增强生成)等技术,让大模型使用最新知识
1.3.4 泛化能力
大模型的一个重要特性是"泛化能力":
- 任务泛化:
-
- 一个模型能完成多种任务
-
- 不需要为每个任务单独训练
-
- 通过Prompt就能切换任务
- 领域泛化:
-
- 能处理不同领域的问题
-
- 通用领域、专业领域都能应对
-
- 不需要专门的领域训练
- 语言泛化:
-
- 能处理多种语言
-
- 翻译、多语言对话
-
- 跨语言理解
1.3.5 涌现能力
当模型规模达到一定程度时,会出现"涌现能力"(Emergent Abilities):
- 什么是涌现能力?:
-
- 小模型不具备的能力
-
- 当模型规模达到一定程度时突然出现
-
- 类似于"量变引起质变"
- 常见的涌现能力:
-
- 复杂推理能力
-
- 多步任务规划能力
-
- 抽象概念理解能力
-
- 创意生成能力
- 涌现能力的意义:
-
- 这是大模型最令人兴奋的特性之一
-
- 意味着更大的模型可能会有更多意想不到的能力
-
- 也让我们对大模型的潜力充满期待
小白问答
问:什么是"泛化能力"?能举个例子吗?
答:"泛化能力"简单说就是"举一反三"的能力。
比如:
- 你教一个小学生"1+1=2"
- 他不仅会算"1+1",还会算"2+3"、"5+7"
- 这就是泛化能力
- 大模型也是一样:
- 它在训练时见过很多例子
- 但它能处理训练时没见过的新问题
- 这就是泛化能力强的表现
问:涌现能力是怎么出现的?为什么小模型没有?
答:这是一个非常前沿的研究问题,科学家们还在研究中。
一个简单的类比:
- 一滴水很小,看不出什么
- 但很多水滴聚在一起,就能形成河流、海洋
- 这时候就会出现"波浪"、"潮汐"等单个水滴没有的特性
- 大模型的涌现能力可能也是类似:
- 当参数量、数据量达到一定程度
- 模型内部会形成复杂的"连接"和"结构"
- 从而出现小模型没有的能力
- 这也是为什么大家都在追求"更大"的模型的原因之一。
1.4 大模型能做什么?
1.4.1 文本处理类
- 文本生成:
-
- 写文章、写故事、写诗歌
-
- 写邮件、写报告、写总结
-
- 写广告文案、写产品描述
- 文本理解:
-
- 文本分类(正面/负面、主题分类)
-
- 情感分析(判断情绪)
-
- 意图识别(理解用户想做什么)
- 文本转换:
-
- 翻译(中英互译、多语言翻译)
-
- 改写(润色、简化、扩写)
-
- 格式转换(文本转表格、文本转JSON)
1.4.2 知识问答类
- 通用问答:
-
- 回答常识问题
-
- 解释概念、定义
-
- 提供信息、数据
- 专业问答:
-
- 医疗健康咨询
-
- 法律咨询
-
- 技术问题解答
- 教育辅导:
-
- 讲解知识点
-
- 解题思路指导
-
- 作业批改、反馈
1.4.3 编程开发类
- 代码生成:
-
- 根据需求写代码
-
- 补全代码片段
-
- 多种编程语言支持
- 代码理解:
-
- 解释代码含义
-
- 代码审查、建议
-
- 代码重构建议
- 调试修复:
-
- 定位bug原因
-
- 提供修复方案
-
- 性能优化建议
1.4.4 创意创作类
- 内容创作:
-
- 写小说、剧本
-
- 写歌词、诗歌
-
- 创作故事、创意
- 艺术设计:
-
- 设计思路建议
-
- 配色方案推荐
-
- 文案、标语创作
- 游戏娱乐:
-
- 游戏剧情设计
-
- 角色对话生成
-
- 谜题设计
1.4.5 企业应用类
- 客户服务:
-
- 智能客服
-
- 常见问题解答
-
- 工单处理
- 内容运营:
-
- 内容生成
-
- 标题优化
-
- SEO建议
- 数据分析:
-
- 数据解读
-
- 报告生成
-
- 趋势分析
小白问答
问:大模型这么厉害,它会取代人类吗?
答:这是一个很多人关心的问题。
我的看法是:大模型会"改变"很多工作,但不会完全"取代"人类。
原因:
- 大模型没有真正的"理解"和"意识"
- 大模型可能会"幻觉"(编造信息)
- 大模型没有情感、价值观、创造力
- 很多工作需要人类的判断力、同理心、创造力
- 更可能的情况是:
- 大模型成为人类的"助手"
- 人类负责决策、创造、判断
- 大模型负责处理重复性、机械性的工作
- 人类和大模型协作,效率更高
问:大模型会"幻觉"吗?什么是幻觉?
答:是的,大模型会"幻觉"(Hallucination),这是大模型的一个重要问题。
"幻觉"简单说就是:
- 大模型编造了一些信息
- 但它表现得像是真的一样
- 听起来很有道理,但实际上是错的
- 比如:
- 你问大模型"某某人获得过诺贝尔奖吗?"
- 大模型可能会编造一个获奖理由
- 但实际上这个人根本没有获奖
- 为什么会出现幻觉?
- 大模型是根据统计规律生成内容的
- 它可能会"合理地编造"一些信息
- 它不知道哪些是真的,哪些是假的
- 所以使用大模型时:
- 重要信息一定要核实
- 不要完全相信大模型的回答
- 尤其是专业领域、事实性问题
1.5 本章总结与回顾
1.5.1 核心知识点总结
- 大模型的定义:
-
- Large Language Model(LLM)
-
- 基于深度学习的人工智能系统
-
- 通过学习海量文本数据,理解和生成人类语言
- 大模型的"大":
-
- 参数量大(几十亿、几百亿、上千亿)
-
- 训练数据量大(几十TB、几百TB)
-
- 计算量大(需要大量GPU)
- 大模型的发展历程:
-
- 规则-based时代 → 统计机器学习时代 → 深度学习时代 → Transformer时代 → 大模型时代
-
- 2017年Transformer架构提出是重要里程碑
-
- 2022年ChatGPT发布引发全球热潮
- 大模型的核心特性:
-
- 语言理解能力
-
- 语言生成能力
-
- 知识存储与应用
-
- 泛化能力(举一反三)
-
- 涌现能力(量变引起质变)
- 大模型的应用:
-
- 文本处理、知识问答
-
- 编程开发、创意创作
-
- 企业应用等
1.5.2 重要概念回顾
|
概念 |
解释 |
|
大模型(LLM) |
Large Language Model,基于深度学习的人工智能系统,能理解和生成人类语言 |
|
参数量 |
模型中可学习参数的数量,类似于大脑神经元连接 |
|
Transformer |
2017年提出的架构,完全基于注意力机制,是大模型的基础 |
|
泛化能力 |
模型处理未见过的新问题的能力,即"举一反三" |
|
涌现能力 |
当模型规模达到一定程度时突然出现的能力,小模型不具备 |
|
幻觉 |
大模型编造信息,但表现得像是真的一样 |
1.5.3 扩展阅读资源
- 论文推荐:
-
- 《Attention Is All You Need》(2017)- Transformer架构原始论文
-
- 《Language Models are Few-Shot Learners》(2020)- GPT-3论文
-
- 《GPT-4 Technical Report》(2023)- GPT-4技术报告
- 书籍推荐:
-
- 《深度学习》(Goodfellow等著)- 深度学习经典教材
-
- 《动手学深度学习》(李沐等著)- 通俗易懂的深度学习入门书
-
- 《大模型时代》(李开复等著)- 大模型科普书
- 在线资源:
-
- Hugging Face(https://huggingface.co/)- 大模型社区
-
- OpenAI博客(https://openai.com/blog)- OpenAI官方博客
-
- 李沐B站视频(https://space.bilibili.com/1567748478)- 深度学习教程
1.5.4 下一步学习建议
在开始下一章之前,建议你:
- 体验一下大模型:
-
- 试用ChatGPT、通义千问等大模型
-
- 尝试不同的任务:问答、写作、编程
-
- 感受大模型的能力和局限性
- 了解一些基础概念:
-
- 什么是机器学习?
-
- 什么是深度学习?
-
- 什么是神经网络?
- 准备学习心态:
-
- 大模型原理涉及一些数学,但不要害怕
-
- 我们会用通俗易懂的方式讲解
-
- 重点是理解概念,不是推导公式
2. 基础篇:机器学习与深度学习入门
2.1 什么是机器学习?
2.1.1 从"写程序"到"学程序"
传统编程是"数据+规则=答案",比如计算圆的面积:
# 传统编程:明确规则
import math
def calculate_circle_area(radius):
# 人类定义的规则:面积 = πr²
return math.pi * radius * radius
# 输入数据,得到答案
print(calculate_circle_area(5)) # 输出: 78.53981633974483
机器学习则是"数据+答案=规则",比如让模型学习区分猫和狗的图片:
# 机器学习思路
数据:1000张猫的图片 + 1000张狗的图片
答案:每张图片的标签(猫/狗)
规则:模型自动学习的区分特征(比如耳朵形状、鼻子大小)
这种模式的优势在于,当规则过于复杂(比如语言理解),人类无法手动定义时,机器学习可以从数据中自动学习。
2.1.2 机器学习的定义
机器学习(Machine Learning,ML) 是人工智能的一个分支,它让计算机能够在没有被明确编程的情况下学习。简单来说,机器学习就是让计算机从数据中学习规律,并用这些规律来预测新的数据。
核心公式:经验(数据)→ 学习 → 改进 → 预测
2.1.3 机器学习的分类
根据学习方式的不同,机器学习主要分为三类:
- 监督学习(Supervised Learning)
-
- 特点:数据带有标签(答案)
-
- 目标:学习输入到输出的映射关系
-
- 常见任务:
-
-
- 分类(Classification):预测离散值(比如猫/狗、正面/负面)
-
-
-
- 回归(Regression):预测连续值(比如房价、温度)
-
-
- 例子:垃圾邮件识别、房价预测、图像分类
- 无监督学习(Unsupervised Learning)
-
- 特点:数据没有标签
-
- 目标:发现数据中的隐藏模式或结构
-
- 常见任务:
-
-
- 聚类(Clustering):将相似的数据分组
-
-
-
- 降维(Dimensionality Reduction):减少数据维度,保留关键信息
-
-
- 例子:用户分群、异常检测、数据压缩
- 强化学习(Reinforcement Learning)
-
- 特点:通过与环境交互学习
-
- 目标:学习最优的行动策略,最大化奖励
-
- 核心概念:智能体(Agent)、环境(Environment)、奖励(Reward)
-
- 例子:AlphaGo、自动驾驶、游戏AI
小白问答
问:监督学习和无监督学习的区别是什么?能举个例子吗?
答:最核心的区别是数据是否有标签:
- 监督学习:老师教学生(有标准答案)
比如:给学生100道数学题+答案,学生学习解题方法
- 无监督学习:学生自己看书总结规律(无标准答案)
比如:给学生100篇文章,学生自己总结出不同的主题
-
- 实际应用例子:
- 监督学习:用带标签的邮件(垃圾/非垃圾)训练垃圾邮件识别模型
- 无监督学习:将用户的购买记录分组,发现不同的消费习惯
2.2 神经网络基础
2.2.1 从生物神经元到人工神经元
人类大脑中有约860亿个神经元,每个神经元通过突触连接,形成复杂的网络。当神经元接收到足够的信号时,就会被激活并传递信号。
人工神经元(Artificial Neuron)是对生物神经元的简化模拟:
graph TD
A[输入1] -->|权重1| C[求和]
B[输入2] -->|权重2| C
D[偏置] --> C
C --> E[激活函数]
E --> F[输出]
核心计算过程:
- 每个输入乘以对应的权重
- 求和后加上偏置
- 通过激活函数得到输出
数学表达式: y = f(\sum_{i=1}^{n} w_i x_i + b)
2.2.2 感知机
感知机(Perceptron)是最简单的人工神经元模型,由Frank Rosenblatt在1957年提出:
import numpy as np
class Perceptron:
def __init__(self, input_size, learning_rate=0.1, epochs=100):
# 初始化权重和偏置
self.weights = np.zeros(input_size)
self.bias = 0
self.learning_rate = learning_rate
self.epochs = epochs
# 激活函数:阶跃函数
def activate(self, x):
return 1 if x >= 0 else 0
# 预测
def predict(self, x):
# 计算加权和 + 偏置
linear_output = np.dot(x, self.weights) + self.bias
# 通过激活函数
return self.activate(linear_output)
# 训练
def train(self, X, y):
for _ in range(self.epochs):
for inputs, label in zip(X, y):
# 预测
prediction = self.predict(inputs)
# 计算误差
error = label - prediction
# 更新权重和偏置
self.weights += self.learning_rate * error * inputs
self.bias += self.learning_rate * error
# 测试:学习逻辑与(AND)
if __name__ == "__main__":
# 训练数据:逻辑与的输入和输出
X = np.array([[0,0], [0,1], [1,0], [1,1]])
y = np.array([0, 0, 0, 1])
# 创建感知机
perceptron = Perceptron(input_size=2)
# 训练
perceptron.train(X, y)
# 测试
print("0 AND 0 =", perceptron.predict([0,0])) # 0
print("0 AND 1 =", perceptron.predict([0,1])) # 0
print("1 AND 0 =", perceptron.predict([1,0])) # 0
print("1 AND 1 =", perceptron.predict([1,1])) # 1
2.2.3 激活函数
激活函数是神经网络的核心,它为线性的神经元添加非线性,让神经网络能够学习复杂的模式。
常见的激活函数:
- Sigmoid函数
-
- 公式: σ(x) = \frac{1}{1 + e^{-x}}
-
- 输出范围:(0, 1)
-
- 特点:平滑、可微,但存在梯度消失问题
-
- 用途:二分类的输出层
- Tanh函数
-
- 公式: tanh(x) = \frac{e^x - e^{-x}}{e^x + e^{-x}}
-
- 输出范围:(-1, 1)
-
- 特点:零均值,比Sigmoid收敛更快
- ReLU函数
-
- 公式: ReLU(x) = max(0, x)
-
- 输出范围:[0, ∞)
-
- 特点:计算简单,缓解梯度消失,是目前最常用的激活函数
-
- 缺点:存在"死亡ReLU"问题(某些神经元永远不激活)
- Softmax函数
-
- 公式: σ(z)_i = \frac{e^{z_i}}{\sum_{j=1}^{K} e^{z_j}}
-
- 输出范围:(0, 1),所有输出之和为1
-
- 用途:多分类的输出层
import numpy as np
import matplotlib.pyplot as plt
# 定义激活函数
def sigmoid(x):
return 1 / (1 + np.exp(-x))
def tanh(x):
return np.tanh(x)
def relu(x):
return np.maximum(0, x)
def softmax(x):
exp_x = np.exp(x - np.max(x)) # 防止溢出
return exp_x / np.sum(exp_x)
# 可视化
x = np.linspace(-5, 5, 100)
plt.figure(figsize=(12, 8))
plt.subplot(2, 2, 1)
plt.plot(x, sigmoid(x))
plt.title('Sigmoid')
plt.grid(True)
plt.subplot(2, 2, 2)
plt.plot(x, tanh(x))
plt.title('Tanh')
plt.grid(True)
plt.subplot(2, 2, 3)
plt.plot(x, relu(x))
plt.title('ReLU')
plt.grid(True)
plt.subplot(2, 2, 4)
plt.plot(x, softmax(x))
plt.title('Softmax (示例)')
plt.grid(True)
plt.tight_layout()
plt.show()
2.3 深度学习入门
2.3.1 什么是深度学习?
深度学习(Deep Learning) 是机器学习的一个子领域,它使用多层神经网络来学习数据的特征表示。"深度"指的是神经网络的层数较多(通常至少3层)。
深度学习的核心思想是特征学习:模型自动从数据中学习特征,而不需要人工设计特征。
2.3.2 深度学习的优势
- 自动特征学习:无需人工设计特征
- 处理复杂数据:擅长处理图像、语音、文本等非结构化数据
- 端到端学习:从原始数据直接学习到目标输出
- 可扩展性:增加数据和模型规模,性能通常会提升
2.3.3 常见的深度学习架构
- 卷积神经网络(CNN)
-
- 专门处理网格结构数据(如图像)
-
- 核心操作:卷积、池化
-
- 特点:共享权重、局部连接
-
- 应用:图像识别、目标检测、图像生成
- 循环神经网络(RNN)
-
- 专门处理序列数据(如文本、语音)
-
- 特点:有记忆能力,能处理变长序列
-
- 变体:LSTM、GRU(解决长序列依赖问题)
-
- 应用:语言模型、机器翻译、语音识别
- Transformer
-
- 基于注意力机制的架构
-
- 完全并行计算,训练速度快
-
- 能处理长序列
-
- 应用:大语言模型、机器翻译、多模态模型
2.4 神经网络的训练
2.4.1 损失函数
损失函数(Loss Function)用于衡量模型预测值与真实值之间的差距,是训练的核心。
常见的损失函数:
- 均方误差(MSE)
-
- 公式: MSE = \frac{1}{n} \sum_{i=1}^{n} (y_i - \hat{y}_i)^2
-
- 用途:回归任务
- 交叉熵损失(Cross-Entropy Loss)
-
- 二分类: CE = -\frac{1}{n} \sum_{i=1}^{n} [y_i log(\hat{y}_i) + (1-y_i) log(1-\hat{y}_i)]
-
- 多分类: CE = -\frac{1}{n} \sum_{i=1}^{n} \sum_{j=1}^{k} y_{ij} log(\hat{y}_{ij})
-
- 用途:分类任务
2.4.2 反向传播
反向传播(Backpropagation)是训练神经网络的核心算法,它的基本思想是:
- 前向传播:计算预测值和损失
- 反向传播:计算损失对每个参数的梯度
- 参数更新:根据梯度调整参数,减小损失
graph TD
A[输入数据] --> B[前向传播]
B --> C[计算预测值]
C --> D[计算损失]
D --> E[反向传播]
E --> F[计算梯度]
F --> G[参数更新]
G --> B
2.4.3 优化器
优化器(Optimizer)用于根据梯度更新参数,常见的优化器:
- 随机梯度下降(SGD)
-
- 公式: θ = θ - η ∇L(θ)
-
- 特点:简单,但收敛慢
- 动量SGD(SGD with Momentum)
-
- 引入动量,加速收敛,减少震荡
- Adam
-
- 结合动量和自适应学习率
-
- 目前最常用的优化器
-
- 收敛快,稳定性好
2.5 本章总结与回顾
2.5.1 核心知识点总结
- 机器学习:让计算机从数据中学习规律,分为监督学习、无监督学习、强化学习
- 神经网络:由人工神经元组成的网络,通过激活函数引入非线性
- 深度学习:使用深层神经网络进行特征学习
- 训练过程:通过前向传播计算损失,反向传播计算梯度,优化器更新参数
2.5.2 重要概念回顾
|
概念 |
解释 |
|
监督学习 |
数据带标签,学习输入到输出的映射 |
|
无监督学习 |
数据无标签,发现数据的隐藏模式 |
|
激活函数 |
为神经元添加非线性,常用ReLU、Sigmoid |
|
损失函数 |
衡量预测值与真实值的差距,常用MSE、交叉熵 |
|
反向传播 |
计算损失对参数的梯度,用于参数更新 |
|
优化器 |
根据梯度更新参数,常用Adam、SGD |
3. 核心篇:Transformer架构详解
3.1 Transformer架构总览
3.1.1 为什么需要Transformer?
在Transformer出现之前,处理序列数据主要使用RNN及其变体(LSTM、GRU),但RNN有两个致命缺点:
- 并行计算困难:RNN需要按顺序处理序列,无法并行计算
- 长序列依赖问题:难以捕捉长距离的依赖关系
Transformer完全基于注意力机制,解决了这两个问题:
- 完全并行计算,训练速度大幅提升
- 能直接捕捉任意位置的依赖关系
- 更容易训练深层模型
3.1.2 Transformer的整体结构
Transformer主要由两部分组成:编码器(Encoder)和解码器(Decoder)。
graph TD
subgraph Transformer
subgraph 编码器
A[输入嵌入层] --> B[位置编码]
B --> C[编码器层1]
C --> D[编码器层2]
D --> E[...编码器层N]
end
subgraph 解码器
F[输出嵌入层] --> G[位置编码]
G --> H[解码器层1]
H --> I[解码器层2]
I --> J[...解码器层N]
J --> K[线性层]
K --> L[Softmax]
end
E --> H
E --> I
E --> J
end
M[输入序列] --> A
N[输出序列] --> F
L --> O[预测序列]
Transformer的核心特点:
- 完全基于注意力机制,没有RNN/CNN
- 编码器和解码器都由多个相同的层堆叠而成
- 使用位置编码来捕捉序列的顺序信息
- 编码器处理输入序列,解码器生成输出序列
3.1.3 Transformer的核心思想
Transformer的核心思想是自注意力机制(Self-Attention),它让模型能够关注输入序列中不同位置的信息,从而捕捉长距离依赖。
3.2 编码器详解
3.2.1 编码器的整体结构
每个编码器层包含两个子层:
- 多头自注意力层(Multi-Head Self-Attention)
- 前馈神经网络层(Feed Forward Network)
- 每个子层都有残差连接(Residual Connection)和层归一化(Layer Normalization)
graph TD
A[输入] --> B[多头自注意力层]
B --> C[残差连接+层归一化]
C --> D[前馈神经网络]
D --> E[残差连接+层归一化]
E --> F[输出]
3.2.2 输入嵌入与位置编码
- 输入嵌入(Input Embedding)
-
- 将离散的token转换为连续的向量
-
- 嵌入维度通常为d_model(比如512)
-
- 所有token共享同一个嵌入矩阵
- 位置编码(Positional Encoding)
-
- Transformer没有顺序信息,需要显式添加位置信息
-
- 位置编码的维度与嵌入维度相同
-
- 可以使用正弦/余弦函数或可学习的位置编码
正弦位置编码的公式:
PE_{(pos,2i)} = sin(pos / 10000^{2i/d_{model}})
PE_{(pos,2i+1)} = cos(pos / 10000^{2i/d_{model}})
3.2.3 多头自注意力机制
多头自注意力是Transformer的核心,它将自注意力机制分成多个头,每个头学习不同的注意力模式。
import torch
import torch.nn as nn
import torch.nn.functional as F
class MultiHeadAttention(nn.Module):
def __init__(self, d_model, num_heads):
super().__init__()
assert d_model % num_heads == 0, "d_model必须能被num_heads整除"
self.d_model = d_model
self.num_heads = num_heads
self.d_k = d_model // num_heads # 每个头的维度
# 线性变换层
self.w_q = nn.Linear(d_model, d_model)
self.w_k = nn.Linear(d_model, d_model)
self.w_v = nn.Linear(d_model, d_model)
self.w_o = nn.Linear(d_model, d_model)
def scaled_dot_product_attention(self, q, k, v, mask=None):
"""
缩放点积注意力
q: [batch_size, num_heads, seq_len, d_k]
k: [batch_size, num_heads, seq_len, d_k]
v: [batch_size, num_heads, seq_len, d_k]
"""
# 计算注意力分数: Q * K^T / sqrt(d_k)
attn_scores = torch.matmul(q, k.transpose(-2, -1)) / torch.sqrt(torch.tensor(self.d_k, dtype=torch.float32))
# 应用掩码(可选)
if mask is not None:
attn_scores = attn_scores.masked_fill(mask == 0, -1e9)
# Softmax得到注意力权重
attn_weights = F.softmax(attn_scores, dim=-1)
# 加权求和得到输出
output = torch.matmul(attn_weights, v)
return output, attn_weights
def forward(self, q, k, v, mask=None):
batch_size = q.size(0)
# 1. 线性变换
q = self.w_q(q) # [batch_size, seq_len, d_model]
k = self.w_k(k)
v = self.w_v(v)
# 2. 分头: [batch_size, seq_len, d_model] -> [batch_size, num_heads, seq_len, d_k]
q = q.view(batch_size, -1, self.num_heads, self.d_k).transpose(1, 2)
k = k.view(batch_size, -1, self.num_heads, self.d_k).transpose(1, 2)
v = v.view(batch_size, -1, self.num_heads, self.d_k).transpose(1, 2)
# 3. 计算注意力
attn_output, attn_weights = self.scaled_dot_product_attention(q, k, v, mask)
# 4. 拼接头: [batch_size, num_heads, seq_len, d_k] -> [batch_size, seq_len, d_model]
attn_output = attn_output.transpose(1, 2).contiguous().view(batch_size, -1, self.d_model)
# 5. 最终线性变换
output = self.w_o(attn_output)
return output, attn_weights
3.2.4 前馈神经网络
前馈神经网络是一个简单的两层全连接网络:
class PositionwiseFeedForward(nn.Module):
def __init__(self, d_model, d_ff, dropout=0.1):
super().__init__()
self.fc1 = nn.Linear(d_model, d_ff)
self.fc2 = nn.Linear(d_ff, d_model)
self.dropout = nn.Dropout(dropout)
self.relu = nn.ReLU()
def forward(self, x):
# x: [batch_size, seq_len, d_model]
x = self.fc1(x) # [batch_size, seq_len, d_ff]
x = self.relu(x)
x = self.dropout(x)
x = self.fc2(x) # [batch_size, seq_len, d_model]
return x
3.2.5 残差连接与层归一化
残差连接解决了深层网络的梯度消失问题,层归一化加速训练:
class EncoderLayer(nn.Module):
def __init__(self, d_model, num_heads, d_ff, dropout=0.1):
super().__init__()
self.self_attn = MultiHeadAttention(d_model, num_heads)
self.feed_forward = PositionwiseFeedForward(d_model, d_ff, dropout)
# 层归一化
self.norm1 = nn.LayerNorm(d_model)
self.norm2 = nn.LayerNorm(d_model)
self.dropout1 = nn.Dropout(dropout)
self.dropout2 = nn.Dropout(dropout)
def forward(self, x, mask=None):
# 多头自注意力 + 残差连接 + 层归一化
attn_output, _ = self.self_attn(x, x, x, mask)
x = self.norm1(x + self.dropout1(attn_output))
# 前馈网络 + 残差连接 + 层归一化
ff_output = self.feed_forward(x)
x = self.norm2(x + self.dropout2(ff_output))
return x
3.3 解码器详解
3.3.1 解码器的整体结构
每个解码器层包含三个子层:
- 掩码多头自注意力层(Masked Multi-Head Self-Attention)
- 编码器-解码器注意力层(Encoder-Decoder Attention)
- 前馈神经网络层
- 每个子层都有残差连接和层归一化
graph TD
A[输入] --> B[掩码多头自注意力层]
B --> C[残差连接+层归一化]
C --> D[编码器-解码器注意力层]
D --> E[残差连接+层归一化]
E --> F[前馈神经网络]
F --> G[残差连接+层归一化]
G --> H[输出]
3.3.2 掩码多头自注意力
掩码自注意力用于防止模型看到未来的token:
class DecoderLayer(nn.Module):
def __init__(self, d_model, num_heads, d_ff, dropout=0.1):
super().__init__()
self.self_attn = MultiHeadAttention(d_model, num_heads)
self.enc_dec_attn = MultiHeadAttention(d_model, num_heads)
self.feed_forward = PositionwiseFeedForward(d_model, d_ff, dropout)
self.norm1 = nn.LayerNorm(d_model)
self.norm2 = nn.LayerNorm(d_model)
self.norm3 = nn.LayerNorm(d_model)
self.dropout1 = nn.Dropout(dropout)
self.dropout2 = nn.Dropout(dropout)
self.dropout3 = nn.Dropout(dropout)
def forward(self, x, enc_output, src_mask=None, tgt_mask=None):
# 1. 掩码自注意力
attn1_output, _ = self.self_attn(x, x, x, tgt_mask)
x = self.norm1(x + self.dropout1(attn1_output))
# 2. 编码器-解码器注意力
attn2_output, _ = self.enc_dec_attn(x, enc_output, enc_output, src_mask)
x = self.norm2(x + self.dropout2(attn2_output))
# 3. 前馈网络
ff_output = self.feed_forward(x)
x = self.norm3(x + self.dropout3(ff_output))
return x
3.3.3 完整的Transformer实现
class Transformer(nn.Module):
def __init__(self, src_vocab_size, tgt_vocab_size, d_model=512, num_heads=8,
num_layers=6, d_ff=2048, max_seq_len=512, dropout=0.1):
super().__init__()
# 嵌入层
self.src_embedding = nn.Embedding(src_vocab_size, d_model)
self.tgt_embedding = nn.Embedding(tgt_vocab_size, d_model)
# 位置编码
self.positional_encoding = self._generate_positional_encoding(max_seq_len, d_model)
# 编码器和解码器
self.encoder_layers = nn.ModuleList([
EncoderLayer(d_model, num_heads, d_ff, dropout)
for _ in range(num_layers)
])
self.decoder_layers = nn.ModuleList([
DecoderLayer(d_model, num_heads, d_ff, dropout)
for _ in range(num_layers)
])
# 输出层
self.fc = nn.Linear(d_model, tgt_vocab_size)
self.dropout = nn.Dropout(dropout)
def _generate_positional_encoding(self, max_seq_len, d_model):
"""生成正弦位置编码"""
pe = torch.zeros(max_seq_len, d_model)
position = torch.arange(0, max_seq_len, dtype=torch.float).unsqueeze(1)
div_term = torch.exp(torch.arange(0, d_model, 2).float() * (-torch.log(torch.tensor(10000.0)) / d_model))
pe[:, 0::2] = torch.sin(position * div_term)
pe[:, 1::2] = torch.cos(position * div_term)
pe = pe.unsqueeze(0) # [1, max_seq_len, d_model]
return pe
def forward(self, src, tgt, src_mask=None, tgt_mask=None):
# 输入嵌入 + 位置编码
src_emb = self.src_embedding(src) * torch.sqrt(torch.tensor(self.src_embedding.embedding_dim, dtype=torch.float32))
src_emb = src_emb + self.positional_encoding[:, :src.size(1), :]
src_emb = self.dropout(src_emb)
# 目标嵌入 + 位置编码
tgt_emb = self.tgt_embedding(tgt) * torch.sqrt(torch.tensor(self.tgt_embedding.embedding_dim, dtype=torch.float32))
tgt_emb = tgt_emb + self.positional_encoding[:, :tgt.size(1), :]
tgt_emb = self.dropout(tgt_emb)
# 编码器前向传播
enc_output = src_emb
for enc_layer in self.encoder_layers:
enc_output = enc_layer(enc_output, src_mask)
# 解码器前向传播
dec_output = tgt_emb
for dec_layer in self.decoder_layers:
dec_output = dec_layer(dec_output, enc_output, src_mask, tgt_mask)
# 输出层
output = self.fc(dec_output)
return output
3.4 本章总结与回顾
3.4.1 核心知识点总结
- Transformer架构:由编码器和解码器组成,完全基于注意力机制
- 自注意力机制:让模型关注输入序列的不同位置,捕捉长距离依赖
- 多头注意力:多个自注意力头,学习不同的注意力模式
- 位置编码:为Transformer添加顺序信息
- 残差连接和层归一化:解决深层网络训练问题
3.4.2 重要概念回顾
|
概念 |
解释 |
|
自注意力 |
输入序列内部的注意力,每个位置关注所有位置 |
|
多头注意力 |
将自注意力分成多个头,学习不同的注意力模式 |
|
位置编码 |
为Transformer添加顺序信息 |
|
残差连接 |
x = x + f(x),解决梯度消失问题 |
|
层归一化 |
对每个样本的特征维度归一化,加速训练 |
|
掩码注意力 |
防止解码器看到未来的token |
4. 进阶篇:注意力机制深度解析
4.1 注意力机制的基本思想
4.1.1 什么是注意力?
注意力机制的核心思想来源于人类的注意力:当我们看一张图片或读一段话时,会重点关注其中的某些部分,而不是平均关注所有部分。
在深度学习中,注意力机制让模型能够动态地关注输入的不同部分,根据重要性分配不同的权重。
4.1.2 注意力机制的类比
想象你在做阅读理解:
- 问题:"小明去超市买了什么?"
- 文章:"小明今天下午去超市买了苹果、香蕉和牛奶,然后去公园玩了。"
- 你的注意力会集中在"买了苹果、香蕉和牛奶"这部分,而忽略其他部分
注意力机制做的就是类似的事情:根据当前任务,计算输入各部分的重要性权重。
4.1.3 注意力机制的发展历程
- 软注意力(Soft Attention):最早的注意力机制,权重是连续的
- 硬注意力(Hard Attention):选择输入的一部分,权重是离散的
- 自注意力(Self-Attention):输入序列内部的注意力
- 多头注意力(Multi-Head Attention):多个注意力头,捕捉不同模式
4.2 自注意力机制
4.2.1 Query、Key、Value
自注意力机制基于三个向量:
- Query(查询):当前位置的表示,用于查询相关信息
- Key(键):所有位置的表示,用于匹配Query
- Value(值):所有位置的表示,用于生成输出
类比字典查询:
- Query:你要查的单词
- Key:字典中的所有单词
- Value:字典中的解释
4.2.2 注意力分数计算
注意力分数衡量Query和Key的匹配程度,常见的计算方式:
- 点积注意力(Dot-Product Attention)
-
- 公式: score(q, k) = q \cdot k
-
- 简单高效,但对向量长度敏感
- 缩放点积注意力(Scaled Dot-Product Attention)
-
- 公式: score(q, k) = \frac{q \cdot k}{\sqrt{d_k}}
-
- Transformer使用的方式,解决维度大时分数过大的问题
- 加性注意力(Additive Attention)
-
- 公式: score(q, k) = v^T tanh(W_q q + W_k k)
-
- 适合Query和Key维度不同的情况
4.2.3 缩放点积注意力的完整流程
graph TD
A[Query] --> B[计算Q·K^T]
C[Key] --> B
B --> D[除以√d_k]
D --> E[Softmax归一化]
E --> F[注意力权重]
G[Value] --> H[加权求和]
F --> H
H --> I[输出]
数学流程:
- 计算Query和所有Key的点积: QK^T
- 缩放:除以 \sqrt{d_k}
- Softmax归一化,得到注意力权重
- 权重与Value加权求和,得到输出
4.2.4 自注意力的代码实现
import torch
import torch.nn.functional as F
def scaled_dot_product_attention(q, k, v, mask=None):
"""
缩放点积注意力的纯PyTorch实现
q: [batch_size, seq_len_q, d_k]
k: [batch_size, seq_len_k, d_k]
v: [batch_size, seq_len_v, d_v] (seq_len_k == seq_len_v)
mask: [batch_size, seq_len_q, seq_len_k] 或 None
"""
d_k = q.size(-1)
# 1. 计算Q·K^T
attn_scores = torch.matmul(q, k.transpose(-2, -1)) # [batch_size, seq_len_q, seq_len_k]
# 2. 缩放
attn_scores = attn_scores / torch.sqrt(torch.tensor(d_k, dtype=torch.float32))
# 3. 应用掩码
if mask is not None:
attn_scores = attn_scores.masked_fill(mask == 0, -1e9)
# 4. Softmax得到注意力权重
attn_weights = F.softmax(attn_scores, dim=-1) # [batch_size, seq_len_q, seq_len_k]
# 5. 加权求和
output = torch.matmul(attn_weights, v) # [batch_size, seq_len_q, d_v]
return output, attn_weights
# 测试
if __name__ == "__main__":
# 随机生成Q, K, V
batch_size = 2
seq_len = 4
d_k = 8
q = torch.randn(batch_size, seq_len, d_k)
k = torch.randn(batch_size, seq_len, d_k)
v = torch.randn(batch_size, seq_len, d_k)
# 计算注意力
output, attn_weights = scaled_dot_product_attention(q, k, v)
print("输入形状:", q.shape)
print("输出形状:", output.shape)
print("注意力权重形状:", attn_weights.shape)
print("\n注意力权重示例:")
print(attn_weights[0]) # 第一个样本的注意力权重
4.3 多头注意力机制
4.3.1 为什么需要多头?
单头注意力只能学习一种注意力模式,而多头注意力:
- 可以学习不同的注意力模式(比如语法注意力、语义注意力)
- 每个头关注输入的不同部分
- 提升模型的表达能力
4.3.2 多头注意力的计算流程
graph TD
A[Q, K, V] --> B[线性变换到多个子空间]
B --> C[头1: 自注意力]
B --> D[头2: 自注意力]
B --> E[头n: 自注意力]
C --> F[拼接所有头的输出]
D --> F
E --> F
F --> G[最终线性变换]
G --> H[输出]
4.3.3 多头注意力的代码实现
class MultiHeadAttention(nn.Module):
def __init__(self, d_model, num_heads):
super().__init__()
assert d_model % num_heads == 0, "d_model必须能被num_heads整除"
self.d_model = d_model
self.num_heads = num_heads
self.d_k = d_model // num_heads
# 线性变换层
self.w_q = nn.Linear(d_model, d_model)
self.w_k = nn.Linear(d_model, d_model)
self.w_v = nn.Linear(d_model, d_model)
self.w_o = nn.Linear(d_model, d_model)
def split_heads(self, x, batch_size):
"""
将输入分成多个头
x: [batch_size, seq_len, d_model]
返回: [batch_size, num_heads, seq_len, d_k]
"""
x = x.view(batch_size, -1, self.num_heads, self.d_k)
return x.transpose(1, 2) # 交换头和序列长度维度
def forward(self, q, k, v, mask=None):
batch_size = q.size(0)
# 1. 线性变换
q = self.w_q(q) # [batch_size, seq_len, d_model]
k = self.w_k(k)
v = self.w_v(v)
# 2. 分头
q = self.split_heads(q, batch_size) # [batch_size, num_heads, seq_len, d_k]
k = self.split_heads(k, batch_size)
v = self.split_heads(v, batch_size)
# 3. 计算缩放点积注意力
attn_output, attn_weights = scaled_dot_product_attention(q, k, v, mask)
# 4. 拼接头
attn_output = attn_output.transpose(1, 2).contiguous() # [batch_size, seq_len, num_heads, d_k]
attn_output = attn_output.view(batch_size, -1, self.d_model) # [batch_size, seq_len, d_model]
# 5. 最终线性变换
output = self.w_o(attn_output)
return output, attn_weights
# 测试
if __name__ == "__main__":
# 参数设置
batch_size = 2
seq_len = 4
d_model = 16
num_heads = 4
# 创建多头注意力
mha = MultiHeadAttention(d_model, num_heads)
# 随机输入
x = torch.randn(batch_size, seq_len, d_model)
# 前向传播
output, attn_weights = mha(x, x, x)
print("输入形状:", x.shape)
print("输出形状:", output.shape)
print("注意力权重形状:", attn_weights.shape)
print(f"每个头的维度: {d_model // num_heads}")
4.4 注意力可视化
4.4.1 注意力权重的可视化
注意力权重可以可视化,帮助我们理解模型关注了哪些部分:
import matplotlib.pyplot as plt
import seaborn as sns
def visualize_attention(attn_weights, tokens):
"""
可视化注意力权重
attn_weights: [seq_len_q, seq_len_k]
tokens: 对应的token列表
"""
plt.figure(figsize=(10, 8))
sns.heatmap(attn_weights,
annot=True,
fmt='.2f',
cmap='Blues',
xticklabels=tokens,
yticklabels=tokens)
plt.xlabel('Key')
plt.ylabel('Query')
plt.title('Attention Weights')
plt.show()
# 测试可视化
if __name__ == "__main__":
# 示例:句子的注意力可视化
tokens = ["我", "爱", "学习", "大模型"]
seq_len = len(tokens)
# 模拟注意力权重
attn_weights = torch.randn(seq_len, seq_len)
attn_weights = F.softmax(attn_weights, dim=-1)
# 可视化
visualize_attention(attn_weights.numpy(), tokens)
4.4.2 注意力模式分析
常见的注意力模式:
- 位置注意力:关注相邻位置
- 语法注意力:关注语法相关的词(比如主语和谓语)
- 语义注意力:关注语义相关的词(比如同义词、上下位词)
- 长距离注意力:关注远距离的依赖关系
4.5 注意力变体
4.5.1 相对位置注意力
在自注意力中加入相对位置信息,更好地捕捉顺序关系。
4.5.2 稀疏注意力
为了处理超长序列,只计算部分位置的注意力,减少计算量。
4.5.3 线性注意力
将注意力计算复杂度从 O(n^2) 降低到 O(n) ,适合超长序列。
4.6 本章总结与回顾
4.6.1 核心知识点总结
- 注意力机制:让模型动态关注输入的不同部分
- 自注意力:输入序列内部的注意力,Query=Key=Value
- 多头注意力:多个注意力头,学习不同的注意力模式
- 注意力可视化:帮助理解模型的关注模式
4.6.2 重要概念回顾
|
概念 |
解释 |
|
Query |
查询向量,当前位置的表示 |
|
Key |
键向量,所有位置的表示,用于匹配Query |
|
Value |
值向量,所有位置的表示,用于生成输出 |
|
缩放点积注意力 |
Transformer使用的注意力计算方式 |
|
多头注意力 |
多个注意力头,提升表达能力 |
|
注意力权重 |
输入各部分的重要性分数 |
5. 训练篇:大模型预训练与微调
5.1 数据准备
5.1.1 数据来源
大模型的训练数据来源广泛,主要包括:
- 公开网页数据:Common Crawl、Wikipedia、BooksCorpus
- 书籍数据:各种类型的书籍、文献
- 代码数据:GitHub、Stack Overflow
- 对话数据:聊天记录、问答数据
- 专业数据:法律、医疗、金融等领域的数据
5.1.2 数据清洗
数据质量直接影响模型效果,数据清洗的主要步骤:
- 去重:去除重复的文本
- 过滤低质量内容:去除垃圾文本、无意义内容
- 语言过滤:只保留目标语言的文本
- 格式标准化:统一编码、换行符等
- 敏感信息处理:去除个人信息、隐私数据
5.1.3 数据预处理
- 分词(Tokenization)
-
- 将文本切分成token(词、子词、字符)
-
- 常用分词器:BPE、WordPiece、SentencePiece
-
- 示例:"我爱学习大模型" → ["我", "爱", "学习", "大", "模型"]
- 构建词汇表(Vocabulary)
-
- 收集所有token,构建词汇表
-
- 词汇表大小通常为几万个到几十万个
-
- 为未知token(UNK)、填充(PAD)、开始(BOS)、结束(EOS)预留位置
- 编码(Encoding)
-
- 将token转换为数字索引
-
- 示例:["我", "爱", "学习"] → [100, 200, 300]
代码示例:使用Hugging Face进行分词
from transformers import AutoTokenizer
# 加载预训练分词器
tokenizer = AutoTokenizer.from_pretrained("bert-base-chinese")
# 分词示例
text = "我爱学习大模型"
tokens = tokenizer.tokenize(text)
print("分词结果:", tokens) # ['我', '爱', '学', '习', '大', '模', '型']
# 编码
encoding = tokenizer.encode_plus(
text,
add_special_tokens=True, # 添加CLS和SEP
max_length=10,
padding='max_length',
truncation=True,
return_tensors='pt'
)
print("输入ID:", encoding['input_ids'])
print("注意力掩码:", encoding['attention_mask'])
5.2 预训练任务
5.2.1 语言建模
预训练的核心是语言建模,即让模型学习语言的规律。
- 因果语言建模(CLM)
-
- 目标:根据前文预测下一个token
-
- 方式:只使用前文的信息(单向)
-
- 代表模型:GPT系列
-
- 适合生成任务
- 掩码语言建模(MLM)
-
- 目标:预测被掩码的token
-
- 方式:使用上下文信息(双向)
-
- 代表模型:BERT
-
- 适合理解任务
5.2.2 预训练流程
graph TD
A[原始文本] --> B[数据清洗]
B --> C[分词]
C --> D[构建训练样本]
D --> E[预训练任务]
E --> F[计算损失]
F --> G[反向传播]
G --> H[更新参数]
H --> E
5.2.3 预训练的挑战
- 计算资源:需要大量GPU/TPU
- 内存限制:长序列需要大量内存
- 训练稳定性:深层模型容易不稳定
- 收敛速度:大模型训练时间长
5.3 微调技术
5.3.1 什么是微调?
微调(Fine-tuning)是指在预训练模型的基础上,使用下游任务的数据继续训练,让模型适应特定任务。
5.3.2 全量微调
全量微调(Full Fine-tuning)是更新模型的所有参数:
import torch
import torch.nn as nn
from transformers import AutoModelForSequenceClassification, AutoTokenizer, AdamW
# 加载预训练模型和分词器
model_name = "bert-base-chinese"
model = AutoModelForSequenceClassification.from_pretrained(model_name, num_labels=2)
tokenizer = AutoTokenizer.from_pretrained(model_name)
# 示例数据
texts = ["这是一篇正面的评论", "这是一篇负面的评论"]
labels = torch.tensor([1, 0])
# 编码
encodings = tokenizer(texts, return_tensors='pt', padding=True, truncation=True)
# 优化器
optimizer = AdamW(model.parameters(), lr=5e-5)
# 训练
model.train()
for epoch in range(3):
# 前向传播
outputs = model(**encodings, labels=labels)
loss = outputs.loss
# 反向传播
optimizer.zero_grad()
loss.backward()
optimizer.step()
print(f"Epoch {epoch+1}, Loss: {loss.item():.4f}")
# 保存微调后的模型
model.save_pretrained("fine-tuned-bert")
tokenizer.save_pretrained("fine-tuned-bert")
5.3.3 参数高效微调(PEFT)
全量微调需要大量计算资源,参数高效微调只更新部分参数:
- LoRA(Low-Rank Adaptation)
-
- 在注意力层插入低秩矩阵
-
- 只训练低秩矩阵,冻结其他参数
-
- 参数量只有全量微调的1%左右
- QLoRA
-
- 量化版本的LoRA
-
- 将模型量化到4位,进一步降低显存占用
- Adapter
-
- 在Transformer层中插入小型网络
-
- 只训练Adapter,冻结主模型
代码示例:使用LoRA进行微调
from peft import LoraConfig, get_peft_model
from transformers import AutoModelForCausalLM, AutoTokenizer, TrainingArguments, Trainer
# 加载模型和分词器
model_name = "baichuan-7B"
model = AutoModelForCausalLM.from_pretrained(model_name)
tokenizer =
(注:文档部分内容可能由 AI 生成)
更多推荐

所有评论(0)