一、上周工作
训练OpenWFI中的InversionNet网络部分,已完成dataset、network、train其中一部分。
二、本周计划
抄代码提取InversionNet相关代码,继续代码部分内容的学习。主要完成train.py这一部分相关代码。学习了transform、切片、__getitem__等。
三、完成情况
3.1. 测试网络部分数据变换情况
# 测试网络部分
if __name__ == '__main__':
# InversionNet
x = torch.zeros((10, 5, 1000, 70))
model = InversionNet(inchannel= 5)
out = model(x)
print("out: ", out.size())
补充:if __name__ == '__main__':
Python是一种解释型脚本语言,Python程序运行时是从模块顶行开始,逐行进行翻译执行。“__name__”是Python的内置变量,用于指代当前模块。__name__ == '__main__' 就表示在当前文件中,可以在if __name__ == '__main__':条件下写入测试代码,如此可以避免测试代码在模块被导入后执行。即当你要导入某个模块,但又不想改模块的部分代码被直接执行,那就可以将一部分代码放在“if __name__=='__main__':”内部。Python中“if __name__=='__main__':”详细解析 - 知乎 (zhihu.com)
3.2. transforms.py
transforms方法是在Compose类中的call函数调用的。call函数对一组transforms方法循环,img = t(img)就是transforms方法。transforms方法只能接受一个参数,返回一个参数。且当前transforms方法的input是上一个transforms方法的output。
class Compose:
def __init__(self, transforms):
if not torch.jit.is_scripting() and not torch.jit.is_tracing():
_log_api_usage_once(self)
self.transforms = transforms
def __call__(self, img):
for t in self.transforms:
img = t(img)
return img
3.2.1 python中的__init__和__call__
- __init__函数:创建一个类的实例化,每当创建一个类的实例对象python解释器都会主动去调用它(使用此函数第一个参数必须为self)。
- __call__函数:使得类实例对象可以像调用普通函数那样使用。
__call__()
方法的作用是把一个类的实例化对象变成了可调用对象。可调用对象包括自定义的函数、Python 内置函数以及本节所讲的类实例对象。对于可调用对象,实际上“名称()”可以理解为是“名称.call()”的简写。如果类里没有实现__call__()
时,此时的对象p只是类的实例,不是一个可调用的对象,当调用它时会报错:‘Person’ object is not callable.python类中的 __call__()方法运用_python中_call_函数-CSDN博客
3.2.2. [pytorch]-torchvision.transforms.Compose()介绍
torchvision.transforms.Compose()
类的主要作用是串联多个图片变换的操作,可把他看作一种容器,它能够同时对多种数据变换进行组合。传入的参数是一个列表,列表中的元素就是对载入的数据进行的各种变换操作。
3.2.3. 自定义transforms步骤:
- 自定义一个类如LogTransform,结构类似Compose类
- __init__函数:多参数传入
- __call__函数:还是只有一个参数传入,具体实现自定义的transforms方法。
class LogTransform(object):
def __init__(self, k=1, c=0):
self.k = k
self.c = c
def __call__(self, data):
return log_transform(data, k=self.k, c=self.c)
3.3. 通过调试查看dataset.py中数据是如何变化的
了解了数据是如何变化的,理解了getitem部分,在dataloader处会执行__getitem__方法。
3.4. main()
3.4.1 加载数据
基本过程:确定设备,读取json文件,确定数据和标签归一化方式,初始化训练集,加载数据集
RandomSampler——数据随机采样pytorch源码阅读(三)Sampler类与4种采样方式 - 知乎 (zhihu.com)
3.4.2 损失函数、学习率、优化器
MAE也是指L1 Loss损失函数。 它是把目标值与模型输出(估计值)
做绝对值得到的误差。
MSE也是指L2 Loss损失函数,PyTorch中也将其命名为torch.nn.MSELoss
它是把目标值与模型输出(估计值)
做差然后平方得到的误差。
adam适合解决机器学习的各种非凸优化问题
L2正则是一种减少过拟合的一种经典方法,它在损失函数中加入对模型所有权重的平方和,乘以给定的超参数。
AdamW 即 Adam + weight decate,效果与 Adam + L2正则化相同,但是计算效率更高。因为L2正则化需要在loss中加入正则项,之后再算梯度,最后在反向传播。而Adamw直接将正则项的梯度加入反向传播的公式中,省去了手动在loss中加正则项这一步。
class torch.optim.Adam(params, lr=0.001, betas=(0.9, 0.999), eps=1e-08, weight_decay=0)实现Adam算法。
参数:
- params (iterable) – 待优化参数的iterable或者是定义了参数组的dict。注:
如果优化一个网络,网络的每一层看做一个parameter group,一整个网络就是parameter groups(一般给赋值为net.parameters()),net.parameters()函数返回的parameter groups实际上是一个变成了generator的字典。
- lr (float, 可选) – 学习率(默认:1e-3),它控制了权重的更新比率(如 0.001)。较大的值(如 0.3)在学习率更新前会有更快的初始学习,而较小的值(如 1.0E-5)会令训练收敛到更好的性能。
- betas (Tuple[float, float], 可选) – 用于计算梯度以及梯度平方的运行平均值的系数(默认:0.9,0.999),betas = (beta1,beta2),beta1:一阶矩估计的指数衰减率(如 0.9),beta2:二阶矩估计的指数衰减率(如 0.999)。该超参数在稀疏梯度(如在 NLP 或计算机视觉任务中)中应该设置为接近 1 的数。
- eps (float, 可选) – 为了增加数值计算的稳定性而加到分母里的项(默认:1e-8),防止在实现中除以零
- weight_decay (float, 可选) – 权重衰减(L2惩罚)(默认: 0)
在遍历epochs的过程中:先将梯度归零(optimizer.zero_grad()),然后反向传播计算得到每个参数的梯度值(loss.backward()),最后通过梯度下降执行一步参数更新(optimizer.step())。
- optimizer.zero_grad()函数会遍历模型的所有参数,通过p.grad.detach_()方法截断反向传播的梯度流,再通过p.grad.zero_()函数将每个参数的梯度值设为0,即上一次的梯度记录被清空。所以如果不将梯度清零的话,梯度会与上一个batch的数据相关,因此该函数要写在反向传播和梯度下降之前。
- PyTorch的反向传播(即tensor.backward())是通过autograd包来实现的,autograd包会根据tensor进行过的数学运算来自动计算其对应的梯度。如果没有进行tensor.backward()的话,梯度值将会是None,因此loss.backward()要写在optimizer.step()之前。
- step()函数的作用是执行一次优化步骤,通过梯度下降法来更新参数的值。因为梯度下降是基于梯度的,所以在执行optimizer.step()函数前应先执行loss.backward()函数来计算梯度。注:optimizer只负责通过梯度下降进行优化,而不负责产生梯度,梯度是tensor.backward()方法产生的。
理解optimizer.zero_grad(), loss.backward(), optimizer.step()的作用及原理_self.optimizer.step()-CSDN博客
3.4.3 加载模型
3.4.4 训练、评价、保存模型
基本过程:训练模型、损失函数的保存,验证的评价指标的保存
param_groups:Optimizer类在实例化时会在构造函数中创建一个param_groups列表,列表中有num_groups个长度为6的param_group字典(num_groups取决于你定义optimizer时传入了几组参数),每个param_group包含了 ['params', 'lr', 'momentum', 'dampening', 'weight_decay', 'nesterov'] 这6组键值对。
param_group['params']:由传入的模型参数组成的列表,即实例化Optimizer类时传入该group的参数,如果参数没有分组,则为整个模型的参数model.parameters(),每个参数是一个torch.nn.parameter.Parameter对象。
model.eval():
不启用 BatchNormalization 和 Dropout,保证BN和dropout不发生变化,pytorch框架会自动把BN和Dropout固定住,不会取平均,而是用训练好的值,否则一旦test的batch_size过小,很容易就会被BN层影响结果。
3.5. 研读OpenFWI论文摘要、结论等部分
在本文介绍了OPENFWI这是一个开源平台,包含12个数据集和四种深度学习方法的基准测试。发布的数据集具有不同的规模,涵盖了地球物理学的不同领域,并模拟了地下结构的多种场景。目前的基准在一些数据集上显示出了有希望的结果,而其他数据集可能需要进一步改进。
此外,还包括复杂性分析、泛化研究和不确定性量化,以证明我们的数据集和基准的良好特性。最后,讨论了可以用这些数据集研究的现有挑战,并设想了随着OPENFWI的发展,未来的进展。
四、存在的主要问题
问题1:class MinMaxNormalize中vid的值是如何传入的?(已解决)
——解决方法:在dataset.py中 getitem部分中传入的data数据。问题所在:自己忘记了dataset这一部分内容,一直在其他地方debug
五、下一步
utils.py
ssim包
学习率调整
非凸优化问题