共计 4518 个字符,预计需要花费 12 分钟才能阅读完成。
前言
在应用过 TVM、TensorRT 等优良的机器学习编译优化零碎以及 Pytorch、Keras 等深度学习框架后,总感觉有必要从 实践上 对这些零碎进行一些剖析,尽管说在实践中学习是最快最间接的(指哪儿打哪儿、不会哪儿查哪儿),但恶补一些对于零碎设计的一些常识还是十分有用了,权当是坚固一些根底了。
因而,有必要学习理解一下机器学习零碎的设计和思维。如果不是很理解机器学习零碎的设计,能够看下知乎上对于这个问题的答复:相比 AI 算法钻研,计算机系统钻研败落了吗?
以下是本系列文章的笔记起源:
- CSE 599W: Systems for ML
- AI-Sys Spring 2019
留神,这一系列文章并不是传统的深度学习或者机器学习解说,对于这部分的解说能够看 CS231n 或者吴恩达的入门课,该系列文章适宜在深度学习方面有教训有理解的童鞋。
附一张 CSE 599W 这门课 (偶像 tqchen 主讲) 一开始的解说阐明:
这门课次要的重点不在深度学习实践算法,而是与深度学习无关,机器学习零碎方面的解说。
什么是深度学习
简略说下深度学习。
由上图可知,深度学习所蕴含的根本内容,也就是以下四大局部:
- 模型的设计(最外围的中央,不同的工作设计的模型不同,应用的具体算法也不同)
- 指标函数,训练策略(用于训练模型权重参数的指标函数,也就是损失函数,以及一些训练的办法)
- 正则化和初始化(与训练过程中的模型权重信息有关系,放慢训练的收敛速度,属于训练局部)
- 足够多的数据(机器学习亦或深度学习都是由数据驱动着了,没有数据的话就什么都不是)
咱们在学习深度学习的过程中,难免会有一些实际,于是咱们就利用以下这些优良的深度学习库去实现咱们本人设计的模型,并且设计好损失函数,一些正则化策略,最终利用这些库去读入咱们须要新联的数据,而后运行期待即可。
这些优良的深度学习库 (caffe、Mxnet、TF、Pytorch) 咱们应该都耳熟能详了,那么这些深度学习库的大略构造都是什么呢?
大部分的深度学习库都是由以下三个局部组成
- 用户 API
- 零碎组件
- 底层架构
大多数的咱们其实并不需要接触除了用户 API 以外的其余两个局部,而用户 API 也是深度学习库最顶层的局部。
Logistic Regression
拿个例子简略说一下用户的 API,首先咱们有一个逻辑回归的工作,就拿最相熟的 MNIST 数据集来进行演示,咱们通过输出每个数字的向量化数据,而后通过全连贯层去计算这些向量并且利用 softmax 函数进行预测。整个网络模型很简略已有一层全连贯层。
接下来咱们看一下应用 numpy 和 tinyflow(这是一个迷你的深度学习零碎库,麻雀虽小五脏俱全,值得咱们去学习)去训练一个简略的神经网络辨认 MNIST 手写数据库的例子:
<figure class=”half”>
<img src=”https://image.oldpan.me/TIM%E6%88%AA%E5%9B%BE20190509191736.jpg” width=49%>
<img src=”https://image.oldpan.me/TIM%E6%88%AA%E5%9B%BE20190509191744.jpg” width=50%>
</figure>
上述代码中 最重要 的也就是三个局部(在上图右侧曾经列了进去):
- 前向计算:因为只有一个全连贯层,所以咱们的计算也很简略 $h_{k}=w_{k}^{T} x_{i}$,其中 $ x_{i}$ 为输出的数据,$w_{k}^{T}$ 为权重,$h_{k}$ 为权重向量和数据向量点乘的后果。计算出来后果后咱们应用 softmax 函数对其进行分类计算失去对应十个数字的概率向量(最初输入的向量蕴含 10 个元素,别离为每个数字的可能性)
- 反向求导:咱们求出权重 W 对于极大似然损失的导数,这里咱们人工写了进去,在右图第二局部
- 梯度更新:咱们简略对权重 W 进行更新,更新值为学习率乘以 W 的梯度,即 $w \leftarrow w-\eta \nabla_{w} L(w)$,也就是咱们常常用的 SGD
整个深度学习库中最重要的也就是上述三个局部,大部分的深度学习库曾经帮咱们实现了上述的代码,咱们不须要反复造轮子,间接应用即可。
尝试应用 TensorFlow like API
接下来,咱们应用相似于 TensorFlow 的 API 来对上述形容的代码进行重构,应用 TensorFlow 的 API 格局来实现上述代码实现的训练过程。
那么,为什么要应用 TensorFlow 类型的 API 进行演示而不是采纳 Pytorch 呢?其实 TensorFlow 与 Pytorch 构建的图类型很不一样,尽管在最近一段时间 TensorFlow 曾经呈现了eager mode
,但经典的 TensorFlow 是采纳动态图来构建整个训练过程的。
也就是说,在 TF 中构建的是动态图,而在 Pytorch 中构建的是动态图:
其实对于动态图和动态图对于这个话题曾经通过了很多的探讨,动态图灵便多变,而动态图尽管没有动态图灵便,然而因为提前都确定好了输出参数,计算形式等等过程,零碎能够针对这些特点来对计算进行布局,所以在计算过程中的性能比动态图是要高一些的。
首先咱们确定要进行的前向数据以及操作算子:
- 输出 x 为 float32 类型的向量,[None,784]中 None 示意以后输出的 batch-size 未知
- W 为权重信息,维度为[784,10]
- y 为前向计算函数,利用算子函数嵌套定义了整个计算过程。
接下来设定了损失函数,能够看到
cross_entropy = tf.reduce_mean(-tf.reduce_sum(y_*tf.log(y), reduction_indices=[1]))
这句中申明了一个损失函数,应用的是分类工作中最罕用的穿插熵损失,留神 y_
代表寄存么一个数据的分类 label,每一个数据的分类标签是一个元素数量为 10 的向量,用于与预测进去的值进行比对。具体的公式在下图右侧。
接下来设定了主动求导的过程,这一步中咱们要求的是权重向量对损失值 (也就是穿插熵损失后计算出来的值) 的梯度,这里咱们只是申明了一个函数,然而其中的计算过程是比较复杂的(也就是咱们常说的主动求导的过程),这个之后会进行解说,主动求导是咱们必须要把握的,间接手撸是必须的。
设定好了损失函数,接下来咱们就要拿计算出来的梯度值来更新网络的权重信息了,在这个例子中应用 SGD 随机梯度降落的形式进行权重更新,咱们只须要设定学习率这个超参数就能够。
因为在 TF 中,所有的申明式都仅仅是对要计算的流程进行申明,实际上并没有计算(这里能够称为一个懒计算的办法),也就是所谓的动态图形式定义好了整个网络以及训练的步骤,只是没有开始运作而已。
在运行完 sess.run
一句后,整个网络才开始正式执行起来。
这几张 ppt 的内容讲述了一个典型的神经网络库的运行流程(TF 类型的,如果是 Pytorch 的话略有不同),通过这个咱们能够晓得一个深度学习框架的根本作用。接下来要说的就是上述过程中最为重要的主动求导过程。
计算图(Computation Graph)
计算图是实现主动求导的根底,也是每个深度学习框架必须实现的局部,接下来咱们简略说说计算图是什么?
要说起计算图首先简略提一下申明式编程,正如下图中所展现的,计算图实质上是一种申明式语言,怎么说比拟适合,这种语言不同于咱们平时所说的 python 和 C ++,它是一种 DSL(畛域语言)或者一种迷你语言,这种语言深刻嵌入到 Python 和 C ++ 中,也就是咱们应用 Python 去操作,应用 C ++ 去具体实现。
是申明式编程不是简略地一条接一条地执行咱们的指令,而是依据咱们给出的所有指令创立一个计算图(computing graph)。这个图被外部优化和编译成可执行的 C++ 代码。这样咱们就能同时利用上两个世界的最优之处:Python 带来的开发速度和 C++ 带来的执行速度。
最终状态就是咱们提前设定好了计算逻辑,其余的交给零碎就行了,具体怎么优化就不必咱们去操心。
下图中就是一个简略的例子,咱们定义计算的逻辑 a*b+3
这个逻辑,其中 node 示意计算内容,箭头示意依赖关系。
下图中咱们就利用 TF-like API 去实现一个简略的 $t=softmax(W*x)$ 的过程,这个过程须要的数据 (x、W) 和算子 (matmult、softmax) 都曾经提前定义好了。
接下来是设置损失函数的计算局部:
而后设定与主动求导相干的梯度降落局部:
接下来是设定梯度更新的形式:
在设定玩所有的计算逻辑后,这里正式开始计算的过程,只有执行完 sess.run
这句后,整个计算图才开始真正的进行计算了。
下面对于主动求导的具体过程并没有展现,这个过程将在下一节中进行解说,不过对于主动求导的具体流程也能够在 CS231n 这门课中见到,具体在 Backpropagation and Neutal Networks 这一节中。
numpy 与 TF-program 的比拟
之前咱们应用了 numpy 与 TF-like API 的形式模仿了一个简略的 Logistic Regression 的过程,也就是实现利用一个简略的全连贯网络去辨认手写数字集 MNIST 的过程,这个过程中咱们应用了两种不同的形式去构建,用计算图来说就是 动态图 (numpy) 与动态图 (TF),而用语言类型来说就是 命令式编程 (numpy) 和申明式编程(TF)。
其实上述的 numpy 的例子也能够应用 Pytorch 做演示,因为 Pytorch 是一个类 numpy 的深度学习库,其操作的算子逻辑和 numpy 简直统一,能够说是一个利用动态图构造的畛域语言。
也就是说对于 numpy 与 TF-program 的比拟,能够等同于对于动态图和动态图的比拟,两者各有优缺点,然而如果谋求性能和开发效率的话,动态图更胜一筹,然而如果谋求灵活性和可拓展性,那么动态图的劣势就展示进去了。
未完待续
这节课的开端提出了一些后续要讲的内容,首当其冲的就是计算图的优化。
计算图优化在 TVM 中这个深度学习编译器中占了很大的篇幅,正如上面所说,咱们建设了计算图,因为这个计算图是动态的,所以咱们能够在底层对其进行尽可能地优化,从而放慢神经网络运行的速度,那么如何去优化呢?这可就是一个大学问,总之就是咱们可优化的空间很大,而对于优化的具体细节放在之后进行形容。
另外一点,数据并行也是重点解决的问题之一,毕竟当初的数据越来越多,显卡计算能力尽管每年晋升,然而内存 (具体点就是显存) 的晋升无限。那么如何更高效更快地训练大量的数据,间接的路径就是并行分布式训练,如何解决并行期间呈现的问题也是一个重点的方向。
相干参考
http://dlsys.cs.washington.ed…
https://ucbrise.github.io/cs2…
https://blog.csdn.net/tealex/…
撩我吧
- 如果你与我气味相投于此,老潘很违心与你交换;
- 如果你喜爱老潘的内容,欢送关注和反对。
- 如果你喜爱我的文章,心愿点赞???? 珍藏 ???? 评论 ???? 三连一下~
想晓得老潘是如何学习踩坑的,想与我交换问题~ 请关注公众号「oldpan 博客」。
老潘也会整顿一些本人的私藏,心愿能帮忙到大家,点击神秘传送门获取。