Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
43d0677
started repolishing namings and structure of data pipeline for final …
sinan2000 May 24, 2025
e071079
revamped download process to cleanup structure of dataset
sinan2000 May 24, 2025
6f136c6
polished some more types and docs, given the uodates
sinan2000 May 24, 2025
8a953d2
started redoing tests
sinan2000 May 24, 2025
944f66d
first model trained!
sinan2000 May 24, 2025
bf67dad
first complete training!!!
sinan2000 May 24, 2025
2915717
small diffs
sinan2000 May 26, 2025
dba0789
solved unit tests for other parts of code
sinan2000 May 26, 2025
88f31ba
fixed data preproc tests
sinan2000 May 26, 2025
b357308
setup integration tests
sinan2000 May 26, 2025
416afe5
finished merging
sinan2000 May 26, 2025
4c0f0bc
started repolishing namings and structure of data pipeline for final …
sinan2000 May 24, 2025
e799210
revamped download process to cleanup structure of dataset
sinan2000 May 24, 2025
799d314
polished some more types and docs, given the uodates
sinan2000 May 24, 2025
ff94289
started redoing tests
sinan2000 May 24, 2025
379dcbd
pulled from main
sinan2000 May 29, 2025
9d4f273
first complete training!!!
sinan2000 May 24, 2025
c9dd0b1
pulled from main
sinan2000 May 26, 2025
58d93ad
solved unit tests for other parts of code
sinan2000 May 26, 2025
6a60723
fixed data preproc tests
sinan2000 May 26, 2025
7d66091
setup integration tests
sinan2000 May 26, 2025
05eef4a
preparing for final submission
sinan2000 May 28, 2025
acdcf99
Merge branch 'feature/integrating' of https://github.com/sinan2000/re…
sinan2000 May 29, 2025
b69c69d
only one random augmentation applied per epoch
sinan2000 May 29, 2025
4ca3332
made kfold print summary of folds
sinan2000 May 29, 2025
587d719
now will start training both models
sinan2000 May 29, 2025
57bd014
starting training now
sinan2000 May 29, 2025
6c3cd1b
now
sinan2000 May 29, 2025
692ee5f
api working
sinan2000 May 29, 2025
3cb29f0
streamlit working
sinan2000 May 29, 2025
eef2c13
training real model
sinan2000 May 29, 2025
a44af7a
trying to train on vm
sinan2000 May 29, 2025
06ed773
last changes
sinan2000 May 29, 2025
0a47525
new img
sinan2000 May 29, 2025
0095141
Merge branch 'main' into feature/integrating
sinan2000 May 29, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 2 additions & 5 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,6 @@ __pycache__/
venv/
.env

private/
/data/

