大家好,又见面了,我是你们的朋友全栈君。
一、Fast AI
代码组织结构 (文档链接)
Fast AI
库主要涉及神经网络在如下四个领域的应用:collab
(协同滤波问题)、tabular
(结构化数据或者说表格数据处理)、text
(自然语言处理)、vision
(机器视觉)。对每一领域(除了collab
),其下又会按照如下结构组织代码:
- (1)
data
:定义了模型所需的数据集类。 - (2)
transform
:数据预处理(如对图像数据的图像增强,表格数据的数据清洗,文本数据的符号化以及数字化) - (3)
models
:定义了相应的网络模型。 - (4)
learner
:定义了将数据和模型关联起来的类,并定义了一系列回调函数。
本系列博客所关注的vision
包,同样是按照如上结构进行组织的,同时也定义了专用于视觉处理的对象:
- (1)
vision.Image
定义了Fast AI
的Image
对象,以及对其进行操作的函数。 - (2)
vision.data
定义了专用于视觉应用的ImageDataBunch
数据集,以及可从DataBunch
构建的用于视觉应用的函数。 - (3)
vision.transform
定义了可用于数据增强的变换。 - (4)
vision.learner
定义了可用于训练网络或迁移学习的一些函数。
若要使用vision
包的功能,仅需如下语句进行导入相关定义:
from fastai.vision import *
二、 vision.Image
数据类型(fastai/vision/image.py
)
Fast AI
用于图像处理的基础类型为Image
,是在PIL.Image
类型上构建的,并封装了一些常用函数。
1. 构建Image
对象
Fast AI
提供了一个将图像文件读取为vision.Image
对象的函数open_image
(定义在fastai/vision/image.py
文件中):
open_image( fn:PathOrStr, # 文件路径
div:bool=True, # 是否除以255
convert_mode:str='RGB', # 转换方式,同PIL.Image
cls:type=Image, # 返回的类型
after_open:Callable=None) # 打开文件后的回调
上述函数以PIL.Image.open()
方式打开fn
指定的文件后,做after_open
的处理,然后调用pil2tensor()
函数将之转换成float32
型的tensor
(会进行维度的交换调整,调整后变为C x H x W
),依据div
决定是否做归一化操作(默认是做归一化操作的),最后转换为cls
类型的变量。cls
默认使用vision.Image
类型。
所以,Image
类型还可使用C x H x W
形状的float32
型的tensor
类直接进行初始化。
2. Image
对象的一些通用属性
Image.data
: 图像像素数据,以tensor
形式存储。Image.shape
:channels
xheight
xwidth
。Image.size
:height
xwidth
。
3. Image
对象的一些通用函数
Image.show()
函数,用于显示图像
Image.show(
ax:Axes=None, # 指定用于显示图像的图对象(由matplotlib的相关函数生成)
figsize:tuple=(3, 3), # 图的大小
title:Optional[str]=None, # 图的标题
hide_axis:bool=True, # 隐藏坐标轴
cmap:str=None, # color map, 与matplotlib中的cmap一致
y:Any=None, # 是否有额外的显示,如定位框、图像掩膜之类的
**kwargs
)
Image.rotate()
函数,用于图像旋转,这是一个神奇的函数,在Image
类及其父类ItemBase
中,均找不到它的定义,不过应该和PIL.Image.rotate()
函数类似。对于旋转后需要扩充的像素,采用的是反射补全。
Image.resize()
函数,用于图像缩放,其参数为一个整数,或者H
xW
型的元组。
Image.apply_tfms()
函数,用于图像变换:
apply_tfms(
tfms:Union[Callable, Collection[Callable]], # 变换列表
do_resolve:bool=True, # 是否重新设置随机化参数。比如对于图像分割,
# 对image和mask需要做同样的缩放或平移,
# 此时即需要设置do_resolve=False
xtra:Optional[Dict[Callable, dict]]=None, # 变换所需的额外的参数
size:Union[int, TensorImageSize, NoneType]=None, # 输出图片的尺寸
resize_method:ResizeMethod=None, # 如何达到最终所要的尺寸 [crop, pad, squish]
mult:int=None, # 保证最终所得图像的尺寸是mult的倍数
padding_mode:str='reflection', # 填充方法 ["zero", "border", "reflection"]
mode:str='bilinear', remove_out:bool=True) → Tensor
除去vision.Image
类外,Fast AI
还定义了一些用于具体任务的类,如用于图像分割的ImageSegment
类,用于目标检测的ImageBBox
类,用于关键点定位的ImagePoints
类等。这些将在相关应用场景下进行介绍。
三、 用于灌入网络的数据装配类型vision.ImageDataBunch
类(fastai/vision/data.py
)
由前一博客的示例,Fast AI
会将训练集、验证集、测试集的数据迭代器组合成DataBunch
对象。而对于视觉领域的应用,Fast AI
提供了更为合适的数据装配类型:ImageDataBunch
类。
对于视觉任务而言,其数据一般有两种组织方式:
ImageNet
类的数据组织形式:每类的图像位于各自的文件夹下:
path
train
class1 class2 ...
valid
class1 class2 ...
test
以csv
文件给出图像以及对应的label
:
path
train test labels.csv
针对这些情形,Fast AI
提供了用于构建ImageDataBunch
的6种工厂类方法。这6种方法均是基于ImageDataBunch.create_from_ll()
方法。由前所述,ImageDataBunch
仅是整合了用于灌入网络的数据加载器(即训练集、验证集和可选的测试集),因此,create_from_ll()
方法也很简单:指定训练集、验证集、测试集的文件列表,指定网络每次读取的数据的大小(batch size
),指定对数据进行的变换等等。
@classmethod
def create_from_ll(cls,
lls:LabelLists, # 文件列表
bs:int=64, val_bs:int=None, # batch size
ds_tfms:Optional[TfmList]=None, # 对数据进行的变换
num_workers:int=defaults.cpus,
dl_tfms:Optional[Collection[Callable]]=None,
device:torch.device=None,
test:Optional[PathOrStr]=None, # 测试数据集的路径
collate_fn:Callable=data_collate,
size:int=None, # 图像大小
no_check:bool=False,
resize_method:ResizeMethod=None,
mult:int=None, padding_mode:str='reflection',
mode:str='bilinear',
tfm_y:bool=False # 是否对标签数据进行变换,如在图像分割任务中,是否对mask进行变换
)->'ImageDataBunch':
实际上很少直接调用这个看着很复杂的函数,而是调用6种工厂类函数。这些工厂类函数大同小异,仅是在如何提供数据标签方面有所差别。下面以fastai.URLs.MNIST_SAMPLE
数据为例演示其用法。
1. URLs.MNIST_SAMPLE
数据说明
代码语言:javascript复制path = untar_data(URLs.MNIST_SAMPLE)
会将数据文件下载至~/.fastai/data
目录下。数据目录结构为
mnist_sample
labels.csv
train(12396)
3(6131) 7(6265)
valid(2038)
3(1010) 7(1028)
数据仅包含MNIST
手写数字集的3
和7
两类,按照ImageNet
数据的组织格式存储,同时以labels.csv
文件提供文件名与类别的对应关系。其中labels.csv
中的每条记录的格式为:(注意其中的labels
不再是3
和7
,而变成了0
和1
)
图 1. labels.csv记录格式
2. 使用文件夹提供数据标签:from_folder()
工厂类方法
from_folder()
的函数签名如下:
@classmethod
def from_folder(cls,
path:PathOrStr, # 数据目录,包含train、valid等分类。
train:PathOrStr='train', # 训练集的文件夹名称,默认为train
valid:PathOrStr='valid', # 验证集的文件夹名称,默认为valid
valid_pct=None, seed:int=None, # 用于划分train和valid数据集的比例参数,以及随机种子
# 如果设置了valid_pct参数,则train、valid参数指定的文件夹不再起作用
classes:Collection=None, # 可以指定选取哪些类
**kwargs:Any)->'ImageDataBunch':
对于MNIST_SAMPLE
数据:
data = ImageDataBunch.from_folder(path, size=24)
3. 使用panda.DataFrame
对象提供数据标签:from_df()
工厂类方法
from_df()
的函数签名如下:
@classmethod
def from_df(cls,
path:PathOrStr, # 数据目录
df:pd.DataFrame, # 存储图像文件及其对应标签的DataFrame
folder:PathOrStr=None, # 相对于path的子路径
label_delim:str=None,
valid_pct:float=0.2, seed:int=None, # 用于划分train和valid数据集的比例参数,以及随机种子
fn_col:IntsOrStrs=0, label_col:IntsOrStrs=1, # 数据文件和标签的列
suffix:str='', # 文件ID是否需要添加后缀
**kwargs:Any)->'ImageDataBunch'
对于MNIST_SAMPLE
数据:
df = pd.read_csv(path/'labels.csv', header='infer')
data = ImageDataBunch.from_df(path, df=df)
其中labels.csv
可能会包含表头,所以会使用header='infer'
来做自动处理。如果labels.csv
中记录的文件路径和path
之间仍有子路径,则可通过folder
参数进行设置。如果labels.csv
中记录的文件路径没有后缀,则可通过suffix
参数指定。如:图像数据以jpg
格式存储在/home/user/data/train/
路径下,设置path="/home/user/data"
,另外labels.csv
中的文件路径为:img_1
、img_2
……,则可设置:folder="train"
,suffix=".jpg"
。
4. 使用csv
文件提供数据标签:from_csv()
工厂类方法
from_csv()
是基于from_df()
函数实现的,其函数签名如下:
@classmethod
def from_csv(cls,
path:PathOrStr, # 数据目录
folder:PathOrStr=None,
label_delim:str=None,
csv_labels:PathOrStr='labels.csv', # csv文件名
valid_pct:float=0.2, seed:int=None,
fn_col:int=0, label_col:int=1,
suffix:str='', delimiter:str=None,
header:Optional[Union[int,str]]='infer',
**kwargs:Any)->'ImageDataBunch'
其中csv
文件应位于path
路径下,如果csv
文件的名称为labels.csv
,则可省略csv
参数;csv
文件中指定的数据,应位于path/folder
路径下。
对于MNIST_SAMPLE
数据:
data = ImageDataBunch.from_csv(path, size=24)
5. 使用文件名提取数据标签:from_name_func()
工厂类方法
from_name_func()
函数的签名如下:
@classmethod
def from_name_func(cls,
path:PathOrStr, # 数据文件路径
fnames:FilePathList, # 数据文件列表
label_func:Callable, # 从文件名中提取标签的函数
valid_pct:float=0.2,
seed:int=None,**kwargs)
注意,函数将依据fnames
中存储的文件路径fname
来查找文件,而不是以path/fname
为路径。
对于MNIST_SAMPLE
数据,其数据文件路径形为:
'/home/user/.fastai/data/mnist_sample/train/3/7463.png'
'/home/user/.fastai/data/mnist_sample/train/7/3087.png'
故可通过检查3
或7
是否在路径中来判断文件类别:
df = pd.read_csv(path/'labels.csv', header='infer')
fnames = [path/file for file in df["name"]]
def get_labels(file_path):
return '3' if '/3/' in str(file_path) else '7'
data = ImageDataBunch.from_name_func(path, fnames, label_func=get_labels, size=24)
6. 使用正则表达式提取数据标签:from_name_re()
工厂类方法
from_name_re()
是基于from_name_func()
实现的,其函数签名为:
def from_name_re(cls,
path:PathOrStr,
fnames:FilePathList,
pat:str, # 正则表达式
valid_pct:float=0.2,
**kwargs)
对于MNIST_SAMPLE
数据,可通过提取数据文件所在的文件夹名称(即"3"
或者"7"
)来指定文件标签:
pat = r"/(d)/d .png$"
data = ImageDataBunch.from_name_re(path, fn_paths, pat=pat, size=24)
7. 使用列表提供数据标签:from_list()
工厂类方法
from_list()
的函数签名为:
@classmethod
def from_lists(cls,
path:PathOrStr,
fnames:FilePathList, # 文件名称列表
labels:Collection[str], # 标签列表
valid_pct:float=0.2, seed:int=None,
item_cls:Callable=None, **kwargs)
对于MNIST_SAMPLE
数据:
df = pd.read_csv(path/'labels.csv', header='infer')
fn_paths = [path/file for file in df["name"]]
def get_labels(file_path):
return '3' if '/3/' in str(file_path) else '7'
labels_ls = list(map(get_labels, fn_paths))
data = data = ImageDataBunch.from_lists(path, fn_paths, labels=labels_ls, size=24)
Fast AI
提供了一套整合数据文件与标签文件的数据类型和API
,上述6种工厂类方法均是在其基础上进行构建的。而这些数据类型和API
也提供了足够的灵活性,可在这6种工厂类方法不能覆盖的应用情景下(如想要通过文件夹区分训练集和验证集,而通过csv
文件提供数据标签),方便地构建出所需的数据集和标签集。这部分内容将在下一博客中进行阐述。
一些有用的链接
Fast AI
代码组织结构文档链接fastai.vision
概览fastai.vision.Image
数据类型文档fastai.vision.data
:ImageDataBunch
类的文档
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/196033.html原文链接:https://javaforall.cn