iT邦幫忙

2021 iThome 鐵人賽

DAY 27
0
AI & Data

Deep Learning 從零開始到放棄的 30 天 PyTorch 數字辨識模型系列 第 27

Day-26 手把手的手寫辨識模型 0x1:資料集整理

  • 我們今天要使用的資料集就是在機器學習世界鼎鼎大名的 MNIST(Modified National Institute of Standards and Technology),我們都知道在學程式語言的過程中,我們都會先寫一隻程式叫做 'hello world' 來和這個程式世界打聲招呼,那 MNIST 就是機器學習領域的 hello world~
  • 此資料集在 1999 年就發布了,至今歷經了幾次整理之後,可以看到已經在 kaggle 上面常駐,屬於此領域的敲門磚~
  • 那我們今天當然就要把資料好好的使用啦~ 今天我們來介紹兩種不同取得這個資料的方式吧~

Kaggle

Download

  • 那要取得 Kaggle 的 MNIST 其實非常簡單,只要在 Google 搜尋 Kaggle MNIST 就可以看到相對應的網頁了,我們也附在這裡
  • 那可以看到這份資料被放在 CSV 裡面去了,這時你應該會問,不是手寫圖片嗎?怎麼是 CSV 檔案?說好的照片呢?你四八四騙我 OAO
  • 我沒有騙你啦~這份 CSV 裡面就已經放好了整個手寫圖片的資訊了歐~讓我來解釋給你聽
  • 圖片是由 Pixel 所組成,也就是一個一個小方格子,那這張圖片其實是一張 28*28 大小的圖片,也就是說他的寬有 28 個 pixel ,高也有 28 個 pixel,所以整張圖片就是 784 個 pixel 組成的,因此 Kaggle 就把圖片資料分成一個一個 pixel 放到 CSV 中,因此我們可以發現 train.csv 這份檔案裡面每一行都是一張圖片,然後共有 785 欄,分別就是 1~784 個 pixel 的顏色狀況 + 1 欄答案
  • 所以基於這樣的狀況,我們來看看我們的 Dataset 要怎麼撰寫吧~

Dataset

  • 我們先解釋一下我們怎麼安排資料的狀況,大致上目錄結構長這樣
    ├── mnist.py
    ├── data
    ├ ├── train.csv
    └ └── test.csv
  • 所以我們要讀取資料的資料位置會是 path = './data/train.csv'
  • 那我們寫成 Dataset 的話會怎麼寫?
# 0) data import and set as pytorch dataset
class MnistDataset(Dataset):

    # data loading
    def __init__(self, path):
        xy = np.loadtxt(path, delimiter=',', dtype=np.float32, skiprows=1)
        self.x = torch.from_numpy(xy[:, 1:])
        self.y = torch.from_numpy(xy[:, [0]].flatten().astype(np.longlong))
        self.n_samples = xy.shape[0]

    # working for indexing
    def __getitem__(self, index):
        
        return self.x[index], self.y[index]

    # return the length of our dataset
    def __len__(self):
        
        return self.n_samples

train_path = './data/train.csv'
test_path = './data/test.csv'
train_dataset = MnistDataset(train_path)
test_dataset = MnistDataset(test_path)

train_loader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True)
test_loader = DataLoader(test_dataset, batch_size=batch_size, shuffle=True)
  • 由於我們兩份資料的檔案不同,因此我們可以傳遞位置來達到讀取不同檔案,那由於我們是 CSV file,裡面的資料分離是由 , 去做切分的,因此我們設定我們的 delimiter 為 ,
  • 那會看到裡面有 skiprows,是因為我們 CSV 中的第一行是名稱,那些並不是特徵,因此我們跳過讀取
  • 那這邊要注意由於資料現在都是攤平的 28 * 28 資料,但是我們使用 CNN 時需要是二維有通道的圖片資料,因此我們的資料整理要包含兩個部分,一個部分就是將 784 的一維資料調整成 28 * 28 的二維資料,並且增加第三個維度把通道數給加進去,那這邊用到 .unsqueeze(0) 去作為度的擴展,利用 .view(28, 28) 去 reshape 資料
# 0) data import and set as pytorch dataset
class MNISTDataset(Dataset):

    # data loading
    def __init__(self, path, transform=None):
        xy = np.loadtxt(path, delimiter=',', dtype=np.float32, skiprows=1)
        self.x = torch.from_numpy(xy[:, 1:])
        self.y = torch.from_numpy(xy[:, [0]].flatten().astype(np.longlong))
        self.n_samples = xy.shape[0]

        self.transform = transform

    # working for indexing
    def __getitem__(self, index):
        sample = self.x[index], self.y[index]

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

    # return the length of our dataset
    def __len__(self):
        
        return self.n_samples


class ToImage:
    def __call__(self, sample):
        inputs, targets = sample

        return inputs.view(28, 28).unsqueeze(0), targets


