{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.12","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"gpu","dataSources":[{"sourceId":18647,"databundleVersionId":1126921,"sourceType":"competition"}],"dockerImageVersionId":30559,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import os\nfrom tqdm.notebook import tqdm\nimport zipfile","metadata":{"execution":{"iopub.status.busy":"2024-09-28T14:26:40.623603Z","iopub.execute_input":"2024-09-28T14:26:40.624625Z","iopub.status.idle":"2024-09-28T14:26:40.727981Z","shell.execute_reply.started":"2024-09-28T14:26:40.624586Z","shell.execute_reply":"2024-09-28T14:26:40.726869Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import time\nimport skimage.io\nimport numpy as np\nimport pandas as pd\nimport cv2\nimport PIL.Image\nfrom sklearn.model_selection import StratifiedKFold\nimport matplotlib.pyplot as plt\nfrom sklearn.metrics import cohen_kappa_score\nfrom tqdm import tqdm_notebook as tqdm","metadata":{"execution":{"iopub.status.busy":"2024-09-28T14:26:40.86225Z","iopub.execute_input":"2024-09-28T14:26:40.862657Z","iopub.status.idle":"2024-09-28T14:26:42.377245Z","shell.execute_reply.started":"2024-09-28T14:26:40.862625Z","shell.execute_reply":"2024-09-28T14:26:42.376321Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"data_dir = '../input/prostate-cancer-grade-assessment'\ndf_train = pd.read_csv(os.path.join(data_dir, 'train.csv'))\n","metadata":{"execution":{"iopub.status.busy":"2024-09-28T14:26:42.379555Z","iopub.execute_input":"2024-09-28T14:26:42.380167Z","iopub.status.idle":"2024-09-28T14:26:42.418391Z","shell.execute_reply.started":"2024-09-28T14:26:42.380126Z","shell.execute_reply":"2024-09-28T14:26:42.417557Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def sample_equal_instances(df, target_column, sample_size):\n    sampled_df = df.groupby(target_column).apply(lambda x: x.sample(sample_size, replace=True)).reset_index(drop=True)\n    return sampled_df","metadata":{"execution":{"iopub.status.busy":"2024-09-28T14:26:42.419548Z","iopub.execute_input":"2024-09-28T14:26:42.419819Z","iopub.status.idle":"2024-09-28T14:26:42.425286Z","shell.execute_reply.started":"2024-09-28T14:26:42.419795Z","shell.execute_reply":"2024-09-28T14:26:42.424215Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"gleason_6 = df_train[df_train['isup_grade'].isin([0, 1, 2, 3, 4, 5])]\n\n# Select 100 rows from the filtered DataFrame\nselected_data = gleason_6.head(80)","metadata":{"execution":{"iopub.status.busy":"2024-09-28T14:26:42.42763Z","iopub.execute_input":"2024-09-28T14:26:42.427967Z","iopub.status.idle":"2024-09-28T14:26:42.441725Z","shell.execute_reply.started":"2024-09-28T14:26:42.42794Z","shell.execute_reply":"2024-09-28T14:26:42.440738Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(f'Total samples: {selected_data.shape[0]}')","metadata":{"execution":{"iopub.status.busy":"2024-09-28T14:26:42.442903Z","iopub.execute_input":"2024-09-28T14:26:42.443189Z","iopub.status.idle":"2024-09-28T14:26:42.45315Z","shell.execute_reply.started":"2024-09-28T14:26:42.443163Z","shell.execute_reply":"2024-09-28T14:26:42.452235Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Image ids in NAME variable with their respective classes in CLASS variable\nNAME= selected_data['image_id'].tolist()\nCLASS=selected_data['isup_grade'].tolist()\nNAME","metadata":{"execution":{"iopub.status.busy":"2024-09-28T14:26:42.454277Z","iopub.execute_input":"2024-09-28T14:26:42.454624Z","iopub.status.idle":"2024-09-28T14:26:42.468767Z","shell.execute_reply.started":"2024-09-28T14:26:42.45458Z","shell.execute_reply":"2024-09-28T14:26:42.467691Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df=[]\ncount=0\nfor i in NAME:\n df.append(df_train[df_train['image_id']==i])\n count+=1\ndf_train=pd.DataFrame(np.array(df).reshape(80,4),columns=['image_id','data_provider','isup_grade','gleason_score'])\ndf_train","metadata":{"execution":{"iopub.status.busy":"2024-09-28T14:26:42.470115Z","iopub.execute_input":"2024-09-28T14:26:42.470451Z","iopub.status.idle":"2024-09-28T14:26:42.695938Z","shell.execute_reply.started":"2024-09-28T14:26:42.470424Z","shell.execute_reply":"2024-09-28T14:26:42.6949Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"TRAIN = '../input/prostate-cancer-grade-assessment/train_images/'\nMASKS = '../input/prostate-cancer-grade-assessment/train_label_masks/'\nOUT_TRAIN = 'train.zip'\nOUT_MASKS = 'masks.zip'\nsz = 256 # Size of each tile\nN = 36 # Total no of tiles","metadata":{"execution":{"iopub.status.busy":"2024-09-28T14:26:42.697122Z","iopub.execute_input":"2024-09-28T14:26:42.69744Z","iopub.status.idle":"2024-09-28T14:26:42.703105Z","shell.execute_reply.started":"2024-09-28T14:26:42.697413Z","shell.execute_reply":"2024-09-28T14:26:42.702057Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def tile(img, mask, sz=256, N=16, cutoff_threshold=0.9):\n    result = []\n    shape = img.shape\n    pad0, pad1 = (sz - shape[0] % sz) % sz, (sz - shape[1] % sz) % sz\n    img = np.pad(img, [[pad0 // 2, pad0 - pad0 // 2], [pad1 // 2, pad1 - pad1 // 2], [0, 0]],\n                 constant_values=255)\n    mask = np.pad(mask, [[pad0 // 2, pad0 - pad0 // 2], [pad1 // 2, pad1 - pad1 // 2], [0, 0]],\n                  constant_values=0)\n    img = img.reshape(img.shape[0] // sz, sz, img.shape[1] // sz, sz, 3)\n    img = img.transpose(0, 2, 1, 3, 4).reshape(-1, sz, sz, 3)\n    mask = mask.reshape(mask.shape[0] // sz, sz, mask.shape[1] // sz, sz, 3)\n    mask = mask.transpose(0, 2, 1, 3, 4).reshape(-1, sz, sz, 3)\n\n    # Filter tiles using tile_cutoff\n    valid_tiles = tile_cutoff(img, cutoff_threshold)\n    img = img[valid_tiles]\n    mask = mask[valid_tiles]\n\n    if len(img) < N:\n        mask = np.pad(mask, [[0, N - len(img)], [0, 0], [0, 0], [0, 0]], constant_values=0)\n        img = np.pad(img, [[0, N - len(img)], [0, 0], [0, 0], [0, 0]], constant_values=255)\n    idxs = np.argsort(img.reshape(img.shape[0], -1).sum(-1))[:N]\n    img = img[idxs]\n    mask = mask[idxs]\n    for i in range(len(img)):\n        augmented_img, augmented_mask = augment_tile(img[i], mask[i])\n        result.append({'img': augmented_img, 'mask': augmented_mask, 'idx': i})\n    return result\n\ndef tile_cutoff(img_tiles, threshold):\n    \"\"\"Filter out tiles that are predominantly white or gray.\"\"\"\n    valid_tiles = []\n    for i, tile in enumerate(img_tiles):\n        if np.mean(tile) / 255.0 < threshold:\n            valid_tiles.append(i)\n    return np.array(valid_tiles)\n\ndef augment_tile(img, mask):\n    \"\"\"Apply augmentations to a tile.\"\"\"\n    # Random horizontal flip\n    if np.random.rand() > 0.5:\n        img = np.fliplr(img)\n        mask = np.fliplr(mask)\n    # Random vertical flip\n    if np.random.rand() > 0.5:\n        img = np.flipud(img)\n        mask = np.flipud(mask)\n    # Random rotation\n    if np.random.rand() > 0.5:\n        k = np.random.randint(0, 4)\n        img = np.rot90(img, k)\n        mask = np.rot90(mask, k)\n    # Additional augmentations can be added here\n    return img, mask\n","metadata":{"execution":{"iopub.status.busy":"2024-09-28T14:26:42.751243Z","iopub.execute_input":"2024-09-28T14:26:42.751602Z","iopub.status.idle":"2024-09-28T14:26:42.771148Z","shell.execute_reply.started":"2024-09-28T14:26:42.751574Z","shell.execute_reply":"2024-09-28T14:26:42.770064Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"x_tot,x2_tot = [],[]\nnames = [name[:-10] for name in os.listdir(MASKS)]\nwith zipfile.ZipFile(OUT_TRAIN, 'w') as img_out,\\\n zipfile.ZipFile(OUT_MASKS, 'w') as mask_out:\n    for name in tqdm(NAME):\n        img = skimage.io.MultiImage(os.path.join(TRAIN,name+'.tiff'))[-1]\n        mask = skimage.io.MultiImage(os.path.join(MASKS,name+'_mask.tiff'))[-1]\n        tiles = tile(img,mask)\n        for t in tiles:\n            img,mask,idx = t['img'],t['mask'],t['idx']\n            x_tot.append((img/255.0).reshape(-1,3).mean(0))\n            x2_tot.append(((img/255.0)**2).reshape(-1,3).mean(0)) \n            #if read with PIL RGB turns into BGR\n            img = cv2.imencode('.png',cv2.cvtColor(img, cv2.COLOR_RGB2BGR))[1]\n            img_out.writestr(f'{name}_{idx}.png', img)\n            mask = cv2.imencode('.png',mask[:,:,0])[1]\n            mask_out.writestr(f'{name}_{idx}.png', mask)","metadata":{"execution":{"iopub.status.busy":"2024-09-28T09:07:12.001374Z","iopub.execute_input":"2024-09-28T09:07:12.001669Z","iopub.status.idle":"2024-09-28T09:15:12.913307Z","shell.execute_reply.started":"2024-09-28T09:07:12.001641Z","shell.execute_reply":"2024-09-28T09:15:12.912275Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!unzip -o /kaggle/working/train.zip","metadata":{"execution":{"iopub.status.busy":"2024-09-28T09:15:12.914602Z","iopub.execute_input":"2024-09-28T09:15:12.914953Z","iopub.status.idle":"2024-09-28T09:15:15.206811Z","shell.execute_reply.started":"2024-09-28T09:15:12.914922Z","shell.execute_reply":"2024-09-28T09:15:15.205712Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# loading all the tile images into img_train array with 12 rows\nimport cv2\nout_dir='/kaggle/working/'\nimg_train=np.empty((80,4*256,4*256,3))\ncount=-1\nfor i in NAME:\n    img_var=[]\n    count+=1\n    for j in range(0,16): \n        img_var.append(cv2.imread(out_dir+str(i)+'_'+str(j)+'.png'))\n    img_var=np.array(img_var)\n    img_var=img_var.reshape(4*256,4*256,3)\n    img_train[count]=img_var\n\n","metadata":{"execution":{"iopub.status.busy":"2024-09-28T14:26:46.948267Z","iopub.execute_input":"2024-09-28T14:26:46.948688Z","iopub.status.idle":"2024-09-28T14:26:50.120975Z","shell.execute_reply.started":"2024-09-28T14:26:46.948656Z","shell.execute_reply":"2024-09-28T14:26:50.120019Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"img_train=img_train.reshape(80,-1) # for smote function to work, it requires only 2 dimensional array","metadata":{"execution":{"iopub.status.busy":"2024-09-28T14:26:50.122777Z","iopub.execute_input":"2024-09-28T14:26:50.123128Z","iopub.status.idle":"2024-09-28T14:26:50.127984Z","shell.execute_reply.started":"2024-09-28T14:26:50.123099Z","shell.execute_reply":"2024-09-28T14:26:50.126955Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 12 to 24 images using smote analysis\nfrom collections import Counter\nfrom imblearn.over_sampling import SMOTE\ncounter = Counter(CLASS)\nprint('Before',counter)\n# oversampling the train dataset using SMOTE\nsmt = SMOTE(sampling_strategy={0:30,1:30,2:30,3:30,4:30,5:30},k_neighbors=3)\n#X_train, y_train = smt.fit_resample(X_train, y_train)\nX_train_sm, y_train_sm = smt.fit_resample(img_train, CLASS)\n\ncounter = Counter(y_train_sm)\nprint('After',counter)","metadata":{"execution":{"iopub.status.busy":"2024-09-28T14:26:50.129403Z","iopub.execute_input":"2024-09-28T14:26:50.129693Z","iopub.status.idle":"2024-09-28T14:27:00.89124Z","shell.execute_reply.started":"2024-09-28T14:26:50.129667Z","shell.execute_reply":"2024-09-28T14:27:00.890176Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(X_train_sm.shape)\nprint(X_train_sm.size)\n","metadata":{"execution":{"iopub.status.busy":"2024-09-28T14:27:00.893449Z","iopub.execute_input":"2024-09-28T14:27:00.893891Z","iopub.status.idle":"2024-09-28T14:27:00.898893Z","shell.execute_reply.started":"2024-09-28T14:27:00.893864Z","shell.execute_reply":"2024-09-28T14:27:00.897877Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from PIL import Image\n\n# Define the desired dimensions for each image\nnew_width = 256\nnew_height = 256\n\n# List to store resized images\nresized_images = []\n\n# Loop through each image in X_train_sm and resize\nfor img_data in X_train_sm:\n    # Reshape the 1D array back into image dimensions\n    img = img_data.reshape(4*256, 4*256, 3)\n    \n    # Convert numpy array to PIL Image\n    pil_img = Image.fromarray(img.astype('uint8'))\n    \n    # Resize the image\n    resized_img = pil_img.resize((new_width, new_height))\n    \n    # Convert back to numpy array\n    resized_img_data = np.array(resized_img)\n    \n    # Append resized image to the list\n    resized_images.append(resized_img_data)\n\n# Convert the list of resized images back to numpy array\nX_train_resized = np.array(resized_images)\n\n# Check the shape of the resized array\nprint(X_train_resized.shape)\n","metadata":{"execution":{"iopub.status.busy":"2024-09-28T14:27:00.900164Z","iopub.execute_input":"2024-09-28T14:27:00.900505Z","iopub.status.idle":"2024-09-28T14:27:03.958897Z","shell.execute_reply.started":"2024-09-28T14:27:00.900478Z","shell.execute_reply":"2024-09-28T14:27:03.957879Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"Y_train=pd.get_dummies(y_train_sm).values # onehotencoding","metadata":{"execution":{"iopub.status.busy":"2024-09-28T14:27:03.960256Z","iopub.execute_input":"2024-09-28T14:27:03.96067Z","iopub.status.idle":"2024-09-28T14:27:03.97096Z","shell.execute_reply.started":"2024-09-28T14:27:03.960633Z","shell.execute_reply":"2024-09-28T14:27:03.969909Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!pip install git+https://github.com/qubvel/classification_models.git","metadata":{"execution":{"iopub.status.busy":"2024-09-28T14:27:03.972112Z","iopub.execute_input":"2024-09-28T14:27:03.97248Z","iopub.status.idle":"2024-09-28T14:27:21.83267Z","shell.execute_reply.started":"2024-09-28T14:27:03.972452Z","shell.execute_reply":"2024-09-28T14:27:21.831391Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import tensorflow as tf\nfrom classification_models.tfkeras import Classifiers\n\n# Get the EfficientNet B4 model and its preprocessing function\nEfficientNetB4, preprocess_input = Classifiers.get('efficientnet-b4')\n\n# Create the model with the desired input shape and weights\neffnet_b4_model = EfficientNetB4(\n    include_top=False,  # Set to True if you need the classification head\n    input_shape=(256, 256, 3),  # Input size, adjust as necessary\n    weights='imagenet'  # Use pre-trained ImageNet weights\n)\n","metadata":{"execution":{"iopub.status.busy":"2024-09-28T14:27:21.834499Z","iopub.execute_input":"2024-09-28T14:27:21.835495Z","iopub.status.idle":"2024-09-28T14:27:32.9889Z","shell.execute_reply.started":"2024-09-28T14:27:21.835439Z","shell.execute_reply":"2024-09-28T14:27:32.987995Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Defining the model\nimport tensorflow.keras as K\nfrom tensorflow.keras.layers import Input\n\n# Define the input shape based on the resized image dimensions\ninput_t = Input(shape=(256, 256, 3))\n\n# Load ResNet50 model with the updated input shape\n# res_model = K.applications.ResNeXt50(include_top=False, weights=\"imagenet\", input_tensor=input_t)\n\n# Build the rest of the model\nmodel = K.models.Sequential()\nmodel.add(enet_b4_model)\nmodel.add(K.layers.Flatten())\nmodel.add(K.layers.Dense(6, activation='softmax'))\nmodel.compile(loss='categorical_crossentropy',optimizer=K.optimizers.RMSprop(lr=0.01),metrics=['accuracy'])","metadata":{"execution":{"iopub.status.busy":"2024-09-28T14:27:32.990256Z","iopub.execute_input":"2024-09-28T14:27:32.990745Z","iopub.status.idle":"2024-09-28T14:27:33.117731Z","shell.execute_reply.started":"2024-09-28T14:27:32.990714Z","shell.execute_reply":"2024-09-28T14:27:33.116659Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"X_train_resized[1,:]","metadata":{"execution":{"iopub.status.busy":"2024-09-28T14:27:33.120495Z","iopub.execute_input":"2024-09-28T14:27:33.120813Z","iopub.status.idle":"2024-09-28T14:27:33.129015Z","shell.execute_reply.started":"2024-09-28T14:27:33.120785Z","shell.execute_reply":"2024-09-28T14:27:33.128023Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from sklearn.model_selection import KFold\nfrom sklearn.metrics import confusion_matrix\nimport numpy as np\n\nk = 13  # Number of folds\nkf = KFold(n_splits=k, shuffle=True, random_state=2)\nfold_no = 1\nscores = []\nconfusion_matrices = []  # To store confusion matrices for each fold\n\nfor train_index, test_index in kf.split(X_train_resized):\n    print(f'Fold {fold_no}')\n\n    # Split the data\n    X_train, X_test = X_train_resized[train_index], X_train_resized[test_index]\n    y_train, y_test = Y_train[train_index], Y_train[test_index]\n\n    # Fit the model\n    model.fit(X_train, y_train, epochs=10)\n\n    # Evaluate the model\n    score = model.evaluate(X_test, y_test)\n    scores.append(score)\n\n    # Generate predictions for confusion matrix\n    y_pred = np.argmax(model.predict(X_test), axis=1)\n    y_true = np.argmax(y_test, axis=1)  # Assuming one-hot encoding for y_test\n\n    # Calculate confusion matrix\n    cm = confusion_matrix(y_true, y_pred)\n    confusion_matrices.append(cm)\n\n    print(f'Score for fold {fold_no}: {model.metrics_names[1]} of {score[1]*100}%')\n    print(f'Confusion matrix for fold {fold_no}:\\n{cm}')\n\n    fold_no += 1\n\n# Calculate and print average accuracy across all folds\naverage_accuracy = np.mean([s[1] for s in scores]) * 100\nprint(f'Average accuracy: {average_accuracy}%')\n","metadata":{"execution":{"iopub.status.busy":"2024-09-28T14:27:33.130258Z","iopub.execute_input":"2024-09-28T14:27:33.1306Z","iopub.status.idle":"2024-09-28T14:31:36.774366Z","shell.execute_reply.started":"2024-09-28T14:27:33.130572Z","shell.execute_reply":"2024-09-28T14:31:36.772838Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Method 2 With datagen","metadata":{}},{"cell_type":"code","source":"import tensorflow.keras as K\nfrom tensorflow.keras.layers import Input\nfrom tensorflow.keras.preprocessing.image import ImageDataGenerator\nfrom tensorflow.keras.callbacks import EarlyStopping\nimport numpy as np\nfrom sklearn.model_selection import KFold\n\n# Define the input shape based on the resized image dimensions\ninput_t = Input(shape=(256, 256, 3))\n\n# Load ResNet50 model with the updated input shape\nres_model = K.applications.ResNet50(include_top=False, weights=\"imagenet\", input_tensor=input_t)\n\n# Freeze earlier layers for fine-tuning (optional)\nfor layer in res_model.layers[:100]:  # Freeze the first 100 layers\n    layer.trainable = False\n\n# Build the rest of the model\nmodel = K.models.Sequential()\nmodel.add(res_model)\nmodel.add(K.layers.Flatten())\nmodel.add(K.layers.Dense(6, activation='softmax'))\n\n# Hyperparameter Tuning\noptimizer = K.optimizers.RMSprop(learning_rate=0.001)  # Lower learning rate\n\n# Regularization (L2 regularization)\nmodel.compile(loss='categorical_crossentropy', optimizer=optimizer, metrics=['accuracy'])\n\n# Assuming X_train_resized and Y_train are already defined\nk = 5  # Number of folds\nkf = KFold(n_splits=k, shuffle=True, random_state=42)\nfold_no = 1\nscores = []\n\n# Early Stopping (monitor validation loss)\nearly_stopping = EarlyStopping(monitor='val_loss', patience=5)  # Stop training after 5 epochs of no improvement in validation loss\n\nfor train_index, test_index in kf.split(X_train_resized):\n    print(f'Fold {fold_no}')\n\n    X_train, X_test = X_train_resized[train_index], X_train_resized[test_index]\n    y_train, y_test = Y_train[train_index], Y_train[test_index]\n\n    # Data Augmentation (applied only on training data)\n    datagen = ImageDataGenerator(\n        rotation_range=20,\n        width_shift_range=0.2,\n        height_shift_range=0.2,\n        shear_range=0.2,\n        zoom_range=0.2,\n        horizontal_flip=True,\n        fill_mode='nearest'\n    )\n\n    train_generator = datagen.flow(\n        X_train, y_train,\n        batch_size=32\n    )\n\n    # For validation/test data, we do not apply augmentation\n    validation_generator = ImageDataGenerator().flow(\n        X_test, y_test,\n        batch_size=32,\n        shuffle=False\n    )\n\n    # Fit the model with augmented training data and early stopping\n    model.fit(train_generator, \n              steps_per_epoch=len(train_generator), \n              epochs=10, \n              validation_data=validation_generator, \n              callbacks=[early_stopping])\n\n    # Evaluate the model on the test data (validation data for this fold)\n    score = model.evaluate(validation_generator)\n    scores.append(score)\n    print(f'Score for fold {fold_no}: {model.metrics_names[1]} of {score[1]*100}%')\n    fold_no += 1\n\n# Calculate and print the average accuracy across all folds\naverage_accuracy = np.mean([s[1] for s in scores]) * 100\nprint(f'Average accuracy: {average_accuracy}%')\n","metadata":{"execution":{"iopub.status.busy":"2024-09-28T09:30:39.060773Z","iopub.execute_input":"2024-09-28T09:30:39.061663Z","iopub.status.idle":"2024-09-28T09:32:35.883634Z","shell.execute_reply.started":"2024-09-28T09:30:39.061627Z","shell.execute_reply":"2024-09-28T09:32:35.882736Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}