%%capture
!pip install torch==1.7.0+cu101 torchvision==0.8.1+cu101 -f https://download.pytorch.org/whl/torch_stable.html
%%capture
!pip install pytorch-lightning einops
!pip install "opencv-python-headless<4.3"
# %%capture
!pip install albumentations==0.5.0
!mkdir data
%cd data
!git clone https://github.com/howl0893/custom-object-detection-datasets.git
%cd /content/data/custom-object-detection-datasets/datasets/cards/images/
import torch
from torch.utils.data import Dataset, DataLoader
import torchvision as V
import pandas as pd
from PIL import Image, ImageDraw
import numpy as np
import albumentations as A
import cv2
import pytorch_lightning as pl
!pwd
!ls
f = open('train_labels.csv').read()
df = pd.read_csv('train_labels.csv')
df
df[(df.filename == 'cam_image35.jpg')]
draw = ImageDraw.Draw(img)
for row in df[(df.filename == 'cam_image35.jpg')].iterrows():
# print(row[1])
draw.rectangle([row[1].xmin, row[1].ymin, row[1].xmax, row[1].ymax], outline='red')
img
classes = {'ace': 5, 'jack': 4, 'king': 3, 'nine': 2, 'queen': 6, 'ten': 1}
class CardDS(Dataset):
def __init__(self, train = True):
self.train = train
if train:
self.df = pd.read_csv('train_labels.csv')
else:
self.df = pd.read_csv('test_labels.csv')
self.files = self.df.filename.unique()
self.transform = A.Compose([
A.HorizontalFlip(p=0.5),
A.Resize(512, 512)
], bbox_params=A.BboxParams(format='pascal_voc'))
def __len__(self):
return len(self.files)
def __getitem__(self, idx):
f = self.files[idx]
if self.train:
img = Image.open(f'train/{f}')
# img = V.io.read_image(f'train/{f}')
else:
img = Image.open(f'test/{f}')
# img = V.io.read_image(f'test/{f}')
img = np.array(img)
annots = []
for row in self.df[self.df.filename == f].iterrows():
# print(row)
annots += [(row[1].xmin, row[1].ymin, row[1].xmax, row[1].ymax, classes[row[1]['class']])]
out = self.transform(image=img, bboxes=annots)
img = V.transforms.functional.to_tensor(out['image'])
out['labels'] = torch.Tensor([x[-1] for x in out['bboxes']]).long()
out['boxes'] = torch.Tensor([x[:4] for x in out['bboxes']])
out.pop('image')
out.pop('bboxes')
return img, out
ds = CardDS()
len(ds)
ds.df['class'].value_counts()
idx = np.random.randint(len(ds))
out = ds[idx]
img, annots = out['image'], out['bboxes']
img.shape
img = Image.fromarray(img)
annots
draw = ImageDraw.Draw(img)
for a in annots:
draw.rectangle(a[:4], outline='red')
img
annots
def collate(batch):
return tuple(zip(*batch))
class Net(pl.LightningModule):
def __init__(self):
super().__init__()
self.model = V.models.detection.retinanet_resnet50_fpn(num_classes=len(classes) + 1, pretrained_backbone=True)
self.lr = 1e-3
def freeze(self):
for p in self.model.parameters():
p.requires_grad = False
for p in self.model.head.parameters():
p.requires_grad = True
def unfreeze(self):
for p in self.model.parameters():
p.requires_grad = True
def forward(self, x, y):
out = self.model(x, y)
return out
def training_step(self, batch, batch_id):
x, y = batch
out = self(x, y)
loss = out['bbox_regression'] + out['classification']
self.log('train loss', loss.item())
return loss
def validation_step(self, batch, batch_nb):
# OPTIONAL
x, y = batch
self.train()
with torch.no_grad():
out = self(x, y)
loss = out['bbox_regression'] + out['classification']
return {'val_loss': loss}
def validation_epoch_end(self, outputs):
avg_loss = torch.stack([x['val_loss'] for x in outputs]).mean()
self.log('val_loss', avg_loss)
return avg_loss
def configure_optimizers(self):
opt = torch.optim.SGD(self.parameters(), self.lr, 0.9)
sched = torch.optim.lr_scheduler.CosineAnnealingWarmRestarts(opt, 37*3) ## changed
return [opt], [{ ## changed
'scheduler': sched, ## changed
'interval': 'step', # The unit of the scheduler's step size ## changed
}]
def train_dataloader(self):
ds = CardDS()
return DataLoader(ds, 8, collate_fn=collate, shuffle=True)
def val_dataloader(self):
ds = CardDS(train=False)
val_dl = DataLoader(ds, 8, collate_fn=collate)
return val_dl
net = Net()
net.freeze()
torch.cuda.is_available()
trainer = pl.Trainer(gpus=1)
lrf = trainer.tuner.lr_find(net, num_training=50) ## changed
fig = lrf.plot(suggest=True) ## changed
fig.show()
net.lr = 3e-2
trainer = pl.Trainer(gpus=1, log_every_n_steps=1, callbacks=[pl.callbacks.LearningRateMonitor('step')]) ## changed
trainer.max_epochs = 30
trainer.fit(net)
trainer.save_checkpoint('txfr.pt', weights_only=True)
net = Net.load_from_checkpoint('txfr.pt')
net.unfreeze()
trainer = pl.Trainer(gpus=1)
lrf = trainer.tuner.lr_find(net, num_training=50, max_lr=3e-2) ## changed
fig = lrf.plot(suggest=True) ## changed
fig.show()
fig.gca().set_ylim(1.0, 1.5)
fig
net.lr = 3e-3
trainer = pl.Trainer(gpus=1, log_every_n_steps=1, callbacks=[pl.callbacks.LearningRateMonitor('step')])
trainer.max_epochs = 25
trainer.fit(net)
%%capture
net.eval()
net.cuda()
df = pd.read_csv('test_labels.csv')
idx = np.random.randint(len(df))
img = Image.open(f'test/{df.filename.loc[idx]}')
img = img.resize((456, 456))
img
inp = V.transforms.functional.to_tensor(img)
inp.shape
with torch.no_grad():
out = net.model([inp.cuda()])
outidx = V.ops.nms(out[0]['boxes'], out[0]['scores'], 0.25)
outidx
out[0]['scores'][outidx][:15]
out[0]['labels'][outidx][:15]
draw = ImageDraw.Draw(img)
for row in out[0]['boxes'][outidx][:4]:
draw.rectangle(list(row.cpu().numpy()), outline='red')
img
classes
%load_ext tensorboard
%tensorboard --logdir ./lightning_logs