各位老铁们咱今天来好好掰扯掰扯 的动态图与自动微分要知道, 可是十分流行且广受赞誉的深度学习训练框架!这可和它的 “动态图” 以及 “自动微分” 这俩特性大有关系哩!
动态图的厉害之处
先来讲讲动态图。用过 Caffe 或者 的同学都清楚,训练前得构建一个神经网络。像 Caffe 是用配置文件 来描述, 则用 代码描述。训练前,框架有个解析和构建神经网络的过程,构建好才进行数据读取和训练,这就跟 “静态图” 似的。
可是,在这种 “静态图” 训练框架里就有很多不便之处!比如你要是想在训练过程中输出中间节点的数据,或者改变一点网络结构,可麻烦了!想要获取中间变量的输出也不容易。在 Caffe 里用 C 训练的话,得获取 layer 的 top 再打印; 则要通过 来获取。甚至想要控制网络的运行,精确到让它停在某一个 OP 之后,基本做不到相比之下!动态图就厉害,它能让 调试非常简单,每一个步骤、每一个流程都能被我们精确地控制、调试、输出,甚至在每个迭代都能重构整个网络!
调试技巧
这里有几个调试的时候能用的小技巧其一,你在进行简单矩阵运算的时候就可以多打印几个步骤看看中间结果。打个比方,你做个两个矩阵相乘的操作,每运算一次就把结果打印看看,没准就能发现哪里算错!其二,你还可以使用占位符和临时小网络,简单地就模拟一个小的运算流程,这样方便找出潜藏的错误
然后,要是你想调整 的动态图网络,也有法子的!有时候在循环条件当中就能够灵活去修改网络结构要是符合某些条件,增加一些卷积层或者去掉一些激活函数层等等都可以操作。
1. 修改卷积层:你要是发现前面跑出来的训练准确率不太够,觉得可能是特征提取得还不够,可以在特定位置添加一个卷积层来增强特征提取能力
2. 调整激活函数:要是梯度消失的情况比较严重,也能尝试把原来用的 激活函数,调整为 ReLU 激活函数。这样一弄,说不定能极大地改善训练结果
自动微分真神奇
再说说 “自动微分” 技术,它可帮大忙!咱们在编写深度学习网络的时候原本就得很麻烦地同时实现算子的前向传播和反向传播,就像 Caffe 那样。你想想,反向传播一般比前向传播复杂好多,手动推导反向传播很容易出错但有了 “自动微分” ,那就只需实现算子的前向传播就行!这么一来能够极大地节约劳动力,提升效率它是怎么运作的?简单地说,在前向传播运算的时候,通过把中间的一些结果和运算信息记录保留下来,在反向传播时就能依据链式法则去有效地推算梯度
如何使用
1. 梯度求解:若你要求一个数值表达式关于其中某个参数的梯度,比如 y = x^2 + 3x + 1
关于 x
的梯度,首先得创建一个可计算反向传播的变量 x
:
torch
x = torch.(2.0, =true)
y = x2 + 3 * x + 1
y.()
print(x.grad)
上面这几步代码就是定义了 x
并且使之能够参与反向传播流程,算出 y
表达式对应的值,再反向传播求关于 x
的梯度最后打印出来
2. 关闭梯度:在进行推理阶段需要节省机器性能可不想要全部参数都去计算求解梯度,那能这么干:
with torch.(): # 用这样一个上下文管理器关闭梯度计算
预测结果 = model()
预测结果
常见问答来解惑
问:动态图与静态图下的 ,在训练速度方面咋样!二者差异大否?
答:通常而言,静态图如果网络设计优化到位后训得挺快一点毕竟静态图提前编译等操作之后让计算调度更优;但是动态图灵活是灵活些,不过在不断实时构建的过程中速度可能慢一丢丢!假如有些任务需要很频繁地根据数据特性、训练情况做适配网络结构调整的任务,选择 动态图可能更好点;要是固定简单结构然后大数据量训练任务,静态图方面 可能表现上能占点优势。
问:用了 “自动微分”之后,参数更新咋整呀 ?简单地说,也就是怎么去做好优化步骤
答:其实哈要用优化器去完成参数更新,先依据需求初始化一个合适优化器比如亚当(Adam)或者随机梯度下降(SGD)优化器以后;接着每批次训练过程当中,反向传播算出梯度之后通过优化器把梯度按照设定的更新策略应用到参数上面即可。以下贴了段简单实现的操作示意啦:
torch
torch.optim as optim
创建优化器:优化器 = optim.Adam(model.(), lr=0.001)
循环进行每一轮训练:
y = model(x)
损失值 = (y,真实标签)
归零梯度:优化器.();
进行反向传播:损失值.()
更新参数啦:优化器.step()
咱在实际做深度学习模型训练任务场景运用过程当中,将 动态图和自动微分这两个要点把控好,充分发挥 框架的长处能少走好多弯路,能大大提升咱们实现构建先进模型的效率所以,大家实操起来的时候多关注一下它们。