日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

PyTorch 系列 | 数据加载和预处理教程

發布時間:2023/12/10 编程问答 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 PyTorch 系列 | 数据加载和预处理教程 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

圖片來源:Unsplash,作者:Damiano Baschiera

2019 年第 66 篇文章,總第 90 篇文章

本文大約?8000?字,建議收藏閱讀

原題?| DATA LOADING AND PROCESSING TUTORIAL

作者?| Sasank Chilamkurthy

譯者?| kbsc13("算法猿的成長"公眾號作者)

原文?| https://pytorch.org/tutorials/beginner/data_loading_tutorial.html

聲明?| 翻譯是出于交流學習的目的,歡迎轉載,但請保留本文出于,請勿用作商業或者非法用途

簡介

本文教程主要是介紹如何加載、預處理并對數據進行增強的方法。

首先需要確保安裝以下幾個?python?庫:

  • scikit-image?:處理圖片數據

  • pandas?:處理 csv 文件

導入模塊代碼如下:

from?__future__?import?print_function,?division import?os import?torch import?pandas?as?pd from?skimage?import?io,?transform import?numpy?as?np import?matplotlib.pyplot?as?plt from?torch.utils.data?import?Dataset,?DataLoader from?torchvision?import?transforms,?utils#?Ignore?warnings import?warnings warnings.filterwarnings("ignore")plt.ion()???#?interactive?mode

本次教程采用的是一個人臉姿勢數據集,其圖片如下所示:

每張人臉都是有 68 個人臉關鍵點,它是由?dlib?生成的,具體實現可以查看其官網介紹:

https://blog.dlib.net/2014/08/real-time-face-pose-estimation.html

數據集下載地址:

https://download.pytorch.org/tutorial/faces.zip

數據集中的?csv?文件的格式如下所示,圖片名字和每個關鍵點的坐標?x, y

image_name,part_0_x,part_0_y,part_1_x,part_1_y,part_2_x,?...?,part_67_x,part_67_y 0805personali01.jpg,27,83,27,98,?...?84,134 1084239450_e76e00b7e7.jpg,70,236,71,257,?...?,128,312

數據集下載解壓縮后放到文件夾?data/faces?中,然后我們先快速打開?face_landmarks.csv?文件,查看文件內容,即標注信息,代碼如下所示:

landmarks_frame?=?pd.read_csv('data/faces/face_landmarks.csv')n?=?65 img_name?=?landmarks_frame.iloc[n,?0] landmarks?=?landmarks_frame.iloc[n,?1:].as_matrix() landmarks?=?landmarks.astype('float').reshape(-1,?2)print('Image?name:?{}'.format(img_name)) print('Landmarks?shape:?{}'.format(landmarks.shape)) print('First?4?Landmarks:?{}'.format(landmarks[:4]))

輸出如下所示:

接著寫一個輔助函數來顯示人臉圖片及其關鍵點,代碼如下所示:

def?show_landmarks(image,?landmarks):"""Show?image?with?landmarks"""plt.imshow(image)plt.scatter(landmarks[:,?0],?landmarks[:,?1],?s=10,?marker='.',?c='r')plt.pause(0.001)??#?pause?a?bit?so?that?plots?are?updatedplt.figure() show_landmarks(io.imread(os.path.join('data/faces/',?img_name)),landmarks) plt.show()

輸出如下所示:

Dataset 類

torch.utils.data.Dataset?是表示一個數據集的抽象類,在自定義自己的數據集的時候需要繼承?Dataset?類別,并重寫下方這些方法:

  • len?:調用?len(dataset)?時可以返回數據集的數量;

  • getitem:獲取數據,可以實現索引訪問,即?dataset[i]?可以訪問第?i?個樣本數據

接下來將給我們的人臉關鍵點數據集自定義一個類別,在?__init__?方法中將讀取數據集的信息,并在?__getitem__?方法調用獲取的數據集,這主要是基于內存的考慮,這種做法不需要將所有數據一次讀取存儲在內存中,可以在需要讀取數據的時候才讀取加載到內存里。

