PyTorch A Binary Classifier
A binary classifier is a model that answers one yes-or-no question for each row. It gives one score per row, and the sign of the score is the answer.
One score per row
A Linear layer with one output gives one score per row.
torch.manual_seed(1)
layer = nn.Linear(2, 1)
points = torch.tensor([[2.0, 2.0], [-2.0, -2.0]])
scores = layer(points)
print(scores.shape)The two-class loss
The loss compares each score with its target. Right and confident scores cost little.
loss_fn = nn.BCEWithLogitsLoss()
scores = torch.tensor([2.0, -2.0, 0.5])
targets = torch.tensor([1.0, 0.0, 1.0])
print(round(loss_fn(scores, targets).item(), 4))Scores become answers
A score above 0 means class 1. A score at or below 0 means class 0.
scores = torch.tensor([1.8, -0.4, 0.3, 3.2])
answers = (scores > 0).long()
print(answers)Example
import torch
from torch import nn
torch.manual_seed(0)
per_class = 60
blob_a = torch.randn(per_class, 2) * 0.8 + torch.tensor([-2.0, -2.0])
blob_b = torch.randn(per_class, 2) * 0.8 + torch.tensor([2.0, 2.0])
points = torch.cat([blob_a, blob_b])
labels = torch.cat([torch.zeros(per_class), torch.ones(per_class)])
torch.manual_seed(1)
model = nn.Linear(2, 1)
loss_fn = nn.BCEWithLogitsLoss()
optimizer = torch.optim.Adam(model.parameters(), lr=0.1)
for epoch in range(100):
scores = model(points).squeeze(1)
loss = loss_fn(scores, labels)
optimizer.zero_grad()
loss.backward()
optimizer.step()
with torch.no_grad():
scores = model(points).squeeze(1)
predictions = (scores > 0).float()
correct = int((predictions == labels).sum())
accuracy = correct / labels.shape[0] * 100
print("Final loss:", round(loss.item(), 4))
print("Correct:", correct, "of", labels.shape[0])
print(f"Accuracy: {accuracy:.0f}%")Key points
- Binary: two classes only, labelled 0 and 1
- Logistic-style: one score per row, pushed up for class 1 rows and down for class 0 rows
- BCEWithLogitsLoss: cross-entropy's two-class form, taking one score per row
- Use (scores > 0) to turn scores into class answers
- One score carries the whole answer, and its sign names the class
In this example, the blobs come from the same seeded recipe as the blob lesson, with 60 points per class. A seed is set again before the model is built, so the layer starts from the same weights every run. The model is one Linear layer with two inputs and one output. BCEWithLogitsLoss scores each row against its label. Adam trains the model for 100 full passes over the data. The final loss prints first. Then scores above 0 become class 1, and the answers match all 120 labels.
Note
BCEWithLogitsLoss takes raw scores, so no sigmoid is applied before it
Try it Yourself
Edit the code, then press Run.
Running is simulated ยท Python Playground
Exercise
A row gets a score of -1.3 from a binary classifier. What class does the model answer?