File size: 4,386 Bytes
2a7ab12
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
c16a9ba
2a7ab12
 
 
 
 
 
c16a9ba
2a7ab12
 
 
 
c16a9ba
2a7ab12
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
c16a9ba
 
2a7ab12
 
 
 
 
c16a9ba
 
2a7ab12
c16a9ba
2a7ab12
 
 
 
 
 
 
 
c16a9ba
2a7ab12
 
 
c16a9ba
2a7ab12
 
 
c16a9ba
2a7ab12
 
c16a9ba
2a7ab12
 
 
 
 
 
 
 
 
 
 
 
 
00538cb
2a7ab12
c16a9ba
2a7ab12
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
from datasets import load_dataset
import torchvision.transforms as T
from torch.utils.data import Dataset, DataLoader
from PIL import Image
from tqdm.auto import tqdm

dataset = load_dataset("uoft-cs/cifar10")
train_transform = T.Compose([
    T.RandomCrop(32, padding=4),
    T.RandomHorizontalFlip(p=0.5),
    T.AutoAugment(policy=T.AutoAugmentPolicy.CIFAR10),
    T.ToTensor(),
    T.Normalize(mean=[0.5, 0.5, 0.5], std=[0.5, 0.5, 0.5])
])
test_transform = T.Compose([
    T.ToTensor(),
    T.Normalize(mean=[0.5, 0.5, 0.5], std=[0.5, 0.5, 0.5])
])

class CIFAR10Wrapper(Dataset):
    def __init__(self, hf_ds, transform):
        self.ds = hf_ds
        self.transform = transform

    def __len__(self):
        return len(self.ds)
    
    def __getitem__(self, i):
        ex = self.ds[i]
        img = ex["img"]
        label = ex["label"]
        
        if not isinstance(img, Image.Image):
            img = Image.fromarray(img)
        x = self.transform(img)
        return { "pixel_values": x, "labels": label }

train_ds = CIFAR10Wrapper(dataset["train"], train_transform)
test_ds = CIFAR10Wrapper(dataset["test"], test_transform)

train_loader = DataLoader(
    train_ds,
    batch_size=128,
    shuffle=True,
    num_workers=0,
    pin_memory=True
)

test_loader = DataLoader(
    test_ds,
    batch_size=256,
    shuffle=False,
    num_workers=0,
    pin_memory=True
)

batch = next(iter(train_loader))
print(batch["pixel_values"].shape)
print(batch['labels'].shape)
from torch.optim.lr_scheduler import SequentialLR, LinearLR, CosineAnnealingLR

cfg = NulaConfig(
    block_channels=(128, 256, 512), 
    classifier_hidden_dim=512,
    use_se=True 
)

DEVICE = "cuda" if pt.cuda.is_available() else "cpu"
model = NulaForImageClassification(cfg).to(DEVICE)

optimizer = pt.optim.AdamW(
    model.parameters(), 
    lr=1e-3, 
    weight_decay=0.01
)
warmup = LinearLR(optimizer, start_factor=0.1, end_factor=1.0, total_iters=5)
cosine = CosineAnnealingLR(optimizer, T_max=45)
scheduler = SequentialLR(optimizer, schedulers=[warmup, cosine], milestones=[5])

def train_one_epoch(model, loader, optimizer, device, grad_clip=1.0):
    model.train()
    
    total_loss = 0.0
    total_correct = 0
    total_examples = 0

    pbar = tqdm(loader, desc="training...", leave=False)

    for batch in pbar:
        x = batch["pixel_values"].to(device, non_blocking=True)
        y = batch["labels"].to(device, non_blocking=True)
        optimizer.zero_grad(set_to_none=True)

        out = model(pixel_values=x, labels=y)
        loss = out.loss
        logits = out.logits
        preds = logits.argmax(dim=1) 
        
        loss.backward()
        pt.nn.utils.clip_grad_norm_(model.parameters(), grad_clip)
        optimizer.step()
        total_loss += loss.item() * y.size(0)

        total_correct += (preds == y).sum().item()
        total_examples += y.size(0)

        pbar.set_postfix(loss=f"{loss.item():.4f}", acc=f"{100 * total_correct / total_examples:.2f}%")
    return total_loss / total_examples, total_correct / total_examples

@pt.no_grad()
def evaluate(model, loader, device):
    model.eval()
    total_loss = 0.0
    total_correct = 0
    total_examples = 0
    
    for batch in loader:
        x = batch["pixel_values"].to(device, non_blocking=True)
        y = batch["labels"].to(device, non_blocking=True)
        
        out = model(pixel_values=x, labels=y)
        loss = out.loss
        logits = out.logits 
        preds = logits.argmax(dim=1)

        total_loss += loss.item() * y.size(0)
        total_correct += (preds == y).sum().item()
        total_examples += y.size(0)
    return total_loss / total_examples, total_correct / total_examples

num_epochs = 50
best_val_acc = 0.0

for epoch in range(1, num_epochs + 1):
    train_loss, train_acc = train_one_epoch(model, train_loader, optimizer, DEVICE)
    val_loss, val_acc = evaluate(model, test_loader, DEVICE)
    scheduler.step()

    best_val_acc = max(best_val_acc, val_acc)
    current_lr = optimizer.param_groups[0]["lr"]
    print(f"{'='}{'-'*60}{'='}") 
    print(f"Epoch [{epoch}/{num_epochs}]")
    print(f"learning_rate : {current_lr:.6f}")
    print(f"train_loss : {train_loss:.6f}")
    print(f"train_acc : {train_acc * 100:.2f}%")
    print(f"val_loss : {val_loss:4f}")
    print(f"val_acc : {val_acc * 100:.2f}")
    print(f"best_val_acc : {100 * best_val_acc:.2f}%")