初探 MindSpore(三):把最小网络接上训练
初探 MindSpore三把最小网络接上训练前两篇只处理了网络定义本身nn.Module - nn.Cellforward() - construct()但只会写前向网络还不够。对 PyTorch 用户来说下一步真正需要搞清楚的是MindSpore 里的一步训练是怎么组织起来的。这一篇只讲最小训练闭环不讲数据集、不讲完整工程结构也不讨论高阶训练技巧。目标只有一个把一个最小网络依次接上损失函数、优化器和一步训练封装看清 MindSpore 的训练骨架。训练结构如果先把结构压缩成一句话MindSpore 的最小训练闭环可以理解为网络Cell-WithLossCell- 优化器 -TrainOneStepCell这不是写法偏好而是官方文档已经明确给出的封装方式WithLossCell用损失函数包装网络输入 data 和 label输出 loss。TrainOneStepCell再用优化器包装训练网络在construct中创建反向图并更新参数。因此第三篇最重要的不是再去对照更多层而是先把这条训练链条看清楚。第一步先有一个最小网络先沿用第二篇里的最小网络。这里仍然只保留一个线性层importmindspore.nnasnnclassNet(nn.Cell):def__init__(self):super().__init__()self.fcnn.Dense(10,2)defconstruct(self,x):returnself.fc(x)到这里为止网络只定义了前向计算还没有损失函数也没有训练步骤。它只能做推理不能直接完成“一步训练”。第二步给网络接上损失函数MindSpore 官方WithLossCell文档对它的作用定义得很明确它是“带损失函数的 Cell”用损失函数包装网络输入 data 和 label返回计算得到的 loss。也就是说在 MindSpore 里训练通常不是直接拿“纯网络”开训而是先把网络和 loss 接成一个新的 Cell。例如最小写法可以这样组织importmindspore.nnasnn netNet()loss_fnnn.MSELoss()net_with_lossnn.WithLossCell(net,loss_fn)这里的结构变化很直接net负责前向输出loss_fn负责把预测值和标签变成标量损失net_with_loss变成一个新的 Cell它的输出不再是网络原始输出而是 loss这一层封装很重要。因为从这里开始训练关注的对象已经不是“网络输出是什么”而是“loss 怎么被构造出来”。第三步给参数接上优化器只有 loss 还不够还需要优化器来更新参数。MindSpore 官方Adam文档把它定义为 Adam 优化器实现作用是根据梯度更新参数。最小写法如下optimizernn.Adam(net.trainable_params(),learning_rate1e-3)这里有两个点需要注意。第一优化器拿到的是可训练参数。第二优化器不是直接包WithLossCell而是在下一步交给TrainOneStepCell去统一接入。也就是说到这一步为止训练链条已经有了三段netnet_with_lossoptimizer但还没有真正形成“一步训练”的执行单元。第四步用TrainOneStepCell封装一步训练这是第三篇最关键的部分。MindSpore 官方TrainOneStepCell文档明确写到它是网络训练封装类用优化器包装网络反向图会在construct函数中创建并用于更新参数。这意味着MindSpore 把“一步训练”本身也封装成了一个 Cell。最小写法如下train_stepnn.TrainOneStepCell(net_with_loss,optimizer)到这里结构终于闭合了Net定义前向WithLossCell把网络和 loss 接起来Adam定义参数更新规则TrainOneStepCell把“前向 loss 反向 参数更新”封成一步训练这也是第三篇真正要说明的事MindSpore 的训练不是额外漂浮在网络外面的一堆过程代码而是继续沿着 Cell 体系封装。一个最小训练闭环把上面的部分拼起来就是一个最小训练示例importnumpyasnpimportmindsporeasmsimportmindspore.nnasnnclassNet(nn.Cell):def__init__(self):super().__init__()self.fcnn.Dense(10,2)defconstruct(self,x):returnself.fc(x)netNet()loss_fnnn.MSELoss()net_with_lossnn.WithLossCell(net,loss_fn)optimizernn.Adam(net.trainable_params(),learning_rate1e-3)train_stepnn.TrainOneStepCell(net_with_loss,optimizer)xms.Tensor(np.random.randn(4,10),ms.float32)labelms.Tensor(np.random.randn(4,2),ms.float32)losstrain_step(x,label)print(loss)这段代码的意义不是“已经能训练出一个有价值的模型”而是把 MindSpore 里最小训练单元的结构一次性摆出来。对 PyTorch 用户来说这里最值得注意的不是MSELoss或Adam本身而是训练过程被分成了两层封装先把网络和 loss 变成一个新的 Cell再把这个训练网络和优化器变成一步训练 Cell为什么这里还要专门引入WithLossCell很多 PyTorch 用户看到这里最容易冒出来的问题是为什么不直接在训练步骤里手写 loss而要单独插一个WithLossCell。原因很简单因为 MindSpore 官方就是把这一步明确抽象出来了。WithLossCell的文档说明已经写得很清楚它接受 data 和 label 作为输入返回计算得到的 loss。这件事的重要性不在于“少写几行代码”而在于它进一步说明了 MindSpore 的组织方式前向网络是 Cell带损失的训练网络还是 Cell一步训练封装依然是 Cell也就是说训练过程不是跳出网络定义体系另外开一套而是不断在现有Cell之上继续包装。这和 PyTorch 的直觉差别在哪里如果从 PyTorch 习惯出发很多人会更自然地把训练理解成一个 loop前向、算 loss、backward()、optimizer.step()。MindSpore 当然同样要完成这些事但它在官方接口层面上更强调把这些步骤收进封装后的 Cell 里。这不是说两者训练本质不同而是说MindSpore 更强调把训练步骤本身对象化、结构化。这也是为什么在前两篇里Cell必须先讲。因为如果不先接受Cell是基本单位第三篇这里的WithLossCell和TrainOneStepCell就会显得很突然但如果前两篇的基础已经建立好这一层封装就很自然。本文范围第三篇不继续展开数据集、训练循环和评估流程是因为到这里为止最关键的结构已经完整了。官方教程把模型训练概括成四步构建数据集、定义网络、定义超参数/损失/优化器、输入数据进行训练与评估。这一篇只刻意取了其中最核心的一段网络、损失、优化器和一步训练封装。如果现在继续往下写数据集和完整训练 loop重点就会被稀释。对 PyTorch 用户来说第三篇真正应该先吃透的不是“怎么写更多样板代码”而是MindSpore 把一步训练也继续封装进了Cell体系。结论第三篇只建立一个结论MindSpore 的最小训练闭环不是“网络 optimizer”这么简单而是Net - WithLossCell - Optimizer - TrainOneStepCell这条封装链。如果压缩成三条就是网络先写成Cell损失先包成WithLossCell一步训练再包成TrainOneStepCell这也是 PyTorch 用户进入 MindSpore 训练部分时最先应该建立的结构理解。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2422623.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!