nn.DataParallel使用注意

文章详细介绍了如何在PyTorch中使用nn.DataParallel进行多GPU训练,包括环境设置和模型优化器的并行化。同时,讨论了如何正确保存和加载多GPU网络,需要注意使用module属性。接着,文章提到了几种损失函数:clamp用于限制梯度,感知损失PerceptualLoss用于比较深层特征,以及总变分损失TVLoss用于图像平滑。最后,介绍了一种CharbonnierLoss,作为L1损失的鲁棒替代品。
摘要由CSDN通过智能技术生成

nn.DataParallel

如果默认不是序号0的话需要添加
os.environ["CUDA_DEVICE_ORDER"] = "PCI_BUS_ID"
os.environ["CUDA_VISIBLE_DEVICES"] = "2, 3"


device_ids = [0, 1]
model = torch.nn.DataParallel(net, device_ids=device_ids)
model.cuda()

优化器同样可以

optimizer = torch.optim.SGD(net.parameters(), lr=lr)
optimizer = nn.DataParallel(optimizer, device_ids=device_ids)

2. 如何保存和加载多GPU网络?

如何来保存和加载多GPU网络,它与普通网络有一点细微的不同:

net = torch.nn.Linear(10,1)  # 先构造一个网络
net = torch.nn.DataParallel(net, device_ids=[0,3])  #包裹起来
torch.save(net.module.state_dict(), './networks/multiGPU.h5') #保存网络

# 加载网络
new_net = torch.nn.Linear(10,1)
new_net.load_state_dict(torch.load("./networks/multiGPU.h5"))


如果是在多卡上普通的model.state_dict()那么就需要
使用model.state_dict()保存,但是单卡加载的时候,要把模型做并行化(在单卡上并行)

因为DataParallel实际上是一个nn.Module,所以我们在保存时需要多调用了一个net.module,模型和优化器都需要使用net.module来得到实际的模型和优化器。

ncoder = Encoder()
encoder = nn.DataParallel(encoder)
decoder = nn.DataParallel(decoder)
#然后加载参数
checkpoint = torch.load(model_path) #model_path是你保存的模型文件的位置
encoder_state_dict=checkpoint['state_dict_encoder']

encoder.load_state_dict(encoder_state_dict)

3 clamp

– 限制tensor值域,特点:clamp函数在反向传播时候,会把小于min和大于max的值梯度全部变成0,只计算【min,max】之间的,可能是这个解决inf的
在这里插入图片描述

4. 感知损失Perceptual Loss

对于图像数据来说,网络在提取特征的过程中,较浅层通常提取边缘、颜色、亮度等低频信息,而网络较深层则提取一些细节纹理等高频信息,再深一点的网络层则提取一些具有辨别性的关键特征,也就是说,网络层越深提取的特征越抽象越高级。

感知损失就是通过一个固定的网络(通常使用预训练的VGG16或者VGG19),分别以真实图像(Ground
Truth)、网络生成结果(Prediciton)作为其输入,得到对应的输出特征:feature_gt、feature_pre,然后使用feature_gt与feature_pre构造损失(通常为L2损失),逼近真实图像与网络生成结果之间的深层信息,也就是感知信息,相比普通的L2损失而言,可以增强输出特征的细节信息。

import torch
import torch.nn as nn
from torch.autograd import Variable
from torchvision.models import vgg16
import warnings
warnings.filterwarnings('ignore')
# 计算特征提取模块的感知损失
def vgg16_loss(feature_module,loss_func,y,y_):
    out=feature_module(y)
    out_=feature_module(y_)
    loss=loss_func(out,out_)
    return loss

# 获取指定的特征提取模块
def get_feature_module(layer_index,device=None):
    vgg = vgg16(pretrained=True, progress=True).features
    vgg.eval()
    # 冻结参数
    for parm in vgg.parameters():
        parm.requires_grad = False
    feature_module = vgg[0:layer_index + 1]
    feature_module.to(device)
    return feature_module


# 计算指定的组合模块的感知损失
class PerceptualLoss(nn.Module):
    def __init__(self,loss_func,layer_indexs=None,device=None):
        super(PerceptualLoss, self).__init__()
        self.creation=loss_func
        self.layer_indexs=layer_indexs
        self.device=device
    def forward(self,y,y_):
        loss=0
        for index in self.layer_indexs:
            feature_module=get_feature_module(index,self.device)
            loss+=vgg16_loss(feature_module,self.creation,y,y_)
        return loss
if __name__ == "__main__":
    layer_indexs = [3, 8, 15, 22]
    # 基础损失函数:确定使用那种方式构成感知损失,比如MSE、MAE
    loss_func = nn.MSELoss().to(device)
    # 感知损失
    creation = PerceptualLoss(loss_func, layer_indexs, device)
    perceptual_loss=creation(x,y)
    print(perceptual_loss)

5.总变分损失(TV Loss)

TV值和噪声是线性相关的,噪声越大TV值也会越大,所以TV值可以作为在图像复原或超分辨等任务中的一种指导正侧项,TVloss越小则图像噪声越小,图像更加平滑
在这里插入图片描述
只针对单幅图像xi,j表示输入图像中的一个像素点,公式的含义是:分别计算每个像素点xi,j与水平方向(图像的宽W)、垂直方向(图像的高H)的下一个紧邻像素xi,j-1、xi+1,j之间的差的平方,然后开方,针对所有像素求和即可。

import torch
import torch.nn as nn
from torchvision import transforms
import numpy as np
import os
import time
import pathlib
from matplotlib import pyplot as plt
import warnings

np.set_printoptions(threshold=np.inf)
warnings.filterwarnings(action='ignore')


def _tensor_size(t):
    return t.size()[1] * t.size()[2] * t.size()[3]

def tv_loss(x):

    h_x = x.size()[2]
    w_x = x.size()[3]
    count_h = _tensor_size(x[:, :, 1:, :])
    count_w = _tensor_size(x[:, :, :, 1:])
    h_tv = torch.pow((x[:, :, 1:, :] - x[:, :, :h_x - 1, :]), 2).sum()
    w_tv = torch.pow((x[:, :, :, 1:] - x[:, :, :, :w_x - 1]), 2).sum()
    return 2*(h_tv/count_h+w_tv/count_w)


class TV_Loss(nn.Module):
    def __init__(self,TVLoss_weight=1):
        super(TV_Loss, self).__init__()
        self.TVLoss_weight = TVLoss_weight

    def forward(self,x):
        batch_size=x.shape[0]
        return self.TVLoss_weight*tv_loss(x)/batch_size


device=torch.device("cuda" if torch.cuda.is_available() else "cpu")
x=torch.randint(10,size=(1,1,3,3))
x=x.to(device)
print(x)
creation=TV_Loss().to(device)
loss=creation(x)
print(loss)

6.Charbonnier Loss

Charbonnier Loss来近似 L1损失来提高模型的性能,这里就对论文中提到的Charbonnier Loss做一个梳理。
在这里插入图片描述
证明了所提出的具有鲁棒 Charbonnier 损失函数的深度网络可以更好地处理异常值,比L2 损失函数提高 SR 性能。

class L1_Charbonnier_loss(torch.nn.Module):
    """L1 Charbonnierloss."""
    def __init__(self):
        super(L1_Charbonnier_loss, self).__init__()
        self.eps = 1e-6
 
    def forward(self, X, Y):
        diff = torch.add(X, -Y)
        error = torch.sqrt(diff * diff + self.eps)
        loss = torch.mean(error)
        return loss
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值