jcarnero commited on
Commit
916ab8e
Β·
1 Parent(s): 4af2e63

Copy deployment files to gradio branch

Browse files
LICENSE DELETED
@@ -1,21 +0,0 @@
1
- MIT License
2
-
3
- Copyright (c) 2023 Javi Carnero
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
README.md DELETED
@@ -1,17 +0,0 @@
1
- # birds-classification
2
-
3
- Train model for birds classification and gradio app
4
-
5
- Training is done using fastai, deployment mimics its transforms to publish a gradio app that has no fastai dependencies.
6
-
7
- ## Train
8
-
9
- ```bash
10
- conda env create -f environment.yml
11
- ```
12
-
13
- ```bash
14
- conda activate fastai
15
- cd training
16
- python -m birds.train
17
- ```
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
deployment/app.py β†’ app.py RENAMED
File without changes
environment.yml DELETED
@@ -1,25 +0,0 @@
1
- name: fastai
2
- channels:
3
- - pytorch
4
- - nvidia
5
- - conda-forge
6
- - fastchan
7
- - defaults
8
- dependencies:
9
- - python=3.10
10
- - pip
11
- - cudatoolkit=11.7
12
- - pytorch=1.13.1
13
- - torchvision=0.14.1
14
- - pytorch-cuda=11.7
15
- - fastcore=1.5.28
16
- - fastai=2.7.11
17
- - pip:
18
- - ipykernel
19
- - ipywidgets
20
- - gradio==3.20.1
21
- - timm==0.6.12
22
- - kaggle==1.5.12
23
- - flake8
24
- - black
25
- - pytest
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
deployment/model.py β†’ model.py RENAMED
File without changes
models/vit_exported.pkl DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:c96e179026917191d7a7e8b62c64d1a212ee77779965523a09a4b26fd6ccb934
3
- size 23232463
 
 
 
 
deployment/requirements.txt β†’ requirements.txt RENAMED
File without changes
tests/__init__.py DELETED
File without changes
tests/test_validation_transforms.py DELETED
@@ -1,109 +0,0 @@
1
- import pytest
2
-
3
- from pathlib import Path
4
- from typing import List
5
- import numpy as np
6
- from PIL import Image
7
- import torch
8
- import torchvision.transforms as tvtfms
9
- from fastai.vision.data import PILImage
10
- import fastai.vision.augment as fastai_aug
11
-
12
- from deployment.transforms import resized_crop_pad, gpu_crop
13
-
14
- DATA_PATH = "data/200-bird-species-with-11788-images"
15
-
16
-
17
- def get_birds_images(path: Path) -> List[str]:
18
- with open(path / "images.txt", "r") as file:
19
- lines = [
20
- path.resolve() / "images" / line.strip().split()[1]
21
- for line in file.readlines()
22
- ]
23
- return lines
24
-
25
-
26
- class TestTransforms:
27
- im_idx = 510
28
-
29
- @pytest.fixture
30
- def img_paths(self) -> List[str]:
31
- path = Path(DATA_PATH) / "CUB_200_2011"
32
- return get_birds_images(path.resolve())
33
-
34
- @pytest.fixture
35
- def im_fastai(self, img_paths: List[str]) -> PILImage:
36
- fname = img_paths[self.im_idx]
37
- return PILImage.create(fname)
38
-
39
- @pytest.fixture
40
- def im_pil(self, img_paths: List[str]) -> Image:
41
- fname = img_paths[self.im_idx]
42
- return Image.open(fname)
43
-
44
- def testImageFastaiEqualsPillow(self, im_fastai: PILImage, im_pil: Image):
45
- assert (np.array(im_fastai) == np.array(im_pil)).all()
46
-
47
- # RandomResizedCrop is not exactly equal to CropPad in validation
48
- # # def testRandomResizedCropEqualsCropPad(self, im_fastai: PILImage):
49
- # # crop_fastai = fastai_aug.CropPad((460, 460))
50
- # # crop_rrc = fastai_aug.RandomResizedCrop((460, 460))
51
-
52
- # # cropped_rrc = crop_rrc(im_fastai, split_idx=1)
53
- # # cropped_fastai = crop_fastai(im_fastai, split_idx=1)
54
-
55
- # # assert (np.array(cropped_rrc) == np.array(cropped_fastai)).all()
56
-
57
- def testRandomResizedCropEqualsCustomResizedCropPad(
58
- self, im_fastai: PILImage, im_pil: Image
59
- ):
60
- crop_rrc = fastai_aug.RandomResizedCrop((460, 460))
61
-
62
- assert (
63
- np.array(crop_rrc(im_fastai, split_idx=1))
64
- == np.array(resized_crop_pad(im_pil, (460, 460)))
65
- ).all()
66
-
67
- def testFlipEqualsCustomGPUCrop(self, im_fastai: PILImage, im_pil: Image):
68
- # apply flip augmentation on validation
69
- tt_fastai = fastai_aug.ToTensor()
70
- i2f_fastai = fastai_aug.IntToFloatTensor()
71
- flip = fastai_aug.Flip(size=(224, 224))
72
- result_im_fastai = flip(
73
- i2f_fastai(tt_fastai(im_fastai).unsqueeze(0)), split_idx=1
74
- )
75
-
76
- # apply custom gpu crop
77
- tt_torch = tvtfms.ToTensor()
78
- result_im_tv = gpu_crop(tt_torch(im_pil).unsqueeze(0), size=(224, 224))
79
-
80
- assert torch.allclose(result_im_fastai, result_im_tv)
81
- assert (result_im_fastai == result_im_tv).all()
82
-
83
- def testFastaiTransformsEqualsCustom(self, im_fastai: PILImage, im_pil: Image):
84
- # fastai transforms
85
- crop_rrc = fastai_aug.RandomResizedCrop((460, 460))
86
- tt_fastai = fastai_aug.ToTensor()
87
- i2f_fastai = fastai_aug.IntToFloatTensor()
88
- flip = fastai_aug.Flip(size=(224, 224))
89
- brightness = fastai_aug.Brightness()
90
- norm_fastai = fastai_aug.Normalize.from_stats(
91
- *fastai_aug.imagenet_stats, cuda=False
92
- )
93
-
94
- # custom transforms
95
- tt_torch = tvtfms.ToTensor()
96
- norm_torch = tvtfms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
97
-
98
- # apply all fastai augmentations on validation (transformations)
99
- batch_im_fastai = tt_fastai(crop_rrc(im_fastai, split_idx=1)).unsqueeze(0)
100
- result_im_fastai = norm_fastai(
101
- brightness(flip(i2f_fastai(batch_im_fastai), split_idx=1), split_idx=1)
102
- )
103
-
104
- # apply all custom transformations
105
- batch_im_tv = tt_torch(resized_crop_pad(im_pil, (460, 460))).unsqueeze(0)
106
- result_im_tv = norm_torch(gpu_crop(batch_im_tv, size=(224, 224)))
107
-
108
- assert torch.allclose(result_im_fastai, result_im_tv)
109
- assert (result_im_fastai == result_im_tv).all()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
training/birds/config.py DELETED
@@ -1,6 +0,0 @@
1
- DATA_STORAGE_PATH = "../data"
2
- MODELS_STORAGE_PATH = "../models"
3
- DATASET = "200-bird-species-with-11788-images"
4
- OWNER = "veeralakrishna"
5
-
6
- DATA_PATH = DATA_STORAGE_PATH + "/" + DATASET
 
 
 
 
 
 
 
