F1 SMOKE ELIMINATION
Smoke Elimination using FFA-Net Model MSE: 12.538
FFA-Net: Feature Fusion Attention Network for Single Image Dehazing
Top Scoring Solution Notebook
F1 Smoke Elimination¶
Step 1: Download the data¶
Download Packages¶
In [1]:
!pip install --upgrade aicrowd-cli
In [2]:
API_KEY = "9cce69d6577e95bdcfaf107bb38f8ff2"
!aicrowd login --api-key $API_KEY
In [3]:
!aicrowd dataset download --challenge f1-smoke-elimination -j 3
In [4]:
!rm -rf data
!mkdir data
!unzip train.zip -d data/train >/dev/null
!unzip val.zip -d data/val >/dev/null
!unzip test.zip -d data/test >/dev/null
In [5]:
!rm -rf ./test.zip ./train.zip ./val.zip ./sample_submission.zip
Step 2: Download the code¶
In [6]:
!git clone https://github.com/zhilin007/FFA-Net
Trained_models are available in google drive: https://drive.google.com/file/d/1QoFKNohireWa0bu_izB1v4Bc3HMaaREr/view?usp=sharing Put models in the net/trained_models/folder.
In [7]:
from google_drive_downloader import GoogleDriveDownloader as gdd
gdd.download_file_from_google_drive(file_id='1QoFKNohireWa0bu_izB1v4Bc3HMaaREr',
dest_path='./pretrainedModels.zip',
unzip=True)
In [8]:
!rm -rf ./pretrainedModels.zip
!cp ./its_train_ffa_3_19.pk ./FFA-Net/net/trained_models/.
!cp ./ots_train_ffa_3_19.pk ./FFA-Net/net/trained_models/.
!rm ./its_train_ffa_3_19.pk
!rm ./ots_train_ffa_3_19.pk
In [9]:
%%writefile ./FFA-Net/net/data_utils.py
import torch.utils.data as data
import torchvision.transforms as tfs
from torchvision.transforms import functional as FF
import os,sys
sys.path.append('.')
sys.path.append('..')
import numpy as np
import torch
import random
from PIL import Image
from torch.utils.data import DataLoader
from matplotlib import pyplot as plt
from torchvision.utils import make_grid
from metrics import *
from option import opt
BS=opt.bs
print(BS)
crop_size='whole_img'
if opt.crop:
crop_size=opt.crop_size
def tensorShow(tensors,titles=None):
'''
t:BCWH
'''
fig=plt.figure()
for tensor,tit,i in zip(tensors,titles,range(len(tensors))):
img = make_grid(tensor)
npimg = img.numpy()
ax = fig.add_subplot(211+i)
ax.imshow(np.transpose(npimg, (1, 2, 0)))
ax.set_title(tit)
plt.show()
class RESIDE_Dataset(data.Dataset):
def __init__(self,path,train,size=crop_size,format='.jpg'):
super(RESIDE_Dataset,self).__init__()
self.size=size
print('crop size',size)
self.train=train
self.format=format
self.haze_imgs_dir=os.listdir(os.path.join(path,'smoke'))
self.haze_imgs=[os.path.join(path,'smoke',img) for img in self.haze_imgs_dir]
self.clear_dir=os.path.join(path,'clear')
def __getitem__(self, index):
haze=Image.open(self.haze_imgs[index])
if isinstance(self.size,int):
while haze.size[0]<self.size or haze.size[1]<self.size :
index=random.randint(0,20000)
haze=Image.open(self.haze_imgs[index])
img=self.haze_imgs[index]
id=img.split('/')[-1].split('_')[0]
clear_name=id#+self.format
clear=Image.open(os.path.join(self.clear_dir,clear_name))
clear=tfs.CenterCrop(haze.size[::-1])(clear)
if not isinstance(self.size,str):
i,j,h,w=tfs.RandomCrop.get_params(haze,output_size=(self.size,self.size))
haze=FF.crop(haze,i,j,h,w)
clear=FF.crop(clear,i,j,h,w)
haze,clear=self.augData(haze.convert("RGB") ,clear.convert("RGB") )
return haze,clear
def augData(self,data,target):
if self.train:
rand_hor=random.randint(0,1)
rand_rot=random.randint(0,3)
data=tfs.RandomHorizontalFlip(rand_hor)(data)
target=tfs.RandomHorizontalFlip(rand_hor)(target)
if rand_rot:
data=FF.rotate(data,90*rand_rot)
target=FF.rotate(target,90*rand_rot)
data=tfs.ToTensor()(data)
data=tfs.Normalize(mean=[0.64, 0.6, 0.58],std=[0.14,0.15, 0.152])(data)
target=tfs.ToTensor()(target)
return data ,target
def __len__(self):
return len(self.haze_imgs)
import os
pwd=os.getcwd()
print(pwd)
path='../../data'#path to your 'data' folder
ITS_train_loader=DataLoader(dataset=RESIDE_Dataset(path+'/train',train=True,size=crop_size),batch_size=BS,shuffle=True)
ITS_test_loader=DataLoader(dataset=RESIDE_Dataset(path+'/val',train=False,size='whole img'),batch_size=1,shuffle=False)
OTS_train_loader=DataLoader(dataset=RESIDE_Dataset(path+'/train',train=True,format='.jpg'),batch_size=BS,shuffle=True)
OTS_test_loader=DataLoader(dataset=RESIDE_Dataset(path+'/val',train=False,size='whole img',format='.jpg'),batch_size=1,shuffle=False)
if __name__ == "__main__":
pass
In [10]:
%%writefile ./FFA-Net/net/main.py
import torch,os,sys,torchvision,argparse
import torchvision.transforms as tfs
from metrics import psnr,ssim
from models import *
import time,math
import numpy as np
from torch.backends import cudnn
from torch import optim
import torch,warnings
from torch import nn
#from tensorboardX import SummaryWriter
import torchvision.utils as vutils
warnings.filterwarnings('ignore')
from option import opt,model_name,log_dir
from data_utils import *
from torchvision.models import vgg16
print('log_dir :',log_dir)
print('model_name:',model_name)
models_={
'ffa':FFA(gps=opt.gps,blocks=opt.blocks),
}
loaders_={
'its_train':ITS_train_loader,
'its_test':ITS_test_loader,
'ots_train':OTS_train_loader,
'ots_test':OTS_test_loader
}
start_time=time.time()
T=opt.steps
def lr_schedule_cosdecay(t,T,init_lr=opt.lr):
lr=0.5*(1+math.cos(t*math.pi/T))*init_lr
return lr
def train(net,loader_train,loader_test,optim,criterion):
losses=[]
start_step=0
max_ssim=0
max_psnr=0
ssims=[]
psnrs=[]
if opt.resume and os.path.exists(opt.model_dir):
print(f'resume from {opt.model_dir}')
ckp=torch.load(opt.model_dir)
losses=ckp['losses']
net.load_state_dict(ckp['model'])
start_step=ckp['step']
max_ssim=ckp['max_ssim']
max_psnr=ckp['max_psnr']
psnrs=ckp['psnrs']
ssims=ckp['ssims']
with torch.no_grad():
max_ssim,max_psnr=test(net,loader_test, max_psnr,max_ssim,start_step)
print(f'start_step:{start_step} start training --- max_ssim: {max_ssim:.4f} max_psnr: {max_psnr:.4f}')
else :
print('train from scratch *** ')
for step in range(start_step+1,opt.steps+1):
net.train()
lr=opt.lr
if not opt.no_lr_sche:
lr=lr_schedule_cosdecay(step,T)
for param_group in optim.param_groups:
param_group["lr"] = lr
x,y=next(iter(loader_train))
x=x.to(opt.device);y=y.to(opt.device)
out=net(x)
loss=criterion[0](out,y)
if opt.perloss:
loss2=criterion[1](out,y)
loss=loss+0.04*loss2
loss.backward()
optim.step()
optim.zero_grad()
losses.append(loss.item())
print(f'\rtrain loss : {loss.item():.5f}| step :{step}/{opt.steps}|lr :{lr :.7f} |time_used :{(time.time()-start_time)/60 :.1f}',end='',flush=True)
#with SummaryWriter(logdir=log_dir,comment=log_dir) as writer:
# writer.add_scalar('data/loss',loss,step)
if step % opt.eval_step ==0 :
with torch.no_grad():
ssim_eval,psnr_eval=test(net,loader_test, max_psnr,max_ssim,step)
print(f'\nstep :{step} |ssim:{ssim_eval:.4f}| psnr:{psnr_eval:.4f}')
# with SummaryWriter(logdir=log_dir,comment=log_dir) as writer:
# writer.add_scalar('data/ssim',ssim_eval,step)
# writer.add_scalar('data/psnr',psnr_eval,step)
# writer.add_scalars('group',{
# 'ssim':ssim_eval,
# 'psnr':psnr_eval,
# 'loss':loss
# },step)
ssims.append(ssim_eval)
psnrs.append(psnr_eval)
if ssim_eval > max_ssim and psnr_eval > max_psnr :
max_ssim=max(max_ssim,ssim_eval)
max_psnr=max(max_psnr,psnr_eval)
torch.save({
'step':step,
'max_psnr':max_psnr,
'max_ssim':max_ssim,
'ssims':ssims,
'psnrs':psnrs,
'losses':losses,
'model':net.state_dict()
},opt.model_dir)
print(f'\n model saved at step :{step}| max_psnr:{max_psnr:.4f}|max_ssim:{max_ssim:.4f}')
np.save(f'./numpy_files/{model_name}_{opt.steps}_losses.npy',losses)
np.save(f'./numpy_files/{model_name}_{opt.steps}_ssims.npy',ssims)
np.save(f'./numpy_files/{model_name}_{opt.steps}_psnrs.npy',psnrs)
def test(net,loader_test,max_psnr,max_ssim,step):
net.eval()
torch.cuda.empty_cache()
ssims=[]
psnrs=[]
#s=True
for i ,(inputs,targets) in enumerate(loader_test):
inputs=inputs.to(opt.device);targets=targets.to(opt.device)
pred=net(inputs)
# # print(pred)
# tfs.ToPILImage()(torch.squeeze(targets.cpu())).save('111.png')
# vutils.save_image(targets.cpu(),'target.png')
# vutils.save_image(pred.cpu(),'pred.png')
ssim1=ssim(pred,targets).item()
psnr1=psnr(pred,targets)
ssims.append(ssim1)
psnrs.append(psnr1)
#if (psnr1>max_psnr or ssim1 > max_ssim) and s :
# ts=vutils.make_grid([torch.squeeze(inputs.cpu()),torch.squeeze(targets.cpu()),torch.squeeze(pred.clamp(0,1).cpu())])
# vutils.save_image(ts,f'samples/{model_name}/{step}_{psnr1:.4}_{ssim1:.4}.png')
# s=False
return np.mean(ssims) ,np.mean(psnrs)
if __name__ == "__main__":
loader_train=loaders_[opt.trainset]
loader_test=loaders_[opt.testset]
net=models_[opt.net]
net=net.to(opt.device)
if opt.device=='cuda':
net=torch.nn.DataParallel(net)
cudnn.benchmark=True
criterion = []
criterion.append(nn.L1Loss().to(opt.device))
if opt.perloss:
vgg_model = vgg16(pretrained=True).features[:16]
vgg_model = vgg_model.to(opt.device)
for param in vgg_model.parameters():
param.requires_grad = False
criterion.append(PerLoss(vgg_model).to(opt.device))
optimizer = optim.Adam(params=filter(lambda x: x.requires_grad, net.parameters()),lr=opt.lr, betas = (0.9, 0.999), eps=1e-08)
optimizer.zero_grad()
train(net,loader_train,loader_test,optimizer,criterion)
In [11]:
%%writefile ./FFA-Net/net/test.py
import os,argparse
import numpy as np
from PIL import Image
from models import *
import torch
import torch.nn as nn
import torchvision.transforms as tfs
import torchvision.utils as vutils
import matplotlib.pyplot as plt
from torchvision.utils import make_grid
abs=os.getcwd()+'/'
def tensorShow(tensors,titles=['smoke']):
fig=plt.figure()
for tensor,tit,i in zip(tensors,titles,range(len(tensors))):
img = make_grid(tensor)
npimg = img.numpy()
ax = fig.add_subplot(221+i)
ax.imshow(np.transpose(npimg, (1, 2, 0)))
ax.set_title(tit)
plt.show()
parser=argparse.ArgumentParser()
parser.add_argument('--task',type=str,default='its',help='its or ots')
parser.add_argument('--test_imgs',type=str,default='test_imgs',help='Test imgs folder')
opt=parser.parse_args()
dataset=opt.task
gps=3
blocks=19
img_dir=abs+opt.test_imgs+'/'
output_dir=abs+f'clear/'
print("pred_dir:",output_dir)
if not os.path.exists(output_dir):
os.mkdir(output_dir)
model_dir=abs+f'trained_models/{dataset}_train_ffa_{gps}_{blocks}.pk'
device='cuda' if torch.cuda.is_available() else 'cpu'
ckp=torch.load(model_dir,map_location=device)
net=FFA(gps=gps,blocks=blocks)
net=nn.DataParallel(net)
net.load_state_dict(ckp['model'])
net.eval()
for im in os.listdir(img_dir):
print(f'\r {im}',end='',flush=True)
haze = Image.open(img_dir+im)
haze1= tfs.Compose([
tfs.ToTensor(),
tfs.Normalize(mean=[0.64, 0.6, 0.58],std=[0.14,0.15, 0.152])
])(haze)[None,::]
haze_no=tfs.ToTensor()(haze)[None,::]
with torch.no_grad():
pred = net(haze1)
ts=torch.squeeze(pred.clamp(0,1).cpu())
#tensorShow([haze_no,pred.clamp(0,1).cpu()],['smoke','pred'])
vutils.save_image(ts,output_dir+im.split('.')[0]+'.jpg')
Change the Working Directory¶
In [12]:
%cd ./FFA-Net/net
Finetune the model for custom dataset¶
Finetune ITS Pretrained Model¶
In [13]:
!python main.py --net='ffa' --blocks=19 --gps=3 --bs=2 --lr=0.0001 --trainset='its_train' --testset='its_test' --steps=500000 --eval_step=5000
FineTune OTS pretrained Model¶
In [14]:
#!python main.py --net='ffa' --crop --crop_size=240 --blocks=19 --gps=3 --bs=2 --lr=0.0001 --trainset='ots_train' --testset='ots_test' --steps=1000000 --eval_step=5000
Test the Model¶
In [15]:
!python test.py --task='its' --test_imgs='../../data/test/smoke'
#!python test.py --task='ots' --test_imgs='../../data/test/smoke'
In [15]:
Visualize the data¶
In [16]:
import matplotlib.pyplot as plt
img = plt.imread("clear/927.jpg")
plt.imshow(img)
Save the prediction to zip¶
In [ ]:
!zip submission.zip -r clear/ > /dev/null
Making direct submission thought aicrowd-cli¶
In [ ]:
!aicrowd submission create -c f1-smoke-elimination -f submission.zip
In [ ]:
Content
Comments
You must login before you can post a comment.