Ultralytics YOLO27: Inscreve-te na lista de espera.
Get Started
Além da detecção: segmentação, pose, OBB e classificação·Classificar, combinar, embarcar·Aula 8/10
Aulaintermediário

Treinar um classificador de imagens

Organize um conjunto de dados em pastas, treine yolo26n-cls.pt em MNIST160, leia probs e a acurácia top-1 e encaminhe para revisão humana as previsões com baixa confiança.

A classificação de imagens responde a uma pergunta por imagem: o que é isto? Ela exige os rótulos mais simples entre todas as tarefas — o nome de uma pasta — e é a mais rápida, o que a torna a segunda etapa padrão após um detector e o primeiro modelo ideal para uma estação de inspeção que vê uma peça por quadro. O conjunto de dados não tem YAML, então a estrutura de pastas é o contrato, e um classificador sempre fornece uma resposta, mesmo para imagens que não se parecem com nada que já tenha visto. Decidir quando não confiar nele é metade do trabalho.

Resultado

Treine yolo26n-cls.pt em MNIST160, informe a acurácia top-1, leia as probabilidades das classes em result.probs e escolha um limite de confiança que encaminhe imagens incertas para revisão.

Via rápida
Se já sabes orientar-te, aqui está a versão resumida.
  1. Coloque as imagens em train/<class>/ e val/<class>/; os nomes das pastas se tornam nomes de classes, em ordem alfabética.

  2. yolo classify train data=mnist160 model=yolo26n-cls.pt epochs=1 imgsz=64.

  3. Use a acurácia top-1 (metrics.top1) como critério; com cinco classes ou menos, top-5 é sempre 1.0.

  4. Leia result.probs.top1 e .top1conf e encaminhe para uma pessoa as previsões abaixo de um limite de confiança.

Prático

A estrutura de pastas do conjunto de dados#

Classificação de imagens com Ultralytics YOLO de três folhas identificadas como saudável, ferrugem e míldio, cada uma com seu nível de confiança

Os conjuntos de dados de classificação são diretórios, não arquivos YAML. Aponte data= para a pasta raiz:

parts/
├── train/
│   ├── good/      img_0001.jpg ...
│   ├── scratch/   img_0412.jpg ...
│   └── dent/      img_0733.jpg ...
└── val/
    ├── good/
    ├── scratch/
    └── dent/

O que o carregador faz com ela, de acordo com o código-fonte instalado e o guia de conjuntos de dados de classificação:

SituaçãoComportamento
Índices das classesnomes de pastas em train/, em ordem alfabética → dent=0, good=1, scratch=2
Pasta de validaçãoval/, depois validation/, depois valid/; usa test/ como alternativa, com um aviso
Sem a pasta train/, apenas pastas de classesdivide automaticamente em 80/20 entre train/ e val/

Na Ultralytics Platform, um conjunto de dados de classificação contém um rótulo por imagem, em vez de formas:

Conjunto de dados de classificação da Ultralytics Platform: uma esteira transportadora com caixas brancas e um único rótulo por imagem, class2, escolhido no painel de classes

Uma nova pasta renumera suas classes

Sintoma: após adicionar uma classe, uma integração antiga relata partes good como dent. Causa: adicionar uma pasta chamada bent faz com que ela seja ordenada primeiro e desloque todos os índices seguintes. Solução: sempre mapeie índices para nomes com model.names (ou result.names); nunca fixe um índice no código.

Treinar com MNIST160#

MNIST160 contém 160 dígitos manuscritos, 80 em train/ e 80 em test/, cada conjunto dividido em dez pastas de dígitos — pequeno o bastante para um teste rápido na CPU. Não há uma pasta val/, então observe o aviso do carregador e a utilização de test/ como alternativa:

from ultralytics import YOLO

model = YOLO("yolo26n-cls.pt")
model.train(data="mnist160", epochs=1, imgsz=64, device="cpu")
metrics = model.val()
print(f"top-1: {metrics.top1:.3f}  top-5: {metrics.top5:.3f}")
WARNING ⚠️ Dataset 'split=val' not found, using 'split=test' instead.
val: .../datasets/mnist160/test... found 80 images in 10 classes ✅
                   all      0.162      0.463
