{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.13","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"gpu","dataSources":[{"sourceId":3362,"databundleVersionId":31148,"sourceType":"competition"}],"dockerImageVersionId":30698,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import numpy as np \nimport pandas as pd \nimport tensorflow as tf\nfrom tensorflow.keras.models import Model\nfrom tensorflow.keras.layers import Dense, Conv2D, BatchNormalization, Dropout, Flatten, Input, MaxPool2D\nfrom tensorflow.keras.optimizers import Adam\nfrom tensorflow.keras.callbacks import EarlyStopping, ReduceLROnPlateau\nfrom tensorflow.keras.preprocessing.image import ImageDataGenerator, load_img\nfrom sklearn.model_selection import train_test_split\nimport os\nimport matplotlib.pyplot as plt\nfrom zipfile import ZipFile\n\n# check directory\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        print(os.path.join(dirname, filename))    ","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2024-05-06T11:07:30.164439Z","iopub.execute_input":"2024-05-06T11:07:30.165389Z","iopub.status.idle":"2024-05-06T11:07:30.172794Z","shell.execute_reply.started":"2024-05-06T11:07:30.165353Z","shell.execute_reply":"2024-05-06T11:07:30.171953Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test1 = '/kaggle/input/dogs-vs-cats/test1.zip'\ntrain = '/kaggle/input/dogs-vs-cats/train.zip'\nhome = '/kaggle/working'\n\nwith ZipFile(train, mode='r') as file:\n    file.extractall(home)\n\nwith ZipFile(test1, mode='r') as file:\n    file.extractall(home)\n","metadata":{"execution":{"iopub.status.busy":"2024-05-06T11:09:03.529486Z","iopub.execute_input":"2024-05-06T11:09:03.530432Z","iopub.status.idle":"2024-05-06T11:09:14.275584Z","shell.execute_reply.started":"2024-05-06T11:09:03.530397Z","shell.execute_reply":"2024-05-06T11:09:14.274604Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_dir = os.path.join(home, 'train')\ndirectory = os.listdir(train_dir)\n# check the filename\ndirectory[0]","metadata":{"execution":{"iopub.status.busy":"2024-05-06T11:11:04.435760Z","iopub.execute_input":"2024-05-06T11:11:04.436631Z","iopub.status.idle":"2024-05-06T11:11:04.460231Z","shell.execute_reply.started":"2024-05-06T11:11:04.436600Z","shell.execute_reply":"2024-05-06T11:11:04.459230Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"labels = []\npaths = []\n# format the and process the data\nfor f in directory:\n    label = f.split('.')[0]\n    paths.append(os.path.join(train_dir, f))\n    if label == 'cat':\n        labels.append('0')\n    else:\n        labels.append('1')\n    \n# create a dataframe\ndata = pd.DataFrame({\n    'filepath': paths,\n    'label': labels\n})\n        \ndata.head(10)        ","metadata":{"execution":{"iopub.status.busy":"2024-05-06T11:11:10.267471Z","iopub.execute_input":"2024-05-06T11:11:10.267818Z","iopub.status.idle":"2024-05-06T11:11:10.347631Z","shell.execute_reply.started":"2024-05-06T11:11:10.267791Z","shell.execute_reply":"2024-05-06T11:11:10.346634Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# display couple of random images\n\ndata_sample = data.sample(5).reset_index()\n\n# print(data_sample.loc[1, 'filepath'])\nfor i in range(1,5):\n    path = data_sample.loc[i, 'filepath']\n    img = plt.imread(path)\n    plt.subplot(2,2,i)\n    plt.imshow(img)\n    plt.axis('off')\n    \n    ","metadata":{"execution":{"iopub.status.busy":"2024-05-06T11:11:16.054070Z","iopub.execute_input":"2024-05-06T11:11:16.054776Z","iopub.status.idle":"2024-05-06T11:11:16.419225Z","shell.execute_reply.started":"2024-05-06T11:11:16.054743Z","shell.execute_reply":"2024-05-06T11:11:16.418334Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# split the data tot train in test 80/20\nX_train, X_test_val = train_test_split(data, test_size=0.2, random_state=7)\n\n#split test to test and val 50/50\nX_test, X_val = train_test_split(X_test_val, test_size=0.5, random_state=7)\n","metadata":{"execution":{"iopub.status.busy":"2024-05-06T11:11:20.334147Z","iopub.execute_input":"2024-05-06T11:11:20.334900Z","iopub.status.idle":"2024-05-06T11:11:20.344760Z","shell.execute_reply.started":"2024-05-06T11:11:20.334868Z","shell.execute_reply":"2024-05-06T11:11:20.343879Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#create a data generators\nBATCH_SIZE = 128\n\ndatagen_train = ImageDataGenerator(\n    rescale=1/255.,\n    shear_range=0.05,\n    zoom_range=0.05,\n    horizontal_flip=True,\n    fill_mode='nearest'\n)\n\n# datagen for val\ndatagen_val = ImageDataGenerator(\n    rescale=1/255.)\n\n# generators for data loading\ntrain_generator = datagen_train.flow_from_dataframe(\n    dataframe=X_train,\n    x_col='filepath',\n    y_col='label',\n    target_size=(227, 227),\n    batch_size=BATCH_SIZE,\n    class_mode='binary',\n    workers=4,\n    use_multiprocessing=True\n)\n\nval_generator = datagen_val.flow_from_dataframe(\n    dataframe=X_val,\n    x_col='filepath',\n    y_col='label',\n    target_size=(227, 227),\n    batch_size=BATCH_SIZE,\n    class_mode='binary',\n    workers=4,\n    use_multiprocessing=True\n)\n\ntest_generator = datagen_val.flow_from_dataframe(\n    dataframe=X_test,\n    x_col='filepath',\n    y_col='label',\n    target_size=(227, 227),\n    batch_size=BATCH_SIZE,\n    class_mode='binary',\n)\n","metadata":{"execution":{"iopub.status.busy":"2024-05-06T11:50:56.489898Z","iopub.execute_input":"2024-05-06T11:50:56.490253Z","iopub.status.idle":"2024-05-06T11:50:56.785345Z","shell.execute_reply.started":"2024-05-06T11:50:56.490227Z","shell.execute_reply":"2024-05-06T11:50:56.784524Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Alex Net architecture implemented from scratch\ndef Alex_Net(weights = None, skip_mismatch=False, include_top = False, input_shape=(227, 227, 3)):\n    '''\n    Alex Net implementation from scratch in Keras\n    The weights are not included ,however, implemented\n    the compatibility with loading custom weights. \n    \n    weights - parameter for filepath to weights to load weights.\n    By default initiated to None and no weights are used. \n    include_top - whether to include the fully-connected layer at the top of the network.\n    skip_mismatch - whether to skip mismatched layers when loading weights.\n    '''  \n    input_lyr = Input(shape=input_shape)\n    # Conv Layer 1\n    x =  Conv2D(96, (11,11), strides=(4,4), padding='valid', activation='relu')(input_lyr)\n    x = BatchNormalization()(x) # instead of LRN\n    x = MaxPool2D((3,3), strides=(2,2))(x)\n    # Conv Layer 2\n    x = Conv2D(256, (5,5), padding='same', activation='relu')(x)\n    x = BatchNormalization()(x) # instead of LRN\n    x = MaxPool2D((3,3), strides=(2,2))(x)\n    # Conv Layers 3-5 (they are all the same)\n    x = Conv2D(384, (3,3), padding='same', activation='relu')(x)\n    x = Conv2D(384, (3,3), padding='same', activation='relu')(x)\n    x = Conv2D(256, (3,3), padding='same', activation='relu')(x)\n    x = MaxPool2D((3,3), strides=(2,2))(x)\n    # FLC Layers \n    # if True: add the classic FLC layers of Alex Net\n    if include_top:\n        flatten = Flatten()(x)\n        x = Dense(4096, activation='relu')(flatten)\n        x = Dropout(0.5)(x)\n        x = Dense(4096, activation='relu')(x)\n        x = Dropout(0.5)(x)\n        x = Dense(1000, activation='softmax')(x)\n    model = Model(inputs=input_lyr, outputs=x)\n    \n    if weights is not None:\n        try:\n            model.load_weights(weights, skip_mismatch=skip_mismatch)\n        except (IOError, OSError, ValueError) as err:\n            print(f\"Error loading weights: {err}\")\n    return model\n\n# model = Alex_Net(include_top=False)\n\n# model.summary()\n# from tensorflow.keras.utils import plot_model\n# plot_model(model, show_shapes=True)  ","metadata":{"execution":{"iopub.status.busy":"2024-05-06T11:39:50.910547Z","iopub.execute_input":"2024-05-06T11:39:50.911349Z","iopub.status.idle":"2024-05-06T11:39:50.924752Z","shell.execute_reply.started":"2024-05-06T11:39:50.911312Z","shell.execute_reply":"2024-05-06T11:39:50.923867Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# we will not use top as we don't have the original weights and don't want to overcomplicate the model\nalex_net_base = Alex_Net(include_top=False) # base model\n\nx = alex_net_base.output # the base model as input\n\n# FLC layers\nx = Flatten()(x)\nx = Dense(128, activation='relu')(x)\n# x = Dropout(0.2)(x)\n# x = Dense(128, activation='relu')(x)\nx = Dropout(0.5)(x)\nout = Dense(1, activation='sigmoid')(x) # output\n\nmodel = Model(inputs=alex_net_base.input, outputs=out)\n\nmodel.summary()","metadata":{"execution":{"iopub.status.busy":"2024-05-06T11:48:16.278499Z","iopub.execute_input":"2024-05-06T11:48:16.279155Z","iopub.status.idle":"2024-05-06T11:48:16.386476Z","shell.execute_reply.started":"2024-05-06T11:48:16.279123Z","shell.execute_reply":"2024-05-06T11:48:16.385543Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# compile the model\n#optimiser\nadam = Adam(learning_rate=0.001)\nmodel.compile(optimizer=adam,\n              loss='binary_crossentropy',\n              metrics=['accuracy'])\n\n#callbacks\nearly_stop = EarlyStopping(\n    monitor=\"val_loss\",\n    patience=15,\n    verbose=1,\n    restore_best_weights=True,\n    mode=\"min\")\n\nreduce_lr = ReduceLROnPlateau(\n    monitor='val_loss',  \n    factor=0.6,\n    patience=5,         \n    min_lr=0.00001,\n    verbose=1)\n# compile \nhistory = model.fit(train_generator,\n                    epochs=15,\n                    validation_data=val_generator,\n                    callbacks=[early_stop, reduce_lr],\n                   )","metadata":{"execution":{"iopub.status.busy":"2024-05-06T11:51:20.344944Z","iopub.execute_input":"2024-05-06T11:51:20.346115Z","iopub.status.idle":"2024-05-06T12:48:43.283038Z","shell.execute_reply.started":"2024-05-06T11:51:20.346072Z","shell.execute_reply":"2024-05-06T12:48:43.282012Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"As we can see the final epoch's training accuracy was ~92% and val accuracy ~88 which is a good result for training Alex Net from scratch on a limited dataset of 20k images. The idea was to keep the model as closer as possible to the original architecture.  ","metadata":{}},{"cell_type":"code","source":"# plot the result\nfig = plt.figure(figsize=(12, 4))\n\nfig.add_subplot(1, 2, 1)\nplt.plot(history.history['loss'], label='Train Loss')\nplt.plot(history.history['val_loss'], label='Val Loss')\nplt.legend()\nplt.grid(True)\nplt.ylim([0, 1])  \nplt.title('Loss')\nplt.xlabel('Epoch')\n\nfig.add_subplot(1, 2, 2)\nplt.plot(history.history['accuracy'], label='Train accuracy')\nplt.plot(history.history['val_accuracy'], label='Val Accuracy')\nplt.legend()\nplt.grid(True)\nplt.ylim([0, 1])  \nplt.title('Accuracy')\nplt.xlabel('Epoch')","metadata":{"execution":{"iopub.status.busy":"2024-05-06T13:06:58.189273Z","iopub.execute_input":"2024-05-06T13:06:58.189962Z","iopub.status.idle":"2024-05-06T13:06:58.739040Z","shell.execute_reply.started":"2024-05-06T13:06:58.189929Z","shell.execute_reply":"2024-05-06T13:06:58.738198Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# evaluate the model on a test set\n","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}