Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
12 changes: 8 additions & 4 deletions configs/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,10 @@
"num_classes": 5270,
# 'input_shape': (180,180,3)
"train_from_scratch": 0, # 0 Means Use pretrained weights 1 Means train from scratch
"layer_count_trainable": 20, # Finetunable layer count if pretrained weights are used.,
"model_name": "inception-v3", # Currently supported = "inception-v3, resnet-101, efficientnet-b7, exception_min"
# Finetunable layer count if pretrained weights are used.,
"layer_count_trainable": 20,
# Currently supported = "inception-v3, resnet-101, efficientnet-b7, exception_min"
"model_name": "inception-v3",
"INIT_LR": 1e-4,
"MAX_LR": 1e-3,
"base_learning_rate": 1e-3,
Expand All @@ -48,9 +50,11 @@
"es_mode": "auto",
"es_restore_best_weights": False,
"optimizer": "adam", # currently only adam is available
"learning_rate_decay_strategy": "polynomial", # available = polynomial, exponential, cyclic, no(if given no there wont be any strategy training will be on the base learning rate)
# available = polynomial, exponential, cyclic, no(if given no there wont be any strategy training will be on the base learning rate)
"learning_rate_decay_strategy": "polynomial",
"reduce_lr_init": 0, # to use reduce lr or not if set to zero not used -> Train Callback
"loss": "categorical_crossentropy", # Focal loss can be also be used for focal loss please mention focalloss
# Focal loss can be also be used for focal loss please mention focalloss
"loss": "categorical_crossentropy",
"earlystopping_init": 0, # Whether to use Early stopping or not if set to 0 not used
"save_checkpoint_per_epoch": 0,
"save_best_checkpoint": 1,
Expand Down
4 changes: 3 additions & 1 deletion infer_class.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import tensorflow as tf
from tensorflow import keras

from src.metrics import f1_m, precision_m, recall_m
from src.model import ModelMaker
from src.metrics import precision_m, recall_m, f1_m


# Class method implementation for Multiple Deployment strategies
class InferModel:
Expand Down
10 changes: 5 additions & 5 deletions inference_benchmark.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import tensorflow as tf
from tensorflow import keras
from infer_class import InferModel
import numpy as np
import time

import numpy as np
import tensorflow as tf
from tensorflow import keras

from infer_class import InferModel

model_path = "../cdiscount_challenge_code_local/models/model-best.h5"

infer_model = InferModel(model_path, "inceptionv3")


model = infer_model.direct_model_load()

41 changes: 21 additions & 20 deletions model_api.py
Original file line number Diff line number Diff line change
@@ -1,28 +1,28 @@
# Class method implementation for Multiple Deployment str
import tensorflow as tf
from tensorflow import keras
from src.model import ModelMaker
from infer_class import InferModel
import argparse
import asyncio
import os
import time
from contextlib import contextmanager
from pathlib import Path
from tempfile import TemporaryDirectory

import cv2
import fastapi
from fastapi import FastAPI, Query
import numpy as np
import pandas as pd
import tensorflow as tf
import uvicorn
import cv2
from starlette.middleware.cors import CORSMiddleware
from contextlib import contextmanager
import asyncio
from tempfile import TemporaryDirectory
from pathlib import Path
from fastapi import FastAPI, Query
from keras.preprocessing.image import ImageDataGenerator, img_to_array, load_img
from PIL import Image
from src.dataprocessor import BSONIterator, CDiscountProcessor
from keras.preprocessing.image import ImageDataGenerator
from keras.preprocessing.image import load_img, img_to_array
import argparse
import time
import pandas as pd
from configs import config
from starlette.middleware.cors import CORSMiddleware
from tensorflow import keras

import os
from configs import config
from infer_class import InferModel
from src.dataprocessor import BSONIterator, CDiscountProcessor
from src.model import ModelMaker

os.environ["CUDA_DEVICE_ORDER"] = "PCI_BUS_ID" # see issue #152
os.environ["CUDA_VISIBLE_DEVICES"] = ""
Expand Down Expand Up @@ -67,7 +67,8 @@ def predict_class(file: fastapi.UploadFile = fastapi.File(...)):
print(filepath)
image = cv2.imread(str(filepath))
print("Image shape before preprocessing:{}".format(image.shape))
image_resized = cv2.resize(image, (180, 180), interpolation=cv2.INTER_AREA)
image_resized = cv2.resize(
image, (180, 180), interpolation=cv2.INTER_AREA)

x = img_to_array(image_resized)
x = ImageDataGenerator().random_transform(x)
Expand Down
3 changes: 2 additions & 1 deletion model_converter.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import tensorflow as tf
from tensorflow import keras

from src.metrics import f1_m, precision_m, recall_m
from src.model import ModelMaker
from src.metrics import precision_m, recall_m, f1_m

