Skip to content
Snippets Groups Projects
Commit e2d85467 authored by gaurav_singhal's avatar gaurav_singhal
Browse files

Open-sourcing the code

parent 809a6ee0
No related branches found
No related tags found
No related merge requests found
.DS_Store 0 → 100644
File added
*.pth filter=lfs diff=lfs merge=lfs -text
ARG PYTORCH="1.6.0"
ARG CUDA="10.1"
ARG CUDNN="7"
FROM pytorch/pytorch:${PYTORCH}-cuda${CUDA}-cudnn${CUDNN}-devel
ENV TORCH_CUDA_ARCH_LIST="6.0 6.1 7.0+PTX"
ENV TORCH_NVCC_FLAGS="-Xfatbin -compress-all"
ENV CMAKE_PREFIX_PATH="$(dirname $(which conda))/../"
RUN apt-get update && apt-get install -y ffmpeg libsm6 libxext6 git ninja-build libglib2.0-0 libsm6 libxrender-dev libxext6 \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update && apt-get install -y \
build-essential \
bzip2 \
cmake \
curl \
git \
g++ \
libboost-all-dev \
pkg-config \
rsync \
software-properties-common \
sudo \
tar \
timidity \
unzip \
wget \
locales \
zlib1g-dev \
python3-dev \
python3 \
python3-pip \
python3-tk \
libjpeg-dev \
libpng-dev \
libgl1-mesa-glx
# Install MMCV
RUN pip install mmcv-full==latest+torch1.6.0+cu101 -f https://openmmlab.oss-accelerate.aliyuncs.com/mmcv/dist/index.html
# Install MMDetection
RUN conda clean --all
RUN git clone https://github.com/open-mmlab/mmdetection.git mmdetection
WORKDIR mmdetection
ENV FORCE_CUDA="1"
RUN pip install -r requirements/build.txt
RUN pip install --no-cache-dir -e .
# Python3
RUN pip install pip --upgrade
RUN pip install cython aicrowd_api timeout_decorator \
numpy \
pandas \
aicrowd-repo2docker \
pillow
RUN pip install albumentations==0.5.1
RUN conda install cython -y && conda clean --all
RUN python3.6 -m pip install aicrowd_api aicrowd-repo2docker
# Unicode support:
RUN locale-gen en_US.UTF-8
ENV LANG en_US.UTF-8
ENV LANGUAGE en_US:en
ENV LC_ALL en_US.UTF-8
# Enables X11 sharing and creates user home directory
ENV USER_NAME aicrowd
ENV HOME_DIR /home/$USER_NAME
#
# Replace HOST_UID/HOST_GUID with your user / group id (needed for X11)
ENV HOST_UID 1000
ENV HOST_GID 1000
RUN export uid=${HOST_UID} gid=${HOST_GID} && \
mkdir -p ${HOME_DIR} && \
echo "$USER_NAME:x:${uid}:${gid}:$USER_NAME,,,:$HOME_DIR:/bin/bash" >> /etc/passwd && \
echo "$USER_NAME:x:${uid}:" >> /etc/group && \
echo "$USER_NAME ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers.d/$USER_NAME && \
chmod 0440 /etc/sudoers.d/$USER_NAME && \
chown ${uid}:${gid} -R ${HOME_DIR}
USER ${USER_NAME}
WORKDIR ${HOME_DIR}
COPY --chown=1000:1000 . .
# COPY . .
# RUN sudo chown ${HOST_UID}:${HOST_GID} -R *
# RUN sudo chmod 775 -R *
README.md 0 → 100644
# <center>Food Recognition Challenge - Starter Kit</center>
![Food-Challenge](https://i.imgur.com/0G3PEc7.png)
<p align="center">
<a href="https://discord.gg/GTckBMx"><img src="https://img.shields.io/discord/657211973435392011?style=for-the-badge" alt="chat on Discord"></a>
</p>
# Table of contents
- [💪 Getting Started](#-getting-started)
* [Using this repository](#using-this-repository)
* [Using colab starter kit](#using-colab-starter-kit)
* [Running the code locally](#running-the-code-locally)
- [🧩 Repository structure](#-repository-structure)
* [Required files](#required-files)
* [Other files](#other-files)
- [🚀 Submission](#-submission)
* [Prepare your environment](#prepare-your-environment)
+ [`Dockerfile`](#dockerfile)
+ [`apt.txt`](#apttxt)
+ [`requirements.txt`](#requirementstxt)
* [Initial setup](#initial-setup)
* [Submit to AIcrowd](#submit-to-aicrowd)
- [🛠 Troubleshooting](#-troubleshooting)
* [My submission failed. How do I know what happened?](#my-submission-failed-how-do-i-know-what-happened)
* [My docker builds fail. Can I reproduce this locally?](#my-docker-builds-fail-can-i-reproduce-this-locally)
- [📎 Important links](#-important-links)
- [✍️ Author](#-author)
* [✨ Contributors](#-contributors)
# 💪 Getting Started
The dataset for this challenge is available on the [challenge's resources page](https://www.aicrowd.com/challenges/food-recognition-challenge/dataset_files).
## Using this repository
This repository contains the code for a random agent. To run the code locally,
- Clone the repository
- Install dependencies
- Execute `run.sh`
Clone the repository
```bash
git clone https://github.com/AIcrowd/food-recognition-challenge-starter-kit
cd food-recognition-challenge-starter-kit
```
Install dependencies
```bash
pip install -r requirements.txt
```
Update the value for `AICROWD_TEST_IMAGES_PATH` to point to your validation dataset
and run `debug.sh`
```bash
./debug.sh
```
During the evaluation, we will execute `run.sh`. You can add any additional commands
as per your needs.
## Using colab starter kit
We prepared a colab notebook that uses `detectron2`. You can train your agent and make
a submission from your notebook!
[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/drive/1F2IbqpI0ecbRDCNiBLPFCCOVEK0cgbH7?usp=sharing)
## Running the code locally
- First, make sure that you have the dataset downloaded.
- Update the value of `AICROWD_TEST_IMAGES_PATH` in `debug.sh` file to point to your dataset
- Execute `debug.sh`
```bash
./debug.sh
```
This will generate `predictions.json` file in your current directory.
# 🧩 Repository structure
## Required files
**File** | **Description**
--- | ---
`Dockerfile` | Configuration file to build docker images used during evaluation
`aicrowd.json` | A configuration file used to identify the challenge and resources needed for evaluation
`aicrowd_helpers.py`<sup>#</sup> | Helpers file used to relay evaluation progress
`apt.txt` | List of packages that should be installed (via `apt`) for your code to run
`requirements.txt` | List of python packages that should be installed (via `pip`) for your code to run
`run.sh` | Entry point to your code
<sup>#</sup> Do not edit these files.
## Other files
**File** | **Description**
--- | ---
`run.py` | Python script to generate random predictions
`debug.sh` | Helps your run your code locally
`utils/` | Directory containing some useful scripts and notebooks
`utils/requirements_detectron2.txt` | A sample `requirements.txt` file for using `detectron2`
`utils/requirements_mmdetection.txt` | A sample `requirements.txt` file for using `mmdetection`
# 🚀 Submission
## Prepare your environment
There are three files that help you setup your environment.
1. `Dockerfile`
2. `apt.txt`
3. `requirements.txt`
### `Dockerfile`
If you plan to use GPU, please make sure that you are using an appropriate `CUDA` and
`CUDNN` versions. You can specify these at the top of your [`Docerfile`](Dockerfile#L1).
### `apt.txt`
If there are certain system level packages that you need, you can specify them in your
`apt.txt`. If you are familiar with ubuntu/debian, this is same as installing these
packages using `apt-get install` command.
### `requirements.txt`
You can specify the list of python packages that need to be installed in your
`requirements.txt`.
Please note that we are using `apt.txt` and `requirements.txt` in the `Dockerfile` to
install required packages. We believe that this makes it easier for you to add the
required packages without much hassle. If you are comfortable with docker, you are
free to edit the `Dockerfile` as needed.
## Initial setup
Before you submit to AIcrowd, you need to setup SSH access to our GitLab instance.
This is a one-time requirement to setup your repository.
This process involves
1. Cloning the repository
2. Replace git origin to point to your personal repository
3. Setup SSH key
To clone the repository, please refer getting started section.
Now, you need to point the repository to your personal repository on AIcrowd GitLab.
```bash
git remote set-url origin git@gitlab.aicrowd.com:<your-aicrowd-username>/food-recognition-challenge-starter-kit.git
```
To be able to push your code to GitLab, you should setup SSH keys first. Please
follow the instructions at
[https://discourse.aicrowd.com/t/how-to-add-ssh-key-to-gitlab/2603](https://discourse.aicrowd.com/t/how-to-add-ssh-key-to-gitlab/2603)
## Submit to AIcrowd
To submit to AIcrowd, you need to push a tag starting with `submission-` to GitLab.
Add the changes to git.
```bash
git add --all
git commit -m "<brief summary of changes>"
```
You need to add large files via `git-lfs`.
```bash
git lfs install
# Add all the files larger than 5 MB to LFS
find . -type f -size +5M -exec git lfs migrate import --include={} &> /dev/null \;
```
For more information on using LFS, please refer
[uploading large files to GitLab](https://discourse.aicrowd.com/t/how-to-upload-large-files-size-to-your-submission/2304).
Create and push the tag
```bash
# You can replace "-initial-version" with something that describes your submission
git tag -am "submission-initial-version" "submission-initial-version"
git lfs push origin master
git push origin master
git push origin submission-initial-version
```
# 🛠 Troubleshooting
## My submission failed. How do I know what happened?
If you make a submission in `debug` mode, we provide the outputs from your code on the
GitLab issue page corresponding to your submission. To make a submission in `debug`
mode, you need to add `"debug": true` in your `aicrowd.json`. Please note that the
debug mode submission will not be considered for leaderboard.
## My docker builds fail. Can I reproduce this locally?
You can build the images locally by running the following
```bash
docker build .
```
# 📎 Important links
- 💪 &nbsp;Challenge Page: https://www.aicrowd.com/challenges/food-recognition-challenge
- 🗣️ &nbsp;Discussion Forum: https://www.aicrowd.com/challenges/food-recognition-challenge/discussion
- 🏆 &nbsp;Leaderboard: https://www.aicrowd.com/challenges/food-recognition-challenge/leaderboards
- Resources - Round 1
* [Colab Notebook for Data Analysis and Tutorial](https://colab.research.google.com/drive/1A5p9GX5X3n6OMtLjfhnH6Oeq13tWNtFO#scrollTo=ok54AWT_VoWV)
* [Baseline with `mmdetection` (pytorch)](https://gitlab.aicrowd.com/nikhil_rayaprolu/food-pytorch-baseline)
* [Baseline with `matterport-maskrcnn` (keras - tensorflow)](https://gitlab.aicrowd.com/nikhil_rayaprolu/food-recognition)
- Resources - Round 2
* [Colab Notebook for Data Analysis and Tutorial](https://colab.research.google.com/drive/1vXdv9quZ7CXO5lLCjhyz3jtejRzDq221)
* [Baseline with `mmdetection` (pytorch)](https://gitlab.aicrowd.com/nikhil_rayaprolu/food-round2)
- Resources - Round 3
* [Colab Notebook for data exploration](https://discourse.aicrowd.com/t/detectron2-colab-notebook-from-data-exploration-to-training-the-model/3691)
- [Participant contributions](https://discourse.aicrowd.com/tags/c/food-recognition-challenge/112/explainer)
- External resources:
* [Convert Annotations from MS COCO format to PascalVOC format](https://github.com/CasiaFan/Dataset_to_VOC_converter/blob/master/anno_coco2voc.py)
# ✍️ Author
**[Sharada Mohanty](https://twitter.com/memohanty?lang=en)**
## ✨ Contributors
* [Nikhil Rayaprolu](https://github.com/nikhilrayaprolu)
* [Pulkit Gera](https://github.com/darthgera123)
* [Shivam Khandelwal](https://twitter.com/skbly7?lang=en)
* [Jyotish P](https://github.com/jyotishp)
\ No newline at end of file
{
"challenge_id" : "aicrowd-food-recognition-challenge",
"grader_id": "aicrowd-food-recognition-challenge",
"authors" : ["gaurav_singhal"],
"description" : "Food Recognition Challenge Submission",
"license" : "MIT",
"gpu": true,
"debug": false
}
\ No newline at end of file
#!/usr/bin/env python
import aicrowd_api
import os
########################################################################
# Instatiate Event Notifier
########################################################################
aicrowd_events = aicrowd_api.events.AIcrowdEvents()
def execution_start():
########################################################################
# Register Evaluation Start event
########################################################################
aicrowd_events.register_event(
event_type=aicrowd_events.AICROWD_EVENT_INFO,
message="execution_started",
payload={ # Arbitrary Payload
"event_type": "food_recognition_challenge:execution_started"
},
)
def execution_progress(progress_payload):
image_ids = progress_payload["image_ids"]
########################################################################
# Register Evaluation Progress event
########################################################################
aicrowd_events.register_event(
event_type=aicrowd_events.AICROWD_EVENT_INFO,
message="execution_progress",
payload={ # Arbitrary Payload
"event_type": "food_recognition_challenge:execution_progress",
"image_ids": image_ids,
},
)
def execution_success(payload):
predictions_output_path = payload["predictions_output_path"]
########################################################################
# Register Evaluation Complete event
########################################################################
expected_output_path = os.getenv("AICROWD_PREDICTIONS_OUTPUT_PATH", False)
if expected_output_path != predictions_output_path:
raise Exception(
"Please write the output to the path specified in the environment variable : AICROWD_PREDICTIONS_OUTPUT_PATH instead of {}".format(
predictions_output_path
)
)
aicrowd_events.register_event(
event_type=aicrowd_events.AICROWD_EVENT_SUCCESS,
message="execution_success",
payload={ # Arbitrary Payload
"event_type": "food_recognition_challenge:execution_success",
"predictions_output_path": predictions_output_path,
},
blocking=True,
)
def execution_error(error):
########################################################################
# Register Evaluation Complete event
########################################################################
aicrowd_events.register_event(
event_type=aicrowd_events.AICROWD_EVENT_ERROR,
message="execution_error",
payload={ # Arbitrary Payload
"event_type": "food_recognition_challenge:execution_error",
"error": error,
},
blocking=True,
)
wget
ca-certificates
g++
libjpeg-dev
libpng-dev
zlib1g-dev
libgl1-mesa-glx
libglib2.0-0
git
import pandas as pd
import numpy as np
import json
with open("prob_matrix.json") as f:
d = json.loads(f.read())
df_csr = pd.read_json(d)
df_csr.index = df_csr.index.astype(int)
df_csr.columns = df_csr.columns.astype(int)
def get_prior_prob(A):
'''
P(A) = num_images(A)/total_images
'''
total_images = 24093
return df_csr.loc[A].sum()/total_images
def get_posterior(A, events):
'''
Get posterior probability of category. P(A/events). Expects co-occurence dataframe
'''
numerator = np.prod(
(
df_csr.loc[A, [j for j in events]] / \
df_csr.loc[[j for j in events]].sum(axis=1)
).to_list()
) * get_prior_prob(A)
denominator = np.prod([get_prior_prob(j) for j in events])
if (numerator/denominator) > 0.99:
#print("{}, {}, {}".format(numerator, denominator, numerator/denominator))
# Something bad
return 0.99
return numerator/denominator
def posterior_util(cats):
'''
Get Posterior probability of all the categories
@input
cats -> List of category ids
'''
probs = []
for i in range(len(cats)):
events = cats[:i]+cats[i+1:]
probs.append(get_posterior(cats[i], events))
return probs
\ No newline at end of file
#!/bin/bash
docker build -t $IMAGE_NAME .
\ No newline at end of file
This diff is collapsed.
{"keep":{"2578":"drs","1198":"drs","2099":"drs","2530":"htc","1026":"drs","1505":"htc","1731":"drs","1538":"htc","1022":"htc","2620":"drs","1074":"drs","1533":"drs","1084":"drs","2730":"htc","1210":"drs","1308":"drs","1156":"htc","1108":"drs","1143":"drs","2413":"drs","2512":"drs","2836":"drs","1482":"drs","3080":"drs","1013":"htc","1942":"drs","2952":"drs","1214":"drs","1889":"drs","2729":"drs","1065":"drs","2742":"drs","2841":"htc","387":"htc","1483":"drs","2973":"htc","1789":"drs","1228":"drs","2501":"drs","1788":"drs","6404":"drs","2237":"htc","1138":"drs","2923":"htc","1967":"drs","1038":"drs","2524":"drs","1607":"drs","2736":"drs","1144":"drs","1119":"drs","1004":"drs","2711":"drs","2498":"drs","1050":"htc","2073":"drs","1321":"drs","2930":"drs","2454":"htc","1614":"drs","1727":"drs","1383":"htc","1070":"htc","1919":"drs","1561":"htc","1948":"drs","2446":"htc","1568":"drs","1280":"htc","2905":"drs","1730":"drs","1186":"htc","2495":"drs","1620":"htc","2743":"drs","1748":"htc","1924":"htc","3262":"drs","1856":"drs","2967":"drs","1223":"drs","1328":"drs","1463":"drs","2320":"drs","1199":"drs","1075":"drs","1153":"drs","1163":"drs","1123":"htc","1157":"drs","2053":"drs","1554":"htc","2521":"drs","1311":"drs","1078":"drs","1453":"htc","2504":"drs","1565":"drs","1853":"drs","1310":"drs","2747":"drs","1009":"drs","1490":"drs","2131":"drs","1588":"htc","1082":"htc","1032":"drs","1150":"drs","1587":"drs","1560":"drs","1831":"drs","1670":"drs","1098":"htc","1007":"drs","1956":"drs","2939":"drs","2303":"drs","1469":"drs","1033":"drs","1496":"htc","732":"drs","1061":"drs","1728":"drs","1068":"drs","1478":"drs","1569":"drs","1327":"drs","1980":"drs","1014":"htc","1094":"htc","1221":"htc","1056":"drs","630":"drs","2970":"drs","1107":"drs","1915":"drs","1102":"drs","2961":"drs","3220":"drs","1113":"htc","1166":"htc","3115":"drs","1557":"drs","1916":"drs","3630":"htc","2376":"htc","1794":"drs","2741":"htc","2954":"htc","3332":"htc","1793":"drs","2269":"drs","2580":"drs","2873":"drs","1547":"drs","1019":"drs","1724":"htc","2172":"drs","2470":"drs","1184":"htc","3306":"htc","2949":"drs","1402":"htc","2555":"htc","2254":"drs","1162":"htc","2362":"htc","1264":"htc","2543":"drs","1494":"htc","1209":"htc","1215":"htc","1089":"htc","1376":"htc","1249":"htc","2616":"drs","1124":"drs","2022":"drs","1566":"drs","1151":"htc","2534":"drs","2738":"htc","1116":"drs","1040":"drs","1154":"drs","2895":"drs","1300":"htc","1893":"drs","1069":"htc","2618":"drs","1058":"drs","1180":"htc","2944":"drs","1384":"htc","1126":"drs","1468":"htc","2350":"drs","633":"drs","2934":"drs","1203":"drs","1024":"htc","5641":"drs","2634":"htc","1060":"drs","1520":"drs","3358":"drs","3532":"drs","2562":"drs","1181":"drs","1536":"htc","1506":"htc","1352":"htc","2807":"drs","1545":"drs","1323":"drs","2750":"htc","1187":"htc","1348":"drs","1085":"drs","2734":"drs","1294":"htc","2728":"drs","1307":"drs","1627":"drs","3100":"htc","1879":"drs","2935":"drs","2898":"drs","50":"drs","1237":"drs","1551":"drs","1092":"drs","1229":"drs","1152":"drs","2103":"htc","1220":"drs","1170":"drs","1986":"drs","1213":"drs","1523":"htc","2920":"htc","3042":"htc","1487":"htc","1467":"drs","3249":"drs","2134":"htc","727":"htc","1556":"drs","1985":"htc","2132":"htc","2749":"drs","3308":"drs","1200":"drs","1580":"drs","1055":"htc","2278":"drs","1371":"drs","1054":"htc","2964":"drs","1176":"drs","1191":"drs","1522":"htc","578":"drs","1190":"htc"}}
\ No newline at end of file
debug.sh 0 → 100755
#!/bin/bash
nvidia-docker run -it \
--net=host \
-v ${TEST_IMAGES_PATH}:/test_images \
-v /tmp:/tmp_host \
-e AICROWD_IS_GRADING=True \
-e AICROWD_TEST_IMAGES_PATH="/test_images" \
-e AICROWD_PREDICTIONS_OUTPUT_PATH="/tmp/output.json" \
$IMAGE_NAME \
/home/aicrowd/run.sh
\ No newline at end of file
infer.py 0 → 100644
import argparse
import glob
import json
import os
import sys
from merge_results import consolidate_results, write_data
import aicrowd_helpers
import mmcv
TEST_IMAGES_PATH = os.getenv("AICROWD_TEST_IMAGES_PATH")
OUT_FILE = os.getenv("AICROWD_PREDICTIONS_OUTPUT_PATH")
def filter_predictions(file_path, map_name):
# Load the predictions
with open(file_path) as f:
preds = json.loads(f.read())
# Load the classwise mAP
with open("classwise_map.json") as f:
d = json.loads(f.read())
class_map = d['keep']
new_predictions = []
for pred in preds:
cat_id = str(pred['category_id'])
# if (cat_id in class_map) and (class_map[cat_id]==map_name):
# new_predictions.append(pred)
if cat_id in class_map:
new_predictions.append(pred)
write_data(new_predictions, file_path)
def create_test_predictions():
annotations = {
'categories': list(),
'info': dict(),
'images': list()
}
all_images = f"{TEST_IMAGES_PATH}/*.jpg"
for item in glob.glob(all_images):
img = mmcv.imread(item)
annotations['images'].append({
"id": int(os.path.basename(item).split('.')[0]),
"file_name": os.path.basename(item),
'width': img.shape[1],
'height': img.shape[0]
})
classes = open("classes.json").read()
annotations.update({'categories': json.loads(classes)})
with open('test_predictions.json', 'w') as fout:
json.dump(annotations, fout)
if __name__ == '__main__':
# Create blank predictions for testing. Same as in predict_model.py
create_test_predictions()
aicrowd_helpers.execution_start()
parser = argparse.ArgumentParser(
description='MMDet test (and eval) a model')
parser.add_argument('--out_file', help='output result file')
args = parser.parse_args()
os.environ["IMAGE_COUNT"] = "0"
## Ensemble
output_files = []
from models import *
model_config = get_model()
for config in model_config:
script_descriptor = open("predict.py")
model_script = script_descriptor.read()
sys.argv = ["predict_model.py", "--config", config['config'], "--checkpoint", config['weights'] \
, "--eval-options", "--format-only", \
, "jsonfile_prefix=predictions", "--out_file", config['output_file']]
exec(model_script)
script_descriptor.close()
output_files.append(config['output_file'])
# # Filter-out predictions
# if "name" in config:
# filter_predictions(config['output_file'], config['name'])
# Consolidate the results
consolidate_results(output_files, 'test_predictions.json', args.out_file)
\ No newline at end of file
import json
import argparse
import os
import numpy as np
from pycocotools import mask as maskUtils
# For bayesian statistics
# import pandas as pd
# import bayes_postprocess as bayes
def calculate_iou(box1, box2):
'''
Calculate IoU of two bounding boxes.
@input
bb1 : dict{'x1', 'x2', 'y1', 'y2'}
bb2 : dict{'x1', 'x2', 'y1', 'y2'}
@output
IoU in float range[0, 1]
'''
bb1 = {
"x1": box1[0],
"y1": box1[1],
"x2": box1[0] + box1[2],
"y2": box1[1] + box1[3],
}
bb2 = {
"x1": box2[0],
"y1": box2[1],
"x2": box2[0] + box2[2],
"y2": box2[1] + box2[3],
}
# Get intersection coordinates
x_left = max(bb1['x1'], bb2['x1'])
y_top = max(bb1['y1'], bb2['y1'])
x_right = min(bb1['x2'], bb2['x2'])
y_bottom = min(bb1['y2'], bb2['y2'])
if x_right < x_left or y_bottom < y_top:
return 0.0
# Intersection of 2 boxes
intersection_area = (x_right - x_left + 1) * (y_bottom - y_top + 1)
# Calculate the areas of both AABBs
box1area = (bb1['x2'] - bb1['x1'] + 1) * (bb1['y2'] - bb1['y1'] + 1)
box2area = (bb2['x2'] - bb2['x1'] + 1) * (bb2['y2'] - bb2['y1'] + 1)
IoU = intersection_area / float(box1area + box2area - intersection_area)
return IoU
def uneBoundingBoxes(boxes_xmls, by_class=True, threshold=0.5):
boundingBoxes=[]
total_boxes=len(boxes_xmls)
while(total_boxes>0):
boxPrim=boxes_xmls[0]
listBox = []
listBox.append(boxPrim)
boxes_xmls_temp=boxes_xmls[1:]
boxes_xmls.remove(boxPrim)
for box in boxes_xmls_temp:
if by_class and boxPrim['category_id']==box['category_id']:
if calculate_iou(boxPrim['bbox'], box['bbox']) > threshold:
boxes_xmls.remove(box)
listBox.append(box)
elif not by_class and calculate_iou(boxPrim['bbox'], box['bbox']) > threshold:
boxes_xmls.remove(box)
listBox.append(box)
boundingBoxes.append(listBox)
total_boxes=len(boxes_xmls)
return boundingBoxes
def group_by_iou(all_predictions, data, by_class=True, threshold = 0.5):
iou_groups = dict()
for img in data['images']:
# All the predictions for an image
preds = [item for item in all_predictions if item['image_id'] == img['id']]
iou_groups[img['id']] = uneBoundingBoxes(preds, by_class, threshold)
return iou_groups
def load_file(file):
with open(file) as f:
data = json.loads(f.read())
return data
def merge_predictions(file_list, annotations):
# load the annotations
data = load_file(annotations)
# load all predictions into one big list
all_predictions = list()
for file_name in file_list:
all_predictions.extend(load_file(file_name))
return all_predictions, data
def group_predictions_by_cat(predictions, data):
'''
Group the predictions by image id and class
'''
grouped_preds = {item["id"]: {} for item in data['images']}
for pred in predictions:
if pred['image_id'] not in grouped_preds:
grouped_preds[pred['image_id']] = dict()
if pred['category_id'] not in grouped_preds[pred['image_id']]:
grouped_preds[pred['image_id']][pred['category_id']] = []
grouped_preds[pred['image_id']][pred['category_id']].append(pred)
return grouped_preds
def remove_redundant_predictions(grouped_preds):
'''
Remove the predictions which are redundant
'''
new_preds = list()
# loop through the images
for img_id, cat_preds in grouped_preds.items():
for cat_id, preds in cat_preds.items():
delete_items = set()
# if we have more than one prediction we will see how much they overlap
if len(preds) > 1:
for i, pred1 in enumerate(preds):
for j, pred2 in enumerate(preds):
if j > i:
overlap = calculate_iou(pred1['bbox'], pred2['bbox'])
# if the overlap is greater than 40 % we will reduce the score of the lower scoring one
if overlap > 0.4 and pred1['score'] > pred2['score']:
delete_items.add(j)
elif overlap > 0.4 and pred2['score'] > pred1['score']:
delete_items.add(i)
# delete the items with the lower scores
delete_items = sorted(delete_items)
delete_items.reverse()
for idx in delete_items:
del preds[idx]
new_preds.extend(preds)
return new_preds
def select_max_score(all_predictions, data, multi_model: bool = True):
'''
Group the results by IOU and class
'''
iou_groups = group_by_iou(all_predictions, data, by_class=True)
new_predictions = list()
for img_id, pred_groups in iou_groups.items():
for i, group in enumerate(pred_groups):
if multi_model:
group[0]['score'] *= 0.5
elif len(group) > 1:
# sort the predictions by descending score
group = sorted(group, key=lambda x: x['score'], reverse=True)
# append the highest score for each group to the new predictions
new_predictions.append(group[0])
# group the predictions by category
grouped_preds = group_predictions_by_cat(new_predictions, data)
# delete redundant predictions
if multi_model:
return remove_redundant_predictions(grouped_preds)
return new_predictions
def remove_duplicated_categories(predictions: list) -> list:
'''
Remove the predictions with duplicated categories and IOU > .2
'''
grouped_preds = group_predictions(predictions, "image_id")
new_predictions = list()
for img_id, img_preds in grouped_preds.items():
# Prediction for an image > 10
if len(img_preds) > 10:
# Group by category_id the predictions
cat_grouped_preds = group_predictions(img_preds, "category_id")
# loop over predicted categories
for cat_id, cat_preds in cat_grouped_preds.items():
# Group the predicted categories with a smaller IOU threshold
cat_groups = uneBoundingBoxes(cat_preds.copy(), threshold=0.5)
for i, group in enumerate(cat_groups):
group = sorted(group, key=lambda x: x['score'], reverse=True)
# Add the best score for each group to new predictions
new_predictions.append(group[0])
else:
new_predictions.extend(img_preds)
return new_predictions
def group_predictions(predictions, key) -> dict:
'''
Group predictions by key
@input
predictions -> List of predictions
key -> String by which predictions are to be grouped
@output
Group the predictions by the given key
'''
grouped_predictions = dict()
for pred in predictions:
if pred[key] not in grouped_predictions:
grouped_predictions[pred[key]] = list()
grouped_predictions[pred[key]].append(pred)
return grouped_predictions
def apply_bayesian_stats(new_preds, img_ids):
df_new_preds = pd.DataFrame(new_preds)
for img_id in img_ids:
temp = df_new_preds.query("image_id==@img_id")[['category_id', 'score']]
temp['prob'] = bayes.posterior_util(temp.category_id.to_list())
mid_score = temp.prob.sort_values(ascending=False).median()
remove_index = temp.query("prob<=@mid_score and score<0.001").index
df_new_preds.drop(index=remove_index, inplace=True)
return df_new_preds.to_dict("records")
def consolidate_results(models, annotations, out_file, remove_duplicates=True, reduce_score=True):
all_predictions, data = merge_predictions(models, annotations)
# group the results by IOU and class
new_preds = select_max_score(all_predictions, data, multi_model=reduce_score)
# remove duplicated overlapping categories
if remove_duplicates:
new_preds = remove_duplicated_categories(new_preds)
# img_ids = [d['id'] for d in data['images']]
# new_preds = apply_bayesian_stats(new_preds, img_ids)
# write the data
out_file_ = os.getenv("AICROWD_PREDICTIONS_OUTPUT_PATH")
write_data(new_preds, out_file_)
def write_data(data, out_file):
'''
Writes the data in the json file
'''
with open(out_file, "w") as file:
json_dump = json.dumps(data)
file.write(json_dump)
\ No newline at end of file
def get_model():
return [
{
"config" : "./models/htc/htc_x101_3.py",
"weights" : "./models/htc/epoch_52.pth",
"output_file" : "predictions_htc.json"
# "name": "htc"
},
# {
# "config" : "./models/detectoRS/detectors_htc_r50_2.py",
# "weights" : "./models/detectoRS/epoch_20.pth",
# "output_file" : "predictions_det.json"
# },
{
"config" : "./models/detectoRS_4/detectors_htc_r50_4.py",
"weights" : "./models/detectoRS_4/epoch_35.pth",
"output_file" : "predictions_det_5.json"
# "name": "drs"
},
# {
# "config" : "./models/detectoRS_4_1/detectors_htc_r50_4_1.py",
# "weights" : "./models/detectoRS_4_1/epoch_39.pth",
# "output_file" : "predictions_det_41.json"
# },
# {
# "config" : "./models/detectoRS_4/detectors_htc_r50_4.py",
# "weights" : "./models/detectoRS_4/epoch_40_ssl.pth",
# "output_file" : "predictions_det_5.json"
# }
]
\ No newline at end of file
File added
File added
This diff is collapsed.
File added
File added
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment