第 2 章 创建张量
学习目标
- 掌握从列表创建张量:
torch.tensor - 掌握规则序列创建方法:
arange、linspace - 掌握占位与特形张量:
zeros、ones、full、eye - 掌握随机张量:
rand、randn、randint与固定种子 - 理解
dtype与device两个创建时就能指定的属性 - 理解
torch.tensor拷贝与torch.from_numpy共享内存的区别
2.1 从列表创建:torch.tensor
上一章已经用过 torch.tensor(列表)。它接收任何嵌套的 Python 序列,生成对应的张量:
import torch
a = torch.tensor([1, 2, 3]) # 一维
b = torch.tensor([[1, 2, 3], [4, 5, 6]]) # 二维
print(a)
print(b)输出:
tensor([1, 2, 3])
tensor([[1, 2, 3],
[4, 5, 6]])创建时可以直接指定 dtype 和 device:
import torch
c = torch.tensor([1, 2, 3], dtype=torch.float32, device='cpu')
print(c)
print(c.dtype, c.device)输出:
tensor([1., 2., 3.])
torch.float32 cpudevice(设备)是张量存放的位置:cpu 或 cuda:0(GPU)。CPU 上的张量和 GPU 上的张量不能直接参与同一运算,第 11 章会系统处理设备问题,现在只需要知道创建时可以指定。
2.2 规则序列:arange 与 linspace
torch.arange(起点, 终点, 步长) 生成等差数列,含起点、不含终点:
import torch
print(torch.arange(10)) # 0 到 9
print(torch.arange(2, 10, 2)) # 2 开始,步长 2,小于 10输出:
tensor([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
tensor([2, 4, 6, 8])torch.linspace(起点, 终点, 个数) 生成等间隔的指定个数的数,含起点和终点:
import torch
print(torch.linspace(0, 1, 5))输出:
tensor([0.0000, 0.2500, 0.5000, 0.7500, 1.0000])arange 和 linspace 的区别:前者给步长、不问个数,后者给个数、不管步长。浮点运算中 arange 可能因舍入误差少一个数,需要精确等分时优先用 linspace。
2.3 占位与特形张量
这些方法按形状生成张量,形状传一个元组,如 (2, 3) 表示 2 行 3 列:
import torch
print(torch.zeros(3)) # 全 0,长度 3
print(torch.zeros((2, 3))) # 全 0,2 行 3 列
print(torch.ones((2, 2))) # 全 1
print(torch.full((2, 3), 7)) # 全部填 7
print(torch.eye(3)) # 3×3 单位矩阵输出:
tensor([0., 0., 0.])
tensor([[0., 0., 0.],
[0., 0., 0.]])
tensor([[1., 1.],
[1., 1.]])
tensor([[7, 7, 7],
[7, 7, 7]])
tensor([[1., 0., 0.],
[0., 1., 0.],
[0., 0., 1.]])注意两点:
zeros、ones、eye默认是float32;full的 dtype 跟随填充值(填7得到int64,填7.0得到float32)。- 传
3和传(3,)效果相同,但二维必须传元组(2, 3),不能写torch.zeros(2, 3)(见常见错误)。
torch.empty((2, 3)) 也会分配一块 2×3 的内存,但不初始化里面的值,打印出来是随机垃圾数。它只在确定马上会被覆盖时使用,新手先不要用。
2.4 随机张量
三个最常用的随机生成器:
torch.rand(形状):均匀分布,取值在[0, 1)。torch.randn(形状):标准正态分布,均值 0、标准差 1。torch.randint(最小, 最大, 形状):整数均匀分布,含最小、不含最大。
import torch
torch.manual_seed(42)
print(torch.rand(3))
print(torch.randn(3))
print(torch.randint(0, 10, (3,)))输出:
tensor([0.8823, 0.9150, 0.3829])
tensor([-0.8293, -1.6137, -0.2147])
tensor([4, 0, 4])torch.manual_seed(42) 的作用是固定随机种子:只要设置同一个种子,后续随机数序列完全一样。本书所有涉及随机的示例都先设种子,保证输出可复现——这也是你写深度学习代码时让实验可复现的标准做法。
2.5 与 NumPy 互操作
PyTorch 与 NumPy 可以互相转换。两种创建方式行为不同:
import torch
import numpy as np
a = np.arange(3)
t1 = torch.tensor(a) # 拷贝:后续互不影响
a[0] = 99
print("torch.tensor 是拷贝:", t1)
b = np.arange(3)
t2 = torch.from_numpy(b) # 共享内存:改一边,另一边跟着变
b[0] = 99
print("from_numpy 共享内存:", t2)输出:
torch.tensor 是拷贝: tensor([0, 1, 2])
from_numpy 共享内存: tensor([99, 1, 2])反向转换是 张量.numpy():
import torch
t = torch.arange(3)
n = t.numpy()
print(n, type(n))输出:
[0 1 2] <class 'numpy.ndarray'>t.numpy() 也是共享内存。共享内存意味着零拷贝、速度快,但改动一侧会影响另一侧;需要独立数据时用 .clone() 或 torch.tensor(...)。
动手实践
- 用
torch.linspace生成 0 到 10 之间(含端点)的 11 个数,打印并核对首尾。 - 创建 3×4 的全 1 张量,打印
shape和dtype,解释为什么 dtype 是浮点。 - 用
torch.full((2, 4), 3.5)创建张量,打印dtype;再创建torch.full((2, 4), 3),对比两者 dtype。 - 设种子 42,连续调用两次
torch.rand(3),记录输出;重新设种子 42 再调用一次,观察结果是否相同。 - 创建一个 NumPy 数组,用
torch.from_numpy转成张量后修改原数组,观察张量变化;再用torch.tensor重复一遍,对比差异。
常见错误
| 错误写法 | 现象 | 原因 |
|---|---|---|
torch.zeros(2, 3) | TypeError: zeros() received an invalid combination of arguments | 二维形状要传元组 torch.zeros((2, 3)) |
torch.tensor(1, 2, 3) | TypeError: tensor() takes 1 or 2 positional arguments but 3 were given | 列表要加方括号:torch.tensor([1, 2, 3]) |
torch.arange(0, 1, 0.1) 直接用于精确等分 | 最后一个元素可能是 0.9 而不是 1.0 | 浮点步长有舍入误差;等分用 linspace |
期望 torch.tensor(a) 与 NumPy 数组共享内存 | 修改一边另一边不变 | torch.tensor 默认拷贝;要共享用 torch.from_numpy |
忘记 torch.manual_seed(42) | 每次运行随机结果不同 | 随机数默认不可复现;训练/示例要设种子 |
用 torch.empty((2, 3)) 打印出来的值当真实数据 | 出现乱数 | empty 不初始化内存,只能用于确定马上被覆盖的场合 |
章末练习
基础
- 用
torch.arange生成[0, 5, 10, 15, 20]并打印。 - 创建 2×4 的全零张量,打印它的
shape和dtype。 - 用
torch.linspace生成 0 到 1 之间的 10 个数,打印第一个和最后一个元素。
提高
- 设种子 7,生成 5 个标准正态分布的随机数;再设种子 7,生成 5 个,验证两组完全一样,并解释原因。
- 创建
torch.eye(4),打印对角线上的元素(提示:用torch.diagonal或索引,第 3 章会教索引)。如果不允许用新方法,先打印整个矩阵观察规律。
挑战
- 写一个函数
make_batch(rows, cols),返回一个形状(rows, cols)、元素为[0, 1)均匀随机数的 float32 张量,并保证设置相同种子时结果一致。 - 创建一个 NumPy 二维数组并转成张量;在张量上做
+1运算,再打印原 NumPy 数组,解释结果,并说明哪种转换方式会共享内存。
章末自测
每题选择一个最佳答案。本书不附答案:完成后交由老师或 AI 老师批改讲解。
torch.arange(2, 10, 2)的结果是?- A.
tensor([2, 4, 6, 8, 10]) - B.
tensor([2, 4, 6, 8]) - C.
tensor([2, 4, 6]) - D.
tensor([0, 2, 4, 6, 8])
- A.
torch.linspace(0, 1, 5)的结果是?- A.
tensor([0., 0.2, 0.4, 0.6, 0.8, 1.]) - B.
tensor([0., 0.25, 0.5, 0.75, 1.]) - C.
tensor([0., 0.5, 1.]) - D. 报错
- A.
torch.zeros((2, 3)).shape的结果是?- A.
torch.Size([2, 3]) - B.
torch.Size([3, 2]) - C.
torch.Size([6]) - D.
torch.Size([2])
- A.
torch.zeros(3).dtype的结果是?- A.
torch.int64 - B.
torch.float64 - C.
torch.float32 - D.
torch.bool
- A.
torch.full((2,), 7).dtype的结果是?- A.
torch.float32 - B.
torch.int64 - C.
torch.float64 - D.
torch.uint8
- A.
torch.eye(3)生成的是?- A. 全 1 的 3×3 矩阵
- B. 全 0 的 3×3 矩阵
- C. 对角线为 1、其余为 0 的 3×3 矩阵
- D. 长度为 3 的向量
torch.manual_seed(42)的作用是?- A. 让随机数更快
- B. 固定随机种子,结果可复现
- C. 让随机数更均匀
- D. 清除所有随机数
- 下列哪种方式创建的张量与 NumPy 数组共享内存?
- A.
torch.tensor(arr) - B.
torch.from_numpy(arr) - C.
torch.zeros(arr.shape) - D.
arr.copy()
- A.
- 创建 2 行 3 列全 1 张量的正确写法是?
- A.
torch.ones(2, 3) - B.
torch.ones((2, 3)) - C.
torch.ones([2, 3]) - D. B 和 C 都正确
- A.
- 关于
torch.randn(3),正确的说法是?- A. 生成 3 个
[0, 1)均匀随机数 - B. 生成 3 个标准正态分布随机数
- C. 生成 3 个
[0, 10)整数 - D. 生成 3×3 矩阵
- A. 生成 3 个
