Make a TensorDataset and Dataloader with multiple inputs parameters

DeepLearner17: <p>Hello,</p>
<p>I have a dataset composed of   labels,features,adjacency matrices, laplacian  graphs in numpy format.</p>
<p>I would like to build a torch.utils.data.data_utils.TensorDataset() and torch.utils.data.DataLoader() that can take labels,features,adjacency matrices, laplacian  graphs.</p>
<p>To do so, l have tried the following</p>
<pre><code class="lang-auto">
import numpy as np
import torch.utils.data as data_utils

# get the numpy data
 labels_train,features_train,adjacency_train,laplacian_train=train
 labels_test,features_test,adjacency_test,laplacian_test=test


# expand dimension
features_train=np.expand_dims(features_train,axis=0)
features_test=np.expand_dims(features_test,axis=0)

adjacency_train=np.expand_dims(adjacency_train,axis=0)
adjacency_test=np.expand_dims(adjacency_test,axis=0)

laplacian_train=np.expand_dims(laplacian_train,axis=0)
laplacian_test=np.expand_dims(laplacian_test,axis=0)

# convert  numy data to torch
labels_train=torch.from_numpy(labels_train)
features_train=torch.from_numpy(features_train)
adjacency_train=torch.from_numpy(adjacency_train)
laplacian_train=torch.from_numpy(laplacian_train)

labels_test=torch.from_numpy(labels_test)
features_test=torch.from_numpy(features_test)
adjacency_test=torch.from_numpy(adjacency_test)
laplacian_test=torch.from_numpy(laplacian_test)
</code></pre>
<p><strong># l get stuck here</strong></p>
<pre><code class="lang-auto">train=data_utils.TensorDataset(features_train.float(),labels_train,adjacency_train.float(),laplacian_train.float())

test=data_utils.TensorDataset(features_test.float(),labels_test,adjacency_test.float(),laplacian_test.float())
</code></pre>
<p>It doesn’t work because it’s supposed to take only two parameters features_train and labels_train only.<br>
Is there any way to accept more than two parameters ?</p>
<p><strong>What is my purpose ?</strong><br>
Once l have get <strong>train</strong> and <strong>test</strong> from <code>data_utils.TensorDataset()</code> l would like to load my data as follow :</p>
<pre><code class="lang-auto">train_loader=data_utils.DataLoader(train)
val_loader= data_utils.DataLoader(test)
</code></pre>
<p>It doesnt’ work because <code>DataLoader()</code> is supposed to have only target and features_data (not adjacency matrices and laplacian).</p>
<p>I need this setup in order to do the following :</p>
<pre><code class="lang-auto">for i,(input,target,adjacency_matrix,laplacian) in enumerate(train_loader):
     # do my training
</code></pre>
<p>Thank you for you help</p>
<p><a class="mention" href="/u/smth">@smth</a>, <a class="mention" href="/u/ptrblck">@ptrblck</a>  is there any cue ?</p>

ptrblck: <p>What kind of error do you get or why is it not working?<br>
The <code>TensorDataset</code> takes an arbitrary number of input tensors.<br>
Here is a small example using just random data:</p>
<pre><code class="lang-python">nb_samples = 100
features = torch.randn(nb_samples, 10)
labels = torch.empty(nb_samples, dtype=torch.long).random_(10)
adjacency = torch.randn(nb_samples, 5)
laplacian = torch.randn(nb_samples, 7)

dataset = TensorDataset(features, labels, adjacency, laplacian)
loader = DataLoader(
    dataset,
    batch_size=2
)

for batch_idx, (x, y, a, l) in enumerate(loader):
    print(x.shape, y.shape, a.shape, l.shape)
</code></pre>

DeepLearner17: <p>Thank you a lot. I was confused. When l looked at TesorDataset function l found that it takes only data_tensor and  target_tensor</p>

rchavezj: <p>What if we wish to pass in a 3d input feature into tensordata? I was told 1d or 2d were only allowed</p>

