在本文中,将探讨如何使用fastai库来构建一个基于PyTorch的食物图像分类器。fastai是一个开源的深度学习库,它为实践者提供了高级组件,可以快速且轻松地在传统深度学习领域产生最先进的结果。同时,它也为研究人员提供了低级组件,可以混合和组合以创造新的技术。fastai是用Python编写的,并且基于PyTorch,因此理解本文需要具备Python知识。将在Google Colab中运行此代码。除了fastai,还将使用图形处理单元(GPU)以尽可能快地获得结果。
首先,需要安装fastai库。可以使用以下命令来安装:
!pip install -Uqq fastai
如果使用的是Anaconda,可以使用以下命令:
conda install -c fastchan fastai anaconda
接下来,将导入分类任务所需的包。fastai库被分为多个模块,其中最常见的是tabular、text和vision。由于任务涉及到视觉,将从vision库中导入所有需要的函数。
from fastai.vision.all import *
fastai库提供了许多学术数据集。其中之一是FOOD,它列在URLs下。获取和提取所需数据的第一步是使用untar_data函数,该函数将自动下载数据集并解压缩。
foodPath = untar_data(URLs.FOOD)
此数据集包含101,000张图片,分为101个食物类别,每个类别有250张测试图片和750张训练图片。训练中的图片没有被清理。所有图片都被调整到每边最大512像素。可以从下载数据集。
接下来的命令将告诉需要处理多少张图片。
len(get_image_files(foodPath))
此外,使用以下命令,将打印出Food数据集的meta目录的内容。
print(os.listdir(foodPath))
meta文件夹包含八个文件,其中四个是文本文件:train.txt、test.txt、classes.txt和labels.txt。train.txt和test.txt文件分别包含训练和测试集的图片列表。classes.txt文件包含所有食物类别的列表,而labels.txt提供所有食物图片标签的列表。该目录还包含一个.h5文件,其中包含预训练模型,以及一个包含101,000张JPG格式图片的images文件夹。最后,训练和测试集以JSON格式提供。
要查看所有图片类别,将运行以下命令:
image_dir_path = foodPath/'images'
image_categories = os.listdir(image_dir_path)
print(image_categories)
然后,将执行以下命令以查看101,000张图片中的一个样本图片。
img = PILImage.create('/root/.fastai/data/food-101/images/frozen_yogurt/1942235.jpg')
img.show();
将使用pandas函数以JSON格式读取训练和测试文件。JSON是一种数据格式,以人类可读的形式存储信息。以下代码读取目录中的train.json文件,并将结果保存在df_train数据框中。
df_train=pd.read_json('/root/.fastai/data/food-101/train.json')
df_train.head()
类似地,使用pandas函数,将读取test.json文件并将其存储在df_test数据框中。
df_test=pd.read_json('/root/.fastai/data/food-101/test.json')
df_test.head()
创建了三个标签,分别包含选择的食物名称,以对食物图片进行分类。
labelA = 'cheesecake'
labelB = 'donuts'
labelC= 'panna_cotta'
现在,将创建一个for循环,该循环将遍历下载的所有图片。借助此循环,正在移除没有标签A、B或C的图片。同时,正在使用以下函数通过使用各自的标签重命名图片。
for img in get_image_files(foodPath):
if labelA in str(img):
img.rename(f"{img.parent}/{labelA}-{img.name}")
elif labelB in str(img):
img.rename(f"{img.parent}/{labelB}-{img.name}")
elif labelC in str(img):
img.rename(f"{img.parent}/{labelC}-{img.name}")
else: os.remove(img)
让检查运行循环后得到的图片数量。
len(get_image_files(foodPath))
让尝试检查三个选定的食物菜肴中的一个样本标签,并查看重命名是否正确。
def GetLabel(fileName):
return fileName.split('-')[0]
GetLabel("cheesecake-1092082.jpg")
输出:
以下代码生成一个DataLoaders对象,它代表训练和验证数据的混合。
dls = ImageDataLoaders.from_name_func(
foodPath, get_image_files(foodPath), valid_pct=0.2, seed=42,
label_func=GetLabel, item_tfms=Resize(224))
dls.train.show_batch()
在这种情况下,将:
- 使用path选项指定下载和解压缩数据的位置。
- 使用get_image_files函数从指定位置收集所有文件名。
- 对数据集进行80-20的分割。
- 使用GetLabel函数从文件名中提取标签。
- 将所有图片调整到相同的大小,即224像素。
- 使用show_batch函数生成一个输出窗口,显示带有分配标签的训练图片网格。
是时候让模型发挥作用了。将使用ResNet34架构构建一个卷积神经网络,重点关注一个名为vision_learner()的单一函数调用。vision_learner函数(也称为cnn_learner)对于训练计算机视觉模型非常有益。它包括原始图像数据集、预训练模型resnet34和一个度量误差率,该误差率决定了在验证数据上错误识别的图片比例。resnet34中的34指的是这种架构类型的层数(其他选项是18、50、101和152)。使用更多层的模型需要更长的时间来训练,并且更容易过拟合。
fastai提供了一个‘fine_tune’函数,用于调整预训练模型以解决选择的数据的特定问题。对于训练模型,将设置训练周期的数量为10。
learn = vision_learner(dls, resnet34, metrics=error_rate, pretrained=True)
learn.fine_tune(epochs=10)
同样,也可以通过将度量替换为‘accuracy’来检查模型的准确性。
从上述结果中,可以说,即使只有10个周期,预训练的ResNet34模型也显示出对于多标签分类任务的>85%的良好准确性。如果增加周期的数量,模型的准确性可能会提高。
现在,让测试一些样本图片,以检查模型性能如何。
样本图片 #1
样本图片 #2
样本图片 #3
从上述结果中,可以说,模型能够正确识别样本图片。
训练模型后,可以将其部署为Web应用程序供其他人使用。尽管fastai主要用于模型训练,但可以快速导出PyTorch模型以在生产中使用‘learn.export’函数。本教程的代码可在中找到。
结论:
在本教程中,学习了如何使用基于PyTorch的fastai构建食物图像分类器。可以使用Heroku或Netlify等服务部署此模型,使其作为Web应用程序可用。