Pytorch學(xué)習(xí)記錄-使用Pytorch進行深度學(xué)習(xí),數(shù)據(jù)加載和預(yù)處理

首頁.jpg

注意確定已經(jīng)安裝了torch和torchvision
數(shù)據(jù)加載和預(yù)處理
在完成60分鐘入門之后,接下來有六節(jié)tutorials和五節(jié)關(guān)于文本處理的tutorials。爭取一天一節(jié)。不過重點還是神經(jīng)網(wǎng)絡(luò)構(gòu)建和數(shù)據(jù)處理部分。

運行任何機器學(xué)習(xí)都會在準備數(shù)據(jù)上花費很大精力,畢竟Rubbish in Rubbish out。Pytorch提供很多工具幫助使數(shù)據(jù)加載更加簡便。本教程中,我們將看到圖和從一個不重要的數(shù)據(jù)集中加載和預(yù)處理/增強數(shù)據(jù)。
預(yù)安裝庫

  • scikit-image:安裝pip install scikit-image,下載有點慢,記得關(guān)閉VPN。
  • pandas:用于更快捷地讀取csv數(shù)據(jù)。
    這次要處理的數(shù)據(jù)集是面部姿勢,意味著一張人臉將像下面這樣被標注。
    image.png

    數(shù)據(jù)下載可以從官網(wǎng)下載,解壓后會看到人臉和相應(yīng)的labels文件。
    image.png

    在csv文件中可以發(fā)現(xiàn),一共有68個part,就是說一張臉有68個點會被標注。

1. 讀取數(shù)據(jù)

1.1 引入必須庫

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

import warnings
warnings.filterwarnings('ignore')

1.2 使用pandas讀取csv數(shù)據(jù)

landmarks_frame = pd.read_csv('data/faces/face_landmarks.csv')
n = 10
img_name = landmarks_frame.ix[n, 0]
landmarks = landmarks_frame.ix[n, 1:].as_matrix().astype('float')
landmarks = landmarks.reshape(-1, 2)
print('image name:{}'.format(img_name))
print('landmarks shape:{}'.format(landmarks.shape))
print('first 4 landmarks"{}'.format(landmarks[:4]))

讀取數(shù)據(jù)后,我們可以展示一下數(shù)據(jù)

def show_landmarks(image, landmarks):
    plt.imshow(image)
    plt.scatter(landmarks[:,0],landmarks[:,1],s=10,marker='.',c='r')
    plt.pause(0.001)

plt.figure()
show_landmarks(io.imread(os.path.join('data/faces/',img_name)),landmarks)
plt.show()
image.png

2. Dataset類

torch.utils.data.Dataset是用于表示數(shù)據(jù)集的類,常用數(shù)據(jù)集都繼承自Dataset,并且覆蓋下面兩個方法:

  • len,len(dataset)返回的時數(shù)據(jù)集的大小
  • getitem,是數(shù)據(jù)集支持索引操作, dataset[i]
    教程構(gòu)建了一個dataset類。在init中讀取csv,讀取圖片的操作在getitem中進行,這樣時一次性存儲在內(nèi)存中,更加高效。

數(shù)據(jù)集的樣本時一個字典格式{'image':image, 'landmarks':landmarks}。數(shù)據(jù)集會有一個操作參數(shù)transform,這樣任何需要操作的都能夠提交到樣例中來。

class FaceLandmarksDataset(Dataset):
    def __init__(self, csv_files, root_dir, transform=None):
        self.landmarks_frame = pd.read_csv(csv_files)
        self.root_dir = root_dir
        self.transform = transform

    def __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)
        landmarks = self.landmarks_frame.iloc[idx, 1:].as_matrix()
        landmarks = landmarks.astype('float').reshape(-1, 2)
        sample = {'image': image, 'landmarks': landmarks}

        if self.transform:
            sample = self.transform(sample)
        return sample

接下來就可以實現(xiàn)一下,輸出四張樣例和它們的標簽

face_dataset=FaceLandmarksDataset(csv_files='data/faces/face_landmarks.csv',root_dir='data/faces')
fig=plt.figure()
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

0 (324, 215, 3) (68, 2)
1 (500, 333, 3) (68, 2)
2 (250, 258, 3) (68, 2)
3 (434, 290, 3) (68, 2)
image.png

3. Transform

上面輸出的圖有一些問題,樣本的尺寸不一,而神經(jīng)網(wǎng)絡(luò)希望處理的是固定大小的數(shù)據(jù),這樣就需要對這些數(shù)據(jù)做一些預(yù)處理。
在前面的Transformer模型中,mask其實也是一種Transform,將不一致的句子通過掩碼調(diào)整成相同長度。
這里有三種變換

  • Rescale縮放圖像
  • RandomCrop隨機剪裁圖像,這是一種數(shù)據(jù)增強的方法
  • ToTensor把 numpy 圖像轉(zhuǎn)換為 PyTorch 圖像(我們需要交換軸)

我們將把它們寫成一個可調(diào)用的類而不是函數(shù),所以變換所需的參數(shù)不必在每次調(diào)用時都傳遞。為此,我們只需實現(xiàn) call 方法,如果需要可以實現(xiàn) init 方法。我們可以向下面這樣使用他們,這段不在代碼中體現(xiàn)

