iT邦幫忙

2021 iThome 鐵人賽

DAY 20
0
AI & Data

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

Day-19 PyTorch 怎麼讀取資料? Dataset and DataLoader

  • 分享至 

  • xImage
  •  
  • 今天來聊聊怎麼讀取資料和調整資料集,你可能會問說奇怪我們前兩天不是就已經可以使用資料了嗎?這邊有啥好學習的?
  • 其實不然,我們先來看看我們前面兩天的資料處裡會是如何
  • 就以昨天的 Iris dataset 做 example,我們回顧一下如果我們昨天的 Training 是怎麼做的
data = Iris.dataset()
# training loop
for epoch in range(100):
    
    # y_predicted = model(x) 其實等同於
    for x, y in data:
        # forward + backward + weight updates
  • 這代表什麼意思,我們昨天的程式其實等於跑了雙層 for loop,第一層決定了我們要訓練過左有資料幾次,而第二層竟然是我們的 Data set size
  • 這很可怕,我們昨天的 Iris dataset 只有 1000 筆資料左右,因此可能不會有特別的感覺,但如果我們的資料有數萬筆呢?我們的總迴圈次數會瞬間變得非常可怕,但是我們又不可能不使用過所有資料,有沒有辦法用到所有資料,然後又不會這樣全部都要 loop 一遍的做法呢?
  • 有的,概念上就是將資料批次使用,什麼意思呢?也就是今天我們不再單筆單筆資料去做觀看使用,而是進行分批次的使用,將一定數量的資料和在一起視為一個批次,去使用這些批次的資料
  • 基於上述的概念,我們的實際運作結構會變成怎樣呢?
# training loop
for epoch in range(100):
    
    # loop over all batches
    for i in range(total_batches):
        x_batch, y_batch = ...
  • 可以很直觀的理解這次的 total time 會大量減少,因為我們的 total_batches 一定少於 total datas
  • 因此這邊我們就需要 PyTorch 的 Dataset 跟 Dataloader Classes 來幫我們進行 batches 的計算跟建立,這也是 PyTorch 一個非常實用簡單的功能,所以等等就會介紹這些東西
  • 那在開始談論 Dataset 跟 Dataloader 之前,我們先來好好理解一下前面沒解釋過的幾個重要名詞

Epoch、Batch size、number of iterations

  • Epoch、Batch size跟numbers of iterations 是我們在機器學習的世界中很常見的名詞,他們在整個機器學習的世界有著舉足輕重的地位,我們來好好了解認識他們一下吧~

Epoch

  • 我們在很前面就用到一個名詞叫做 Epoch ,使用的情境是這樣使用的
    epochs = nums # a number
    # training loop
    for epoch in range(epochs):
        ...
    
  • 那其實我們可以很直觀的理解就是我們要基於現在有的資料,去訓練更新資料幾次
  • 我們來假設我們的資料集是一本書,今天我們就是那個機器,Epoch 的數量就是我們要完整地看完這本書幾次的意思,然後利用這本書的知識來更新我們的觀念
  • 比較學術的定義就是一個 ==Epoch = 1 forward and backward pass of All training samples==,也就是完整對所有資料做一次 forward 跟 backward pass 的這一整個流程

Batch size

  • Batch size 的學術定義則是 number os training samples in one forward & backward pass,也就是每次我要執行一個 forward & backward pass 要使用的資料量
  • Batch(批次)存在的意義,Batch size 能決定我一次做判斷學習時,是對多少筆資料做觀察整理的,然後對於這些資料的結論去做資料調整
  • 因此 Batch size 最重要的意義並不是減少 loop 次數,反而應該說她決定了我們如何更好的去學習資料特徵之間的關係

Number of iterations

  • iterations 的定義則是 number of passes, each pass using [batch size] number of samples,也就是我們到底在一次 Epoch 中更新調整了幾次

小統整

  • 我們直接拿個例子來輔助大家了解,假設我們有 100 個資料點,我們把 batch_size 設定成 20,那我們每一個 epoch 會有 5 個 iterations
  • 這就是各個名詞之間的關聯性了~

如何架設 Dataset & Dataloader

Dataset

  • Dataset 就是要幫我們把資料包起來,因此這邊我們就來看看怎麼設定相對應的資料集
  • 我們假設我們有一組資料集長這樣(偷偷逼逼這個資料集其實我們之後會用到)
    {%gist=78346b637e4aff281377f754d6bf8681%}
  • 那我們來看看建立這個資料集的 PyTorch Dataset 要怎麼建立
  • 首先先引用我們會需要的套件,如果是建立 Dataset 會需要 torch.utils.data 裡面的 Dataset
import torch
from torch.utils.data import Dataset

# 這兩個是資料處裡常用的套件
import numpy as np
import pandas as pd
  • 那我們基本建立 Dataset 會需要三個必要的 function,分別處理資料的讀取,特定資料回傳跟資料長度,我們先看 code,然後再一一解釋