train_path = './data/train.csv'
test_path = './data/test.csv'
train_dataset = MNISTDataset(train_path, transform=ToImage())
test_dataset = MNISTDataset(test_path, transform=ToImage())

train_loader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True)
test_loader = DataLoader(test_dataset, batch_size=batch_size, shuffle=True)
  • 我們特別撰寫了一個去改變資料狀態的轉換器,去轉換我們的資料成 1 * 28 * 28 的資料
  • 這是當我們要讀取 kaggle 資料集的方式,下面讓我們看看利用 Pytorch 內建資料集的使用方式

Pytorch

  • Pytorch 其實也有提供像 sklearn 一樣的 Datasets 提供下載,那想要下載這些資料需要用到 Pytorch 的 torchvision 函式庫,那下面就讓我們示範怎麼去使用 Pytorch 的 Dataset 去取得 MNIST 的資料吧~
import torchvision
import torchvision.transforms as transforms

# MNIST
train_dataset = torchvision.datasets.MNIST(root='./data', train=True,
    transform=transforms.ToTensor(), download=True)

test_dataset = torchvision.datasets.MNIST(root='./data', train=False,
    transform=transforms.ToTensor(), download=False)
  • 我們來一一解釋上面的 Code 的參數部分,首先我們要取得資料就是利用 torchvision.datasets.資料集名稱 去取得,那分成 training data 跟 testing data 的方式非常簡單,Pytorch 非常貼心的提供一個參數叫做 train,來區分資料集中的 training data 跟 testing data
  • 另外資料在做訓練之前,還是需要做下載,因此我們需要給予 download 參數確定是否需要下載資料,那只要有資料之後,可以把 download 改成 False,也就是說資料下載只需要一次
  • root 參數說明了資料位置,那我們下面畫一下資料的結構圖
    ├── mnist.py
    ├── data
    ├ ├── MNIST
    ├ ├ ├── train-images-idx3-ubyte
    ├ ├ ├── train-labels-idx1-ubyte
    ├ ├ ├── t10k-images-idx3-ubyte
    └ └ └── t10k-labels-idx1-ubyte
    Pytorch 會在 root 目錄裡面下載相對應的資料集資料,並以資料集名稱作為目錄
  • 最後一個參數是 transform,這個參數定義了資料的轉換,例如說今天的資料是圖片資料,我們可以利用 transform 來做 img to tensor 的轉換,因此我們可以看到在這邊我們就掛了 transforms.ToTensor() 確保資料型態是 Tensor
  • 那這邊可以發現我們資料的掛載變得比較簡單輕鬆,但是這畢竟是因為資料集有在 Pytorch 的資料庫中,因此我們還是主要以讀取外部資料集的方式做練習
  • 那下面讓我們建立我們的 Dataloader
train_loader = DataLoader(dataset=train_dataset, batch_size=batch_size,
    shuffle=True)

test_loader = DataLoader(dataset=test_dataset, batch_size=batch_size,
    shuffle=True)
  • 這邊就是將對應的 Dataset 放給對應的 Dataloader 並訂定 Batch size,這邊比較特殊的參數是 shuffle,shuffle 參數允許我們在使用資料前優先打亂資料,那這個參數很好用,因為大部分現成的資料集內部資料都是有整理過的,也就是有序排列,也就是說,如果不先 shuffle 過資料的話,容易造成模型訓練的偏差,因此如果需要的話,shuffle 參數都是可以隨手掛載的,對訓練會有幫助

每日小結

  • 雖然 Pytorch Dataset 中也有 MNIST 資料集,但是我們還是提到了第一種資料讀取方式是有原因的,大部分的現實問題一定不會有現成的資料集,因此如何讀取使用這些資料集反而是我們應該學習的,也因此我們要熟悉自己撰寫資料讀取
  • 但是由於 kaggle 提供的 test data 並沒有附贈答案,因此,我們還是必須在這邊先使用 Pytorch 提供的資料集來做資料驗證 QQ,所以明天的完整版將會使用 Pytorch dataset
  • Pytorch 提供了很多實用且方便的參數讓我們在資料使用的過程中更加輕鬆,如何更好的利用他們都可以去看官方的文件去更加了解參數的使用,會對後續的訓練有極大的幫助,在這邊筆者都只提到一些常用的參數,還有更多參數可以去理解學習
  • 那我們今天把資料讀取進來了,明天就讓我們開始訓練我們的 CNN 模型來面對這份資料集吧~

上一篇
Day-25 PyTorch 的 CNN Model
下一篇
Day-27 手把手的手寫面是模型 0x2:資料訓練和結果輸出
系列文
Deep Learning 從零開始到放棄的 30 天 PyTorch 數字辨識模型31

尚未有邦友留言

立即登入留言