Pytorch
-
torch.backends.cudnn.deterministic
和torch.backends.cudnn.benchmark
这两个参数,用于固定算法,使每次运行结果都一样。将deterministic
置为True的话,每次返回的卷积算法将是确定的,即默认算法。如果配合上设置 Torch 的随机种子为固定值的话,应该可以保证每次运行网络的时候相同输入的输出是固定的。
benchmark
作用是优化cudnn
的运行,cuda可以加快程序运行速度,自动寻找最适合当前配置的高效算法,来达到优化运行效率的问题。因此将benchmark
设置为True
可以提高运行速度,但是每次运行的cuda底层最优算法可能不同,导致程序的结果可能有一些差异。
所以如果在训练阶段,可以如下设置:def set_seed(myseed=2022): # 设置numpy随机种子 np.random.seed(myseed) # 设置python随机种子 random.seed(myseed) # 固定cuda底层优化算法 torch.backends.cudnn.deterministic = True torch.backends.cudnn.benchmark = False os.environ['CUBLAS_WORKSPACE_CONFIG'] = ':4096:8' # 设置cpu和cuda的随机数种子 torch.manual_seed(myseed) # 用于自查自己的代码是否包含不确定的算法,报错说明有 torch.use_deterministic_algorithms(True) # 固定环境变量种子 os.environ['PYTHONHASHSEED'] = str(myseed)
此外,这里面还有许多固定算法,参考我的注释和这篇博客,这里就不再介绍了。该代码段可以直接复制使用。
-
特别注意,出了固定种子外,还需要固定装载数据集的方法,具体可直接copy以下代码,也可参考pytorch的官网
# 固定装载数据集初始化 def worker_init(worked_id): worker_seed = torch.initial_seed() % 2**32 np.random.seed(worker_seed) random.seed(worker_seed) DataLoader(dataset, batch_size, shuffle, num_workers,pin_memory=True,worker_init_fn=worker_init)
-
在需要生成随机数据的实验中,每次实验都需要生成数据。设置随机种子是为了确保每次生成固定的随机数,参考
深度学习网络模型中初始的权值参数通常都是初始化成随机数,random.seed()、torch.manual_seed()、torch.cuda.manual_seed()、torch.cuda.manual_seed_all()
用法总结(备注,在torch1.8及以后版本中,只使用torch.manual_seed()
就可以同时固定cpu和cuda了)
-
关于
Pytorch
默认的参数初始化问题,参考
用自己的话总结一下:Pytorch中默认会初始化参数,这个初始化在调用神经网络时已经给初始好了,不需要自己手动初始化。系统默认初始化参数时也是用random
的相关函数,这也是为什么我们需要设置seed了,因为设置seed后,每次初始化的参数值是一模一样的。
此外,也可以手动初始化参数。自动初始化参数是可以满足大多数情况的,但是针对有些特定的RNN、CNN的网络,有更适合收敛的参数,因此可以默认,但也可以手动初始化参数。 本人写的手动初始化参数的文章 -
有关报错:
RuntimeError: Trying to backward through the graph a second time (or directly access saved tensors after they have already been freed)
问题。
翻译一下就是:第二次尝试在图中向后遍历时,保存的临时变量已经被释放。
报错的代码如下:feature = feature_extractor(total_data) domain_pred = domain_classifier(feature) loss = critical_domain(domain_pred, total_label) running_D_loss += loss.detach().item() * len(train_data) loss.backward() domain_optimizer.step() label_pred = label_predictor(feature[:train_data.shape[0]]) domain_pred = domain_classifier(feature)
我们在有关GAN或者类似与GAN的运算中,往往会需要不同的神经网络求损失函数,反向传播等。但是执行反向传播(backward)时会释放临时变量,例如上面的程序feature变量在第一次loss.backward()时已经释放了,结果下面又一次调用,这样是不可以的!!
正确的做法是domain_pred = domain_classifier(feature.detach())
或者在调用时重新再写一遍feature = feature_extractor(total_data)
detach阻断了反向传播,这个变量不进行反向传播,也就不释放了呗。 -
with
是上下文管理器,除可用于打开文件,还经常用于with torch.no_grad():
这句话是用在testing神经网络时加上的。神经网络在反向传播时会自动求导,占用内存,在testing时不需要反向传播(自动求导),所以加上这句话更好,当然,加不加不影响结果,可能影响测试速度。 -
squeeze属性
的作用就是对tensor
变量进行维度压缩,去除维数为1的的维度。例如,一个3×2×1×2×1的tensor,squeeze()之后便成了3×2×2。存储的数据并没有发生变化,但是去除了“多余”的维度信息:如果没有为1的维度,则不进行操作。参考 -
nn.Sequential:
一个有序的容器,神经网络模块将按照在传入构造器的顺序依次被添加到计算图中执行
-
深度学习时会看见如下3行代码:
import gc del train, train_label, train_x, train_y, val_x, val_y gc