lyffseba commited on
Commit
9a56540
·
verified ·
1 Parent(s): 17c0e08

Upload main.ipynb

Browse files

Model Architecture Description

🧠 Dual CNN Architecture for Interpretable Music Genre Classification

Model 1: Batch Normalization CNN (bn_model)
Architecture Overview:
• Base Model: ResNet152V2 pre-trained on ImageNet
• Input Shape: (300, 300, 3) RGB images
• Transfer Learning: Feature extraction + fine-tuning approach

Layer Architecture:
1. Feature Extractor: ResNet152V2 (frozen initially, then fine-tuned from conv5_block3_preact_bn)
2. Global Pooling: GlobalMaxPooling2D for spatial dimension reduction
3. Dense Layer 1: 512 neurons + ReLU + L1 regularization (0.01)
4. Dropout 1: 30% dropout for regularization
5. Dense Layer 2: 256 neurons + ReLU + L1 regularization (0.01)
6. Dropout 2: 30% dropout for regularization
7. Dense Layer 3: 128 neurons + ReLU + L1 regularization (0.01)
8. Dropout 3: 30% dropout for regularization
9. Output Layer: 3 neurons + Softmax for multi-class classification

Model 2: Concept Whitening CNN (cw_model)
Architecture Overview:
• Base Model: ResNet152V2 pre-trained on ImageNet
• Novel Component: Custom Concept Whitening layer for interpretability
• Input Shape: (300, 300, 3) RGB images

Layer Architecture:
1. Feature Extractor: ResNet152V2 (frozen initially, then fine-tuned from conv5_block3_preact_cw)
2. 🔬 Concept Whitening Layer: Custom interpretability layer performing:
• Covariance matrix computation of input activations
• Singular Value Decomposition (SVD) for whitening matrix calculation
• Feature decorrelation and normalization for enhanced interpretability
3. Global Pooling: GlobalMaxPooling2D for spatial dimension reduction
4. Dense Layer 1: 512 neurons + ReLU + L1 regularization (0.01)
5. Dropout 1: 30% dropout for regularization
6. Dense Layer 2: 256 neurons + ReLU + L1 regularization (0.01)
7. Dropout 2: 30% dropout for regularization
8. Dense Layer 3: 128 neurons + ReLU + L1 regularization (0.01)
9. Dropout 3: 30% dropout for regularization
10. Output Layer: 3 neurons + Softmax for multi-class classification

Training Configuration:
Optimizer: RMSprop (learning_rate=1e-4)
Loss Function: Categorical Crossentropy
Callbacks:
• Learning Rate Scheduler (step decay)
• ReduceLROnPlateau (factor=0.6, patience=8)
• ModelCheckpoint (save best model)
• EarlyStopping (patience=5)

Key Innovations:
🎯 Concept Whitening Layer Features:
• Interpretability: Makes CNN decision-making process more transparent
• Mathematical Foundation: SVD-based feature decorrelation
• Real-time Processing: Applied during forward pass without additional inference cost
• Research Contribution: Novel approach to explainable AI in music genre classification

Model Comparison:
• Performance: Both models achieve competitive accuracy on vinyl album cover classification
• Interpretability: Concept Whitening model provides enhanced feature visualization and understanding
• Architecture: Identical except for the custom whitening layer insertion
• Research Value: Empirical comparison of accuracy vs. interpretability trade-offs in deep learning

Files changed (1) hide show
  1. main.ipynb +840 -0
