Skip to content

Commit

Permalink
Changed the Waste-Segregator project file from a submodule to a folde…
Browse files Browse the repository at this point in the history
…r to allow people to commit easily (#6)
  • Loading branch information
Shorya1835 committed May 8, 2023
1 parent 54eb3e4 commit 229d0b3
Show file tree
Hide file tree
Showing 13 changed files with 7,398 additions and 1 deletion.
1 change: 0 additions & 1 deletion Waste-Segregator_shorya
Submodule Waste-Segregator_shorya deleted from ad55e2
3 changes: 3 additions & 0 deletions Waste-Segregator_shorya/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
data/
faster_rcnn_implementation/resized_data/
faster_rcnn_implementation/outputs/
65 changes: 65 additions & 0 deletions Waste-Segregator_shorya/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@

# Waste Segregator

### Project Description

The project uses object detection to detect waste in the wild, the model uses a pretrained faster rcnn resnet50 and is trained on the [taco dataset](http://tacodataset.org/).

### Prerequisites

You can install the libraries needed using
```
pip install -r requirements.txt
```
The python version used in the project is 3.10.11

### Installation

To clone the git repository use
```
git clone https://github.com/Shorya1835/Waste-Segregator.git
```


### Libraries Used

- Pytorch
- The model uses torch, torchvision for the model and torchmetrics to evaluate the model.
- Numpy
- For arrays
- Cv2 and matplotlib
- For visualization
- albumentaions
- For transforming the data
- glob
- To search for files
- Chitra and ppyboxes
- During data analysis for data conversion and plotting

### Usage

The model can detect waste in the wild and categorize it between 18 categories, which can be furhter mapped to recylable and organic, allowing effective waste segregation. The model has mAP of 6 percent, with highest 7 percent achieved.

![An example](https://i.imgur.com/axekldV.png)

### Structure

```
Faster_rcnn_implementation
├── config.py
├── custom_utils.py
├── datasets.py
├── image_distributor.ipynb
├── inference.py
├── model.py
├── outputs
│   ├── best_model.pth
│   ├── train_loss.png
│   └── valid_loss.png
├── resized_data
│   ├── annotations.json
│   ├── test
│   ├── train
│   └── validation
└── train.py
```
1,381 changes: 1,381 additions & 0 deletions Waste-Segregator_shorya/data_analysis.ipynb

Large diffs are not rendered by default.

32 changes: 32 additions & 0 deletions Waste-Segregator_shorya/faster_rcnn_implementation/config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import torch

#Hyperparameters
BATCH_SIZE=7
RESIZE_TO=(256,224)
NUM_EPOCHS=500
NUM_WORKERS=0

#Choosing between cpu or gpu
DEVICE=torch.device(('cuda') if torch.cuda.is_available() else torch.device('cpu'))

#Training images
TRAIN_DIR='resized_data/train'

#Validation images
VALID_DIR='resized_data/validation'

#classes: 0 index is reserved for background
CLASSES=[
'__background__','Aluminium foil', 'Bottle', 'Bottle cap', 'Broken glass', 'Can', 'Carton', 'Cup', 'Lid', 'Other plastic', 'Paper', 'Plastic bag & wrapper', 'Plastic container', 'Plastic utensils', 'Pop tab', 'Straw', 'Styrofoam piece','Cigarette','Others']

NUM_CLASSES=len(CLASSES)

# whether to visualize images after crearing the data loaders
VISUALIZE_TRANSFORMED_IMAGES = True

# location to save model and plots
OUT_DIR = 'outputs'




144 changes: 144 additions & 0 deletions Waste-Segregator_shorya/faster_rcnn_implementation/custom_utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
import albumentations as A
import cv2
import numpy as np
import torch
import matplotlib.pyplot as plt

from albumentations.pytorch import ToTensorV2
from config import DEVICE,CLASSES

plt.style.use('ggplot')


class Averager:
"""
This class keeps track of the training and validation loss values
and helps to get the average for each epoch as well.
"""
def __init__(self):
self.current_total = 0.0
self.iterations = 0.0

def send(self, value):
self.current_total += value
self.iterations += 1

@property
def value(self):
if self.iterations == 0:
return 0
else:
return 1.0 * self.current_total / self.iterations

def reset(self):
self.current_total = 0.0
self.iterations = 0.0

class SaveBestModel:
"""
Class to save the best model while training. If the current epoch's
validation loss is less than the previous least less, then save the
model state.
"""
def __init__(
self, best_valid_loss=float('inf')
):
self.best_valid_loss = best_valid_loss

def __call__(
self, current_valid_loss,
epoch, model, optimizer
):
if current_valid_loss < self.best_valid_loss:
self.best_valid_loss = current_valid_loss
print(f"\nBest validation loss: {self.best_valid_loss}")
print(f"\nSaving best model for epoch: {epoch+1}\n")
torch.save({
'epoch': epoch+1,
'model_state_dict': model.state_dict(),
'optimizer_state_dict': optimizer.state_dict(),
}, 'outputs/best_model.pth')

def collate_fn(batch):
"""
To handle the data loading as different images may have different number
of objects and to handle varying size tensors as well.
"""
return tuple(zip(*batch))

#Define the training tranforms
def get_train_transform():
return A.Compose([
A.Flip(0.5),
A.RandomRotate90(0.5),
A.MotionBlur(p=0.2),
A.MedianBlur(blur_limit=3, p=0.1),
A.Blur(blur_limit=3, p=0.1),
ToTensorV2(p=1.0),
], bbox_params={
'format': 'pascal_voc',
'label_fields': ['labels']
})

# define the validation transforms
def get_valid_transform():
return A.Compose([
ToTensorV2(p=1.0),
], bbox_params={
'format': 'pascal_voc',
'label_fields': ['labels']
})

def show_tranformed_image(train_loader):
"""
This function shows the transformed images from the `train_loader`.
Helps to check whether the tranformed images along with the corresponding
labels are correct or not.
Only runs if `VISUALIZE_TRANSFORMED_IMAGES = True` in config.py.
"""
if len(train_loader) > 0:
for i in range(1):
images, targets = next(iter(train_loader))
images = list(image.to(DEVICE) for image in images)
targets = [{k: v.to(DEVICE) for k, v in t.items()} for t in targets]
boxes = targets[i]['boxes'].cpu().numpy().astype(np.int32)
labels = targets[i]['labels'].cpu().numpy().astype(np.int32)
sample = images[i].permute(1, 2, 0).cpu().numpy()
for box_num, box in enumerate(boxes):
cv2.rectangle(sample,
(box[0], box[1]),
(box[2], box[3]),
(0, 0, 255), 2)
cv2.putText(sample, CLASSES[labels[box_num]],
(box[0], box[1]-10), cv2.FONT_HERSHEY_SIMPLEX,
1.0, (0, 0, 255), 2)
cv2.imshow('Transformed image', sample)
cv2.waitKey(0)
cv2.destroyAllWindows()

def save_model(epoch, model, optimizer):
"""
Function to save the trained model till current epoch, or whenver called
"""
torch.save({
'epoch': epoch+1,
'model_state_dict': model.state_dict(),
'optimizer_state_dict': optimizer.state_dict(),
}, 'outputs/last_model.pth')


def save_loss_plot(OUT_DIR, train_loss, val_loss):
figure_1, train_ax = plt.subplots()
figure_2, valid_ax = plt.subplots()
train_ax.plot(train_loss, color='tab:blue')
train_ax.set_xlabel('iterations')
train_ax.set_ylabel('train loss')
valid_ax.plot(val_loss, color='tab:red')
valid_ax.set_xlabel('iterations')
valid_ax.set_ylabel('validation loss')
figure_1.savefig(f"{OUT_DIR}/train_loss.png")
figure_2.savefig(f"{OUT_DIR}/valid_loss.png")
print('SAVING PLOTS COMPLETE...')
plt.close('all')


Loading

0 comments on commit 229d0b3

Please sign in to comment.