Skip to content

Python 语法与常用包


Python — Guido van Rossum, 1991

Python is a programming language that lets you work quickly and integrate systems more effectively.

Python 是一门让你能够快速开发并高效整合系统的编程语言。它是机器学习与人工智能领域最主流的编程语言,几乎所有深度学习框架都以 Python 为主要接口。


基础语法

变量与数据类型

Python 是动态类型语言,变量不需要声明类型,赋值即创建。

# 基本数据类型
x = 42              # int 整数
y = 3.14            # float 浮点数
name = "疾旋鼬"     # str 字符串
is_cute = True      # bool 布尔值
nothing = None      # NoneType 空值

# 查看类型
print(type(x))      # <class 'int'>
print(type(y))      # <class 'float'>
print(type(name))   # <class 'str'>
print(type(is_cute))# <class 'bool'>

Python 3 中,int 没有大小限制,可以表示任意大的整数:

big_number = 10 ** 100  # 10 的 100 次方,googol
print(big_number)       # 10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000

类型转换

# 显式类型转换
s = "123"
n = int(s)          # 字符串 → 整数: 123
f = float(s)        # 字符串 → 浮点数: 123.0
s2 = str(n)         # 整数 → 字符串: "123"

# 浮点数与整数互转
a = int(3.9)        # 3 (截断,不是四舍五入)
b = float(3)        # 3.0

字符串操作

# 字符串是不可变的序列类型
s = "Hello, 疾旋鼬"

# 索引与切片(从 0 开始)
print(s[0])         # 'H'
print(s[-1])        # '鼬'(负索引从末尾开始)
print(s[0:5])       # 'Hello'(左闭右开区间)

# 常用方法
print(s.lower())    # 'hello, 疾旋鼬'
print(s.upper())    # 'HELLO, 疾旋鼬'
print(s.replace('Hello', 'Hi'))  # 'Hi, 疾旋鼬'
print(s.split(', '))# ['Hello', '疾旋鼬']
print(len(s))       # 10

# f-string 格式化(Python 3.6+)
name = "疾旋鼬"
age = 1
print(f"{name}今年{age}岁")         # '疾旋鼬今年1岁'
print(f"{3.14159:.2f}")             # '3.14'(保留两位小数)
print(f"{'居中':^10}")              # '    居中    '(居中对齐)

# 多行字符串
poem = """
疾旋鼬,
蜷缩旋转,
速度惊人。
"""

运算符

