Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added src/__pycache__/__init__.cpython-310.pyc
Binary file not shown.
Binary file added src/__pycache__/config.cpython-310.pyc
Binary file not shown.
Binary file added src/__pycache__/config0.cpython-310.pyc
Binary file not shown.
Binary file added src/__pycache__/config1.cpython-310.pyc
Binary file not shown.
Binary file added src/__pycache__/config2.cpython-310.pyc
Binary file not shown.
Binary file added src/__pycache__/dataset.cpython-310.pyc
Binary file not shown.
Binary file added src/__pycache__/metric.cpython-310.pyc
Binary file not shown.
Binary file added src/__pycache__/network.cpython-310.pyc
Binary file not shown.
Binary file added src/__pycache__/util.cpython-310.pyc
Binary file not shown.
15 changes: 8 additions & 7 deletions src/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,35 +2,36 @@

# Training Hyperparameters
NUM_CLASSES = 200
BATCH_SIZE = 512
BATCH_SIZE = 256
VAL_EVERY_N_EPOCH = 1

NUM_EPOCHS = 40
OPTIMIZER_PARAMS = {'type': 'SGD', 'lr': 0.005, 'momentum': 0.9}
NUM_EPOCHS = 80
# OPTIMIZER_PARAMS = {'type': 'SGD', 'lr': 0.001, 'momentum': 0.5}
OPTIMIZER_PARAMS = {'type': 'Adam', 'lr': 0.001, 'betas': (0.9, 0.999), 'eps': 1e-8}
SCHEDULER_PARAMS = {'type': 'MultiStepLR', 'milestones': [30, 35], 'gamma': 0.2}

# Dataaset
DATASET_ROOT_PATH = 'datasets/'
NUM_WORKERS = 8

# Augmentation
IMAGE_ROTATION = 20
IMAGE_ROTATION = 30
IMAGE_FLIP_PROB = 0.5
IMAGE_NUM_CROPS = 64
IMAGE_PAD_CROPS = 4
IMAGE_MEAN = [0.4802, 0.4481, 0.3975]
IMAGE_STD = [0.2302, 0.2265, 0.2262]

# Network
MODEL_NAME = 'resnet18'
MODEL_NAME = 'MyNetworksmall'

# Compute related
ACCELERATOR = 'gpu'
DEVICES = [0]
DEVICES = [0,1,2]
PRECISION_STR = '32-true'

# Logging
WANDB_PROJECT = 'aue8088-pa1'
WANDB_PROJECT = 'aue8088-pa1-mynetwork1'
WANDB_ENTITY = os.environ.get('WANDB_ENTITY')
WANDB_SAVE_DIR = 'wandb/'
WANDB_IMG_LOG_FREQ = 50
Expand Down
38 changes: 34 additions & 4 deletions src/metric.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,36 @@

# [TODO] Implement this!
class MyF1Score(Metric):
pass
def __init__(self, num_classes=200):
super().__init__()
self.num_classes = num_classes

self.add_state("tp", default=torch.zeros(num_classes), dist_reduce_fx="sum")
self.add_state("fp", default=torch.zeros(num_classes), dist_reduce_fx="sum")
self.add_state("fn", default=torch.zeros(num_classes), dist_reduce_fx="sum")

def update(self, preds, target):
pred_classes = torch.argmax(preds, dim=1)

for c in range(self.num_classes):
target_mask = (target == c)
pred_mask = (pred_classes == c)

self.tp[c] += (target_mask & pred_mask).sum()

self.fp[c] += (~target_mask & pred_mask).sum()

self.fn[c] += (target_mask & ~pred_mask).sum()

def compute(self):
eps = 1e-10

precision = self.tp / (self.tp + self.fp + eps)
recall = self.tp / (self.tp + self.fn + eps)

f1 = 2 * (precision * recall) / (precision + recall + eps)

return torch.mean(f1)

class MyAccuracy(Metric):
def __init__(self):
Expand All @@ -13,13 +42,13 @@ def __init__(self):

def update(self, preds, target):
# [TODO] The preds (B x C tensor), so take argmax to get index with highest confidence

predicted_classes = torch.argmax(preds, dim=1)

# [TODO] check if preds and target have equal shape

assert predicted_classes.shape == target.shape

# [TODO] Cound the number of correct prediction

correct = (predicted_classes == target).sum()

# Accumulate to self.correct
self.correct += correct
Expand All @@ -29,3 +58,4 @@ def update(self, preds, target):

def compute(self):
return self.correct.float() / self.total.float()

230 changes: 220 additions & 10 deletions src/network.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,21 +12,211 @@
import torch

# Custom packages
from src.metric import MyAccuracy
from src.metric import MyAccuracy, MyF1Score
import src.config as cfg
from src.util import show_setting


# [TODO: Optional] Rewrite this class if you want
class MyNetwork(AlexNet):
def __init__(self):
class MyNetwork(nn.Module):
def __init__(self, num_classes=200, dropout=0.5):
super().__init__()

