神经网络

一、线性回归案例

我们在机器学习阶段学习了线性回归模型,并且使用scikit-learn的API来使用该模型。
在本章节,我们使用PyTorch的API来手动构建一个线性回归模型。在Pytorch中进行模型构建的整个流程一般分为四个步骤:
1、准备数据集
2、构建要使用的模型
3、设置损失函数和优化器
4、模型训练
在接下来模型构建过程中,我们将
1、使用PyTorch的nn.MSELoss()代替自定义的平方损失函数,
2、使用PyTorch的data.DataLoader代替自定义的数据加载器,
3、使用PyTorch的optim.SGD代替自定义的优化器,
4、使用PyTorch的nn.Linear代替自定义的假设函数。

1)导入工具包

#导入相关模块
import torch from torch.utils.data
import TensorDataset
#构造数据集对象
from torch.utils.data
import DataLoader
#数据加载器
from torch import nn
#nn模块中有平方损失函数和假设函数
from torch import optim
#optim模块中有优化器函数
from sklearn.datasets import make_regression
#创建线性回归模型数据集
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif']=['SimHei']#用来正常显示中文标签
plt.rcParams['axes.unicode_minus']=False#用来正常显示负号

2)数据集构建

def create_dataset():
x,y,coef=make_regression(n_samples=100,n_features=1,noise=10,coef=True,bias=1.5,random_state=0)#将构建数据转换为张量类型
x=torch.tensor(x)
y=torch.tensor(y)
return x,y,coef
if __name__=="__main__":
#生成的数据
x,y,coef=create_dataset()
#绘制数据的真实的线性回归结果
plt.scatter(x,y)
x=torch.linspace(x.min(),x.max(),1000)
y1=torch.tensor([v*coef+1.5 for v in x])
plt.plot(x,y1,label='real’)
plt.grid()
plt.legend()
plt.show()

3)数据加载器构建及模型构建

#构造数据集
x,y,coef=create_dataset()
#构造数据集对象
dataset=TensorDataset(x,y)
#构造数据加载器
#dataset=:数据集对象
#batch_size=:批量训练样本数据
#shuffle=:样本数据是否进行乱序
dataloader=DataLoader(dataset=dataset,batch_size=16,shuffle=True)
#构造模型
#in_features指的是输入张量的大小size
#out_features指的是输出张量的大小size
model=nn.Linear(in_features=1,out_features=1)

4)训练参数设置

#构造平方损失函数
criterion=nn.MSELoss()
#构造优化函数
optimizer=optim.SGD(params=model.parameters(),lr=1e-2)

5)模型训练

epochs=100
#损失的变化
loss_epoch=[]
total_loss=0.0
train_sample=0.0
for _ in range(epochs):
for train_x,train_y in dataloader:
#将一个batch的训练数据送入模型
y_pred=model(train_x.type(torch.float32))
#计算损失值
loss=criterion(y_pred,train_y.reshape(-1,1).type(torch.float32))
total_loss+=loss.item()
train_sample+=len(train_y)
#梯度清零
optimizer.zero_grad()
#自动微分(反向传播)
loss.backward()
#更新参数
optimizer.step()
#获取每个batch的损失
loss_epoch.append(total_loss/train_sample)

6)构建训练模型函数

#绘制损失变化曲线
plt.plot(range(epochs),loss_epoch)
plt.title('损失变化曲线')
plt.grid()
plt.show()
#绘制拟合直线
plt.scatter(x,y)
x=torch.linspace(x.min(),x.max(),1000)
y1=torch.tensor([v*model.weight+model.bi as for v in x])
y2=torch.tensor([v*coef+1.5 for v in x])
plt.plot(x,y1,label='训练')
plt.plot(x,y2,label='真实')
plt.grid()
plt.legend()
plt.show()

二、神经网络前向传播

深度学习神经网络就是大脑仿生,数据从输入到输出经过一层一层的神经元产生预测值的过程就是前向传播(也叫正向传播)。

前向传播涉及到人工神经元是如何工作的(也就是神经元的初始化、激活函数),神经网络如何搭建,权重参数计算、数据形如何状变化。千里之行始于足下,我们一起进入深度学习的知识海洋吧。

