当前位置: 首页>后端>正文

2.各个组件和实战

3 主要组成模块

模块的学习,承接的是tensor,正如张朝阳说的“有些东西你不懂,是因为你不知道所有问题都是由基本单元组成的,这个和你每天吃饭坐地铁上班的流程一样”,大致意思是这样哈,也就是你分成微小单位的时候,这个问题就不难了。

之前的学习,我就是遇到这样的弯路,面对各个模块,就只学只记模块,但是怎么记得完呢,而且有时候也不理解啊。

回到正题,深度学习模型其实是由tensor和函数组成的,有些特别常用的,就可以写成模块,直接用就行。

torch.utils.data.Dataset

主要作用:数据导入。说点不一样的,你们知道为什么数据导入还用得着写个类么?原来我也不懂,直接导入不行嘛,再不济,搞个函数,行不。嗯,其实还真不行,因为对于机器学习尤其是表格数据来说,数据占用内存很低(对你姑且可以理解为内存条也可以理解为cuda内存),但是图像就不行了,都读进去太大了,这就需要“可迭代对象”这个东西,配合迭代器进行一批一批的导入,而不是那种全搞进去,所以你姑且也可以把dataset理解为构建可迭代对象,dataload理解为迭代器。

这里多说一句,为什么要分批次,只是因为内存不够大吗?其实不仅仅,所有导入计算损失,相当于建立了一个超大的“方程组,对就是你第一反应的方程组”,而分批次相当于抽样,每次都是小部分的方程组,传统是基于整体方程组优化,这样极其容易过拟合,分批次就不同了,本次的梯度用完就释放了(还得手动,后面会有),下个批次再计算自己的梯度,这样不容易过拟合,因为“多样化”,对很牛逼的多样化,我曾一度认为分批次才是对梯度下降最大的优化。不每一步沿着同一批数据的梯度走到底,挺好!

回到正题:Dataset类。主要包含三个函数:①__init__: 用于向类中传入外部参数,同时定义样本集;②__getitem__: 用于逐个读取样本集合中的元素,可以进行一定的变换,并将返回训练/验证所需的数据;③__len__: 用于返回数据集的样本数

2.各个组件和实战,第1张

看到没,上面就是对于Dataset类的集成,在pytorch中所有的程序都是以这样形式进行编写的,也就是说pytorch其实已经把需要的模块都写了基础的类,你需要做的就是集成然后组装和改写,真是太贴心了。

什么?不知道上面那个Dataset类是哪里来的,fromtorch.utils.data.datasetimportDataset,就本小结标题的那个

torch.utils.data.DataLoader

基础的思想同上,但实际应用时候更简单,因为没多少可做的,类似sklearn中的from sklearn.model_selection import train_test_split

对照下面的应用程序,你说像不像,只不过会需要返回批次的image和label

fromtorch.utils.dataimportDataLoadertrain_loader=torch.utils.data.DataLoader(train_data,batch_size=batch_size,num_workers=4,shuffle=True,drop_last=True)val_loader=torch.utils.data.DataLoader(val_data,batch_size=batch_size,num_workers=4,shuffle=False)

对了,transformer类集成后对图像进行变化,应该是在dataset中

torch.nn

思想不用多说了,也是先继承pytorch中已有的模块类,再自己搭建,对,这里没有多少人重写,就是搭建,有牛逼的人比如何开明团队会写自己的resnet残差模块,当然后续很快就有人复现和发布这个模块了,这也就是很多论文中“xx is all you need”,怎么办,直接搞来用,搭建一下网络,论文搞起来

