原文链接:https://heartbeat.fritz.ai/the-5-deep-learning-frameworks-every-serious-machine-learner-should-be-familiar-with-93f4d469d24c
深度学习需要大量的计算。它通常涉及具有多个节点的神经网络,并且每个节点都有许多连接——在学习过程中必须不断更新这些连接。换句话说,在网络的每一层,成百上千个相同的人工神经元执行相同的计算。
因此,神经网络的结构非常适合 GPU(图形处理单元)能够有效执行的计算类型——GPU 被设计成并行计算相同的指令。
最近几年,随着深度学习和人工智能领域的飞速发展,我们也看到了许多深度学习框架的引入。创建深度学习框架的目的是在 GPU 上高效运行深度学习系统。它们都依赖于计算图的概念——计算图定义了需要执行的计算顺序。
在这些框架中所拥有的是一种设置计算图形的语言和一种与宿主语言不同的执行机制。然后可以对图形进行优化,并在目标 GPU 中并行运行。
在这篇文章中,将介绍 5 个深度学习框架,它们是深度学习开发的主力。它们使数据科学家和工程师更容易为复杂的问题构建深度学习解决方案,并执行更复杂的任务。这些只是众多开源框架中的一小部分,这些框架由不同的技术巨头支持,它们相互推动,以更快的速度进行创新。
TensorFlow 最初是由 Google Brain Team 的研究人员和工程师开发的。其目的是面向深度神经网络和机器智能研究。自2015年末以来,该库已正式在 GitHub上开源。TensorFlow 对于快速进行基于图形的计算非常有用。灵活的TensorFlow API 可以通过其 GPU 支持的体系结构跨多个设备部署模型。
简而言之,TensorFlow生态系统有三个主要组成部分:
TensorFlow 在学术研究和工业应用中得到了广泛的应用。目前一些值得注意的当前用途包括Deep Speech,RankBrain,SmartReply和On-Device Computer Vision。您可以在 GitHub 仓库上查看一些最好的官方使用、研究模型、示例和 TensorFlow 教程。
下面让我们来看一个代码示例。 在这里,我在 TensorFlow 上用随机数据训练一个基于 L2 损失的 2 层 ReLU 网络。
import numpy as np
import tensorflow as tf
# Batch size = 32, Input Dimension = 500, Hidden Dimension = 50
# Define computational graph
# Create placeholders
x = tf.placeholder(tf.float32, shape=(32, 500))
y = tf.placeholder(tf.float32, shape=(32, 500))
w1 = tf.placeholer(tf.float32, shape=(500, 50))
w2 = tf.placeholder(tf.float32, shape=(50, 500))
# Forward pass
h = tf.maximum(tf.matmul(x, w1), 0)
y_pred = tf.matmul(h, w2)
diff = y_pred - y
# Use predefined common losses
loss = tf.losses.mean_squared_error(y_pred, y)
# Compute loss of gradient
grad_w1, grad_w2 = tf.gradients(loss, [w1, w2])
# Run the graph multiple times
with tf.Session() as sess:
# Create numpy arrays
values = {x: np.random.randn(32, 500),
w1: np.random.randn(500, 50),
w2: np.random.randn(50, 500),
y: np.random.randn(32, 500),}
# Train the network
learning_rate = 1e-5
# Run the graph in a loop
for t in range(20):
out = sess.run([loss, grad_w1, grad_w2], feed_dict=values)
loss_val, grad_w1_val, grad_w2_val = out
values[w1] -= learning_rate * grad_w1_val
values[w2] -= learning_rate * grad_w2_val
这段代码有两个主要组件:定义计算图和多次运行此图。在定义图形时,我为输入 x、权重 w1和 w2 以及目标 y 创建占位符(placeholders),然后在在前向传播中计算目标 y 和 损失值的预测(即真实值 y 和预测值 y_pred 之间的 L2 距离)。
最后,TensorFlow 会计算关于 w1 和 w2 的梯度损失。构建完图表之后,我创建一个会话框来运行计算图。在这里,我创建了 numpy 数组,它将填充建图时创建的占位符,并将数值提供给 x、y、w1、w2。为了训练网络,我反复多次运行这个图,使用梯度来更新权重,最终获得用于 loss、grad_w1 和 grad_w2 的 numpy 数组。
Keras:高级包装(Keras: The High-Level Wrapper)
深度学习框架在两个抽象层次上运行:低层次——实现数学运算和神经网络原语(TensorFlow、Theano、PyTorch等);高层次——使用低层次原语实现神经网络抽象,如模型和层(Keras)。
Keras 是其后端库的包装,该后端库可以是TensorFlow或Theano——这意味着如果将Keras与TensorFlow后端一起使用,那么实际运行的是 TensorFlow 代码。Keras 可以处理大量的细节,因为它是面向神经网络技术消费者的,非常适合那些实践数据科学的人。它支持简单快速的原型设计,支持多种神经网络架构,并在 CPU/GPU 上无缝运行。
import keras
import numpy as np
from keras.models import Sequential
from keras.layers.core import Dense, Activation
from keras.optimizers import SGD
# Batch size = 32, Input Dimension = 500, Hidden Dimension = 50
# Create the model
model = Sequential()
model.add(Dense(input_dim=500, output_dim=50))
model.add(Activation('relu'))
model.add(Dense(input_dim=50, output_dim=500))
# Define optimizer object
optimizer = SGD(lr=1e0)
# Compile the model
model.compile(loss='mean_squared_error', optimizer=optimizer)
# Randomize data
x = np.random.randn(32, 500)
y = np.random.randn(32, 500)
# Fit the model
model.fit(x, y, epochs=50, batch_size=64, verbose=0)
在本例中,执行与之前例子类似的神经网络训练,首先将模型对象定义为一系列图层,然后定义优化器对象。接下来,构建模型,指定损失函数,并用一条“fit”曲线训练模型。
Theano 是另一个用于快速数值计算的 Python 库,可以在 CPU 或 GPU 上运行。这是蒙特利尔大学蒙特利尔学习算法小组开发的一个开源项目。它的一些最突出的特性包括 GPU 的透明使用、与 NumPy 的紧密集成、高效的符号微分、速度/稳定性优化和广泛的单元测试。
遗憾的是,Youshua Bengio(MILA实验室负责人)在2017年11月宣布他们将不再积极维护或开发 Theano。原因在于 Theano 多年来推出的大部分创新技术现在已被其他框架所采用和完善。如果有兴趣,大家仍然可以为它的开源库做贡献。
Theano 在很多方面与 TensorFlow 相似。让我们来看另一个使用相同批处理大小和输入/输出维度训练神经网络的代码示例:
import theano
import theano.tensor as T
# Batch size = 32, Input Dimension = 500, Hidden Dimension = 50, Number of Classes = 5
# Define symbolic variables
x = T.matrix('x')
y = T.vector('y', dtype='int64')
w1 = T.matrix('w1')
w2 = T.matrix('w2')
# Forward pass: compute scores
a = x.dot(w1)
a_relu = T.nnet.relu(a)
scores = a_relu.dot(w2)
# Forward pass: compute softmax loss
probs = T.nnet.softmax(scores)
loss = T.nnet.categorical_crossentropy(probs, y).mean()
# Backward pass: compute gradients
dw1, dw2 = T.grad(loss, [w1, w2])
# Compile function
f = theano.function(
inputs = [x, y, w1, w2],
outputs = [loss, scores, dw1, dw2],
)
# Run the function
xx = np.random.rand(32, 500)
yy = np.random.randint(5, size=32)
ww1 = 1e-2 * np.random.randn(500, 50)
ww2 = 1e-2 * np.random.randn(50, 5)
learning_rate = 1e-1
for t in xrange(20):
loss, scores, dww1, dww2 = f(xx, yy, ww1, ww2)
print loss
ww1 -= learning_rate * dww1
ww2 -= learning_rate * dww2
我首先定义了 Theano 符号变量(类似于 TensorFlow 占位符)。对于正向传播,主要计算预测和损失;对于反向传播,计算梯度。然后编译了一个函数,它根据数据和权重计算损失、分数和梯度。最后,我多次运行这个函数来训练网络。
PyTorch 是一个相对较新的深度学习框架,在研究人员中迅速流行起来。Facebook 人工智能研究团队开发它是为了应对采用其前身 Torch 库时遇到的挑战。由于编程语言 Lua 的受欢迎程度较低,Torch 永远无法体验到谷歌的 TensorFlow 所具有的增长。
因此,PyTorch 采用了原生 Python 命令式编程风格,这已经为许多研究人员、开发人员和数据科学家所熟悉。它还支持动态计算图形,这一特性使它对研究人员和工程师具有吸引力,他们使用时间序列和自然语言处理数据。
到目前为止,最好的应用来自 Uber,它已经构建了一个使用 PyTorch 作为后台的通用概率编程语言 Pyro。PyTorch 执行微分和构造梯度的动态能力对于概率模型中的随机操作非常有价值。
这里我将着重于张量抽象层。PyTorch 张量就像 numpy 数组一样,但是它们可以在 GPU 上运行。没有计算图形、梯度或深度学习的内置概念。在这里,将使用 PyTorch 张量拟合一个 2 层的网络:
import torch
# Batch Size = 32, Input Dimension = 500, Hidden Dimension = 50, Output Dimension = 5
dtype = torch.FloatTensor
# Create random tensors for data and weights
x = torch.randn(32, 500).type(dtype)
y = torch.randn(32, 5).type(dtype)
w1 = torch.randn(500, 50).type(dtype)
w2 = torch.randn(50, 5).type(dtype)
learning_rate = 1e-6
for t in range(250):
# Forward pass: Compute predictions and loss
h = x.mm(w1)
h_relu = h.clamp(min=0)
y_pred = h_relu.mm(w2)
loss = (y_pred - y).pow(2).sum()
# Backward pass: Compute gradients
grad_y_pred = 2.0 * (y_pred - y)
grad_w2 = h_relu.t().mm(grad_y_pred)
grad_h_relu = grad_y_pred.mm(w2.t())
grad_h = grad_h_relu.clone()
grad_h[h < 0] = 0
grad_w1 = x.t().mm(grad_h)
# Gradient descent step on weights
w1 -= learning_rate * grad_w1
w2 -= learning_rate * grad_w2
正如代码所示,首先为数据和权重创建随机张量。然后计算正向传播过程中的预测值和损失值,并在反向传播过程中手动计算梯度。同时也为每个权重设置梯度下降步长。最后,通过多次运行该功能来训练网络。
接下来聊一下 Torch。它是 Facebook 的开源机器学习库、科学计算框架和基于 Lua 编程语言的脚本语言。它提供了广泛的深度学习算法,并已被 Facebook,IBM,Yandex 和其他公司用于解决数据流的硬件问题。
作为 PyTorch 的直接祖先,Torch 共享了很多 C 后端。不像 PyTorch 有3个抽象层次,Torch只有 2 个:张量和模块。下面来探索一个使用 Torch 张量训练 2 层网络的代码示例:
require 'torch'
require 'nn'
require 'optim'
-- Build a model as a sequence of layers, and a loss function
local model = nn.Sequential()
model:add(nn.Linear(500, 50))
model:add(nn.ReLU())
model:add(nn.Linear(50, 5))
local loss_fn = nn.CrossEntropyCriterion()
local x = torch.randn(32, 500)
local y = torch.Tensor(32):random(5)
local weights, grad_weights = model:getParameters()
-- Define callback
local function f(w)
assert(w == weights)
-- Forward Pass
local stores = model:forward(x)
local loss = loss_fn:forward(scores, y)
-- Backward Pass
grad_weights:zero()
local grad_scores = loss_fn:backward(scores,y)
local grad_x = model:backward(x, grad_scores)
return loss, grad_weights
end
-- Pass callback to optimizer
local state = {learningRate=1e-3}
for t = 1, 25 do
optim.adam(f, weights, state)
end
view raw
首先,建立了一个多层的神经网络模型和一个损失函数。接着,定义了一个回调函数,输入权重并在权重上生成损失/梯度。在函数内部,计算了向前传递的预测和损失,以及向后传递的梯度。最后,反复将该回调函数传递给优化器进行优化。
Caffe 是一个兼具表达性、速度和思维模块化的深度学习框架。它是由伯克利人工智能研究小组和伯克利视觉与学习中心开发的。虽然它的核心是用 C++ 编写的,但 Caffe 有 Python 和 Matlab 绑定。这对于训练或微调前馈分类模型非常有用。虽然它在研究中使用的并不多,但是它仍然在部署模型方面很受欢迎,社区贡献者已经证明了这一点。
为了使用 Caffe 训练和微调神经网络,需要进行以下4个步骤的操作:
转换数据:我们读取数据文件,后用 Caffe 可以使用的格式进行清理和存储。我们将编写一个 Python 脚本来处理数据预处理和存储。
定义模型:模型定义了神经网络的结构。我们选择CNN体系结构,并在一个扩展名为.prototxt
的配置文件中定义其参数。
定义求解器:求解器负责模型优化,定义所有关于如何进行梯度下降的信息。我们在扩展名为.prototxt
的配置文件中定义求解器参数。
训练模型:一旦我们准备好了模型和求解器,我们通过从终端调用 caffe
二进制来训练模型。在对模型进行训练之后,我们将在扩展名为.caffemodel
的文件中获得训练好的模型。
在这里不对 Caffe 进行代码演练,读者可以自行在 Caffe 的主页上查看教程。总的来说,Caffe 对于前馈网络和现有网络的微调非常有用。您可以轻松地训练模型,而不需要编写任何代码。它的 Python 接口非常有用,因为可以在不使用 Python 代码的情况下部署模型。另一方面,你需要为每一个新的 GPU 层编写核心 C++ 代码(在Caffe下)。因此,对于大型网络(AlexNet、VGG、GoogLeNet、ResNet等)来说,这是非常麻烦的。
随着 Theano 不再开发维护,Torch 使用不熟悉的语言 Lua 编写,而 Caffe 处于早熟状态,TensorFlow 和 PyTorch 成为大多数深度学习实践者的首选框架。虽然这两个框架都使用Python,但它们之间有一些不同之处:
最重要的是,TensorFlow 是“定义并运行”的,在这个过程中,可以在图结构中定义条件和迭代,然后运行它。另一方面,PyTorch 是“按运行定义”的,在向前计算期间动态定义图结构。换句话说,TensorFlow 使用静态计算图,而 PyTorch 使用动态计算图。
基于动态图的方法为复杂的体系结构(如动态神经网络)提供了更简单的可调试性和更强的处理能力。基于静态图的方法可以更容易地部署到移动设备,更容易地部署到更奇特的体系结构,并且能够提前执行编译器技术。
因此,PyTorch 更适合于业余爱好者和小型项目的快速原型开发,而 TensorFlow 更适合于大型部署,尤其是考虑跨平台和嵌入式部署时。
TensorFlow 经受住了时间的考验,并得到了更广泛的应用。对于较大的项目,它具有更多的功能和更好的可伸缩性。PyTorch 正在获得发展势头,因为它更容易学习,但是它没有相同的集成。这对于需要快速完成的小项目非常好,但是对于产品部署不是最优的。
上面的列表只是其中几个主要支持 Python 的较为突出的框架。在过去的几年里,已经发布了多个新的深度学习框架,比如DeepLearning4j (Java)、Apache的MXNet (R、Python、Julia)、Microsoft CNTK (c++、Python)和Intel的Neon (Python)。
每个框架都是不同的,因为它们是由不同的人开发的,用于不同的目的。对这一领域有一个全面的了解肯定会让你对解决下一个深度学习挑战有一个很好的认识。
易用性(在架构和速度方面)、GPU支持、教程和训练材料的可用性、神经网络建模能力和支持的语言都是选择哪种最适合的深度学习框架的重要考虑因素。