ptrblck: <p>I’m not sure what the limit is.<br>
If you change <code>features</code> in my example code to a 10dimensional tensor (<code>features = torch.randn(nb_samples, 2, 2, 2, 2, 2, 2, 2, 2, 10)</code>), it still works on the CPU and GPU.<br>
I think I’ve heard once some limitation regarding the dimensionality of GPU tensors, but I can’t produce an example which is not working currently.<br>
Who told you 3dimensional tensors are now allowed?</p>

rchavezj: <p>Sorry I wasn’t told anything but referenced a post on stack overflow (<a href="https://stackoverflow.com/questions/41924453/pytorch-how-to-use-dataloaders-for-custom-datasets" rel="nofollow noopener">https://stackoverflow.com/questions/41924453/pytorch-how-to-use-dataloaders-for-custom-datasets</a>)</p>

ptrblck: <p>Thanks for the link. I had a look through the history of <code>TensorDataset</code> as the post came from Feb. 2017, and can’t find any constraints regarding 2dimensional tensors.<br>
This would also mean that no image tensors could be used in <code>TensorDataset</code> which would be a strange design.<br>
Another person commented a week later that tensors with an arbitrary number of dimensions can be used, so I guess it’s just a mistake by the user.</p>

rchavezj: <p>Continue being awesome!</p>

Mohamed_Ragab: <p>Thanks for your clear explanation. But how what if in the given example I have different number of samples (nb_samples) for features and adjacency? How can I deal with this?</p>

ptrblck: <p>I assume features and adjacency correspond to your input and target data?<br>
If so, how are the data samples corresponding to the target, if you have different number of samples?</p>

Mohamed_Ragab: <p>Thanks for your reply, in my case, I have input_tensor, target_tensor and label. the target tensors are somehow reconstructed versions of the input tensors and its on;y available for input tensors without labels. For example, I have 500 input samples,   200 of them have labels, and the other 300 hundred doesn’t  have labels but have their corresponding target tensors.</p>

Mohamed_Ragab: <p>I have workaround this problem by splitting the data into two parts. But now I have another Issue:<br>
train_dataset= TensorDataset(input_tensor,target_tensor, label)<br>
train_dl = DataLoader(train_dataset,batch_size=batch_size, shuffle=True,drop_last=drop_last)<br>
My issue is that I need to have a pair of input and target tensor. But when I activate shuffling the input and target are somehow shuffled in a different manner. Is there a method to keep the input tensor and target tensor in pairs even with shuffling activated.</p>

ptrblck: <p>If I understand the code correctly, you are passing now tensors with a different shape to <code>TensorDataset</code>.<br>
I would rather create a single target tensor and make sure the target and labels correspond to the input samples.</p>
<p>Shuffling will shuffle each tensor in the same way, so I assume you might see some issues if the shapes do not match. I’m not sure, if the smallest size will be used in this approach.</p>

Mohamed_Ragab: <aside class="quote no-group" data-username="ptrblck" data-post="13" data-topic="26605">
<div class="title">
<div class="quote-controls"></div>
<img loading="lazy" alt="" width="24" height="24" src="https://discuss.pytorch.org/user_avatar/discuss.pytorch.org/ptrblck/48/1823_2.png" class="avatar"> ptrblck:</div>
<blockquote>
<p>Shuffling will shuffle each tensor in the same way</p>
</blockquote>
</aside>
<p>This what I also assumed, but when I get a single batch without shuffle the pairs works fine. Only when shuffle is true the input and target tensors are no longer pairs. Note: to check the the issue of shuffling I have made the input and target with same shape and same values, and I found that they are shuffled independently. So, please, can you help with this</p>

ptrblck: <p>Could you post a code snippet to reproduce this issue, since the data and target samples should be shuffled in the same way. Otherwise their correspondence would be broken.</p>
<p>This dummy example works fine:</p>
<pre><code class="lang-python">x = torch.arange(100)
y = torch.arange(100)

dataset = torch.utils.data.TensorDataset(x, y)
loader = torch.utils.data.DataLoader(
    dataset,
    shuffle=True,
    batch_size=2
)

for data, target in loader:
    print((data==target).all())
</code></pre>

Mohamed_Ragab: <aside class="quote no-group" data-username="ptrblck" data-post="15" data-topic="26605">
<div class="title">
<div class="quote-controls"></div>
<img loading="lazy" alt="" width="24" height="24" src="https://discuss.pytorch.org/user_avatar/discuss.pytorch.org/ptrblck/48/1823_2.png" class="avatar"> ptrblck:</div>
<blockquote>
<p>x = torch.arange(100) y = torch.arange(100) dataset = torch.utils.data.TensorDataset(x, y) loader = torch.utils.data.DataLoader( dataset, shuffle=True, batch_size=2 ) for data, target in loader: print((data==target).all())</p>
</blockquote>
</aside>
<p>I am really thankful for your response, Let me explain further what I am doing so that you have the full picture, I am using a sequence to sequence model on time series data to achieve two tasks concurrently: forecast the next time step and predict the corresponding label of the input sequence.  So, for my model for each input sequence I have two targets:(shifted version of the input and the truth label of the input). at the end of the day, I need the input tensor(n) to be similar target_tensor(n-1)  as I am shifting by step 1.<br>
Here is the code:</p>
<p>Class Cmapps_train_Dataset(Dataset):</p>
<pre><code>def __init__(self, data_identifier,data_dir,win_size):
    """Reads source and target sequences from processing file ."""
    x_train, x_test,y_train,y_test = process_data(data_dir,data_identifier,win_size)
    self.input_tensor=(torch.from_numpy(x_train)).float()
    self.target_tensor=roll(self.input_tensor,-1,0,0)
    self.label=(torch.from_numpy(y_train)).float()
    self.num_total_seqs = len(self.input_tensor)

def __getitem__(self, index):
    """Returns one data pair (source and target)."""
    src_seq = self.input_tensor[index]
    trg_seq = self.target_tensor[index]
    labels = self.label[index]
    return src_seq, trg_seq,labels

def __len__(self):
    return self.num_total_seqs
</code></pre>
<p>data_dir= r"…/…/Deep Learning for RUL/data/"<br>
data_identifier=‘FD001’<br>
win_size=30;batch_size=10;<br>
shuffle_stats;drop_last=True</p>
<p>train_data=Cmapps_train_Dataset(data_identifier,data_dir,win_size)<br>
train_dl = DataLoader(train_data,batch_size=batch_size, shuffle=shuffle_stats,drop_last=drop_last)</p>
<p>=====</p>
<p>sample=next(iter(train_dl))<br>
input_tesnor=sample[0]<br>
target_tensor=sample[1]<br>
for n in range(1,10):<br>
print((input_tesnor[n]==target_tensor[n-1]).all())</p>
<p>===========</p>
<p>Results:<br>
with Shuffle=<strong>False</strong>:<br>
tensor(True)<br>
tensor(True)<br>
tensor(True)<br>
tensor(True)<br>
tensor(True)<br>
tensor(True)<br>
tensor(True)<br>
tensor(True)<br>
tensor(True)</p>
<p>=====</p>
<p>Results with shuffle=<strong>True</strong> :</p>
<p>tensor(False)<br>
tensor(False)<br>
tensor(False)<br>
tensor(False)<br>
tensor(False)<br>
tensor(False)<br>
tensor(False)<br>
tensor(False)<br>
tensor(False)</p>

Mohamed_Ragab: <p>I am completely embarrassed, but I found that I am trying to match input and target with different indices. When I compared input and target with the same index I found that their correspondence is kept. I apologize again for wasting your valuable time.</p>

ptrblck: <p>Haha, good to hear it’s working now!<br>
Don’t feel embarrassed. Yesterday I forgot to zero out the gradients and was debugging my model for 15 minutes <img src="https://discuss.pytorch.org/images/emoji/apple/slight_smile.png?v=9" title=":slight_smile:" class="emoji" alt=":slight_smile:"></p>

Mohamed_Ragab: <p>Haha, so even experts can go wrong at some times <img src="https://discuss.pytorch.org/images/emoji/apple/sweat_smile.png?v=9" title=":sweat_smile:" class="emoji" alt=":sweat_smile:"></p>

hamid_20: <p>hello<br>
What is a labels ?</p>