- 我們今天要使用的資料集就是在機器學習世界鼎鼎大名的 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 模型來面對這份資料集吧~