PyTorch深度学习教程第一章-深度学习库的概览



前言

机器学习是一个广泛的话题。特别是深度学习,它是使用神经网络进行机器学习的一种方式。神经网络可能是一个比机器学习更早的概念,可以追溯到20世纪50年代。毫无意外,为此创建了许多库。以下内容旨在概述一些著名的神经网络和深度学习库。阅读完本章后,你将了解:

  • 一些深度学习或神经网络库
  • PyTorch 和 TensorFlow 这两个常用库之间的功能差异

一、C++ 库

在过去的十年中,深度学习引起了广泛关注。在此之前,人们对如何训练具有多层的神经网络缺乏信心。然而,多层感知器的构建方法已经存在多年。

在我们拥有深度学习之前,可能最著名的神经网络库是 libann。它是一个用于 C++ 的库,由于其年代久远,功能有限。这个库自2004年以来已停止开发。一个较新的 C++ 库是 OpenNN,它允许使用现代 C++ 语法。

但这几乎是 C++ 的全部内容。C++ 的严格语法可能是我们没有太多深度学习库的原因之一。深度学习项目的训练阶段关于实验。我们需要一些工具能让我们更快地迭代。因此,动态编程语言可能更合适。因此,你看到 Python 登上了舞台。

二、Python 库

Caffe 是最早的深度学习库之一,它是在加州大学伯克利分校专门为计算机视觉问题开发的。虽然它是用 C++ 开发的,但它提供了一个 Python 接口。因此,我们可以在 Python 中构建项目,网络定义使用类 JSON 语法。

Chainer 是另一个 Python 库。它非常有影响力,因为它的语法非常合理。虽然现在它不那么常见了,但 Keras 和 PyTorch 的 API 与 Chainer 非常相似。以下是来自 Chainer 文档的一个示例,你可能会误以为它是 Keras 或 PyTorch 的代码:

清单 1.1:Chainer 示例代码

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:

清单 1.2:R 语言中的 MXNet 示例代码

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.3:使用子类化语法的 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()

但也有顺序语法来使代码更加简洁:

清单 1.4:使用顺序语法的 PyTorch 示例代码

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)
)

在 2.x 版本中,TensorFlow 将 Keras 作为其库的一部分。在过去,这两个是分开的项目。在 TensorFlow 1.x 中,我们需要构建一个计算图,设置一个会话,并从会话中导出梯度以用于深度学习模型。因此,它的表达方式有些过于冗长。Keras 被设计为一个库,用来隐藏所有这些底层细节。

上述相同的网络可以通过 TensorFlow 的 Keras 语法如下实现:

清单 1.5:使用顺序语法的 TensorFlow 示例代码

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.6:在 TensorFlow 中使用 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 中,我们需要编写自己的训练循环代码:

清单 1.7: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 接口的库。因此,它们也可能有其他语言的接口。例如,有 R 的 Torch 和 R 的 TensorFlow。

另外,请注意,我们上面提到的库都是全功能的库,包括训练和预测。如果你考虑到生产环境中使用训练好的模型,可能会有更多的选择。TensorFlow 有一个“TensorFlow Lite”对应版本,允许在移动设备或网络上运行训练好的模型。英特尔还有一个 OpenVINO 库,旨在优化预测性能。


总结

在本章中,你了解了各种深度学习库及其一些特点。具体来说,你学到了:

  • C++ 和 Python 中有哪些可用的库
  • Chainer 库如何影响了深度学习模型的构建语法
  • Keras 与 TensorFlow 2.x 之间的关系
  • PyTorch 和 TensorFlow 之间的区别

在下一章中,你将进一步了解本教程中所选择的深度学习库——PyTorch。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值