# 算术运算符
print(7 + 3)    # 10  加法
print(7 - 3)    # 4   减法
print(7 * 3)    # 21  乘法
print(7 / 3)    # 2.3333...  除法(结果总是 float)
print(7 // 3)   # 2   整除(向下取整)
print(7 % 3)    # 1   取模(余数)
print(7 ** 3)   # 343 幂运算

# 比较运算符(返回 bool)
print(3 == 3)   # True   等于
print(3 != 4)   # True   不等于
print(3 > 2)    # True   大于
print(3 <= 3)   # True   小于等于

# 逻辑运算符
print(True and False)   # False  与
print(True or False)    # True   或
print(not True)         # False  非

# 身份运算符(判断是否是同一个对象)
a = [1, 2, 3]
b = a
c = [1, 2, 3]
print(a is b)       # True  (b 指向同一个对象)
print(a is c)       # False (c 是新创建的对象)
print(a == c)       # True  (值相等)

# 成员运算符
print(3 in [1, 2, 3])         # True
print('疾' in '疾旋鼬')       # True

# 链式比较
x = 5
print(1 < x < 10)             # True

条件语句

score = 85

if score >= 90:
    grade = "A"
elif score >= 80:
    grade = "B"
elif score >= 70:
    grade = "C"
else:
    grade = "D"

print(f"成绩: {grade}")  # 成绩: B

elifelse if 的缩写。条件判断从上到下,执行第一个满足条件的分支后跳过其余分支。

循环

for 循环

# 遍历列表
animals = ["疾旋鼬", "捣蛋猫", "桃旋鼬"]
for animal in animals:
    print(animal)

# range(start, stop, step) 生成整数序列
for i in range(5):          # 0, 1, 2, 3, 4
    print(i)

for i in range(2, 8, 2):    # 2, 4, 6
    print(i)

# enumerate 同时获取索引和值
for i, animal in enumerate(animals):
    print(f"{i}: {animal}")
# 0: 疾旋鼬
# 1: 捣蛋猫
# 2: 桃旋鼬

# zip 并行遍历多个序列
names = ["疾旋鼬", "捣蛋猫"]
types = ["龙", "无"]
for name, t in zip(names, types):
    print(f"{name}{t} 属性")

while 循环

n = 10
while n > 0:
    print(n)
    n -= 1
print("发射!")

break 与 continue

# break: 立即退出整个循环
for i in range(10):
    if i == 5:
        break           # 当 i=5 时退出
    print(i)            # 输出 0 1 2 3 4

# continue: 跳过当前迭代,进入下一次
for i in range(10):
    if i % 2 == 0:
        continue        # 跳过偶数
    print(i)            # 输出 1 3 5 7 9

List Comprehension

列表推导式(List Comprehension)是 Python 中创建列表的简洁方式,在机器学习代码中极其常用。

# 基本语法: [表达式 for 变量 in 可迭代对象]
squares = [x**2 for x in range(10)]
print(squares)  # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

# 带条件过滤: [表达式 for 变量 in 可迭代对象 if 条件]
evens = [x for x in range(20) if x % 2 == 0]
print(evens)    # [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]

# 嵌套推导: 展平二维列表
matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
flat = [x for row in matrix for x in row]
print(flat)     # [1, 2, 3, 4, 5, 6, 7, 8, 9]

# 带表达式的推导
labels = [0, 1, 2, 1, 0]
one_hot = [[1 if i == l else 0 for i in range(3)] for l in labels]
print(one_hot)  # [[1,0,0], [0,1,0], [0,0,1], [0,1,0], [1,0,0]]

数据结构

列表(list)

列表是有序、可变的序列,是 Python 中最常用的数据结构。

# 创建列表
fruits = ["疾旋鼬", "捣蛋猫", "桃旋鼬"]

# 索引与切片
print(fruits[0])        # '疾旋鼬'
print(fruits[-1])       # '桃旋鼬'
print(fruits[0:2])      # ['疾旋鼬', '捣蛋猫']

# 修改元素
fruits[1] = "火绒狐"
print(fruits)           # ['疾旋鼬', '火绒狐', '桃旋鼬']

# 添加元素
fruits.append("冰刺猬")         # 末尾添加
fruits.insert(1, "雷角鹿")      # 在索引 1 处插入
fruits.extend(["风灵龙", "水灵猫"])  # 扩展列表

# 删除元素
fruits.remove("桃旋鼬")         # 按值删除
popped = fruits.pop()           # 弹出末尾元素
del fruits[0]                   # 按索引删除

# 排序
numbers = [3, 1, 4, 1, 5, 9]
numbers.sort()                  # 原地排序: [1, 1, 3, 4, 5, 9]
numbers.sort(reverse=True)      # 降序: [9, 5, 4, 3, 1, 1]
sorted_nums = sorted(numbers)   # 返回新列表,不修改原列表

# 列表复制(注意浅拷贝与深拷贝)
a = [1, 2, [3, 4]]
b = a               # 浅拷贝: b 和 a 指向同一对象
c = a.copy()        # 浅拷贝: 新列表,但内部列表仍共享
import copy
d = copy.deepcopy(a)# 深拷贝: 完全独立的副本

# 常用操作
print(len(fruits))          # 列表长度
print(fruits.count("疾旋鼬")) # 统计出现次数
print(fruits.index("疾旋鼬")) # 查找第一次出现的索引

浅拷贝与深拷贝

在 Python 中,列表复制涉及浅拷贝和深拷贝,理解它们的区别对于避免意外的数据修改非常重要。

a = [1, 2, [3, 4]]  # 初始列表

直接赋值

b = a
- ba 的别名,两者指向同一个对象 - 修改其中一个会同时影响另一个
b.append(5)
print(a)  # [1, 2, [3, 4], 5]

浅拷贝

c = a.copy()  # 或 a[:] 或 list(a)
- 创建新列表,但内嵌元素仍是原列表元素的引用 - 修改不可变元素(如整数)不会相互影响 - 修改可变元素(如内嵌列表)会相互影响
a[0] = 100        # 修改整数,c 不变
a[2].append(5)    # 修改内嵌列表,c 也会变化
print(a)          # [100, 2, [3, 4, 5]]
print(c)          # [1, 2, [3, 4, 5]]

深拷贝

import copy
d = copy.deepcopy(a)
  • 递归复制所有对象,创建完全独立的副本
  • 修改任何元素都不会相互影响
a[2].append(6)
print(a)          # [100, 2, [3, 4, 5, 6]]
print(d)          # [100, 2, [3, 4, 5]]

元组(tuple)

元组是有序、不可变的序列。一旦创建,不能修改。

# 创建元组
point = (3, 4)
single = (42,)      # 单元素元组需要逗号
empty = ()

# 元组解包
x, y = point
print(x, y)         # 3 4

# 交换变量(利用元组解包)
a, b = 1, 2
a, b = b, a         # a=2, b=1

# 元组作为字典的键(因为不可变)
locations = {
    (0, 0): "起点",
    (3, 4): "疾旋鼬的家",
}

字典(dict)

字典是键值对的无序集合(Python 3.7+ 保持插入顺序)。

# 创建字典
pal = {
    "name": "疾旋鼬",
    "type": "龙",
    "hp": 100,
    "skills": ["旋转冲击", "蜷缩防御"],
}

# 访问元素
print(pal["name"])              # '疾旋鼬'
print(pal.get("mp", 0))        # 0(键不存在时返回默认值)

# 修改与添加
pal["hp"] = 120                 # 修改
pal["attack"] = 85              # 添加新键

# 删除
del pal["attack"]
removed = pal.pop("skills")     # 弹出并返回

# 遍历
for key, value in pal.items():
    print(f"{key}: {value}")

for key in pal.keys():
    print(key)

for value in pal.values():
    print(value)

# 字典推导式
squares = {x: x**2 for x in range(6)}
print(squares)  # {0: 0, 1: 1, 2: 4, 3: 9, 4: 16, 5: 25}

# 合并字典(Python 3.9+)
d1 = {"a": 1, "b": 2}
d2 = {"b": 3, "c": 4}
d3 = d1 | d2        # {'a': 1, 'b': 3, 'c': 4}(后者覆盖前者)

集合(set)

集合是无序、不重复的元素集合,常用于去重和集合运算。

# 创建集合
types = {"龙", "火", "水", "龙"}  # 自动去重
print(types)        # {'龙', '火', '水'}

# 集合运算
a = {1, 2, 3, 4}
b = {3, 4, 5, 6}
print(a | b)        # 并集: {1, 2, 3, 4, 5, 6}
print(a & b)        # 交集: {3, 4}
print(a - b)        # 差集: {1, 2}
print(a ^ b)        # 对称差集: {1, 2, 5, 6}

# 集合推导式
evens = {x for x in range(20) if x % 2 == 0}

函数

# 基本函数定义
def greet(name):
    """问候函数(这是 docstring,文档字符串)"""
    return f"你好,{name}!"

print(greet("疾旋鼬"))  # 你好,疾旋鼬!

# 默认参数
def power(base, exp=2):
    return base ** exp

print(power(3))       # 9 (使用默认 exp=2)
print(power(3, 3))    # 27

# 可变参数 *args(接收任意数量的位置参数,打包为元组)
def mean(*numbers):
    return sum(numbers) / len(numbers)

print(mean(1, 2, 3, 4, 5))  # 3.0

# 关键字可变参数 **kwargs(接收任意数量的关键字参数,打包为字典,参数key=value 形式)
def build_model(**kwargs):
    for key, value in kwargs.items():
        print(f"{key} = {value}")

build_model(d_model=512, num_heads=8, d_ff=2048)

# 参数组合顺序: 位置参数 → 默认参数 → *args → **kwargs
def transformer_forward(x, mask=None, *layers, **config):
    pass

# Lambda 匿名函数(常用于简短的函数定义)
square = lambda x: x ** 2
print(square(5))  # 25

# 函数是一等公民,可以作为参数传递
def apply(func, value):
    return func(value)

print(apply(square, 4))        # 16
print(apply(lambda x: x + 1, 4))  # 5

类与面向对象编程

Python 中一切皆对象。类是创建对象的蓝图。

class Pal:
    """帕鲁(游戏中的生物)的基类"""

    # 类变量(所有实例共享)
    kingdom = "帕鲁世界"

    def __init__(self, name, element, hp=100):
        """构造函数,创建实例时自动调用"""
        # 实例变量(每个实例独有)
        self.name = name
        self.element = element
        self.hp = hp
        self._secret = "内部变量"   # 单下划线:约定为"私有"(但不强制)
        self.__hidden = "真正私有"  # 双下划线:名称改写(name mangling)

    def attack(self):
        """实例方法:第一个参数必须是 self"""
        return f"{self.name} 发动攻击!"

    def take_damage(self, damage):
        self.hp -= damage
        if self.hp <= 0:
            self.hp = 0
            print(f"{self.name} 倒下了!")

    @property
    def is_alive(self):
        """属性装饰器:像属性一样访问,但有计算逻辑"""
        return self.hp > 0

    @staticmethod
    def is_valid_element(element):
        """静态方法:不需要实例,不接收 self"""
        valid = {"龙", "火", "水", "草", "电", "冰"}
        return element in valid

    @classmethod
    def from_dict(cls, data):
        """类方法:接收类本身作为第一个参数(cls),常用于替代构造函数"""
        return cls(data["name"], data["element"], data["hp"])

    def __str__(self):
        """定义 print() 时的输出"""
        return f"Pal({self.name}, {self.element}, HP={self.hp})"

    def __repr__(self):
        """定义在交互式环境中的显示(更详细)"""
        return f"Pal(name='{self.name}', element='{self.element}', hp={self.hp})"

    def __len__(self):
        """定义 len() 的行为"""
        return self.hp


# 使用
jxy = Pal("疾旋鼬", "龙", 120)
print(jxy)                  # Pal(疾旋鼬, 龙, HP=120)
print(jxy.attack())         # 疾旋鼬 发动攻击!
print(jxy.is_alive)         # True
print(Pal.is_valid_element("龙"))  # True

# 从字典创建
data = {"name": "桃旋鼬", "element": "龙", "hp": 90}
txy = Pal.from_dict(data)
print(txy)                  # Pal(桃旋鼬, 龙, HP=90)

继承

class DragonPal(Pal):
    """龙属性帕鲁,继承自 Pal"""

    def __init__(self, name, hp=100, dragon_power=50):
        # 调用父类构造函数
        super().__init__(name, "龙", hp)
        self.dragon_power = dragon_power

    def attack(self):
        """重写父类方法"""
        return f"{self.name} 发动龙之怒!(威力: {self.dragon_power})"

    def fly(self):
        """子类独有方法"""
        return f"{self.name} 展翅高飞!"


dragon = DragonPal("疾旋鼬", 120, 80)
print(dragon.attack())      # 疾旋鼬 发动龙之怒!(威力: 80)
print(dragon.fly())         # 疾旋鼬 展翅高飞!
print(dragon.is_alive)      # True(继承的属性装饰器仍然可用)

# isinstance 判断类型
print(isinstance(dragon, DragonPal))  # True
print(isinstance(dragon, Pal))        # True(子类实例也是父类实例)

多重继承与 Mixin

class Flyable:
    def fly(self):
        return f"{self.name} 在飞!"

class Swimmable:
    def swim(self):
        return f"{self.name} 在游泳!"

class WaterDragonPal(Pal, Flyable, Swimmable):
    """多重继承:同时获得多个类的能力"""
    pass

wd = WaterDragonPal("海龙", "水", 150)
print(wd.fly())     # 海龙 在飞!
print(wd.swim())    # 海龙 在游泳!

异常处理

try:
    result = 10 / 0
except ZeroDivisionError as e:
    print(f"错误: {e}")           # 错误: division by zero
except (TypeError, ValueError) as e:
    print(f"类型或值错误: {e}")    # 可以同时捕获多种异常
else:
    print("没有异常时执行")
finally:
    print("无论是否异常都执行")    # 常用于清理资源

# 自定义异常
class ModelNotFoundError(Exception):
    pass

# 抛出异常
def load_model(path):
    import os
    if not os.path.exists(path):
        raise ModelNotFoundError(f"模型文件不存在: {path}")
    return "model"

# 上下文管理器(with 语句)
with open("data.txt", "r", encoding="utf-8") as f:
    content = f.read()
# 离开 with 块后,文件自动关闭

模块与导入

# 导入整个模块
import math
print(math.sqrt(16))        # 4.0

# 导入特定函数
from math import sqrt, log
print(sqrt(16))             # 4.0

# 导入并重命名
import numpy as np
from torch.nn import functional as F

# 导入模块中的所有(不推荐,容易命名冲突)
from math import *

# 自定义模块
# 假设有一个文件 utils.py,其中定义了 function hello()
# import utils
# from utils import hello

文件操作

# 读取文件
with open("data.txt", "r", encoding="utf-8") as f:
    content = f.read()              # 读取全部内容
    # 或逐行读取
    for line in f:
        print(line.strip())

# 写入文件
with open("output.txt", "w", encoding="utf-8") as f:
    f.write("疾旋鼬\n")
    f.write("捣蛋猫\n")

# 追加写入
with open("output.txt", "a", encoding="utf-8") as f:
    f.write("桃旋鼬\n")

# 读写 JSON
import json
data = {"name": "疾旋鼬", "hp": 100}
with open("pal.json", "w", encoding="utf-8") as f:
    json.dump(data, f, ensure_ascii=False, indent=2)

with open("pal.json", "r", encoding="utf-8") as f:
    loaded = json.load(f)
    print(loaded)  # {'name': '疾旋鼬', 'hp': 100}

数值计算基础:NumPy

NumPy 是 Python 科学计算的基石,提供了高效的多维数组对象和大量数学函数。理解 NumPy 是使用 PyTorch 等深度学习框架的前提。

为什么需要 NumPy?

Python 原生的列表虽然灵活,但存储和计算效率极低。NumPy 数组在内存中连续存储,底层用 C 实现,运算速度比纯 Python 快 10-100 倍。在机器学习中,数据几乎总是以数组(张量)的形式存在,NumPy 提供了操作这些数据的所有基础工具。

数组创建

import numpy as np

# 从列表创建
a = np.array([1, 2, 3, 4, 5])          # 一维数组
b = np.array([[1, 2, 3], [4, 5, 6]])   # 二维数组(矩阵)

# 常用创建函数
zeros = np.zeros((3, 4))        # 3×4 全零矩阵
ones = np.ones((2, 3))          # 2×3 全一矩阵
eye = np.eye(4)                 # 4×4 单位矩阵
arange = np.arange(0, 10, 2)    # [0, 2, 4, 6, 8](类似 range)
linspace = np.linspace(0, 1, 5) # [0, 0.25, 0.5, 0.75, 1](等间隔)
random_normal = np.random.randn(3, 4)    # 标准正态分布随机数
random_uniform = np.random.rand(3, 4)    # [0, 1) 均匀分布随机数
random_int = np.random.randint(0, 10, (3, 4))  # 随机整数

# 数组属性
print(a.shape)      # (5,)       形状
print(b.shape)      # (2, 3)     形状
print(b.ndim)       # 2          维度数
print(b.size)       # 6          元素总数
print(b.dtype)      # int64      数据类型

数组运算

NumPy 的核心特性是向量化运算——不需要显式循环,直接对整个数组进行运算。

a = np.array([1, 2, 3])
b = np.array([4, 5, 6])

# 逐元素运算(element-wise)
print(a + b)        # [5, 7, 9]      加法
print(a - b)        # [-3, -3, -3]   减法
print(a * b)        # [4, 10, 18]    逐元素乘法
print(a / b)        # [0.25, 0.4, 0.5]  除法
print(a ** 2)       # [1, 4, 9]      幂运算
print(np.sqrt(a))   # [1.0, 1.414, 1.732]  平方根
print(np.exp(a))    # [2.718, 7.389, 20.086]  指数
print(np.log(a))    # [0.0, 0.693, 1.099]  自然对数

# 聚合运算
print(np.sum(a))    # 6      求和
print(np.mean(a))   # 2.0    均值
print(np.std(a))    # 0.816  标准差
print(np.max(a))    # 3      最大值
print(np.min(a))    # 1      最小值
print(np.argmax(a)) # 2      最大值索引

# 矩阵运算
A = np.array([[1, 2], [3, 4]])
B = np.array([[5, 6], [7, 8]])

# 矩阵乘法(三种等价写法)
C1 = A @ B              # [[19, 22], [43, 50]]  推荐
C2 = np.dot(A, B)       # 同上
C3 = A.dot(B)           # 同上

# 转置
print(A.T)              # [[1, 3], [2, 4]]

# 点积(向量内积)
v1 = np.array([1, 2, 3])
v2 = np.array([4, 5, 6])
print(np.dot(v1, v2))   # 32 = 1*4 + 2*5 + 3*6

索引与切片

A = np.array([[1, 2, 3],
              [4, 5, 6],
              [7, 8, 9]])

# 基本索引
print(A[0, 1])      # 2    第0行第1列
print(A[1, :])      # [4, 5, 6]    第1行所有列
print(A[:, 2])      # [3, 6, 9]    所有行第2列

# 切片
print(A[0:2, 1:3])  # [[2, 3], [5, 6]]    子矩阵

# 步长切片
print(A[:, 0::2])   # [[1, 3], [4, 6], [7, 9]]  每隔一列

# 布尔索引(条件筛选)
print(A[A > 5])     # [6, 7, 8, 9]    大于5的元素

# 花式索引(用数组索引)
print(A[[0, 2], [1, 2]])  # [2, 9]    (0,1) 和 (2,2) 位置的元素

形状操作

a = np.arange(12)

# 重塑
b = a.reshape(3, 4)         # 3行4列
c = a.reshape(3, -1)        # -1 表示自动推断: 3行4列
d = a.reshape(-1,)          # 展平为一维

# 转置与轴操作
M = np.random.randn(2, 3, 4)
print(M.shape)              # (2, 3, 4)
M_T = M.transpose(0, 2, 1) # 交换轴: (2, 4, 3)
M_swap = np.swapaxes(M, 1, 2)  # 同上

# 拼接
a = np.array([[1, 2], [3, 4]])
b = np.array([[5, 6], [7, 8]])
print(np.concatenate([a, b], axis=0))  # 沿行拼接: (4, 2)
print(np.concatenate([a, b], axis=1))  # 沿列拼接: (2, 4)
print(np.stack([a, b], axis=0))        # 堆叠: (2, 2, 2)

# 增加维度
v = np.array([1, 2, 3])
print(v.shape)              # (3,)
print(v[np.newaxis, :].shape)   # (1, 3)  等价于 v.reshape(1, -1)
print(v[:, np.newaxis].shape)   # (3, 1)  等价于 v.reshape(-1, 1)

广播(Broadcasting)

广播是 NumPy 中最强大的特性之一,它允许不同形状的数组进行运算。

# 规则:从末尾开始比较维度,满足以下条件之一即可广播:
# 1. 维度相等
# 2. 其中一个维度为 1

# 标量与数组运算
a = np.array([1, 2, 3])
print(a * 2)            # [2, 4, 6]  标量 2 被广播到每个元素

# 二维与一维运算
A = np.array([[1, 2, 3],
              [4, 5, 6]])    # (2, 3)
b = np.array([10, 20, 30])   # (3,)  → 广播为 (2, 3)
print(A + b)            # [[11, 22, 33], [14, 25, 36]]

# 列向量与行向量
col = np.array([[1], [2], [3]])  # (3, 1)
row = np.array([10, 20])         # (2,)  → 广播为 (1, 2)
print(col + row)        # (3, 2): [[11, 21], [12, 22], [13, 23]]

# 实际应用:对每行减去均值(数据归一化)
data = np.random.randn(5, 3)    # 5个样本,3个特征
mean = data.mean(axis=0)        # 每个特征的均值: (3,)
normalized = data - mean         # 广播: (5,3) - (3,) = (5,3)

深度学习框架:PyTorch

PyTorch 是当前最流行的深度学习框架之一,以其动态计算图Pythonic 的设计哲学著称。Transformer.md 中的所有代码都基于 PyTorch。

张量(Tensor)

张量是 PyTorch 的核心数据结构,本质上是多维数组,与 NumPy 的 ndarray 类似,但额外支持 GPU 加速和自动微分。

import torch

# === 创建张量 ===

# 从列表创建
t = torch.tensor([1, 2, 3, 4])             # 一维张量
m = torch.tensor([[1, 2], [3, 4]])          # 二维张量

# 常用创建函数
zeros = torch.zeros(3, 4)                   # 全零
ones = torch.ones(2, 3)                     # 全一
eye = torch.eye(4)                          # 单位矩阵
rand = torch.randn(3, 4)                    # 标准正态分布
rand_uniform = torch.rand(3, 4)             # [0, 1) 均匀分布
arange = torch.arange(0, 10, 2)             # [0, 2, 4, 6, 8]
linspace = torch.linspace(0, 1, 5)          # [0, 0.25, 0.5, 0.75, 1]
full = torch.full((3, 3), 3.14)             # 全部填充指定值

# 指定数据类型
t_float = torch.tensor([1, 2, 3], dtype=torch.float32)
t_int = torch.tensor([1, 2, 3], dtype=torch.int64)

# 张量属性
x = torch.randn(2, 3, 4)
print(x.shape)          # torch.Size([2, 3, 4])  形状
print(x.dtype)          # torch.float32           数据类型
print(x.device)         # cpu                     所在设备
print(x.dim())          # 3                       维度数
print(x.numel())        # 24                      元素总数

张量运算

a = torch.tensor([1.0, 2.0, 3.0])
b = torch.tensor([4.0, 5.0, 6.0])

# 逐元素运算
print(a + b)            # tensor([5., 7., 9.])
print(a - b)            # tensor([-3., -3., -3.])
print(a * b)            # tensor([ 4., 10., 18.])  逐元素乘法
print(a / b)            # tensor([0.2500, 0.4000, 0.5000])
print(a ** 2)           # tensor([1., 4., 9.])

# 聚合运算
print(a.sum())          # tensor(6.)
print(a.mean())         # tensor(2.)
print(a.max())          # tensor(3.)
print(a.min())          # tensor(1.)
print(a.argmax())       # tensor(2)  最大值索引

# 矩阵运算
A = torch.randn(2, 3)
B = torch.randn(3, 4)

# 矩阵乘法(三种等价写法)
C1 = A @ B              # (2, 4)  推荐写法
C2 = torch.matmul(A, B) # (2, 4)
C3 = torch.mm(A, B)     # (2, 4)  仅限二维

# 转置
print(A.T)              # (3, 2)
print(A.transpose(0, 1)) # 等价写法,指定交换的维度

# 批量矩阵乘法(Transformer 中最常见的操作)
# 用于并行计算多个样本的注意力分数
batch_A = torch.randn(8, 3, 4)     # 8个 3×4 矩阵
batch_B = torch.randn(8, 4, 5)     # 8个 4×5 矩阵
batch_C = batch_A @ batch_B         # (8, 3, 5)  逐个矩阵相乘
# 或者
batch_C = torch.bmm(batch_A, batch_B)  # 等价

# 点积(向量内积)
v1 = torch.tensor([1.0, 2.0, 3.0])
v2 = torch.tensor([4.0, 5.0, 6.0])
print(torch.dot(v1, v2))  # tensor(32.) = 1*4 + 2*5 + 3*6

形状操作

PyTorch 的形状操作与 NumPy 非常相似,但有些方法名不同。

x = torch.arange(24).float()

# reshape / view:改变形状
a = x.reshape(2, 3, 4)         # (2, 3, 4)
b = x.view(2, 3, 4)            # 同上(view 要求内存连续)
c = x.reshape(2, -1)           # (2, 12)  -1 自动推断

# view 与 reshape 的区别:
# view 共享内存,要求张量在内存中连续;reshape 可能创建副本
# 在 Transformer 代码中,通常先 .contiguous() 再 .view()

# 转置与维度交换
M = torch.randn(2, 3, 4)
M_T = M.transpose(1, 2)        # 交换维度1和2: (2, 4, 3)
M_perm = M.permute(0, 2, 1)    # 更通用的维度重排: (2, 4, 3)

# contiguous:使张量在内存中连续
# transpose/permute 后的张量在内存中不连续,需要 contiguous() 才能 view
M_cont = M_T.contiguous()      # 确保内存连续

# 拼接
a = torch.randn(2, 3)
b = torch.randn(2, 3)
cat_0 = torch.cat([a, b], dim=0)    # (4, 3)  沿维度0拼接
cat_1 = torch.cat([a, b], dim=1)    # (2, 6)  沿维度1拼接
stack = torch.stack([a, b], dim=0)  # (2, 2, 3)  堆叠(增加新维度)

# 增加/减少维度
v = torch.tensor([1.0, 2.0, 3.0])
print(v.shape)                      # torch.Size([3])
v_unsq = v.unsqueeze(0)             # (1, 3)  等价于 v[None, :]
v_unsq2 = v.unsqueeze(1)            # (3, 1)  等价于 v[:, None]
s = torch.tensor([[1.0, 2.0, 3.0]])
s_sq = s.squeeze(0)                 # (3,)  去掉大小为1的维度

索引与切片

x = torch.arange(24).reshape(2, 3, 4).float()
# 形状 (2, 3, 4)

# 基本索引
print(x[0])             # 第0个: (3, 4)
print(x[0, 1])          # 第0个的第1行: (4,)
print(x[0, 1, 2])       # 标量: tensor(6.)

# 切片(与 NumPy 相同)
print(x[:, 0:2, :])     # 所有样本,前2行: (2, 2, 4)
print(x[0, :, 0::2])    # 第0个样本,所有行,每隔一列: (3, 2)

# 布尔索引
mask = x > 12
print(x[mask])          # 一维张量,包含所有大于12的元素

# 花式索引
indices = torch.tensor([0, 2])
print(x[0, indices])    # 第0个样本的第0行和第2行: (2, 4)

掩码操作

掩码操作在 Transformer 的注意力机制中至关重要。

# 创建掩码张量
scores = torch.randn(3, 3)

# 下三角掩码(因果掩码,用于解码器)
causal_mask = torch.tril(torch.ones(3, 3))
print(causal_mask)
# tensor([[1., 0., 0.],
#         [1., 1., 0.],
#         [1., 1., 1.]])

# masked_fill:将掩码为0的位置填充为指定值
scores_masked = scores.masked_fill(causal_mask == 0, float('-inf'))
# 掩码为 0 的位置被替换为 -inf,softmax 后变为 0

# 上三角掩码
upper_mask = torch.triu(torch.ones(3, 3), diagonal=1)
print(upper_mask)
# tensor([[0., 1., 1.],
#         [0., 0., 1.],
#         [0., 0., 0.]])

# 应用 softmax 后,-inf 位置变为 0
weights = torch.softmax(scores_masked, dim=-1)
print(weights)
# 每一行是一个概率分布,对角线以下(含对角线)有值,其余为0

设备管理(CPU / GPU)

# 检查 GPU 是否可用
print(torch.cuda.is_available())    # True / False

# 将张量移到 GPU
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
x = torch.randn(3, 4)
x = x.to(device)                    # 移到 GPU(如果可用)

# 创建时直接指定设备
x_gpu = torch.randn(3, 4, device='cuda')

# 移回 CPU
x_cpu = x.cpu()

# 模型移到 GPU
# model = model.to(device)

# 获取张量值(从 GPU 移到 CPU 并转为 Python 数字)
val = x[0, 0].item()                # 仅适用于标量张量
arr = x.detach().cpu().numpy()      # 转为 NumPy 数组

自动微分(Autograd)

自动微分是深度学习的核心——它自动计算梯度,使得反向传播成为可能。

import torch

# requires_grad=True 告诉 PyTorch 需要追踪这个张量上的操作
x = torch.tensor([2.0, 3.0], requires_grad=True)

# 前向计算
y = x ** 2 + 3 * x + 1
z = y.sum()         # 标量才能调用 .backward()

# 反向传播:计算 dz/dx
z.backward()

# 梯度:dz/dx = 2x + 3
print(x.grad)       # tensor([7., 9.])  即 [2*2+3, 2*3+3]

计算图与反向传播

PyTorch 使用动态计算图——每次前向传播时实时构建计算图,反向传播后自动释放。这使得调试和控制流(如 iffor)非常自然。

# 在 Transformer 中的实际使用
model = SomeModel()
optimizer = torch.optim.Adam(model.parameters(), lr=1e-3)

# 训练循环
for epoch in range(num_epochs):
    # 前向传播
    logits = model(src, tgt)            # 自动构建计算图
    loss = F.cross_entropy(logits, target)

    # 反向传播
    optimizer.zero_grad()               # 清除旧梯度
    loss.backward()                     # 计算梯度,填充 .grad
    optimizer.step()                    # 更新参数

torch.nn 模块

torch.nn 是 PyTorch 的神经网络模块,提供了构建网络所需的所有组件。

import torch
import torch.nn as nn
import torch.nn.functional as F

nn.Module:所有网络的基类

class MyModel(nn.Module):
    def __init__(self):
        super().__init__()                  # 必须调用父类构造函数
        self.linear = nn.Linear(10, 5)      # 线性层
        self.relu = nn.ReLU()               # 激活函数

    def forward(self, x):                   # 定义前向传播
        x = self.linear(x)
        x = self.relu(x)
        return x

model = MyModel()
print(model)            # 打印网络结构
print(list(model.parameters()))  # 列出所有可学习参数

常用层

# 线性层(全连接层): y = xW^T + b
linear = nn.Linear(in_features=512, out_features=2048, bias=True)
x = torch.randn(1, 10, 512)     # (batch, seq_len, d_model)
y = linear(x)                    # (1, 10, 2048)
print(y.shape)

# 无偏置的线性层(Transformer 中常用)
linear_no_bias = nn.Linear(512, 512, bias=False)

# 嵌入层:将整数索引映射为向量
embedding = nn.Embedding(num_embeddings=10000, embedding_dim=512)
token_ids = torch.tensor([[1, 5, 42, 7]])   # token ID
embedded = embedding(token_ids)              # (1, 4, 512)
print(embedded.shape)

# 参数
print(embedding.weight.shape)   # (10000, 512)  可学习的嵌入表

# nn.Parameter:将普通张量注册为模型参数
class MyLayer(nn.Module):
    def __init__(self, d_model):
        super().__init__()
        # 这两个参数会被 model.parameters() 自动追踪
        self.gamma = nn.Parameter(torch.ones(d_model))
        self.beta = nn.Parameter(torch.zeros(d_model))

# register_buffer:注册不参与梯度计算的"缓冲区"
class MyTransformer(nn.Module):
    def __init__(self):
        super().__init__()
        # 位置编码是预计算的,不需要梯度
        pe = torch.zeros(100, 512)
        self.register_buffer('pos_encoding', pe)

# nn.ModuleList:管理子模块列表
class MyEncoder(nn.Module):
    def __init__(self, num_layers=6):
        super().__init__()
        # ModuleList 中的模块会被正确注册
        self.layers = nn.ModuleList([
            nn.Linear(512, 512) for _ in range(num_layers)
        ])

    def forward(self, x):
        for layer in self.layers:
            x = layer(x)
        return x

激活函数

# ReLU: max(0, x)
relu = nn.ReLU()
x = torch.tensor([-2.0, -1.0, 0.0, 1.0, 2.0])
print(relu(x))          # tensor([0., 0., 0., 1., 2.])

# 也可以用函数式接口
print(F.relu(x))        # 同上

# GELU(现代 Transformer 中更常用)
gelu = nn.GELU()
print(gelu(x))          # tensor([-0.0455, -0.1588,  0.0000,  0.8412, 1.9545])

# Sigmoid: 1 / (1 + exp(-x))
sigmoid = nn.Sigmoid()
print(sigmoid(x))       # tensor([0.1192, 0.2689, 0.5000, 0.7311, 0.8808])

# Softmax: 将向量转换为概率分布
softmax = nn.Softmax(dim=-1)
logits = torch.tensor([2.0, 1.0, 0.1])
print(softmax(logits))  # tensor([0.6590, 0.2424, 0.0986])
# 注意: softmax 在 Transformer.md 中用 torch.softmax(scores, dim=-1) 调用

损失函数

# 交叉熵损失(分类任务最常用)
# 内部包含 Softmax,所以输入应该是 logits,不是概率
criterion = nn.CrossEntropyLoss()

logits = torch.randn(3, 5)     # 3个样本,5个类别
targets = torch.tensor([0, 2, 4])  # 真实类别
loss = criterion(logits, targets)
print(loss)                    # tensor(1.6094)

# 函数式接口
loss = F.cross_entropy(logits, targets)

# 对于 Transformer 的输出
# logits: (batch, seq_len, vocab_size)
# targets: (batch, seq_len)
# 需要 reshape
logits_flat = logits.view(-1, 5)     # (3, 5)
targets_flat = targets.view(-1)      # (3,)
loss = F.cross_entropy(logits_flat, targets_flat)

优化器

import torch.optim as optim

model = MyModel()

# Adam 优化器(最常用)
optimizer = optim.Adam(model.parameters(), lr=1e-3)

# 带权重衰减(L2 正则化)
optimizer = optim.Adam(model.parameters(), lr=1e-3, weight_decay=1e-5)

# AdamW(现代 Transformer 训练推荐)
optimizer = optim.AdamW(model.parameters(), lr=1e-3, weight_decay=0.01)

# 学习率调度器
scheduler = optim.lr_scheduler.StepLR(optimizer, step_size=10, gamma=0.1)
# 每 10 个 epoch,学习率乘以 0.1

scheduler = optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max=100)
# 余弦退火:学习率按余弦曲线衰减

