<jupyter_start><jupyter_text>To make a dataset class that is compatible with the torch.utils.data.DataLoader thing you should subclass **VisionDataset** from *torchvision.datasets.vision.VisionDataset* and implement *__getitem__* and *__len__*<jupyter_code>transform = transforms.Compose([
    transforms.ToTensor(),
    transforms.Normalize(mean=(0.5, 0.5, 0.5), std=(0.5, 0.5, 0.5))
])

# Returns a Dataset object
trainset = torchvision.datasets.CIFAR10(root='data', train=True,
                                        download=False, transform=transform)
# Equivalent to Tensorflow generators, 
trainloader = torch.utils.data.DataLoader(trainset, batch_size=16,
                                          shuffle=True, num_workers=20)

testset = torchvision.datasets.CIFAR10(root='data', train=False,
                                       download=False, transform=transform)

testloader = torch.utils.data.DataLoader(testset, batch_size=16,
                                         shuffle=False, num_workers=20)

classes = ('plane', 'car', 'bird', 'cat',
           'deer', 'dog', 'frog', 'horse', 'ship', 'truck')
# function to show an image
def imshow(img, labels: list):
    img = img / 2 + 0.5     # unnormalize
    npimg = img.numpy()
    plt.imshow(np.transpose(npimg, (1, 2, 0)))
    plt.title(labels)
    plt.show()


# get some random training images
dataiter = iter(trainloader)
images, labels = dataiter.next()


# show images
imshow(torchvision.utils.make_grid(images), str(labels.numpy()))
class Net(nn.Module):
    def __init__(self):
        super().__init__()
        # in_channels: Input channels (3 since RGB)
        # out_channels: Number of filters basically
        # kernel_size: u know what it is
        self.conv1 = nn.Conv2d(in_channels=3, out_channels=6, kernel_size=5)
        self.pool = nn.MaxPool2d(kernel_size=2, stride=2)
        self.conv2 = nn.Conv2d(in_channels=6, out_channels=16, kernel_size=5)
        # TODO: Figure out why 16*5*5, I believe you just need to know based on
        # input dimensions
        self.fc1 = nn.Linear(in_features=16*5*5, out_features=120)
        self.fc2 = nn.Linear(in_features=120, out_features=84)
        self.fc3 = nn.Linear(in_features=84, out_features=10)
        
    def forward(self, x):
        x = self.pool(F.relu(self.conv1(x)))
        x = self.pool(F.relu(self.conv2(x)))
        # Like reshape
        x = x.view(-1 , 16*5*5)
        x = F.relu(self.fc1(x))
        x = F.relu(self.fc2(x))
        # Using nn.CrossEntropyLoss will kinda implicaitly apply some kind 
        # of softmax or something idk
        x = self.fc3(x)
        return x

# .to method can be use to cast to many different things, and is used to "cast" tensors to GPU 
net = Net().to(device)
net(images.to(device)).shape
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9)
n_epochs = 60
for epoch in range(n_epochs):
    
    running_loss = 0.0
    
    bar = tqdm(
        iterable=enumerate(trainloader, 0), 
        total=len(trainloader), 
        unit=' batches',
        desc=f' Epoch {epoch+1}/{n_epochs}',
#         file=sys.stdout,
        ascii=True,
        position=0
    )
    
    # Loop through batches
    for i, data in bar:
        inputs, labels = data[0].to(device), data[1].to(device)
                
        # Zero parameter gradients since PyTorch will just accumulate the gradient
        # vectors while it trains (in order to get the "mean" direction to move in
        # the parameter space). Also doing it this way minimizes memory allocation 
        # etc, probably. 
        optimizer.zero_grad()
        
        # forward + backward + optimize
        outputs = net(inputs)
        loss = criterion(outputs, labels)
        loss.backward() # Computes gradients 
        optimizer.step() # Do a gradient step
        
        # print statistics
        running_loss += loss.item()
        bar.set_postfix({'loss':running_loss / (i+1)})
torch.save(net.state_dict(), 'models/cifar_net.pth')
# net.load_state_dict(torch.load('models/cifar_net.pth'))
outputs = net(images.to(device))
correct = 0
total = 0
with torch.no_grad():
    for data in testloader:
        images, labels = data[0].to(device), data[1].to(device)
        outputs = net(images)
        _, predicted = torch.max(outputs.data, 1)
        total += labels.size(0)
        correct += (predicted == labels).sum().item()

print('Accuracy of the network on the 10000 test images: %d %%' % (
    100 * correct / total))<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.1225834797891037, 'fraction_numerical': 0.023725834797891036, 'mean_word_length': 2.6511627906976742, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 8, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '1', 'dir': 'jupyter-structured-clean-dedup', 'id': '641327', 'license': 'MIT', 'n_tokens_mistral': 1511, 'n_tokens_neox': 1440, 'n_words': 360, 'path': 'torchtutorial/TorchTutorial-TrainingAClassifier.ipynb', 'repo_name': 'Napam/JallaResearch', 'size': '4552'}