Прежде чем начать, я хотел бы добавить, что я относительно новичок в глубоком обучении, поэтому моя настройка может быть слишком сложной или неоптимальной.
Я обучаю модель классификации изображений (EfficientNet-B3 на изображениях кандзи в оттенках серого) с помощью PyTorch с:
- AMP (+ GradScaler)
Код: Выделить всё
torch.amp.autocast - сбалансированный по классам разделенный набор данных из HDF5
- Вход: (1, 128, 128) изображений в оттенках серого (~ 620 000 изображений в 3036 классах)
- Потери: CrossEntropyLoss (сглаживание метки = 0,1)
- Оптимизатор: AdamW (снижение веса = 1e-4)
Моя настройка (упрощенная):
Код: Выделить всё
model:
num_classes: 3036
pretrained: True
training:
batch_size: 256
learning_rate: 0.001
epochs: 40
num_workers: 6
shuffle: True
pin_memory: True
persistent_workers: True
prefetch_factor: 4
unfreeze_epoch: 3
optimizer:
type: adamW
weight_decay: 0.0001
data:
...
normalize_mean: [0.5]
normalize_std: [0.5]
val_split: 0.2
device: cuda
...
Код: Выделить всё
...
model = EfficientNetB3Kanji(num_classes=3036, pretrained=True)
for param in model.model.features.parameters():
param.requires_grad = False
optimizer = torch.optim.AdamW(
model.parameters(),
lr=config["training"]["learning_rate"],
weight_decay=config["optimizer"]["weight_decay"]
)
epochs = config["training"]["epochs"]
unfreeze_epoch = config["training"]["unfreeze_epoch"]
scheduler = torch.optim.lr_scheduler.CosineAnnealingLR(
optimizer,
T_max=epochs * len(train_loader),
eta_min=1e-6
)
...
Код: Выделить всё
...
for epoch in range(epochs):
if epoch == unfreeze_epoch:
print(f"\nEpoch {epoch + 1}: Unfreezing backbone")
for param in model.model.features.parameters():
param.requires_grad = True
model.train()
...
for step, (images, labels) in loop:
images = images.to(device, non_blocking=True)
labels = labels.to(device, non_blocking=True)
with autocast(device_type="cuda"):
outputs = model(images)
loss = criterion(outputs, labels)
scaler.scale(loss).backward()
scaler.unscale_(optimizer)
torch.nn.utils.clip_grad_norm_(model.parameters(), 1.0)
scale_before = scaler.get_scale()
scaler.step(optimizer)
scaler.update()
scale_after = scaler.get_scale()
if scale_after >= scale_before:
scheduler.step()
optimizer.zero_grad(set_to_none=True)
...
Код: Выделить всё
def get_train_transforms(mean, std):
return v2.Compose([
v2.RandomAffine(
degrees=15,
translate=(0.1, 0.1),
scale=(0.9, 1.1),
shear=5,
fill=0
),
v2.RandomApply(
[v2.ElasticTransform(alpha=20.0, sigma=3.0)],
p=0.2
),
v2.RandomChoice([
v2.GaussianBlur(kernel_size=3, sigma=(0.1, 1.5)),
v2.Identity()
]),
v2.Normalize(mean=mean, std=std)
])
def get_val_transforms(mean, std):
return v2.Compose([
v2.Normalize(mean=mean, std=std)
])
Переоснащение: разрыв между точностью обучения и проверки увеличивается. Точность обучения все еще улучшается, в то время как показатель Top-1 проверки стабилизировался на уровне 64–65 %.
Высокая точность Top-5: точность моего теста Top-5 довольно высока (~88 %), что позволяет предположить, что модель постоянно правильно определяет «соседство» персонажа, но терпит неудачу в конкретной классификации Top-1.