3.fastAI进阶(2)(DataBlock)

进阶DataBlock

1.1 从头开始创建一个DataBlock

DataBlock 可以理解为一个如何汇聚数据的模板,我们可以通过DataBlock的实例的 datasets 方法获取数据集、dataloaders方法来获取 Dataloader进行训练、
summary 方法来看数据集的构造细节。

下面的示例代码中创建了一个空的DataBlock,然后将文件名作为数据集传入其中,随后输出数据集的第一个。

from fastai.data.all import *
from fastai.vision.all import *
path = untar_data(URLs.PETS)
fnames = get_image_files(path/"images")# 下面的代码中使用get_items可以直接指定。
dblock = DataBlock()#创建一个空的DataBlock

dsets = dblock.datasets(fnames)
dsets.train[0]

在这里插入图片描述

默认情况下DataBlock对数据集的处理包含输入(X)和输出(Y),因为这里没做任何处理,所以打印出来2次重复的。

首先我们可以指定get_items 来确定如何获取数据集(X)。

dblock = DataBlock(get_items = get_image_files)

随后是如何获取标签值(Y)

观察数据集可知,文件名如果是大写英文开头,则为猫,小写则为狗,我们可以根据这种规则来对数据打标签,下面使用label_func函数来实现。

在这里插入图片描述

def label_func(fname):
    return "cat" if fname.name[0].isupper() else "dog"

dblock = DataBlock(get_items = get_image_files,
                   get_y     = label_func)

dsets = dblock.datasets(path/"images")
dsets.train[0]

可以看到train[0] 已经可以正常输出X,Y了(注意X虽然是路径,但框架可以很方便的通过这个完整的文件路径来获取图片)

在这里插入图片描述

我们现在知道了输入是图片(Images),输出是类别(Category), 我们可以通过blocks来制定输入和输出的类型。

dblock = DataBlock(blocks    = (ImageBlock, CategoryBlock),
                   get_items = get_image_files,
                   get_y     = label_func)

dsets = dblock.datasets(path/"images")
dsets.train[0]

在这里插入图片描述

这样的输出的train[0]就更为简单易懂了,输入为RGB图片,输出为类别下标1,我们可以通过dsets.vocab 来获取类别,这里1代表dog

在这里插入图片描述

接下来的是一些进一步的优化和展示。

splitter 表示对数据集中验证集的划分,这里是随机划分。

item_tfms 代表对X的处理,这里将他们的size都设置为224x224

dblock = DataBlock(blocks    = (ImageBlock, CategoryBlock),
                   get_items = get_image_files,
                   get_y     = label_func,
                   splitter  = RandomSplitter(),
                   item_tfms = Resize(224))

使用show_bach可以方便的查看数据集

dls = dblock.dataloaders(path/"images")
dls.show_batch()

在这里插入图片描述

总结一下,我们可以通过回答下列的问题来构建一个datablock:

  • 输入(X)/目标(Y)的类型分别是什么? 上文例子中为 图片/类别。
  • 数据在哪里? 这里的输入来自一个文件夹
  • 有无必要在数据输入时做一些处理?这里没有做任何处理
  • 有无必要对目标(Y)做一些处理?这里 使用 label_func
  • 如何划分训练集和验证集?这里使用的是随机划分。
  • 需要对样本进行格式统一操作吗? 这里图片大小不一致,使用resize 进行调整。
  • 需要对batches进行统一处理吗? 这里不需要。

1.2 MINST数据集

接下来将使用MNIST_TINY手写数据集进行学习,这个数据集中包含一些数字3和7的手写图片

首先看一下要使用的数据集目录结构, mnist_tiny下已经划分好了训练集验证集和测试集。

在这里插入图片描述

三个数据集目录下有两个子目录3 和7 代表两个数字的图片集。

在这里插入图片描述

如何构建DataBlock?

首先,输入的图片并不是RGB图片而是黑白图片,因此要指定ImageBlock的类别为 cls=PILImageBW

如何获取图片标签? 这里图片所在的目录即为类别,可以通过get_y=parent_label来获取。

