在 torch.manual_seed() 之后,以下 PyTorch 函数/操作会受到影响:
1. 随机数生成函数
直接随机数生成
# 所有 torch.*rand* 函数
torch.rand() # [0,1)均匀分布
torch.randn() # 标准正态分布
torch.randperm() # 随机排列
torch.randint() # 整数随机
torch.rand_like() # 类似形状的随机
torch.randn_like() # 类似形状的正态分布
torch.normal() # 正态分布(指定参数)
torch.bernoulli() # 伯努利分布
torch.multinomial() # 多项式分布
torch.poisson() # 泊松分布
示例
torch.manual_seed(123)
print(torch.rand(3)) # tensor([0.2961, 0.5166, 0.2517])
print(torch.randn(3)) # tensor([-1.1885, 0.8498, -1.7125])
print(torch.randperm(5)) # tensor([4, 3, 0, 1, 2])
2. 神经网络初始化函数
torch.nn.Module 的随机初始化
torch.manual_seed(123)
model = torch.nn.Sequential(
torch.nn.Linear(10, 5), # 权重初始化固定
torch.nn.Conv2d(3, 16, 3), # 卷积核初始化固定
torch.nn.BatchNorm2d(16), # 批归一化参数
torch.nn.Embedding(100, 10), # 嵌入层初始化
)
特定初始化方法
import torch.nn.init as init
torch.manual_seed(123)
weight = torch.empty(3, 3)
init.xavier_uniform_(weight) # Xavier初始化固定
init.kaiming_normal_(weight) # Kaiming初始化固定
init.orthogonal_(weight) # 正交初始化固定
3. 数据加载和采样操作
DataLoader 相关
from torch.utils.data import DataLoader, TensorDataset
torch.manual_seed(123)
dataset = TensorDataset(torch.arange(10))
dataloader = DataLoader(
dataset,
batch_size=2,
shuffle=True, # shuffle顺序固定
sampler=RandomSampler(dataset) # 随机采样固定
)
采样器类
from torch.utils.data import RandomSampler, SubsetRandomSampler
torch.manual_seed(123)
# 各种采样器都会固定
sampler1 = RandomSampler(dataset)
sampler2 = SubsetRandomSampler(indices=[0, 1, 2])
4. Dropout 和随机操作层
随机性神经网络层
torch.manual_seed(123)
model = torch.nn.Sequential(
torch.nn.Dropout(p=0.5), # Dropout mask固定
torch.nn.Dropout2d(p=0.3), # 2D Dropout
torch.nn.Dropout3d(p=0.2), # 3D Dropout
torch.nn.AlphaDropout(p=0.1), # Alpha Dropout
)
训练/评估模式影响
dropout = torch.nn.Dropout(0.5)
torch.manual_seed(123)
# 训练模式(使用随机性)
dropout.train()
output = dropout(input) # 固定的Dropout mask
# 评估模式(不使用随机性)
dropout.eval()
output = dropout(input) # 无Dropout,不受种子影响
5. 随机函数和分布
概率分布类
torch.manual_seed(123)
# 各种概率分布
dist = torch.distributions.Normal(0, 1)
sample = dist.sample((3,)) # 采样固定
dist2 = torch.distributions.Categorical(torch.tensor([0.2, 0.3, 0.5]))
sample2 = dist2.sample((5,)) # 采样固定
# 其他分布
torch.distributions.Bernoulli
torch.distributions.Binomial
torch.distributions.Poisson
torch.distributions.Uniform
6. 其他随机操作
索引和选择
torch.manual_seed(123)
x = torch.arange(10)
# torch.choice (注意:Python 3.8+ 中从random迁移)
indices = torch.randint(0, 10, (5,)) # 间接实现选择
# 随机掩码
mask = torch.rand(x.shape) > 0.5 # 布尔掩码固定
矩阵操作
# 随机正交矩阵
torch.manual_seed(123)
torch.nn.init.orthogonal_(torch.empty(3, 3))
# 随机旋转等
7. 特定场景的随机性
自动微分的随机性
# 某些自动微分操作可能有随机性
torch.manual_seed(123)
# 在某些版本的PyTorch中,这些可能有影响:
torch.autograd.Variable # 旧版本
torch.autograd.grad() # 某些情况
CUDA 特定操作
#这段代码是用于设置CUDA(GPU)随机种子,确保在GPU上的随机操作也能复现。
#为什么需要单独设置?CPU和GPU使用不同的随机数生成器
if torch.cuda.is_available():
torch.cuda.manual_seed(123) # 单独设置CUDA种子
torch.cuda.manual_seed_all(123) # 多GPU
# CUDA特定的随机操作
a = torch.cuda.FloatTensor(3, 3).uniform_() # 受CUDA种子影响
8. 不受 torch.manual_seed() 影响的
以下操作需要单独设置种子:
import numpy as np
import random
# 这些不受 torch.manual_seed() 影响
np.random.seed(123) # 需要单独设置
random.seed(123) # 需要单独设置
os.environ['PYTHONHASHSEED'] = '123' # Python哈希种子
# 系统级随机性(如文件读取顺序)
9.注意事项,作用范围
# 只在当前设置后生效
torch.manual_seed(123)
a = torch.rand(3) # 固定
# 改变种子会影响后续操作
torch.manual_seed(456)
b = torch.rand(3) # 新的固定序列
完整示例:验证影响
import torch
def test_seed_effects(seed=123):
torch.manual_seed(seed)
results = {}
# 1. 基本随机数
results['rand'] = torch.rand(3)
results['randn'] = torch.randn(3)
results['randperm'] = torch.randperm(5)
# 2. 初始化
linear = torch.nn.Linear(5, 3)
results['linear_weight'] = linear.weight.clone()
# 3. Dropout
dropout = torch.nn.Dropout(0.5)
dropout.train()
x = torch.ones(10)
results['dropout'] = dropout(x)
# 4. 分布采样
dist = torch.distributions.Normal(0, 1)
results['normal_sample'] = dist.sample((3,))
return results
# 多次运行结果相同
print(test_seed_effects(123)['rand'])
# tensor([0.2961, 0.5166, 0.2517]) - 总是相同
最佳实践
def set_all_seeds(seed=42):
"""设置所有相关种子"""
# PyTorch
torch.manual_seed(seed)
if torch.cuda.is_available():
torch.cuda.manual_seed(seed)
torch.cuda.manual_seed_all(seed)
torch.backends.cudnn.deterministic = True
torch.backends.cudnn.benchmark = False
# 其他库
import numpy as np
import random
np.random.seed(seed)
random.seed(seed)
# Python
import os
os.environ['PYTHONHASHSEED'] = str(seed)
总结:torch.manual_seed() 主要影响所有基于 torch 的随机数生成、初始化、采样和随机操作,但对 numpy.random、Python 内置 random 等库没有影响,需要分别设置。