AI模型
本质是“参数估计”(Learning is parameter estimation
梯度消失和梯度爆炸
梯度消失和梯度爆炸的产生原因源于神经网络的串联式结构和反向传播优化方法。
源于反向传播中梯度的累乘影响,从而导致了浅层网络的参数发生了变化微弱或者震荡较大的问题
解决方案
一个是从神经网络的结构出发,在模型中加入一定的限制条件;
另一个是从反向传播方法出发,进行训练模型的改变。
模型说明:1.1 激活函数 1.2 Normalization 1.3 残差链接 梯度裁剪: 则化
激活函数的主要功能是在神经网络计算中引入非线性计算来强化网络对非线性的泛化性
ReLU作用可以从两个方面来解析:正向保留激活值、反向统一化梯度
梯度和参数更新
梯度--梯度下降-梯度反向传播
梯度下降是沿着梯度相反的方向走,即更新参数的时候是用原参数减去学习率乘以梯度
梯度反向传播:
即“误差的反向传播”,梯度的偏导数对误差进行量化。通过网络向后传播误差,
利用最后一层(最接近输出层的层)梯度的偏导数来计算第二层到最后一层的梯度
利用当前层中前一层的梯度的偏导数确定误差在各层中的传播,一直传播到网络中的第一层(与输入层最近的层
W=W−η*∂W/∂L 其中 η 学习率
自适应的学习率(ADATIVE LEARNING RATE)
batch
Mini-batch(小批量):Mini-batch 是指从训练数据集中选择的较小的数据子集。在训练模型时,通常将整个训练数据集划分为多个 mini-batch
向量化运算
梯度反向传播
矩阵运算
芯片层、框架层、模型层和应用层
概念-名词
01.网络结构-神经网络模型是由神经网络层和Tensor操作构成的--前向传播
02.代价函数--
模型预测值(logits)与正确标签(label)
送入损失函数(loss function)获得loss,
然后进行反向传播计算,求得梯度(gradients),最终更新至模型参数(parameters
03.优化方法-反向传播 梯度下降 梯度消失 梯度爆炸 学习率
利用自动微分机制,自动求模型参数(parameters)对于loss的梯度(gradients)。
将梯度更新到参数上。
Pytorch网络层、优化器、损失函数等模块
net = nn.Sequential()
criterion = nn.HingeEmbeddingLoss()
optimizer = torch.optim.RMSprop(net.parameters(), lr=1e-3, alpha=0.9)
# 前向传播
model.set_train()
out = net(im)
loss = criterion(out, label)
# 反向传播
optimizer.zero_grad()
loss.backward()
optimizer.step()
自动微分(Automatic Differentiation)机制采用函数式可微分编程架构
torch.autograd.grad(z,x)[0] torch.autograd.grad 不会将求导结果累加在grad上
loss.backward()会将求导结果累加在grad上。这也是为什么我们在训练每个batch的最开始,需要对梯度清零的原因
AI框架
为MindSpore、百度PaddlePaddle、商汤科技SenseParrots、腾讯TNN、阿里MNN、字节跳动BytePS、旷视MegEngine、小米Mace等。
昇思-MindSpore
华为 硬件芯片-操作系统-开发语言Cangjie--开发框架
是一个全场景深度学习框架
主流的深度学习框架的执行模式有两种,分别为静态图模式和动态图模式。
静态图模式拥有较高的训练性能,但难以调试。set_context(mode=GRAPH_MODE)可切换成静态图模式
动态图模式相较于静态图模式虽然易于调试,但难以高效执行 set_context(mode=PYNATIVE_MODE)
计算图是用图论语言表示数学函数的一种方式,也是深度学习框架表达神经网络模型的统一方法
昇思MindSpore总体架构--有端(手机与IOT设备)、边(基站与路由设备)、云(服务器)场景的不同系列硬件
从高到低分别为High-Level Python API、Medium-Level Python API以及Low-Level Python API。
基础层次: 张量定义、基础算子、自动微分等模块
第二层:
可以继承nn.Cell类,并重写__init__方法和construct方法
第一层
torch.autograd.grad() torch.autograd.backward()
grad_fn = mindspore.grad(function, (2, 3))
MindSpore执行步骤
#2019年8月,华为推出昇思MindSpore,并在2020年3月将框架开源
import mindspore
from mindspore import nn
from mindspore import ops
model = Network() # def construct(self, x
loss_fn = nn.CrossEntropyLoss()
optimizer = nn.SGD(model.trainable_params(), learning_rate=learning_rate)
model.set_train()
logits = model(data)
loss = loss_fn(logits, label)
(loss, _), grads = grad_fn(data, label)
optimizer(grads)
###模型定义
construct()
###训练
正向计算函数定义。
通过函数变换获得梯度计算函数。
训练函数定义,执行正向计算、反向传播和参数优化。
def forward_fn(data, label):
grad_fn = ops.value_and_grad(forward_fn, None, optimizer.parameters, has_aux=True)
def train_step(data, label):
###自定义损失函数的方法有两种:一是基于nn.Cell来定义损失函数;二是nn.LossBase来定义损失函数
PaddlePaddle
百度布局AI框架的时间,2016年该公司发布并开源飞桨PaddlePaddle
从代码结构上看,模型均为数据处理、定义网络结构和训练过程三个部分
import paddle
import paddle.nn.functional as F
# 定义多层全连接神经网络
class MNIST(paddle.nn.Layer):
#网络结构部分之后的代码,
def train(model):
opt = paddle.optimizer.SGD(learning_rate=0.01, parameters=model.parameters())
#准备数据
#前向计算的过程
predicts = model(images)
#后向传播,更新参数的过程
loss = F.square_error_cost(predicts, labels)
avg_loss = paddle.mean(loss)
avg_loss.backward()
# 最小化loss,更新参数
opt.step()
# 清除梯度
opt.clear_grad()
对比
基类
mindspore的模型基类是mindspore.nn.Cell
pytorch的模型基类是torch.nn.Module
全连接层
mindspore的全连接层是mindspore.nn.Dense
pytorch的全连接层是torch.nn.Linear
模型连接
mindspore的顺序容器是mindspore.nn.SequentialCell
pytorch的顺序容器是torch.nn.Sequential
前向传播
mindspore的前向传播函数(要执行的计算逻辑)基类函数为construct(self, xxx)
pytorch的前向传播函数基类函数为forward(self, xxx)
参数可以写为model.trainable_params(),也可以由优化器提供(optimizer.parameters)
:mindspore.ops.value_and_grad
把正向传播、反向传播的整个流程走一遍,最后的输出为正向传输函数的返回值+待求导参数的梯度值
# 设置为动态图模式
mindspore.set_context(mode=mindspore.PYNATIVE_MODE)
自动微分机制
由于不同深度学习框架的自动微分机制不同,所以实现梯度累加的方式有显著差异。
1.以Tensor为核心的自动微分,
Tensor可配置requires_grad参数控制是否需要梯度。
每个Tensor对象有 grad_fn属性用来存储该Tensor参与的反向操作,
同时还有 grad属性,存储该Tensor对应的梯度
业界多数框架选择此方案,如Pytorch、Paddle、Oneflow、MegEngine等。
2.函数式自动微分
将神经网络 正向计算视作输入到Loss的计算函数,
通过函数变换获得反向计算函数,并调用反向计算函数来获得梯度。
业界采用此方案的框架有Jax、MindSpore,此外Tensorflow的GradientTape
Pytorch等框架更多定位纯深度学习,此时只体现backward更符合目标用户的使用习惯。
而Jax、MindSpore则在定位上更加底层,
Jax直接明言自身为数值计算框架,
MindSpore则定位为AI+科学计算融合计算框架,因此函数式自动微分设计更符合框架定位
Pytorch本身在求完梯度后会自动挂载到Tensor.grad属性上,
而在没有手动清空(即optimizer.zero_grad())的情况下,每个step训练求得的梯度会自动累加,因此只需要控制梯度清零和参数更新的间隔步数
MindSpore 函数式自动微分,由于暴露接口更加底层,所以是直接求导返回梯度的
grad_fn = mindspore.value_and_grad(forward_fn, None, weights=model.trainable_params())
loss, grads = grad_fn(x, y)
print(grads)
没有直接挂载到Tensor属性的操作,因此需要单独维护一份和训练参数相同大小的参数进行累加的计算。
单独维护了一个Accumulator
查看自动微分机制
我们高估了语言 语言只是载体和工具
基于数值计算+反向传播的这一套机制到底还能吃多少年还是要打个问号,
是否脑科学才是更优解?又或者量子计算机or生物计算机更符合智能涌现的需要?犹未可知。实现人类语言规则这样不确定的复杂函数的拟合
SQL本身是相对轻量化的编程语言,规则也比较少,然后经过一系列的代码大模型预训练,尤其是文本+代码平行语料的训练,其能力很快就达到了很强的水平。
自然语言成为了查询语句,将中间能够产生误差、遗漏、错误的环节统统抹去了,就像是去掉了中间商
生态系统中的迁徙和坚守
差异
网络构造,满足面向对象编程习惯,MindSpore提供与Pytorch完全一致的Layer构造方式,因此该部分两者几乎完全相同。
前向计算和反向传播,MindSpore使用函数式,将前向计算构造成function,然后通过函数变换,获得grad function,最后通过执行grad function获得权重对应的梯度。
权重更新,这里三者差异最大,
其中Pytorch通过step方法内置了获取梯度和更新权重的过程,仅需要一次方法调用即可;
MindSpore则将Optimizer同样视为和Layer同样的组件,管理整个网络的权重,通过对象调用传入梯度进行更新;
而Jax则最为复杂,将权重单独使用一个State对象进行管理,需要提前创建State,然后不断作为函数的输入输出,进行更新。
华为
ModelArts是面向开发者的一站式AI平台 八爪鱼
MindSpore MindSpore(AI框架):为支持端、边、云独立的和协同的统一训练和推理框架
CANN CANN(神经网络计算架构):提供芯片算子库和算子开发工具,关键组件是高度自动化算子开发工具Tensor Engine
Ascend(昇腾)Ascend(昇腾):即IP和芯片组层,提供基于统一、可扩展架构的系列化AI IP和芯片,包括Max、Mini、Lite、Tiny和Nano五个系列
编程范式
代码(code)和数据(data)
类的methods和attributes分别对应了code和data:方法(Methods)属性(Attributes)
神经网络Tensor操作 (Operation) 和 权重 (Weights)
pytorch
torch.autograd和函数式的grad无法统一。
以Tensor为中心的反向传播接口和函数式接口完全割裂
数值计算这一场景本身就应当满足数学语义-习惯函数变换(输入函数,返回新函数)
Jax;没有Layer概念,神经网络由多个函数变化构成
不论是Pytorch还是Jax,其发展思路都是保住基本盘而后用套件完成跨领域生态构建的策略
直采用半函数式做反向传播的功能,使得融合编程范式的切换几乎水到渠成
OOP方式构造神经网络
带副作用的半函数式,方便状态管理-一套自动微分机制同时用于科学计算和AI
参考
https://www.paddlepaddle.org.cn/tutorials/projectdetail/5836960
https://www.mindspore.cn/tutorials/zh-CN/r2.0/beginner/train.html
https://gitee.com/mindspore/mindspore
聊聊梯度累加(Gradient Accumulation) https://zhuanlan.zhihu.com/p/595716023
AI框架的第三条路:面向对象+函数式融合编程 https://zhuanlan.zhihu.com/p/554357198