完整训练循环

import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim

# 1. 定义模型
class SimpleNet(nn.Module):
    def __init__(self, input_dim, hidden_dim, output_dim):
        super().__init__()
        self.fc1 = nn.Linear(input_dim, hidden_dim)
        self.fc2 = nn.Linear(hidden_dim, output_dim)

    def forward(self, x):
        x = F.relu(self.fc1(x))
        x = self.fc2(x)
        return x

# 2. 准备数据
X_train = torch.randn(100, 10)          # 100 个样本,10 维特征
y_train = torch.randint(0, 3, (100,))   # 100 个标签(0, 1, 2)

# 3. 创建模型和优化器
model = SimpleNet(10, 32, 3)
optimizer = optim.Adam(model.parameters(), lr=0.01)

# 4. 训练循环
for epoch in range(100):
    # 前向传播
    logits = model(X_train)
    loss = F.cross_entropy(logits, y_train)

    # 反向传播
    optimizer.zero_grad()   # 清除旧梯度(PyTorch 默认累加梯度)
    loss.backward()         # 计算梯度
    optimizer.step()        # 更新参数

    if (epoch + 1) % 20 == 0:
        acc = (logits.argmax(dim=1) == y_train).float().mean()
        print(f"Epoch {epoch+1}, Loss: {loss.item():.4f}, Acc: {acc.item():.4f}")