數據集的樣本將用一個字典表示:{'image': image, 'landmarks': landmarks},另外還有一個可選參數?transform?用于預處理讀取的樣本數據,下一節將介紹這個?transform?的用處。

自定義函數的代碼如下所示:

class?FaceLandmarksDataset(Dataset):"""Face?Landmarks?dataset."""def?__init__(self,?csv_file,?root_dir,?transform=None):"""Args:csv_file?(string):?帶有標注信息的?csv?文件路徑root_dir?(string):?圖片所在文件夾transform?(callable,?optional):?可選的用于預處理圖片的方法"""self.landmarks_frame?=?pd.read_csv(csv_file)self.root_dir?=?root_dirself.transform?=?transformdef?__len__(self):return?len(self.landmarks_frame)def?__getitem__(self,?idx):#?讀取圖片img_name?=?os.path.join(self.root_dir,self.landmarks_frame.iloc[idx,?0])image?=?io.imread(img_name)#?讀取關鍵點并轉換為?numpy?數組landmarks?=?self.landmarks_frame.iloc[idx,?1:]landmarks?=?np.array([landmarks])landmarks?=?landmarks.astype('float').reshape(-1,?2)sample?=?{'image':?image,?'landmarks':?landmarks}if?self.transform:sample?=?self.transform(sample)return?sample

接下來是一個簡單的例子來使用上述我們自定義的數據集類,例子中將讀取前 4 個樣本并展示:

face_dataset?=?FaceLandmarksDataset(csv_file='data/faces/face_landmarks.csv',root_dir='data/faces/')fig?=?plt.figure() #?讀取前?4?張圖片并展示 for?i?in?range(len(face_dataset)):sample?=?face_dataset[i]print(i,?sample['image'].shape,?sample['landmarks'].shape)ax?=?plt.subplot(1,?4,?i?+?1)plt.tight_layout()ax.set_title('Sample?#{}'.format(i))ax.axis('off')show_landmarks(**sample)if?i?==?3:plt.show()break

輸出結果如下所示:

Transforms

從上述例子輸出的結構可以看到一個問題,圖片的大小并不一致,但大多數神經網絡都需要輸入圖片的大小固定。因此,接下來是給出一些預處理的代碼,主要是下面三種預處理方法:

  • Rescale?:調整圖片大小

  • RandomCrop:隨機裁剪圖片,這是一種數據增強的方法

  • ToTensor:將?numpy?格式的圖片轉換為?pytorch?的數據格式?tensors,這里需要交換坐標。

這幾種方法都將寫成可調用的類,而不是簡單的函數,這樣就不需要每次都傳遞參數。因此,我們需要實現?__call__?方法,以及有必要的話,__init__?方法也是要實現的,然后就可以如下所示一樣調用這些方法:

tsfm?=?Transform(params) transformed_sample?=?tsfm(sample)

Rescale?方法的實現代碼如下:

class?Rescale(object):"""將圖片調整為給定的大小.Args:output_size (tuple or int):?期望輸出的圖片大小. 如果是 tuple 類型,輸出圖片大小就是給定的 output_size;如果是 int 類型,則圖片最短邊將匹配給的大小,然后調整最大邊以保持相同的比例。"""def?__init__(self,?output_size):assert?isinstance(output_size,?(int,?tuple))self.output_size?=?output_sizedef?__call__(self,?sample):image,?landmarks?=?sample['image'],?sample['landmarks']h,?w?=?image.shape[:2]#?判斷給定大小的形式,tuple?還是?int?類型if?isinstance(self.output_size,?int):#?int?類型,給定大小作為最短邊,最大邊長根據原來尺寸比例進行調整if?h?>?w:new_h,?new_w?=?self.output_size?*?h?/?w,?self.output_sizeelse:new_h,?new_w?=?self.output_size,?self.output_size?*?w?/?helse:new_h,?new_w?=?self.output_sizenew_h,?new_w?=?int(new_h),?int(new_w)img?=?transform.resize(image,?(new_h,?new_w))#?根據調整前后的尺寸比例,調整關鍵點的坐標位置,并且?x?對應?w,y?對應?hlandmarks?=?landmarks?*?[new_w?/?w,?new_h?/?h]return?{'image':?img,?'landmarks':?landmarks}

