机器学习是一个广泛的话题。尤其是深度学习,是一种使用神经网络进行机器学习的方式。神经网络可能是一个比机器学习更早的概念,可以追溯到1950年代。不出所料,有许多库是为它而创建的。
在下文中,我们将对一些著名的神经网络和深度学习库进行概述。
完成本教程后,你将学会:
- 一些深度学习或神经网络库
- 两个常见库PyTorch和TensorFlow之间的功能差异
让我们开始吧。
概述
本教程分为三个部分,它们是:
- C++库
- Python库
- PyTorch和TensorFlow
C++库
深度学习在过去十年中获得了关注。在此之前,我们对如何训练多层次的神经网络没有信心。然而,对于如何构建多层感知器的理解已经存在了很多年。
在我们拥有深度学习之前,最著名的神经网络库可能是libann 。它是一个C++的库,由于年代久远,功能有限。这个库已经停止开发。一个较新的C++库是OpenNN。它允许现代C++语法。
但这几乎是C++的全部。C++僵化的语法可能是我们没有太多深度学习库的原因。深度学习项目的训练阶段是关于实验的。我们希望有一些工具能让我们更快地进行迭代。因此,一种动态编程语言可能更适合。因此,你会看到Python出现在现场。
Python库
最早的深度学习库之一是Caffe。它是在U.C. Berkeley开发的,专门用于计算机视觉问题。虽然它是用C++开发的,但它是作为一个具有Python接口的库。因此,我们可以在Python中建立我们的项目,用类似JSON的语法来定义网络。
Chainer是Python中的另一个库。它是一个有影响力的库,因为它的语法很有意义。虽然它现在不太常见,但Keras和PyTorch的API与Chainer很相似。下面是Chainer文档中的一个例子,你可能会把它误认为是Keras或PyTorch。
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)
# create model
model = MLP()
model = L.Classifier(model) # using softmax cross entropy
# set up optimizer
optimizer = optimizers.MomentumSGD()
optimizer.setup(model)
# connect train iterator and optimizer to an updater
updater = training.updaters.StandardUpdater(train_iter, optimizer)
# set up trainer and run
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类似。
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中定义深度学习模型的常用方法是创建一个类。
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()
但也有一种顺序的语法,使代码更加简洁。
import torch
import torch.nn as nn
model = nn.Sequential(
# assume input 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语法可以产生与上述相同的网络,如下所示。
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() 函数来完成所有的训练工作,如下所示。
...
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中,我们需要自己编写训练循环代码。
# self-defined training loop function
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):
# Training
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()
# Validation
model.eval()
status = (f"{str(datetime.datetime.now())} End of 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接口的库。因此,也有可能为其他语言提供接口。例如,有Torch for R和TensorFlow for R。
还要注意的是,我们上面提到的库是全功能的库,包括训练和预测。如果我们考虑在生产环境中使用训练好的模型,可能会有更多的选择。TensorFlow有一个 "TensorFlow Lite "的对应版本,允许训练好的模型在移动或网络上运行。英特尔也有一个OpenVINO库,旨在优化预测的性能。
摘要
在这篇文章中,你发现了各种深度学习库和它们的一些特点。具体来说,你学到了:
- 有哪些库可以用于C++和Python
- Chainer库是如何影响到现在构建深度学习模型的语法的?
- Keras和TensorFlow 2.x之间的关系
- PyTorch和TensorFlow之间的区别是什么?