机器学习是一个广阔的领域。特别是深度学习,是一种利用神经网络进行机器学习的方法。神经网络的概念可能比机器学习更早,可以追溯到 20 世纪 50 年代。不出所料,为此也产生了许多库。
以下旨在概述一些用于神经网络和深度学习的著名库。
完成本教程后,你将学到:
- 一些深度学习或神经网络库
- 两个常用库 PyTorch 和 TensorFlow 之间的功能差异
让我们开始吧。

一些深度学习库概述
照片来源:Francesco Ungaro。部分权利保留。
概述
本教程分为三个部分;它们是
- C++ 库
- Python 库
- PyTorch 和 TensorFlow
C++ 库
深度学习在过去十年中引起了广泛关注。在此之前,人们对于如何训练一个拥有许多层的神经网络缺乏信心。然而,关于如何构建多层感知机的理解已经存在多年。
在我们拥有深度学习之前,可能是最著名的神经网络库是 libann
。它是一个 C++ 库,但由于其年代久远,功能有限。该库后来停止了开发。一个更新的 C++ 库是 OpenNN,它允许使用现代 C++ 语法。
但这差不多就是 C++ 的全部了。C++ 僵化的语法可能就是为什么我们没有太多深度学习库的原因。深度学习项目的训练阶段是关于实验的。我们想要一些能够让我们更快地迭代的工具。因此,动态编程语言可能更合适。所以,Python 就登上了舞台。
Python 库
最早的深度学习库之一是 Caffe。它由加州大学伯克利分校开发,专门用于计算机视觉问题。虽然它是在 C++ 中开发的,但它提供了一个带有 Python 接口的库。因此,我们可以用 Python 构建我们的项目,而网络定义则采用类似 JSON 的语法。
Chainer 是另一个 Python 库。它是一个有影响力的库,因为它使得语法非常合理。虽然如今它不那么常见了,但 Keras 和 PyTorch 的 API 与 Chainer 相似。下面是 Chainer 文档中的一个例子,你可能会误认为是 Keras 或 PyTorch。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
import chainer import chainer.functions as F import chainer.links as L from chainer import iterators, optimizer, training, Chain from chainer.datasets import mnist train, test = mnist.get_mnist() batchsize = 128 max_epoch = 10 train_iter = iterators.SerialIterator(train, batchsize) class MLP(Chain): def __init__(self, n_mid_units=100, n_out=10): super(MLP, self).__init__() with self.init_scope(): self.l1 = L.Linear(None, n_mid_units) self.l2 = L.Linear(None, n_mid_units) self.l3 = L.Linear(None, n_out) def forward(self, x): h1 = F.relu(self.l1(x)) h2 = F.relu(self.l2(h1)) return self.l3(h2) # 创建模型 model = MLP() model = L.Classifier(model) # 使用 softmax 交叉熵 # 设置优化器 optimizer = optimizers.MomentumSGD() optimizer.setup(model) # 连接训练迭代器和优化器到更新器 updater = training.updaters.StandardUpdater(train_iter, optimizer) # 设置训练器并运行 trainer = training.Trainer(updater, (max_epoch, 'epoch'), out='mnist_result') trainer.run() |
另一个被淘汰的库是 Theano。它已停止开发,但曾几何时,它是深度学习的一个主要库。事实上,Keras 库的早期版本允许你在 Theano 或 TensorFlow 后端之间进行选择。确实,Theano 和 TensorFlow 都不是严格意义上的深度学习库。它们是张量库,能够方便地进行矩阵运算和微分,可以在其上构建深度学习操作。因此,从 Keras 的角度来看,这两个被认为是彼此的替代品。
微软的 CNTK 和 Apache MXNet 是另外两个值得一提的库。它们功能强大,支持多种语言的接口。Python 当然也是其中之一。CNTK 具有 C# 和 C++ 接口,而 MXNet 支持 Java、Scala、R、Julia、C++、Clojure 和 Perl 的接口。但最近,微软决定停止开发 CNTK。但 MXNet 确实有一些发展势头,并且可能是 TensorFlow 和 PyTorch 之后最受欢迎的库。
下面是通过 R 接口使用 MXNet 的示例。从概念上讲,您会发现其语法与 Keras 的函数式 API 相似。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
require(mxnet) train <- read.csv('data/train.csv', header=TRUE) train <- data.matrix(train) train.x <- train[,-1] train.y <- train[,1] train.x <- t(train.x/255) data <- mx.symbol.Variable("data") fc1 <- mx.symbol.FullyConnected(data, name="fc1", num_hidden=128) act1 <- mx.symbol.Activation(fc1, name="relu1", act_type="relu") fc2 <- mx.symbol.FullyConnected(act1, name="fc2", num_hidden=64) act2 <- mx.symbol.Activation(fc2, name="relu2", act_type="relu") fc3 <- mx.symbol.FullyConnected(act2, name="fc3", num_hidden=10) softmax <- mx.symbol.SoftmaxOutput(fc3, name="sm") devices <- mx.cpu() mx.set.seed(0) model <- mx.model.FeedForward.create(softmax, X=train.x, y=train.y, ctx=devices, num.round=10, array.batch.size=100, learning.rate=0.07, momentum=0.9, eval.metric=mx.metric.accuracy, initializer=mx.init.uniform(0.07), epoch.end.callback=mx.callback.log.train.metric(100)) |
PyTorch 和 TensorFlow
PyTorch 和 TensorFlow 是当今的两个主要库。过去,当 TensorFlow 是 1.x 版本时,它们差别很大。但随着 TensorFlow 将 Keras 吸纳为其库的一部分,这两个库现在大多工作方式相似。
PyTorch 由 Facebook 支持,其语法多年来一直保持稳定。还有很多现有的模型可以借用。在 PyTorch 中定义深度学习模型的常见方式是创建一个类。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
import torch import torch.nn as nn import torch.nn.functional as F class Model(nn.Module): def __init__(self): super().__init__() self.conv1 = nn.Conv2d(1, 6, kernel_size=(5,5), stride=1, padding=2) self.pool1 = nn.AvgPool2d(kernel_size=2, stride=2) self.conv2 = nn.Conv2d(6, 16, kernel_size=5, stride=1, padding=0) self.pool2 = nn.AvgPool2d(kernel_size=2, stride=2) self.conv3 = nn.Conv2d(16, 120, kernel_size=5, stride=1, padding=0) self.flatten = nn.Flatten() self.linear4 = nn.Linear(120, 84) self.linear5 = nn.Linear(84, 10) self.softmax = nn.LogSoftmax(dim=1) def forward(self, x): x = F.tanh(self.conv1(x)) x = self.pool1(x) x = F.tanh(self.conv2(x)) x = self.pool2(x) x = F.tanh(self.conv3(x)) x = self.flatten(x) x = F.tanh(self.linear4(x)) x = self.linear5(x) return self.softmax(x) model = Model() |
但也有顺序语法,可以使代码更简洁。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
import torch import torch.nn as nn model = nn.Sequential( # 假设输入为 1x28x28 nn.Conv2d(1, 6, kernel_size=(5,5), stride=1, padding=2), nn.Tanh(), nn.AvgPool2d(kernel_size=2, stride=2), nn.Conv2d(6, 16, kernel_size=5, stride=1, padding=0), nn.Tanh(), nn.AvgPool2d(kernel_size=2, stride=2), nn.Conv2d(16, 120, kernel_size=5, stride=1, padding=0), nn.Tanh(), nn.Flatten(), nn.Linear(120, 84), nn.Tanh(), nn.Linear(84, 10), nn.LogSoftmax(dim=1) ) |
TensorFlow 在 2.x 版本中将 Keras 作为其库的一部分。过去,这两个项目是分开的。在 TensorFlow 1.x 中,我们需要构建计算图,设置会话,并从会话中推导深度学习模型的梯度。因此,它有点过于冗长。Keras 被设计为一个隐藏所有这些底层细节的库。
与上述相同的网络可以通过 TensorFlow 的 Keras 语法如下生成:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
from tensorflow.keras.models import Sequential from tensorflow.keras.layers import Conv2D, Dense, AveragePooling2D, Flatten model = Sequential([ Conv2D(6, (5,5), input_shape=(28,28,1), padding="same", activation="tanh"), AveragePooling2D((2,2), strides=2), Conv2D(16, (5,5), activation="tanh"), AveragePooling2D((2,2), strides=2), Conv2D(120, (5,5), activation="tanh"), Flatten(), Dense(84, activation="tanh"), Dense(10, activation="softmax") ]) |
PyTorch 和 Keras 语法之间的一个主要区别在于训练循环。在 Keras 中,我们只需要将损失函数、优化算法、数据集和其他一些参数分配给模型。然后我们有一个 fit()
函数来完成所有的训练工作,如下所示:
1 2 3 4 |
... model.compile(loss="categorical_crossentropy", optimizer="adam", metrics=["accuracy"]) model.fit(X_train, y_train, validation_data=(X_test, y_test), epochs=100, batch_size=32) |
但在 PyTorch 中,我们需要自己编写训练循环代码。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
# 自定义训练循环函数 def training_loop(model, optimizer, loss_fn, train_loader, val_loader=None, n_epochs=100): best_loss, best_epoch = np.inf, -1 best_state = model.state_dict() for epoch in range(n_epochs): # 训练 model.train() train_loss = 0 for data, target in train_loader: output = model(data) loss = loss_fn(output, target) optimizer.zero_grad() loss.backward() optimizer.step() train_loss += loss.item() # 验证 model.eval() status = (f"{str(datetime.datetime.now())} Epoch {epoch} 结束, " f"training loss={train_loss/len(train_loader)}") if val_loader: val_loss = 0 for data, target in val_loader: output = model(data) loss = loss_fn(output, target) val_loss += loss.item() status += f", validation loss={val_loss/len(val_loader)}" print(status) optimizer = optim.Adam(model.parameters()) criterion = nn.NLLLoss() training_loop(model, optimizer, criterion, train_loader, test_loader, n_epochs=100) |
如果您正在试验一种新的网络设计,希望对损失函数的计算方式和优化器更新模型权重的方式有更多控制,这可能不是问题。但否则,您会欣赏 Keras 更简洁的语法。
请注意,PyTorch 和 TensorFlow 都是带有 Python 接口的库。因此,也有可能为其他语言提供接口。例如,有 R 版的 Torch 和 R 版的 TensorFlow。
另外,请注意,上面提到的库是功能齐全的库,包括训练和预测。如果您考虑生产环境,需要使用已训练的模型,则可能选择范围更广。TensorFlow 有一个“TensorFlow Lite”版本,允许将已训练的模型在移动设备或 Web 上运行。英特尔还推出了 OpenVINO 库,旨在优化预测性能。
进一步阅读
以下是我们上面提到的库的链接:
总结
在此帖中,您了解了各种深度学习库及其特性。具体来说,您学到了:
- 有哪些适用于 C++ 和 Python 的库
- Chainer 库如何影响构建深度学习模型的语法
- Keras 和 TensorFlow 2.x 之间的关系
- PyTorch 和 TensorFlow 之间的区别
很棒的概述!
谢谢 Ciprian 的反馈!
感谢概述及代码片段!
感谢这篇精彩的文章!
这些库正迅速从学术机构转向由商业公司支持。最终这让我思考,随着深度学习从研究转向生产,我们是否会需要更多的 C++ 和 Java 库来进行机器学习?反之,如果存在更多的 C++ 和 Java 库,是否会有更多的公司采用机器学习解决方案?总的来说,我期待了解更多您提到的那些生产环境库。–Romeo
Romeo,你提出了几个有趣的问题!答案取决于具体目标(例如,研究、产品开发、教育……等)。