10.损失函数
损失函数这里列举几个:
class torch.nn.L1Loss(size_average=True)[source]
创建一个衡量输入x
(模型预测输出
)和目标y
之间差的绝对值的平均值的标准。
x
和y
可以是任意形状,每个包含n
个元素。- 对
n
个元素对应的差值的绝对值求和,得出来的结果除以n
。 - 如果在创建
L1Loss
实例的时候在构造函数中传入size_average=False
,那么求出来的绝对值的和将不会除以n
代码如下实例
import torch from torch.nn import L1Loss input=torch.tensor([1,2,3],dtype=torch.float32) output=torch.tensor([1,2,5],dtype=torch.float32) loss=L1Loss() result=loss(input,output) print(result)
运行结果如下图,如果不需要求平均可以这样设置
loss=L1Loss(reduction="sum")
class torch.nn.MSELoss(size_average=True)[source]
创建一个衡量输入x(模型预测输出)和目标y之间均方误差标准。
x 和 y 可以是任意形状,每个包含n个元素。
对n个元素对应的差值的绝对值求和,得出来的结果除以n。
如果在创建MSELoss实例的时候在构造函数中传入size_average=False,那么求出来的平方和将不会除以n
class torch.nn.CrossEntropyLoss(weight=None, size_average=True)
当训练一个多类分类器的时候,这个方法是十分有用的。exp是以e为底的指数函数,在一个猫狗二分类问题中,一个图片经过神经网络模型输出为x[0.5,0.7],其中这张图片的target为0,0代表为猫,1代表为狗,损失函数的计算为-x[0(target)]+ln(exp(x[0])+exp(x[1])。
代码如下
import torch from torch.nn import CrossEntropyLoss x=torch.tensor([0.1,0.2,0.3]) y=torch.tensor([1]) x=torch.reshape(x,(1,3)) loss=CrossEntropyLoss() result=loss(x,y) print(result)
11.反向传播和优化器
反向传播 loss.backward()
优化器一般是使用梯度下降的方法进行优化:在梯度法中,函数的取值从当前位置沿着梯度方向前进一定距离,然后在新的地方重新求梯度,再沿着新梯度方向前进,如此反复,不断地沿梯度方向前进。像这样,通过不断地沿梯度方向前进,逐渐减小函数值的过程就是梯度法(gradient method)。梯度法是解决机器学习中最优化问题的常用方法,特别是在神经网络的学习中经常被使用。根据目的是寻找最小值还是最大值,梯度法的叫法有所不同。严格地讲,寻找最小值的梯度法称为梯度下降法(gradient descent method),寻找最大值的梯度法称为梯度上升法(gradient ascent method)。但是通过反转损失函数的符号,求最小值的问题和求最大值的问题会变成相同的问题,因此“下降”还是“上升”的差异本质上并不重要。一般来说,神经网络(深度学习)中,梯度法主要是指梯度下降法。
反向传播和优化器代码实例如下:
test1=test() #lossFunction模型 loss=nn.CrossEntropyLoss() #优化器模型 optim=torch.optim.SGD(test1.parameters(),0.01) #进行20次优化 for epcho in range (20): running_loss=0.0 for data in dataloader: imgs,t=data output=test1(imgs) loss=loss(output,t) #将每个梯度清为0(初始化) optim.zero_grad() #反向传播,得到每个可调节参数对应的梯度(grad不再是none) loss.backward() #对每个参数进行改变,weight-data被改变 optim.step() #计算每轮优化中每个变量的loss和 running_loss=running_loss+result_loss print(running_loss) output: #总loss在逐渐变小 # tensor(18712.0938, grad_fn= < AddBackward0 >) # tensor(16126.7949, grad_fn= < AddBackward0 >) # tensor(15382.0703, grad_fn= < AddBackward0 >)
12.残差网络
传统的神经网络,由于网络层数增加,会导致梯度越来越小,这样会导致后面无法有效的训练模型,这样的问题成为梯度消弭。为了解决这样的问题,引入残差神经网络(Residual Networks),残差神经网络的核心是”跳跃”+“残差块”。通过引入RN网络,可以有效缓解梯度消失的问题,可以训练更深的网络。
下图是一个基本残差块。它的操作是把某层输入跳跃连接到下一层乃至更深层的激活层之前,同本层输出一起经过激活函数输出。
定义残差模型,根据最基本的残差块,残差中间需要经过卷积->激活->卷积这样的操作,为了保证输入输出大小一致,故中间两个卷积层的输入输出大小都和模型最初输入大小保持一致。
class ResidualBlock(nn.Module): def __init__(self, channels): super(ResidualBlock, self).__init__() self.channels = channels self.conv1 = nn.Conv2d(channels, channels, kernel_size=3, padding=1) self.conv2 = nn.Conv2d(channels, channels, kernel_size=3, padding=1) def forward(self, x): y = F.relu(self.conv1(x)) y = self.conv2(y) return F.relu(x + y)
13.CIFAR10模型结构
下面是利用CIFAR10模型结构进行图像分类数据的训练和预测。
import torch import torchvision from torch import nn from torch.utils.data import DataLoader from torch.utils.tensorboard import SummaryWriter #import自己写的models from p27_1model import * train_data=torchvision.datasets.CIFAR10("../datasets",train=True,transform=torchvision.transforms.ToTensor(), download=True) test_data=torchvision.datasets.CIFAR10("../datasets",train=False,transform=torchvision.transforms.ToTensor(), download=True) #查看数据集长度 train_size=len(train_data) test_size=len(test_data) print("size of train,test is:{},{}".format(train_size,test_size)) #利用dataloader加载 train_dataloader=DataLoader(train_data,64) test_dataloader=DataLoader(test_data,64) #创建网络模型 test1=test() #损失函数 loss_f=nn.CrossEntropyLoss() #优化器 #1e-2=0.01 learning_rate=1e-2 opt=torch.optim.SGD(test1.parameters(),lr=learning_rate,) #设置训练网络的参数 #记录训练次数 train_step=0 #测试次数 test_step=0 #训练轮数 epoch=10 #添加tensoeboard writer=SummaryWriter("train_log") for i in range(epoch): print("第{}轮训练开始".format(i+1)) #训练步骤开始 #有时不必要:test1.train() for data in train_dataloader: imgs,t=data output=test1(imgs) loss=loss_f(output,t) #优化器优化模型 opt.zero_grad() loss.backward() opt.step() train_step=train_step+1 #loss.item更加规范(.item不会打印数据类型,例如tensor(5)) if train_step%100==0: print("训练次数{},loss值为{}".format(train_step,loss.item())) writer.add_scalar("train_loss",loss.item(),train_step) loss_total=0 #测试步骤开始 #有时不必要:test1.eval() total_correct=0 with torch.no_grad(): for data in test_dataloader: imgs,t=data output=test1(imgs) loss=loss_f(output,t) loss_total=loss_total+loss.item() test_step=test_step+1 #argmax参数:1为横向比较,2为纵向比较,output为64,10的矩阵 #output.argmax(1)==t是为了得到[Ture,False,True....]这种形式 #.sum:T为1,F为0 corect=(output.argmax(1)==t).sum() total_correct=total_correct+corect accuracy=total_correct/test_size print("测试集总loss{}".format(loss_total)) writer.add_scalar("test_loss",loss_total,test_step) writer.add_scalar("accuracy",accuracy,test_step) torch.save(test1,"test1{}.pth".format(i)) print("模型已保存")