python与pytroch相关

1.pytroch模型类

PyTorch 是一个易学且清晰明了的深度学习库。本节讲解如何查看一个模型的结构。 首先,最简单创建模型的方式如下:

复制代码
#导入必要的库
import torch.nn as nn
myNet=nn.Sequential(
    nn.Linear(2,10),#第一层(全连接层):接受两个输入特征,输出10个特征
    nn.ReLU(),#对第一层的输出进行非线性变换,增加网络的表达能力,对第一层的输出进行非线性变换,增加网络的表达能力
    nn.Linear(10,1)#将ReLU层的10个输出特征映射到1个输出特征
    nn.Sigmoid()#将第二层的输出转换为0到1之间的值,常用于二分类问题中将输出转换为概率。
)

一般来说,PyTorch 的模型都会定义成一个类,然后在主函数中直接实例化这个类。比如类是设计图,实例化就是按照这个设 计图做出来的实物。

复制代码
#导入必要的库
import torch
import torch.nn as nn
import torch.nn.functional as F #torch.nn.functional 包含了一些函数式的接口,可以用来构建自定义的前向传播。
#开始定义模型类
class Network(nn.Module):#定义了一个名为 Network 的新类,它继承自 nn.Module。nn.Module 是PyTorch中所有神经网络模块的基类
    def __init __(self):#这行代码调用了父类 nn.Module 的构造函数。
    super(Network,self). __init __()#定义了一个名为 dis 的 nn.Sequential 模型
    self.dis=nn.Sequential(
        nn.Linear(2,32),#nn.Sequential 是一个容器,它按照它们在构造器中传递的顺序执行模块
        nn.LeakyReLU(0.2),#这是一种改进的ReLU函数,它允许负输入有一个小的非零输出,这有助于解决梯度消失问题。参数 0.2 指定了负斜率
        nn.Linear(32,32),
        nn.LeakyReLU(0.2),
        nn.Linear(32,1),
        nn.Sigmoid()#这是一个将输出值压缩到0和1之间的激活函数,通常用于二分类问题的输出层
    )
    #模型包含三个全连接层(nn.Linear)和两个 LeakyReLU 激活函数,最后是一个 Sigmoid 激活函数。每个 nn.Linear 层都指定了输入和输出的特征数量。
    def forward(self,x):
    #forward 方法定义了数据通过模型的前向传播路径。在这个方法中,输入数据 x 通过 dis 序列模型进行处理,然后返回处理后的结果
        x=self.dis(x)
        return x
    #梯度消失(Vanishing Gradients)是深度学习中常见的一个问题,特别是在训练深层神经网络时。这个问题指的是在反向传播过程中,梯度(误差的导数)随着层数的增加而迅速减小
    # 最终变得非常接近于零。当梯度非常小的时候,权重的更新也会非常小,导致网络学习速度极慢,甚至完全停止学习。

下面是一个标准的pytroch模型的定义:

复制代码
#导入必要的库
import torch 
import torch.nn as nn
import torch.nn.functional as F
#开始定义模型类
class Network(nn.Module):## 开始定义模型类
class Network(nn.Module):
    def __init __(self):
    super(Network,self). init__()#__init__ 方法在创建类的新实例时被调用
    self.dis=nn.Sequential(#这里创建了一个 nn.Sequential 容器,它按照它们在构造器中被添加的顺序执行每个模块
        nn.Linear(2,32),#nn.Linear(2, 32) 创建了一个全连接层,它将输入的2维向量转换为32维的向量
        nn.LeakyReLU(0.2),#创建了一个LeakyReLU激活函数,它允许小的梯度值通过,参数0.2是负斜率。
        nn.Linear(32,32),
        nn.LeakReLU(0.2),
        nn.Linear(32,1),#nn.Linear(32, 1) 创建了一个全连接层,它将32维的向量转换为1维的向量。
        nn.Sigmoid()#nn.Sigmoid() 添加了一个Sigmoid激活函数,它将输出值压缩到0和1之间,通常用于二分类问题中。
    )