# example of dataset create
class ExampleDataset(Dataset):

    # data loading
    def __init__(self):
        xy = np.loadtxt('./dataset-example.csv', delimiter=',', dtype=np.float32, skiprows=1)
        self.x = torch.from_numpy(xy[:, 1:])
        self.y = torch.from_numpy(xy[:, [0]])
        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
  • 因為我們的資料集中,第一 coloum 是 label,也就是答案,因此我們資料特徵跟答案要分開一下,所有關於 data 的基本資料都應該在 __init__ 裡面整理好
  • 那資料集整理好之後,讀取之後,我們要能夠使用每一筆資料,因此當然要能夠利用 index 回傳資料,所以要設定 __getitem__ 的 return
    • 那這邊不只可以設定資料回傳,PyTorch 還有一個 Dataset Transform 的功能,如果需要資料型態變化也會寫在這裡,那這邊我們不會特別提到 Dataset Transform,有興趣的可以自己再去看看
  • 那我們也必須掌控資料集的長度,因此要設定 __init__ 的 return 去回傳資料長度
  • 那我們來看看使用上可以怎麼使用
dataset = ExampleDataset()

# pick first data
first_data = dataset[0]
features, labels = first_data
print(features, labels)
print(len(dataset))
  • 所以我們可以看到如果我們要使用第一筆資料就可以直接用 index 去索引,想知道資料長度也可以直接用 len() 去做顯示

切割資料集

  • 我們有說過在訓練模型時,會將資料分成 training 跟 testing 來訓練跟檢查資料,那如果我們有 dataset 之後,想切分資料要如何去做切分?
  • 這時會用到 from torch.utils.data.sampler import SubsetRandomSampler 提供一種迭代數據集元素索引的__len__()方法,以及一個返回返回迭代器長度的方法
  • 利用這個工具搭配資料的整理就能切分 training dataset 跟 testing dataset
  • 我們直接來看範例
from torch.utils.data.sampler import SubsetRandomSampler

# create data
...


# split data
# set testing data size
test_split = 0.2
# need shuffle or not
shuffle_dataset = True
# random seed of shuffle
random_seed = 1234

# creat data indices for training and testing splits
dataset_size = len(dataset)
indices = list(range(dataset_size))
# count out split size
split = int(np.floor(test_split * dataset_size))
if shuffle_dataset:
    np.random.seed(random_seed)
    np.random.shuffle(indices)
train_indices, test_indices = indices[split:], indices[:split]

# creating data samplers and loaders:
train_sampler = SubsetRandomSampler(train_indices)
test_sampler = SubsetRandomSampler(test_indices)

train_loader = DataLoader(dataset, batch_size=batch_size, sampler=train_sampler)
test_loader = DataLoader(dataset, batch_size=batch_size, sampler=test_sampler)

DataLoader

  • 如果說 Dataset 是定義了資料的結構跟資料本身的一個包裝,那 DataLoader 就是定義了使用讀取資料的方式(換句話說就是一定要先有 Dataset 才可以用 DataLoader 操作)
  • 那 DataLoader 可以設定那些部分呢?就是包含我們一開始提到的 Batch_size 之類的部分啦~
  • 我們來看個示範
# example of dataloader use
dataloader = DataLoader(dataset=dataset, batch_size=4, shuffle=True)

dataiter = iter(dataloader)
data = dataiter.next()
features, labels = data
print(features, labels)

# tensor([[0., 0., 0.,  ..., 0., 0., 0.],
#         [0., 0., 0.,  ..., 0., 0., 0.],
#         [0., 0., 0.,  ..., 0., 0., 0.],
#         [0., 0., 0.,  ..., 0., 0., 0.]]) tensor([[1.],
#         [0.],
#         [1.],
#         [4.]])
  • 那我們上面做了那些設定,分別就是說明了我們是使用剛剛定義過的 ExampleDataset() 作為我們的資料集,另外我們希望每 4 筆資料一起看,所以設定 batch_size 為 4
  • 另外還可以在這邊設定資料打亂啊等等,都可以在這邊設定好
  • 那實際看輸出會發現就是會有四筆資料,也就是達到我們希望四筆資料一起比較的概念,且資料是全隨機的

實際帶入訓練應用

# example of dataloader use
dataloader = DataLoader(dataset=dataset, batch_size=4, shuffle=True)

# training loop
epochs = 2
total_samples = len(dataset)
n_iterations = np.ceil(total_samples / 4)
print(total_samples, n_iterations)

for epoch in range(epochs):

    for i, (features, targets) in enumerate(dataloader):
        # forward backward pass, update
        if (i+1) % 1 == 0:
            print(f'epoch {epoch+1}/{epochs}, step{i+1}/{n_iterations}')
            
# 9 3.0
# epoch 1/2, step1/3.0
# epoch 1/2, step2/3.0
# epoch 1/2, step3/3.0
# epoch 2/2, step1/3.0
# epoch 2/2, step2/3.0
# epoch 2/2, step3/3.0

每日小結

  • 資料訓練都會有資料集,那如何更好的利用這些資料,達到節省時間和更好的準確率的目標,這些都是值得去研究測試的
  • PyTorch 提供了一個更加簡潔的創建資料的方式和一個更好定義使用的方式,就是 Dataset 跟 Dataloader,分別負責了創建讀取資料的工作和定義如何使用資料的工作
  • 那到這裡我們已經基本上可以說是把最基礎需要知道的 PyTorch 工具都介紹完整了~明天就可以試試看利用 PyTorch 從零開始建立第一個神經網路啦~

上一篇
Day-18 Pytorch 的 Logistic Regrssion
下一篇
Day-20 用 Pytorch 的最後一個塊拼圖
系列文
Deep Learning 從零開始到放棄的 30 天 PyTorch 數字辨識模型31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言