main.ipynb ADDED
@@ -0,0 +1,840 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "markdown",
5
+ "source": [
6
+ "# Interpretable Music Genre Classification Using Whitened Artwork Concepts\n"
7
+ ],
8
+ "metadata": {
9
+ "id": "3tvGZXi_DJUt"
10
+ }
11
+ },
12
+ {
13
+ "cell_type": "markdown",
14
+ "metadata": {
15
+ "id": "bM1UyWDzs-Nt"
16
+ },
17
+ "source": [
18
+ "## requirements.txt\n"
19
+ ]
20
+ },
21
+ {
22
+ "cell_type": "code",
23
+ "execution_count": null,
24
+ "metadata": {
25
+ "id": "uHQBlPYKibjR"
26
+ },
27
+ "outputs": [],
28
+ "source": [
29
+ "# Importing libraries\n",
30
+ "import os\n",
31
+ "import random\n",
32
+ "import numpy as np\n",
33
+ "import tensorflow as tf\n",
34
+ "import math\n",
35
+ "import matplotlib.pyplot as plt\n",
36
+ "import shutil\n",
37
+ "import pandas as pd\n",
38
+ "from sklearn.model_selection import train_test_split\n",
39
+ "from tensorflow.keras import layers\n",
40
+ "from tensorflow.keras import models\n",
41
+ "from keras.preprocessing.image import ImageDataGenerator\n",
42
+ "from tensorflow.keras.applications import ResNet152V2\n",
43
+ "from tensorflow.keras import regularizers\n",
44
+ "from tensorflow.keras.callbacks import LearningRateScheduler\n",
45
+ "from keras.callbacks import ReduceLROnPlateau, ModelCheckpoint, EarlyStopping\n",
46
+ "import keras\n"
47
+ ]
48
+ },
49
+ {
50
+ "cell_type": "code",
51
+ "execution_count": null,
52
+ "metadata": {
53
+ "id": "C4MUfWGXmJVU"
54
+ },
55
+ "outputs": [],
56
+ "source": [
57
+ "# Set matplotlib to inline mode\n",
58
+ "%matplotlib inline\n",
59
+ "\n",
60
+ "# Seed value definition\n",
61
+ "def set_seed(seed=42):\n",
62
+ " \"\"\"Set seed for reproducibility.\"\"\"\n",
63
+ " os.environ['PYTHONHASHSEED'] = str(seed)\n",
64
+ " random.seed(seed)\n",
65
+ " np.random.seed(seed)\n",
66
+ " tf.random.set_seed(seed)\n",
67
+ "\n",
68
+ "# Call the function with the desired seed\n",
69
+ "set_seed(42)\n"
70
+ ]
71
+ },
72
+ {
73
+ "cell_type": "markdown",
74
+ "source": [
75
+ "## dataset_preparation.py"
76
+ ],
77
+ "metadata": {
78
+ "id": "yeKy3Wk3Ciyo"
79
+ }
80
+ },
81
+ {
82
+ "cell_type": "code",
83
+ "execution_count": null,
84
+ "metadata": {
85
+ "id": "1_Mh5OHKmJVU"
86
+ },
87
+ "outputs": [],
88
+ "source": [
89
+ "# Specify paths to the datasets\n",
90
+ "original_dataset_directory = \"/content/drive/MyDrive/documentos/vinyl genre class/data/For thesis\"\n",
91
+ "original_train_directory = os.path.join(original_dataset_directory, 'Training')\n"
92
+ ]
93
+ },
94
+ {
95
+ "cell_type": "code",
96
+ "execution_count": null,
97
+ "metadata": {
98
+ "id": "WrWwgb3PmJVV"
99
+ },
100
+ "outputs": [],
101
+ "source": [
102
+ "# 0 for electronic, 1 for rock, 2 for hiphop\n",
103
+ "# Initialize lists to store genres and image files\n",
104
+ "genres = []\n",
105
+ "img_files= []\n",
106
+ "\n",
107
+ "# List all files in the training directory\n",
108
+ "imgs = os.listdir(original_train_directory)\n",
109
+ "\n",
110
+ "# Load training labels from CSV\n",
111
+ "training_lbls = pd.read_csv('/content/drive/MyDrive/documentos/vinyl genre class/data/For thesis/training_labels.csv')\n",
112
+ "\n",
113
+ "# Loop through all labels and append corresponding genres and image files to the lists\n",
114
+ "for k in range(len(training_lbls)):\n",
115
+ " for file in imgs:\n",
116
+ " if file == training_lbls['name'][k]:\n",
117
+ " genres.append(training_lbls['category'][k])\n",
118
+ " img_files.append(file)\n",
119
+ "\n",
120
+ "# Create a dataframe to map each image with its label\n",
121
+ "df = pd.DataFrame({'image': img_files,'category':genres})\n",
122
+ "\n",
123
+ "# Display the first few rows of the dataframe\n",
124
+ "df.head(min(3000, len(df)))\n"
125
+ ]
126
+ },
127
+ {
128
+ "cell_type": "code",
129
+ "execution_count": null,
130
+ "metadata": {
131
+ "id": "5MuUMX0QWAMp"
132
+ },
133
+ "outputs": [],
134
+ "source": [
135
+ "# Define directories for train, test and validation datasets\n",
136
+ "base_dir = \"./data_split\"\n",
137
+ "train_dir = os.path.join(base_dir, 'train')\n",
138
+ "test_dir = os.path.join(base_dir, 'test')\n",
139
+ "validate_dir = os.path.join(base_dir, 'validate')\n",
140
+ "\n",
141
+ "# Create directories for train, test and validation datasets if they don't exist\n",
142
+ "for directory in [base_dir, train_dir, test_dir, validate_dir]:\n",
143
+ " if not os.path.exists(directory):\n",
144
+ " os.mkdir(directory)\n",
145
+ " print(directory, \"created\")\n",
146
+ "\n",
147
+ "# Define directories for each genre in train, test and validation datasets\n",
148
+ "subdirectories_electronic = []\n",
149
+ "subdirectories_rock = []\n",
150
+ "subdirectories_hiphop = []\n",
151
+ "\n",
152
+ "# Create directories for each genre in train, test and validation datasets if they don't exist\n",
153
+ "for subdirectory in [train_dir, test_dir, validate_dir]:\n",
154
+ " subdirectories_electronic.append(os.path.join(subdirectory,'electronic'))\n",
155
+ " if not os.path.exists(os.path.join(subdirectory,'electronic')):\n",
156
+ " os.mkdir(os.path.join(subdirectory,'electronic'))\n",
157
+ " print(os.path.join(subdirectory,'electronic'),\"created\")\n",
158
+ "\n",
159
+ " subdirectories_rock.append(os.path.join(subdirectory, 'rock'))\n",
160
+ " if not os.path.exists(os.path.join(subdirectory, 'rock')):\n",
161
+ " os.mkdir(os.path.join(subdirectory, 'rock'))\n",
162
+ " print(os.path.join(subdirectory, 'rock'), \"created\")\n",
163
+ "\n",
164
+ " subdirectories_hiphop.append(os.path.join(subdirectory,'hiphop'))\n",
165
+ " if not os.path.exists(os.path.join(subdirectory,'hiphop')):\n",
166
+ " os.mkdir(os.path.join(subdirectory,'hiphop'))\n",
167
+ " print(os.path.join(subdirectory,'hiphop'),\"created\")\n"
168
+ ]
169
+ },
170
+ {
171
+ "cell_type": "code",
172
+ "execution_count": null,
173
+ "metadata": {
174
+ "id": "fVJUacXowtzf"
175
+ },
176
+ "outputs": [],
177
+ "source": [
178
+ "# Split the data into train, test and validation sets\n",
179
+ "x_train, x_test1, y_train, y_test1 = train_test_split(df[\"image\"], df[\"category\"] ,test_size=0.2, random_state=42)\n",
180
+ "x_test, x_val, y_test, y_val = train_test_split(x_test1, y_test1 ,test_size=0.5, random_state=42)\n",
181
+ "\n",
182
+ "# Print the size of each set\n",
183
+ "print('Training data set size :', y_train.shape[0])\n",
184
+ "print('Test data set size :', y_test.shape[0])\n",
185
+ "print('Validation data set size :', y_val.shape[0])\n"
186
+ ]
187
+ },
188
+ {
189
+ "cell_type": "code",
190
+ "execution_count": null,
191
+ "metadata": {
192
+ "id": "X0EHWy1qxID_"
193
+ },
194
+ "outputs": [],
195
+ "source": [
196
+ "# Copy the files into the corresponding genre directories in train, test and validation datasets\n",
197
+ "x = [x_train,x_test,x_val]\n",
198
+ "y = [y_train,y_test,y_val]\n",
199
+ "k = 0\n",
200
+ "\n",
201
+ "for images,genres in zip(x,y) :\n",
202
+ " for (file,category) in zip(images,genres):\n",
203
+ " if category == 'electronic':\n",
204
+ " src = os.path.join(original_train_directory, file)\n",
205
+ " dst = os.path.join(subdirectories_electronic[k], file)\n",
206
+ " shutil.copyfile(src, dst)\n",
207
+ " elif category == 'rock':\n",
208
+ " src = os.path.join(original_train_directory, file)\n",
209
+ " dst = os.path.join(subdirectories_rock[k], file)\n",
210
+ " shutil.copyfile(src, dst)\n",
211
+ " else:\n",
212
+ " src = os.path.join(original_train_directory, file)\n",
213
+ " dst = os.path.join(subdirectories_hiphop[k], file)\n",
214
+ " shutil.copyfile(src, dst)\n",
215
+ "\n",
216
+ " print(len(os.listdir(subdirectories_electronic[k])), \" electronic covers copied to:\", subdirectories_electronic[k])\n",
217
+ " print(len(os.listdir(subdirectories_rock[k])), \" rock covers copies to:\", subdirectories_rock[k])\n",
218
+ " print(len(os.listdir(subdirectories_hiphop[k])), \" hiphop covers copied to:\", subdirectories_hiphop[k])\n",
219
+ "\n",
220
+ " k = k + 1\n"
221
+ ]
222
+ },
223
+ {
224
+ "cell_type": "code",
225
+ "execution_count": null,
226
+ "metadata": {
227
+ "id": "ZFldb7zIxgfj"
228
+ },
229
+ "outputs": [],
230
+ "source": [
231
+ "# Visualize training electronic images examples\n",
232
+ "plt.figure(figsize=(25,20))\n",
233
+ "plt.suptitle(\"Train Electronic Images\", fontsize=20)\n",
234
+ "\n",
235
+ "images = os.listdir(subdirectories_electronic[0])\n",
236
+ "for i in range(len(images)-20, len(images)):\n",
237
+ " plt.subplot(5,5,i-len(images)+20+1)\n",
238
+ "\n",
239
+ " full_image = plt.imread(os.path.join(original_train_directory, images[i]))\n",
240
+ " plt.xticks([])\n",
241
+ " plt.yticks([])\n",
242
+ " plt.grid(False)\n",
243
+ " plt.imshow(full_image, cmap=plt.cm.binary)\n"
244
+ ]
245
+ },
246
+ {
247
+ "cell_type": "code",
248
+ "execution_count": null,
249
+ "metadata": {
250
+ "id": "XVl8cEzY7lP6"
251
+ },
252
+ "outputs": [],
253
+ "source": [
254
+ "# Visualize training rock images examples\n",
255
+ "plt.figure(figsize=(25,20))\n",
256
+ "plt.suptitle(\" Train Rock Images\", fontsize=20)\n",
257
+ "\n",
258
+ "images = os.listdir(subdirectories_rock[0])\n",
259
+ "for i in range(len(images)-20, len(images)):\n",
260
+ " plt.subplot(5,5,i-len(images)+20+1)\n",
261
+ "\n",
262
+ " full_image = plt.imread(os.path.join(original_train_directory, images[i]))\n",
263
+ " plt.xticks([])\n",
264
+ " plt.yticks([])\n",
265
+ " plt.grid(False)\n",
266
+ " plt.imshow(full_image, cmap=plt.cm.binary)"
267
+ ]
268
+ },
269
+ {
270
+ "cell_type": "code",
271
+ "execution_count": null,
272
+ "metadata": {
273
+ "id": "nNizgXt9cw3U"
274
+ },
275
+ "outputs": [],
276
+ "source": [
277
+ "# Visualize training hiphop images examples\n",
278
+ "plt.figure(figsize=(25,20))\n",
279
+ "plt.suptitle(\"Train HipHop images\", fontsize=20)\n",
280
+ "\n",
281
+ "images = os.listdir(subdirectories_hiphop[0])\n",
282
+ "for i in range(len(images)-20, len(images)):\n",
283
+ " plt.subplot(5,5,i-len(images)+20+1)\n",
284
+ "\n",
285
+ " full_image = plt.imread(os.path.join(original_train_directory, images[i]))\n",
286
+ " plt.xticks([])\n",
287
+ " plt.yticks([])\n",
288
+ " plt.grid(False)\n",
289
+ " plt.imshow(full_image, cmap=plt.cm.binary)"
290
+ ]
291
+ },
292
+ {
293
+ "cell_type": "code",
294
+ "execution_count": null,
295
+ "metadata": {
296
+ "id": "nqYNkhrb9EKS"
297
+ },
298
+ "outputs": [],
299
+ "source": [
300
+ "# Create ImageDataGenerators for training and validation datasets\n",
301
+ "# ImageDataGenerators are used to generate batches of tensor image data with real-time data augmentation\n",
302
+ "train_datagen = ImageDataGenerator(rescale=1./255)\n",
303
+ "test_datagen = ImageDataGenerator(rescale=1./255)\n",
304
+ "\n",
305
+ "# Define target size for resizing images and batch size\n",
306
+ "# Class mode is set to 'categorical' for multi-class classification\n",
307
+ "train_generator = train_datagen.flow_from_directory(\n",
308
+ " train_dir,\n",
309
+ " target_size=(300,300),\n",
310
+ " batch_size=20,\n",
311
+ " class_mode='categorical')\n",
312
+ "\n",
313
+ "validation_generator = test_datagen.flow_from_directory(\n",
314
+ " validate_dir,\n",
315
+ " target_size=(300,300),\n",
316
+ " batch_size=20,\n",
317
+ " class_mode='categorical')\n",
318
+ "\n",
319
+ "# Print the shapes of data and labels batches to confirm they are as expected\n",
320
+ "for data_batch, labels_batch in train_generator:\n",
321
+ " print('data batch shape:', data_batch.shape)\n",
322
+ " print('labels batch shape:', labels_batch.shape)\n",
323
+ " break\n"
324
+ ]
325
+ },
326
+ {
327
+ "cell_type": "markdown",
328
+ "metadata": {
329
+ "id": "jR58jYwFmJVX"
330
+ },
331
+ "source": [
332
+ "## model_without_whitening.py"
333
+ ]
334
+ },
335
+ {
336
+ "cell_type": "code",
337
+ "execution_count": null,
338
+ "metadata": {
339
+ "id": "ZnCSZKVYmJVX"
340
+ },
341
+ "outputs": [],
342
+ "source": [
343
+ "# Import ResNet152v2 pre-trained model with ImageNet weights\n",
344
+ "from tensorflow.keras.applications import ResNet152V2\n",
345
+ "\n",
346
+ "# 1. ResNet152V2: Utilizes a pre-trained architecture to initialize weights, aiding in feature extraction.\n",
347
+ "pre_trained_model = ResNet152V2(weights='imagenet', include_top=False, input_shape=(300, 300, 3))\n",
348
+ "pre_trained_model.summary()"
349
+ ]
350
+ },
351
+ {
352
+ "cell_type": "code",
353
+ "execution_count": null,
354
+ "metadata": {
355
+ "id": "D0apnmP_Cys9"
356
+ },
357
+ "outputs": [],
358
+ "source": [
359
+ "# Set all pre-trained model layers to non-trainable\n",
360
+ "for layer in pre_trained_model.layers:\n",
361
+ " layer.trainable = False\n",
362
+ "\n",
363
+ "# Define the custom neural network architecture\n",
364
+ "last_layer = pre_trained_model.get_layer('post_relu')\n",
365
+ "last_output = last_layer.output\n",
366
+ "\n",
367
+ "# 2. GlobalMaxPooling2D: Reduces the spatial dimensions of the output volume.\n",
368
+ "x = tf.keras.layers.GlobalMaxPooling2D()(last_output)\n",
369
+ "\n",
370
+ "# 3. Dense 512 and ReLU Activation: Fully connected layer with 512 neurons and ReLU activation for non-linearity.\n",
371
+ "x = tf.keras.layers.Dense(512, activation='relu', kernel_regularizer=regularizers.l1(0.01))(x)\n",
372
+ "\n",
373
+ "# 4. Dropout 0.3: Prevents overfitting by randomly setting a fraction of input units to 0 during training.\n",
374
+ "x = tf.keras.layers.Dropout(0.3)(x)\n",
375
+ "\n",
376
+ "# 5. Dense 256 and ReLU Activation: Another fully connected layer with 256 neurons and ReLU activation.\n",
377
+ "x = tf.keras.layers.Dense(256, activation='relu', kernel_regularizer=regularizers.l1(0.01))(x)\n",
378
+ "\n",
379
+ "# 6. Dropout 0.3: Another dropout layer for regularization.\n",
380
+ "x = tf.keras.layers.Dropout(0.3)(x)\n",
381
+ "\n",
382
+ "# 7. Dense 128 and ReLU Activation: Further fully connected layer with 128 neurons for feature transformation.\n",
383
+ "x = tf.keras.layers.Dense(128, activation='relu', kernel_regularizer=regularizers.l1(0.01))(x)\n",
384
+ "\n",
385
+ "# 8. Dropout 0.3: Final dropout layer to counteract overfitting.\n",
386
+ "x = tf.keras.layers.Dropout(0.3)(x)\n",
387
+ "\n",
388
+ "# 9. Dense 3 and Softmax Activation: Output layer with 3 neurons corresponding to the classes, with softmax activation for probability distribution.\n",
389
+ "x = tf.keras.layers.Dense(3, activation='softmax')(x)\n",
390
+ "\n",
391
+ "# Combine the pre-trained model with the additional layers to complete the architecture\n",
392
+ "bn_model = tf.keras.Model(pre_trained_model.input, x)\n",
393
+ "bn_model.summary()\n",
394
+ "\n"
395
+ ]
396
+ },
397
+ {
398
+ "cell_type": "code",
399
+ "execution_count": null,
400
+ "metadata": {
401
+ "id": "6EErvH34HK0K"
402
+ },
403
+ "outputs": [],
404
+ "source": [
405
+ "# Open trainable layers\n",
406
+ "pre_trained_model.trainable = True\n",
407
+ "set_trainable = False\n",
408
+ "for layer in pre_trained_model.layers:\n",
409
+ " if layer.name == 'conv5_block3_preact_bn':\n",
410
+ " set_trainable = True\n",
411
+ " if set_trainable:\n",
412
+ " layer.trainable = True\n",
413
+ " else:\n",
414
+ " layer.trainable = False\n",
415
+ "\n",
416
+ "# Define the learning rate scheduler function\n",
417
+ "def lr_scheduler(epoch):\n",
418
+ " lr = 1e-4\n",
419
+ " if epoch > 10:\n",
420
+ " lr *= 0.1\n",
421
+ " if epoch > 20:\n",
422
+ " lr *= 0.1\n",
423
+ " return lr\n",
424
+ "\n",
425
+ "# Set up callback functions\n",
426
+ "lr_scheduler_callback = LearningRateScheduler(lr_scheduler)\n",
427
+ "lr_reduce = ReduceLROnPlateau(monitor='val_accuracy', factor=0.6, patience=8, verbose=1, mode='max', min_lr=1e-4)\n",
428
+ "checkpoint = ModelCheckpoint('bn_finetune.h16', monitor='val_accuracy', mode='max', save_best_only=True, verbose=1)\n",
429
+ "early_stopping = EarlyStopping(monitor='val_accuracy', min_delta=0, patience=5, verbose=1, mode='max')\n",
430
+ "\n",
431
+ "# Compile the model\n",
432
+ "# This step prepares the model for training.\n",
433
+ "# It specifies the optimizer to update model weights, the loss function to evaluate performance,\n",
434
+ "# and the metric to monitor during training.\n",
435
+ "bn_model.compile(\n",
436
+ " optimizer=tf.keras.optimizers.RMSprop(learning_rate=1e-4), # RMSprop optimizer with a learning rate of 1e-4\n",
437
+ " loss='categorical_crossentropy', # categorical cross-entropy for multi-class classification\n",
438
+ " metrics=['accuracy'] # Monitoring accuracy during training\n",
439
+ ")\n",
440
+ "\n",
441
+ "# Train the model\n",
442
+ "# This step starts the training process by feeding the data into the model.\n",
443
+ "bn_history = bn_model.fit(\n",
444
+ " train_generator, # Using the training data generator\n",
445
+ " epochs=10, # Training for 10 complete passes through the training dataset\n",
446
+ " validation_data=validation_generator, # Using the validation data generator\n",
447
+ " validation_steps=len(validation_generator), # Number of batches to draw from the validation generator for evaluation\n",
448
+ " callbacks=[lr_reduce, checkpoint, early_stopping, lr_scheduler_callback] # Applying various callback functions\n",
449
+ ")\n"
450
+ ]
451
+ },
452
+ {
453
+ "cell_type": "markdown",
454
+ "source": [
455
+ "## model_with_whitening.py\n"
456
+ ],
457
+ "metadata": {
458
+ "id": "AFaWtJySUqej"
459
+ }
460
+ },
461
+ {
462
+ "cell_type": "code",
463
+ "source": [
464
+ "# Create custome Keras layer for concept whitening\n",
465
+ "class ConceptWhitening(tf.keras.layers.Layer):\n",
466
+ " def __init__(self, epsilon=1e-5, **kwargs):\n",
467
+ " super(ConceptWhitening, self).__init__(**kwargs)\n",
468
+ " self.epsilon = epsilon\n",
469
+ "\n",
470
+ " def build(self, input_shape):\n",
471
+ " super(ConceptWhitening, self).build(input_shape)\n",
472
+ "\n",
473
+ " def call(self, inputs):\n",
474
+ " # Compute the covariance matrix of the input activations\n",
475
+ " mean = tf.reduce_mean(inputs, axis=[0, 1, 2], keepdims=True)\n",
476
+ " centered_inputs = inputs - mean\n",
477
+ " cov_matrix = tf.reduce_mean(tf.einsum('bijc,bijd->bcd', centered_inputs, centered_inputs), axis=0)\n",
478
+ "\n",
479
+ " # Compute the whitening matrix\n",
480
+ " s, u, v = tf.linalg.svd(cov_matrix)\n",
481
+ " whitening_matrix = tf.einsum('bi,bj->bij', tf.math.rsqrt(tf.reshape(s, [-1, 1]) + self.epsilon), u)\n",
482
+ "\n",
483
+ " # Squeeze out the singleton dimension\n",
484
+ " whitening_matrix = tf.squeeze(whitening_matrix, axis=1)\n",
485
+ "\n",
486
+ " # Apply the whitening transformation\n",
487
+ " whitened_inputs = tf.einsum('bijc,bd,de->bije', centered_inputs, u, whitening_matrix)\n",
488
+ "\n",
489
+ " # Debugging: Print the shape of the centered inputs for verification\n",
490
+ " print(\"Shape of centered_inputs:\", tf.shape(centered_inputs))\n",
491
+ "\n",
492
+ " # Debugging: Print the shape of 'u' to ensure it's as expected\n",
493
+ " print(\"Shape of u:\", tf.shape(u))\n",
494
+ "\n",
495
+ " # Debugging: Print the shape of the whitening matrix for validation\n",
496
+ " print(\"Shape of whitening_matrix:\", tf.shape(whitening_matrix))\n",
497
+ "\n",
498
+ " return whitened_inputs\n",
499
+ "\n",
500
+ " def get_config(self):\n",
501
+ " config = super(ConceptWhitening, self).get_config()\n",
502
+ " config.update({\"epsilon\": self.epsilon})\n",
503
+ " return config"
504
+ ],
505
+ "metadata": {
506
+ "id": "yatkMSAqUtRt"
507
+ },
508
+ "execution_count": null,
509
+ "outputs": []
510
+ },
511
+ {
512
+ "cell_type": "code",
513
+ "source": [
514
+ "# Import ResNet152v2 pre trained model with imagenet weights\n",
515
+ "from tensorflow.keras.applications import ResNet152V2\n",
516
+ "from tensorflow.keras import regularizers\n",
517
+ "\n",
518
+ "# Import your pre-trained model\n",
519
+ "pre_trained_model = ResNet152V2(weights='imagenet', include_top=False, input_shape=(300, 300, 3))\n",
520
+ "\n",
521
+ "# Make all layers non-trainable\n",
522
+ "for layer in pre_trained_model.layers:\n",
523
+ " layer.trainable = False\n",
524
+ "\n",
525
+ "# Get the last layer's output\n",
526
+ "last_layer = pre_trained_model.get_layer('post_relu')\n",
527
+ "last_output = last_layer.output\n",
528
+ "\n",
529
+ "# Insert the Concept Whitening layer\n",
530
+ "x = ConceptWhitening()(last_output)\n",
531
+ "\n",
532
+ "# Add your additional layers\n",
533
+ "x = tf.keras.layers.GlobalMaxPooling2D()(x)\n",
534
+ "x = tf.keras.layers.Dense(512, activation='relu', kernel_regularizer=regularizers.l1(0.01))(x)\n",
535
+ "x = tf.keras.layers.Dropout(0.3)(x)\n",
536
+ "x = tf.keras.layers.Dense(256, activation='relu', kernel_regularizer=regularizers.l1(0.01))(x)\n",
537
+ "x = tf.keras.layers.Dropout(0.3)(x)\n",
538
+ "x = tf.keras.layers.Dense(128, activation='relu', kernel_regularizer=regularizers.l1(0.01))(x)\n",
539
+ "x = tf.keras.layers.Dropout(0.3)(x)\n",
540
+ "x = tf.keras.layers.Dense(3, activation='softmax')(x)\n",
541
+ "\n",
542
+ "# Create the final model\n",
543
+ "cw_model = tf.keras.Model(pre_trained_model.input, x)\n",
544
+ "cw_model.summary()"
545
+ ],
546
+ "metadata": {
547
+ "id": "O_F93p9QVFnJ"
548
+ },
549
+ "execution_count": null,
550
+ "outputs": []
551
+ },
552
+ {
553
+ "cell_type": "code",
554
+ "source": [
555
+ "# Open trainable layers\n",
556
+ "pre_trained_model.trainable = True\n",
557
+ "set_trainable = False\n",
558
+ "for layer in pre_trained_model.layers:\n",
559
+ " if layer.name == 'conv5_block3_preact_cw':\n",
560
+ " set_trainable = True\n",
561
+ " if set_trainable:\n",
562
+ " layer.trainable = True\n",
563
+ " else:\n",
564
+ " layer.trainable = False\n",
565
+ "\n",
566
+ "# Define the learning rate scheduler function\n",
567
+ "def lr_scheduler(epoch):\n",
568
+ " lr = 1e-4\n",
569
+ " if epoch > 10:\n",
570
+ " lr *= 0.1\n",
571
+ " if epoch > 20:\n",
572
+ " lr *= 0.1\n",
573
+ " return lr\n",
574
+ "\n",
575
+ "# Set up callback functions\n",
576
+ "lr_scheduler_callback = LearningRateScheduler(lr_scheduler)\n",
577
+ "lr_reduce = ReduceLROnPlateau(monitor='val_accuracy', factor=0.6, patience=8, verbose=1, mode='max', min_lr=1e-4)\n",
578
+ "checkpoint = ModelCheckpoint('cw_finetune.h16', monitor='val_accuracy', mode='max', save_best_only=True, verbose=1)\n",
579
+ "early_stopping = EarlyStopping(monitor='val_accuracy', min_delta=0, patience=5, verbose=1, mode='max')\n",
580
+ "\n",
581
+ "# Compile the model\n",
582
+ "cw_model.compile(optimizer=tf.keras.optimizers.RMSprop(learning_rate=1e-4),\n",
583
+ " loss='categorical_crossentropy',\n",
584
+ " metrics=['accuracy'])\n",
585
+ "\n",
586
+ "# Train the model\n",
587
+ "cw_history = cw_model.fit(\n",
588
+ " train_generator,\n",
589
+ " epochs=10,\n",
590
+ " validation_data=validation_generator,\n",
591
+ " validation_steps=len(validation_generator),\n",
592
+ " callbacks=[lr_reduce, checkpoint, early_stopping, lr_scheduler_callback])"
593
+ ],
594
+ "metadata": {
595
+ "id": "YB4TP7vWV4sB"
596
+ },
597
+ "execution_count": null,
598
+ "outputs": []
599
+ },
600
+ {
601
+ "cell_type": "markdown",
602
+ "source": [
603
+ "## comparison_analysis.py"
604
+ ],
605
+ "metadata": {
606
+ "id": "JoWM_4yMVNl5"
607
+ }
608
+ },
609
+ {
610
+ "cell_type": "code",
611
+ "execution_count": null,
612
+ "metadata": {
613
+ "id": "5Cv68ofGIXfa"
614
+ },
615
+ "outputs": [],
616
+ "source": [
617
+ "# Retrieve accuracy and loss from the bn_model's history\n",
618
+ "acc = bn_history.history['accuracy']\n",
619
+ "val_acc = bn_history.history['val_accuracy']\n",
620
+ "loss = bn_history.history['loss']\n",
621
+ "val_loss = bn_history.history['val_loss']\n",
622
+ "\n",
623
+ "# Create a range of epochs to use in the plot\n",
624
+ "epochs = range(1, len(acc) + 1)\n",
625
+ "\n",
626
+ "# Plot training and validation accuracy\n",
627
+ "plt.plot(epochs, acc, 'bo', label='Training acc')\n",
628
+ "plt.plot(epochs, val_acc, 'b', label='Validation acc')\n",
629
+ "plt.title('Training and validation accuracy')\n",
630
+ "plt.legend()\n",
631
+ "\n",
632
+ "plt.figure()\n",
633
+ "\n",
634
+ "# Plot training and validation loss\n",
635
+ "plt.plot(epochs, loss, 'bo', label='Training loss')\n",
636
+ "plt.plot(epochs, val_loss, 'b', label='Validation loss')\n",
637
+ "plt.title('Training and validation loss')\n",
638
+ "plt.legend()\n",
639
+ "\n",
640
+ "plt.show()\n"
641
+ ]
642
+ },
643
+ {
644
+ "cell_type": "code",
645
+ "source": [
646
+ "# Retrieve accuracy and loss from the cw_model's history\n",
647
+ "acc = cw_history.history['accuracy']\n",
648
+ "val_acc = cw_history.history['val_accuracy']\n",
649
+ "loss = cw_history.history['loss']\n",
650
+ "val_loss = cw_history.history['val_loss']\n",
651
+ "\n",
652
+ "# Create a range of epochs to use in the plot\n",
653
+ "epochs = range(1, len(acc) + 1)\n",
654
+ "\n",
655
+ "# Plot training and validation accuracy\n",
656
+ "plt.plot(epochs, acc, 'bo', label='Training acc')\n",
657
+ "plt.plot(epochs, val_acc, 'b', label='Validation acc')\n",
658
+ "plt.title('Training and validation accuracy')\n",
659
+ "plt.legend()\n",
660
+ "\n",
661
+ "plt.figure()\n",
662
+ "\n",
663
+ "# Plot training and validation loss\n",
664
+ "plt.plot(epochs, loss, 'bo', label='Training loss')\n",
665
+ "plt.plot(epochs, val_loss, 'b', label='Validation loss')\n",
666
+ "plt.title('Training and validation loss')\n",
667
+ "plt.legend()\n",
668
+ "\n",
669
+ "plt.show()"
670
+ ],
671
+ "metadata": {
672
+ "id": "MCibCLsrxFuO"
673
+ },
674
+ "execution_count": null,
675
+ "outputs": []
676
+ },
677
+ {
678
+ "cell_type": "code",
679
+ "source": [
680
+ "# Extract the metrics from the history dictionaries\n",
681
+ "bn_acc = bn_history['accuracy']\n",
682
+ "bn_val_acc = bn_history['val_accuracy']\n",
683
+ "bn_loss = bn_history['loss']\n",
684
+ "bn_val_loss = bn_history['val_loss']\n",
685
+ "\n",
686
+ "cw_acc = cw_history['accuracy']\n",
687
+ "cw_val_acc = cw_history['val_accuracy']\n",
688
+ "cw_loss = cw_history['loss']\n",
689
+ "cw_val_loss = cw_history['val_loss']\n",
690
+ "\n",
691
+ "epochs = range(1, len(bn_acc) + 1)\n",
692
+ "\n",
693
+ "# Create the plots\n",
694
+ "plt.figure(figsize=(10, 5))\n",
695
+ "\n",
696
+ "# Plot for accuracy\n",
697
+ "plt.subplot(1, 2, 1)\n",
698
+ "plt.plot(epochs, bn_acc, 'bo-', label='bn_model Training acc')\n",
699
+ "plt.plot(epochs, bn_val_acc, 'ro-', label='bn_model Validation acc')\n",
700
+ "plt.plot(epochs, cw_acc, 'go-', label='cw_model Training acc')\n",
701
+ "plt.plot(epochs, cw_val_acc, 'mo-', label='cw_model Validation acc')\n",
702
+ "plt.title('Training and Validation Accuracy')\n",
703
+ "plt.xlabel('Epochs')\n",
704
+ "plt.ylabel('Accuracy')\n",
705
+ "plt.legend()\n",
706
+ "\n",
707
+ "# Plot for loss\n",
708
+ "plt.subplot(1, 2, 2)\n",
709
+ "plt.plot(epochs, bn_loss, 'bo-', label='bn_model Training loss')\n",
710
+ "plt.plot(epochs, bn_val_loss, 'ro-', label='bn_model Validation loss')\n",
711
+ "plt.plot(epochs, cw_loss, 'go-', label='cw_model Training loss')\n",
712
+ "plt.plot(epochs, cw_val_loss, 'mo-', label='cw_model Validation loss')\n",
713
+ "plt.title('Training and Validation Loss')\n",
714
+ "plt.xlabel('Epochs')\n",
715
+ "plt.ylabel('Loss')\n",
716
+ "plt.legend()\n",
717
+ "\n",
718
+ "plt.tight_layout()\n",
719
+ "plt.show()"
720
+ ],
721
+ "metadata": {
722
+ "id": "aUjYDrhsYyrs"
723
+ },
724
+ "execution_count": null,
725
+ "outputs": []
726
+ },
727
+ {
728
+ "cell_type": "markdown",
729
+ "source": [
730
+ "## deploy"
731
+ ],
732
+ "metadata": {
733
+ "id": "UuE29qx6Z4DC"
734
+ }
735
+ },
736
+ {
737
+ "cell_type": "code",
738
+ "execution_count": null,
739
+ "metadata": {
740
+ "id": "S5fqPCg-Izf0"
741
+ },
742
+ "outputs": [],
743
+ "source": [
744
+ "# Save the model (bn_model) without concept whitening\n",
745
+ "bn_model.save('bn_model.h6')\n",
746
+ "\n",
747
+ "# Load test images\n",
748
+ "images_test = os.listdir(\"/content/drive/MyDrive/documentos/vinyl genre class/data/For thesis/data/For thesis/Testing\")\n",
749
+ "\n",
750
+ "# Initialize a dataframe to store test results\n",
751
+ "df_test = pd.DataFrame(columns=['category', 'name'])\n",
752
+ "categories = ['electronic','rock','hiphop']\n",
753
+ "\n",
754
+ "# Loop through all test images, predict their category and append results to the dataframe\n",
755
+ "for image in images_test:\n",
756
+ " if image.endswith(\".jpg\") is True or image.endswith(\".jpeg\") is True:\n",
757
+ " img = tf.keras.utils.load_img (\n",
758
+ " f\"/content/drive/MyDrive/documentos/vinyl genre class/data/For thesis/data/For thesis/Testing/{image}\", target_size=(300, 300)\n",
759
+ " )\n",
760
+ " img_array = tf.keras.utils.img_to_array(img)\n",
761
+ " img_array = tf.expand_dims(img_array, 0)\n",
762
+ " img_array /= 255.\n",
763
+ "\n",
764
+ " preds = bn_model.predict(img_array)\n",
765
+ " score = preds[0]\n",
766
+ " max_indexes = np.argmax(score)\n",
767
+ "\n",
768
+ " df_test = pd.concat([df_test, pd.DataFrame({'category': [categories[max_indexes]], 'name': [image]})], ignore_index=True)\n",
769
+ " print(f\"{image} is {categories[max_indexes]}\")\n",
770
+ "\n",
771
+ "# Save test results to a CSV file\n",
772
+ "df_test.to_csv('results_bn_new.csv', header=True)"
773
+ ]
774
+ },
775
+ {
776
+ "cell_type": "code",
777
+ "source": [
778
+ "# Save the model (cw_model) with concept whitening\n",
779
+ "cw_model.save('cw_model.h6')\n",
780
+ "\n",
781
+ "# Load test images\n",
782
+ "images_test = os.listdir(\"/content/drive/MyDrive/documentos/vinyl genre class/data/For thesis/Testing\")\n",
783
+ "\n",
784
+ "# Initialize a dataframe to store test results\n",
785
+ "df_test = pd.DataFrame(columns=['category', 'name'])\n",
786
+ "categories = ['electronic','rock','hiphop']\n",
787
+ "\n",
788
+ "# Loop through all test images, predict their category and append results to the dataframe\n",
789
+ "for image in images_test:\n",
790
+ " if image.endswith(\".jpg\") is True or image.endswith(\".jpeg\") is True:\n",
791
+ " img = tf.keras.utils.load_img (\n",
792
+ " f\"/content/drive/MyDrive/documentos/vinyl genre class/data/For thesis/data/For thesis/Testing/{image}\", target_size=(300, 300)\n",
793
+ " )\n",
794
+ " img_array = tf.keras.utils.img_to_array(img)\n",
795
+ " img_array = tf.expand_dims(img_array, 0)\n",
796
+ " img_array /= 255.\n",
797
+ "\n",
798
+ " preds = cw_model.predict(img_array)\n",
799
+ " score = preds[0]\n",
800
+ " max_indexes = np.argmax(score)\n",
801
+ "\n",
802
+ " df_test = pd.concat([df_test, pd.DataFrame({'category': [categories[max_indexes]], 'name': [image]})], ignore_index=True)\n",
803
+ " print(f\"{image} is {categories[max_indexes]}\")\n",
804
+ "\n",
805
+ "# Save test results to a CSV file\n",
806
+ "df_test.to_csv('results_cw_new.csv', header=True)"
807
+ ],
808
+ "metadata": {
809
+ "id": "dfahimjUaM4G"
810
+ },
811
+ "execution_count": null,
812
+ "outputs": []
813
+ }
814
+ ],
815
+ "metadata": {
816
+ "colab": {
817
+ "provenance": []
818
+ },
819
+ "gpuClass": "standard",
820
+ "kernelspec": {
821
+ "display_name": "Python 3 (ipykernel)",
822
+ "language": "python",
823
+ "name": "python3"
824
+ },
825
+ "language_info": {
826
+ "codemirror_mode": {
827
+ "name": "ipython",
828
+ "version": 3
829
+ },
830
+ "file_extension": ".py",
831
+ "mimetype": "text/x-python",
832
+ "name": "python",
833
+ "nbconvert_exporter": "python",
834
+ "pygments_lexer": "ipython3",
835
+ "version": "3.10.10"
836
+ }
837
+ },
838
+ "nbformat": 4,
839
+ "nbformat_minor": 0
840
+ }