RMT的pytorch笔记(不定期更新)

    科技2022-07-15  157

    RMT的pytorch笔记

    序:pytorch是灵活的深度学习开发平台零、用pytorch写一个神经网络完成任务大概要写哪些东西一、准备工作1.1 特殊文件格式简介1.1.1 pkl文件是python的二进制文件1.1.2 npy文件是numpy专用的二进制文件1.1.3 mat文件是matlab的二进制存储文件 1.2 文件操作1.2.1 numpy、pandas初步介绍1.2.2 `import`其他脚本以及其他脚本中的函数1.2.2.1 同根目录的脚本直接导入1.2.2.2 导入上级目录下的脚本需要修改sys.path1.2.2.3 导入同级文件夹下的脚本需要增加__init__.py 1.3 数据的预处理1.2.1 归一化将数据映射到0和1之间1.2.2 标准化将数据映射到标准正态分布上 1.4 使用parser传递参数1.4.1 parser主要用于命令行传参1.4.2 store_true和store_false可以简化布尔型参数的设置1.4.3 从yaml文件中导入args 二、建立数据集需要`from torch.utils.data import Dataset, DataLoader`2.1 建立的dataset对象需要继承Dataset父类2.2 建立dataset需要重写三个函数2.2.1 `__init__()`函数定义数据集的基本信息2.2.2 `__len__()`函数返回数据集的长度2.2.3 `__getitem__()`函数定义了如何获取一个数据 2.2 使用建好的Dataset还需要DataLoader2.2.1 实例化Dataset2.2.2 使用DataLoader2.2.3 对于图像数据的变换可以放进`transforms.Compose()`中 三、建立网络使用`torch.nn`3.1 引言3.2 网络类需要定义`__init__()`和`forward()`3.2 基本的网络搭建使用nn提供的各种层 3.3 整合多个网络层可以使用`nn.Sequential`和`add_module()`3.4 `nn.Conv2d`的参数是in_channels, out_channels, kernel_size, stride, padding3.5 Torchvision是强大的计算机视觉工具包3.5.1 torchvision包含基本的数据集与网络模型 四、优化器4.1

    序:pytorch是灵活的深度学习开发平台

    pytorch是一个灵活的深度学习开发平台,对于张量的操作与科学计算库numpy非常相似,使得这个库比较容易上手。

    本文主要针对pytorch深度学习的初学者,作为笔记而非详细的教程或API,带有较强的个人化倾向和补充性质,对于一些较深的内容往往点到为止,在广度上也并不做特意追求。同时,与其它介绍pytorch的博客的不同之处在于,本文不仅介绍pytorch本身的用法,还结合了作者使用时的经验,增加了许多“周边”内容,比如python本身的一些功能,一些有用的库等等。

    增加这些内容是因为对于经验不深、编程水平有限的读者来说,要想读懂github等平台上的现成项目代码,不仅需要了解与pytorch等深度学习库相关的代码,还要了解背景知识。额外介绍一些与深度学习无关的python附加内容,可以减少读者查阅资料的工作量。

    零、用pytorch写一个神经网络完成任务大概要写哪些东西

    在我自己学习tensorflow与pytorch的时候看了许多教程,有的非常详细。他们会告诉你,什么叫tensor,tensor的运算法则,然后给出一个简单的任务,从库里面调用数据集,等等等等。这样的讲法很细致,但是对于你手头的任务完全没有帮助。因为你所要用到的东西,教程里面可能几乎并没有涉及。这让人非常痛苦。所以首先的,当你使用pytorch完成一个任务的时候,你需要写的代码包括如下几个部分——

    数据集文件:这是你的放在文件夹或各种表格里的数据和pytorch之间的桥梁,API接口配置文件:这里存放你的程序会用到的各种常量,比如训练的轮数、batch_size的大小、学习率的初值与衰减的比例,还有各种文件的路径等等训练脚本:这是用来训练的脚本,这里会定义训练函数train、评估函数eval,还会设置可视化用到的writer与保存模型的函数

    一、准备工作

    1.1 特殊文件格式简介

    1.1.1 pkl文件是python的二进制文件

    pickle库可以生成pkl文件,并以此作为python读取的数据文件。通过pickle.dump()可以存储,而通过先open再pickle.load()可以加载。dump可以存储多种数据,列表、字典、对象等等,使用时,第一个参数代表需要存储的内容,第二个参数代表pkl文件的路径+名称。读取时,一定按照二进制'rb'去open,之后再load.

    import pickle with open(example.pkl, 'rb') as fpkl: info = pickle.load(fpkl)

    通常,训练好的模型参数使用pkl格式,pt格式或pth格式存储。这时候,使用torch.save()和torch.load()函数,在之后会介绍。

    1.1.2 npy文件是numpy专用的二进制文件

    使用np.save()保存,第一个参数是路径+文件名,第二个参数是需要保存的内容。 提取使用np.load() 处理好的数据集往往使用这一格式进行存储。

    1.1.3 mat文件是matlab的二进制存储文件

    在matlab中,使用load()函数打开mat文件,参数为文件的路径+名字,使用save()函数保存文件,第一个参数是文件的路径+名字,第二个参数是需要保存的内容。 在python中,使用scipy.io来进行操作。通过loadmat()和savemat()两个函数对需要保存的内容进行操作,通常会采用字典的形式进行存取。

    1.2 文件操作

    数据的存储有txt,csv,xlsx的格式,此外还有图片,对于图片的处理,本节暂不讨论。

    1.2.1 numpy、pandas初步介绍

    1.2.2 import其他脚本以及其他脚本中的函数

    1.2.2.1 同根目录的脚本直接导入

    对于处在一个文件夹下,没有被包含在子文件夹当中的脚本,可以像库一样直接import。

    1.2.2.2 导入上级目录下的脚本需要修改sys.path

    sys.path.append("..") import mod1

    此处的mod1代表当前脚本的目录的上级目录之前的脚本,需要在sys.path中增加上级目录,然后导入。

    1.2.2.3 导入同级文件夹下的脚本需要增加__init__.py

    对于同级文件夹之下的脚本,也就是“隔壁”的脚本,需要在隔壁文件夹当中增加__init__.py,这个init文件当中不需要写任何内容。但如果在导入这个文件夹之下的脚本时有什么特殊的操作,也可以写在init当中。

    1.3 数据的预处理

    1.2.1 归一化将数据映射到0和1之间

    数据的量级是不同的,量纲也是不同的。一个100量级的数据和一个0.01量级的数据,如果不加处理地输入神经网络,会对网络的表现有所影响。为了避免这种影响,通过归一化消除量级、量纲的影响。

    1.2.2 标准化将数据映射到标准正态分布上

    标准化更进一步,将数据映射到标准正态分布上,用原始数据减去平均数然后除以标准差。 对于一般的数据,使用numpy自己定义标准化函数,或者像下面的代码一样,使用sklearn库进行计算,此处展示了两种scaler方法: 注意:代码来源https://blog.csdn.net/Yellow_python/article/details/81051144

    from sklearn.preprocessing import MinMaxScaler, StandardScaler X = [[0.0, 1], [0.4, 1], [0.6, 9], [0.8, 9]] print(MinMaxScaler().fit(X).transform(X)) print(StandardScaler().fit(X).transform(X))

    如果是想要对于神经网络中的torch tensor进行标准化,需要用到BatchNorm相关的函数,会在之后进行介绍。

    1.4 使用parser传递参数

    1.4.1 parser主要用于命令行传参

    这里暂时不探讨为什么要使用parser以及使用parser的好处,只单纯列举一些用法,如果在阅读代码时遇到,便不至于感到困惑,也可以有样学样用在自己的代码中。

    以下代码初始化了一个parser,向其中写入了一个参数,并导出了这个参数。

    parser = argparse.ArgumentParser(description='parser的描述') parser.add_argument( '--参数(参数的名字,写在两个短横线后,名称内部不区分下划线与短横线)', default='此处填写参数的默认值', help='此处填写参数的介绍') arg = parser.parse_args() # 使用arg.参数名 的形式调用你预设的参数即可

    在命令行中,用这种命令更改你预设的参数:

    python example.py --参数 想要改成的值

    1.4.2 store_true和store_false可以简化布尔型参数的设置

    特别的,对于布尔型参数,可以使用store_true和store_false的default值,在命令行中,如果用上面的双横线形式“提到”了这个参数,那么store_true将把它设为True,store_false将把它设为False。就像下面的代码一样:

    parser = argparse.ArgumentParser(description='parser的描述') parser.add_argument( '--参数(参数的名字,写在两个短横线后,名称内部不区分下划线与短横线)', default='store_true', help='此处填写参数的介绍') arg = parser.parse_args() # 使用arg.参数名 的形式调用你预设的参数即可

    在命令行中:

    python example.py --参数 (对于store_true,只要“提到”,就是True)

    1.4.3 从yaml文件中导入args

    在上一节中提到了parser,parser的使用将函数所使用的参数集中到了一起,既可以在脚本中直接修改默认值,也可以使用命令行进行覆盖。但是这样仍然不够直观与集中,yaml文件为我们提供了新的可能性,它的特性决定了其非常适合作为一种配置文件。关于yaml的具体写法在这里不再详细介绍,如有需要可以参考https://www.cnblogs.com/wxmdevelop/p/7341292.html yaml文件中,一个无缩进的条目对应parser中的一个arg,或者说是args这个字典中的一个key,而缩进的条目则作为其上边第一个缩进少一级的条目的一个key,也就是这个key对应的value也变成一个字典,作为小字典中的一个key。 以下的代码展示了如何使用文件中的配置覆盖掉parser中的default配置,并指出parser中忘记添加的arg:

    with open(yaml文件的路径, 'r') as f: default_arg = yaml.load(f, Loader=yaml.FullLoader) key = vars(p).keys() for k in default_arg.keys(): if k not in key: print('WRONG ARG: {}'.format(k)) assert (k in key) parser.set_defaults(**default_arg)

    二、建立数据集需要from torch.utils.data import Dataset, DataLoader

    注意:此部分参考https://www.jianshu.com/p/2d9927a70594

    2.1 建立的dataset对象需要继承Dataset父类

    class MyDataset(Dataset):

    其中的MyDataset是自定义的数据集的名字,可以根据需要自己定义。

    2.2 建立dataset需要重写三个函数

    2.2.1 __init__()函数定义数据集的基本信息

    在初始化函数中,会将数据集的路径等信息定义为对象的属性,同时也会定义其他之后将要用到的各种属性。需要注意的是,训练集和验证集都会从Dataset类实例化,而其名字的不同是在实例化的时候决定的,而其内容的不同是在init的时候决定的,因此,是通过init时,使用的目录不同或使用的索引文件不同等方式,达到使用同一个类构建训练集和测试集这两个内容不同的数据集的。

    2.2.2 __len__()函数返回数据集的长度

    这个函数是最好写的一个函数,返回一个整数,是数据集的长度。数据集中有多少条数据,就返回几。

    2.2.3 __getitem__()函数定义了如何获取一个数据

    这个函数接收一个index参数,表示取出数据集中的某个序号对应的那一条数据。不同的数据有不同的组织形式,因此在这个函数中需要体现如何拿出一个数据并整理成特定的形式,通常是某个特定长度的numpy array。

    2.2 使用建好的Dataset还需要DataLoader

    2.2.1 实例化Dataset

    实例化Dataset与实例化一个类没有区别,填写好__init__()中需要传进去的参数就可以。

    example_dataset = MyDataset(各种参数)

    2.2.2 使用DataLoader

    example_dataloader = DataLoader(dataset=example_trainset, batch_size=32, shuffle=True, num_workers=4) for i_batch, sample_batch in enumerate(trainset_dataloader): 对每个batch进行操作

    2.2.3 对于图像数据的变换可以放进transforms.Compose()中

    pytorch提供了transforms库对图片进行简单的批处理。此处可以参考https://www.jianshu.com/p/a6996ed4eb37。 而Compose方法可以将分步的操作整合到一起。将每一步操作的方法写成列表,传入Compose当中,就可以得到一个总的Compose,在数据集实例化的时候,作为一个参数init数据集。

    from torchvision.transforms import transforms example_dataset = MyDataset(各种参数, transforms=transforms.Compose([操作1, 操作2]))

    三、建立网络使用torch.nn

    3.1 引言

    一个网络由许多网络层组成,每一个网络层对象都需要各自的参数初始化。 在class的init函数中,完成初始化的工作。另一方面,在使用网络层的时候,有输入和输出,在forward函数中,规定数据的流向。 因此,对于一个网络层,我们要知道两方面的内容:

    它的初始化参数有哪些?值是什么?它的输入数据是什么格式,输出数据又是什么格式?

    先看一段代码,这段代码定义了一个pytorch网络,我们会在之后逐渐介绍如何定义一个网络。 注意:代码参考https://www.jianshu.com/p/f0a78e983b9a

    from torch import nn import torch.nn.functional as F class Net(nn.Module): # 继承父类 def __init__(self): super(Net, self).__init__() # 首先init self.fc1 = nn.Linear(20, 120) # 接着定义网络层 self.fc2 = nn.Linear(120, 64) self.fc3 = nn.Linear(64, 1) self.drop = nn.Dropout(0.3) def forward(self, x): # forward中定义batch数据的流向 x = F.relu(self.fc1(x)) x = F.relu(self.fc2(x)) x = self.drop(x) x = self.fc3(x) return x if __name__ == '__main__': net = Net() print(net)

    3.2 网络类需要定义__init__()和forward()

    3.2 基本的网络搭建使用nn提供的各种层

    3.3 整合多个网络层可以使用nn.Sequential和add_module()

    # 法1 self.seq = nn.Sequential( nn.Conv2d(3, 64, 7, 2, 3, bias=False), nn.BatchNorm2d(64), nn.ReLU(inplace=True), nn.MaxPool2d(3, 2, 1) ) # 法2 self.seq = nn.Sequential() self.seq.add_module('layer_name1', layer1)

    3.4 nn.Conv2d的参数是in_channels, out_channels, kernel_size, stride, padding

    self.conv2d = nn.Conv2d(in_channels=3,out_channels=64,kernel_size=4,stride=2,padding=1)

    3.5 Torchvision是强大的计算机视觉工具包

    3.5.1 torchvision包含基本的数据集与网络模型

    注意,此处参考https://www.cnblogs.com/yjphhw/p/9773333.html

    四、优化器

    4.1

    Processed: 0.014, SQL: 8