Beispiel #1
0
    def __init__(self, learning_rate=0.00005, activation="softmax", loss="categorical_crossentropy",
                 min_value_count=500, per_class=527):
        """
        Initiate new model(classifier) instance

        :param learning_rate: learning rate of the model, default is 0.00005
        :param activation: activation function of the prediction layer, default is 'softmax'
        :param loss: loss function of the classifier, default is 'categorical_crossentropy'
        :param min_value_count: at least how much a class have to have training data, default is 500
        :param per_class: at most how much data from each class should the model take to train and test, default is 527
        """
        self.learning_rate = learning_rate
        self.activation = activation
        self.loss = loss
        self.number_of_classes = 15
        self.min_value_count = min_value_count
        self.per_class = per_class

        self.classifier = Classifier(self.number_of_classes, self.learning_rate, self.activation, self.loss)
        self.apparel_data = ApparelDataset(app_config['DATA_LABEL_PATH'], app_config['DATA_IMAGE_ROOT'])

        self.model = self.classifier.get_model()

        self.candidate_meta = self.apparel_data.get_candidate_meta(min_value_count, per_class)
        self.data_processor = Preprocessing(self.candidate_meta)
        self.data_processor.move_image()
        self.validation_data_generator = self.data_processor.get_data_generator('validation')
        self.train_data_generator = self.data_processor.get_data_generator('train')
        self.test_data_generator = self.data_processor.get_data_generator('test')
 def __init__(self):
     """
     Initiate the inference instance
     """
     self.apparel_meta = ApparelDataset(app_config['DATA_LABEL_PATH'],
                                        app_config['DATA_IMAGE_ROOT'])
     self.embedding_model = ImageEmbedding()
     self.embedding_map = utils.load_from_pickle('embeddings')
     self.candidate_images_ids = utils.load_from_pickle('candidate_images')
     self.candidate_images = self.apparel_meta.filter_by_ids(
         self.candidate_images_ids)
     self.candidate_images['emb'] = self.candidate_images.apply(
         lambda row: self.embedding_map[row['id']], axis=1)
     self.recommendations = []
Beispiel #3
0
class EmbeddingCalculator:

    def __init__(self):
        self.apparel_meta = ApparelDataset(app_config['DATA_LABEL_PATH'], app_config['DATA_IMAGE_ROOT'])
        self.embedding_model = ImageEmbedding()
        self.embedding_map = {}
        return

    # Calculate embedding of all items
    def calculate_all_embeddings(self):
        """
            Calculate embeddings of all the images in the inventory

            :return:
        """
        self.embedding_map = {}
        all_metadata = self.apparel_meta.get_all_meta()
        for meta in all_metadata.iterrows():
            if meta[1]['id'] not in self.embedding_map:
                self.embedding_map[meta[1]['id']] = self.embedding_model.get_embedding(meta[1]['image'])

    def save_embeddings_to_pickle(self):
        """
        Save calculated embeddings in a pickle file

        :return:
        """
        utils.save_to_pickle(self.embedding_map, 'embeddings')

    def generate_candidate_products(self):
        """
        Generate candidate products from different gender-article group

        :return: True if successful, raise error otherwise
        """
        all_meta = self.apparel_meta.get_all_meta()
        all_meta['emb'] = all_meta.apply(lambda row: self.embedding_map[row['id']], axis=1)
        utils.generate_candidates(all_meta, save_as_pickle=True)
        return True
Beispiel #4
0
 def __init__(self):
     self.apparel_meta = ApparelDataset(app_config['DATA_LABEL_PATH'], app_config['DATA_IMAGE_ROOT'])
     self.embedding_model = ImageEmbedding()
     self.embedding_map = {}
     return
