深度学习是基于神经网络的机器学习模型的一种分支。在其他机器模型中,通过手动或依靠领域专业知识进行数据处理以找到有意义的特征;然而,深度学习可以模仿人脑来发现重要特征,提高模型性能。
深度学习模型有许多应用,包括人脸识别、欺诈检测、语音转文本、文本生成等等。深度学习已成为许多高级机器学习应用的标准方法,学习它们不会有任何损失。
为了开发这个深度学习模型,我们可以依靠各种库框架,而不是从零开始。在本文中,我们将讨论两个不同的库,即PyTorch和Lightning AI,用于开发深度学习模型。让我们开始吧。
PyTorch
PyTorch是一个用于训练深度学习神经网络的开源库框架。PyTorch由Meta group在2016年开发,并逐渐流行起来。其流行的原因在于PyTorch将Torch的GPU后端库与Python语言结合起来。这种组合使得该包易于用户理解,但在开发深度学习模型方面仍然强大。
PyTorch具有一些突出的特点,包括良好的前端界面、分布式训练和快速灵活的实验过程。由于PyTorch用户众多,社区开发和投资也非常庞大。因此,学习PyTorch从长远来看会非常有益。
PyTorch的构建块是张量,即用于编码所有输入、输出和模型参数的多维数组。你可以把张量想象成NumPy数组,但具有在GPU上运行的能力。
让我们试用一下PyTorch库。如果你没有GPU系统(尽管它也可以在CPU上工作),建议在云端进行教程,比如Google Colab。但是,如果你想在本地开始,我们需要通过这个页面安装库。选择适合你的系统和规格。
例如,如果你有一个支持CUDA的系统,下面的代码是用于pip安装的。
pip3 install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118
安装完成后,让我们尝试一些PyTorch的功能来开发深度学习模型。在本教程中,我们将基于PyTorch的网络教程,使用PyTorch制作一个简单的图像分类模型。我们将浏览代码并解释代码中发生的事情。
首先,我们需要使用PyTorch下载数据集。在本例中,我们将使用MNIST数据集,这是一个手写数字分类数据集。
from torchvision import datasets
train = datasets.MNIST(
root="image_data",
train=True,
download=True
)
test = datasets.MNIST(
root="image_data",
train=False,
download=True,
)
我们将下载MNIST的训练集和测试集到我们的根文件夹中。让我们看看我们的数据集是什么样子。
import matplotlib.pyplot as plt
for i, (img, label) in enumerate(list(train)[:10]):
plt.subplot(2, 5, i+1)
plt.imshow(img, cmap="gray")
plt.title(f'Label: {label}')
plt.axis('off')
plt.show()
每个图像都是一个介于零和九之间的单个数字,意味着我们有十个标签。接下来,让我们基于这个数据集开发一个图像分类器。
我们需要将图像数据集转换为张量,以便使用PyTorch开发深度学习模型。由于图像是PIL对象,我们可以使用PyTorch的ToTensor函数进行转换。此外,我们还可以使用datasets函数自动转换图像。
from torchvision.transforms import ToTensor
train = datasets.MNIST(
root="data",
train=True,
download=True,
transform=ToTensor()
)
test = datasets.MNIST(
root="data",
train=False,
download=True,
transform=ToTensor()
)
通过将转换函数传递给transform参数,我们可以控制数据的形式。接下来,我们将数据包装到DataLoader对象中,以便PyTorch模型可以访问我们的图像数据。
from torch.utils.data import DataLoader
size = 64
train_dl = DataLoader(train, batch_size=size)
test_dl = DataLoader(test, batch_size=size)
for X, y in test_dl:
print(f"X的形状[N, C, H, W]: {X.shape}")
print(f"y的形状: {y.shape} {y.dtype}")
break
X的形状[N, C, H, W]: torch.Size([64, 1, 28, 28])
y的形状: torch.Size([64]) torch.int64
在上面的代码中,我们为训练和测试数据创建了DataLoader对象。每个数据批次迭代将返回64个特征和标签。此外,我们的图像形状为28 * 28(高度 * 宽度)。
接下来,我们将开发神经网络模型对象。
from torch import nn
#如果有GPU访问权限,请更改为'cuda'
device = 'cpu'
class NNModel(nn.Module):
def __init__(self):
super().__init__()
self.flatten = nn.Flatten()
self.lr_stack = nn.Sequential(
nn.Linear(28*28, 128),
nn.ReLU(),
nn.Linear(128, 128),
nn.ReLU(),
nn.Linear(128, 10)
)
def forward(self, x):
x = self.flatten(x)
logits = self.lr_stack(x)
return logits
model = NNModel().to(device)
print(model)
NNModel(
(flatten): Flatten(start_dim=1, end_dim=-1)
(lr_stack): Sequential(
(0): Linear(in_features=784, out_features=128, bias=True)
(1): ReLU()
(2): Linear(in_features=128, out_features=128, bias=True)
(3): ReLU()
(4): Linear(in_features=128, out_features=10, bias=True)
)
)
在上面的对象中,我们创建了一个带有少量层结构的神经模型。为了开发神经模型对象,我们使用nn.module函数的子类化方法,在__init__中创建神经网络层。
我们首先使用flatten函数将2D图像数据转换为像素值。然后,我们使用sequential函数将我们的层包装成一系列层。在sequential函数内部,我们有我们的模型层:
nn.Linear(28*28, 128),
nn.ReLU(),
nn.Linear(128, 128),
nn.ReLU(),
nn.Linear(128, 10)
按顺序,上面发生的是:
- 首先,通过线性层中的线性函数将28 * 28个特征的输入数据转换为128个特征的输出。
- ReLU是一个非线性激活函数,介于模型输入和输出之间,引入非线性。
- 128个特征输入到线性层,并有128个特征输出。
- 另一个ReLU激活函数。
- 128个特征作为线性层的输入,10个特征作为输出(我们的数据集标签只有10个标签)。
最后,forward函数用于模型的实际输入过程。接下来,模型将需要损失函数和优化函数。
from torch.optim import SGD
loss_fn = nn.CrossEntropyLoss()
optimizer = SGD(model.parameters(), lr=1e-3)
在下面的代码中,我们只是在运行建模活动之前准备训练和测试。
import torch
def train(dataloader, model, loss_fn, optimizer):
size = len(dataloader.dataset)
model.train()
for batch, (X, y) in enumerate(dataloader):
X, y = X.to(device), y.to(device)
pred = model(X)
loss = loss_fn(pred, y)
loss.backward()
optimizer.step()
optimizer.zero_grad()
if batch % 100 == 0:
loss, current = loss.item(), (batch + 1) * len(X)
print(f"损失: {loss:>2f} [{current:>5d}/{size:>5d}]")
def test(dataloader, model, loss_fn):
size = len(dataloader.dataset)
num_batches = len(dataloader)
model.eval()
test_loss, correct = 0, 0
with torch.no_grad():
for X, y in dataloader:
X, y = X.to(device), y.to(device)
pred = model(X)
test_loss += loss_fn(pred, y).item()
correct += (pred.argmax(1) == y).type(torch.float).sum().item()
test_loss /= num_batches
correct /= size
print(f"测试错误:\n准确率:{(100*correct):>0.1f}%,平均损失:{test_loss:>2f} \n")
现在我们准备运行模型训练。我们需要决定我们想要使用模型进行多少个epoch(迭代)。对于这个例子,假设我们想要运行5次。
epoch = 5
for i in range(epoch):
print(f"Epoch {i+1}\n-------------------------------")
train(train_dl, model, loss_fn, optimizer)
test(test_dl, model, loss_fn)
print("完成!")
该模型现在已经完成训练,可以用于任何图像预测活动。结果可能会有所不同,所以请期待与上述图像不同的结果。
这只是PyTorch可以做的一些事情,但你可以看到使用PyTorch构建模型很容易。如果你对预训练模型感兴趣,PyTorch有一个可以访问的Hub。
Lighting AI
Lighting AI是一家提供各种产品的公司,用于减少训练PyTorch深度学习模型的时间并简化模型。他们的一个开源产品是PyTorch Lightning,它是一个提供训练和部署PyTorch模型框架的库。
Lighting提供了一些功能,包括代码灵活性、无样板文件、最小API和改进的团队协作。Lighting还提供了多GPU利用和快速、低精度训练等功能。这使Lighting成为开发PyTorch模型的良好选择。
让我们尝试使用Lighting进行模型开发。首先,我们需要安装这个包。
pip install lightning
安装Lighting后,我们还需要安装Lighting AI的另一个产品TorchMetrics,以简化度量选择。
pip install torchmetrics
安装所有库后,我们将尝试使用Lighting包装器开发与之前示例相同的模型。下面是开发模型的完整代码。
import torch
import torchmetrics
import pytorch_lightning as pl
from torch import nn
from torch.optim import SGD
# 如果你有GPU,将其更改为'cuda'
device = 'cpu'
class NNModel(pl.LightningModule):
def __init__(self):
super().__init__()
self.flatten = nn.Flatten()
self.lr_stack = nn.Sequential(
nn.Linear(28 * 28, 128),
nn.ReLU(),
nn.Linear(128, 128),
nn.ReLU(),
nn.Linear(128, 10)
)
self.train_acc = torchmetrics.Accuracy(task="multiclass", num_classes=10)
self.valid_acc = torchmetrics.Accuracy(task="multiclass", num_classes=10)
def forward(self, x):
x = self.flatten(x)
logits = self.lr_stack(x)
return logits
def training_step(self, batch, batch_idx):
x, y = batch
x, y = x.to(device), y.to(device)
pred = self(x)
loss = nn.CrossEntropyLoss()(pred, y)
self.log('train_loss', loss)
# 计算训练准确率
acc = self.train_acc(pred.softmax(dim=-1), y)
self.log('train_acc', acc, on_step=True, on_epoch=True, prog_bar=True)
return loss
def configure_optimizers(self):
return SGD(self.parameters(), lr=1e-3)
def test_step(self, batch, batch_idx):
x, y = batch
x, y = x.to(device), y.to(device)
pred = self(x)
loss = nn.CrossEntropyLoss()(pred, y)
self.log('test_loss', loss)
# 计算测试准确率
acc = self.valid_acc(pred.softmax(dim=-1), y)
self.log('test_acc', acc, on_step=True, on_epoch=True, prog_bar=True)
return loss
让我们分解一下上面的代码发生了什么。与我们之前开发的PyTorch模型不同的是,NNModel类现在使用LightingModule的子类化。此外,我们使用TorchMetrics分配了用于评估的准确率指标。然后,我们在类内部添加了训练和测试步骤,并设置了优化函数。
有了所有设置好的模型,我们将使用转换后的DataLoader对象来运行模型训练。
# 创建一个PyTorch Lightning训练器
trainer = pl.Trainer(max_epochs=5)
# 创建模型
model = NNModel()
# 拟合模型
trainer.fit(model, train_dl)
# 测试模型
trainer.test(model, test_dl)
print("训练完成")
使用Lightning库,我们可以轻松调整所需的结构。要进一步阅读,请查阅他们的文档。
结论
PyTorch是一个用于开发深度学习模型的库,它提供了一个简单的框架,可以访问许多高级API。Lightning AI也支持该库,它提供了一个简化模型开发和增强开发灵活性的框架。本文介绍了库的特点和简单的代码实现。Cornellius Yudha Wijaya是一名数据科学助理经理和数据作者。在全职工作于Allianz Indonesia的同时,他喜欢通过社交媒体和写作媒体分享Python和数据技巧。