keras还是pytorch?完整的pytorch回归分类任务训练流程

前言
相信在2023年入门深度学习方向的同学,面对众多成熟的深度学习框架,尤其是pytorch、TensorFlow、keras这三个使用率较高的框架,很容易犯起选择困难症。
我首先是通过kaggle的深度学习教程入门的,一般来说,一些入门级别的深度学习教程,即从概念到多层感知机,基本都是用keras,然而随着学习的深入,keras的高层API特性似乎反而成为了学习上的阻碍,因此我随后转向了pytorch
下面我就基于使用keras和pytorch入门深度学习的使用感受和训练过程,通过回归和分类两种任务来说明
使用体验
首先,从使用体验上,个人认为两种框架各自有自己的优点。
Keras

keras的API非常人性化,封装的很到位,基本可以从sklearn无缝衔接过来,而且基本不需要纠结输入输出,特别是卷积操作
keras很适合快速验证想法,不需要过于执着于内部实现和繁杂的代码编写,例如在每层可以方便的进行正则化,提供激活函数,初始化参数
keras的可视化非常方便,自带进度条,
keras的功能实现很方便,比如动态调整学习率、早停法、checkpoint都只要在fit方法中加入对应callback函数即可
下面我用自己之前写的一段多层感知机的代码作为演示
可以看出keras总体架构大概服从一下的思路
确定验证策略并分割数据集:确定验证策略,例如交叉验证或留出法。将数据集分割为训练集和验证集。
设置超参数:选择批次大小(batch size)和学习率(learning rate)等超参数。
创建Sequential模型:创建一个Sequential对象,作为模型的容器。
添加网络架构:将每个网络架构按顺序添加到Sequential模型中。
配置网络架构:对于每个网络架构,选择适当的激活函数、正则化方法和参数初始化等。
编译模型:使用compile方法编译模型,指定损失函数和优化策略。
训练模型:使用fit方法将模型与训练集进行训练,指定训练的轮数(epochs)和批次大小。
预测结果:使用predict方法对新样本进行预测。
Pytorch
pytorch的框架更复杂一些,对于网络结构的把控会有更好的认识
pytorch提供了更多的自定义空间,可以加入更多自己的想法和需求,例如我想创建一个比较特殊的损失函数(比如对于预测成癌症的结果取更大损失),或者特殊的读取批次方法(比如每次读取时进行某种转换)
使用pytorch的人越来越多,在复现别人的代码上具有一些优势
总而言之就是,个人认为keras适合前期入门,快速掌握概念并进行代码实现。而pytorch适合进一步学习,更深层次的理解整个神经网络是如何架构起来的
打个比方吧,keras就像一个很方便的mod整合包,提供给用户的是一个个已经高度完备的建材,用户只需要知道这些建材怎么搭配,哪个要放在哪里就好了。
而pytorch更像是一个原滋原味的原材料工厂,用户必须指定每个建材的规格大小,指定怎么入料出料,详细的产品质量把控策略
因此从宏观来看,虽然在代码编写上麻烦了一点,但整体上对整个网络的运行有更好的把控,可以避免很多因“黑箱”造成的问题,例如梯度消失和爆炸、loss不合理、网络不合理等

详细的使用pytorch训练流程:以分类和回归为例
下面就以分类和回归为例子,分享一下使用pytorch进行训练的一般流程,不管是哪种网络,基本都可以用这种“堆积木”式的架构来完成
总体流程思路
导入工具包
定义超参数,例如批次大小,初始学习率等,可以放在一个config或者其他配置文件中
创建数据集和数据读取器:常用DataLoader,TensorDataset,或继承自Dataset进行自定义数据集
创建网络类
继承自nn.Module
初始化网络结构
实现前向传播方法
(可选)使用.to(device)或者.cuda()将模型放入GPU中
进行参数初始化,并apply到网络上
定义损失函数与优化器
损失函数需要自定义时继承自nn.Module
(可选)定义学习率调度器
(可选)使用tensorboard进行可视化,创建writer并可视化网络结构
from torch.utils.tensorboard import SummaryWriter
writer=SummaryWriter('log')
writer.add_graph(model=model)
开始训练并将模型调到训练模式model.train()
迭代dataloader,读取训练集的数据与标签 for data, label in train_loader
(可选)将数据和标签转移到GPU上data, label = data.cuda(), label.cuda()
清零优化器梯度optimizer.zero_grad()
把数据传入网络output = model(data)
计算输出标签与真实标签的损失loss = criterion(output, label)
反向传播求梯度loss.backward()
更新参数optimizer.step()
开始验证并将模型调到验证模式model.eval()
使用上下文管理,不再计算梯度with torch.no_grad()
迭代dataloader,读取验证集的数据与标签for data, label in val_loader
(可选)将数据和标签转移到GPU上data, label = data.cuda(), label.cuda()
把数据传入网络output = model(data)
计算输出标签与真实标签的损失loss = criterion(output, label)
(可选)进行学习率调度器更新: scheduler.step(val_loss)传入的是要监控的指标
(可选)进行tensorboard更新指标,这里我只展示监控学习曲线、学习率和参数权重分布
14.(可选)保存模型torch.save(model,'TempModel.pkl')
具体代码实现
任务一:对加利福利亚房价数据(20640,8)进行回归任务,预测真实房价
工具包导入
超参数定义
获取数据集
自定义Dataset存储我们的数据
ps:若出现错误RuntimeError: mixed dtype (CPU): expect input to have scalar type of BFloat16只需将tensor指定dtype设置为float32,这里发现有时候不指定dtype会出错
分割数据集,分别置入我们的Dataset
定义DataLoader
对于Windows环境,必须是num_workers=0
一般验证集不设置打乱数据shuffle=False
测试一下我们是否成功定义了数据读取逻辑
很好!输出是符合我们的维度要求的
定义网络结构
初始化参数
定义损失函数和优化器
这里我们自定义一个损失函数,对于预测小于真实房价的结果,使用MAE,否则使用MSE
优化器需要传入模型的参数以便其进行更新,以及定义的学习率
测试一下自定义的损失函数是否正常工作
定义学习率调度器
这里我们监控验证集上的损失,若五轮没有比最优的下降,我们就让学习率乘以0.2
使用Tensorboard进行可视化训练流程
开始训练和验证

观察Tensorboard上的情况
在命令行中输入tensorboard --logdir=log --port=1145 这里--logdir的参数为之前的writer=SummaryWriter('log'),--port为端口可以不写
Ctrl+左键进入链接

观察我们之前绘制的学习曲线
可以看出最终模型趋于收敛,存在一些过拟合的情况

在网页的Graph页面中观察我们的网络架构,可以具体点进去看每一层

观察我们的参数分布

(与我们的基线模型岭回归进行对比)
可以发现多层感知机的损失是0.41,而岭回归是0.53,表明多层感知机是优于线性模型的
模型保存
任务二:对XOR数据进行分类
具体相同流程不再赘述,这里只展示不相同的地方
读取数据集
我们这里将10%的随机数据取反

定义网络架构
这里注意避免踩坑,有些pytorch损失函数不支持gpu计算,例如二元交叉熵损失
定义损失函数与优化器
模型训练与验证

打印我们的决策边界

结语
目前为止还是我在入门深度学习上,对不同框架使用的一些感受,在后续进一步学习卷积神经网络和循环神经网络后,或许会有不一样的感受,这里暂且记录于此,希望能帮到各位初学者,并祝大家炼丹成功!
