Converting Logits to Class Labels
Softmax changes the values in a row, but it does not change which position holds the largest value. If the only goal is a predicted label, argmax on the logits gives the same label as argmax on the probabilities.
Why One Prediction Is Not Enough
Earlier, a model's outputs were turned into class labels one example at a time. That works for a single example, but a training set or test set contains many examples, and what we usually want is one number that summarizes how often the model is right across all of them. This article builds the pieces that produce that number: first a way to turn each row of model outputs into a single class label, then a reusable function that counts correct predictions over an entire dataset.
A classifier does not usually answer with a class name. For each input it produces a row of numbers, one number per possible class, describing how strongly the model leans toward each class. Before reading the explanation, try the following question. Given the row of scores below, which position would you pick as the model's decision?
What do you think happens?
For the row of logits [2.1, 0.3, 1.7], which position does torch.argmax return when it scans the row?
Reveal answer
Position 0
Argmax returns the position of the largest value in the row. The largest value here is 2.1, which sits at position 0.
Picking the Largest Score in Each Row
The function torch.argmax returns the index of the highest value in a tensor. With dim=1, it scans each row and returns, for every row, the position of that row's largest value. Turning a row of class scores into a single class label is exactly what this does: the returned position is the predicted class.
Reading one row of logits
A model produces the row [2.1, 0.3, 1.7] for one example. Use torch.argmax with dim=1 to find the predicted class label.
- 1Identify the row
The row has three numbers, one per possible class: 2.1 at position 0, 0.3 at position 1, and 1.7 at position 2.
- 2Find the largest value
Comparing the three values, 2.1 is the largest.
- 3Return its position
2.1 sits at position 0, so argmax with dim=1 returns 0. The predicted class label for this example is 0.
The predicted class label is 0.
Notice what argmax does not return. It does not return the value 2.1. It returns the position of that value. The class label is the position, which is why the output of argmax is a set of integers, one per row.
Why the Dimension Argument Sets the Direction
The dimension argument decides the direction of the search. With dim=1, the function scans each row. Changing it to dim=0 scans down each column instead and returns, for every column, the row position of its largest value. That second result answers a different question, so using the wrong dimension is one of the most common ways to get label predictions that look plausible but mean something else.
Logits Versus Softmax Probabilities
The same argmax operation applies to probabilities and to the raw outputs of the network. Computing softmax first and then calling argmax is a valid path, but it is not required to obtain class labels. The position of the largest value is the same whether you look at the logits or at the probabilities computed from them, so argmax can be applied to the logits directly.
Softmax changes the values in a row, but it does not change which position holds the largest value. If the only goal is a predicted label, argmax on the logits gives the same label as argmax on the probabilities.
Comparing Predictions With the True Labels
Once there are predicted labels, the next question is whether they match the true labels. The == operator compares two tensors element by element and returns a tensor of booleans, one for each position, where True means the prediction matched the true label at that position. Adding up the True values then counts the correct predictions. The source does this with torch.sum, which counts the True entries in the boolean tensor produced by the comparison.
import torch
predicted = torch.tensor([0, 2, 1, 1, 0])
true_labels = torch.tensor([0, 2, 1, 1, 0])
matches = predicted == true_labels
print(matches)
correct = torch.sum(matches)
print(correct)- 1The predicted tensor and the true-label tensor each hold one integer per example, so their positions line up.
- 2The == operator returns a boolean tensor. Each position is True where the predicted label equals the true label.
- 3torch.sum adds the True entries, treating each True as 1, which gives the number of correct predictions.
- predicted holds one integer label per example
- == compares the two tensors position by position
- torch.sum counts the True entries
tensor([True, True, True, True, True])
tensor(5)The source uses a training set of five examples in which all five predictions are correct. In that case the comparison is all True and the count is 5.
Turning a Count into Accuracy
Accuracy is the fraction of predictions that were correct. Because the correct count can never exceed the total count of examples, the fraction always falls between 0 and 1. A result of 0 means no predictions matched, and a result of 1 means all of them matched. Expressed as a percentage, the same fraction is multiplied by 100.
Accuracy from a count of matches
The comparison produces three True values out of four positions. What is the accuracy, as a fraction and as a percentage?
- 1Identify the counts
The number of correct predictions is 3, and the total number of examples is 4.
- 2Divide
The fraction is $\frac{3}{4}$.
- 3Convert to a percentage
Multiplying by 100 gives $\frac{3}{4} \times 100 = 75$.
The accuracy is three quarters, or 75 percent.
Looping Over Batches in compute_accuracy
The accuracy function does not send the whole dataset through the model at once. A dataset may be far too large for memory, so the function gives the model only one chunk at a time. Each chunk has the same size as the batch size used during training. The function does its work in a single loop over the data loader. On each pass, one batch of features and labels arrives, the model produces logits for that batch, and those logits are converted into predicted labels. The predicted labels are compared with the true labels, and the count of matches is added to a running total of correct predictions. The number of examples in the batch is added to a running count of all examples.
import torch
def compute_accuracy(model, data_loader):
correct = 0
total = 0
for features, labels in data_loader:
logits = model(features)
predictions = torch.argmax(logits, dim=1)
matches = predictions == labels
correct += torch.sum(matches)
total += len(labels)
accuracy = correct / total
return float(accuracy)- 1The two counters start at zero and carry results across batches.
- 2The for loop receives one batch of features and labels each time, so the whole dataset is never passed to the model at once.
- 3The model produces logits for the batch, and argmax with dim=1 converts each row into a predicted class label.
- 4The == comparison gives a boolean per example, torch.sum counts the True entries, and both counters are updated.
- 5After the loop ends, the correct count is divided by the total count, and the result is converted to an ordinary Python float.
- The loop handles one batch per pass
- argmax with dim=1 runs on the logits directly
- The final line returns a Python float
Because the counters carry results forward batch by batch, the final accuracy covers the full dataset even though the model never saw all of it in one call. The same function therefore works for datasets of any size, not just the small ones that fit in memory.
Same Function, Training Loader Versus Test Loader
The function is applied to the training data first and then to the test data, using the same model in both calls. Each call prints one value. The two calls differ only in the data loader they receive: the input examples and true labels change, while the function and the model stay the same.
Before you run the two calls, decide what kind of value each one returns and what range that value can take. Because each result is a count of correct predictions divided by a count of all examples, every printed value lies between 0 and 1. A printed value of 0 would mean no predictions matched on that loader, and a printed value of 1 would mean all of them matched. The two printed values can differ because they are computed over different examples.
Mistakes That Produce Wrong Accuracy
Common mistake Using dim=0 instead of dim=1 in argmax
What it looks likeCalling torch.argmax(logits, dim=0) on a tensor with one row per example
Why it failsdim=0 scans down each column and returns, for every column, the row position of its largest value. That answers a different question from the one needed.
Do this insteadUse dim=1 so that argmax scans each row and returns one predicted label per example.
Common mistake Believing softmax is required before argmax
What it looks likeComputing softmax on the logits and then calling argmax, while assuming the raw logits cannot be used
Why it failsThe position of the largest value is the same in the logits and in the probabilities computed from them.
Do this insteadApply argmax directly to the logits. Softmax is a valid path but is not needed to get labels.
Common mistake Reporting a count instead of a fraction
What it looks likePrinting 3 when the expected value is 3 out of 4
Why it failsThe count of correct predictions is not an accuracy. Accuracy is the count divided by the total number of examples.
Do this insteadDivide the correct count by the total count, and multiply by 100 only when a percentage is wanted.
Common mistake Comparing predicted labels against the wrong true-label tensor, which silently produces a plausible but meaningless count
Debugging an Unexpected Accuracy
When an accuracy number surprises you, the mistake almost always sits in one of three places: the dimension passed to argmax, the tensor passed into argmax, or the true labels it is compared against. Work through the pipeline in that order, and check each stage before trusting the final count.
- 1Print the predicted labels first and check that there is exactly one integer per example.
- 2Print the comparison result and confirm that its length matches the number of examples.
- 3Confirm that the true-label tensor lines up position by position with the predictions.
- 4Only then read the count, because a wrong count is usually a symptom of a wrong label tensor upstream.
- 5If the batches disagree, trace the counters batch by batch to find where the divergence begins.
A row of logits is [0.4, 2.8, 1.1]. Predict the label that argmax with dim=1 returns, then say whether softmax would change that answer. Explain your reasoning in terms of which position holds the largest value.
Hints
- Find the largest of the three values and note its position.
- Think about whether softmax moves the largest value to a different position.
Key Takeaways
- torch.argmax with dim=1 returns the position of the largest value in each row, which turns a row of class scores into a predicted class label.
- Argmax can be applied directly to logits, because softmax does not change which position holds the largest value.
compute_accuracyloops over the data loader, compares predicted and true labels with ==, counts matches with torch.sum, and keeps running totals, so it works on datasets too large to pass to the model at once.- Accuracy is the number of correct predictions divided by the total number of examples, so it always falls between 0 and 1.
- When accuracy looks wrong, check the argmax dimension, the predicted-label tensor, and the true-label tensor, in that order.