Beispiel #5
0
class ModelTraining:
    """
    Model Training
    """

    def __init__(self, learning_rate=0.00005, activation="softmax", loss="categorical_crossentropy",
                 min_value_count=500, per_class=527):
        """
        Initiate new model(classifier) instance

        :param learning_rate: learning rate of the model, default is 0.00005
        :param activation: activation function of the prediction layer, default is 'softmax'
        :param loss: loss function of the classifier, default is 'categorical_crossentropy'
        :param min_value_count: at least how much a class have to have training data, default is 500
        :param per_class: at most how much data from each class should the model take to train and test, default is 527
        """
        self.learning_rate = learning_rate
        self.activation = activation
        self.loss = loss
        self.number_of_classes = 15
        self.min_value_count = min_value_count
        self.per_class = per_class

        self.classifier = Classifier(self.number_of_classes, self.learning_rate, self.activation, self.loss)
        self.apparel_data = ApparelDataset(app_config['DATA_LABEL_PATH'], app_config['DATA_IMAGE_ROOT'])

        self.model = self.classifier.get_model()

        self.candidate_meta = self.apparel_data.get_candidate_meta(min_value_count, per_class)
        self.data_processor = Preprocessing(self.candidate_meta)
        self.data_processor.move_image()
        self.validation_data_generator = self.data_processor.get_data_generator('validation')
        self.train_data_generator = self.data_processor.get_data_generator('train')
        self.test_data_generator = self.data_processor.get_data_generator('test')

    def train_model(self, epoch=10):
        """
        Train the model after compilation of the model

        :param epoch: number of epoch to train the model
        :return: history of the training of the model returned by fit_generator method
        """

        csv_logger = CSVLogger(os.path.join(app_config['MODEL_LOG_PATH'], 'train-log.csv'), append=True, separator=';')
        train_history = self.model.fit_generator(self.train_data_generator,
                                                 steps_per_epoch=None,
                                                 epochs=epoch,
                                                 verbose=1,
                                                 validation_data=self.validation_data_generator,
                                                 callbacks=[csv_logger])

        self.classifier.save_model_to_disk('classifier.h5')

        return train_history

    def evaluate_model(self):
        """
        Evaluate the trained model

        :return: test accuracy, dictionary of class-wise right & wrong count.
                 example - (accuracy, { 'Topwear': {'right': n, 'wrong': m } })
        """
        class_indices = self.validation_data_generator.class_indices
        tester = ModelTesting(self.test_data_generator, self.model)
        return tester.test_model(class_indices)

    def reset_data_processor(self):
        """
        Reset the inventory after training the model. Move the training/testing/validation images back to inventory root
        directory

        :return:
        """
        self.data_processor.return_image_to_inventory()
Beispiel #6
0
from app import app
from app.config import app_config
from flask import request, jsonify, send_from_directory
from flask_cors import cross_origin
from werkzeug.utils import secure_filename

import app.utils.utils as utils
import time
import os

from app.inference import Inference
from app.data.dataset import ApparelDataset

inferer = Inference()
all_meta = ApparelDataset(app_config['DATA_LABEL_PATH'],
                          app_config['DATA_IMAGE_ROOT']).get_all_meta()
all_meta.fillna('', inplace=True)


@app.route('/')
@cross_origin()
def index():
    return "Hello World"


@app.route('/search-by-id', methods=['POST'])
@cross_origin()
def search_by_id():
    # check if the post request has the file part
    if 'image_id' not in request.form:
        return jsonify({'success': False, 'message': 'Provide an image id'})
