Pytorch中TensorDataset,DataLoader的聯(lián)合使用方式
Pytorch中TensorDataset,DataLoader的聯(lián)合使用
首先從字面意義上來理解TensorDataset和DataLoader,TensorDataset是個(gè)只用來存放tensor(張量)的數(shù)據(jù)集,而DataLoader是一個(gè)數(shù)據(jù)加載器,一般用到DataLoader的時(shí)候就說明需要遍歷和操作數(shù)據(jù)了。
TensorDataset(tensor1,tensor2)的功能就是形成數(shù)據(jù)tensor1和標(biāo)簽tensor2的對應(yīng),也就是說tensor1中是數(shù)據(jù),而tensor2是tensor1所對應(yīng)的標(biāo)簽。
來個(gè)小例子
from torch.utils.data import TensorDataset,DataLoader import torch ? a = torch.tensor([[1, 2, 3], ? ? ? ? ? ? ? ? ? [4, 5, 6], ? ? ? ? ? ? ? ? ? [7, 8, 9], ? ? ? ? ? ? ? ? ? [1, 2, 3], ? ? ? ? ? ? ? ? ? [4, 5, 6], ? ? ? ? ? ? ? ? ? [7, 8, 9], ? ? ? ? ? ? ? ? ? [1, 2, 3], ? ? ? ? ? ? ? ? ? [4, 5, 6], ? ? ? ? ? ? ? ? ? [7, 8, 9], ? ? ? ? ? ? ? ? ? [1, 2, 3], ? ? ? ? ? ? ? ? ? [4, 5, 6], ? ? ? ? ? ? ? ? ? [7, 8, 9]]) ? b = torch.tensor([44, 55, 66, 44, 55, 66, 44, 55, 66, 44, 55, 66]) train_ids = TensorDataset(a,b) # 切片輸出 print(train_ids[0:4]) # 第0,1,2,3行 # 循環(huán)取數(shù)據(jù) for x_train,y_label in train_ids: ? ? print(x_train,y_label)
下面是對應(yīng)的輸出:
(tensor([[1, 2, 3],
[4, 5, 6],
[7, 8, 9],
[1, 2, 3]]), tensor([44, 55, 66, 44]))
===============================================
tensor([1, 2, 3]) tensor(44)
tensor([4, 5, 6]) tensor(55)
tensor([7, 8, 9]) tensor(66)
tensor([1, 2, 3]) tensor(44)
tensor([4, 5, 6]) tensor(55)
tensor([7, 8, 9]) tensor(66)
tensor([1, 2, 3]) tensor(44)
tensor([4, 5, 6]) tensor(55)
tensor([7, 8, 9]) tensor(66)
tensor([1, 2, 3]) tensor(44)
tensor([4, 5, 6]) tensor(55)
tensor([7, 8, 9]) tensor(66)
從輸出結(jié)果我們就可以很好的理解,tensor型數(shù)據(jù)和tensor型標(biāo)簽的對應(yīng)了,這就是TensorDataset的基本應(yīng)用。
接下來我們把構(gòu)造好的TensorDataset封裝到DataLoader來操作里面的數(shù)據(jù):
# 參數(shù)說明,dataset=train_ids表示需要封裝的數(shù)據(jù)集,batch_size表示一次取幾個(gè) # shuffle表示亂序取數(shù)據(jù),設(shè)為False表示順序取數(shù)據(jù),True表示亂序取數(shù)據(jù) train_loader = DataLoader(dataset=train_ids,batch_size=4,shuffle=False) # 注意enumerate返回值有兩個(gè),一個(gè)是序號,一個(gè)是數(shù)據(jù)(包含訓(xùn)練數(shù)據(jù)和標(biāo)簽) for i,data in enumerate(train_loader,1): ? ? train_data, label = data ? ? print(' batch:{0} train_data:{1} ?label: {2}'.format(i+1, train_data, label))
下面是對應(yīng)的輸出:
batch:1 x_data:tensor([[1, 2, 3],
[4, 5, 6],
[7, 8, 9],
[1, 2, 3]]) label: tensor([44, 55, 66, 44])
batch:2 x_data:tensor([[4, 5, 6],
[7, 8, 9],
[1, 2, 3],
[4, 5, 6]]) label: tensor([55, 66, 44, 55])
batch:3 x_data:tensor([[7, 8, 9],
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]]) label: tensor([66, 44, 55, 66])
至此,TensorDataset和DataLoader的聯(lián)合使用就介紹完了。
我們再看一下這兩種方法的源碼:
class TensorDataset(Dataset[Tuple[Tensor, ...]]): ? ? r"""Dataset wrapping tensors. ? ? Each sample will be retrieved by indexing tensors along the first dimension. ? ? Arguments: ? ? ? ? *tensors (Tensor): tensors that have the same size of the first dimension. ? ? """ ? ? tensors: Tuple[Tensor, ...] ? ? ? def __init__(self, *tensors: Tensor) -> None: ? ? ? ? assert all(tensors[0].size(0) == tensor.size(0) for tensor in tensors) ? ? ? ? self.tensors = tensors ? ? ? def __getitem__(self, index): ? ? ? ? return tuple(tensor[index] for tensor in self.tensors) ? ? ? def __len__(self): ? ? ? ? return self.tensors[0].size(0) ? # 由于此類內(nèi)容過多,故僅列舉了與本文相關(guān)的參數(shù),其余參數(shù)可以自行去查看源碼 class DataLoader(Generic[T_co]): ? ? r""" ? ? Data loader. Combines a dataset and a sampler, and provides an iterable over ? ? the given dataset. ? ? The :class:`~torch.utils.data.DataLoader` supports both map-style and ? ? iterable-style datasets with single- or multi-process loading, customizing ? ? loading order and optional automatic batching (collation) and memory pinning. ? ? See :py:mod:`torch.utils.data` documentation page for more details. ? ? Arguments: ? ? ? ? dataset (Dataset): dataset from which to load the data. ? ? ? ? batch_size (int, optional): how many samples per batch to load ? ? ? ? ? ? (default: ``1``). ? ? ? ? shuffle (bool, optional): set to ``True`` to have the data reshuffled ? ? ? ? ? ? at every epoch (default: ``False``). ? ? """ ? ? dataset: Dataset[T_co] ? ? batch_size: Optional[int] ? ? ? def __init__(self, dataset: Dataset[T_co], batch_size: Optional[int] = 1, ? ? ? ? ? ? ? ? ?shuffle: bool = False): ? ? ? ? ? self.dataset = dataset ? ? ? ? self.batch_size = batch_size
Pytorch的DataLoader和Dataset以及TensorDataset的源碼分析
1.為什么要用DataLoader和Dataset
要對大量數(shù)據(jù)進(jìn)行加載和處理時(shí)因?yàn)榭赡軙霈F(xiàn)內(nèi)存不夠用的情況,這時(shí)候就需要用到數(shù)據(jù)集類Dataset或TensorDataset和數(shù)據(jù)集加載類DataLoader了。
使用這些類后可以將原本的數(shù)據(jù)分成小塊,在需要使用的時(shí)候再一部分一本分讀進(jìn)內(nèi)存中,而不是一開始就將所有數(shù)據(jù)讀進(jìn)內(nèi)存中。
2.Dateset的使用
pytorch中的torch.utils.data.Dataset是表示數(shù)據(jù)集的抽象類,但它一般不直接使用,而是通過自定義一個(gè)數(shù)據(jù)集來使用。
來自定義數(shù)據(jù)集應(yīng)該繼承Dataset并應(yīng)該有實(shí)現(xiàn)返回?cái)?shù)據(jù)集尺寸的__len__方法和用來獲取索引數(shù)據(jù)的__getitem__方法。
Dataset類的源碼如下:
class Dataset(object): ? ? r"""An abstract class representing a :class:`Dataset`. ? ? All datasets that represent a map from keys to data samples should subclass ? ? it. All subclasses should overwrite :meth:`__getitem__`, supporting fetching a ? ? data sample for a given key. Subclasses could also optionally overwrite ? ? :meth:`__len__`, which is expected to return the size of the dataset by many ? ? :class:`~torch.utils.data.Sampler` implementations and the default options ? ? of :class:`~torch.utils.data.DataLoader`. ? ? .. note:: ? ? ? :class:`~torch.utils.data.DataLoader` by default constructs a index ? ? ? sampler that yields integral indices. ?To make it work with a map-style ? ? ? dataset with non-integral indices/keys, a custom sampler must be provided. ? ? """ ? ? def __getitem__(self, index): ? ? ? ? raise NotImplementedError ? ? def __add__(self, other): ? ? ? ? return ConcatDataset([self, other]) ? ? # No `def __len__(self)` default? ? ? # See NOTE [ Lack of Default `__len__` in Python Abstract Base Classes ] ? ? # in pytorch/torch/utils/data/sampler.py
可以看到Dataset類中沒有__len__方法,雖然有__getitem__方法,但是并沒有實(shí)現(xiàn)啥有用的功能。
所以要寫一個(gè)Dataset類的子類來實(shí)現(xiàn)其應(yīng)有的功能。
自定義類的實(shí)現(xiàn)舉例:
import torch from torch.utils.data import Dataset, DataLoader, TensorDataset from torch.autograd import Variable import numpy as np import pandas as pd value_df = pd.read_csv('data1.csv') value_array = np.array(value_df) print("value_array.shape =", value_array.shape) ?# (73700, 300) value_size = value_array.shape[0] ?# 73700 train_size = int(0.7*value_size) train_array = val_array[:train_size] ? train_label_array = val_array[60:train_size+60] class DealDataset(Dataset): ? ? """ ? ? ? ? 下載數(shù)據(jù)、初始化數(shù)據(jù),都可以在這里完成 ? ? """ ? ? def __init__(self, *arrays): ? ? ? ? assert all(arrays[0].shape[0] == array.shape[0] for array in arrays) ? ? ? ? self.arrays = arrays ? ? def __getitem__(self, index): ? ? ? ? return tuple(array[index] for array in self.arrays) ? ? def __len__(self): ? ? ? ? return self.arrays[0].shape[0] # 實(shí)例化這個(gè)類,然后我們就得到了Dataset類型的數(shù)據(jù),記下來就將這個(gè)類傳給DataLoader,就可以了。 train_dataset = DealDataset(train_array, train_label_array) train_loader2 = DataLoader(dataset=train_dataset, ? ? ? ? ? ? ? ? ? ? ? ? ? ?batch_size=32, ? ? ? ? ? ? ? ? ? ? ? ? ? ?shuffle=True) for epoch in range(2): ? ? for i, data in enumerate(train_loader2): ? ? ? ? # 將數(shù)據(jù)從 train_loader 中讀出來,一次讀取的樣本數(shù)是32個(gè) ? ? ? ? inputs, labels = data ? ? ? ? # 將這些數(shù)據(jù)轉(zhuǎn)換成Variable類型 ? ? ? ? inputs, labels = Variable(inputs), Variable(labels) ? ? ? ? # 接下來就是跑模型的環(huán)節(jié)了,我們這里使用print來代替 ? ? ? ? print("epoch:", epoch, "的第", i, "個(gè)inputs", inputs.data.size(), "labels", labels.data.size())
結(jié)果:
epoch: 0 的第 0 個(gè)inputs torch.Size([32, 300]) labels torch.Size([32, 300])
epoch: 0 的第 1 個(gè)inputs torch.Size([32, 300]) labels torch.Size([32, 300])
epoch: 0 的第 2 個(gè)inputs torch.Size([32, 300]) labels torch.Size([32, 300])
epoch: 0 的第 3 個(gè)inputs torch.Size([32, 300]) labels torch.Size([32, 300])
epoch: 0 的第 4 個(gè)inputs torch.Size([32, 300]) labels torch.Size([32, 300])
epoch: 0 的第 5 個(gè)inputs torch.Size([32, 300]) labels torch.Size([32, 300])
...
3.TensorDataset的使用
TensorDataset是可以直接使用的數(shù)據(jù)集類,它的源碼如下:
class TensorDataset(Dataset): ? ? r"""Dataset wrapping tensors. ? ? Each sample will be retrieved by indexing tensors along the first dimension. ? ? Arguments: ? ? ? ? *tensors (Tensor): tensors that have the same size of the first dimension. ? ? """ ? ? def __init__(self, *tensors): ? ? ? ? assert all(tensors[0].size(0) == tensor.size(0) for tensor in tensors) ? ? ? ? self.tensors = tensors ? ? def __getitem__(self, index): ? ? ? ? return tuple(tensor[index] for tensor in self.tensors) ? ? def __len__(self): ? ? ? ? return self.tensors[0].size(0)
可以看到TensorDataset類是Dataset類的子類,且擁有返回?cái)?shù)據(jù)集尺寸的__len__方法和用來獲取索引數(shù)據(jù)的__getitem__方法,所以可以直接使用。
它的結(jié)構(gòu)跟上面自定義的子類的結(jié)構(gòu)是一樣的,惟一的不同是TensorDataset已經(jīng)規(guī)定了傳入的數(shù)據(jù)必須是torch.Tensor類型的,而自定義子類可以自由設(shè)定。
使用舉例:
import torch from torch.utils.data import Dataset, DataLoader, TensorDataset from torch.autograd import Variable import numpy as np import pandas as pd value_df = pd.read_csv('data1.csv') value_array = np.array(value_df) print("value_array.shape =", value_array.shape) ?# (73700, 300) value_size = value_array.shape[0] ?# 73700 train_size = int(0.7*value_size) train_array = val_array[:train_size] ? train_tensor = torch.tensor(train_array, dtype=torch.float32).to(device) train_label_array = val_array[60:train_size+60] train_labels_tensor = torch.tensor(train_label_array,dtype=torch.float32).to(device) train_dataset = TensorDataset(train_tensor, train_labels_tensor) train_loader = DataLoader(dataset=train_dataset, ? ? ? ? ? ? ? ? ? ? ? ? ? batch_size=100, ? ? ? ? ? ? ? ? ? ? ? ? ? shuffle=False, ? ? ? ? ? ? ? ? ? ? ? ? ? num_workers=0) for epoch in range(2): ? ? for i, data in enumerate(train_loader): ? ? ? ? inputs, labels = data ? ? ? ? inputs, labels = Variable(inputs), Variable(labels) ? ? ? ? print(epoch, i, "inputs", inputs.data.size(), "labels", labels.data.size())
結(jié)果:
0 0 inputs torch.Size([100, 300]) labels torch.Size([100, 300])
0 1 inputs torch.Size([100, 300]) labels torch.Size([100, 300])
0 2 inputs torch.Size([100, 300]) labels torch.Size([100, 300])
0 3 inputs torch.Size([100, 300]) labels torch.Size([100, 300])
0 4 inputs torch.Size([100, 300]) labels torch.Size([100, 300])
0 5 inputs torch.Size([100, 300]) labels torch.Size([100, 300])
0 6 inputs torch.Size([100, 300]) labels torch.Size([100, 300])
0 7 inputs torch.Size([100, 300]) labels torch.Size([100, 300])
0 8 inputs torch.Size([100, 300]) labels torch.Size([100, 300])
0 9 inputs torch.Size([100, 300]) labels torch.Size([100, 300])
0 10 inputs torch.Size([100, 300]) labels torch.Size([100, 300])
...
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
Python實(shí)現(xiàn)一個(gè)完整學(xué)生管理系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了如何利用python實(shí)現(xiàn)學(xué)生管理系統(tǒng)(面向?qū)ο蟀妫?,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2023-01-01NumPy.npy與pandas DataFrame的實(shí)例講解
今天小編就為大家分享一篇NumPy.npy與pandas DataFrame的實(shí)例講解,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-07-07Python數(shù)學(xué)建模StatsModels統(tǒng)計(jì)回歸可視化示例詳解
圖形總是比數(shù)據(jù)更加醒目、直觀。解決統(tǒng)計(jì)回歸問題,無論在分析問題的過程中,還是在結(jié)果的呈現(xiàn)和發(fā)表時(shí),都需要可視化工具的幫助和支持2021-10-10Python爬蟲數(shù)據(jù)的分類及json數(shù)據(jù)使用小結(jié)
這篇文章主要介紹了Python爬蟲數(shù)據(jù)的分類及json數(shù)據(jù)使用小結(jié),幫助大家更好的理解和學(xué)習(xí)使用python,感興趣的朋友可以了解下2021-03-03一篇文章帶你學(xué)習(xí)Python3的高階函數(shù)
這篇文章主要為大家詳細(xì)介紹了Python3的高階函數(shù),主要介紹什么是高階函數(shù),高階函數(shù)的用法以及幾個(gè)常見的內(nèi)置的高階函數(shù),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-01-01基于keras 模型、結(jié)構(gòu)、權(quán)重保存的實(shí)現(xiàn)
今天小編就為大家分享一篇基于keras 模型、結(jié)構(gòu)、權(quán)重保存的實(shí)現(xiàn),具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-01-01