# 5. 推理
with torch.no_grad():       # 不追踪梯度,节省内存
    test_x = torch.randn(5, 10)
    pred = model(test_x).argmax(dim=1)
    print(f"预测: {pred}")

完整的 Transformer 训练示例

结合以上所有知识,下面是 Transformer.md 中代码的完整训练流程:

import torch
import torch.nn as nn
import torch.nn.functional as F
import math

# (此处包含 Transformer.md 中定义的所有组件)
# MultiHeadAttention, LayerNorm, FeedForward, EncoderBlock, DecoderBlock, TinyTransformer

# 准备数据
src_vocab_size = 50
tgt_vocab_size = 50
model = TinyTransformer(src_vocab_size, tgt_vocab_size,
                        d_model=16, num_heads=4, d_ff=64, num_layers=2)

# 模拟训练数据
src_ids = torch.tensor([[3, 7, 12, 5, 9]])   # 源序列
tgt_ids = torch.tensor([[2, 15, 8, 4]])       # 目标序列(输入)
target = torch.tensor([[5, 12, 3, 8]])         # 目标序列(标签,偏移一位)

# 优化器
optimizer = torch.optim.Adam(model.parameters(), lr=1e-3)

# 训练一步
logits = model(src_ids, tgt_ids)                # (1, 4, 50)
loss = F.cross_entropy(logits.view(-1, 50), target.view(-1))

