
1、数据操作深度学习里操作数据的基本单位是张量tensor可以理解成多维数组。PyTorch 的张量不仅能放在 GPU 上加速还支持自动求导比 NumPy 更适合训练模型。1.1 创建张量与基本属性import torch # 用 arange 创建一个包含 0~11 的整数行向量 x torch.arange(12) x # 输出: tensor([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]) # 查看形状每个轴的长度这里是一个一维向量长度为 12 x.shape # 输出: torch.Size([12]) # 查看元素总数 x.numel() # 输出: 121.2 改变形状# 把向量 x 变成 3 行 4 列的矩阵总元素数不变 X x.reshape(3, 4) X # 输出: # tensor([[ 0, 1, 2, 3], # [ 4, 5, 6, 7], # [ 8, 9, 10, 11]]) # -1 可以让 PyTorch 自动推算那一维的大小 x.reshape(-1, 4) # 与 x.reshape(3,4) 效果相同1.3 用常量或随机数初始化# 形状为 (2, 3, 4) 的全 0 张量 torch.zeros((2, 3, 4)) # 输出一个 2x3x4 的 0. 张量 # 形状为 (2, 3, 4) 的全 1 张量 torch.ones((2, 3, 4)) # 输出一个 2x3x4 的 1. 张量 # 从标准正态分布均值0标准差1中随机采样形状 (3,4) torch.randn(3, 4) # 输出示例: # tensor([[-0.0135, 0.0665, 0.0912, 0.3212], # [ 1.4653, 0.1843, -1.6995, -0.3036], # [ 1.7646, 1.0450, 0.2457, -0.7732]]) # 直接通过 Python 列表构造张量 torch.tensor([[2, 1, 4, 3], [1, 2, 3, 4], [4, 3, 2, 1]]) # 输出: # tensor([[2, 1, 4, 3], # [1, 2, 3, 4], # [4, 3, 2, 1]])1.4 运算符最常见的操作是按元素运算即对两个张量中相同位置的元素逐一计算。x torch.tensor([1.0, 2, 4, 8]) y torch.tensor([2, 2, 2, 2]) x y, x - y, x * y, x / y, x ** y # 输出: (tensor([ 3., 4., 6., 10.]), # 加法 # tensor([-1., 0., 2., 6.]), # 减法 # tensor([ 2., 4., 8., 16.]), # 乘法 # tensor([0.5000, 1.0000, 2.0000, 4.0000]), # 除法 # tensor([ 1., 4., 16., 64.])) # 幂运算 # 一元运算符如 exp torch.exp(x) # 输出: tensor([2.7183e00, 7.3891e00, 5.4598e01, 2.9810e03])连结多个张量X torch.arange(12, dtypetorch.float32).reshape(3, 4) Y torch.tensor([[2.0, 1, 4, 3], [1, 2, 3, 4], [4, 3, 2, 1]]) # 沿轴 0行堆叠会变成 6×4 的矩阵 torch.cat((X, Y), dim0) # 输出: # tensor([[ 0., 1., 2., 3.], # [ 4., 5., 6., 7.], # [ 8., 9., 10., 11.], # [ 2., 1., 4., 3.], # [ 1., 2., 3., 4.], # [ 4., 3., 2., 1.]]) # 沿轴 1列堆叠会变成 3×8 的矩阵 torch.cat((X, Y), dim1) # 输出: # tensor([[ 0., 1., 2., 3., 2., 1., 4., 3.], # [ 4., 5., 6., 7., 1., 2., 3., 4.], # [ 8., 9., 10., 11., 4., 3., 2., 1.]]) # 逻辑比较结果是一个布尔型张量 X Y # tensor([[False, True, False, True], # [False, False, False, False], # [False, False, False, False]]) # 对所有元素求和得到标量张量 X.sum() # 输出: tensor(66.)1.5 广播机制当两个张量形状不同但某些维度是 1 时PyTorch 会自动复制扩展使它们形状一致后再进行按元素运算。a torch.arange(3).reshape((3, 1)) # 形状 3×1 b torch.arange(2).reshape((1, 2)) # 形状 1×2 a, b # (tensor([[0], # [1], # [2]]), # tensor([[0, 1]])) a b # a 被复制为 3×2b 被复制为 3×2然后相加 # tensor([[0, 1], # [1, 2], # [2, 3]]) 2.1.6 索引与切片 和 Python 列表类似支持用方括号访问和修改元素。 python X torch.arange(12, dtypetorch.float32).reshape(3, 4) # 取最后一行 X[-1] # tensor([ 8., 9., 10., 11.]) # 取第 2 行、第 3 行索引 1 和 2 X[1:3] # tensor([[ 4., 5., 6., 7.], # [ 8., 9., 10., 11.]]) # 写入单个元素 X[1, 2] 9 # 将前两行全部赋值为 12 X[0:2, :] 12 X # tensor([[12., 12., 12., 12.], # [12., 12., 12., 12.], # [ 8., 9., 10., 11.]])1.7 节省内存类似Y Y X这样的操作会分配新内存。如果想原地更新可以使用切片或。# 新内存分配的例子 before id(Y) Y Y X id(Y) before # False, 说明 Y 指向了新地址 # 原地操作使用切片分配 Z torch.zeros_like(Y) Z[:] X Y # Z 的地址不变 # 或者用 before id(X) X Y id(X) before # True, 地址没有变1.8 与 NumPy 互转PyTorch 张量和 NumPy 数组共享底层内存修改一个会直接影响另一个。A X.numpy() # 张量 - numpy 数组 B torch.tensor(A) # numpy 数组 - 张量 type(A), type(B) # (numpy.ndarray, torch.Tensor) # 大小为 1 的张量可以转换成 Python 标量 a torch.tensor([3.5]) a.item() # 3.5 float(a) # 3.5 int(a) # 32 数据预处理现实数据通常不是现成的张量需要用pandas这样的库进行预处理。2.1 读取 CSV 数据集import os import pandas as pd # 创建一个小数据集写入 CSV 文件模拟真实数据 os.makedirs(os.path.join(.., data), exist_okTrue) data_file os.path.join(.., data, house_tiny.csv) with open(data_file, w) as f: f.write(NumRooms,Alley,Price\n) f.write(NA,Pave,127500\n) f.write(2,NA,106000\n) f.write(4,NA,178100\n) f.write(NA,NA,140000\n) # 用 pandas 读取 data pd.read_csv(data_file) print(data) # 打印结果 # NumRooms Alley Price # 0 NaN Pave 127500 # 1 2.0 NaN 106000 # 2 4.0 NaN 178100 # 3 NaN NaN 1400002.2 处理缺失值缺失值用NaN表示。常见的处理方法是用同一列的均值填充数值列用独热编码处理离散列同时将缺失也当作一个类别。# 分开输入和输出列 inputs, outputs data.iloc[:, 0:2], data.iloc[:, 2] # 数值列的缺失值用该列均值填充 inputs inputs.fillna(inputs.mean()) print(inputs) # NumRooms Alley # 0 3.0 Pave # 1 2.0 NaN # 2 4.0 NaN # 3 3.0 NaN # 离散列 Alley 包含 Pave 和 NaN 两种值用 get_dummies 转成指示列 # 该行数值转换后表示的列数值为1 dummy_naTrue表示nan会单独为一列 inputs pd.get_dummies(inputs, dummy_naTrue) print(inputs) # NumRooms Alley_Pave Alley_nan # 0 3.0 1 0 # 1 2.0 0 1 # 2 4.0 0 1 # 3 3.0 0 12.3 转换为张量处理干净之后就可以把inputs和outputs转成 PyTorch 张量继续用前面学到的张量运算了。import torch X torch.tensor(inputs.to_numpy(dtypefloat)) y torch.tensor(outputs.to_numpy(dtypefloat)) X, y # (tensor([[3., 1., 0.], # [2., 0., 1.], # [4., 0., 1.], # [3., 0., 1.]], dtypetorch.float64), # tensor([127500., 106000., 178100., 140000.], dtypetorch.float64))3 线性代数 内容总结3.1 标量标量是仅含单个数值的数学对象在 PyTorch 中由单元素张量表示支持基础算术运算。import torch # 定义两个标量张量单元素张量 x torch.tensor(3.0) # x tensor(3.) y torch.tensor(2.0) # y tensor(2.) # 加法对应数值直接相加 3.0 2.0 5.0 x y # tensor(5.) # 乘法3.0 * 2.0 6.0 x * y # tensor(6.) # 除法3.0 / 2.0 1.5 x / y # tensor(1.5000) # 幂运算3.0的2.0次方 9.0 x**y # tensor(9.)3.2 向量向量是一阶张量由有序标量列表组成可通过索引访问元素len()获取长度.shape获取张量形状。# 生成从0开始、长度为4的一维整型向量 x torch.arange(4) # 结果tensor([0, 1, 2, 3]) # 通过下标访问第4个元素索引从0开始索引3对应第4个值 x[3] # tensor(3) # 获取向量的元素个数长度 len(x) # 4 # 获取张量的形状1个轴轴长度为4 x.shape # torch.Size([4])3.3 矩阵矩阵是二阶张量由 m 行 n 列标量组成支持转置操作对称矩阵满足「矩阵 自身转置」。# 生成0~19的连续整数重塑为5行4列的矩阵 A torch.arange(20).reshape(5, 4) # 结果 # tensor([[ 0, 1, 2, 3], # [ 4, 5, 6, 7], # [ 8, 9, 10, 11], # [12, 13, 14, 15], # [16, 17, 18, 19]]) # 矩阵转置行和列互换原5×4变为4×5 A.T # 结果 # tensor([[ 0, 4, 8, 12, 16], # [ 1, 5, 9, 13, 17], # [ 2, 6, 10, 14, 18], # [ 3, 7, 11, 15, 19]]) # 定义3阶对称矩阵满足 a_ij a_ji B torch.tensor([[1, 2, 3], [2, 0, 4], [3, 4, 5]]) # 结果 # tensor([[1, 2, 3], # [2, 0, 4], # [3, 4, 5]]) # 逐元素比较B和它的转置验证对称性 B B.T # 结果所有位置均相等输出 # tensor([[True, True, True], # [True, True, True], # [True, True, True]])3.4 张量张量是 n 维数组的通用形式标量是 0 阶张量、向量是 1 阶、矩阵是 2 阶可扩展到更高维度如图像的 3 阶张量。# 生成0~23的整数重塑为 2个块 × 3行 × 4列 的三阶张量 X torch.arange(24).reshape(2, 3, 4) # 结果 # tensor([[[ 0, 1, 2, 3], # 第0个块 # [ 4, 5, 6, 7], # [ 8, 9, 10, 11]], # # [[12, 13, 14, 15], # 第1个块 # [16, 17, 18, 19], # [20, 21, 22, 23]]])3.5 张量算法的基本性质同形状张量的二元运算为逐元素运算结果形状不变矩阵逐元素乘法称为 Hadamard 积。标量与张量运算时标量会广播到张量的每个元素运算后形状不变。# 创建float32类型的5×4矩阵元素为0.~19. A torch.arange(20, dtypetorch.float32).reshape(5, 4) B A.clone() # 深拷贝分配新内存B与A数值相同但相互独立 # 逐元素加法对应位置相加每个元素变为原值的2倍 A B # 结果 # tensor([[ 0., 2., 4., 6.], # [ 8., 10., 12., 14.], # [16., 18., 20., 22.], # [24., 26., 28., 30.], # [32., 34., 36., 38.]]) # Hadamard积逐元素乘法对应位置相乘 A * B # 计算示例第0行第0列 0.*0.0.第0行第1列 1.*1.1. # 结果 # tensor([[ 0., 1., 4., 9.], # [ 16., 25., 36., 49.], # [ 64., 81., 100., 121.], # [144., 169., 196., 225.], # [256., 289., 324., 361.]]) # 标量与张量运算广播机制 a 2 X torch.arange(24).reshape(2, 3, 4) # 标量加法每个元素都加2 a X # 结果所有元素2形状仍为2×3×4 # tensor([[[ 2, 3, 4, 5], # [ 6, 7, 8, 9], # [10, 11, 12, 13]], # [[14, 15, 16, 17], # [18, 19, 20, 21], # [22, 23, 24, 25]]]) # 标量乘法不改变张量形状 (a * X).shape # torch.Size([2, 3, 4])3.6 降维求和、求均值等操作会沿指定轴消除张量维度称为降维也可通过参数保持维度或计算累积和。# 定义测试向量 x torch.arange(4, dtypetorch.float32) # tensor([0., 1., 2., 3.]) # 向量全局求和所有元素相加 0123 6 x.sum() # tensor(6.) # A tensor([[ 0., 1., 2., 3.], # [ 4., 5., 6., 7.], # [ 8., 9., 10., 11.], # [12., 13., 14., 15.], # [16., 17., 18., 19.]]) # 矩阵全局求和所有元素相加 A.shape # 原形状 torch.Size([5, 4]) A.sum() # 01...19 190 → tensor(190.) # 沿轴0行方向求和消去行维度对每一列的所有行元素求和 A_sum_axis0 A.sum(axis0) # 计算过程 # 第0列0481216 40第1列1591317 45 # 第2列26101418 50第3列37111519 55 A_sum_axis0 # tensor([40., 45., 50., 55.]) A_sum_axis0.shape # 消去轴0形状变为 torch.Size([4]) # 沿轴1列方向求和消去列维度对每一行的所有列元素求和 A_sum_axis1 A.sum(axis1) # 计算过程 # 第0行0123 6第1行4567 22 # 第2行891011 38第3行12131415 54第4行16171819 70 A_sum_axis1 # tensor([ 6., 22., 38., 54., 70.]) A_sum_axis1.shape # 消去轴1形状变为 torch.Size([5]) # 同时沿两个轴求和等价于全局求和 A.sum(axis[0, 1]) # tensor(190.)2. 平均值计算# A tensor([[ 0., 1., 2., 3.], # [ 4., 5., 6., 7.], # [ 8., 9., 10., 11.], # [12., 13., 14., 15.], # [16., 17., 18., 19.]]) # 全局平均值总和 / 元素总数 A.mean() # 190 / 20 9.5 → tensor(9.5000) A.sum() / A.numel() # numel()返回元素总个数结果同上 # 沿轴0求平均值每列的和 / 行数 A.mean(axis0) # tensor([ 8., 9., 10., 11.]) A.sum(axis0) / A.shape[0] # 40/58、45/59 ... 结果同上3. 非降维求和保持维度# A tensor([[ 0., 1., 2., 3.], # [ 4., 5., 6., 7.], # [ 8., 9., 10., 11.], # [12., 13., 14., 15.], # [16., 17., 18., 19.]]) # 沿轴1求和但保留被降维的轴长度变为1 sum_A A.sum(axis1, keepdimsTrue) # 结果5行1列的矩阵而非长度为5的向量 # tensor([[ 6.], # [22.], # [38.], # [54.], # [70.]]) sum_A.shape # torch.Size([5, 1]) # 保留维度后可直接通过广播做归一化每行元素除以该行总和维度数量相同可以进行广播 A / sum_A # 计算示例第0行 0/60, 1/6≈0.1667, 2/6≈0.3333, 3/60.5 # 结果 # tensor([[0.0000, 0.1667, 0.3333, 0.5000], # [0.1818, 0.2273, 0.2727, 0.3182], # [0.2105, 0.2368, 0.2632, 0.2895], # [0.2222, 0.2407, 0.2593, 0.2778], # [0.2286, 0.2429, 0.2571, 0.2714]])4. 累积求和不降维# A tensor([[ 0., 1., 2., 3.], # [ 4., 5., 6., 7.], # [ 8., 9., 10., 11.], # [12., 13., 14., 15.], # [16., 17., 18., 19.]]) # 沿轴0计算累积和不降低维度 A.cumsum(axis0) # 计算过程每个位置 上方所有元素含自身的累加和 # 第0行保持原值 [0., 1., 2., 3.] # 第1行044, 156, 268, 3710 → [4., 6., 8., 10.] # 第2行4812, 6915, 81018, 101121 → [12., 15., 18., 21.] # 后续行以此类推 # 结果 # tensor([[ 0., 1., 2., 3.], # [ 4., 6., 8., 10.], # [12., 15., 18., 21.], # [24., 28., 32., 36.], # [40., 45., 50., 55.]])3.7 点积两个同长向量的点积 对应位置元素相乘后求和最终结果为一个标量可表示加权和、向量夹角余弦等。y torch.ones(4, dtype torch.float32) # 全1向量 tensor([1., 1., 1., 1.]) x torch.arange(4, dtypetorch.float32) # tensor([0., 1., 2., 3.]) # 直接调用点积函数 torch.dot(x, y) # 计算过程0*1 1*1 2*1 3*1 6 → tensor(6.) # 等价实现逐元素相乘后求和 torch.sum(x * y) # 结果同样为 tensor(6.)3.8 矩阵 - 向量积矩阵Am×n与向量xn相乘结果是长度为 m 的向量每个元素等于矩阵对应行与向量的点积。A.shape # 矩阵形状 torch.Size([5, 4]) x.shape # 向量长度 torch.Size([4]) # A tensor([[ 0., 1., 2., 3.], # [ 4., 5., 6., 7.], # [ 8., 9., 10., 11.], # [12., 13., 14., 15.], # [16., 17., 18., 19.]]) # x tensor([0., 1., 2., 3.]) # 矩阵-向量乘法 torch.mv(A, x) # 计算过程每行与向量做点积 # 第0行0*0 1*1 2*2 3*3 0149 14 # 第1行4*0 5*1 6*2 7*3 051221 38 # 第2行8*0 9*1 10*2 11*3 092033 62 # 第3行12*0 13*1 14*2 15*3 0132845 86 # 第4行16*0 17*1 18*2 19*3 0173657 110 # 结果tensor([ 14., 38., 62., 86., 110.])3.9 矩阵 - 矩阵乘法矩阵An×k与Bk×m相乘得到n×m的结果矩阵元素cij A 的第 i 行与 B 的第 j 列的点积。B torch.ones(4, 3) # 4行3列全1矩阵 A.shape, B.shape # torch.Size([5, 4]), torch.Size([4, 3]) # 标准矩阵乘法 torch.mm(A, B) # 计算过程A的每行与B的每列做点积B全为1等价于对A的每行求和 # 第0行结果0123 6 → [6., 6., 6.] # 第1行结果4567 22 → [22., 22., 22.] # 后续行以此类推 # 结果 # tensor([[ 6., 6., 6.], # [22., 22., 22.], # [38., 38., 38.], # [54., 54., 54.], # [70., 70., 70.]])注意矩阵乘法要求「第一个矩阵的列数 第二个矩阵的行数」且与逐元素 Hadamard 积是完全不同的运算。3.10 范数范数用于衡量向量 / 矩阵的「大小」需满足非负性、齐次性、三角不等式深度学习中常用于损失函数、正则项。u torch.tensor([3.0, -4.0]) # 1. L2范数欧几里得范数元素平方和的平方根 torch.norm(u) # 计算过程√(3² (-4)²) √(916) √25 5 → tensor(5.) # 2. L1范数元素绝对值之和 torch.abs(u).sum() # 计算过程|3| |-4| 34 7 → tensor(7.) # 3. Frobenius范数矩阵的L2型范数所有元素平方和的平方根 torch.norm(torch.ones((4, 9))) # 计算过程4×9共36个1平方和为36 → √36 6 → tensor(6.)