RandomCrop?的代碼實現:

class?RandomCrop(object):"""給定圖片,隨機裁剪其任意一個和給定大小一樣大的區域.Args:output_size (tuple or int):?期望裁剪的圖片大小。如果是 int,將得到一個正方形大小的圖片."""def?__init__(self,?output_size):assert?isinstance(output_size,?(int,?tuple))if?isinstance(output_size,?int):self.output_size?=?(output_size,?output_size)else:assert?len(output_size)?==?2self.output_size?=?output_sizedef?__call__(self,?sample):image,?landmarks?=?sample['image'],?sample['landmarks']h,?w?=?image.shape[:2]new_h,?new_w?=?self.output_size#?隨機選擇裁剪區域的左上角,即起點,(left,?top),范圍是由原始大小-輸出大小top?=?np.random.randint(0,?h?-?new_h)left?=?np.random.randint(0,?w?-?new_w)image?=?image[top:?top?+?new_h,left:?left?+?new_w]#?調整關鍵點坐標,平移選擇的裁剪起點landmarks?=?landmarks?-?[left,?top]return?{'image':?image,?'landmarks':?landmarks}

ToTensor?的方法實現:

class?ToTensor(object):"""將?ndarrays?轉換為?tensors."""def?__call__(self,?sample):image,?landmarks?=?sample['image'],?sample['landmarks']#?調整坐標尺寸,numpy?的維度是?H?x?W?x?C,而?torch?的圖片維度是?C?X?H?X?Wimage?=?image.transpose((2,?0,?1))return?{'image':?torch.from_numpy(image),'landmarks':?torch.from_numpy(landmarks)}

組合使用預處理方法

接下來就是介紹使用上述自定義的預處理方法的例子。

假設我們希望將圖片的最短邊長調整為 256,然后隨機裁剪一個 224*224 大小的圖片區域,也就是我們需要組合調用?Rescale?和?RandomCrop?預處理方法。

torchvision.transforms.Compose?是一個可以實現組合調用欲處理方法的類,實現代碼如下所示:

scale?=?Rescale(256) crop?=?RandomCrop(128) composed?=?transforms.Compose([Rescale(256),RandomCrop(224)])#?對圖片數據調用上述?3?種形式預處理方法,即單獨使用?Rescale,RandomCrop,組合使用?Rescale和?RandomCrop fig?=?plt.figure() sample?=?face_dataset[65] for?i,?tsfrm?in?enumerate([scale,?crop,?composed]):transformed_sample?=?tsfrm(sample)ax?=?plt.subplot(1,?3,?i?+?1)plt.tight_layout()ax.set_title(type(tsfrm).__name__)show_landmarks(**transformed_sample)plt.show()

輸出結構:

迭代整個數據集

現在我們已經定義好一個處理數據集的類,3種預處理數據的類,那么可以將它們整合在一起,實現加載并預處理數據的流程,流程如下所示:

  • 首先根據圖片路徑讀取圖片

  • 對圖片都調用預處理的方法

  • 預處理方法也可以實現數據增強

實現的代碼如下所示:

transformed_dataset?=?FaceLandmarksDataset(csv_file='data/faces/face_landmarks.csv',root_dir='data/faces/',transform=transforms.Compose([Rescale(256),RandomCrop(224),ToTensor()]))for?i?in?range(len(transformed_dataset)):sample?=?transformed_dataset[i]print(i,?sample['image'].size(),?sample['landmarks'].size())if?i?==?3:break

