Can someone please clarify what happens in _getitem_ function? Thanks
I understand that output contains the all of encodings, token type ids, attention_mask, and corresponding labels as tensors. I would like to understand the inner working of getitem function and the need of getting label lengths with len function.
class NewsGroupsDataset(torch.utils.data.Dataset):
    def __init__(self, encodings, labels):
        self.encodings = encodings
        self.labels = labels

    def __getitem__(self, idx):
        item = {k: torch.tensor(v[idx]) for k, v in self.encodings.items()}
        item[&quot;labels&quot;] = torch.tensor([self.labels[idx]])
        return item

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

# convert our tokenized data into a torch Dataset
train_dataset = NewsGroupsDataset(train_encodings, train_labels)
valid_dataset = NewsGroupsDataset(valid_encodings, valid_labels)


Python defines many special methods for classes. These methods define the behavior of the class in certain situations. You're probably already familiar with the __init__ special method, that gets invoked when a new instance of the class is created. __getitem__ is another special method that is called when you use subscription on an instance of the class (i.e. square brackets []), and __len__ is called when you use pass an instance of your class to the built-in len function.
As for Pytorch, we must implement these methods because that's what Pytorch's DataLoader object expects. It uses these methods to sample your dataset and know when it is done sampling the dataset. Though DataLoader uses many abstractions to support different sampling and multi-process operations, it basically needs __len__ in order to know the maximum index it can query from the dataset, and it uses __getitem__ to sample the indices it needs.
For example, when you're using random sampling with 0 workers, the following snippets do effectively the same thing
from torch.utils.data import DataLoader

train_dataset = NewsGroupsDataset(train_encodings, train_labels)
data_loader = DataLoader(train_dataset, batch_size=5, shuffle=True)
for items in data_loader:
    # items now contains batches of samples of size 5 from your dataset

and
# For demonstration purposes only, do NOT sample your datasets like this (use DataLoader)!
import random
from torch.utils.data import default_collate

def random_batches(dataset, batch_size, shuffle):
    indices = list(range(len(dataset)))  # uses Dataset.__len__
    if shuffle:
        random.shuffle(indices)
    batch = []
    for i in indices:
        batch.append(dataset[i])  # uses Dataset.__getitem__
        if len(batch) == batch_size:
            yield default_collate(batch)
            batch = []
    if batch:
        yield default_collate(batch)

train_dataset = NewsGroupsDataset(train_encodings, train_labels)
for items in random_batches(train_dataset, batch_size=5, shuffle=True):
    # items now contains batches of samples of size 5 from your dataset

Note that default_collate is a function that takes a list of samples and converts them into stacks of batch-sized tensors. The implementation can be found here if you're curious of the details.
DataLoader also supports a lot of other cool things, like multiple workers (probably most important), custom sampling schemes, custom data collation, pinned memory, dropping last non-full batch, and more. Pytorch does most of the work for you with this class, you just need to write the dataset object with __len__ and __getitem__ implementations.