top-1: 0.162  top-5: 0.463

Uma época mal altera a nova cabeça de dez classes. Na nossa execução, epochs=10 alcançou top-1 de 0.55 e top-5 de 0.95 em cerca de dez segundos na CPU de um laptop — o ciclo funciona; só precisa de um cronograma de treinamento. O guia da tarefa Classify lista os tamanhos pré-treinados.

Top-1 é a proporção de imagens cuja classe com maior probabilidade está correta. Top-5 conta como acerto se a classe correta estiver entre as cinco mais prováveis. Top-5 é informativo para o ImageNet de 1.000 classes, cujas classes vão das mais abrangentes às muito específicas; com cinco classes ou menos, o valor é sempre 1.0, e com dez é generoso. Use a acurácia top-1 e uma matriz de confusão por classe como critérios.

Imagens de amostra do ImageNet organizadas da mais abrangente à mais específica, como de mamífero a husky e de veículo a trimarã

Ler as probabilidades no código#

from ultralytics import YOLO

model = YOLO("yolo26n-cls.pt")  # ImageNet, 1,000 classes
result = model("https://ultralytics.com/images/bus.jpg")[0]

probs = result.probs
print(f"top-1: {result.names[probs.top1]} ({float(probs.top1conf):.2f})")
for i, conf in zip(probs.top5, probs.top5conf.tolist()):
    print(f"  {result.names[i]:20s} {conf:.3f}")
top-1: minibus (0.52)
  minibus              0.516
  police_van           0.369
  trolleybus           0.096
  minivan              0.006
  ambulance            0.003

probs.top1 é um índice, probs.top5 é uma lista de índices e probs.data é o vetor completo de probabilidades. Observe a confiança top-1: 0.52 é só um pouco mais do que jogar uma moeda para decidir entre minibus e police_van. É esse valor que você usa para encaminhar as previsões.

Encaminhar previsões incertas para uma pessoa#

Um classificador em produção raramente precisa acertar todas as imagens; precisa acertar as imagens que classifica sem ajuda. Este script treina o modelo por 10 épocas e, em seguida, mede o efeito de diferentes limites de confiança nas 80 imagens de dígitos reservadas para teste:

from pathlib import Path

from ultralytics import YOLO

model = YOLO("yolo26n-cls.pt")
model.train(data="mnist160", epochs=10, imgsz=64, device="cpu", plots=False)  # model now holds best.pt
print(model.names)  # folder names, sorted, became class indices

test = Path(model.trainer.data["test"])  # mnist160/test, the split the loader validated on
images = sorted(test.rglob("*.png"))
results = model(images, imgsz=64, verbose=False)
truth = [p.parent.name for p in images]

for threshold in (0.0, 0.3, 0.6):
    kept = [(r, t) for r, t in zip(results, truth) if r.probs.top1conf >= threshold]
    correct = sum(r.names[r.probs.top1] == t for r, t in kept)
    print(f"threshold {threshold:.1f}: auto-accept {len(kept):2d}/{len(images)}, accuracy on accepted {correct / max(len(kept), 1):.0%}")
{0: '0', 1: '1', 2: '2', 3: '3', 4: '4', 5: '5', 6: '6', 7: '7', 8: '8', 9: '9'}
threshold 0.0: auto-accept 80/80, accuracy on accepted 55%
threshold 0.3: auto-accept 41/80, accuracy on accepted 68%
threshold 0.6: auto-accept 10/80, accuracy on accepted 80%

Cada linha representa uma troca: aumentar o limite torna as previsões aceitas mais precisas e encaminha mais imagens para uma pessoa. Com 0.6, este modelo decide sozinho apenas 10 dos 80 dígitos — ainda não está pronto para automatizar nada, e a solução é treinar mais, não escolher um limite mais engenhoso. Gere a mesma tabela novamente após cada rodada de treinamento: ela mostra tanto a acurácia que você terá quanto o volume exato de trabalho de revisão que cada limite gera.

