第二篇 FastAI数据准备「建议收藏」
一、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:channelsxheightxwidth。Image.size:heightxwidth。
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()函數,用于圖像縮放,其參數為一個整數,或者HxW型的元組。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數據說明
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類的文檔
總結
以上是生活随笔為你收集整理的第二篇 FastAI数据准备「建议收藏」的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 什么是 SAP Fiori Tools
- 下一篇: 1bit等于多少字节,换算方法??[通俗