1.神经网络
1.1什么是神经网络
人工神经网络(Artificial Neural Network,简写为ANN)也简称为神经网络,(NN),是一种模仿生物神经网络结构和功能的计算模型。

人脑可以看做是一个生物神经网络,由众多的神经元连接而成。各个神经元传递复杂的电信号,树突接收到输入信号,然后对信号进行处理,通过轴突输出信号。

下图是生物神经元示意图:
在这里插入图片描述
1.2人工神经网络

那怎么构建人工神经网络中的神经元呢?
在这里插入图片描述
这个流程就像,来源不同树突(树突都会有不同的权重)的信息,进行的加权计算,输入到细胞中做加和,再通过激活函数输出细胞值。

接下来,我们使用多个神经元来构建神经网络,相邻层之间的神经元相互连接,并给每一个连接分配一个强度,

如下图所示:
在这里插入图片描述
神经网络中信息只向一个方向移动,即从输入节点向前移动,通过隐藏节点,再向输出节点移动。
其中的基本部分是:
1.输入层:即输入x的那一层
2.输出层:即输出y的那一层
3.隐藏层:输入层和输出层之间都是隐藏层
特点是:同一层的神经元之间没有连接。第N层的每个神经元和第N-1层的所有神经元相连(这就是full connected的含义),第N-1层神经元的输出就是第N层神经元的输入。每个连接都有一个权值。

1.3神经元的内部状态值和激活值
在这里插入图片描述
每一个神经元工作时
1、前向传播会产生两个值,内部状态值和激活值;
2、反向传播时会产生激活值梯度和内部状态值梯度。

通过控制
1、每个神经元的内部状态值大小
2、每个神经元的激活值大小
3、每一层的内部状态值的方差
4、每一层的激活值的方差
可让整个神经网络工作的更好
所以下面两个小节,我们将要学习神经元的激活函数,神经元的权重初始化。

2.激活函数
2.1网络非线性因素的理解
激活函数用于对每层的输出数据进行变换,进而为整个网络注入了非线性因素。此时,神经网络就可以拟合各种曲线。如果不使用激活函数,整个网络虽然看起来复杂,其本质还相当于一种线性模型
在这里插入图片描述
在这里插入图片描述
结论:
1.没有引入非线性因素的网络等价于使用一个线性模型来拟合
2.通过给网络输出增加激活函数,实现引入非线性因素,使得网络模型可以逼近任意函数,提升网络对复杂问题的拟合能力
另外通过图像可视化的形式理解:神经网络可视化
在这里插入图片描述
我们发现增加激活函数之后,对于线性不可分的场景,神经网络的拟合能力更强。

2.2常见的激活函数
激活函数主要用来向神经网络中加入非线性因素,以解决线性模型表达能力不足的问题,它对神经网络有着极其重要的作用。
我们的网络参数在更新时,使用的反向传播算法(BP),这就要求我们的激活函数必须可微。
在这里插入图片描述
sigmoid激活函数的函数图像如下:
在这里插入图片描述

从sigmoid函数图像可以得到:
sigmoid函数可以将任意的输入映射到(0, 1)之间,当输入的值大致在<-6或者>6时,意味着输入任何值得到的激活值是差不多的,这样会丢失部分的信息。

比如:输入100和输出10000经过sigmoid的激活值几乎都是等于1的,但是输入的数据之间相差100倍的信息就丢失了。
对于sigmoid函数而言,输入值在[-6, 6]之间输出值才会有明显差异,输入值在[-3, 3]之间才会有比较好的效果。

通过上述导数图像:
我们发现导数数值范围是(0, 0.25),当输入<-6或者>6时,sigmoid激活函数图像的导数接近为0,此时网络参数将更新极其缓慢,或者无法更新。一般来说,sigmoid网络在5层之内就会产生梯度消失现象。而且,该激活函数并不是以0为中心的,所以在实践中这种激活函数使用很少。sigmoid函数一般只用于二分类的输出层。

sigmoid函数的示例代码:

