Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

To build a basic image classifier in PyTorch, send each image through a model that returns one raw score, or logit, per class. Train those logits with torch.nn.CrossEntropyLoss; apply softmax afterward when you want to display normalized class probabilities. The example below follows the official CIFAR-10 tutorial and shows how to adapt its data-loading pattern to labeled image folders.

What “softmax classifier” means in PyTorch

A classifier produces a score for each possible label. For a batch of images, its output is a two-dimensional tensor with one row per image and one column per class. In CIFAR-10, the output has ten columns because the dataset has ten labels.

Softmax converts a row of logits into values between zero and one that sum to one across the class dimension. Those values are useful to display as normalized class probabilities, but they do not guarantee that the prediction is correct or that the model is well calibrated.

For training, pass raw logits—not softmax output—to CrossEntropyLoss. PyTorch documents that “This criterion computes the cross entropy loss between input logits and target.” The loss incorporates the log-softmax operation internally, so applying softmax first is unnecessary and changes the input the loss is designed to receive. See the PyTorch CrossEntropyLoss reference.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Prepare CIFAR-10 images and labels

CIFAR-10 contains ten classes of color images, each represented as a 3 × 32 × 32 tensor after conversion to channel-first format. PyTorch’s tutorial loads separate training and test datasets with TorchVision, converts image values to tensors, and normalizes the channels. Use preprocessing at inference that is compatible with the preprocessing used during training; normalization statistics should suit your dataset rather than being copied blindly. The PyTorch CIFAR-10 classifier tutorial provides the complete dataset and transformation example.

In a typical pipeline, a dataset returns an image tensor and its class-index label. A DataLoader groups examples into batches so the model can process several images in one forward pass. Labels must be valid class indices for the output classes.

Define a model with one output per class

The official CIFAR-10 walkthrough uses a small convolutional neural network trained from scratch and ends with a linear layer of width ten. The essential constraint is that the final layer width equals the number of classes; the model should return logits without a softmax layer for this training setup.

Here is a compact model illustrating the input and output shapes. It expects batches of CIFAR-10-style images shaped [batch, 3, 32, 32] and returns logits shaped [batch, 10]. It is an instructional example, not the exact network architecture from the official tutorial.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
import torch
from torch import nn

class SmallImageClassifier(nn.Module):
    def __init__(self, num_classes=10):
        super().__init__()
        self.features = nn.Sequential(
            nn.Conv2d(3, 16, kernel_size=3, padding=1),
            nn.ReLU(),
            nn.MaxPool2d(2),
            nn.Conv2d(16, 32, kernel_size=3, padding=1),
            nn.ReLU(),
            nn.MaxPool2d(2),
        )
        self.classifier = nn.Sequential(
            nn.Flatten(),
            nn.Linear(32 * 8 * 8, 128),
            nn.ReLU(),
            nn.Linear(128, num_classes),
        )

    def forward(self, images):
        return self.classifier(self.features(images))

For a different image size or number of channels, adjust the model’s input layers and dimensions. For a different number of labels, set num_classes to that count and ensure the dataset’s class indices match the output range.

Train with logits and CrossEntropyLoss

The core training sequence is: get a batch, clear old gradients, compute logits, calculate the loss against labels, backpropagate, and update the parameters. The official tutorial uses cross-entropy loss with stochastic gradient descent and momentum; that is one example configuration, not a universal best optimizer or set of hyperparameters.

import torch
from torch import nn

model = SmallImageClassifier(num_classes=10)
criterion = nn.CrossEntropyLoss()
optimizer = torch.optim.SGD(model.parameters(), lr=0.001, momentum=0.9)

for images, labels in train_loader:
    optimizer.zero_grad()
    logits = model(images)             # [batch_size, 10]
    loss = criterion(logits, labels)   # labels are class indices
    loss.backward()
    optimizer.step()

Do not insert torch.softmax(logits, dim=1) between the model and the loss. The call to zero_grad() prevents gradients from previous batches accumulating, and backward() computes gradients before the optimizer updates the model. PyTorch’s parameter optimization tutorial explains this loop in more detail.

Evaluate separately from training

Keep held-out test examples out of parameter updates, then use them to measure how the trained model performs on data it did not train on. The CIFAR-10 tutorial loads separate training and test datasets and evaluates the classifier on the test set. For evaluation, switch the model to evaluation mode and disable gradient tracking; use the same compatible image preprocessing as during training.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
model.eval()
correct = 0
total = 0

with torch.no_grad():
    for images, labels in test_loader:
        logits = model(images)
        predictions = logits.argmax(dim=1)
        total += labels.size(0)
        correct += (predictions == labels).sum().item()

accuracy = correct / total

This computes a simple accuracy fraction for the supplied test loader. The tutorial and cited sources do not establish a guaranteed accuracy, speed, or training-time result for this example; outcomes depend on the model, data, preprocessing, and training choices.

Convert logits to probabilities for display

Apply softmax along the class dimension, which is dimension 1 for a batch shaped [batch, classes]. A single-image logits vector can use dimension 0 instead.

model.eval()
with torch.no_grad():
    logits = model(images)
    probabilities = torch.softmax(logits, dim=1)

    # Top class for each image
    confidence, predicted_class = probabilities.max(dim=1)

Each row of probabilities sums to one, making it convenient to show the model’s relative scores as probabilities. Softmax is a transformation of the model’s scores, not an independent test of correctness.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Use your own labeled image folders

For images arranged by class, TorchVision’s ImageFolder can infer labels from the directory structure. Put each class’s images in its own subdirectory, then compose image transforms and wrap the dataset in a DataLoader. See the PyTorch custom datasets, DataLoaders, and transforms tutorial.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
from torchvision import datasets, transforms
from torch.utils.data import DataLoader

transform = transforms.Compose([
    transforms.Resize((32, 32)),
    transforms.ToTensor(),
])

dataset = datasets.ImageFolder("data/train", transform=transform)
loader = DataLoader(dataset, batch_size=32, shuffle=True)

print(dataset.classes)  # class names in the order assigned by ImageFolder

A folder layout might look like this:

data/train/
    cats/
        cat_001.jpg
        cat_002.jpg
    dogs/
        dog_001.jpg
        dog_002.jpg

Use a separate held-out folder for evaluation, with the same class subdirectory names and compatible transforms. Check dataset.classes and dataset.class_to_idx so you know how folder names map to numeric labels. For custom datasets, choose normalization statistics appropriate to the images; the CIFAR-10 channel normalization is not automatically suitable for unrelated data.

Common mistakes to check

  • Softmax before the loss: pass logits directly to CrossEntropyLoss.
  • Wrong output width: make the final layer’s number of units equal to the number of labels.
  • Invalid targets: provide class indices in the range represented by the output units.
  • Inconsistent preprocessing: use compatible resizing, tensor conversion, and normalization at training and inference.
  • Overinterpreting probabilities: softmax outputs sum to one but do not establish accuracy or calibration.

PyTorch’s Introduction to PyTorch offers additional context on tensors and the broader training workflow. The neural network tutorial discusses device options including CUDA, MPS, MTIA, and XPU; accelerator use is an optional extension rather than a requirement for this basic workflow.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.