self.features = nn.Sequential(
nn.Conv2d(3, 64, kernel_size=5, stride=1, padding=2),
nn.BatchNorm2d(64),
nn.ReLU(inplace=True),
nn.MaxPool2d(kernel_size=2, stride=2),

nn.Conv2d(64, 192, kernel_size=3, stride=1, padding=1),
nn.BatchNorm2d(192),
nn.ReLU(inplace=True),
nn.MaxPool2d(kernel_size=2, stride=2),

nn.Conv2d(192, 384, kernel_size=3, stride=1, padding=1),
nn.BatchNorm2d(384),
nn.ReLU(inplace=True),

nn.Conv2d(384, 256, kernel_size=3, stride=1, padding=1),
nn.BatchNorm2d(256),
nn.ReLU(inplace=True),

nn.Conv2d(256, 256, kernel_size=3, stride=1, padding=1),
nn.BatchNorm2d(256),
nn.ReLU(inplace=True),
nn.MaxPool2d(kernel_size=2, stride=2),
)

self.avgpool = nn.AdaptiveAvgPool2d((6, 6))

self.classifier = nn.Sequential(
nn.Dropout(p=dropout),
nn.Linear(256 * 6 * 6, 1024),
nn.BatchNorm1d(1024),
nn.ReLU(inplace=True),
nn.Dropout(p=dropout),
nn.Linear(1024, 1024),
nn.BatchNorm1d(1024),
nn.ReLU(inplace=True),
nn.Linear(1024, num_classes),
)

# [TODO] Modify feature extractor part in AlexNet
def forward(self, x: torch.Tensor) -> torch.Tensor:
x = self.features(x)
x = self.avgpool(x)
x = torch.flatten(x, 1)
x = self.classifier(x)
return x

class MyNetworkSmall(nn.Module):
def __init__(self, num_classes=200, dropout=0.5):
super().__init__()

self.features = nn.Sequential(
nn.Conv2d(3, 32, kernel_size=3, stride=1, padding=1),
nn.BatchNorm2d(32),
nn.ReLU(inplace=True),
nn.MaxPool2d(kernel_size=2, stride=2),

nn.Conv2d(32, 64, kernel_size=3, stride=1, padding=1),
nn.BatchNorm2d(64),
nn.ReLU(inplace=True),
nn.MaxPool2d(kernel_size=2, stride=2),

nn.Conv2d(64, 128, kernel_size=3, stride=1, padding=1),
nn.BatchNorm2d(128),
nn.ReLU(inplace=True),
nn.MaxPool2d(kernel_size=2, stride=2),
)

self.avgpool = nn.AdaptiveAvgPool2d((4, 4))

self.classifier = nn.Sequential(
nn.Dropout(p=dropout),
nn.Linear(128 * 4 * 4, 512),
nn.BatchNorm1d(512),
nn.ReLU(inplace=True),
nn.Linear(512, num_classes),
)

def forward(self, x: torch.Tensor) -> torch.Tensor:
x = self.features(x)
x = self.avgpool(x)
x = torch.flatten(x, 1)
x = self.classifier(x)
return x


#test
class MyNetworkWide(nn.Module):
def __init__(self, num_classes=200, dropout=0.5):
super().__init__()

self.features = nn.Sequential(
nn.Conv2d(3, 128, kernel_size=5, stride=1, padding=2),
nn.BatchNorm2d(128),
nn.ReLU(inplace=True),
nn.MaxPool2d(kernel_size=2, stride=2),

nn.Conv2d(128, 256, kernel_size=3, stride=1, padding=1),
nn.BatchNorm2d(256),
nn.ReLU(inplace=True),
nn.MaxPool2d(kernel_size=2, stride=2),

nn.Conv2d(256, 512, kernel_size=3, stride=1, padding=1),
nn.BatchNorm2d(512),
nn.ReLU(inplace=True),

nn.Conv2d(512, 512, kernel_size=3, stride=1, padding=1),
nn.BatchNorm2d(512),
nn.ReLU(inplace=True),

nn.Conv2d(512, 384, kernel_size=3, stride=1, padding=1),
nn.BatchNorm2d(384),
nn.ReLU(inplace=True),
nn.MaxPool2d(kernel_size=2, stride=2),
)

self.avgpool = nn.AdaptiveAvgPool2d((6, 6))

self.classifier = nn.Sequential(
nn.Dropout(p=dropout),
nn.Linear(384 * 6 * 6, 2048),
nn.BatchNorm1d(2048),
nn.ReLU(inplace=True),
nn.Dropout(p=dropout),
nn.Linear(2048, 2048),
nn.BatchNorm1d(2048),
nn.ReLU(inplace=True),
nn.Linear(2048, num_classes),
)

def forward(self, x: torch.Tensor) -> torch.Tensor:
x = self.features(x)
x = self.avgpool(x)
x = torch.flatten(x, 1)
x = self.classifier(x)
return x

class MyNetworkDeep(nn.Module):
def __init__(self, num_classes=200, dropout=0.5):
super().__init__()