tsfm = Transform(params)
transform_sample = tsfm(sample)

下面實現(xiàn)Transform,是對上面三種變化的實現(xiàn)

class Rescale(object):
    '''
    將圖片縮放成實例要求的大小
    '''

    def __init__(self, output_size):
        assert isinstance(output_size, (int, tuple))
        self.output_size = output_size

    def __call__(self, sample):
        image, landmarks = sample['image'], sample['landmarks']
        h, w = image.shape[:2]
        if isinstance(self.output_size, int):
            # 圖片的大小縮放,配平
            if h > w:
                new_h, new_w = self.output_size * h / w, self.output_size
            else:
                new_h, new_w = self.output_size, self.output_size * w / h
        else:
            new_h, new_w = self.output_size
        new_h, new_w = int(new_h), int(new_w)
        img = transform.resize(image, (new_h, new_w))

        landmarks = landmarks * [new_w / w, new_h / h]
        return {'image': img, 'landmarks': landmarks}


class RandomCrop(object):
    '''
    對樣例圖片進行隨機剪切
    '''

    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) == 2
            self.output_size = output_size

    def __call__(self, sample):
        image, landmarks = sample['image'], sample['landmarks']

        h, w = image.shape[:2]
        new_h, new_w = self.output_size
        top = np.random.randint(0, h - new_h)
        left = np.random.randint(0, w - new_w)
        img = image[top: top + new_h, left: left + new_w]

        landmarks = landmarks - [left, top]
        return {'image': img, 'landmarks': landmarks}


class ToTensor(object):
    '''
    將numpy數(shù)據(jù)轉(zhuǎn)為Tensors
    '''

    def __call__(self, sample):
        image, landmarks = sample['image'], sample['landmarks']

        # swap color axis because
        # numpy image: H x W x C
        # torch image: C X H X W
        image = image.transpose((2, 0, 1))
        return {'image': torch.from_numpy(image),
                'landmarks': torch.from_numpy(landmarks)}

3.2 整合Transform

假如我們想先把圖像的較短的一邊縮放到256,然后從中隨機剪裁一個224*224大小的圖像。即我們想要組合 Rescale 和 RandomCrop 兩個變換。
torchvision.transforms.Compose是一個簡單的可調(diào)用類,允許我們來組合多個變換

scale=Rescale(256)
crop=RandomCrop(128)
composed=transforms.Compose([Rescale(256),RandomCrop(224)])
fig=plt.figure()
sample=face_dataset[65]
for i ,tsfm in enumerate([scale, crop, composed]):
    transform_sample=tsfm(sample)
    ax=plt.subplot(1,3, i+1)
    plt.tight_layout()
    ax.set_title(type(tsfm).__name__)
    show_landmarks(**transform_sample)
plt.show()
image.png

4. 迭代數(shù)據(jù)集

將之前實現(xiàn)的類整合創(chuàng)建一個包含組合變換的數(shù)據(jù)集,執(zhí)行以下操作:

  • 批處理數(shù)據(jù)
  • 打亂數(shù)據(jù)
  • 使用multiprocessing加載數(shù)據(jù)
    torch.utils.data.DataLoader 是一個提供以上所有的功能的迭代器。main函數(shù)中相應(yīng)的參數(shù)很清楚。其中一個參數(shù)是 collate_fn。你可以指定如何使用 collate_fn 對樣本進行批處理。但是,對大多數(shù)情況來說,默認的自動分頁應(yīng)該可以正常工作的很好。
if __name__ == '__main__':
    # 搞定數(shù)據(jù),還有整合變換
    transformed_dataset = FaceLandmarksDataset(csv_files='data/faces/face_landmarks.csv', root_dir='data/faces',
                                               transform=transforms.Compose([
                                                   Rescale(256),
                                                   RandomCrop(224),
                                                   ToTensor()
                                               ]))
    # 使用DataLoader,包括變換好的數(shù)據(jù)集、批處理大小、自動打亂
    dataloader = DataLoader(transformed_dataset, batch_size=4, shuffle=True, num_workers=4)


    def show_landmarks_batch(sample_batched):
        images_batch, landmarks_batch = sample_batched['image'], sample_batched['landmarks']
        batch_size = len(images_batch)
        im_size = images_batch.size(2)
        grid = 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,
                        landmarks_batch[i, :, 1].numpy(),
                        s=10, marker='.', c='r')


    for i_batch, sample_batched in enumerate(dataloader):
        print(i_batch, sample_batched['image'].size(), sample_batched['landmarks'].size())

        if i_batch == 3:
            plt.figure()
            show_landmarks_batch(sample_batched)
            plt.axis('off')
            plt.ioff()
            plt.show()
            break

回顧一下數(shù)據(jù)預(yù)處理:

  • 加載數(shù)據(jù),監(jiān)督學(xué)習(xí)中,一般使用pandas讀取已有數(shù)據(jù)標簽
  • 使用Dataset表示表示數(shù)據(jù)集
  • 對數(shù)據(jù)進行轉(zhuǎn)換(縮放統(tǒng)一大小、裁剪、轉(zhuǎn)成Tensor)
  • 整合Compose數(shù)據(jù),使用DataLoader進行迭代
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容