Image processing em pipeline
- ⬜🖼️ Computer vision básico com OpenCV(Computer Vision Clássico)
Recomendamos completar os pré-requisitos antes de seguir, mas nada te impede de continuar.
Pipeline = contrato treino↔inferência
Regra de ouro: a mesma normalização usada no treino precisa ser aplicada em inferência, pixel por pixel. Discrepância aqui é a causa mais comum de modelo “bom em validação, ruim em produção”.
Se seu treino normaliza com mean=[0.485, 0.456, 0.406] e std=[0.229, 0.224, 0.225] (ImageNet) mas a inferência esquece — acurácia cai 5–15% silenciosamente. Commit no repositório: arquivo preprocess.py único importado pelo treino e pela API.
Augmentation com Albumentations
| Etapa | Treino | Validação e produção | Por que a diferença |
|---|---|---|---|
| Redimensionar | Sim | Sim | Precisa ser IDÊNTICO — divergência aqui derruba a acurácia em silêncio |
| Normalizar | Sim | Sim | Mesmos valores; é o contrato entre treino e inferência |
| Espelhar, girar, variar cor | Sim | NÃO | Aleatoriedade na avaliação torna a métrica incomparável entre épocas |
| Recortar aleatoriamente | Sim | NÃO — recorte central determinístico | Mesma razão |
| Aumentação em tempo de teste | Não se aplica | Opcional e explícita | Média de várias versões melhora a nota e multiplica o custo |
import albumentations as A
from albumentations.pytorch import ToTensorV2
train_transform = A.Compose([
A.LongestMaxSize(max_size=640),
A.PadIfNeeded(min_height=640, min_width=640, border_mode=0),
A.HorizontalFlip(p=0.5),
A.RandomBrightnessContrast(p=0.3),
A.HueSaturationValue(p=0.3),
A.GaussNoise(p=0.2),
A.Normalize(mean=(0.485, 0.456, 0.406), std=(0.229, 0.224, 0.225)),
ToTensorV2(),
], bbox_params=A.BboxParams(format="yolo", label_fields=["class_labels"]))
val_transform = A.Compose([
A.LongestMaxSize(max_size=640),
A.PadIfNeeded(min_height=640, min_width=640, border_mode=0),
A.Normalize(mean=(0.485, 0.456, 0.406), std=(0.229, 0.224, 0.225)),
ToTensorV2(),
], bbox_params=A.BboxParams(format="yolo", label_fields=["class_labels"]))Validação/inferência nunca têm augmentation aleatório — só resize + normalize determinísticos. Violar isso destrói comparabilidade entre épocas.
Data loading: CPU vs DALI
# Pipeline DALI minimal: decode JPEG + resize + normalize 100% na GPU
from nvidia.dali import pipeline_def, fn, types
@pipeline_def(batch_size=64, num_threads=4, device_id=0)
def cv_pipeline(file_root):
jpegs, labels = fn.readers.file(file_root=file_root, random_shuffle=True)
images = fn.decoders.image(jpegs, device="mixed") # mixed = GPU decode
images = fn.resize(images, resize_x=224, resize_y=224)
images = fn.crop_mirror_normalize(
images,
mean=[0.485 * 255, 0.456 * 255, 0.406 * 255],
std=[0.229 * 255, 0.224 * 255, 0.225 * 255],
output_layout="CHW",
)
return images, labelsO módulo trata o pré-processamento como contrato entre treino e inferência. Qual defeito isso previne?
Preprocessing determinístico para inferência
# preprocess.py — importado pelo treino e pela API FastAPI
import cv2
import numpy as np
MEAN = np.array([0.485, 0.456, 0.406], dtype=np.float32)
STD = np.array([0.229, 0.224, 0.225], dtype=np.float32)
def preprocess(img_bgr: np.ndarray, size: int = 640) -> np.ndarray:
img = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2RGB)
h, w = img.shape[:2]
scale = size / max(h, w)
nh, nw = int(h * scale), int(w * scale)
img = cv2.resize(img, (nw, nh), interpolation=cv2.INTER_LINEAR)
canvas = np.zeros((size, size, 3), dtype=np.uint8)
canvas[:nh, :nw] = img
x = canvas.astype(np.float32) / 255.0
x = (x - MEAN) / STD
return x.transpose(2, 0, 1) # HWC -> CHWUm arquivo, uma função, dois consumidores. Se o treino mudar de 640 pra 800, a API não quebra silenciosamente — uma mudança, um deploy sincronizado.
Perguntas frequentes
❓ Para que serve aumento de dado em visão?
❓ Aumento de dado no treino ou também na inferência?
❓ Onde o pré-processamento costuma divergir entre treino e produção?
Fixando
Por que validação e inferência nunca usam aumentação aleatória?
Mover a decodificação e o redimensionamento para a placa gráfica resolve qual gargalo?
Terminou de ler?
Marcar como concluído registra o XP, mantém sua sequência e coloca 3 cartas deste módulo na fila de revisão espaçada.
Próximos passos sugeridos
Temas deste módulo
Discussão
Carregando comentários…