import tensorflow as tf
from tensorflow import keras
from tensorflow.keras.preprocessing.image import ImageDataGenerator
from tensorflow.keras.layers import Conv2D, MaxPooling2D, Flatten, Dense, Embedding, LSTM, Attention, Input, concatenate
from tensorflow.keras.optimizers import AdamW
from tensorflow.keras.losses import BinaryCrossentropy, CategoricalCrossentropy, MeanSquaredError
from tensorflow.keras.metrics import Precision, Recall, F1Score
from tensorflow.keras.models import Model
from tensorflow.keras.utils import to_categorical

import pandas as pd
import os
import numpy as np
from utils import download_images, parse_string
import constants
import logging
import time

# --- Logging Setup ---

logging.basicConfig(filename='training.log', level=logging.INFO,
                    format='%(asctime)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)

# --- Data Preprocessing ---

def load_and_preprocess_data(data_path, image_size=(224, 224), batch_size=32):
    """Loads and preprocesses the training or test data."""

    data = pd.read_csv(data_path)
    image_links = data['image_link'].values
    entity_names = data['entity_name'].values
    entity_values = data['entity_value'].values
    group_ids = data['group_id'].values

    # Download Images
    download_folder = '../images'  # Make sure to create this folder if it doesn't exist
    download_images(image_links, download_folder)

    # Create ImageDataGenerator for Augmentation
    datagen = ImageDataGenerator(
        rescale=1.0/255,
        rotation_range=20,
        width_shift_range=0.2,
        height_shift_range=0.2,
        shear_range=0.2,
        zoom_range=0.2,
        horizontal_flip=True,
        fill_mode='nearest'
    )

    # Load and pre-process images
    def load_image(image_path):
        image = tf.keras.preprocessing.image.load_img(image_path, target_size=image_size)
        image = tf.keras.preprocessing.image.img_to_array(image)
        return image / 255.0

    # Load and pre-process images
    images = []
    for i, image_link in enumerate(image_links):
        image_path = os.path.join(download_folder, os.path.basename(image_link))
        try:
            image = load_image(image_path)
            images.append(image)
        except:
            images.append(np.zeros((image_size[0], image_size[1], 3)))

    images = np.array(images)

    # One-hot encode units
    units = []
    for entity_value in entity_values:
        if pd.isna(entity_value):
            units.append(np.zeros(len(constants.allowed_units)))
        else:
            _, unit = parse_string(entity_value)
            units.append(to_categorical(list(constants.allowed_units).index(unit), num_classes=len(constants.allowed_units)))
    units = np.array(units)

    # Prepare for training
    train_ds = tf.data.Dataset.from_tensor_slices((images, entity_values, units)).batch(batch_size).prefetch(tf.data.AUTOTUNE)

    return train_ds

# --- Model Architecture ---

def build_model(image_size=(224, 224), embedding_dim=128):
    """Creates the multi-modal model."""

    # Image Input
    image_input = Input(shape=(image_size[0], image_size[1], 3))

    # Image Encoder
    image_encoder = tf.keras.applications.ResNet50(include_top=False, weights='imagenet', input_tensor=image_input, pooling='avg')

    # Textual Feature Extraction (Simplified for now, you could use a language model for real-world use)
    entity_name_input = Input(shape=(1,), dtype='string')
    entity_name_embedding = Embedding(input_dim=len(set(train['entity_name'])), output_dim=embedding_dim)(entity_name_input)
    entity_name_embedding = LSTM(embedding_dim)(entity_name_embedding)

    # Merge Image and Text Features
    merged_features = concatenate([image_encoder.output, entity_name_embedding])

    # Decoder
    decoder = Dense(128, activation='relu')(merged_features)
    decoder = Dense(64, activation='relu')(decoder)
    value_output = Dense(1, activation='linear', name='value_output')(decoder)  # Value prediction
    unit_output = Dense(len(constants.allowed_units), activation='softmax', name='unit_output')(decoder)  # Unit prediction

    # Model
    model = Model(inputs=[image_input, entity_name_input], outputs=[value_output, unit_output])

    return model

# --- Training ---

def train_model(train_ds, model, epochs=10):
    """Trains the model."""

    # Loss Functions
    value_loss = MeanSquaredError()  # MSE for value prediction
    unit_loss = CategoricalCrossentropy()  # Categorical cross-entropy for unit prediction

    # Optimizer
    optimizer = AdamW(learning_rate=0.001)

    # Metrics
    metrics = [
        Precision(name='precision'),
        Recall(name='recall'),
        F1Score(name='f1_score')
    ]

    # Compile the Model
    model.compile(
        optimizer=optimizer,
        loss={'value_output': value_loss, 'unit_output': unit_loss},
        metrics={'value_output': metrics, 'unit_output': metrics}
    )

    # Train the Model
    history = model.fit(
        train_ds, 
        epochs=epochs, 
        validation_data=None,  # You can add validation data if you want
        verbose=1,
        callbacks=[
            keras.callbacks.EarlyStopping(monitor='val_loss', patience=3, restore_best_weights=True),
            keras.callbacks.ModelCheckpoint('best_model.h5', save_best_only=True)
        ]
    )

    return model, history

# --- Main Execution ---

if __name__ == "__main__":
    # Load Data
    start_time = time.time()
    train_ds = load_and_preprocess_data('../dataset/train.csv', batch_size=64)
    end_time = time.time()
    logger.info(f"Data Loading Time: {end_time - start_time} seconds")

    # Build Model
    model = build_model()

    # Train Model
    start_time = time.time()
    model, history = train_model(train_ds, model, epochs=10)
    end_time = time.time()
    logger.info(f"Training Time: {end_time - start_time} seconds")

    # Save the Model (Optional)
    model.save('trained_model')

    # ... (Continue to section 3 for testing)
Use code with caution.
Python
2. test.py (Testing with Logging & Optimization)
import tensorflow as tf
from tensorflow.keras.models import load_model
import pandas as pd
import os
import numpy as np
from utils import download_images, parse_string
import constants
import logging
import time

# --- Logging Setup ---
logging.basicConfig(filename='testing.log', level=logging.INFO,
                    format='%(asctime)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)

# --- Load Model and Data ---

def load_model_and_data(model_path, test_data_path, image_size=(224, 224)):
    """Loads the trained model and test data."""

    model = load_model(model_path)
    test_data = pd.read_csv(test_data_path)
    image_links = test_data['image_link'].values
    entity_names = test_data['entity_name'].values

    # Download Images
    download_folder = '../images'
    download_images(image_links, download_folder)

    # Load and pre-process images
    def load_image(image_path):
        image = tf.keras.preprocessing.image.load_img(image_path, target_size=image_size)
        image = tf.keras.preprocessing.image.img_to_array(image)
        return image / 255.0

    images = []
    for i, image_link in enumerate(image_links):
        image_path = os.path.join(download_folder, os.path.basename(image_link))
        try:
            image = load_image(image_path)
            images.append(image)
        except:
            images.append(np.zeros((image_size[0], image_size[1], 3)))

    images = np.array(images)

    # One-hot encode units
    units = []
    for entity_name in entity_names:
        units.append(to_categorical(list(constants.allowed_units).index(entity_name), num_classes=len(constants.allowed_units)))
    units = np.array(units)

    return model, images, entity_names, test_data['index'].values

# --- Make Predictions ---

def make_predictions(model, images, entity_names, indices):
    """Generates predictions on the test data."""

    predictions = model.predict([images, entity_names])
    predicted_values = predictions[0].flatten()
    predicted_units = np.argmax(predictions[1], axis=1)
    predicted_units = [list(constants.allowed_units)[i] for i in predicted_units]

    # Combine predictions into 'x unit' format
    formatted_predictions = []
    for value, unit in zip(predicted_values, predicted_units):
        formatted_predictions.append(f"{value:.2f} {unit}")  # Format to two decimal places

    predictions_df = pd.DataFrame({'index': indices, 'prediction': formatted_predictions})

    return predictions_df

# --- Main Execution ---

if __name__ == "__main__":
    model_path = 'trained_model'  # Path to your saved model
    test_data_path = '../dataset/test.csv'

    # Load Model and Data
    start_time = time.time()
    model, images, entity_names, indices = load_model_and_data(model_path, test_data_path)
    end_time = time.time()
    logger.info(f"Model and Data Loading Time: {end_time - start_time} seconds")

    # Make Predictions
    start_time = time.time()
    predictions_df = make_predictions(model, images, entity_names, indices)
    end_time = time.time()
    logger.info(f"Prediction Time: {end_time - start_time} seconds")

    # Save Predictions
    predictions_df.to_csv('test_out.csv', index=False)

    # Run Sanity Check
    !python sanity.py --test_filename ../dataset/test.csv --output_filename test_out.csv

is this optimised and good?

Problem Statement
Feature Extraction from Images
In this hackathon, the goal is to create a machine learning model that extracts entity values from images. This capability is crucial in fields like healthcare, e-commerce, and content moderation, where precise product information is vital. As digital marketplaces expand, many products lack detailed textual descriptions, making it essential to obtain key details directly from images. These images provide important information such as weight, volume, voltage, wattage, dimensions, and many more, which are critical for digital stores.
Data Description:
The dataset consists of the following columns:
index: A unique identifier (ID) for the data sample.
image_link: Public URL where the product image is available for download. Example link - https://m.media-amazon.com/images/I/71XfHPR36-L.jpg To download images, use the download_images function from src/utils.py. See sample code in src/test.ipynb.
group_id: Category code of the product.
entity_name: Product entity name. For example, “item_weight”.
entity_value: Product entity value. For example, “34 gram”.
Note: For test.csv, you will not see the column entity_value as it is the target variable.
Output Format:
The output file should be a CSV with 2 columns:
index: The unique identifier (ID) of the data sample. Note that the index should match the test record index.
prediction: A string which should have the following format: “x unit” where x is a float number in standard formatting and unit is one of the allowed units (allowed units are mentioned in the Appendix). The two values should be concatenated and have a space between them.
For example: “2 gram”, “12.5 centimetre”, “2.56 ounce” are valid.
Invalid cases: “2 gms”, “60 ounce/1.7 kilogram”, “2.2e2 kilogram”, etc.
Note: Make sure to output a prediction for all indices. If no value is found in the image for any test sample, return an empty string, i.e., “”. If you have less/more number of output samples in the output file as compared to test.csv, your output won’t be evaluated.
File Descriptions:
Source Files:
src/sanity.py: Sanity checker to ensure that the final output file passes all formatting checks.
Note: The script will not check if fewer/more number of predictions are present compared to the test file. See sample code in src/test.ipynb.
src/utils.py: Contains helper functions for downloading images from the image_link.
src/constants.py: Contains the allowed units for each entity type.
sample_code.py: A sample dummy code that can generate an output file in the given format. Usage of this file is optional.
Dataset Files:
dataset/train.csv: Training file with labels (entity_value).
dataset/test.csv: Test file without output labels (entity_value). Generate predictions using your model/solution on this file's data and format the output file to match sample_test_out.csv (Refer to the "Output Format" section above).
dataset/sample_test.csv: Sample test input file.
dataset/sample_test_out.csv: Sample outputs for sample_test.csv. The output for test.csv must be formatted in the exact same way.
Note: The predictions in the file might not be correct.
Constraints:
You will be provided with a sample output file and a sanity checker file. Format your output to match the sample output file exactly and pass it through the sanity checker to ensure its validity.
Note: If the file does not pass through the sanity checker, it will not be evaluated. You should receive a message like Parsing successful for file: ...csv if the output file is correctly formatted.
You are given the list of allowed units in constants.py and also in the Appendix. Your outputs must be in these units. Predictions using any other units will be considered invalid during validation.
Evaluation Criteria:
Submissions will be evaluated based on the F1 score, which is a standard measure of prediction accuracy for classification and extraction problems.
Let GT = Ground truth value for a sample and OUT be the output prediction from the model for a sample. Then we classify the predictions into one of the 4 classes with the following logic:
True Positives: If OUT != "" and GT != "" and OUT == GT
False Positives: If OUT != "" and GT != "" and OUT != GT
False Positives: If OUT != "" and GT == ""
False Negatives: If OUT == "" and GT != ""
True Negatives: If OUT == "" and GT == ""
Then,
F1 score = 2 * Precision * Recall / (Precision + Recall)
where:
Precision = True Positives / (True Positives + False Positives)
Recall = True Positives / (True Positives + False Negatives)
Submission File:
Upload a test_out.csv file in the portal with the exact same formatting as sample_test_out.csv.
image_link,group_id,entity_name,entity_value
https://m.media-amazon.com/images/I/61I9XdN6OFL.jpg,748919,item_weight,500.0 gram
https://m.media-amazon.com/images/I/71gSRbyXmoL.jpg,916768,item_volume,1.0 cup
this is the input csv and i've attached the images as you can see they haven't explicitly mentioned item_weight or item_volume but it is mentioned somewhere
now how do i train a model which detectes this now
i have a training data of more than 2,00,000 entries and test_data of 1,00,000 entries and people have completed this with f1 score >0.98 i want to attain atleast 0.7 how to do it?