如何划分数据集? 这里数据集已经分好类了,图片的上两级目录(grandparent ,或者说父目录的父目录)即为不同的数据集splitter=GrandparentSplitter()

如一张图片目录为 train/3/9932.png , 其parent 即为3,其grandparent即为train。

mnist = DataBlock(blocks=(ImageBlock(cls=PILImageBW), CategoryBlock), 
                  get_items=get_image_files, 
                  splitter=GrandparentSplitter(),
                  get_y=parent_label)

构造完成后,可以查看一下具体的内容

dls = mnist.dataloaders(untar_data(URLs.MNIST_TINY))
dls.show_batch(max_n=9, figsize=(4,4))

在这里插入图片描述

也可以通过summary看看构造的具体过程

在这里插入图片描述

1.3 Oxford IIIT Pets dataset 数据集(多分类+标签处理)

我们一开始用的数据集就是这个,不过刚才只关注猫狗的二分类,实际上这个数据集 共有37种不同的类别。

在这里插入图片描述

图片的格式为 品种_序号.jpg ,其中品种可能有多个单词,也使用 _ 进行分割。大小写分别代表猫和狗。

如何构造DataBlock?

比较难的点在于获取标签,使用如下代码来获取

get_y=Pipeline([attrgetter("name"), RegexLabeller(pat = r'^(.*)_\d+.jpg$')]),

首先调用artrgetter来获取 输入的Pathname的值(即文件名)。

然后调用RegexLabeller(正则匹配)对这个值进行处理,最后获取类别。

最后使用PipeLine方法来将这两个处理合并。

pets = DataBlock(blocks=(ImageBlock, CategoryBlock), 
                 get_items=get_image_files, 
                 splitter=RandomSplitter(),
                 get_y=Pipeline([attrgetter("name"), RegexLabeller(pat = r'^(.*)_\d+.jpg$')]),
                 item_tfms=Resize(128),
                 batch_tfms=aug_transforms())

1.4 Pascal (多标签分类)

加载

pascal_source = untar_data(URLs.PASCAL_2007)
df = pd.read_csv(pascal_source/"train.csv")

图片中可能有多个标签(如骑马的图片中会有人 和马的标签)

在这里插入图片描述

如何构造DataBlock?

这里对DataBlock输入的是一个csv文件,我们可以根据其每行的数据来构造数据集。

pascal = DataBlock(blocks=(ImageBlock, MultiCategoryBlock),
                   splitter=ColSplitter(),
                   get_x=ColReader(0, pref=pascal_source/"train"),
                   get_y=ColReader(1, label_delim=' '),
                   item_tfms=Resize(224),
                   batch_tfms=aug_transforms())

dls = pascal.dataloaders(df)
dls.show_batch()

通过 get_y=ColReader(1, label_delim=' '),的label_delim来设置按空格分隔。

pascal = DataBlock(blocks=(ImageBlock, MultiCategoryBlock),
                   splitter=ColSplitter(),
                   get_x=lambda x:pascal_source/"train"/f'{x[0]}',
                   get_y=lambda x:x[1].split(' '),
                   item_tfms=Resize(224),
                   batch_tfms=aug_transforms())

通过使用lambda 表达式来更简洁的进行分割。

def _pascal_items(x): return (
    f'{pascal_source}/train/'+x.fname, x.labels.str.split())
valid_idx = df[df['is_valid']].index.values

pascal = DataBlock.from_columns(blocks=(ImageBlock, MultiCategoryBlock),
                   get_items=_pascal_items,
                   splitter=IndexSplitter(valid_idx),
                   item_tfms=Resize(224),
                   batch_tfms=aug_transforms())

这个跟前两个不同的是,调用了DataBlock的from_columns方法来构造。

  1. 通过使用自定义函数,该函数的输入为csv的行,我们可以根据列名字来访问成员,其返回值为(X,Y)。

  2. 通过df[df['is_valid']].index.values 获取了所有is_valid为True的下标用于验证集的划分。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

1.4 图片定位