optimizer.zero_grad()                           # 清除旧梯度
loss.backward()                                 # 反向传播
optimizer.step()                                # 更新参数

print(f"Loss: {loss.item():.4f}")

数据处理与可视化

Matplotlib:绑图可视化

import matplotlib.pyplot as plt
import numpy as np

# 基本折线图
x = np.linspace(0, 2 * np.pi, 100)
y = np.sin(x)

plt.figure(figsize=(10, 6))
plt.plot(x, y, label='sin(x)', color='blue', linewidth=2)
plt.plot(x, np.cos(x), label='cos(x)', color='red', linewidth=2, linestyle='--')
plt.xlabel('x')
plt.ylabel('y')
plt.title('三角函数')
plt.legend()
plt.grid(True, alpha=0.3)
plt.savefig('trig.png', dpi=150, bbox_inches='tight')
plt.show()

# 子图
fig, axes = plt.subplots(2, 2, figsize=(12, 10))

axes[0, 0].plot(x, np.sin(x))
axes[0, 0].set_title('sin(x)')

axes[0, 1].plot(x, np.cos(x))
axes[0, 1].set_title('cos(x)')

axes[1, 0].bar([1, 2, 3], [3, 1, 4])
axes[1, 0].set_title('柱状图')

axes[1, 1].scatter(np.random.randn(50), np.random.randn(50))
axes[1, 1].set_title('散点图')

