2023 11.25~12.1 周报

一、上周工作

        训练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__

  1. __init__函数:创建一个类的实例化,每当创建一个类的实例对象python解释器都会主动去调用它(使用此函数第一个参数必须为self)。
  2. __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步骤:

  1. 自定义一个类如LogTransform,结构类似Compose类
  2. __init__函数:多参数传入
  3. __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损失函数。 它是把目标值y_{i}与模型输出(估计值)f(x_{i}) 做绝对值得到的误差。loss(x,y)=\frac{1}{n} \sum_{i=1}^{n} \left |y_{i}-f(x_{i}) \right |

MSE也是指L2 Loss损失函数,PyTorch中也将其命名为torch.nn.MSELoss

它是把目标值y_{i}与模型输出(估计值)f(x_{i}) 做差然后平方得到的误差。loss(x,y)=\frac{1}{n} \sum_{i=1}^{n} (y_{i}-f(x_{i}))^{2}

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包

学习率调整

非凸优化问题

  • 21
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值