Filtering a class form subset of FashonMNIST

username: Gabro
cooked: <p>Hi everybody,<br>
I’m trying to learn how to use datasets form torchvision. Like written in the title, I want to filter a specific subset taken from FashonMNIST, dataset that I already splitted using random_split. the code that I written from now is this:</p>
<pre><code class="lang-auto">trainset_list = []
    trainloader_list = []

    # Define a transform to normalize the data
    transform = transforms.Compose([transforms.ToTensor(),
                                    transforms.Normalize((0.5,), (0.5,))])

    # Download and load the training data
    trainset = datasets.FashionMNIST('~/.pytorch/F_MNIST_data/', download=True, train=True, transform=transform)

    trainset_list = torch.utils.data.random_split(trainset, [int(len(trainset) / x) for _ in range(x)])
    
    for i_trainset in trainset_list:
        trainloader_list.append(torch.utils.data.DataLoader(i_trainset, batch_size=64, shuffle=True))

</code></pre>
<p>My idea was to write something like this after splitting the dataset in x, to remove class y from that portion of dataset:</p>
<pre><code class="lang-auto">    trainset_list[0].train_data = trainset_list[0].train_data[trainset_list[0].train_labels != y]
    trainset_list[0].train_labels = trainset_list[0].train_labels[trainset_list[0].train_labels != y]

</code></pre>
<p>Of course the code give me this error : ‘Subset’ object has no attribute ‘train_data’, because after splitting the dataset, each splitted part are now Subset.</p>
<p>How can I achieve  the filtering?</p>

username: ptrblck
cooked: <p><code>Subset</code> will hold the passed <code>Dataset</code> in its internal <code>.dataset</code> attribute, so <code>trainset_list[0].dataset.train_data</code> might work for you.</p>

username: Gabro
cooked: <p>Unfortunately, in doing that I retrive again the whole dataset where the class is not nine, loosing the split i did before.</p>

username: ptrblck
cooked: <p>I wasn’t sure what your use case is and just focused on the error message.<br>
Why would you like to remove specific indices from each split? Note that each <code>Subset</code> has its own indices and uses these to index the underlying <code>Dataset</code> directly.</p>

username: Gabro
cooked: <p>My goal is to have just one split without one class, train a network and then create another network that will be trained with new data having one label more. I kinda succeeded in this creating my own class that mimic dataset, but I’m not sure if i trust the results of the training or not for now.<br>
My point is: I want to be sure that batch of data are taken uniformly from the original dataset and then remove one label from just one split to train the first network.</p>
<p>If you know some other, easier, method to do it, I will be grateful <img src="https://discuss.pytorch.org/images/emoji/apple/slight_smile.png?v=9" title=":slight_smile:" class="emoji" alt=":slight_smile:"></p>

username: ptrblck
cooked: <p>I think in your use case it might be easier to manipulate the indices before creating the <code>Subsets</code> as shown in this small example:</p>
<pre><code class="lang-python">from torch.utils.data import Subset
from sklearn.model_selection import train_test_split
import torchvision.datasets as datasets

dataset = datasets.MNIST(
    root='./data',
    transform=transforms.ToTensor()
)

# Get all targets
targets = dataset.targets
# Create target_indices
target_indices = np.arange(len(targets))
# Split into train and validation
train_idx, val_idx = train_test_split(target_indices, train_size=0.8)

# Specify which class to remove from train
classidx_to_remove = 0
# Get indices to keep from train split
idx_to_keep = targets[train_idx]!=classidx_to_remove
# Only keep your desired classes
train_idx = train_idx[idx_to_keep]

train_dataset = Subset(dataset, train_idx)
val_dataset = Subset(dataset, val_idx)
</code></pre>
<p>Let me know, if this would work for you.</p>

username: Gabro
cooked: <p>Initially, I thought about that, but with the split of sklearn i can divide the initial dataset in just two part, or at least 2 split at the time from what I understood. I tried to apply this method using the split given by torch and have multiple split, but like before I have as a result subsets and so I could not access to the targets and data of that subset.</p>
<p>Thanks for the help, but for now I will continue using this custom class, that seems work fine</p>
<pre><code class="lang-auto">    def __init__(self, subset, label):
        self.subset = subset
        self.targets = []
        self.data = []

        indeces = subset.indices
        for index in indeces:
            if subset.dataset.__getitem__(int(index))[1] == label:
                continue
            else:
                self.data.append(subset.dataset.__getitem__(int(index))[0])
                self.targets.append(subset.dataset.__getitem__(int(index))[1])

    def __len__(self):
        return len(self.data)

    def __getitem__(self, idx):
        img, target = self.data[idx], int(self.targets[idx])
        return img, target
type or paste code here
</code></pre>

username: Shahid_Siddiqui
cooked: <p>Thanks for the answer, this works till fetching the subset. Training later raises error if the class labels don’t start from zero or aren’t sequential. Thank you.</p>