self.features = nn.Sequential(
nn.Conv2d(3, 64, kernel_size=3, stride=1, padding=1),
nn.BatchNorm2d(64),
nn.ReLU(inplace=True),
nn.Conv2d(64, 64, kernel_size=3, stride=1, padding=1),
nn.BatchNorm2d(64),
nn.ReLU(inplace=True),
nn.MaxPool2d(kernel_size=2, stride=2),

nn.Conv2d(64, 128, kernel_size=3, stride=1, padding=1),
nn.BatchNorm2d(128),
nn.ReLU(inplace=True),
nn.Conv2d(128, 128, kernel_size=3, stride=1, padding=1),
nn.BatchNorm2d(128),
nn.ReLU(inplace=True),
nn.MaxPool2d(kernel_size=2, stride=2),

nn.Conv2d(128, 256, kernel_size=3, stride=1, padding=1),
nn.BatchNorm2d(256),
nn.ReLU(inplace=True),
nn.Conv2d(256, 256, kernel_size=3, stride=1, padding=1),
nn.BatchNorm2d(256),
nn.ReLU(inplace=True),
nn.Conv2d(256, 256, kernel_size=3, stride=1, padding=1),
nn.BatchNorm2d(256),
nn.ReLU(inplace=True),
nn.MaxPool2d(kernel_size=2, stride=2),

nn.Conv2d(256, 512, kernel_size=3, stride=1, padding=1),
nn.BatchNorm2d(512),
nn.ReLU(inplace=True),
nn.Conv2d(512, 512, kernel_size=3, stride=1, padding=1),
nn.BatchNorm2d(512),
nn.ReLU(inplace=True),
nn.Conv2d(512, 512, kernel_size=3, stride=1, padding=1),
nn.BatchNorm2d(512),
nn.ReLU(inplace=True),
nn.MaxPool2d(kernel_size=2, stride=2),
)

self.avgpool = nn.AdaptiveAvgPool2d((4, 4))

self.classifier = nn.Sequential(
nn.Dropout(p=dropout),
nn.Linear(512 * 4 * 4, 1024),
nn.BatchNorm1d(1024),
nn.ReLU(inplace=True),
nn.Dropout(p=dropout),
nn.Linear(1024, 1024),
nn.BatchNorm1d(1024),
nn.ReLU(inplace=True),
nn.Linear(1024, num_classes),
)

def forward(self, x: torch.Tensor) -> torch.Tensor:
# [TODO: Optional] Modify this as well if you want
x = self.features(x)
x = self.avgpool(x)
x = torch.flatten(x, 1)
Expand All @@ -45,7 +235,13 @@ def __init__(self,

# Network
if model_name == 'MyNetwork':
self.model = MyNetwork()
self.model = MyNetwork(num_classes=num_classes)
elif model_name == 'MyNetworkSmall':
self.model = MyNetworkSmall(num_classes=num_classes)
elif model_name == 'MyNetworkWide':
self.model = MyNetworkWide(num_classes=num_classes)
elif model_name == 'MyNetworkDeep':
self.model = MyNetworkDeep(num_classes=num_classes)
else:
models_list = models.list_models()
assert model_name in models_list, f'Unknown model name: {model_name}. Choose one from {", ".join(models_list)}'
Expand All @@ -56,6 +252,7 @@ def __init__(self,

# Metric
self.accuracy = MyAccuracy()
self.f1_score = MyF1Score(num_classes=num_classes)

# Hyperparameters
self.save_hyperparameters()
Expand All @@ -79,15 +276,27 @@ def forward(self, x):
def training_step(self, batch, batch_idx):
loss, scores, y = self._common_step(batch)
accuracy = self.accuracy(scores, y)
self.log_dict({'loss/train': loss, 'accuracy/train': accuracy},
on_step=False, on_epoch=True, prog_bar=True, logger=True)
f1 = self.f1_score(scores, y)

self.log_dict({
'loss/train': loss,
'accuracy/train': accuracy,
'f1_score/train': f1
}, on_step=False, on_epoch=True, prog_bar=True, logger=True)

return loss

def validation_step(self, batch, batch_idx):
loss, scores, y = self._common_step(batch)
accuracy = self.accuracy(scores, y)
self.log_dict({'loss/val': loss, 'accuracy/val': accuracy},
on_step=False, on_epoch=True, prog_bar=True, logger=True)
f1 = self.f1_score(scores, y)

self.log_dict({
'loss/val': loss,
'accuracy/val': accuracy,
'f1_score/val': f1
}, on_step=False, on_epoch=True, prog_bar=True, logger=True)

self._wandb_log_image(batch, batch_idx, scores, frequency = cfg.WANDB_IMG_LOG_FREQ)

def _common_step(self, batch):
Expand All @@ -109,3 +318,4 @@ def _wandb_log_image(self, batch, batch_idx, preds, frequency = 100):
key=f'pred/val/batch{batch_idx:5d}_sample_0',
images=[x[0].to('cpu')],
caption=[f'GT: {y[0].item()}, Pred: {preds[0].item()}'])