"""

Expand Down
15 changes: 9 additions & 6 deletions src/callbacks.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
# Class to define different callbacks and learning rate strategies
import tensorflow as tf
import wandb
from configs import config
import tensorflow_addons as tfa
from datetime import datetime
import os
import shutil
from datetime import datetime

import tensorflow as tf
import tensorflow_addons as tfa
import wandb
from wandb.keras import WandbCallback

from configs import config


# Custom class to log learning rate to Wandb
class LRLogger(tf.keras.callbacks.Callback):
Expand Down Expand Up @@ -107,7 +109,8 @@ def set_callbacks_and_optimizer(self):
# Save best checkpoint based on metric monitoring

filepath = (
checkpoints_path + "/" + "weights.best_{epoch:02d}-{val_accuracy:.2f}.hdf5"
checkpoints_path + "/" +
"weights.best_{epoch:02d}-{val_accuracy:.2f}.hdf5"
)
checkpoint_best = tf.keras.callbacks.ModelCheckpoint(
filepath,
Expand Down
61 changes: 35 additions & 26 deletions src/dataprocessor.py
Original file line number Diff line number Diff line change
@@ -1,28 +1,33 @@
import os, sys, math, io
import numpy as np
import pandas as pd
import io
import math
import multiprocessing as mp
import bson
import os
import struct
import sys
import threading
import time
from collections import defaultdict


import bson
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import pymongo
import skimage.io
from keras.preprocessing.image import load_img, img_to_array
from configs import config
from tqdm import tqdm
from keras.preprocessing.image import Iterator
from keras.preprocessing.image import ImageDataGenerator
import skimage.io as skio
from keras import backend as K
from keras.preprocessing.image import (
ImageDataGenerator,
Iterator,
img_to_array,
load_img,
)
from PIL import Image
from pymongo import MongoClient
import io
import pymongo
import skimage.io as skio
import threading
import time
from collections import defaultdict
from tqdm import *
from tqdm import tqdm

from configs import config


class CDiscountProcessor:
Expand Down Expand Up @@ -60,7 +65,6 @@ def make_category_tables(self, categories_df):
idx2cat = {}
i = 0
for ir in categories_df.itertuples():

category_id = ir[0]
category_idx = ir[4]
cat2idx[category_id] = category_idx
Expand Down Expand Up @@ -130,7 +134,8 @@ def make_val_set(self, df, split_percentage=0.2, drop_percentage=0.0):
# Randomly choose the products that become part of the validation set.
val_size = int(len(product_ids) * split_percentage)
if val_size > 0:
val_ids = np.random.choice(product_ids, val_size, replace=False)
val_ids = np.random.choice(
product_ids, val_size, replace=False)
else:
val_ids = []

Expand All @@ -150,16 +155,17 @@ def make_val_set(self, df, split_percentage=0.2, drop_percentage=0.0):
return train_df, val_df

def generate_lookup_table(self):
self.categories_df = pd.read_csv(self.category_path, index_col="category_id")
self.categories_df = pd.read_csv(
self.category_path, index_col="category_id")
self.categories_df["category_idx"] = pd.Series(
range(len(self.categories_df)), index=self.categories_df.index
)
self.cat2idx, self.idx2cat = self.make_category_tables(self.categories_df)
self.cat2idx, self.idx2cat = self.make_category_tables(
self.categories_df)
# Testing
print(self.cat2idx[1000012755], self.idx2cat[4])

def read_images_load_train_val(self):

self.train_offsets_df = self.read_bson(
self.train_path, num_records=self.num_train_products, with_categories=True
)
Expand Down Expand Up @@ -258,7 +264,6 @@ def __init__(
shuffle=False,
seed=None,
):

self.file = bson_file
self.images_df = images_df
self.offsets_df = offsets_df
Expand All @@ -270,16 +275,20 @@ def __init__(
self.image_shape = self.target_size + (3,)

print(
"Found %d images belonging to %d classes." % (self.samples, self.num_class)
"Found %d images belonging to %d classes." % (
self.samples, self.num_class)
)

super(BSONIterator, self).__init__(self.samples, batch_size, shuffle, seed)
super(BSONIterator, self).__init__(
self.samples, batch_size, shuffle, seed)
self.lock = lock

def _get_batches_of_transformed_samples(self, index_array):
batch_x = np.zeros((len(index_array),) + self.image_shape, dtype=K.floatx())
batch_x = np.zeros((len(index_array),) +
self.image_shape, dtype=K.floatx())
if self.with_labels:
batch_y = np.zeros((len(batch_x), self.num_class), dtype=K.floatx())
batch_y = np.zeros(
(len(batch_x), self.num_class), dtype=K.floatx())

for i, j in enumerate(index_array):
# Protect file and dataframe access with a lock.
Expand Down
6 changes: 4 additions & 2 deletions src/model.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import tensorflow
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers
import tensorflow

from configs import config


Expand All @@ -11,7 +12,8 @@ def __init__(self):
self.input_shape = config.model_parameter_dict["target_size"] + (3,)
print("==" * 10)
print(
"The default input shape of the model will be {}".format(self.input_shape)
"The default input shape of the model will be {}".format(
self.input_shape)
)
self.num_classes = config.model_parameter_dict["num_classes"]
print(
Expand Down
15 changes: 8 additions & 7 deletions train.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
from src.callbacks import CallbacksFormatter
from src.dataprocessor import CDiscountProcessor
from src.metrics import precision_m, recall_m, f1_m
from src.model import ModelMaker
from configs import config
import tensorflow as tf
from tensorflow import keras
import argparse

import tensorflow as tf
import wandb
from tensorflow import keras
from wandb.keras import WandbCallback

from configs import config
from src.callbacks import CallbacksFormatter
from src.dataprocessor import CDiscountProcessor
from src.metrics import f1_m, precision_m, recall_m
from src.model import ModelMaker

cdiscount_processor = CDiscountProcessor()
modelmaker = ModelMaker()
Expand Down
6 changes: 4 additions & 2 deletions web_app.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@
if image is not None:
files = {"file": image.getvalue()}
with st.spinner("API Request Initiated.Waiting for Response"):
res = requests.post(("http://localhost:5001/predict/"), files=files)
res = requests.post(
("http://localhost:5001/predict/"), files=files)
st.success("Request completed Successfully")
text = res.json()
st.session_state.key = text
Expand All @@ -52,4 +53,5 @@

col4, col5 = st.columns(2)
col4.metric(label="Response Time", value=text["response_time"])
col5.metric(label="Model Inference time", value=text["model_inference_time"])
col5.metric(label="Model Inference time",
value=text["model_inference_time"])