????????深度學習中,我們能看到別人的代碼中都有一個繼承Dataset類的數據集處理過程,這也是深度學習處理數據集的的基礎,下面介紹這個數據集的定義和使用:
1、數據集加載
1.1 通用的定義
Bach:表示每次喂給模型的數據
Epoch:表示訓練一次完整數據集數據的過程
解釋:當一個數據集的大小為10時,設定batch大小為5,那么這個數據就會分為2份,每份大小為5,依次投入到模型中進行訓練。訓練完所有數據后,就叫做一次迭代,稱為epoch
1.2 繼承Dataset類
我們繼承Dataset類需要實現它的三個方法,代碼在文末,與Dataloader代碼一起。
init:載入數據
getitem:返回指定位置數據
len:返回數據長度
固定用法如下:
import numpy as np
import torch
from torch.utils.data import Datasetclass MyDataset(Dataset):def __init__(self):#載入數據passdef __getitem__(self, item):#返回相應位置的數據passdef __len__(self):#返回數據長度pass
?例如我們有數據集為手寫數字識別數據,文件目錄如下:
? ? ? ? 在pytorch當然最簡單的是用內置的MNIST函數,這里不使用該方法,使用Dataset類寫一下。
載入數據:由于數據量太大,因此我們載入每個數據的索引,也就是數據的路徑。
返回相應位置的數據:實現給出index,能返回相應位置的數據。
返回數據長度:返回所有數據的個數。
1.3?代碼實現
灰度圖轉換(任選其一)
任選其一都可以實現,將原始圖片轉為灰度圖:
transforms.Grayscale(num_output_channels=1)#transform實現轉換
Image.open(image_path).convert("L") #image庫轉換灰度圖
因此可以寫出Dataset類加載代碼?:
transform = transforms.Compose([#transforms.Grayscale(num_output_channels=1), # 轉換為單通道灰度圖transforms.ToTensor() # 轉換為張量
])
class MyDataset(Dataset):def __init__(self):# 載入數據self.images = []self.labels = []for i in range(10):pathX =os.path.join('../mnist_images/train',str(i))imageNameList = os.listdir(pathX)image = []for filename in imageNameList:imagePath = os.path.join('../mnist_images/train',str(i),filename)image.append(imagePath)label = [i] * len(image)#label = [i for _ in range(len(image))]列表推導式self.images.extend(image)self.labels.extend(label)def __getitem__(self, item):#返回相應位置的數據image = Image.open(self.images[item]).convert("L")#image = Image.open(self.images[item])return transform(image),torch.tensor(self.labels[item])#返回一個元組def __len__(self):#返回數據長度return len(self.images)
1.4?Dataloader批量加載?
? ? ? ? 使用Dataset函數處理數據集后,就需要使用Dataloader,它的使用很簡單,只有一行:
DataLoader(oneDataset, batch_size=32, shuffle=True, drop_last = False,num_works = 8)
????????其中oneDateset表示輸入的Dataset對象下面是對其中一些參數的解釋:
batach_size?表示一個Batch的大小,
shuffle?表示是否打亂數據,
drop_last?表示是否舍棄最后數據,若為True那么會舍棄Datasize對batch_size不能整除的部分,也就是如果數據量為10,batch_size為3的話,最后一個數據會被舍棄,如果drop_last為False的話,最后一個數會被保留。也就是最后一個batch_size的大小為1。
num_works?表示使用多少進程加載數據,num_works = 0表示使用主進程加載數據,num_works > 0表示使用多少個子進程加載數據。
????????DataLoader返回為一個張量,形狀為[batch_size, channels, height, width] batch_size表示批量大小,可以是任意正整數,訓練模型時,模型輸入對該參數batch_size無要求限制,但是后面的三個特征維度[channels, height, width]必須跟模型model定義的輸入層數據維度一致。
1.5完整代碼:
import os
import torch
from PIL import Image
from torch.utils.data import Dataset, DataLoader
from torchvision.transforms import transformstransform = transforms.Compose([#transforms.Grayscale(num_output_channels=1), # 轉換為單通道灰度圖transforms.ToTensor() # 轉換為張量
])
class MyDataset(Dataset):def __init__(self):# 載入數據self.images = []self.labels = []for i in range(10):pathX =os.path.join('../mnist_images/train',str(i))imageNameList = os.listdir(pathX)image = []for filename in imageNameList:imagePath = os.path.join('../mnist_images/train',str(i),filename)image.append(imagePath)label = [i] * len(image)#label = [i for _ in range(len(image))]列表推導式self.images.extend(image)self.labels.extend(label)def __getitem__(self, item):#返回相應位置的數據image = Image.open(self.images[item]).convert("L")#image = Image.open(self.images[item])return transform(image),torch.tensor(self.labels[item])#返回一個元組def __len__(self):#返回數據長度return len(self.images)
def getDataloder():oneDataset = MyDataset()return DataLoader(oneDataset, batch_size=32, shuffle=True)
if __name__ == '__main__':dataloader = getDataloder()for images, labels in dataloader:print("Batch shape:", images.shape) # 輸出批次形狀print("Labels:", labels) # 輸出標簽#print(images[0][0][18])break # 只打印第一個批次
二、 文件下載
文件項目是一個完整的簡單神經網絡訓練手寫數字識別,打包下載在這里:點擊下載項目
????????最后:實現手寫數字識別數據集加載方法最簡單的是使用pytorch內置MNIST函數實現,僅有一行代碼實現上述功能,本文不采用該方法,通過自行實現理解數據集加載原理。
train_dataset = torchvision.datasets.MNIST(root='./data', train=True, download=True, transform=transform)