class Inference:
    """
        Model Inference
    """

    # Constructor to initialize and load data, embedding and recommendation table of items
    def __init__(self):
        """
        Initiate the inference instance
        """
        self.apparel_meta = ApparelDataset(app_config['DATA_LABEL_PATH'],
                                           app_config['DATA_IMAGE_ROOT'])
        self.embedding_model = ImageEmbedding()
        self.embedding_map = utils.load_from_pickle('embeddings')
        self.candidate_images_ids = utils.load_from_pickle('candidate_images')
        self.candidate_images = self.apparel_meta.filter_by_ids(
            self.candidate_images_ids)
        self.candidate_images['emb'] = self.candidate_images.apply(
            lambda row: self.embedding_map[row['id']], axis=1)
        self.recommendations = []

    # Recommend similar items to another item in the inventory by id
    def recommend_by_id(self, image_id):
        """
        Recommend product similar to another product in the inventory.

        :param image_id: id of the  image of the query product
        :return: top 10 most similar recommended product
        """
        filtered_meta = self.apparel_meta.filter_by_id(image_id)
        if filtered_meta.shape[0] <= 0:
            print('No image found')
            return

        filtered_meta['emb'] = filtered_meta.apply(
            lambda row: self.embedding_map[row['id']], axis=1)
        self.recommendations = utils.get_top_100_similar_product(
            self.embedding_map[image_id], filtered_meta)

        return self.recommendations

    # Recommend similar items to a query image
    def recommend_by_image(self,
                           image_path,
                           article_type=None,
                           gender=None,
                           color=None):
        """
        Recommend available products similar to an unknown query product

        :param color: color of the apparel
        :param gender: gender of the product to search for
        :param article_type: article_type of the product
        :param image_path: path of the query image
        :return: top 10 most similar products
        """
        all_metadata = self.apparel_meta.get_all_meta()

        try:
            new_img_embedding = get_embeddings(image_path)
            labels = [
                'Bags', 'Belts', 'Bottomwear', 'Eyewear', 'Flip Flops',
                'Fragrance', 'Innerwear', 'Jewellery', 'Lips', 'Sandal',
                'Shoes', 'Socks', 'Topwear', 'Wallets', 'Watches'
            ]
            other_labels = [
                "Dress", "Loungewear and Nightwear", "Saree", "Nails",
                "Makeup", "Headwear", "Ties", "Accessories", "Scarves",
                "Cufflinks", "Apparel Set", "Free Gifts", "Stoles",
                "Skin Care", "Skin", "Eyes", "Mufflers", "Shoe Accessories",
                "Sports Equipment", "Gloves", "Hair", "Bath and Body",
                "Water Bottle", "Perfumes", "Umbrellas", "Wristbands",
                "Beauty Accessories", "Sports Accessories", "Vouchers",
                "Home Furnishing"
            ]

            temp_candidate_images = self.candidate_images
            modified_metadata = all_metadata
            sub_modified_metadata = None
            sub_class_article_gender = None

            if article_type is None:
                print('Classifying')
                sub_categories, sub_cat_sim_score = classify_image(
                    labels, other_labels, image_path)
                print(sub_categories)
                sub_modified_metadata = all_metadata[
                    all_metadata['subCategory'].isin(sub_categories)]
                sub_class_article_gender = sub_modified_metadata[
                    'genderArticle']

            else:
                temp_candidate_images = temp_candidate_images[
                    temp_candidate_images['articleType'] == article_type]
                modified_metadata = all_metadata[all_metadata['articleType'] ==
                                                 article_type]

            if gender is not None:
                if sub_modified_metadata is not None:
                    sub_modified_metadata = sub_modified_metadata[
                        sub_modified_metadata['gender'] == gender]
                modified_metadata = modified_metadata[
                    modified_metadata['gender'] == gender]
                temp_candidate_images = temp_candidate_images[
                    temp_candidate_images['gender'] == gender]

            if color is not None:
                if sub_modified_metadata is not None:
                    sub_modified_metadata = sub_modified_metadata[
                        sub_modified_metadata['baseColour'] == color]
                modified_metadata = modified_metadata[
                    modified_metadata['baseColour'] == color]
                temp_candidate_images = temp_candidate_images[
                    temp_candidate_images['baseColour'] == color]

            if article_type is None or gender is None:
                c_gender, c_article_type, candidate_sim_score, sub_article, sub_sim_score = utils.get_article_type(
                    new_img_embedding, temp_candidate_images,
                    sub_class_article_gender)

                print(c_article_type)
                print(sub_article)

                if sub_modified_metadata is not None:
                    modified_candidate_metadata = sub_modified_metadata
                else:
                    modified_candidate_metadata = modified_metadata

                if gender is None:
                    modified_candidate_metadata = modified_candidate_metadata[
                        modified_candidate_metadata['gender'] == c_gender]

                if article_type is None:
                    modified_candidate_metadata = modified_candidate_metadata[
                        modified_candidate_metadata['articleType'] ==
                        c_article_type]

                if len(modified_candidate_metadata) > 0:
                    print('Only candidate')
                    modified_metadata = modified_candidate_metadata
                else:
                    if sub_modified_metadata is not None:
                        # modified_metadata = modified_metadata[(modified_metadata['articleType'] == c_article_type)
                        #                                       |
                        #                                       (modified_metadata['articleType'] == sub_article)]
                        if sub_sim_score >= 0.8 or (candidate_sim_score -
                                                    sub_sim_score) <= 0.05:
                            print('Both candidate and sub-cat')
                            modified_metadata = modified_metadata[
                                (modified_metadata['articleType'] ==
                                 c_article_type)
                                | (modified_metadata['articleType'] ==
                                   sub_article)]
                        else:
                            print('Only candidate on invalid sub-cat')
                            print(sub_sim_score)
                            modified_metadata = modified_metadata[
                                modified_metadata['articleType'] ==
                                c_article_type]
                        modified_metadata = modified_metadata[
                            modified_metadata['gender'] == c_gender]

            modified_metadata['emb'] = modified_metadata.apply(
                lambda row: self.embedding_map[row['id']], axis=1)
            print(article_type)
            print(len(modified_metadata))
            self.recommendations = utils.get_top_100_similar_product(
                new_img_embedding, modified_metadata)

            # self.apparel_meta.filter_by_sub_categories(sub_categories)
            return self.recommendations

        except IOError as io_error:
            print('Invalid model file, train and save a valid model')
            return pd.DataFrame()
        except ImportError as import_error:
            print('No model found, train and save the model first')
            return pd.DataFrame()
        except Exception as exception:
            print('Unknown error')
            print(exception)
            return pd.DataFrame()
        finally:
            print('Done...')

    # SHow recommendations through plotting figure
    def show_recommendation(self):
        """
        Show the recommended products to the screen

        :return:
        """
        utils.plot_figures(self.recommendations, nrows=2, ncols=5)
        return