plt.tight_layout()
plt.show()

# 训练曲线可视化
def plot_training(train_losses, val_losses, train_accs, val_accs):
    fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(14, 5))

    ax1.plot(train_losses, label='Train Loss')
    ax1.plot(val_losses, label='Val Loss')
    ax1.set_xlabel('Epoch')
    ax1.set_ylabel('Loss')
    ax1.set_title('Loss Curve')
    ax1.legend()

    ax2.plot(train_accs, label='Train Acc')
    ax2.plot(val_accs, label='Val Acc')
    ax2.set_xlabel('Epoch')
    ax2.set_ylabel('Accuracy')
    ax2.set_title('Accuracy Curve')
    ax2.legend()

    plt.tight_layout()
    plt.show()

Pandas:数据分析

import pandas as pd

# 创建 DataFrame
data = {
    'name': ['疾旋鼬', '捣蛋猫', '桃旋鼬', '火绒狐'],
    'type': ['龙', '无', '龙', '火'],
    'hp': [120, 80, 100, 90],
    'attack': [85, 60, 75, 95],
}
df = pd.DataFrame(data)

# 查看数据
print(df.head())                # 前5行
print(df.describe())            # 统计摘要
print(df.info())                # 数据类型信息

# 筛选
dragon = df[df['type'] == '龙']        # 筛选龙属性
strong = df[df['attack'] > 80]         # 筛选攻击>80

