1. 张量创建基础:全0与全1张量的生成
在PyTorch中,创建全0或全1张量是最基础的操作之一。torch.zeros()和torch.ones()这两个函数看似简单,但实际使用中有许多细节需要注意。
1.1 torch.zeros()函数详解
创建全0张量的标准语法是:
python复制torch.zeros(*size, *, out=None, dtype=None, layout=torch.strided, device=None, requires_grad=False)
关键参数说明:
- size:张量的维度,可以是一个整数或整数元组
- dtype:数据类型,默认为torch.float32
- device:指定在CPU还是GPU上创建张量
- requires_grad:是否启用梯度计算
实际应用示例:
python复制# 创建一个3x3的全0浮点张量
zero_tensor = torch.zeros(3, 3)
print(zero_tensor)
# 创建一个5维的全0长整型张量,放在GPU上
zero_tensor_gpu = torch.zeros(5, dtype=torch.long, device='cuda')
注意:当不指定dtype时,默认创建的浮点张量是32位精度的。如果需要更高精度,需要显式指定dtype=torch.float64。
1.2 torch.ones()函数详解
创建全1张量的语法与zeros()几乎相同:
python复制torch.ones(*size, *, out=None, dtype=None, layout=torch.strided, device=None, requires_grad=False)
实际应用中的常见场景:
python复制# 创建一个2x2x2的全1张量
ones_tensor = torch.ones(2, 2, 2)
print(ones_tensor)
# 创建一个长度为10的全1布尔张量
bool_tensor = torch.ones(10, dtype=torch.bool)
经验分享:在初始化神经网络权重时,全1张量通常不是好的选择,因为它会导致梯度爆炸。但在某些特定场景,如注意力机制中的掩码处理,全1张量很有用。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 创建指定值的张量
除了全0和全1,我们经常需要创建填充特定值的张量。PyTorch提供了多种方法来实现这一点。
2.1 torch.full()函数
最直接的方法是使用torch.full()函数:
python复制torch.full(size, fill_value, *, out=None, dtype=None, layout=torch.strided, device=None, requires_grad=False)
典型用法示例:
python复制# 创建一个3x3的张量,所有元素都是5.5
filled_tensor = torch.full((3, 3), 5.5)
print(filled_tensor)
# 创建一个填充π值的张量
pi_tensor = torch.full((2, 2), 3.14159)
2.2 其他创建指定值张量的方法
除了full(),还有几种等效的方法:
- 使用乘法操作:
python复制# 等价于torch.full((3,3), 5)
tensor = 5 * torch.ones(3, 3)
- 使用加法操作:
python复制# 创建一个所有元素都是7的张量
tensor = torch.zeros(3, 3) + 7
- 使用fill_()原地操作:
python复制tensor = torch.empty(3, 3)
tensor.fill_(7) # 注意这下划线表示原地操作
性能提示:torch.full()是最直接和高效的方法,特别是在创建大型张量时。其他方法会涉及额外的计算步骤。
3. 张量创建的高级技巧
3.1 设备与数据类型的选择
创建张量时,设备(device)和数据类(dtype)的选择非常重要:
python复制# 在GPU上创建张量的正确方法
if torch.cuda.is_available():
device = torch.device('cuda')
else:
device = torch.device('cpu')
# 创建同时指定设备和数据类型的张量
tensor = torch.zeros(3, 3, dtype=torch.float16, device=device)
常见数据类型选择指南:
- torch.float32:默认浮点类型,适合大多数情况
- torch.float16:半精度浮点,节省内存但精度较低
- torch.int64:长整型,常用于索引
- torch.bool:布尔类型,用于掩码操作
3.2 与其他张量属性对齐
有时我们需要新张量与现有张量具有相同的属性:
python复制existing_tensor = torch.randn(2, 2, dtype=torch.float64, device='cuda')
# 创建与existing_tensor属性相同的新张量
new_tensor = torch.zeros_like(existing_tensor)
类似的函数还有:
- torch.ones_like()
- torch.full_like()
3.3 内存布局考虑
PyTorch支持不同的内存布局,最常见的是strided布局:
python复制# 创建一个非连续内存的张量
tensor = torch.zeros(10, 10).t() # 转置操作会使张量不连续
# 检查内存连续性
print(tensor.is_contiguous()) # 输出False
# 如果需要连续内存,可以使用contiguous()
contiguous_tensor = tensor.contiguous()
4. 常见问题与解决方案
4.1 版本兼容性问题
不同版本的PyTorch可能会有细微差别:
python复制# 检查PyTorch版本
print(torch.__version__)
# 版本特定问题的解决方案
if version.parse(torch.__version__) >= version.parse('1.8.0'):
# 新版本API
tensor = torch.zeros(3, 3, memory_format=torch.channels_last)
else:
# 旧版本回退方案
tensor = torch.zeros(3, 3)
4.2 CUDA与CPU张量转换
python复制# 将CPU张量移动到GPU
cpu_tensor = torch.zeros(3, 3)
gpu_tensor = cpu_tensor.to('cuda')
# 将GPU张量移回CPU
cpu_tensor = gpu_tensor.cpu()
# 更通用的方法
device = 'cuda' if torch.cuda.is_available() else 'cpu'
tensor = tensor.to(device)
4.3 张量形状错误
python复制try:
# 尝试创建非法形状的张量
tensor = torch.zeros(-1, 3)
except RuntimeError as e:
print(f"错误捕获:{e}")
# 合理的错误处理逻辑
tensor = torch.zeros(1, 3)
4.4 内存不足处理
python复制try:
# 尝试分配过大内存
huge_tensor = torch.zeros(100000, 100000)
except RuntimeError as e:
print(f"内存不足:{e}")
# 替代方案:使用更小的批次或不同的数据类型
huge_tensor = torch.zeros(10000, 10000, dtype=torch.float16)
5. 性能优化技巧
5.1 预分配内存
对于需要频繁创建和销毁张量的场景:
python复制# 不好的做法:在循环中重复创建张量
for i in range(1000):
temp = torch.zeros(100, 100)
# 使用temp...
# 好的做法:预分配内存
buffer = torch.zeros(100, 100)
for i in range(1000):
buffer.zero_() # 重用内存
# 使用buffer...
5.2 使用torch.empty()与后续填充
当不需要初始化值时:
python复制# 只分配内存不初始化
tensor = torch.empty(3, 3)
# 后续填充
tensor.fill_(5)
5.3 批量操作优于循环
python复制# 不好的做法:循环创建多个小张量
tensors = [torch.zeros(10) for _ in range(1000)]
# 好的做法:创建一个大张量再分割
big_tensor = torch.zeros(1000, 10)
tensors = torch.split(big_tensor, 1)
6. 实际应用案例
6.1 神经网络初始化
python复制# 自定义初始化
def init_weights(m):
if isinstance(m, torch.nn.Linear):
# 使用均匀分布初始化,而不是全0或全1
torch.nn.init.uniform_(m.weight, -0.1, 0.1)
# 偏置初始化为小的正值
torch.nn.init.constant_(m.bias, 0.01)
model = torch.nn.Sequential(
torch.nn.Linear(10, 20),
torch.nn.ReLU(),
torch.nn.Linear(20, 1)
)
model.apply(init_weights)
6.2 图像处理中的掩码创建
python复制# 创建图像掩码
height, width = 256, 256
mask = torch.zeros(height, width, dtype=torch.bool)
# 中心区域设置为True
center_size = 100
start = (height - center_size) // 2
end = start + center_size
mask[start:end, start:end] = True
6.3 序列填充
python复制# 序列批处理中的填充
sequences = [[1, 2, 3], [4, 5], [6]]
max_len = max(len(seq) for seq in sequences)
# 创建填充后的张量
padded = torch.zeros(len(sequences), max_len, dtype=torch.long)
for i, seq in enumerate(sequences):
padded[i, :len(seq)] = torch.tensor(seq)
7. 调试与验证技巧
7.1 张量属性检查
python复制tensor = torch.zeros(3, 3)
# 检查各种属性
print(f"形状:{tensor.shape}")
print(f"数据类型:{tensor.dtype}")
print(f"设备:{tensor.device}")
print(f"是否启用梯度:{tensor.requires_grad}")
print(f"内存布局:{tensor.is_contiguous()}")
7.2 数值验证
python复制# 验证张量是否全0
tensor = torch.zeros(100, 100)
print(torch.all(tensor == 0)) # 应该返回True
# 验证张量是否全1
tensor = torch.ones(100, 100)
print(torch.allclose(tensor, torch.ones_like(tensor))) # 应该返回True
7.3 梯度验证
python复制# 创建需要梯度的张量
x = torch.zeros(3, requires_grad=True)
y = x.sum()
y.backward()
print(x.grad) # 应该全是1,因为sum()的梯度是1