/models/
/simple_classifier_checkpoints/
/main_classifier_checkpoints/
/data/
/private/
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,6 @@ repos:
hooks:
- id: run-unittests
name: Run unittests
entry: pipenv run python -m unittest discover tests
entry: pipenv run python -m unittest discover tests/unit
language: system
pass_filenames: false
3 changes: 2 additions & 1 deletion Pipfile
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ pre-commit = "*"
torch = {index = "pytorch-cu128", version = "2.7.0+cu128", markers = "platform_system == 'Windows'"}
torchvision = {index = "pytorch-cu128", version = "0.22.0+cu128", markers = "platform_system == 'Windows'"}
torchaudio = {index = "pytorch-cu128", version = "2.7.0+cu128", markers = "platform_system == 'Windows'"}
pandas = "*"
pillow = "*"
pandas= "*"
torcheval = "*"
tqdm = "*"
requests = "*"
Expand Down
78 changes: 30 additions & 48 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,24 +23,6 @@ Make sure you have the following installed:
For detailed installation instructions, [click here](https://pipenv.pypa.io/en/latest/installation.html).

## Getting Started
### Setting up the repository

If you're collaborating or want to explore the latest version of the project:

1. Fork this repository.
2. Clone your fork locally.
3. Configure a remote pointing to the upstream repository to sync changes between your fork and the original repository.
```bash
git remote add upstream https://github.com/sinan2000/recaptcha
```
**Don't skip this step.** We might update the original repository, so you should be able to easily pull our changes.

To update your forked repo follow these steps:
1. `git fetch upstream`
2. `git rebase upstream/main`
3. `git push origin main`
Sometimes you may need to use git push --force origin main. Only use this flag the first time you push after you rebased, and be careful as you might overwrite someone' changes.

## Installing Dependencies
To install the project dependencies run:

Expand Down Expand Up @@ -102,60 +84,60 @@ To make navigating through the repository easier, you can find its structure bel
├───README.md # Instructions
```

## **API Launching 🚀**
## **🚀 Usage Guide**

To start the FastAPI server locally, follow these steps:
### Running the App

1. Activate pipenv environment (if not already activated)

```bash
pipenv shell
```

2. You can start the FastAPI server using:

2. To launch any component of our project, run:
```bash
uvicorn recaptcha_classifier.api:app --host 0.0.0.0 --port 8000 --reload
python main.py [OPTION]
```

Alternatively, run the API by running main.py:
Available list of options:
--streamlit - Launches Streamlit UI
--api - starts the FastAPI backend
--train-simple-cnn - Trains the simple baseline model
--train-main-cnn - Trains our main model

Make sure the open_api() function is uncommented in main.py
If no argument has been passed, an interactive menu will appear to let you choose the action.

```python
def main():
# train_main_classifier()
open_api() # ✅ Uncomment this line
```
## API Documentation

### API Documentation
### Example API call and response format

After running the server, you can access the Documentation:
You can make a call to the api using curl, by running the command below. Make sure to include a valid file path. The path can either be absolute (full) or relative to your
current location from command terminal.

Interactive API docs (Swagger UI): http://localhost:8000/docs
```bash
curl -X POST "http://localhost:8000/predict" -H "accept: application/json" -H "Content-Type: multipart/form-data" -F "file=@<path_to_file>"
```
You will get a response in the following format:

ReDoc documentation: http://localhost:8000/redoc
```json
{
"class_id":1,
"class_name":"Bridge",
"confidence": "99.9%"
}
```

These interfaces allow you to test predictions and inspect the request/response formats.
The API is stateless, initializing the model on launching, and caches responses for 1 hour.

### API call and response format

You can make a call to the api using curl, by running the chunk below. Make sure to include a valid file path.
After running the server, you can access the Documentation:

```bash
curl -X POST "http://localhost:8000/predict" -H "accept: application/json" -H "Content-Type: multipart/form-data" -F "file=<path_to_file>"
```
You will get a response in the following format:
Interactive API docs (Swagger UI): http://localhost:8000/docs

```bash
{"class_id":1,"class_name":"Bridge"}
```
ReDoc documentation: http://localhost:8000/redoc

If you're using Windows, running the request in the format mentioned above may not work in Powershell. Instead, use the format below in Command Prompt:
These interfaces allow you to test predictions and inspect the request/response formats.

```bash
curl -X POST "http://localhost:8000/predict" -H "accept: application/json" -H "Content-Type: multipart/form-data" -F "file=@<path_to_file>"
```

### Possible error Responses

Expand Down
File renamed without changes.
13 changes: 8 additions & 5 deletions main.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,14 @@ def handle_action(choice: str):
handle_action(choice)

def ui():
from recaptcha_classifier.server.app import StreamlitApp
import subprocess
import os
root_dir = os.path.dirname(os.path.abspath(__file__))
streamlit_file = os.path.join(root_dir, "recaptcha_classifier", "server", "app.py")

app = StreamlitApp()
app.render()
subprocess.Popen(["uvicorn", "recaptcha_classifier.server.api:app", "--reload"])

subprocess.run(["streamlit", "run", streamlit_file])

def train_simple_cnn():
from recaptcha_classifier.pipeline.simple_cnn_pipeline import SimpleClassifierPipeline
Expand All @@ -63,14 +67,13 @@ def train_simple_cnn():
def train_main_classifier():
from recaptcha_classifier.pipeline.main_model_pipeline import MainClassifierPipeline

pipeline = MainClassifierPipeline(epochs=1, k_folds=2)
pipeline = MainClassifierPipeline()
pipeline.run(save_train_checkpoints=False)

def open_api():
import uvicorn
# opens endpoint at http://localhost:8000/
uvicorn.run("recaptcha_classifier.server.api:app", reload=True)


if __name__ == '__main__':
main()
11 changes: 10 additions & 1 deletion recaptcha_classifier/__init__.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,18 @@
from .models import SimpleCNN
from .models.main_model import MainCNN, HPOptimizer
from .detection_labels import DetectionLabels
from .data import DataPreprocessingPipeline
from .train import Trainer
from .features import evaluate_model
from .server import load_model

__all__ = [
"DetectionLabels",
"DataPreprocessingPipeline",
'SimpleCNN'
'SimpleCNN',
'MainCNN',
'HPOptimizer',
'Trainer',
'evaluate_model',
'load_model'
]
2 changes: 1 addition & 1 deletion recaptcha_classifier/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
IMAGE_SIZE = (IMAGE_WIDTH, IMAGE_HEIGHT)
INPUT_SHAPE = (IMAGE_CHANNELS, IMAGE_HEIGHT, IMAGE_WIDTH)

MODELS_FOLDER="models" # Folder where models are saved
MODELS_FOLDER="models/final" # Folder where models are saved
MAIN_MODEL_FILE_NAME = "main_model.pt"
SIMPLE_MODEL_FILE_NAME = "simple_model.pt"
OPTIMIZER_FILE_NAME = "optimizer.pt"
Expand Down
29 changes: 9 additions & 20 deletions recaptcha_classifier/data/__init__.py
Original file line number Diff line number Diff line change
@@ -1,26 +1,19 @@
from .pipeline import DataPreprocessingPipeline
from .downloader import DatasetDownloader
from .pair_loader import ImageLabelLoader
from .paths_loader import ImagePathsLoader
from .splitter import DataSplitter
from .visualizer import Visualizer
from .loader_factory import LoaderFactory
from .dataset import ImageDataset
from .preprocessor import ImagePrep
from .augment import (
AugmentationPipeline,
HorizontalFlip,
RandomRotation
)
from .scaler import YOLOScaler
from .augment import AugmentationPipeline

from .collate_batch import collate_batch

from .types import (
FilePair,
FilePairList,
DatasetSplitDict,
BBoxList,
DataPair,
ImagePathList,
DatasetSplitMap,
LoadedImg,
DataItem,
DataBatch
)
Expand All @@ -29,24 +22,20 @@
# Classes
"DataPreprocessingPipeline",
"DatasetDownloader",
"ImageLabelLoader",
"ImagePathsLoader",
"DataSplitter",
"Visualizer",
"LoaderFactory",
"ImageDataset",
"ImagePrep",
"AugmentationPipeline",
"HorizontalFlip",
"RandomRotation",
"YOLOScaler",
# Methods
"collate_batch",
# Types
"FilePair",
"FilePairList",
"DatasetSplitDict",
"BBoxList",
"DataPair",
"ImagePathList",
"DatasetSplitMap",
"LoadedImg",
"DataItem",
"DataBatch",
]
92 changes: 13 additions & 79 deletions recaptcha_classifier/data/augment.py
Original file line number Diff line number Diff line change
@@ -1,93 +1,27 @@
import random
from abc import ABC, abstractmethod
from PIL import Image
from typing import List
from .scaler import YOLOScaler
from .types import DataPair, BBoxList


class Augmentation(ABC):
"""Abstract class for data augmentation."""
@abstractmethod
def augment(self,
image: Image.Image,
annotations: List) -> DataPair:
"""
Apply the transformation of the image and updates the bounding boxes
if necessary.

Args:
image (Image.Image): The image to be augmented.
annotations (List): List of annotations associated with the image.

Returns:
DataPair: The augmented image and the updated
annotations.
"""
pass
from .types import LoadedImg
from torchvision import transforms


class AugmentationPipeline:
"""Class to manage a series of augmentations in sequence."""
def __init__(self, transforms=[]) -> None:
self._transforms: List[Augmentation] = transforms
def __init__(self, transforms_list: List) -> None:
"""
Initializes the augmentation pipeline with a list of transformations.
"""
self._transforms_list = transforms_list

def apply_transforms(self,
image: Image.Image,
annotations: BBoxList) -> DataPair:
image: LoadedImg) -> LoadedImg:
"""
Apply all transformations in the pipeline to the image and
annotations.
Apply a random transformation from the pipeline to the image.

Args:
image (Image.Image): The image to be augmented.
annotations (BBoxList): List of annotations
associated with the image.
image (LoadedImg): The image to be augmented.

Returns:
DataPair: The augmented image and the updated
annotations.
LoadedImg: The augmented image.
"""
for transform in self._transforms:
if hasattr(transform, 'prob') and random.random() > transform.prob:
continue
image, annotations = transform.augment(image, annotations)
return image, annotations


class HorizontalFlip(Augmentation):
"""Flips the image horizontally, with probability p and updates bboxes."""
def __init__(self, p: float = 0.5) -> None:
self.prob = p

def augment(self,
image: Image.Image,
annotations: BBoxList) -> DataPair:
flipped = image.transpose(Image.FLIP_LEFT_RIGHT)
new_annotations = YOLOScaler.scale_for_flip(annotations)

return flipped, new_annotations


class RandomRotation(Augmentation):
"""
Rotates the image by a random angle,
also updates bboxes to reflect the rotation.
"""
def __init__(self, degrees: float = 30.0, p: float = 0.5) -> None:
self._degrees = degrees
self.prob = p

def augment(self,
image: Image.Image,
annotations: BBoxList) -> DataPair:
angle = random.uniform(-self._degrees, self._degrees)

rotated = image.rotate(angle)
new_annotations = (YOLOScaler
.scale_for_rotation(annotations,
angle,
image.size)
)

return rotated, new_annotations
transform = random.choice(self._transforms_list)
return transform(image)
Loading