# 排序
sorted_df = df.sort_values('hp', ascending=False)

# 添加列
df['total'] = df['hp'] + df['attack']

# 分组统计
type_stats = df.groupby('type').mean(numeric_only=True)

# 读取/保存文件
# df = pd.read_csv('data.csv')
# df.to_csv('output.csv', index=False)

常用标准库与工具

os 与 pathlib:文件系统操作

import os
from pathlib import Path

# 获取当前工作目录
cwd = os.getcwd()

# 路径拼接
config_path = os.path.join(cwd, 'config', 'model.yaml')

# 使用 pathlib(更现代的方式)
p = Path('.')
config = p / 'config' / 'model.yaml'
print(config.exists())       # True / False
print(config.suffix)         # '.yaml'
print(config.parent)         # config/

# 列出目录下的文件
for f in Path('.').glob('*.py'):
    print(f)

# 递归搜索
for f in Path('.').rglob('*.md'):
    print(f)

collections:高级数据结构

from collections import defaultdict, Counter, OrderedDict

# defaultdict:带默认值的字典
word_count = defaultdict(int)       # 默认值为 0
for word in ['疾旋鼬', '捣蛋猫', '疾旋鼬', '桃旋鼬', '疾旋鼬']:
    word_count[word] += 1
print(dict(word_count))  # {'疾旋鼬': 3, '捣蛋猫': 1, '桃旋鼬': 1}