import torch import matplotlib.pyplot as plt
import torch.nn.functional as F
def test():
_,axes=plt.subplots(1,2)
#函数图像
x=torch.linspace(-20,20,1000)
y=F.sigmoid(x)axes[0].plot(x,y)axes[0].grid()axes[0].set_title('Sigmoid函数图像')
#导数图像
x=torch.linspace(-20,20,1000,requires_grad=True)
torch.sigmoid(x).sum().backward()
axes[1].plot(x.detach(),x.grad)axes[1].grid()axes[1].set_title('Sigmoid导数图像)
plt.show()
if __name__=='__main__':
test()

在这里插入图片描述

Tanh的函数图像、导数图像如下:
在这里插入图片描述
由上面的函数图像可以看到:
Tanh函数将输入映射到(-1,1)之间,图像以0为中心在0点对称,当输入大概<-3或者>3时将被映射为-1或者1其导数值范围(0, 1),当输入的值大概<-3或者> 3时,其导数近似0与Sigmoid相比,它是以0为中心的,使得其收敛速度要比Sigmoid快,减少迭代次数。然而,从图中可以看出,Tanh两侧的导数也为0,同样会造成梯度消失。

若使用时,可在隐藏层使用tanh函数,在输出层使用sigmoid函数

import torch
import matplotlib.pyplot as plt
import torch.nn.functional as F
deftest():
_,axes=plt.subplots(1,2)
#函数图像
x=torch.linspace(-20,20,1000)
y=F.tanh(x)
axes[0].plot(x,y)
axes[0].grid()
axes[0].set_title('Tanh函数图像')
#导数图像
x=torch.linspace(-20,20,1000,requires_grad=True)
F.tanh(x).sum().backward()axes[1]
plot(x.detach(),x.grad)axes[1].grid()
axes[1].set_title('Tanh导数图像')
plt.show()
if __name__=='__main__':
test()

在这里插入图片描述
ReLU的函数图像、导数图像如下:
在这里插入图片描述

从上述函数图像可知:
ReLU激活函数将小于0的值映射为0,而大于0的值则保持不变,它更加重视正信号,而忽略负信号,这种激活函数运算更为简单,能够提高模型的训练效率。但是,如果我们网络的参数采用随机初始化时,很多参数可能为负数,这就使得输入的正值会被舍去,而输入的负值则会保留,这可能在大部分的情况下并不是我们想要的结果。

从ReLU的导数图像可以看到:当x<0时,ReLU导数为0,而当x>0时,则存在饱和问题。所以,ReLU能够在x>0时保持梯度不衰减,从而缓解梯度失问题。然而,随着训练的推进,部分输入会落入小于0区域,导致对应权重无法更新,这种现象被称为神经元死亡。

与sigmoid相比,RELU的优势是:
采用sigmoid函数,计算量大(指数运算),反向传播求误差梯度时,求导涉及除法,计算量相对大,而采用Relu激活函数,整个过程的计算量节省很多sigmoid函数反向传播时,很容易就会出现梯度消失的情况,从而无法完成深层网络的训练。Relu会使一部分神经元的输出为0,这样就造成了网络的稀疏性,并且减少了参数的相互依存关系,缓解了过拟合问题的发生。

SoftMax
softmax用于多分类过程中,它是二分类函数sigmoid在多分类上的推广,目的是将多分类的结果以概率的形式展现出来。
公式如下:
在这里插入图片描述
计算方法如下图所示:
在这里插入图片描述
Softmax直白来说就是将网络输出的logits通过softmax函数,就映射成为(0,1)的值,而这些值的累和为1(满足概率的性质),那么我们将它理解成概率,选取概率最大(也就是值对应最大的)节点,作为我们的预测目标类别。

import torch
if __name__=='__main__':
	scores=torch.tensor([0.2,0.02,0.15,0.15,1.3,0.5,0.06,1.1,0.05,3.75])
	probabilities=torch.softmax(scores,dim=0)
	print(probabilities)

程序输出结果:

tensor([0.0212,0.0177,0.0202,0.0202,0.0638,0.0287,0.0185,0.0522,0.0183,0.7392])

2.3其他激活函数
本小节带着同学们了解下常见的激活函数,以及对应的API的使用。
除了上述的激活函数,还存在很多其他的激活函数,如下图所示:
在这里插入图片描述
2.4如何选择激活函数
这么多激活函数,我们应该如何选择呢?

对于隐藏层:
1.优先选择RELU激活函数
2.如果ReLu效果不好,那么尝试其他激活,如Leaky ReLu等。
3.如果你使用了Relu,需要注意一下Dead Relu问题,避免出现大的梯度从而导致过多的神经元死亡。
4.少用使用sigmoid激活函数,可以尝试使用tanh激活函数

对于输出层:
1.二分类问题选择sigmoid激活函数
2.多分类问题选择softmax激活函数
3.回归问题选择identity激活函数

3.参数初始化

我们在构建网络之后,网络中的参数是需要初始化的。
我们需要初始化的参数主要有权重和偏置。偏重一般初始化为0即可,而对权重的初始化则会更加重要,我们介绍在PyTorch中为神经网络进行初始化的方法。
常见的初始化方法有:
.均匀分布初始化:权重参数初始化从区间均匀随机取值。即在均匀分中生成当前神经元的权重,其中d为每个神经元的输入数量。
.正态分布初始化:随机初始化从均值为0,标准差是1的高斯分布中取样,使用一些很小的值对参数W进行初始化。
·全0初始化:将神经网络中的所有权重参数初始化为0。
·全1初始化:将神经网络中的所有权重参数初始化为1。
·固定值初始化:将神经网络中的所有权重参数初始化为某个固定值。·kaiming初始化:也叫做HE初始化。
·HE初始化分为正态分布的HE初始化、均匀分布的HE初始化。
·xavier初始化:也叫做Glorot初始化,该方法的基本思想是各层的激活值和梯度的方差在传播过程中保持一致。它有两种,一种是正态分布的xavier初始化、一种是均匀分布的xavier初始化。

一般我们在使用PyTorch构建网络模型时,每个网络层的参数都有默认的初始化方法,当然同学们也可以通过交给大家的方法来使用指定的方式对网络参数进行初始化。

接下来,我们使用PyTorch调用相关API:

import torch
import torch.nn.functional as F
import torch.nn as nn
#1.均匀分布随机初始化
def test01():
linear=nn.Linear(5,3)
#从0-1均匀分布产生参数
nn.init.uniform_(linear.weight)
print(linear.weight.data)
#2.固定初始化
def test02():
linear=nn.Linear(5,3)nn.init.constant_(linear.weight,5)
print(linear.weight.data)
#3.全0初始化
def test03():
linear=nn.Linear(5,3)
nn.init.zeros_(linear.weight)
print(linear.weight.data)
#4.全1初始化
def test04():
linear=nn.Linear(5,3)
nn.init.ones_(linear.weight)
print(linear.weight.data)
#5.正态分布随机初始化
def test05():
linear=nn.Linear(5,3)
nn.init.normal_(linear.weight,mean=0,std=1)
print(linear.weight.data)
#6.kaiming初始化
def test06():
#kaiming正态分布初始化
linear=nn.Linear(5,3)
nn.init.kaiming_normal_(linear.weight)
print(linear.weight.data)
#kaiming均匀分布初始化
linear=nn.Linear(5,3)
nn.init.kaiming_uniform_(linear.weight)
print(linear.weight.data)
#7.xavier初始化
def test07():
#xavier正态分布初始化
linear=nn.Linear(5,3)
nn.init.xavier_normal_(linear.weight)
print(linear.weight.data)
#xavier均匀分布初始化
linear=nn.Linear(5,3)
nn.init.xavier_uniform_(linear.weight)
print(linear.weight.data)
if __name__=='__main__':
	test07()

4
神经网络搭建和参数计算
4.1
构建简单神经网络
接下来我们来构建如下图所示的神经网络模型:

在这里插入图片描述
编码设计如下:
第一个隐藏层:激活函数使用sigmoid,权重初始化采用标准化的xavier初始化
第二个隐藏层:激活函数采用relu,权重初始化采用标准化的He初始化。输出层如果是二分类,采用softmax做数据归一化。

import torch
import torch.nn as nn
from torchsummary import summary
classModel(nn.Module):
def __init__(self,):
super(Model,self).__init__()
self.linear1=nn.Linear(3,3)
nn.init.xavier_normal_(self.linear1.weight)
self.linear2=nn.Linear(3,2)
nn.init.kaiming_normal_(self.linear2.weight)
self.out=nn.Linear(2,2)
def forward(self,x):
#数据经过第一个线性层
x=self.linear1(x)
x=torch.sigmoid(x)
#数据经过第二个线性层
x=self.linear2(x)
x=torch.relu(x)
#数据经过输出层
x=self.out(x)
x=torch.softmax(x,dim=-1)
return x

4.2观察数据形状变化

if __name__=="__main__":
#实例化model对象
mymodel=Model()
#随机产生数据
mydata=torch.randn(5,3)
#数据经过网络
output=mymodel(mydata)
print('mydata.shape--->',mydata.shape)
print('output.shape--->',output.shape)
print('mydata--->\n',mydata)
print('output--->\n',output)
print('-'*50)
summary(mymodel,input_size=(3,),batch_size=5)

观察程序输入和输出的数据形状变化
输入5行数据,出来也是5行数据
输入5行数据3个特征,经过第一个隐藏层是3个特征,经过第二个隐藏层是2个特征,经过输出层是2个特征。
模型最终预测结果是:5行2列数据

mydata.shape--->torch.Size([5,3])
output.shape--->torch.Size([5,2])
mydata--->tensor([[-0.3714,-0.8578,-1.6988],[0.3149,0.0142,-1.0432],[0.5374,-0.1479,-2.0006],[0.4327,-0.3214,1.0928],[2.2156,-1.1640,1.0289]])
output--->tensor([[0.5095,0.4905],[0.5218,0.4782],[0.5419,0.4581],[0.5163,0.4837],[0.6030,0.3970]],grad_fn=<SoftmaxBackward>)

4.3计算模型参数
观察模型的参数

----------------------------------------------------------------
Layer(type)                OutputShape                  Param
#
================================================================
Linear-1[5,3]12
Linear-2[5,2]8
Linear-3[5,2]6
================================================================
Total params:26
Trainable params:26
Non-trainable params:0
----------------------------------------------------------------
Input size(MB):0.00
Forward/backward pass size(MB):0.00
Paramssize(MB):0.00
Estimated Total Size(MB):0.00
----------------------------------------------------------------

在这里插入图片描述
在这里插入图片描述
4.4查看模型参数
通常继承nn.Module,撰写自己的网络层。它强大的封装不需要我们定义可学习的参数(比如卷核的权重和偏置参数)。
如何才能查看封装好的,可学习的网络参数哪?–>模块实例名.name_parameters(),会分别返回name和parameter:

if __name__=="__main__":
#实例化model对象
mymodel=Model()
#查看网络参数
for name,parameter in mymodel.named_parameters():
#print('name--->',name)
#print('parameter--->',parameter)
print(name,parameter)

结果显示

linear1.weightParametercontaining:
tensor([[0.1715,-0.3711,0.1692],[-0.2497,-0.6156,-0.4235],[-0.7090,-0.0380,0.4790]],requires_grad=True)
linear1.biasParametercontaining:
tensor([-0.2320,0.3431,0.2771],requires_grad=True)
linear2.weightParametercontaining:
tensor([[-0.5044,-0.7435,-0.6736],[0.6908,-0.1466,-0.0019]],requires_grad=True)
linear2.biasParametercontaining:
tensor([0.2340,0.4730],requires_grad=True)
out.weightParametercontaining:
tensor([[0.5185,0.4019],[-0.4313,-0.3438]],requires_grad=True)
out.biasParametercontaining:
tensor([0.4521,-0.6339],requires_grad=True)

5优缺点
优点
精度高,性能优于其他的机器学习算法,甚至在某些领域超过了人类
可以近似任意的非线性函数随之计算机硬件的发展,
近年来在学界和业界受到了热捧,有大量的框架和库可供调。
缺点
黑箱,很难解释模型是怎么工作的
训练时间长,需要大量的计算资源
网络结构复杂,需要调整超参数
部分数据集上表现不佳,容易发生过拟合

三、神经网络损失函数

1、损失函数概念

在这里插入图片描述

在深度学习中,损失函数是用来衡量模型参数的质量的函数,衡量的方式是比较网络输出和真实输出的差异,损失函数在不同的文献中名称是不一样的,主要有以下几种命名方式:

在这里插入图片描述

2、分类任务损失函数

在深度学习的分类任务中使用最多的是交叉熵损失函数,所以在这里我们着重介绍这种损失函数。
2.1多分类任务损失函数
在多分类任务通常使用softmax将logits转换为概率的形式,所以多分类的交叉熵损失也叫做softmax损失,它的计算方法是:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在pytorch中使用nn.CrossEntropyLoss()或nn.NLLLoss()实现,如下所示:

#导包
import torch
import torch.nn as nn
import torch.nn.functional as F
#多分类交叉熵损失:
#1)使用nn.CrossEntropyLoss()实现。多分类交叉熵损失=nn.CrossEntropyLoss()=softmax+损失计算(-,log)
#2)使用nn.NLLLoss()实现。多分类交叉熵损失=nn.NLLLoss()+softmax+损失计算(log)
def test01():
#设置真实值:可以是热编码后的结果,也可以不进行热编码
#y_true=torch.tensor([[0,1,0],[0,0,1]],dtype=torch.long)
y_true=torch.tensor([1,2],dtype=torch.long)y_pred=torch.tensor([[1.04,1.95,1.01],[1.1,1.8,1.1]],dtype=torch.float32)
print('y_true--->',y_true,y_true.shape)
print('y_pred--->',y_pred,y_pred.shape)
#1手工验算
print('-'*50)
print(torch.softmax(y_pred,dim=-1))
#tensor([[0.2245,0.5577,0.2178],
#[0.2491,0.5017,0.2491]])
#手工验证:log以e为底不是log以10为底
#-((0*log0.2245+1*log0.5577+0*log0.2178)+(0*log0.2491+0*log0.5017+1*log0.2491))
a=-((0*F.math.log(0.2245)+1*F.math.log(0.5577)+0*F.math.log(0.2178))+\(0*F.math.log(0.2491)+0*F.math.log(0.5017)+1*F.math.log(0.2491)))
print('\n手工验证:平均损失a--->',a/2,'log以e为底')
print('\n手工验证:损失a--->',a,'log以e为底')
print('--------------------------------------------------')
#2nn.CrossEntropyLoss()
#实例化交叉熵损失
loss1=nn.CrossEntropyLoss()
#默认求平均损失
#loss1=nn.CrossEntropyLoss(reduction='sum')
#计算损失结果
my_loss1=loss1(y_pred,y_true).numpy()
print('nn.CrossEntropyLoss():my_loss1--->',my_loss1)
#3nn.NLLLoss()
#实例化交叉熵损失:仅仅实现负号的功能
loss2=nn.NLLLoss()
#loss2=nn.NLLLoss(reduction='sum')
#计算损失结果
my_loss2=loss2(F.log_softmax(y_pred,dim=-1),y_true).numpy()
print('nn.NLLLoss():my_loss2--->',my_loss2)

输出结果:

y_true--->tensor([1,2])
torch.Size([2])
y_pred--->tensor([[1.0400,1.9500,1.0100],[1.1000,1.8000,1.1000]])
torch.Size([2,3])
tensor([[0.2245,0.5577,0.2178],[0.2491,0.5017,0.2491]])
手工验证:平均损失a/2--->0.9869174761503157log以e为底
手工验证:损失a--->1.9738349523006313log以e为底
--------------------------------------------------
nn.CrossEntropyLoss():
my_loss1--->0.98685086
nn.NLLLoss():my_loss2--->0.98685086

2.2二分类任务损失函数
在处理二分类任务时,我们不在使用softmax激活函数,而是使用sigmoid激活函数,那损失函数也相应的进行调整,使用二分类的交叉熵损失函数:
在这里插入图片描述

#二分类交叉熵损失:
#1)使用nn.BCEWithLogitsLoss()实现。
#2)使用nn.BCELoss()实现。需要手动实现sigmoid
def test02():
#设置真实值和预测值
y_pred=torch.tensor([1.6901,-0.5459,-0.2469],
requires_grad=True)
y_true=torch.tensor([0,1,0],dtype=torch.float32)
#1手工验证
#loss=-ylog(y^)-(1-y)log(1-y^)
a=-0*F.math.log(0.8442)-(1-0)*F.math.log(1-0.8442)\-1*F.math.log(0.3668)-(1-1)*F.math.log(1-0.3668)\-0*F.math.log(0.4386)-(1-0)*F.math.log(1-0.4386)
print('损失a--->',a)
print('平均损失a/3--->',a/3)
print('--------------------------------------------------')
#2nn.BCEWithLogitsLoss()
#实例化二分类交叉熵损失
loss1=nn.BCEWithLogitsLoss()
#计算损失不需要再对y_pred加入Sigmoid函数
my_loss1=loss1(y_pred,y_true)
print('nn.BCEWithLogitsLoss():my_loss1--->',my_loss1)
#3nn.BCELoss()
#实例化二分类交叉熵损失:不包含Sigmoid
#因是一个概率分布,在数据输入损失函数之前,需要经过一下Sigmoid来把输出值变成0~1之间
loss2=nn.BCELoss()
#计算损失
my_loss2=criterion(torch.sigmoid(y_pred),y_true)
#注意使用sigmoid,不是softmax
print('nn.BCELoss():my_loss2--->',my_loss2)

输出结果:

损失a--->3.4394422991996714
平均损失a/3--->1.1464807663998904
--------------------------------------------------
nn.BCEWithLogitsLoss():my_loss1--->tensor(1.1465,grad_fn=<BinaryCrossEntropyWithLogitsBackward>)
nn.BCELoss():my_loss2--->tensor(1.1465,grad_fn=<BinaryCrossEntropyBackward>)

在这里插入图片描述
在这里插入图片描述
在pytorch中使用nn.L1Loss()实现,如下所示:

#APi功能计算算inputs与target之差的绝对值
#主要参数:reduction计算模式可为none、sum、mean
#none:逐个元素计算
#sum:所有元素求和,返回标量
#mane:加权平均,返回标量
def test03():
#1设置真实值和预测值
y_pred=torch.tensor([1.0,1.0,1.9],requires_grad=True)
y_true=torch.tensor([2.0,2.0,2.0],dtype=torch.float32)
#2实例MAE损失对象
loss=nn.L1Loss()
#3计算损失
my_loss=loss(y_pred,y_true)
print('myloss--->',my_loss)

输出结果:

myloss--->tensor(0.7000,grad_fn=<L1LossBackward>)

在这里插入图片描述
在这里插入图片描述
在pytorch中通过nn.MSELoss()实现:

def test04():
#1设置真实值和预测值
y_pred=torch.tensor([1.0,1.0,1.9],requires_grad=True)
y_true=torch.tensor([2.0,2.0,2.0],dtype=torch.float32)
#2实例MAE损失对象
loss=nn.MSELoss()
#3计算损失
my_loss=loss(y_pred,y_true)
print('myloss--->',my_loss)

输出结果:

myloss--->tensor(0.6700,grad_fn=<MseLossBackward>)

在这里插入图片描述
在这里插入图片描述
在pytorch中使用nn.SmoothL1Loss()计算该损失,如下所示:

def test05():
#1设置真实值和预测值
y_true=torch.tensor([[0],[1]])
y_pred=torch.tensor([[0.6],[0.4]],requires_grad=True)
#2实例smmothL1损失对象
loss=nn.SmoothL1Loss()
#3计算损失
my_loss=loss(y_pred,y_true)
print('myloss--->',my_loss)
#手工验证:
#总损失:(0.5*(0.6-0)^2+0.5*(0.4-1)^2)=(0.18+0.18)=0.3
mysquare=torch.square(torch.tensor([0.6,0.6]))*0.5
my_loss2=torch.mean(mysquare)
print('2个样本,手工计算损失my_loss2--->',my_loss2.numpy())

输出结果:

myloss--->tensor(0.1800,grad_fn=<SmoothL1LossBackward>)
2个样本,手工计算损失my_loss2--->0.18
  • 13
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值