Regra de decisão

Escolha o menor limiar cuja precisão nas imagens aceitas atenda ao seu requisito, medida em dados separados para teste. Em seguida, verifique se sua equipe consegue lidar com o volume de revisões gerado; caso contrário, melhore o modelo.

Armadilhas#

Sem uma classe «nenhuma das opções»

Sintoma: uma estação vazia, uma peça incorreta ou uma mão sobre a lente recebe um rótulo de classe com alta confiança. Causa: as probabilidades de softmax sempre somam 1, então o classificador sempre escolhe uma de suas classes. Solução: adicione uma pasta other/ contendo exatamente essas imagens e encaminhe para revisão as previsões com top1conf baixo.

Validar uma cabeça pré-treinada em novas pastas

Sintoma: um modelo pré-treinado obtém uma pontuação próxima de zero no seu conjunto de dados antes de qualquer treinamento. Causa: yolo26n-cls.pt prevê 1.000 índices ImageNet, e suas pastas reutilizam os índices 0–9 com significados diferentes: no MNIST160, a pasta 0 é o índice 0, que a cabeça pré-treinada identifica como tench. Medimos top-1 de 0.000 dessa forma. Solução: primeiro, ajuste fino e, em seguida, valide.

Pastas com vazamento

Sintoma: top-1 próximo de 1.0 na validação, mas muito menor em produção. Causa: fotos quase duplicadas da mesma peça em train/ e val/. Solução: divida por peça ou por sessão, como em Dividir o conjunto de dados corretamente.

Os classificadores são pré-treinados em imgsz=224, não em 640. Para objetos pequenos em um quadro grande, é melhor detectar e depois classificar (próxima lição) do que usar um imgsz maior.

Experimente

Treine yolo26n-cls.pt em mnist160 por 1 época e depois por 10 épocas em imgsz=64, e registre top-1 e top-5 nas duas execuções. Imprima model.names para confirmar como os nomes das pastas se tornaram índices de classes. Em seguida, execute route.py e escolha o limite que você usaria em produção para um requisito de pelo menos 75% de acurácia nas imagens aceitas automaticamente.

Concluído quando
Você concluiu a aula quando todos estes critérios forem atendidos.
  • Você tem os valores top-1 e top-5 para uma execução de 1 época e outra de 10 épocas.

  • Você imprimiu model.names e consegue explicar a regra de índices alfabéticos e por que top-5 não serve para um problema com cinco classes.

  • Você indicou um limite, a acurácia das imagens aceitas e quantas das 80 imagens ele encaminha para revisão.

Mostrar solução
from ultralytics import YOLO

for epochs in (1, 10):
    model = YOLO("yolo26n-cls.pt")
    model.train(data="mnist160", epochs=epochs, imgsz=64, device="cpu")
    metrics = model.val()
    print(f"{epochs:2d} epochs  top-1: {metrics.top1:.3f}  top-5: {metrics.top5:.3f}")
print(model.names)  # {0: '0', 1: '1', ..., 9: '9'}

Nossas execuções: 1 época → top-1 0.162, top-5 0.463; 10 épocas → top-1 0.550, top-5 0.950. Com cinco classes, a resposta correta sempre está entre as cinco primeiras, então top-5 é 1.0 por definição e não informa nada.

Para atingir 75% de acurácia nas imagens aceitas, route.py indica 0.6 (80% nas 10 imagens aceitas), o que encaminha 70 dos 80 dígitos para revisão. Essa é a resposta honesta: o limite atende ao requisito de acurácia, mas o modelo ainda não é útil. Treine por mais tempo e gere novamente a tabela antes de escolher um limite para uso real.

Próximos passos

A seguir, encadeamos tarefas: um detector que alimenta um classificador e um modelo de pose que alimenta um rastreador.

Entre para salvar seu progresso