图像定位类别中有各种问题:图像分割(这是一项必须预测图像中每个像素类别的任务)、坐标预测(预测图像上的一个或多个关键点)和目标检测(在要检测的对象周围画一个框)。

图像分割

将图片的所有像素进行分类。首先输入是一张正常的图片,输出则为对图片所有像素分好类的图片。

数据集的(X,Y)如下:

在这里插入图片描述

camvid = DataBlock(blocks=(ImageBlock, MaskBlock(codes = np.loadtxt(path/'codes.txt', dtype=str))),
    get_items=get_image_files,
    splitter=RandomSplitter(),
    get_y=lambda o: path/'labels'/f'{o.stem}_P{o.suffix}',
    batch_tfms=aug_transforms())

首先是MaskBlockMaskBlock(codes = np.loadtxt(path/'codes.txt', dtype=str) 即我们的输出的像素的类别由codes.txt来定义。

获取Y的方法: lambda o: path/'labels'/f'{o.stem}_P{o.suffix}',

图片的文件名为0001TP_006750.png ,输出的文件名为0001TP_006750_P.png ,f’{o.stem}_P{o.suffix} '即为

f’{0001TP_006750}_P{.jpg}’

坐标预测

biwi = DataBlock(blocks=(ImageBlock, PointBlock),
                 get_items=get_image_files,
                 splitter=RandomSplitter(),
                 get_y=lambda o:fn2ctr[o.name].flip(0),
                 batch_tfms=aug_transforms())

get_y=lambda o:fn2ctr[o.name].flip(0) 的作用是根据输入图像文件名,找到相应的目标坐标点,并进行翻转。这样,每个输入图像就有了与之相匹配的目标点,可以用于训练模型。

目标检测

这里使用的是COCO数据集, 它包含日常物品的图片,目的是通过在日常物品周围绘制矩形来预测日常物品的位置。

train.json对应了图片中的物品位置、物品类型

在这里插入图片描述

首先将其加载进来

在这里插入图片描述

img2bbox就是字典类型,key为文件名,Value就是图片中物品的位置、类型。这个字典后续用于标签的构造。

coco = DataBlock(blocks=(ImageBlock, BBoxBlock, BBoxLblBlock),
                 get_items=get_image_files,
                 splitter=RandomSplitter(),
                 get_y=[lambda o: img2bbox[o.name][0], lambda o: img2bbox[o.name][1]], 
                 item_tfms=Resize(128),
                 batch_tfms=aug_transforms(),
                 n_inp=1)

在block中有三个block,因为输出有box的坐标和box对应的类别,通过n_inp=1来说明输入截止的block(第一个)。

dls = coco.dataloaders(coco_source)
dls.show_batch(max_n=9)

语言模型

from fastai.text.all import *

path = untar_data(URLs.IMDB_SAMPLE)
df = pd.read_csv(path/'texts.csv')
df.head()

跟其他DataBlock不同的是,输入和输出几乎一致,因此这里只用了一个TextBlock

imdb_lm = DataBlock(blocks=TextBlock.from_df('text', is_lm=True),
                    get_x=ColReader('text'),
                    splitter=ColSplitter())
dls = imdb_lm.dataloaders(df, bs=64, seq_len=72)
dls.show_batch(max_n=6)

在这里插入图片描述

input[x]= output[x-1] ,用于训练预测下一个词,生成 文本。

on
from fastai.text.all import *

path = untar_data(URLs.IMDB_SAMPLE)
df = pd.read_csv(path/‘texts.csv’)
df.head()




跟其他DataBlock不同的是,输入和输出几乎一致,因此这里只用了一个TextBlock

````python
imdb_lm = DataBlock(blocks=TextBlock.from_df('text', is_lm=True),
                    get_x=ColReader('text'),
                    splitter=ColSplitter())
dls = imdb_lm.dataloaders(df, bs=64, seq_len=72)
dls.show_batch(max_n=6)

[外链图片转存中…(img-8E4GBCRz-1694058515427)]

input[x]= output[x-1] ,用于训练预测下一个词,生成 文本。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值