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