前两周系统学习笔记
说明
本笔记覆盖 Python 核心语法 + 大模型工作原理,按「基础→进阶」分周编排,包含核心知识点、代码示例、注意事项、实操任务、进阶提示,适配新手系统学习与即时自测。
第一周:基础认知与核心入门
本周学习目标
- 掌握 Python 基础语法,能编写简单的条件判断、循环程序
- 理解大模型的核心基础概念(Token、上下文窗口、分词)
- 能独立处理简单的 Python 语法错误(如除数为0、类型错误、缩进错误)
- 熟练使用交互式环境(IDLE 或 Jupyter Notebook)进行代码调试
模块1:Python 核心语法 - 基础篇
1.1 变量与数据类型
变量规则
| 维度 | 核心内容 | 注意事项 |
|---|---|---|
| 变量命名 | 1. 命名:字母/数字/下划线,不能以数字开头 2. 无需声明类型,赋值即定义 3. 支持多变量赋值: a, b = 10, 204. 支持链式赋值: x = y = z = 0 | 1. 变量名区分大小写(Age ≠ age)2. 避免使用关键字(如 if/for/class)作为变量名3. 变量名应具有描述性,遵循PEP 8命名规范(小写字母+下划线) |
代码示例:
# 合法命名
name = "Alice"
age_18 = True
# 多变量赋值
x, y, z = 1, 2.5, "hello"
# 链式赋值
a = b = c = 100
# 查看类型
print(type(age_18)) # <class 'bool'>
核心数据类型
| 维度 | 核心内容 | 注意事项 |
|---|---|---|
| 不可变类型 | - int(整数):5 100 0b1010(二进制)- float(浮点数): 3.14 2.0 1e-3- str(字符串): "python" 'AI' """多行"""- bool(布尔): True False- tuple(元组): (1, 2, 3)- NoneType: None | 1. 元组即使只有一个元素,也需加逗号:(5,)2. 浮点数存在精度问题(如 0.1+0.2 不等于 0.3),可使用 decimal.Decimal 处理精确计算 |
| 可变类型 | - list(列表):[1, 2, 3]- dict(字典): {"name": "Bob", "age": 20}- set(集合): {1, 2, 3}- bytearray(字节数组) | 字典的键必须是不可变类型(如字符串/数字/元组) |
代码示例:
# 不可变类型:修改会报错
tup = (1, 2)
# tup[0] = 10 # 报错:TypeError
# 可变类型:可修改
lst = [1, 2]
lst[0] = 10 # 合法,lst变为 [10, 2]
# 字符串不可变
s = "hello"
# s[0] = 'H' # 报错
s = "Hello" # 重新赋值,新字符串对象
类型转换
| 维度 | 核心内容 | 注意事项 |
|---|---|---|
| 常用转换 | 常用函数:int()/float()/str()/bool()/list()/tuple()/set()/dict()转换规则:仅合法格式可转(如 "10" 可转 int,"abc" 不可)进制转换: int("1010", 2) 二进制转十进制 | 1. 空字符串/0/None/空容器转 bool 为 False,非空/非0 为 True2. 浮点转 int 会直接截断小数部分(不是四舍五入) 3. 字典转 list 得到键列表 |
代码示例:
# 合法转换
num1 = int("100") # 100
num2 = float(5) # 5.0
num3 = int("1a", 16) # 26 (十六进制转十进制)
# 异常处理(避免转换报错)
try:
num4 = int("abc")
except ValueError:
print("输入不是合法数字")
# bool转换规则
print(bool("")) # False
print(bool("abc")) # True
print(bool(0)) # False
print(bool(1)) # True
实操任务
- 定义三个变量:
name(姓名)、age(年龄)、height(身高),使用合适的数据类型并打印它们的类型。 - 尝试将一个包含数字的字符串(如
"123")分别转换为整数、浮点数、布尔值,观察结果。 - 创建一个元组
t = (1, 2, 3),尝试修改元组中的元素,观察错误信息并理解不可变类型。 - 计算
0.1 + 0.2并比较是否等于0.3,若不等,思考如何解决。
进阶提示
- Python 中所有数据都是对象,变量名是对象的引用。可以使用
id()函数查看对象的内存地址,理解赋值操作的本质。 - 了解 Python 的“小整数缓存”机制(-5 到 256 的整数被重用)。
1.2 运算符与流程控制
常用运算符
| 类别 | 核心内容 | 注意事项 | |
|---|---|---|---|
| 算术运算符 | + - * /(除法)//(整除)%(取余)**(幂) | 整除 // 是向下取整(对于负数需注意) | |
| 比较运算符 | == != > < >= <= | 比较返回布尔值 | |
| 逻辑运算符 | and(与)or(或)not(非) | 支持短路运算 | |
| 赋值运算符 | = += -= *= /= //= %= **= | 复合赋值 | |
| 位运算符 | & ` | ^ ~ << >>` | 用于整数二进制位操作 |
| 成员运算符 | in not in | 判断元素是否在容器中 | |
| 身份运算符 | is is not | 判断两个对象是否为同一对象(内存地址) |
代码示例:
# 算术运算
print(10 // 3) # 3(整除,向下取整)
print(10 % 3) # 1(取余)
print(2 ** 3) # 8(幂运算)
# 逻辑运算
print(3>2 and 5<4) # False
print(not True) # False
# 赋值运算
a = 5
a += 3 # a = a + 3
print(a) # 8
# 位运算
print(5 & 3) # 1 (0101 & 0011 = 0001)
print(5 << 1) # 10 (左移一位相当于乘以2)
# 成员运算
lst = [1,2,3]
print(2 in lst) # True
# 身份运算
x = [1,2]
y = [1,2]
print(x is y) # False (不同对象)
print(x == y) # True (值相等)
条件判断
| 维度 | 核心内容 | 注意事项 |
|---|---|---|
| if-elif-else | 语法:if-elif-else,缩进(4个空格)是语法核心支持多条件嵌套 | Python 3.10+ 支持 match-case 模式匹配 |
| match-case | 类似其他语言的switch,但功能更强 | 需Python 3.10+ |
代码示例:
score = 85
if score >= 90:
print("优秀")
elif 80 <= score < 90:
print("良好")
else:
print("继续努力")
# 嵌套条件
age = 18
if age >= 18:
if age <= 25:
print("青年")
else:
print("成年")
# match-case (Python 3.10+)
command = "start"
match command:
case "start":
print("开始")
case "stop":
print("停止")
case _:
print("未知命令")
循环结构
| 维度 | 核心内容 | 注意事项 |
|---|---|---|
| for循环 | 遍历可迭代对象(列表/字符串/range/字典等)range(start, end, step):生成整数序列(左闭右开) | 遍历字典时默认遍历键,需用.items()获取键值对 |
| while循环 | 条件为True时执行,需避免死循环 | 注意更新循环变量 |
| break/continue | break(终止循环)、continue(跳过当前轮) | 可配合else子句 |
| for-else | 循环正常结束(未被break中断)时执行else | 常用于搜索场景 |
代码示例:
# for循环:遍历1-5
for i in range(1, 6):
print(i)
# while循环:累加1-100
sum_num = 0
i = 1
while i <= 100:
sum_num += i
i += 1
print(sum_num) # 5050
# break/continue
for i in range(5):
if i == 2:
continue # 跳过i=2
if i == 4:
break # 终止循环
print(i) # 输出:0 1 3
# for-else
for n in range(2, 10):
for x in range(2, n):
if n % x == 0:
print(n, '等于', x, '*', n//x)
break
else:
# 循环中没有找到因数
print(n, '是质数')
异常处理
| 维度 | 核心内容 | 注意事项 |
|---|---|---|
| try-except | 语法:try-except[异常类型]-else-finally作用:捕获报错,避免程序崩溃 可以捕获多个异常类型 可以使用 as e 获取异常对象 | 1. 可捕获多类异常(如 ValueError/TypeError)2. 避免滥用 except:(不指定异常类型)3. 可以使用 except Exception as e 捕获大多数异常 |
| raise | 手动抛出异常 | 可自定义异常类 |
代码示例:
# 捕获除数为0异常
try:
a = 10 / 0
except ZeroDivisionError as e:
print(f"错误:{e}") # 错误:division by zero
else:
print("计算成功") # 无异常时执行
finally:
print("无论是否报错都执行")
# 捕获多个异常
try:
num = int("abc")
except (ValueError, TypeError) as e:
print("输入类型错误:", e)
# 手动抛出异常
def divide(a, b):
if b == 0:
raise ValueError("除数不能为0")
return a / b
实操小任务
- 计算:
(10 + 5) * 2 - 8 // 2,验证结果是否为26。 - 编写程序:输入一个数,判断是否为正数且是偶数。
- 输入一个年份,判断是否为闰年(能被4整除但不能被100整除,或者能被400整除)。
- 编写程序:用循环计算10的阶乘(10! = 1×2×…×10)。
- 打印九九乘法表。
- 使用 while 循环实现猜数字游戏(随机生成1-100,用户输入猜测,提示“猜大了/猜小了”,直到猜中)。
- 编写一个程序,接收用户输入的两个数字,进行除法运算,处理可能出现的除零错误和值错误(输入非数字)。
- 使用 while 循环实现:不断要求用户输入密码,直到输入正确密码(假设正确密码为 "python123")为止,并限制最多尝试3次。
进阶提示
- 了解 Python 的短路运算:
and和or会返回最后一个计算的值,而不仅仅是布尔值。例如3 and 5返回5。 - 学习使用
enumerate同时获取索引和值:for i, val in enumerate(lst): - 了解
pass语句作为占位符。
1.3 大模型工作原理 - 基础篇
| 核心概念 | 通俗解释 | 关键注意点 |
|---|---|---|
| Token(令牌) | 大模型处理文本的最小单位,不是单纯的“字/词”,而是「子词/字符」的组合。所有文本需先转为 Token 才能被模型处理。分词算法常见的有 BPE、WordPiece、SentencePiece 等。 | 1. 不同语言和模型的分词规则不同,导致 Token 数量与文字数量无直接对应。 2. 模型的“最大 Token 限制”指的是输入+输出的总 Token 数,不是字数。 3. 中文一个汉字通常是一个 Token,但英文一个单词可能拆成多个 Token。 |
| 上下文窗口 | 模型能“记住并参考”的「输入+输出」Token 总数上限(如 GPT-3.5 是 4096 Token,GPT-4 支持 128k)。上下文窗口决定了一次性能处理多长的内容。 | 1. 窗口过小的问题:无法处理长文档、多轮对话记忆丢失。 2. 实际使用中需注意 Token 计数,可通过分词器估算 Token 数量。 |
| 大模型核心定位 | 基于深度学习的“语言模型”,核心能力是「理解自然语言」+「生成自然语言」,而非“真正思考”。它通过预训练学习到统计规律,能根据上下文预测下一个 Token。 | 1. 大模型的“知识”来自预训练数据,截止到训练截止时间(无实时学习能力)。 2. 模型可能产生“幻觉”(hallucination),生成看似合理但不符合事实的内容。 |
| 分词器(Tokenizer) | 将原始文本转换为 Token ID 序列的工具,同时也能将 ID 序列转回文本。分词器包含词表和合并规则。 | 不同的模型使用不同的分词器,不能混用。例如 GPT 使用的 BPE 和 BERT 使用的 WordPiece 不同。 |
代码示例(使用 tiktoken 估算 Token 数):
import tiktoken
# 加载 GPT-4 的分词器
enc = tiktoken.encoding_for_model("gpt-4")
text = "Hello, world! 你好,世界!"
tokens = enc.encode(text)
print(f"Token 数量: {len(tokens)}")
print(f"Token IDs: {tokens}")
print(f"解码回文本: {enc.decode(tokens)}")
实操任务
- 使用在线 Token 计数器(如 OpenAI 的 Tokenizer 工具)或 Python 的
tiktoken库,计算一段中文和英文文本的 Token 数量,对比字数与 Token 数的差异。 - 假设一个模型的上下文窗口为 4096 Token,你有一段 6000 Token 的文档需要总结,请设计一个处理方案(如分段、摘要、RAG)。
- 思考为什么大模型需要分词器?如果直接按字符处理会有什么问题?
进阶提示
- 深入了解 BPE 算法的工作原理:如何从字符开始逐步合并高频对,构建子词词表。
- 学习不同模型的分词器差异:如 LLaMA 使用 SentencePiece,GPT 使用 BPE,BERT 使用 WordPiece。
- 了解“Token 经济”:API 按 Token 计费,如何优化提示词减少 Token 消耗。
第一周自测题(简易版)
1. Python 部分
- 写出代码:输入两个数,计算除法,若除数为0则提示“除数不能为0”。
- 用循环打印 10 以内的所有奇数(使用 for 和 while 两种方式)。
- 定义一个变量
s = "Python",尝试修改第一个字符为 'p',观察错误并解释原因。 - 编写程序,接收用户输入的一个整数,判断它是否是质数。
2. 大模型部分
- 简述 Token 对大模型的作用,为什么不能直接按字符处理?
- 上下文窗口大小为 2000 Token 的模型,处理 3000 字的中文文本会有什么问题?可以如何解决?
- 什么是“幻觉”?举例说明大模型可能产生的幻觉现象。
第二周:进阶应用与原理深挖
本周学习目标
- 掌握 Python 列表推导式、函数高级特性、面向对象编程基础
- 理解 Transformer 架构、自注意力机制的核心作用,以及位置编码的意义
- 能解释大模型“预训练+微调”流程和文本生成逻辑,了解常见生成策略
- 能够分析大模型的过拟合、欠拟合、幻觉等问题及其解决方法
模块1:Python 核心语法 - 进阶篇
2.1 列表推导式(高效处理列表)
基础用法
| 维度 | 核心内容 | 注意事项 |
|---|---|---|
| 列表推导式 | [表达式 for 变量 in 可迭代对象 if 条件]替代“循环+判断”,代码更简洁 | 1. 避免过度嵌套(超过两层)影响可读性 2. 复杂逻辑建议用普通循环 3. 列表推导式生成新列表,内存占用较大;大数据集考虑生成器表达式 |
| 其他推导式 | 字典推导式:{key_expr: value_expr for item in iterable if condition}集合推导式: {expression for item in iterable if condition}生成器表达式: (expression for item in iterable if condition) | 生成器表达式惰性计算,适合大数据流 |
代码示例:
# 过滤偶数并乘以2
lst = [1,2,3,4,5]
new_lst = [x*2 for x in lst if x%2==0]
print(new_lst) # [4, 8]
# 生成1-10的平方列表
square_lst = [x**2 for x in range(1,11)]
print(square_lst) # [1,4,...,100]
# 嵌套列表推导式:二维列表扁平化
matrix = [[1,2], [3,4]]
flat_lst = [x for row in matrix for x in row]
print(flat_lst) # [1,2,3,4]
# 生成九九乘法表(二维)
multi = [f"{i}×{j}={i*j}" for i in range(1,10) for j in range(1,10) if i<=j]
# 带条件的复杂表达式:对奇数平方,偶数保留原值
mixed = [x**2 if x%2 else x for x in range(1,6)]
print(mixed) # [1, 2, 9, 4, 25]
# 字典推导式
names = ['Alice', 'Bob', 'Charlie']
name_len = {name: len(name) for name in names}
print(name_len) # {'Alice': 5, 'Bob': 3, 'Charlie': 7}
# 集合推导式
words = ['apple', 'banana', 'avocado']
first_letters = {word[0] for word in words}
print(first_letters) # {'a', 'b'}
# 生成器表达式
gen = (x**2 for x in range(1000000))
print(next(gen)) # 0
print(next(gen)) # 1
实操任务
- 使用列表推导式生成 1 到 50 之间所有能被 3 整除的数的平方。
- 给定一个字符串列表
words = ['hello', 'world', 'python', 'ai'],使用列表推导式生成每个单词的大写形式,并过滤掉长度小于 5 的单词。 - 使用字典推导式,将列表
[1,2,3,4]转换为字典,键为数字,值为数字的立方。 - 使用生成器表达式计算前 100 个自然数的平方和,并与列表推导式比较内存占用(可以使用
sys.getsizeof()粗略比较)。
进阶提示
- 了解“海象运算符”
:=在列表推导式中的用法(Python 3.8+),可以在条件中重复使用计算结果。 - 列表推导式的执行顺序:从外到内,先循环后条件。
2.2 函数(代码复用核心)
函数定义与调用
| 维度 | 核心内容 | 注意事项 |
|---|---|---|
| 定义 | def 函数名(参数): 函数体,return 返回值 | 函数内定义的变量是“局部变量”,外部无法访问 |
| 文档字符串 | """函数说明""" | 可通过 函数名.__doc__ 查看 |
代码示例:
# 定义求和函数
def add(a, b):
"""计算两数之和(函数文档字符串)"""
return a + b
# 调用函数
result = add(5, 3)
print(result) # 8
# 查看函数说明
print(add.__doc__) # 计算两数之和(函数文档字符串)
参数规则
| 维度 | 核心内容 | 注意事项 |
|---|---|---|
| 默认参数 | def func(a, b=10): 默认参数需放在非默认参数后 | 默认参数尽量不用可变类型(如列表) |
| 关键字参数 | 调用时指定参数名,顺序不限 | 提高可读性 |
| 可变参数 | *args(可变位置参数,接收元组)**kwargs(可变关键字参数,接收字典) | 参数名可自定义,但习惯用 args 和 kwargs |
| 仅限关键字参数 | * 后面的参数必须用关键字传递 | Python 3 引入 |
代码示例:
# 默认参数
def say_hello(name, msg="你好"):
print(f"{msg},{name}")
say_hello("张三") # 你好,张三
say_hello("李四", msg="下午好") # 下午好,李四
# 可变参数
def calc_sum(*args):
return sum(args)
print(calc_sum(1,2,3)) # 6
# 可变关键字参数
def print_info(**kwargs):
for key, value in kwargs.items():
print(f"{key}: {value}")
print_info(name="Alice", age=25) # name: Alice age: 25
# 仅限关键字参数
def greet(name, *, greeting="Hello"):
print(f"{greeting}, {name}")
greet("Bob", greeting="Hi") # Hi, Bob
# greet("Bob", "Hi") # 报错,greeting必须用关键字
作用域
| 维度 | 核心内容 | 注意事项 |
|---|---|---|
| LEGB规则 | Local → Enclosing → Global → Built-in | 查找变量顺序 |
| global | 声明全局变量 | 尽量避免在函数内部修改全局变量 |
| nonlocal | 声明外层变量(用于嵌套函数) | 修改外层非全局变量 |
代码示例:
x = 10 # 全局变量
def outer():
y = 20 # outer 的局部变量
def inner():
nonlocal y # 引用 outer 的 y
y += 5
global x # 引用全局 x
x += 1
print(x, y)
inner()
outer() # 11 25
print(x) # 11
匿名函数(lambda)
| 维度 | 核心内容 | 注意事项 |
|---|---|---|
| lambda | lambda 参数: 表达式 | 只能包含一个表达式,不能包含语句或复杂逻辑 |
代码示例:
# 定义lambda
square = lambda x: x**2
print(square(5)) # 25
# 结合sorted按值排序字典
students = [{'name': 'Alice', 'score': 85}, {'name': 'Bob', 'score': 72}]
sorted_students = sorted(students, key=lambda s: s['score'])
print(sorted_students) # [{'name': 'Bob', 'score': 72}, {'name': 'Alice', 'score': 85}]
# 结合map
nums = [1,2,3,4]
squared = list(map(lambda x: x**2, nums))
print(squared) # [1,4,9,16]
递归函数
| 维度 | 核心内容 | 注意事项 |
|---|---|---|
| 递归 | 函数调用自身,必须包含终止条件(基线条件) | Python 默认递归深度限制约1000,可调整但不建议 |
代码示例:
# 阶乘递归
def factorial(n):
if n == 1:
return 1
else:
return n * factorial(n-1)
print(factorial(5)) # 120
# 斐波那契数列
def fib(n):
if n <= 1:
return n
else:
return fib(n-1) + fib(n-2)
实操任务
- 编写一个函数
is_palindrome(s),判断字符串是否为回文(忽略大小写和空格)。 - 编写一个函数
calculate,接受任意数量的数值,返回它们的和、平均值、最大值、最小值(使用可变参数)。 - 实现一个装饰器(进阶),但可以先不用。尝试编写一个函数,使用默认参数时注意可变对象的陷阱(例如默认参数为列表),并演示问题。
- 使用 lambda 和
filter过滤出列表中所有偶数,并与列表推导式比较。
进阶提示
- 学习“装饰器”(decorator):用于在不修改函数代码的情况下增强函数功能(如计时、日志)。
- 了解“偏函数”(functools.partial)固定部分参数。
- 学习“生成器函数”(yield)实现惰性计算。
2.3 面向对象(类与对象)
类的定义与实例化
| 维度 | 核心内容 | 注意事项 |
|---|---|---|
| 类定义 | class 类名: 定义类 | 类属性所有实例共享,实例属性每个实例独有 |
__init__ | 构造方法,初始化实例属性 | 不是构造函数,对象创建后自动调用 |
| self | 代表实例本身,必须作为第一个参数 | 通过 self 访问实例属性和方法 |
代码示例:
class Student:
# 类属性(所有实例共享)
school = "第一中学"
# 构造方法:初始化实例属性
def __init__(self, name, age, score):
self.name = name # 实例属性
self.age = age
self.score = score
# 实例方法:计算平均分
def get_avg_score(self):
if not self.score:
return 0.0
return sum(self.score)/len(self.score)
# 实例方法:获取信息
def get_info(self):
avg = self.get_avg_score()
return f"姓名:{self.name},学校:{self.school},平均分:{avg}"
# 实例化对象
stu1 = Student("李四", 20, [75,88,92])
# 访问属性/调用方法
print(stu1.school) # 第一中学
print(stu1.get_info()) # 姓名:李四,学校:第一中学,平均分:85.0
类的继承
| 维度 | 核心内容 | 注意事项 |
|---|---|---|
| 继承 | 子类继承父类的属性和方法,可重写父类方法 | 使用 super() 调用父类方法 |
| 多继承 | 支持多继承,但应谨慎使用 | 方法解析顺序(MRO)使用 类名.__mro__ 查看 |
代码示例:
# 子类:继承Student类
class CollegeStudent(Student):
# 重写构造方法
def __init__(self, name, age, score, major):
# 调用父类构造方法
super().__init__(name, age, score)
self.major = major # 新增属性
# 重写方法
def get_info(self):
avg = self.get_avg_score()
return f"姓名:{self.name},专业:{self.major},平均分:{avg}"
# 新增方法
def study(self):
print(f"{self.name} 正在学习 {self.major}")
# 实例化子类
stu2 = CollegeStudent("王五", 22, [80,85], "计算机")
print(stu2.get_info()) # 姓名:王五,专业:计算机,平均分:82.5
stu2.study() # 王五 正在学习 计算机
访问控制
| 维度 | 核心内容 | 注意事项 |
|---|---|---|
| 命名约定 | 单下划线 _name:表示“受保护”双下划线 __name:名称修饰(name mangling) | Python 没有严格的私有成员,靠自觉遵守 |
代码示例:
class Person:
def __init__(self, name, age):
self._name = name # 受保护(约定)
self.__age = age # 私有(名称修饰)
def get_age(self):
return self.__age
p = Person("Tom", 25)
print(p._name) # Tom (仍可访问,但不推荐)
# print(p.__age) # 报错 AttributeError
print(p._Person__age) # 25 (通过名称修饰后的名字可访问)
print(p.get_age()) # 25 (通过方法访问)
特殊方法(魔术方法)
| 维度 | 核心内容 | 注意事项 |
|---|---|---|
__str__ | 面向用户的字符串表示,由 print() 和 str() 调用 | 若未定义,回退到 __repr__ |
__repr__ | 面向开发者的表示,通常可用来重建对象 | 交互式解释器默认调用 |
| 其他 | __len__、__add__ 等实现容器行为和运算符重载 |
代码示例:
class Book:
def __init__(self, title, author):
self.title = title
self.author = author
def __str__(self):
# 面向用户的字符串表示
return f"《{self.title}》 by {self.author}"
def __repr__(self):
# 面向开发者的表示,通常可用来重建对象
return f"Book('{self.title}', '{self.author}')"
def __len__(self):
return len(self.title)
book = Book("Python编程", "张三")
print(str(book)) # 《Python编程》 by 张三
print(repr(book)) # Book('Python编程', '张三')
print(len(book)) # 9
类方法与静态方法
| 维度 | 核心内容 | 注意事项 |
|---|---|---|
@classmethod | 类方法,第一个参数为 cls,可访问类属性 | 常用于工厂模式 |
@staticmethod | 静态方法,无特殊参数,相当于独立函数 | 放在类命名空间内 |
代码示例:
class MathUtil:
pi = 3.14159
@classmethod
def circle_area(cls, radius):
return cls.pi * radius ** 2
@staticmethod
def add(x, y):
return x + y
print(MathUtil.circle_area(5)) # 78.53975
print(MathUtil.add(3, 5)) # 8
实操任务
- 定义一个类
Book,包含属性:title(书名)、author(作者)、pages(页数),方法:get_book_info()(返回“书名:XXX,作者:XXX,页数:XXX”)。并实现__str__方法,使得print(book)输出格式化的信息。 - 定义一个类
BankAccount,包含属性:owner(账户名)、balance(余额,默认为0),方法:deposit(amount)存款,withdraw(amount)取款(余额不足时提示),display_balance()显示余额。 - 创建一个子类
SavingsAccount继承BankAccount,新增属性interest_rate,方法apply_interest()将利息加入余额。 - 尝试使用
@classmethod定义一个工厂方法,从字符串创建对象,例如Book.from_string("Python编程,张三,200")。
进阶提示
- 学习“属性装饰器”
@property,将方法变为属性访问,并可实现计算属性。 - 了解“抽象基类”(abc模块)定义接口。
- 研究“多态”和“鸭子类型”的概念。
模块2:大模型工作原理 - 进阶篇
2.1 核心架构:Transformer
flowchart LR
A[输入文本] --> B[Tokenization(分词)]
B --> C[Embedding(嵌入:Token转向量)]
C --> D[位置编码 Positional Encoding]
D --> E[编码器Encoder:自注意力+前馈网络]
E --> F[解码器Decoder:自注意力+掩码+交叉注意力+前馈网络]
F --> G[输出层:线性变换+Softmax]
G --> H[预测下一个Token]
| 核心组件 | 通俗解释 | 核心作用 |
|---|---|---|
| 自注意力机制 | 模型计算文本中“每个Token与其他Token的关联权重”,理解上下文逻辑。通过查询(Q)、键(K)、值(V)的矩阵运算,得到每个Token的加权表示。 | 让模型关注到相关词语,例如“他”关联“小明” |
| 多头注意力 | 将自注意力机制并行多次(多个头),每个头关注不同的语义空间,最后拼接结果。 | 提升模型表达能力,从多角度理解文本 |
| 位置编码 | 由于Transformer没有循环结构,需要显式注入位置信息。常用正弦余弦函数或可学习的位置嵌入。 | 让模型知道单词的顺序,例如“我爱你”和“你爱我”语义不同 |
| 前馈网络 | 每个注意力层后接一个全连接前馈网络,对每个位置的表示进行非线性变换。 | 进一步提取和转换特征 |
| 编码器 | 处理输入文本,提取语义信息(理解“输入是什么”)。由多个相同的层堆叠。 | 负责“读懂”用户的提示词 |
| 解码器 | 基于编码器的语义信息,逐Token生成输出文本。包含掩码自注意力(防止看到未来Token)和交叉注意力(关注编码器输出)。 | 负责“生成”符合上下文的回答 |
| 优势 | 相比传统RNN/LSTM,Transformer支持“并行计算”,处理长文本更快,且能捕捉长距离依赖。 | 是大模型的核心架构基础 |
代码示例(使用 Hugging Face 加载BERT模型查看架构):
from transformers import BertModel
model = BertModel.from_pretrained("bert-base-uncased")
print(model)
实操任务
- 阅读图解Transformer(如 Jay Alammar 的博客),尝试用手工计算一个简单的自注意力例子(2个Token,2维向量)。
- 使用 Hugging Face 的
transformers库加载一个小型 Transformer 模型(如 BERT-tiny),观察其架构(打印模型结构)。 - 解释为什么 Transformer 需要位置编码?如果去掉会怎样?
进阶提示
- 了解“残差连接”和“层归一化”在Transformer中的作用,防止梯度消失和加速训练。
- 学习“因果掩码”(causal mask)在解码器中的使用,确保生成时不能看到未来Token。
2.2 大模型训练与生成流程
| 阶段 | 核心内容 | 通俗类比 |
|---|---|---|
| 预训练 | 数据:海量通用文本(书籍、网页、文章) 目标:学习通用语言知识(语法、常识、逻辑) 任务:语言建模(预测下一个Token)或掩码语言建模 | 相当于“小学到高中的通识教育” |
| 微调 | 数据:小批量特定任务数据(如客服对话、翻译数据) 目标:适配具体任务(客服、代码生成、翻译等) 方式:全量微调或参数高效微调(LoRA等) | 相当于“大学的专业课程” |
| 文本生成流程 | 1. 输入提示词 → Tokenization 2. Token → Embedding + 位置编码 3. 自注意力计算 4. 解码器预测“下一个Token”的概率分布 5. 根据生成策略选择下一个Token 6. 重复直到生成结束符 | 模型不是“写全文”,而是“猜下一个字” |
| 生成策略 | 贪婪搜索、随机采样、Top-k采样、Top-p采样、束搜索 | 贪婪:最保险;采样:有创意;Top-p:动态平衡 |
| 温度参数 | 在Softmax前将logits除以温度T:T小则分布尖锐(趋近贪婪),T大则分布平滑(增加随机性) | 低温使模型保守,高温使模型有创造性 |
代码示例(使用GPT-2进行文本生成):
from transformers import GPT2LMHeadModel, GPT2Tokenizer
model = GPT2LMHeadModel.from_pretrained("gpt2")
tokenizer = GPT2Tokenizer.from_pretrained("gpt2")
input_text = "Once upon a time"
inputs = tokenizer(input_text, return_tensors="pt")
# 贪婪搜索
greedy_output = model.generate(**inputs, max_length=50)
print(tokenizer.decode(greedy_output[0]))
# 采样(温度=0.7)
sample_output = model.generate(**inputs, max_length=50, do_sample=True, temperature=0.7)
print(tokenizer.decode(sample_output[0]))
# Top-p采样
top_p_output = model.generate(**inputs, max_length=50, do_sample=True, top_p=0.9)
print(tokenizer.decode(top_p_output[0]))
实操任务
- 使用 Hugging Face 的
transformers库加载一个GPT-2模型,尝试用不同的生成策略(贪婪、采样、top-k、top-p)生成文本,观察差异。 - 找一个微调的例子:例如使用
transformers的 Trainer 对预训练模型进行情感分类微调(可使用IMDb数据集)。 - 解释为什么需要微调?如果直接使用预训练模型进行特定任务,效果可能不佳的原因是什么?
进阶提示
- 了解“指令微调”(Instruction Tuning)和“RLHF”(基于人类反馈的强化学习)如何提升模型对话能力。
- 研究“上下文学习”(In-Context Learning)与微调的区别。
- 学习参数高效微调方法(LoRA、Prefix Tuning)的原理。
2.3 大模型常见问题与优化
| 问题 | 定义 | 解决思路 |
|---|---|---|
| 过拟合 | 模型在训练数据上表现极好,但在未见过的测试数据上表现差(“死记硬背”) | 增加数据量、正则化(Dropout、权重衰减)、早停、降低模型复杂度 |
| 欠拟合 | 模型在训练数据和测试数据上表现都差(“没学够”) | 增加训练轮数、提升模型复杂度、减少正则化、优化数据质量 |
| 幻觉 | 模型生成“看似合理但不符合事实”的内容 | 高质量数据、检索增强生成(RAG)、提示工程、RLHF惩罚幻觉 |
| 偏见与伦理 | 模型学习到训练数据中的社会偏见,生成有害内容 | 数据去偏、对抗训练、内容审核、AI伦理准则 |
| 长文本处理 | 模型受限于上下文窗口,无法处理超长文档 | 长窗口模型、RAG、摘要式处理、滑动窗口 |
| 推理速度慢 | 大模型参数量大,生成速度慢 | 模型量化、批处理、KV缓存、高效架构(MQA、GQA)、硬件加速 |
实操任务
- 假设你正在开发一个医疗问答系统,大模型有时会产生幻觉给出错误的医疗建议。请设计一个方案来减少幻觉(例如结合知识库、提示工程等)。
- 查找一个关于大模型偏见的案例,分析其产生原因,并提出缓解措施。
- 如果模型在特定任务上表现不佳(欠拟合),你会尝试哪些优化?
进阶提示
- 了解“检索增强生成”(RAG)的架构和工作原理,以及如何用LangChain等框架实现。
- 学习“指令微调”如何缓解幻觉(如让模型学会说“我不知道”)。
- 探索“思维链”(Chain-of-Thought)提示如何提升复杂推理能力。
第二周自测题(简易版)
1. Python 部分
- 定义一个类
Book,包含属性:title(书名)、author(作者)、pages(页数),方法:get_book_info()(返回“书名:XXX,作者:XXX,页数:XXX”),并实现__str__方法。 - 编写函数:接收一个列表,返回列表中所有元素的乘积(处理空列表返回1,遇到非数字元素抛出异常)。
- 使用列表推导式生成一个包含 1 到 20 之间所有奇数的平方的列表。
- 解释
*args和**kwargs的作用,并给出一个示例函数。
2. 大模型部分
- 简述 Transformer 中自注意力机制的作用,并解释为什么需要多头注意力。
- 大模型“预训练”和“微调”的核心区别是什么?微调为什么能提升特定任务效果?
- 为什么大模型生成文本是“逐Token”的,而非一次性生成?如果一次性生成会有什么问题?
- 列举至少两种减少大模型幻觉的方法,并简要说明原理。
总结
核心知识点回顾
Python 部分
- 基础层:掌握变量/数据类型、运算符、条件判断、循环、异常处理,是编写程序的基础;
- 进阶层:列表推导式提升列表处理效率,函数实现代码复用,面向对象是大型项目的核心编程范式;
- 关键原则:代码需兼顾“正确性”与“可读性”,异常处理避免程序崩溃;理解可变与不可变对象对编程的影响;掌握作用域规则,避免变量污染。
大模型部分
- 基础层:Token 是模型处理文本的最小单位,上下文窗口决定模型的“记忆容量”;分词器是连接文本和模型的桥梁。
- 核心架构:Transformer 是大模型的基础,自注意力机制解决了上下文关联问题,位置编码赋予模型顺序感知,多头注意力提升表达能力。
- 核心流程:大模型通过“预训练学通用知识+微调适配具体任务”,文本生成是“逐Token预测”的过程,生成策略(温度、Top-p等)影响输出多样性。
- 常见问题:过拟合、欠拟合、幻觉、偏见等需要针对性地优化,如数据清洗、正则化、检索增强等。
学习建议
- Python 学习:每学一个知识点,立即编写代码验证(如学完函数,写1-2个实用函数);多用调试工具(print、pdb)理解代码执行过程;阅读优秀代码,学习规范。
- 大模型学习:结合实际场景理解(如用 ChatGPT 时,观察它的回答是否受上下文长度影响,尝试不同生成参数);动手实践:使用 Hugging Face 库加载模型、进行推理和微调;关注前沿论文和博客,理解技术演进。
- 自测闭环:每周完成自测题,错题对应回顾知识点,确保“学一个会一个”。可创建错题本,记录易错点和解决方案。
- 项目驱动:尝试用所学知识完成一个小项目(如命令行工具、简单的对话机器人),加深理解和综合运用能力。