training/birds/train.py DELETED
@@ -1,81 +0,0 @@
1
- import os
2
- from pathlib import Path
3
-
4
- from fastai.vision.data import (
5
- IndexSplitter,
6
- DataBlock,
7
- ImageBlock,
8
- CategoryBlock,
9
- RegexLabeller,
10
- )
11
- from fastai.vision.augment import (
12
- RandomResizedCrop,
13
- aug_transforms,
14
- Normalize,
15
- imagenet_stats,
16
- )
17
-
18
- from fastai.callback import schedule # noqa: F401
19
- from fastai.vision.learner import vision_learner, accuracy
20
-
21
- from birds import config
22
- from birds.utils.kaggle import download_dataset
23
-
24
-
25
- def get_birds_images(path):
26
- with open(path / "images.txt", "r") as file:
27
- lines = [
28
- path.resolve() / "images" / line.strip().split()[1]
29
- for line in file.readlines()
30
- ]
31
- return lines
32
-
33
-
34
- def BirdsSplitter(path):
35
- with open(path / "train_test_split.txt", "r") as file:
36
- valid_idx = [
37
- int(line.strip().split()[0]) - 1
38
- for line in file.readlines()
39
- if line.strip().split()[1] == "1"
40
- ]
41
- return IndexSplitter(valid_idx)
42
-
43
-
44
- if __name__ == "__main__":
45
- bs = 64
46
-
47
- if download_dataset(config.OWNER, config.DATASET, config.DATA_PATH):
48
- import tarfile
49
-
50
- with tarfile.open(Path(config.DATA_PATH) / "CUB_200_2011.tgz", "r:gz") as tar:
51
- tar.extractall(path=config.DATA_PATH)
52
-
53
- os.remove(Path(config.DATA_PATH) / "CUB_200_2011.tgz")
54
- os.remove(Path(config.DATA_PATH) / "segmentations.tgz")
55
-
56
- path = Path(config.DATA_PATH) / "CUB_200_2011"
57
-
58
- item_tfms = RandomResizedCrop(460, min_scale=0.75, ratio=(1.0, 1.0))
59
- batch_tfms = [
60
- *aug_transforms(size=224, max_warp=0),
61
- Normalize.from_stats(*imagenet_stats),
62
- ]
63
-
64
- birds = DataBlock(
65
- blocks=(ImageBlock, CategoryBlock),
66
- get_items=get_birds_images,
67
- splitter=BirdsSplitter(path),
68
- get_y=RegexLabeller(pat=r"/([^/]+)_\d+_\d+\.jpg"),
69
- item_tfms=item_tfms,
70
- batch_tfms=batch_tfms,
71
- )
72
-
73
- dls = birds.dataloaders(path)
74
-
75
- learner = vision_learner(dls, "vit_tiny_patch16_224", metrics=[accuracy])
76
-
77
- learner.fine_tune(7, base_lr=0.001, freeze_epochs=12)
78
-
79
- learner.export(Path(config.MODELS_STORAGE_PATH).resolve() / "vit_exported.pkl")
80
- learner.model_dir = Path(config.MODELS_STORAGE_PATH).resolve()
81
- learner.save("vit_saved", with_opt=False)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
training/birds/utils/kaggle.py DELETED
@@ -1,57 +0,0 @@
1
- import os
2
- from pathlib import Path
3
- from zipfile import ZipFile
4
- from kaggle import api
5
-
6
-
7
- def running_on_kaggle() -> bool:
8
- """
9
- Checks if script is running on kaggle
10
- :return: true if the script is running on kaggle, false otherwise
11
- """
12
- if os.environ.get("KAGGLE_KERNEL_RUN_TYPE", ""):
13
- return True
14
- else:
15
- return False
16
-
17
-
18
- def download_competition_data(competition: str, input_path: str | Path) -> None:
19
- """
20
- Downloads data from kaggle competition only if input folder is empty
21
- :param comptetition: string with the competition name id of kaggle
22
- :param input_path: path of the input folder
23
- """
24
- data_path = Path(input_path)
25
- if not data_path.exists():
26
- data_path.mkdir(parents=True)
27
- if not any(data_path.iterdir()):
28
- api.competition_download_cli(competition, path=data_path)
29
- with ZipFile(data_path / (competition + ".zip"), "r") as zipObj:
30
- # Extract all the contents of zip file in current directory
31
- zipObj.extractall(path=data_path)
32
- os.remove(data_path / (competition + ".zip"))
33
-
34
- print(os.listdir(data_path))
35
-
36
-
37
- def download_dataset(owner: str, dataset: str, input_path: str | Path) -> bool:
38
- """
39
- Downloads data from kaggle competition only if input folder is empty
40
- :param comptetition: string with the competition name id of kaggle
41
- :param input_path: path of the input folder
42
- """
43
- downloaded = False
44
- data_path = Path(input_path)
45
- if not data_path.exists():
46
- data_path.mkdir(parents=True)
47
- if not any(data_path.iterdir()):
48
- downloaded = True
49
- api.dataset_download_files(f"{owner}/{dataset}", path=data_path)
50
- with ZipFile(data_path / (dataset + ".zip"), "r") as zipObj:
51
- # Extract all the contents of zip file in current directory
52
- zipObj.extractall(path=data_path)
53
- os.remove(data_path / (dataset + ".zip"))
54
-
55
- print(os.listdir(data_path))
56
-
57
- return downloaded
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
training/notebooks/lab.ipynb DELETED
The diff for this file is too large to render. See raw diff
 
training/notebooks/transforms-lab.ipynb DELETED
The diff for this file is too large to render. See raw diff
 
deployment/transforms.py β†’ transforms.py RENAMED
File without changes
models/vit_saved.pth β†’ vit_saved.pth RENAMED
File without changes
deployment/vocab.py β†’ vocab.py RENAMED
File without changes