輸出結果:

上述只是一個簡單的處理過程,實際上處理和加載數據的時候,我們一般還對數據做以下的處理:

  • 將數據按給定大小分成一批一批數據

  • 打亂數據排列順序

  • 采用?multiprocessing?來并行加載數據

torch.utils.data.DataLoader?是一個可以實現上述操作的迭代器。其需要的參數如下代碼所示,其中一個參數?collate_fn?是用于指定如何對數據進行分批的操作,但也可以采用默認函數。

dataloader?=?DataLoader(transformed_dataset,?batch_size=4,shuffle=True,?num_workers=4)#?輔助函數,用于展示一個?batch?的數據 def?show_landmarks_batch(sample_batched):"""Show?image?with?landmarks?for?a?batch?of?samples."""images_batch,?landmarks_batch?=?\sample_batched['image'],?sample_batched['landmarks']batch_size?=?len(images_batch)im_size?=?images_batch.size(2)grid_border_size?=?2grid?=?utils.make_grid(images_batch)plt.imshow(grid.numpy().transpose((1,?2,?0)))for?i?in?range(batch_size):plt.scatter(landmarks_batch[i,?:,?0].numpy()?+?i?*?im_size?+?(i?+?1)?*?grid_border_size,landmarks_batch[i,?:,?1].numpy()?+?grid_border_size,s=10,?marker='.',?c='r')plt.title('Batch?from?dataloader')for?i_batch,?sample_batched?in?enumerate(dataloader):print(i_batch,?sample_batched['image'].size(),sample_batched['landmarks'].size())#?observe?4th?batch?and?stop.if?i_batch?==?3:plt.figure()show_landmarks_batch(sample_batched)plt.axis('off')plt.ioff()plt.show()break

輸出結果:

torchvision

最后介紹?torchvision?這個庫,它提供了一些常見的數據集和預處理方法,采用這個庫就可以不需要自定義類,它比較常用的方法是?ImageFolder?,它假定圖片的保存路徑如下所示:

root/ants/xxx.png root/ants/xxy.jpeg root/ants/xxz.png . . . root/bees/123.jpg root/bees/nsdf3.png root/bees/asd932_.png

這里的?ants,bees?等等都是類別標簽,此外對?PIL.Image?的預處理方法,如?RandomHorizontalFlip?、Scale?都包含在?torchvision?中,一個使用例子如下所示:

import?torch from?torchvision?import?transforms,?datasetsdata_transform?=?transforms.Compose([transforms.RandomSizedCrop(224),transforms.RandomHorizontalFlip(),transforms.ToTensor(),transforms.Normalize(mean=[0.485,?0.456,?0.406],std=[0.229,?0.224,?0.225])]) hymenoptera_dataset?=?datasets.ImageFolder(root='hymenoptera_data/train',transform=data_transform) dataset_loader?=?torch.utils.data.DataLoader(hymenoptera_dataset,batch_size=4,?shuffle=True,num_workers=4)

小結

本教程主要介紹如何對自己的數據集自定義一個類來加載,以及預處理的方法,同時最后也介紹了?PyTorch?中的?torchvision?,torch.utils.data.DataLoader?方法。

本文的代碼上傳至 Github:

https://github.com/ccc013/DeepLearning_Notes/blob/master/Pytorch/pytorch_dataloader_tutorial.ipynb

另外,還有用?dlib?生成人臉關鍵點的代碼:

https://github.com/ccc013/DeepLearning_Notes/blob/master/Pytorch/create_landmark_dataset.py

此外,也可以公眾號后臺回復“PyTorch”獲取本次教程的數據集和代碼。

留言時間


歡迎關注我的微信公眾號--算法猿的成長,或者掃描下方的二維碼,大家一起交流,學習和進步!

如果覺得不錯,在看、轉發就是對小編的一個支持!

總結

以上是生活随笔為你收集整理的PyTorch 系列 | 数据加载和预处理教程的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。