# Counter:计数器
words = ['疾旋鼬', '捣蛋猫', '疾旋鼬', '桃旋鼬', '疾旋鼬']
counter = Counter(words)
print(counter)                    # Counter({'疾旋鼬': 3, '捣蛋猫': 1, '桃旋鼬': 1})
print(counter.most_common(2))     # [('疾旋鼬', 3), ('捣蛋猫', 1)]

typing:类型注解

类型注解不影响运行时行为,但能让代码更易读,并被 IDE 和工具用于静态检查。

from typing import Optional, List, Tuple, Dict

def attention(
    Q: torch.Tensor,        # (batch, seq, d_model)
    K: torch.Tensor,        # (batch, seq, d_model)
    V: torch.Tensor,        # (batch, seq, d_model)
    mask: Optional[torch.Tensor] = None,  # 可选参数
) -> Tuple[torch.Tensor, torch.Tensor]:
    """返回 (注意力输出, 注意力权重)"""
    d_k = Q.size(-1)
    scores = Q @ K.transpose(-2, -1) / (d_k ** 0.5)
    if mask is not None:
        scores = scores.masked_fill(mask == 0, float('-inf'))
    weights = torch.softmax(scores, dim=-1)
    return weights @ V, weights

# Python 3.10+ 更简洁的写法
def process(data: list[str]) -> dict[str, float]:
    ...

functools:函数工具

from functools import partial, lru_cache

# partial:创建偏函数(固定部分参数)
# 在 Transformer 中,常用 partial 来简化优化器的创建
from torch.optim import Adam
create_optimizer = partial(Adam, lr=1e-3, betas=(0.9, 0.98))
optimizer = create_optimizer(model.parameters())

# lru_cache:缓存函数结果(适用于纯函数)
@lru_cache(maxsize=128)
def fibonacci(n):
    if n < 2:
        return n
    return fibonacci(n-1) + fibonacci(n-2)

print(fibonacci(100))  # 354224848179261915075(瞬间完成)

time 与 tqdm:计时与进度条

import time
from tqdm import tqdm

# 计时
start = time.time()
# ... 一些计算 ...
elapsed = time.time() - start
print(f"耗时: {elapsed:.2f}s")

# tqdm 进度条(训练循环中常用)
for epoch in tqdm(range(100), desc="Training"):
    # 训练逻辑
    time.sleep(0.01)  # 模拟训练

random:随机数

import random

# 设置随机种子(确保可复现性)
random.seed(42)
torch.manual_seed(42)
np.random.seed(42)
if torch.cuda.is_available():
    torch.cuda.manual_seed_all(42)

# 常用操作
print(random.random())            # [0, 1) 随机浮点数
print(random.randint(1, 100))     # [1, 100] 随机整数
print(random.choice([1, 2, 3]))   # 随机选择一个
print(random.sample(range(100), 5))  # 无放回抽样5个

re:正则表达式

import re

text = "疾旋鼬的HP是120,桃旋鼬的HP是90"

# 查找数字
numbers = re.findall(r'\d+', text)
print(numbers)          # ['120', '90']

# 匹配模式
pattern = r'(\w+)的HP是(\d+)'
matches = re.findall(pattern, text)
print(matches)          # [('疾旋鼬', '120'), ('桃旋鼬', '90')]

# 替换
cleaned = re.sub(r'\d+', '***', text)
print(cleaned)          # 疾旋鼬的HP是***,桃旋鼬的HP是***

附录:Python 语法速查表

语法 说明 示例
f"{x:.2f}" 格式化字符串 f"{3.14159:.2f}""3.14"
*args 可变位置参数 def f(*args): print(args)
**kwargs 可变关键字参数 def f(**kwargs): print(kwargs)
[x for x in it] 列表推导式 [x**2 for x in range(5)]
{k: v for k, v in it} 字典推导式 {x: x**2 for x in range(5)}
{x for x in it} 集合推导式 {x % 3 for x in range(10)}
a, b = b, a 交换变量 利用元组解包
x if cond else y 三元表达式 a if a > 0 else 0
lambda x: expr 匿名函数 lambda x: x + 1
with open(...) as f: 上下文管理器 自动关闭文件
try/except/finally 异常处理 捕获并处理错误
@property 属性装饰器 像属性一样调用方法
@staticmethod 静态方法 不需要实例和 self
@classmethod 类方法 接收类本身作为 cls
x @ y 矩阵乘法 PyTorch/NumPy 均支持
x.T 转置 行列互换
x.shape 形状 (batch, seq, dim)
x.view(...) 重塑 改变形状,共享内存
x.reshape(...) 重塑 改变形状,可能复制
x.unsqueeze(dim) 增加维度 (3,)(1, 3)
x.squeeze(dim) 减少维度 (1, 3)(3,)
x.item() 转为 Python 数字 仅限标量张量
x.detach() 从计算图分离 停止梯度追踪

我们也有一些关于安全的Python实用说明,您可以参见Python for Security

今天让我emo的人问我怎么又emo了……嗯嘟……

2026.05.11