def forward(self,x):
    x=self.dis(x)
    return x
#在神经网络中,激活函数是用来增加网络的非线性特性的。没有激活函数,即使网络有很多层
# 它也只是一个简单的线性变换,无法解决复杂的非线性问题。

(1)必须要继承 nn.Module 。 所以假设在阅读一个新的PyTorch 编写的代码时,只需要找到nn.Module, 就可以知道代码中定义模型的地方了。

复制代码
#实例化网络
Net=vetwor1()

该模型本质上就是一个函数, 一个映射关系,输入数据时可以根据这个函数关系计算出输出数据。现在创建一些输入数据

复制代码
#创建一些数据
input=torch.FloatTensor(5,2)
print(input)

输入数据

复制代码
output=net(input)

在实例化网络时:net=Network(),这个过程调用了Network 类中的__init_函数。

(2)在网络接收到输入数据input 时,实际上是调用了Network 类中的 forward 函数, 也可以说调用了net 这个实例的forward 函数;forward 函数中的x 其实就是输入数据 input,forward 函数return 回来的值就是 output 值。

复制代码
class Network(nn.Module)
    def __init __(self):
    super(Network,self). __init__()
    self.dis1=nn.Sequential(
        nn.Linear(2,32),
        nn.LeakyReLU(0.2),
        nn.Linear(32,32),
        nn.LeakyReLU(0.2)
    )
    self.dis2=nn.Sequential(
        nn.Linear(16,1),
        nn.Sigmoid()
    )
    def forward(self,x):
        x=self.dis1(x)
        output1=x.view(-1,16)
        output2=self.dis2(output1)
        return output1,output2

2.PyTorch data

对于深度学习,整个流程比较重要的两个部分一个是之前讲的模型的定义,另外一个就 是数据的处理。模型其实对于数据的要求是比较高的, 一个是需要数据的质量高, 一个就是 要求数据的格式统一。

例如, 一个图像分类的卷积模型的输入图片,假设模型输入要求大小为416像素的正方形图片。而原始图片是长方形或者尺寸大小不是416的图片,这样就需要对图片进行一些预处理,比方说在原始图片中剪裁出416的正方形部分或者把原始图片压缩到416像素大小。 这次主要讲解就是PyTorch 中另外两个类,DataLoader类和Dataset类。

复制代码
#训练模型

for epoch in range(num_epoch)
#它用于将一个可迭代对象(如列表、元组或字符串)组合为一个索引序列,同时列出数据和数据下标,通常用于for循环中
    for i,data in enumerate(loader):

