使用PyTorch进行批量预测
%matplotlib inline
此示例遵循Torch的迁移学习教程。我们会
-
对特定任务(蚂蚁与蜜蜂)微调预训练的卷积神经网络。
-
使用Dask群集对该模型进行批量预测。
主要重点是使用Dask群集进行批次预测。
请注意,examples.dask.org Binder上的基本环境不包括PyTorch或torchvision。要运行此示例,您需要运行
!conda install -y pytorch-cpu torchvision
这将需要一些时间才能运行。
下载资料
PyTorch文档包含一小组数据。我们将在本地下载并解压缩。
import urllib.request import zipfile
filename, _ = urllib.request.urlretrieve("https://download.pytorch.org/tutorial/hymenoptera_data.zip", "data.zip") zipfile.ZipFile(filename).extractall()
目录看起来像
hymenoptera_data/ train/ ants/ 0013035.jpg ... 1030023514_aad5c608f9.jpg bees/ 1092977343_cb42b38d62.jpg ... 2486729079_62df0920be.jpg train/ ants/ 0013025.jpg ... 1030023514_aad5c606d9.jpg bees/ 1092977343_cb42b38e62.jpg ... 2486729079_62df0921be.jpg
在学习完本教程之后,我们将对模型进行微调。
import torchvision from tutorial_helper import (imshow, train_model, visualize_model, dataloaders, class_names, finetune_model)
微调模型
我们的基本模型是resnet18。它可以预测1,000种类别,而我们只预测2种(蚂蚁或蜜蜂)。为了使该模型在examples.dask.org上快速培训,我们仅使用几个纪元。
import dask
%%time model = finetune_model()
时代0/1 ---------- 火车损失:0.6196累积:0.6844 val损失:0.2042 Acc:0.9281 时代1/1 ---------- 火车损失:0.4517累积:0.7787 val损失:0.1458 Acc:0.9477 训练在0m 4s内完成 最佳增值值:0.947712 CPU时间:用户3.92 s,系统:2.03 s,总计:5.95 s 挂墙时间:6.33 s
在一些随机图像上,事情似乎还可以:
visualize_model(model)
使用Dask进行批量预测
现在是主要主题:在Dask集群上使用预训练的模型进行批量预测。有两个主要的复杂性,它们都涉及最小化移动的数据量:
-
将数据加载到工作程序上。。我们将用于
dask.delayed
将数据加载到工作程序上,而不是将数据加载到客户端上并将其发送给工作程序。 -
PyTorch神经网络很大。我们不希望它们出现在Dask任务图中,我们只希望将它们移动一次。
from distributed import Client client = Client(n_workers=2, threads_per_worker=2) client
客户
|
簇
|
将数据加载到工作人员上
首先,我们将定义几个助手来加载数据并对神经网络进行预处理。我们将dask.delayed
在这里使用它,以便执行是懒惰的,并且在集群上进行。有关使用的更多信息,请参见延迟的示例dask.delayed
。
import glob import toolz import dask import dask.array as da import torch from torchvision import transforms from PIL import Image @dask.delayed def load(path, fs=__builtins__): with fs.open(path, 'rb') as f: img = Image.open(f).convert("RGB") return img @dask.delayed def transform(img): trn = transforms.Compose([ transforms.Resize(256), transforms.CenterCrop(224), transforms.ToTensor(), transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]) ]) return trn(img)
objs = [load(x) for x in glob.glob("hymenoptera_data/val/*/*.jpg")]
要从云存储(例如Amazon S3)加载数据,您将使用
import s3fs fs = s3fs.S3FileSystem(...) objs = [load(x, fs=fs) for x in fs.glob(...)]
PyTorch模型期望特定形状的张量,因此让我们对其进行转换。
tensors = [transform(x) for x in objs]
而且该模型需要成批的输入,因此让我们将其堆叠在一起。
batches = [dask.delayed(torch.stack)(batch) for batch in toolz.partition_all(10, tensors)] batches[:5]
[已延迟('stack-da59d324-464a-4dce-adfa-0dc99dc53299', 延迟的('stack-939f881b-58ba-4bb5-b4eb-1df6ccfa850f'), 延迟('stack-e3809d5d-84f2-4279-a1a6-71131f4d2c53'), 延迟的('stack-a172c545-7cdd-467f-a2bc-e5c5ae611d50'), 延迟('stack-8698c88b-6e05-442d-8346-8af67d0992ae')]
最后,我们将编写一个小的predict
帮助程序来预测输出类(0或1)。
@dask.delayed def predict(batch, model): with torch.no_grad(): out = model(batch) _, predicted = torch.max(out, 1) predicted = predicted.numpy() return predicted
移动模型
PyTorch神经网络很大,因此我们不想在任务图中重复很多次(每批一次)。
import pickle dask.utils.format_bytes(len(pickle.dumps(model)))
'44 .80 MB'
相反,我们还将模型本身包装在中dask.delayed
。这意味着该模型在Dask图中仅显示一次。
此外,由于我们在上面进行了微调(如果可以在GPU上运行,则可以在GPU上运行),因此我们应该将模型移回CPU。
dmodel = dask.delayed(model.cpu()) # ensuring model is on the CPU
现在,我们将使用(延迟)predict
方法来获得我们的预测。
predictions = [predict(batch, dmodel) for batch in batches] dask.visualize(predictions[:2])
可视化有些混乱,但是大型的PyTorch模型是这两个predict
任务的始祖。
现在,我们可以使用Dask集群执行所有工作了。由于我们正在使用的数据集很小,因此仅dask.compute
将结果带回本地客户端是安全的。对于较大的数据集,您将要写入磁盘或云存储,或者继续处理集群上的预测。
predictions = dask.compute(*predictions) predictions
(数组([1,1,1,0,1,0,1,1,1,1]), 数组([1,1,1,1,1,1,1,1,1,1,1]), 数组([1,1,1,1,1,1,1,1,1,1,1]), 数组([1,1,1,1,1,1,1,1,1,1,1]), 数组([1,1,1,1,1,1,1,1,1,1,1]), 数组([1,1,1,1,1,1,1,0,1,0]), 数组([1,1,1,1,1,1,1,1,1,1,1]), 数组([1,1,1,1,1,1,1,1,1,1,1]), array([1,1,1,0,0,0,0,0,0,0]), array([0,0,0,1,0,0,0,0,0,0]), 数组([1,0,0,0,0,0,0,0,0,0]), array([0,0,0,1,0,0,0,0,0,0]), array([0,0,0,1,0,0,0,0,0,0]), 数组([0,0,0,0,0,0,0,0,0,0]), 数组([0,0,0,0,0,0,0,0,0,0]), 数组([0,0,0]))
概要
本示例说明了如何使用PyTorch和Dask对一组图像进行批量预测。我们非常小心地将数据远程加载到群集上,并且只对大型神经网络进行一次序列化。