Pytorch技法之繼承Subset類完成自定義數(shù)據(jù)拆分
我們在 《torch.utils.data.DataLoader與迭代器轉(zhuǎn)換操作》 中介紹了如何使用Pytorch內(nèi)置的數(shù)據(jù)集進行論文實驗,如 torchvision.datasets 。下面是加載內(nèi)置訓練數(shù)據(jù)集的常見操作:
from torchvision.datasets import FashionMNIST from torchvision.transforms import Compose, ToTensor, Normalize RAW_DATA_PATH = './rawdata' transform = Compose( ? ? ? ? [ToTensor(), ? ? ? ? ?Normalize((0.1307,), (0.3081,)) ? ? ? ? ?] ? ? ) train_data = FashionMNIST( ? ? ? ? root=RAW_DATA_PATH, ? ? ? ? download=True, ? ? ? ? train=True, ? ? ? ? transform=transform ? ? )
這里的train_data
做為 dataset
對象,它擁有許多熟悉,我們可以通過以下方法獲取樣本數(shù)據(jù)的分類類別集合、樣本的特征維度、樣本的標簽集合等信息。
classes = train_data.classes num_features = train_data.data[0].shape[0] train_labels = train_data.targets print(classes) print(num_features) print(train_labels)
輸出如下:
['T-shirt/top', 'Trouser', 'Pullover', 'Dress', 'Coat', 'Sandal', 'Shirt', 'Sneaker', 'Bag', 'Ankle boot']
28
tensor([9, 0, 0, ..., 3, 0, 5])
但是,我們常常會在訓練集的基礎(chǔ)上拆分出驗證集(或者只用部分數(shù)據(jù)來進行訓練)。我們想到的第一個方法是使用 torch.utils.data.random_split
對 dataset
進行劃分,下面我們假設(shè)劃分10000個樣本做為訓練集,其余樣本做為驗證集:
from torch.utils.data import random_split k = 10000 train_data, valid_data = random_split(train_data, [k, len(train_data)-k])
注意我們?nèi)绻蛴?train_data 和 valid_data
的類型,可以看到顯示:
<class 'torch.utils.data.dataset.Subset'>
已經(jīng)不再是torchvision.datasets.mnist.FashionMNIST
對象,而是一個所謂的 Subset 對象!此時 Subset 對象雖然仍然還存有 data 屬性,但是內(nèi)置的 target
和 classes
屬性已經(jīng)不復存在,
比如如果我們強行訪問 valid_data 的 target 屬性:
valid_target = valid_data.target
就會報如下錯誤:
'Subset' object has no attribute 'target'
但如果我們在后續(xù)的代碼中常常會將拆分后的數(shù)據(jù)集也默認為 dataset 對象,那么該如何做到代碼的一致性呢?
這里有一個trick,那就是以繼承 SubSet 類的方式的方式定義一個新的 CustomSubSet 類,使新類在保持 SubSet 類的基本屬性的基礎(chǔ)上,擁有和原本數(shù)據(jù)集類相似的屬性,如 targets
和 classes
等:
from torch.utils.data import Subset class CustomSubset(Subset): ? ? '''A custom subset class''' ? ? def __init__(self, dataset, indices): ? ? ? ? super().__init__(dataset, indices) ? ? ? ? self.targets = dataset.targets # 保留targets屬性 ? ? ? ? self.classes = dataset.classes # 保留classes屬性 ? ? def __getitem__(self, idx): #同時支持索引訪問操作 ? ? ? ? x, y = self.dataset[self.indices[idx]] ? ? ? ? ? ? ? return x, y? ? ? def __len__(self): # 同時支持取長度操作 ? ? ? ? return len(self.indices)
然后就引出了第二種劃分方法,即通過初始化 CustomSubset
對象的方式直接對數(shù)據(jù)集進行劃分(這里為了簡化省略了shuffle的步驟):
import numpy as np from copy import deepcopy origin_data = deepcopy(train_data) train_data = CustomSubset(origin_data, np.arange(k)) valid_data = CustomSubset(origin_data, np.arange(k, len(origin_data))-k)
注意: CustomSubset
類的初始化方法的第二個參數(shù) indices 為樣本索引,我們可以通過 np.arange()
的方法來創(chuàng)建。
然后,我們再訪問 valid_data 對應的 classes 和 targes 屬性:
print(valid_data.classes) print(valid_data.targets)
此時,我們發(fā)現(xiàn)可以成功訪問這些屬性了:
['T-shirt/top', 'Trouser', 'Pullover', 'Dress', 'Coat', 'Sandal', 'Shirt', 'Sneaker', 'Bag', 'Ankle boot'] tensor([9, 0, 0, ?..., 3, 0, 5])
當然, CustomSubset
的作用并不只是添加數(shù)據(jù)集的屬性,我們還可以自定義一些數(shù)據(jù)預處理操作。
我們將類的結(jié)構(gòu)修改如下:
class CustomSubset(Subset): ? ? '''A custom subset class with customizable data transformation''' ? ? def __init__(self, dataset, indices, subset_transform=None): ? ? ? ? super().__init__(dataset, indices) ? ? ? ? self.targets = dataset.targets ? ? ? ? self.classes = dataset.classes ? ? ? ? self.subset_transform = subset_transform ? ? def __getitem__(self, idx): ? ? ? ? x, y = self.dataset[self.indices[idx]] ? ? ? ?? ? ? ? ? if self.subset_transform: ? ? ? ? ? ? x = self.subset_transform(x) ? ? ?? ? ? ? ? return x, y ?? ? ?? ? ? def __len__(self):? ? ? ? ? return len(self.indices)
我們可以在使用樣本前設(shè)置好數(shù)據(jù)預處理算子:
from torchvision import transforms valid_data.subset_transform = transforms.Compose(\ ? ? [transforms.RandomRotation((180,180))])
這樣,我們再像下列這樣用索引訪問取出數(shù)據(jù)集樣本時,就會自動調(diào)用算子完成預處理操作:
print(valid_data[0])
打印結(jié)果縮略如下:
(tensor([[[-0.4242, -0.4242, -0.4242, ......-0.4242, -0.4242, -0.4242, -0.4242, -0.4242]]]), 9)
到此這篇關(guān)于Pytorch技法之繼承Subset類完成自定義數(shù)據(jù)拆分的文章就介紹到這了,更多相關(guān)繼承Subset類完成自定義數(shù)據(jù)拆分內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
使用Python實現(xiàn)數(shù)據(jù)重采樣的示例代碼
數(shù)據(jù)重采樣是一種用于調(diào)整數(shù)據(jù)集大小或分布的技術(shù),它涉及通過增加或減少數(shù)據(jù)點的數(shù)量來修改現(xiàn)有數(shù)據(jù)集,下面我們就來學習一下如何利用Python實現(xiàn)數(shù)據(jù)重采樣吧2023-11-11Python爬蟲框架scrapy實現(xiàn)downloader_middleware設(shè)置proxy代理功能示例
這篇文章主要介紹了Python爬蟲框架scrapy實現(xiàn)downloader_middleware設(shè)置proxy代理功能,結(jié)合實例形式分析了scrapy框架proxy代理設(shè)置技巧與相關(guān)問題注意事項,需要的朋友可以參考下2018-08-08Python中tkinter的用戶登錄管理的實現(xiàn)
這篇文章主要介紹了Python中tkinter的用戶登錄管理的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2021-04-04Python序列化基礎(chǔ)知識(json/pickle)
這篇文章主要為大家詳細介紹了Python序列化json和pickle基礎(chǔ)知識,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-10-10