diff --git a/pre-preparation/condenser.py b/pre-preparation/condenser.py index 2caef17..6f45680 100644 --- a/pre-preparation/condenser.py +++ b/pre-preparation/condenser.py @@ -39,25 +39,33 @@ def condenser(spreadsheets, with_images): # Remove rows with all NaN values merged_data.dropna(how='all', axis=1, inplace=True) - if with_images: + if not with_images: + # If images are not requested, include rows with image paths containing 'images/wee/' and 'images/no-image2/' + df_without_images = pd.concat([merged_data[merged_data['image-id'].str.contains('images/wee/Fig')], + merged_data[merged_data['image-id'].str.contains('images/no-image2/')], + merged_data[merged_data['image-id'].str.contains('to')], + merged_data[merged_data['image-id'].str.contains('and')]], + ignore_index=True) + + # Return the DataFrame without images + return df_without_images + + else: # If images are requested, filter rows with image paths containing 'images/wee/' - df_with_images = merged_data[merged_data['image-id'].str.contains('images/wee/')] + df_with_images = merged_data[ + merged_data['image-id'].str.contains('images/wee/') & ~merged_data['image-id'].str.contains( + 'images/wee/Fig')] - # Extract a cleaned-up ID from the 'image-id' column - df_with_images['cleaned_id'] = df_with_images['image-id'].str.extract(r'images/wee/(\d+_\d+)\.jpg') - - # Drop the original 'image-id' column - df_with_images.drop(columns=['image-id'], inplace=True) + # Extract the cleaned ID and extension from the 'image-id' column + df_with_images[['cleaned_id', 'extension']] = df_with_images['image-id'].str.extract( + r'images/wee/(\d+_\d+)_?\d*\.(jpg|tif|jpeg)') + # Drop the original 'image-id' column and the 'extension' column + df_with_images.drop(columns=['image-id', 'extension'], inplace=True) + df_with_images = df_with_images[df_with_images['cleaned_id'] != ''] # Return the DataFrame with images return df_with_images - # If images are not requested, filter rows with image paths containing 'images/no-image2' - df_without_images = merged_data[merged_data['image-id'].str.contains('images/no-image2')] - - # Return the DataFrame without images - return df_without_images - if __name__ == "__main__": # Set up command-line argument parser diff --git a/pre-preparation/reformatter.py b/pre-preparation/reformatter.py index d4e2986..d6ffece 100644 --- a/pre-preparation/reformatter.py +++ b/pre-preparation/reformatter.py @@ -44,6 +44,7 @@ def data_reformatter(df, training_data): formatted_df[tag] = filtered_df.apply(lambda row: 1 if tag in row.values else 0, axis=1) formatted_df = duplicate_cleanser(formatted_df) + formatted_df = formatted_df[formatted_df['image_id'] != 'nan.png'] return formatted_df diff --git a/requirements.txt b/requirements.txt index 2bfa3d5..4118243 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,6 @@ pandas~=2.2.1 openpyxl~=3.1.2 -pillow~=10.2.0 \ No newline at end of file +pillow~=10.2.0 +numpy~=1.26.4 +tensorflow~=2.16.1 +scikit-learn~=1.4.1.post1 \ No newline at end of file diff --git a/training.py b/training.py new file mode 100644 index 0000000..a2a1716 --- /dev/null +++ b/training.py @@ -0,0 +1,97 @@ +import sys +import os +import numpy as np +import matplotlib.pyplot as plt +from tensorflow.keras.preprocessing.image import img_to_array, load_img +from tensorflow.keras.models import Sequential +from tensorflow.keras.layers import Conv2D, MaxPooling2D, Flatten, Dense, Dropout +from tensorflow.keras.optimizers import Adam +from sklearn.model_selection import train_test_split + +sys.path.append('pre-preparation') +import reformatter +import condenser + +# Load your dataset +data = condenser.condenser('pre-preparation/dataset/unformatted/spreadsheets/*.xlsx', with_images=True) +data = reformatter.data_reformatter(data, True) + +# Define image processing parameters +image_size = (128, 128) + + +# Function to load and preprocess an image +def preprocess_image(image_path, target_size): + image = load_img(image_path, target_size=target_size) + image = img_to_array(image) / 255.0 # Normalize to [0, 1] + return image + + +# Set the base path to the image folder +base_image_path = 'pre-preparation/dataset/formatted/images/' + +# Initialize lists for images and labels +images = [] +valid_labels = [] + +# Preprocess all images and collect valid labels +for index, row in data.iterrows(): + image_id = row['image_id'] + img_path = os.path.join(base_image_path, image_id) + if os.path.exists(img_path): + img = preprocess_image(img_path, image_size) + images.append(img) + + # Ensure labels are binary (0 or 1) + labels = row.drop('image_id').values + labels = np.array(labels > 0.5, dtype=int) # Convert to 0 or 1 if binary + valid_labels.append(labels) + print(f"Image {image_id} processed") + else: + print(f"Image {image_id} not found, skipping...") + +# Convert lists of images and labels to numpy arrays +images = np.array(images, dtype='float32') +valid_labels = np.array(valid_labels, dtype='int32') + +# Visualize some samples +for i in range(5): + plt.imshow(images[i]) + plt.title(f"Label: {valid_labels[i]}") + plt.show() + +# Split the data +X_train, X_val, y_train, y_val = train_test_split(images, valid_labels, test_size=0.2, random_state=42) + +# Build a simpler model +model = Sequential([ + Conv2D(32, (3, 3), activation='relu', input_shape=(128, 128, 3)), + MaxPooling2D((2, 2)), + Dropout(0.3), + + Conv2D(64, (3, 3), activation='relu'), + MaxPooling2D((2, 2)), + Dropout(0.3), + + Flatten(), + Dense(128, activation='relu'), + Dropout(0.5), + Dense(valid_labels.shape[1], activation='sigmoid') +]) + +# Compile the model with a lower learning rate +model.compile(optimizer=Adam(learning_rate=1e-5), + loss='binary_crossentropy', + metrics=['accuracy']) + +print(model.summary()) + +# Train the simpler model +history = model.fit(X_train, y_train, epochs=30, validation_data=(X_val, y_val), batch_size=32) + +# Calculate final accuracy +train_accuracy_percentage = history.history['accuracy'][-1] * 100 +validation_accuracy_percentage = history.history['val_accuracy'][-1] * 100 + +print("Train Accuracy:", train_accuracy_percentage, "%") +print("Validation Accuracy:", validation_accuracy_percentage, "%")