第一层循环就是要循环的 epoch 次数,第二层就是要讲的 DataLoader 了,从 DataLoader中用循环的方式不断取出来一个 batch的数据。可以把DataLoader看成[第一 个batch 的数据,第二个 batch 的数据,第三个 batch 的数据....

复制代码
#从dataloader中取数据
#dataloader的实例化
loader=DataLoader(dataset=set,batch size=2)#dataset为数据集

Dataset 就是定义每一个 batch 的数据的。例如:

复制代码
from torch.utils.data import Dataset,DataLoader#导入必要的库
#Dataset 是一个抽象类,用于定义数据集的结构和如何访问数据。DataLoader 是一个迭代器
# 它封装了 Dataset 对象,并提供了批量获取数据、打乱数据、多线程加载等功能。
import os 
class MyDataset1(Dataset):
    def __init__(self):
        self.data=['我','爱','祖','国']
    def __getitem__(self,index):
        return self.data[index]
    def __len__(self):
        return len(self.data)#它返回数据集的总大小。这里它返回 self.data 列表的长度
    #实例化数据集类
    set=MyDataset1()
    loader=DataLoader(dataset=set,batch_size=2)#这里首先创建了 MyDataset1 类的一个实例 set,然后使用 DataLoader 来包装这个实例。
    #DataLoader 的 batch_size=2 参数指定了每个批次的数据项数量
    print("len(loader):",len(loader))
    #从dataloader中抽取batch数据
    for data in loader:
        print(data)
3.激活函数

激活函数其实是神经网络可以拟合任意函数的灵魂。假设一个两输入、 一输出的全连接网络没有激活函数,那么每一层之间的关系都是wx+b 的形式。无论有多少层,每一层 有多少的神经元,最后总可以用y=C₁x₁+c₂x₂+c₃ 这样的公式表示。线性的堆积多少层都是线性的。然而在利用神经网络分类的时候,很多分类界限是非线性的。简单来说, 激活函数可以把线性的关系映射成非线性的,这样神经网络才有能力去逼近任意的函数。

激活函数有几十种之多,这里主要介绍常见的几种激活函数。首先介绍PyTorch 深度学习库中已经封装好的激活函数:

复制代码
import torch.nn as nn
import matplotlib.pyplot as plt#Matplotlib 的 pyplot 模块,它用于绘制图形
#随便定义一个画图函数
def plot(x,y,name=""):
    plt.plot(x,y,'r')#x 是横坐标数据,y 是纵坐标数据,name 是图形的标题。
#函数使用 Matplotlib 的 plot 函数绘制 x 和 y,设置坐标轴的范围,显示网格,并设置标题
    plt.xlim((-2,2))
    plt.ylim((-2,2))
    plt.grid()
    plt.title(name)
x=torch.arange(-2,2,0.01)
Activation=nn.ReLU()#这里创建了一个 ReLU 激活函数的实例
y=Activation(x)#应用 ReLU 激活函数到 x 上,得到 y
plot(x,y,'ReLU')#这里调用之前定义的 plot 函数,传入 x、y 和标题 'ReLU'。
plt.show()#这行代码调用 Matplotlib 的 show 函数,将绘制好的图形显示出来。

四个经典的激活函数:

(1)ReLU: 线性整流单元。由图可以看出,大于零的值经过这个函数没有影响,小于0的值经过这个激活函数会变成0。数学表达:ReLU(x)= max(0,x)。

优点1:ReLU 的收敛速度快于Sigmoid/Tanh (因为Sigmoid 激活函数的最大值只有 1,而ReLU 没有最大值的限制)。

优点2:ReLU 要求的计算量小,因为没有指数运算(见 Sigmoid 的数学表达)。

缺点:ReLU 对于小于0的数据的梯度是0(因为ReLU 的导数在x<0 的时候是0,而 不是因为ReLU 在 x<0 的时候为0)。梯度为0意味着不会再更新,不会再更新意味着梯 度一直是0,这样神经元就"坏死"了,没用了。避免这样情况发生的操作就是设置一个比较 小的学习率。

(2)Sigmoid: 把输入压缩成0~1的值,负无穷映射0,正无穷映射1。数学表达:

优点:非线性的经典激活函数,而且压缩成0~1刚好体现了概率值。在图像分类任务 中,希望模型输出的正是输入图像属于每一个类别的概率。

缺点1:依然是梯度消失问题。与 ReLU 的坏死类似,当输入非常大或者非常小的时候,可以发现 Sigmoid 的导数近乎为0,这样就产生了梯度消失问题。

缺点2:不难发现,因为输出的数据是0~1,所以 Sigmoid 的输出不是0均值的(zero- centered,以0为中心),导致收敛速度缓慢。

缺点3:包含指数运算,计算量大。但是其实这个计算量相对于整个模型的计算,九牛 一毛,这个缺点其实不算什么问题。

3.Tanh: 与 Sigmoid类似。数据的输出范围是-1,1。数学表达:

优点:从图中看到,解决了Sigmoid 的 zero-centered的问题。

缺点:依然存在gradient vanishing 的问题。

4.LeakyReLU: 是 ReLU 的改进版本,为了解决ReLU 的坏死问题,LeakyReLU 在 x<0 的时候用一个较小的斜率(图中的斜率是0.1,不过一般默认是0.01)。

优点:解决了ReLU 的坏死问题。

缺点:x<0 斜率的取值是 一 个问题。这里简单提及 一 下 PReLU 激活函数 ,这是一个可以根据训练过程,自动找到一个好的斜率的 LeakyReLU 。 换句话说,PReLU 的 x<0 部分的斜率也参与到了梯度下降中。

以上就是常见的4种激活函数。最后再提一下 Softmax 激活函数 。这个不与上面的放在一起是因为这个函数的输入要求多个值, 一般用在多分类任务。数学表达式上。

损失函数

均 方 误 差
均方误差(Mean Squared Error,MSE)非常经典,是真实值和估计值的差的平方的期望。数学公式是:

先设置两个变量:

复制代码
a=torch.FloatTensor([1,1,1])
b=torch.FloatTensor([1,2,4])

在上面的两个变量a、b中 ,batch是3。来计算一下a 和b 的均方误差:

复制代码
#定义loss函数
loss_function=nn.MSELoss()
#loss_function=nn.MSELoss(reduction='mean')
print(loss_function(a,b))

就是说如果输入"reduction='sum'", 那么会返回10,MSE 公式中求均值就会变成求 和,上式中就不会先乘以1/3。reduction默认是求均值, 一般使用的也是求均值的版本。

交叉熵

交叉熵是最常见的Loss 函数,经常用来处理多分类问题,当然也 可以处理二分类问题。想象一个多分类的神经网络,这个网络输出层的节点个数应该是与分类任务的类别数量相等,假设这是一个三分类问题(猫、狗、鸟),有一个样本狗的图片,所以这个样本的分类真实值应该是1(如果是猫的话就是0,如果是鸟的话就是2)。

Softmax 的意义就是把这些没有限制的值变成概率值,把模型打分的高低转换成图片 属于某一个类别的概率。图片被模型判断正确的概率越大,交叉熵越小。交叉熵是表明实际输出的概率与期望输出的概率的距离,交叉熵越小,两个概率越接近。

交叉熵CrossEntropy 就是完全等价于一个 Softmax+ 自然对数In+NLLLoss。 一般如果 Softmax 在模型中嵌入了,那就直接可以NLLLoss 作为损失函数。

复制代码
#计算softmax
output=torch.FloatTensor([-1,0.5,2],[-1,0.5,2],[-1,0.5,3])
Softmax=nn.Softmax(dim=1)#dim=1 指定了 Softmax 函数沿着哪个维度(列)进行计算。在这个例子中,我们希望对每一行的元素进行 Softmax 计算,因此 dim=1
output=Softmax(output)#将 Softmax 函数应用于 output 张量,计算每一行的 Softma
print('做一个Softmax:\n{}'.format(output))

#求自然对数
output=torch.log(output)
print('做一个自然对数:\n{}'.format(output))

#计算NLLLoss
NLLLoss=nn.NLLLoss()
output=NLLLoss(output,torch.tensor([1,2]))
print('做一个NLLLoss:{}'.format())

#使用 PyTorch 框架中的 CrossEntropyLoss 函数来计算交叉熵损失
output=torch.FloatTensor([-1,0.5,2],[-1,0.5,3])
loss_function=nn.CrossEntropyLoss()#CrossEntropyLoss 需要两个参数:模型的输出(logits)和目标标签(ground truth labels)。
CE=loss_function(output,torch.tensor([1,2]))#这里调用 loss_function 计算交叉熵损失
#第一个参数是模型的输出 output,第二个参数是目标标签,这里使用 torch.tensor([1, 2]) 表示第一个样本的正确类别是索引 1(对应第二个元素),第二个样本的正确类别是索引 2(对应第三个元素)
print('用CrossEntropyLoss:{}'.format(CE))#这行代码打印出计算得到的交叉熵损失值

在代码中可能会看到这样的代码,在训练的时候调用model.train() 告诉模型现在要开 始训练了,在测试或者验证的时候调用model.eval()告诉模型现在不训练了。

(1)model.train()是启用模型的 BatchNormalization和 Dropout层; (2)model.eval() 是限制模型的BatchNormalization 和 Dropout 层。

在学习了 BN 层之后,可以知道BN 计 算均值和方差是需要一整个 batch 的数据进行计算的。batch是指一次训练或推断中的一组数据样本。

BN的数学公式如下:

gamma 和 beta是训练中学习的参数,在测试过程中,已经训练完成并且固定下来了, 那均值和方差就是用训练集的全部样本来计算均值和方差。Dropout层则更简单,如果是训练过程,就让一定量的神经元失活,即让这个神经元不 再输出内容,在测试过程中,Dropout 层失效,没有神经元失活。假设 Dropout rate=0.2,就是会有20%的神经元失活,那么存活的80%的神经元输出 的值就要除以0.8来抵消有20%神经元失活的事实。

(1)model.train() 启 用 BN 层的训练,并且求取一个 batch 数据的均值和方差; Dropout层正常启用,并且存活的神经元输出值会经过处理来抵消Dropout 失活的影响。

(2)model.eval()限制 BN 层,参数不再学习,使用所有训练数据求取均值和方差; Dropout 禁止使用,不对神经元输出值做任何处理。

注意:一般BN 层和Dropout 层不同时使用。

Python 的命令行库 argparse
复制代码
import argparse

# 创建 ArgumentParser 对象,并设置描述
parser = argparse.ArgumentParser(description='这里一般是讲述代码是干什么的')
# 使用 add_argument 方法添加命令行参数:--name 和 --age
# 每个参数都有一个默认值(default),一个帮助信息(help),以及一个标识符(--name 或 --age)
parser.add_argument('--name', default='啥也没写', help='这里输入你的名字')
parser.add_argument('--age', default='不告诉你我几岁', help='这里输入你的年龄')

# 解析命令行参数
args = parser.parse_args()

# 打印解析后的参数值
print('你的名字:{}'.format(args.name))
print('你的年龄:{}'.format(args.age))

就算有了命令行库,也是可以照常运行代码的。不管遇到什么代码,只要输入"-help"就可以查询如何正确地使用这个命令行,并且查 询到每一个属性的help内容。

相关推荐
Gu Gu Study25 分钟前
ScoutLoop开放域深度研究引擎(agent的初步设计想法)
人工智能·python
HyperAI超神经1 小时前
15亿参数挑战机器人控制,MiniCPM-RobotManip正式开源;覆盖文本/图/视频/动作序列,英伟达发布全模态模型Cosmos3-Edge
人工智能·深度学习·机器人·多模态·图像生成·具身智能·智能体
卷无止境1 小时前
写代码这件事,到底该讲究点什么?
后端·python
卷无止境1 小时前
循环复杂度到底在算什么,Python 代码怎么才能写得让人一看就懂
后端·python
lpfasd1231 小时前
MediaCrawler 项目深度分析
chrome·python·chrome devtools
江畔柳前堤2 小时前
系统的本质——从LTI系统到神经网络
人工智能·深度学习·神经网络·机器学习·计算机视觉·数据挖掘·语音识别
Dxy12393102162 小时前
Python项目打包成EXE完整教程(PyInstaller实战避坑)
开发语言·python
bamb002 小时前
一个项目带你入门AI应用开发01
python
0566463 小时前
Python康复训练——常用标准库
开发语言·python·学习
昆曲之源_娄江河畔3 小时前
Python如何安装flask, pymssql
开发语言·python·flask·pymssql