2.各个组件和实战,第2张
以上的 MLP 类中?须定义反向传播函数。系统将通过?动求梯度?自动?成反向传播所需的 backward 函数(在优化里调用grad,所以反向传播也在优化部分里

前面我说了要对照最基本单元tensor,然而你会发现,这里既没有reauires_grad,同时也没用backward(),真的是令人sad又happy,高兴的是可以这么方便的进行网络搭建,忧伤的是,既然在使用中不会用到这么多基础知识,为什么上来先搞了那么多背景知识削弱了极大积极性,努力搞懂学完了,实际中又不用,这不是欺负老实人嘛!!!不好意思,从情理上确实是这样,当然这样是很多教材的通病,我一直人为,真实的教材应该是这样的,先搞项目,然后再在后面结合项目步骤一一讲解,而不是反过来,或许有些反常识,但这才是最快的,如果你身边有人一对一讲,那你怎样都行,如果你身边没人,完全自学就像我一样,真的很想有一个类似国外那个左边讲解右边工程程序的书,希望未来会有吧,十年之内没的话,我就自己写一本

torch.optimizer

上图备注里说了,反向传播在这里,所以你在网络搭建的时候自然就没看见forward(),这里纠正前面一个说法,确实是隐含在模块里了,不过不是隐含在搭建模型里而是在optimizer里,惊不惊喜,意不意外,我完全自学的时候有段时间就疑惑这个

回到正题,loss=criterion(label,output);loss.backward();optimizer.step(),再次纠正,backward好像是在loss中,也就是module是前向搭建,loss就是反向传播,而optmizer则是优化达到目的常用Adam和SGD

注:上面写的比较简略甚至有些口语化,是因为我在纯自学流程中已经淌了不少浑水,有同样困难的可以联系我

4 基础实战

基础实战——FashionMNIST时装分类

任务类型:图像分类,10类

数据集:训练集共60,000张图像,测试集共10,000张图像。每张图像均为单通道黑白图像,大小为28*28pixel

下载地址:Fashion MNIST | Kaggle?或者?fashion-mnist/data/fashion at master · zalandoresearch/fashion-mnist (github.com)

4.1 首先是导入包

2.各个组件和实战,第3张
Dataxx-输入导入,torch.nn-网络搭建,torch.optim-反向传播优化,齐活

4.2 配置环境和超参数

2.各个组件和实战,第4张

4.3 读取数据

有两种方式:(1)如果只是想尽快验证自己的模型,那么就用pytorch内置数据集;

(2)如果想做任务,为落地做准备,就自己构建Dataset类;

以上会涉及对图像的预处理,包含不仅限于:统一大小、数据都转为tensor等,这些都可以用torchvision完成,所以还需要from torchvison import transforms

2.各个组件和实战,第5张

注:前面说的pytorch自带数据集,其实这指的就是torchvision,而也有其他领域:处理自然语言的torchtext,处理音频的torchaudio

(1)内置数据集

2.各个组件和实战,第6张
好是还,但由于很大不可能像sklearn一样自带,只能下载

(2)读入csv格式,自己构建Dataset类,进而定义DataLoader类

2.各个组件和实战,第7张

4.4 模型设计

这个实战程序这点写的挺好的,用2个Sequential封装了特征提取和分类阶段,这样在forward的时候就很明朗。这里要说一点分类和回归的区别,回归很好理解损失函数的理解更没有什么障碍,但是分类这里,用的交叉熵,主要衡量的是预测分布和真实分布之间的差距,注意,这里是分布的差距,也就是说每一类的值没必要是0~1,只要真实分类的对应数值最高而且尽可能比其他高就行,当然如果真的不舒服,可以在这里再加个归一化操作

2.各个组件和实战,第8张

4.5 模型保存

2.各个组件和实战,第9张
保存为pkl格式

4.6 模型加载

下一节联系这个,因为训练的时候会保存很多个临时模型

另外在部署的时候也需要

总之,之前刚接触的时候,老感觉怎么这么多模块,而且会害怕有新模块,其实当真正了解软件设计规范后(对,我还真的就是通过看python,java,单片机c,最后落脚设计模型和软件设计应包含哪几个文件夹这些看似不相关的东西升华的),看一切都很自然了,也就是懂了这个事情的运行套路(一切都是套路,你不了解的时候会害怕套路,了解之后,就能会心一笑,当然横冲直撞是了解不会套路的,我用的路线是从软件开发角度,这个角度比较大,所以是兼容的策略,没办法,自己一人搞就是这样)

我刚开始时候是由机器学习sklearn转过来的,数据集的预处理很简单,即使不会也能在excel中处理好再导入,看到还需要Dataset和DataLoader的时候,心想这TM是啥啊,为什么还需要这么复杂,呵呵此时我一不了解python中的可迭代对象和迭代器,二不完全理解深度学习开发就是继承torch中各个步骤的类二次开发的过程,三不知道软件设计的高聚合低耦合思想,这是为了分解大程序步骤。但是,当我走了一些弯路搞懂了上面这三点,再来看这里的开发,哼,简直第二阶段“看山不是山,看水不是水”

噢~~我突然有点了解大学一些经典知识的目的了,社会变化很快,大学的内容做不到也不能时刻围绕社会里的新技术转,那就教授一些“思想”,比如高聚合低耦合,懂了这个看软件的设计方方面面都是,虽然不可能一眼就完全懂,但是亲切。

另外说到这里了,多说一句,围绕社会新技术进行教,我觉得职业教育该干这个事,职业教育就不要教微积分线性代数了,上来直接java-spring后端,javascript前端,并发等等搞起来!职业教育的老师做不到?那就允许企业人兼职或者引入竞争,大学的青年教师都卷成什么样了,真正该更新的是职业教育,这才是以后大多数人的未来。甚至职业教育和商业市场挂钩,或许能激起涌泉而来,即使你抗拒也不行,你看多少人是通过商业培训找到工作的就知道。那为什么不把这些引到职业教育的校园呢,让他们浪费那几年时间干嘛?职业教育,职业啊,贴近挣钱更合适,一家之言,让大家见笑了。

当然说偏了,只是建言献策而已~

附注,自己写在pycharm中的错误debug历程:

(1)绘图不显示

image,label =next(iter(train_loader))

print(image.shape,label.shape)

plt.imshow(image[1][0],cmap='gray')

plt.show() #加这一句就行

(2)不理解为什么是image[0][0]两个索引

image对应绘图展示是一张图片,其中可得到两件事,其一next(iter(train_loader))会返回一个batch的图像和对应的label;其二是因为是batch的,所以image的尺寸为torch.Size([256, 1, 28, 28]),因此image[0][0]第一个索引定位到本batch中哪种图像,第二个索引定位到哪个通道(此处只能是0,因为只有一个通道)

(3)大程序为什么不用next()

那实际大程序中为什么没有看到next(iter())这种用法,只是在可视化这里用了,这就要看train阶段的程序了:

2.各个组件和实战,第10张
for循环,记着,这个是个循环

根据上面的for循环,我加了2个print,结果疯狂输出“torch.Size([256, 1, 28, 28])

torch.Size([256])

torch.Size([256, 1, 28, 28])

torch.Size([256])

torch.Size([256, 1, 28, 28])

torch.Size([256])

torch.Size([256, 1, 28, 28])

torch.Size([256])”

因此,你知道为什么实际大程序中没有next(iter())了吧,因为直接用for循环就把dataset切分为不同的batch了,这个for循环运行完,其实就是一个epoch,就是把几乎所有数据都遍历了一遍。

(4)训练时候的batch处理哪去了?

在训练的时候,每个batch都使用output = model(data),但是输入的data尺寸为torch.Size([256, 1, 28, 28]),而model接收数据后data处理只有nn.Conv2d(1,32,5),哪里体现了256张的处理,还是说会自动做处理并在训练的loss中做平均呢?

是的,会自动

(5)计算平均误差

懂了,为什么写train_loss += loss.item()*data.size(0),因为想做一个epoch

大无语事件,把上面两点调通之后,acc一直无法争取现实,print之后发现get_labels不正确,逐个排查竟然发现在concat的时候发现写成了gt_labels,所以才是一个patch的40,而不是总的一万,确实如果对这些熟悉的话,看数量关系就能定位。

(6)gt_labels大乌龙

我去,改了之后还是不行,才发现本来作者程序就是“gt_labels”而我其中一个写的是“get_labels”,这里不得不说,作者有些懒省事了,字母少的时候还是写全吧

嗯,后来经过解答,原来gt是“GroundTruth”啊

一切正常

2.各个组件和实战,第11张

https://www.xamrdz.com/backend/3u31995584.html

相关文章: