从模型到输出


收集数据

数据清洗

key = os.environ.get('AZURE_SEARCH_KEY', 'XXX')
# https://www.microsoft.com/en-us/bing/apis/bing-image-search-api
results = search_images_bing(key, 'grizzly bear')
ims = results.attrgot('contentUrl')
bear_types = 'grizzly','black','teddy'
path = Path('bears')
fns = get_image_files(path)
failed = verify_images(fns) # 检查文件是否已损坏
failed.map(Path.unlink) # 删除失败的图像

fastai:文档帮助

??function_name
?function_name
doc(function_name)

从数据到数据加载器

class DataLoaders(GetAttr):
    def __init__(self, *loaders): self.loaders = loaders
    def __getitem__(self, i): return self.loaders[i]
    train,valid = add_props(lambda i,self: self[i])
    pass

DataLoaders是一个fastai类,用于储存传递给它的多个DataLoader对象,通常用它定义处理训练集的train和处理验证集的valid。

将下载的数据转换为DataLoaders对象,fastai中有已经预定义的方法,当对特定任务不适用时,数据块API,可以完全自定义适合的DataLoaders。

bears = DataBlock( # 提供了一个DataBlock对象,类似于创建了DataLoaders的模板
    blocks=(ImageBlock, CategoryBlock), # 指定自变量(数据)和因变量的类型(预测目标)
    get_items=get_image_files, # 接受一个路径,返回该路径下所有图像的列表
    splitter=RandomSplitter(valid_pct=0.2, seed=42), # 
    get_y=parent_label, # 获取文件所在文件夹的名称,通常以文件夹名称为标签
    item_tfms=Resize(128)) # 数据转换,张量尺寸要一样

随机种子,每次都将获得完全相同的列表,每次运行,训练集和验证集都以相同的方式拆分。

dls = bears.dataloaders(path) # 告诉fastai数据的实际来源
dls.valid.show_batch(max_n=4, nrows=1) #show_batch方法查看其中的数据

数据转换

默认情况下使用全宽或全高裁剪图像,但可能丢失细节,也可以用零(黑色)来填充图像,或者挤压/拉伸图像。

bears = bears.new(item_tfms=Resize(128, ResizeMethod.Squish)) # Squish
# bears = bears.new(item_tfms=Resize(128, ResizeMethod.Pad, pad_mode='zeros')) #黑色填充
dls = bears.dataloaders(path)
dls.valid.show_batch(max_n=4, nrows=1) # 1行,四个

挤压或拉伸会改变原图像的形状,裁剪会删除一些特征,填充会有大量空白空间,有效分辨率低。

通常实践中,先随机选取图像中的某一部分,然后直接将选择的这部分图像裁剪出来作为新的图像进行后续处理。在每个周期(完整的数据集中的所有图像进行处理的过程)中,随机选择每张图像的不同部分。这意味着模型可以学习关注并识别图像中的不同特征,它还反映了图像在现实世界中的工作方式:同一事物的不同照片可能以略微不同的方式被框起来。

数据增强

数据增强是指创建输入数据的随机变体,以使他们看起来有所不同,但不会改变数据的含义。

图像的常见数据增强技术有:旋转、翻转、透视变形、亮度变化和对比度变化。

一个完全未经训练的神经网络对图像的各类特征一无所知,甚至不知道旋转1度之后仍是一个物体。

RandomResizedCrop替换Resizemin_scale决定了每次至少选择多少张图像,unique=True生成了同一张图像的不同版本。

bears = bears.new(item_tfms=RandomResizedCrop(128, min_scale=0.3))
dls = bears.dataloaders(path)
dls.train.show_batch(max_n=4, nrows=1, unique=True)

aug_transforms函数提供了一组标准数据增强方法。由于图像现在具有相同的大小,因此可以使用GPU将这些数据增强方法应用于整批图像,以节省时间。为了告诉fastai在batch上使用这些转换,使用batch_tfms参数。

bears = bears.new(item_tfms=Resize(128), batch_tfms=aug_transforms(mult=2))#两倍的扩充量
dls = bears.dataloaders(path)
dls.train.show_batch(max_n=8, nrows=2, unique=True)

训练模型,并使用模型进行数据清洗

训练分类器

熊分类器

bears = bears.new(
    item_tfms=RandomResizedCrop(224, min_scale=0.5),
    batch_tfms=aug_transforms())
dls = bears.dataloaders(path)

创建Learner,并微调

learn = vision_learner(dls, resnet18, metrics=error_rate)
learn.fine_tune(4)

可视化模型的错误-混淆矩阵

interp = ClassificationInterpretation.from_learner(learn)
interp.plot_confusion_matrix()

混淆矩阵

行代表数据集中的所有类别,包括黑熊、灰熊、泰迪熊,列代表模型预测为黑熊、灰熊、泰迪熊的图像。因此混淆矩阵的对角线显示正确分类的图像,非对角线单元代表分类错误的图像。(验证集计算得出的)

混淆矩阵能很好地帮助我们查看模型究竟是在哪里产生错误的预测的,是数据集的问题(例如错误的数据’根本不是熊的图像’或标注不正确的数据)还是模型的问题(也许图像处理的方式造成了异常的亮度或是很奇怪的角度)。为此可以按照损失对其进行排序。

如果模型输出的结果不正确(尤其是如果模型对自己的错误答案有信心),或者模型输出的结果是正确的,但模型对正确答案不是很确信,则相应的损失就会更高。

plot_top_losses显示数据集中损失最大的图像,每张图像都标有4样东西:预测结果、实际结果、损失、概率。

interp.plot_top_losses(5, nrows=1)

数据集中损失最大的图像

先训练一个快速而简单的模型,然后再使用它来帮助数据清洗。

fastai包含一个便于使用的用于数据清洗的GUI,称为ImageClassifierCleaner,允许选择好特定的类别,以及训练集与验证集,并按顺序查看损失最大的图像,并且还含有选择图像进行删除或重新标记的菜单栏。

cleaner = ImageClassifierCleaner(learn)
# for idx in cleaner.delete(): cleaner.fns[idx].unlink()
# for idx,cat in cleaner.change(): shutil.move(str(cleaner.fns[idx]), path/cat)

注意: 不需要大数据: 在使用这些步骤清洗数据集后,通常会看到这个任务100% 的准确率。当我们下载的图像比我们在这里使用的每个类150张图片少得多时,我们甚至可以预见该结果。如你所见,通常大家都认为需要大量的数据才能进行深度学习,但这个例子证明,这种说法与现实情况可能相去甚远。

将模型转换为在线应用程序

使用模型进行推理

训练完模型并对结果满意之后就可以进行部署模型。要模型部署到生产环境中,需要保存模型的架构训练参数

learn.export() # 导出名为export.pkl文件
path = Path()
path.ls(file_exts='.pkl')

当使用模型来获取预测结果时,称为推理(inference)。

learn_inf = load_learner(path/'export.pkl')
learn_inf.predict('images/grizzly.jpg')
# ('grizzly', tensor(1), tensor([9.0767e-06, 9.9999e-01, 1.5748e-07]))
learn_inf.dls.vocab # vocab是一个存储了所有可能类别的列表
# (#3) ['black','grizzly','teddy']

从模型创建notebook应用

Jupyter notebook创建一个完整的、可工作的Web应用程序。安装以下两个插件:

  • IPython widgets (ipywidgets)
  • Voilà
btn_upload = widgets.FileUpload()
def on_click_classify(change):
    img = PILImage.create(btn_upload.data[-1])
    out_pl.clear_output()
    with out_pl: display(img.to_thumb(128,128))
    pred,pred_idx,probs = learn_inf.predict(img)
    lbl_pred.value = f'Prediction: {pred}; Probability: {probs[pred_idx]:.04f}'

btn_run.on_click(on_click_classify)

GUI

让notebook成为一个真正的应用程序

#hide
# !pip install voila # 安装
# !jupyter serverextension enable --sys-prefix voila # 将voila连接到现有的Jupyter notebook

将浏览器URL中的“notebook”替换为“volia/render”。

https://nbviewer.org/github/fastai/fastbook/blob/master/02_production.ipynb

数据伦理

追索权和问责制

反馈回路

偏见


文章作者: nusqx
文章链接: https://nusqx.top
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 nusqx !
评论
  目录