1.导入必须的包。
2.超参数的统一设置。
-
batch size
-
初始学习率(初始)
-
训练次数(max_epochs)
-
GPU配置
batch_size = 16 lr = 1e-4 max_epochs = 100 #GPU配置 # 方案一:使用os.environ,这种情况如果使用GPU不需要设置 os.environ['CUDA_VISIBLE_DEVICES'] = '0,1' # 方案二:使用“device”,后续对要使用GPU的变量用.to(device)即可 device = torch.device("cuda:1" if torch.cuda.is_available() else "cpu")数据读入
PyTorch数据读入是通过Dataset+Dataloader的方式完成的,Dataset定义好数据的格式和数据变换形式,Dataloader用iterative的方式不断读入批次数据。
用Dataset进行数据读取继承Dataset 类需要override 以下⽅法:
from torch.utils.data import Dataset class trainDataset(Dataset): def __init__(self): #用于向类中传入外部参数,同时定义样本集 def __getitem__(self,index): #用于逐个读取样本集合中的元素,可以进行一定的变换,并将返回训练/验证所需的数据 def __len__(self): #用于返回数据集的样本数用DataLoader来按批次读入数据
val_loader=torch.utils.data.DataLoader(train_data, batch_size=batch_size, num_workers=4, shuffle=True, drop_last=True) # batch_size:样本是按“批”读入的,batch_size就是每次读入的样本数 # num_workers:有多少个进程用于读取数据 # shuffle:是否将读入的数据打乱 # drop_last:对于样本最后一部分没有达到批次数的样本,不再参与训练
PyTorch中的DataLoader的读取可以使用next和iter来完成
import matplotlib.pyplot as plt images, labels = next(iter(val_loader)) print(images.shape) plt.imshow(images[0].transpose(1,2,0)) plt.show()模型的构建
PyTorch中神经网络构造一般是基于 Module 类的模型来完成的。Module 类是 nn 模块里提供的一个模型构造类,是所有神经⽹网络模块的基类,我们可以继承它来定义我们想要的模型。
所有的模型都需要继承torch.nn.Module , 需要实现以下⽅法:
class MyModel(torch.nn.Module): def __init__(self): super(MyModel, self).__init__() # 声明带有模型参数的层(神经网络) def forward(self,x): # 定义模型的前向计算,即如何根据输入x计算返回所需要的模型输出 return model = MyModel()
其中forward() ⽅法是前向传播的过程。在实现模型时,我们不需要考虑反向传播。系统将通过⾃动求梯度⽽自动⽣成反向传播所需的 backward 函数。
损失函数PyTorch中一些常用的损失函数(一般通过torch.nn调用),及每个损失函数的功能介绍、数学公式和调用代码。
L1损失函数功能: 计算输出y和真实标签target之间的差值的绝对值。
torch.nn.L1Loss(size_average=None, reduce=None, reduction='mean')` # ‘reduction’参数决定了计算模式。一共有三种模式: # none:逐个元素计算。 # sum:所有元素求和,返回标量。 # mean:加权平均,返回标量。 # 如果选择‘none’,那么返回的结果是和输入元素相同尺寸的。默认计算方式是求平均。
计算公式
实现代码
loss = nn.L1Loss() input = torch.randn(3, 5, requires_grad=True) target = torch.randn(3, 5) output = loss(input, target) output.backward()
print('L1损失函数的计算结果为',output)
L1损失函数的计算结果为 tensor(1.5729, grad_fn=MSE损失函数)
功能:计算输出y和真实标签target之差的平方。
torch.nn.MSELoss(size_average=None, reduce=None, reduction='mean')
计算公式:
实现代码:
loss = nn.MSELoss() input = torch.randn(3, 5, requires_grad=True) target = torch.randn(3, 5) output = loss(input, target) output.backward()
print('MSE损失函数的计算结果为',output)
MSE损失函数的计算结果为 tensor(1.6968, grad_fn=平滑L1 (Smooth L1)损失函数)
功能: L1的平滑输出,其功能是减轻离群点带来的影响
torch.nn.SmoothL1Loss(size_average=None, reduce=None, reduction='mean', beta=1.0)`
计算公式:
代码实现:
loss = nn.SmoothL1Loss() input = torch.randn(3, 5, requires_grad=True) target = torch.randn(3, 5) output = loss(input, target) output.backward()
print('SmoothL1Loss损失函数的计算结果为',output)
SmoothL1Loss损失函数的计算结果为 tensor(0.7808, grad_fn=目标泊松分布的负对数似然损失 功能: 泊松分布的负对数似然损失函数)
torch.nn.PoissonNLLLoss(log_input=True, full=False, size_average=None, eps=1e-08, reduce=None, reduction='mean') # log_input:输入是否为对数形式,决定计算公式。 # full:计算所有 loss,默认为 False。 # eps:修正项,避免 input 0 为 时,log(input) 为 nan 的情况。
数学公式:
-
当参数log_input=True:
-
当参数log_input=False:
loss = nn.PoissonNLLLoss() log_input = torch.randn(5, 2, requires_grad=True) target = torch.randn(5, 2) output = loss(log_input, target) output.backward()
print('PoissonNLLLoss损失函数的计算结果为',output)
PoissonNLLLoss损失函数的计算结果为 tensor(0.7358, grad_fn=KL散度)
功能: 计算KL散度,也就是计算相对熵。用于连续分布的距离度量,并且对离散采用的连续输出空间分布进行回归通常很有用。
torch.nn.KLDivLoss(size_average=None, reduce=None, reduction='mean', log_target=False) # reduction:计算模式,可为 none/sum/mean/batchmean。 # none:逐个元素计算。 # sum:所有元素求和,返回标量。 # mean:加权平均,返回标量。 # batchmean:batchsize 维度求平均值。
计算公式:
inputs = torch.tensor([[0.5, 0.3, 0.2], [0.2, 0.3, 0.5]]) target = torch.tensor([[0.9, 0.05, 0.05], [0.1, 0.7, 0.2]], dtype=torch.float) loss = nn.KLDivLoss() output = loss(inputs,target)
print('PoissonNLLLoss损失函数的计算结果为',output)
PoissonNLLLoss损失函数的计算结果为 tensor(-0.3335)MarginRankingLoss
功能: 计算两个向量之间的相似度,用于排序任务。该方法计算两组数据之间的差异。
torch.nn.MarginRankingLoss(margin=0.0, size_average=None, reduce=None, reduction='mean') # margin:边界值,x{1}与x{2}之间的差异值。 # reduction:计算模式,可为 none/sum/mean。
计算公式:
loss = nn.MarginRankingLoss() input1 = torch.randn(3, requires_grad=True) input2 = torch.randn(3, requires_grad=True) target = torch.randn(3).sign() output = loss(input1, input2, target) output.backward() print('MarginRankingLoss损失函数的计算结果为',output)
MarginRankingLoss损失函数的计算结果为 tensor(0.7740, grad_fn=多标签边界损失函数)
功能: 对于多标签分类问题计算损失函数。
torch.nn.MultiLabelMarginLoss(size_average=None, reduce=None, reduction='mean') # reduction:计算模式,可为 none/sum/mean。
计算公式:
loss = nn.MultiLabelMarginLoss() x = torch.FloatTensor([[0.9, 0.2, 0.4, 0.8]]) # for target y, only consider labels 3 and 0, not after label -1 y = torch.LongTensor([[3, 0, -1, 1]]) # 真实的分类是,第3类和第0类 output = loss(x, y) print('MarginRankingLoss损失函数的计算结果为',output)
MarginRankingLoss损失函数的计算结果为 tensor(0.4500)二分类损失函数
torch.nn.SoftMarginLoss(size_average=None, reduce=None, reduction='mean')torch.nn.(size_average=None, reduce=None, reduction='mean')
功能: 二分类的 logistic 损失。
计算公式:
inputs = torch.tensor([[0.3, 0.7], [0.5, 0.5]]) # 两个样本,两个神经元 target = torch.tensor([[-1, 1], [1, -1]], dtype=torch.float) # 该 loss 为逐个神经元计算,需要为每个神经元单独设置标签 loss_f = nn.SoftMarginLoss() output = loss_f(inputs, target) print('SoftMarginLoss损失函数的计算结果为',output)
SoftMarginLoss损失函数的计算结果为 tensor(0.6764)优化器
Pytorch很人性化的给我们提供了一个优化器的库torch.optim,在这里面给我们提供了十种优化器。
-
torch.optim.ASGD
-
torch.optim.Adadelta
-
torch.optim.Adagrad
-
torch.optim.Adam
-
torch.optim.AdamW
-
torch.optim.Adamax
-
torch.optim.LBFGS
-
torch.optim.RMSprop
-
torch.optim.Rprop
-
torch.optim.SGD
-
torch.optim.SparseAdam
而以上这些优化算法均继承于Optimizer,下面我们先来看下所有优化器的基类Optimizer。定义如下:
class Optimizer(object): def __init__(self, params, defaults): self.defaults = defaults self.state = defaultdict(dict) self.param_groups = [] # `defaults`:存储的是优化器的超参数 {'lr': 0.1, 'momentum': 0.9, 'dampening': 0, 'weight_decay': 0, 'nesterov': False} # `state`:参数的缓存 # `param_groups`:管理的参数组,是一个list,其中每个元素是一个字典,顺序是params,lr,momentum,dampening,weight_decay,nesterov,
Optimizer还有以下的方法
注意:
-
每个优化器都是一个类,我们一定要进行实例化才能使用,比如下方实现:
class Net(nn.Moddule): ··· net = Net() optim = torch.optim.SGD(net.parameters(),lr=lr) optim.step()
-
optimizer在一个神经网络的epoch中需要实现下面两个步骤:
-
梯度置零
-
梯度更新
-
optimizer = torch.optim.SGD(net.parameters(), lr=1e-5) for epoch in range(EPOCH): ... optimizer.zero_grad() #梯度置零 loss = ... #计算loss loss.backward() #BP反向传播 optimizer.step() #梯度更新训练和评估
完成了上述设定后就可以加载数据开始训练模型了。首先应该设置模型的状态:如果是训练状态,那么模型的参数应该支持反向传播的修改;如果是验证/测试状态,则不应该修改模型参数。在PyTorch中,模型的状态设置非常简便,如下的两个 *** 作二选一即可:
model.train() # 训练状态 model.eval() # 验证/测试状态
我们前面在DataLoader构建完成后介绍了如何从中读取数据,在训练过程中使用类似的 *** 作即可,区别在于此时要用for循环读取DataLoader中的全部数据。
for data, label in train_loader:
之后将数据放到GPU上用于后续计算,此处以.cuda()为例
data, label = data.cuda(), label.cuda()
开始用当前批次数据做训练时,应当先将优化器的梯度置零:
optimizer.zero_grad()
之后将data送入模型中训练:
output = model(data)
根据预先定义的criterion计算损失函数:
loss = criterion(output, label)
将loss反向传播回网络:
loss.backward()
使用优化器更新模型参数:
optimizer.step()
这样一个训练过程就完成了,后续还可以计算模型准确率等指标。
验证/测试的流程基本与训练过程一致,不同点在于:
-
需要预先设置torch.no_grad,以及将model调至eval模式
-
不需要将优化器的梯度置零
-
不需要将loss反向回传到网络
-
不需要更新optimizer
一个完整的训练过程如下所示:
def train(epoch): model.train() train_loss = 0 for data, label in train_loader: data, label = data.cuda(), label.cuda() optimizer.zero_grad() output = model(data) loss = criterion(label, output) loss.backward() optimizer.step() train_loss += loss.item()*data.size(0) train_loss = train_loss/len(train_loader.dataset) print('Epoch: {} tTraining Loss: {:.6f}'.format(epoch, train_loss))
对应的,一个完整的验证过程如下所示:
def val(epoch): model.eval() val_loss = 0 with torch.no_grad(): for data, label in val_loader: data, label = data.cuda(), label.cuda() output = model(data) preds = torch.argmax(output, 1) loss = criterion(output, label) val_loss += loss.item()*data.size(0) running_accu += torch.sum(preds == label.data) val_loss = val_loss/len(val_loader.dataset) print('Epoch: {} tTraining Loss: {:.6f}'.format(epoch, val_loss))
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)