Deployed: https://floating-refuge-59093.herokuapp.com/
Look at bottom of this file for how i deployed to Heroku
Creation of IFO Dataset
Dataset Link: https://drive.google.com/file/d/1LXbEadbpuvTJVwj5thGrlMjYP9hzt6Wn/view?usp=sharing
PreProcess raw dataset: https://github.com/satyajitghana/TSAI-DeepVision-EVA4.0-Phase-2/blob/master/02-MobileNet/IFO_preprocess.ipynb
DatasetVisualization: https://github.com/satyajitghana/TSAI-DeepVision-EVA4.0-Phase-2/blob/master/02-MobileNet/01_IFODataset.ipynb
Misclassifications: https://github.com/satyajitghana/TSAI-DeepVision-EVA4.0-Phase-2/blob/master/02-MobileNet/03_Misclassifications.ipynb
class IFODataset(Dataset):
"""
Dataset generator for MobileNetV2 implementation on Identified
flying objects dataset
"""
class_names = ['Flying_Birds', 'Large_QuadCopters', 'Small_QuadCopters', 'Winged_Drones']
def __init__(self, root, source_zipfile, transform=None):
self.root = Path(root) / 'IFO'
self.root.mkdir(parents=True, exist_ok=True)
self.source_zipfile = Path(source_zipfile)
self.transform = transform
if os.path.isdir(self.root / 'IFOCleaned'):
print(f"dataset folder/files already exist in {self.root / 'IFOCleaned'}")
else:
self.extractall()
self.images_paths = sorted(list(Path(self.root / 'IFOCleaned').glob('*/*.jpg')))
self.targets = [self.class_names.index(image_path.parent.name) for image_path in self.images_paths]
print(f'found {len(self.images_paths)} images in total')
l = list(dataset.targets)
images_per_class = dict((dataset.class_names[x],l.count(x)) for x in set(l))
print(json.dumps(images_per_class, indent=4))
# split indices to train and test, use stratify to distribute equally
self.train_idxs, self.test_idxs = train_test_split(np.arange(len(self.images_paths)), test_size=0.3, shuffle=True, stratify=self.targets)
def extractall(self):
print('Extracting the dataset zip file')
zipf = ZipFile(self.source_zipfile, 'r')
zipf.extractall(self.root)
def split_dataset(self):
return Subset(self, indices=self.train_idxs), Subset(self, self.test_idxs)
def __len__(self):
return len(self.images_paths)
def __getitem__(self, index):
image_path = self.images_paths[index]
image = Image.open(image_path)
image = image.convert('RGB')
target = self.targets[index]
if self.transform:
image = self.transform(image)
return image, target
The dataset is a simple zip file with the classes in their individual folders, what’s interesting is how we transforms the images for training
Some dataset stats
{
"Flying_Birds": 8164,
"Large_QuadCopters": 4886,
"Small_QuadCopters": 3612,
"Winged_Drones": 5531
}
"mean = ['0.533459901809692', '0.584880530834198', '0.615305066108704']"
"std = ['0.172962218523026', '0.167985364794731', '0.184633478522301']"
train_transforms = A.Compose([
# A.VerticalFlip(), not useful, flying objects cannot be flipped vertically
A.HorizontalFlip(),
A.LongestMaxSize(max_size=500),
A.Normalize(mean=self.mean, std=self.std),
A.PadIfNeeded(min_height=500, min_width=500, border_mode=0, always_apply=True, value=self.mean),
A.Resize(height=224, width=224, always_apply=True),
A.Rotate(limit=30, border_mode=0, always_apply=False, value=self.mean),
A.Cutout(num_holes=2, max_h_size=48, max_w_size=48, p=0.9, fill_value=self.mean),
AT.ToTensor()
])
The Series of Transformations are
Horizontal Flip
LongestMaxSize
Normalize
PadIfNeeded
500x500Resize
224x244 image so we convert it to suchRotate
+-30 degrees to increase the test accuracyCutOut

Dataset

Augmented Dataset
BatchLoss-Train
EpochLoss-Test
EpochLoss-Train
EpochAccuracy-Train
EpochAccuracy-Test
{
'Flying_Birds': 18,
'Large_QuadCopters': 133,
'Small_QuadCopters': 748,
'Winged_Drones': 324
}

Classification Report
precision recall f1-score support
Flying_Birds 0.96 0.99 0.98 2449
Large_QuadCopters 0.58 0.91 0.71 1466
Small_QuadCopters 0.84 0.31 0.45 1084
Winged_Drones 0.94 0.80 0.87 1659
accuracy 0.82 6658
macro avg 0.83 0.75 0.75 6658
weighted avg 0.85 0.82 0.80 6658
Flying_Birds ... Winged_Drones
Flying_Birds 2431 ... 12
Large_QuadCopters 29 ... 50
Small_QuadCopters 12 ... 24
Winged_Drones 59 ... 1335
[4 rows x 4 columns]
Confusion Matrix

Refer to ifo-app for source code
Install streamlit
pip install streamlit
Now after wrting app.py simply run streamlit run app.py, check if everything works
Cool, Now let’s Deploy!
Make sure your requirements.txt uses these version of torch and torchvision, there are for cpu and python3.6 which heroku uses
requirements.txt
https://download.pytorch.org/whl/cpu/torch-1.6.0%2Bcpu-cp36-cp36m-linux_x86_64.whl
https://download.pytorch.org/whl/cpu/torchvision-0.7.0%2Bcpu-cp36-cp36m-linux_x86_64.whl
You can find pytorch releases here: https://download.pytorch.org/whl/torch_stable.html
now Procfile
web: sh setup.sh && streamlit run app.py
Initialize a empty git repo
git init
git add .
git commit -m "initial build"
Now create a heroku project and push to it !
heroku create
git push heroku master
NOTE: you can also connect your github repo to heroku and it’ll build on push to github