{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.7.12","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"nvidiaTeslaT4","dataSources":[{"sourceId":35429,"databundleVersionId":3433890,"sourceType":"competition"},{"sourceId":3444396,"sourceType":"datasetVersion","datasetId":2074397},{"sourceId":3973617,"sourceType":"datasetVersion","datasetId":2358079}],"dockerImageVersionId":30214,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import os\nimport cv2\nimport random\nimport numpy as np\nimport pandas as pd\nimport tensorflow as tf\nimport tensorflow_io as tfio\nimport tensorflow_addons as tfa\nimport seaborn as sns\n\nfrom PIL import Image\nfrom PIL import ImageEnhance\nfrom PIL import ImageFilter as Filter\nfrom matplotlib import pyplot as plt\n\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.metrics import accuracy_score, confusion_matrix\nfrom tensorflow.keras.models import Model, Sequential\nfrom tensorflow.keras.layers import InputLayer, Conv2D, MaxPooling2D, Input, Activation, Add, ReLU\nfrom tensorflow.keras.layers import BatchNormalization, Dropout, AveragePooling2D, Dense, Flatten, Concatenate\nfrom tensorflow.keras.activations import relu, softmax\nfrom tensorflow.keras.regularizers import l2\nfrom tensorflow.keras.preprocessing.image import ImageDataGenerator","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","pycharm":{"name":"#%%\n"},"execution":{"iopub.status.busy":"2026-01-08T17:45:48.210222Z","iopub.execute_input":"2026-01-08T17:45:48.211142Z","iopub.status.idle":"2026-01-08T17:45:54.705339Z","shell.execute_reply.started":"2026-01-08T17:45:48.211057Z","shell.execute_reply":"2026-01-08T17:45:54.704460Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## config","metadata":{"pycharm":{"name":"#%% md\n"}}},{"cell_type":"code","source":"train_meta_data = '../input/unifesp-xray-body-part-classifier-dataset-jpeg/data/train.csv'\ntrain_data_dir = '../input/unifesp-xray-body-part-classifier-dataset-jpeg/data/train'\nepochs = 200\nlr = 1e-3\nvalid_split = 0.2\ninput_size = 224\nbatch_size = 32\nclasses = 22\ninitializer = tf.keras.initializers.HeUniform()\noptimizer = tf.keras.optimizers.Nadam(learning_rate=lr)\nloss = tf.keras.losses.categorical_crossentropy\nweight_decay = 5e-4","metadata":{"pycharm":{"name":"#%%\n"},"execution":{"iopub.status.busy":"2026-01-08T17:45:54.707614Z","iopub.execute_input":"2026-01-08T17:45:54.708186Z","iopub.status.idle":"2026-01-08T17:45:54.720446Z","shell.execute_reply.started":"2026-01-08T17:45:54.708154Z","shell.execute_reply":"2026-01-08T17:45:54.719412Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Pre-processing pipeline","metadata":{"pycharm":{"name":"#%% md\n"}}},{"cell_type":"code","source":"test_image = Image.open('../input/unifesp-xray-body-part-classifier-dataset-jpeg/data/train/10093718510761734264315711288650185574.jpg')\ntest_arr = np.expand_dims(np.asarray(test_image),2)\ntest_arr_rgb = tf.image.grayscale_to_rgb(tf.convert_to_tensor(test_arr))","metadata":{"pycharm":{"name":"#%%\n"},"execution":{"iopub.status.busy":"2026-01-08T17:45:54.721860Z","iopub.execute_input":"2026-01-08T17:45:54.722128Z","iopub.status.idle":"2026-01-08T17:45:58.134813Z","shell.execute_reply.started":"2026-01-08T17:45:54.722102Z","shell.execute_reply":"2026-01-08T17:45:58.133862Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"plt.figure(figsize=[8,8], dpi=100)\nplt.imshow(test_arr,cmap=plt.cm.gray)","metadata":{"pycharm":{"name":"#%%\n"},"execution":{"iopub.status.busy":"2026-01-08T17:45:58.136065Z","iopub.execute_input":"2026-01-08T17:45:58.136447Z","iopub.status.idle":"2026-01-08T17:45:58.411363Z","shell.execute_reply.started":"2026-01-08T17:45:58.136397Z","shell.execute_reply":"2026-01-08T17:45:58.410475Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## augmentations apply:\n\n* edge enhance\n* de-texturization\n* filp right-left\n* flip up-down\n* random cropping","metadata":{"pycharm":{"name":"#%% md\n"}}},{"cell_type":"code","source":"ada_thold = cv2.adaptiveThreshold(test_arr, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 11, 2.01)","metadata":{"pycharm":{"name":"#%%\n"},"execution":{"iopub.status.busy":"2026-01-08T17:45:58.413469Z","iopub.execute_input":"2026-01-08T17:45:58.413841Z","iopub.status.idle":"2026-01-08T17:45:58.434496Z","shell.execute_reply.started":"2026-01-08T17:45:58.413815Z","shell.execute_reply":"2026-01-08T17:45:58.433586Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"fig, axes = plt.subplots(nrows=1, ncols=2, figsize=[12,6], dpi=200)\naxes = axes.ravel()\n\naxes[0].imshow(test_arr, cmap=plt.cm.gray)\naxes[1].imshow(ada_thold,cmap=plt.cm.gray)\n\naxes[0].axis('off')\naxes[1].axis('off')","metadata":{"pycharm":{"name":"#%%\n"},"execution":{"iopub.status.busy":"2026-01-08T17:45:58.435473Z","iopub.execute_input":"2026-01-08T17:45:58.435764Z","iopub.status.idle":"2026-01-08T17:45:58.942188Z","shell.execute_reply.started":"2026-01-08T17:45:58.435740Z","shell.execute_reply":"2026-01-08T17:45:58.941204Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"laplacian = cv2.Laplacian(test_arr,cv2.CV_64F, ksize=5)","metadata":{"pycharm":{"name":"#%%\n"},"execution":{"iopub.status.busy":"2026-01-08T17:45:58.943521Z","iopub.execute_input":"2026-01-08T17:45:58.943870Z","iopub.status.idle":"2026-01-08T17:45:58.981431Z","shell.execute_reply.started":"2026-01-08T17:45:58.943835Z","shell.execute_reply":"2026-01-08T17:45:58.980624Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"fig, axes = plt.subplots(nrows=1, ncols=2, figsize=[12,6], dpi=200)\naxes = axes.ravel()\n\naxes[0].imshow(test_arr, cmap=plt.cm.gray)\naxes[1].imshow(laplacian, cmap=plt.cm.gray)\n\naxes[0].axis('off')\naxes[1].axis('off')","metadata":{"pycharm":{"name":"#%%\n"},"execution":{"iopub.status.busy":"2026-01-08T17:45:58.982510Z","iopub.execute_input":"2026-01-08T17:45:58.982795Z","iopub.status.idle":"2026-01-08T17:45:59.545163Z","shell.execute_reply.started":"2026-01-08T17:45:58.982769Z","shell.execute_reply":"2026-01-08T17:45:59.544157Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"edgeEnahnced = test_image.filter(Filter.EDGE_ENHANCE_MORE)","metadata":{"pycharm":{"name":"#%%\n"},"execution":{"iopub.status.busy":"2026-01-08T17:45:59.546829Z","iopub.execute_input":"2026-01-08T17:45:59.547216Z","iopub.status.idle":"2026-01-08T17:45:59.556744Z","shell.execute_reply.started":"2026-01-08T17:45:59.547179Z","shell.execute_reply":"2026-01-08T17:45:59.555828Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"fig, axes = plt.subplots(nrows=1, ncols=2, figsize=[12,6], dpi=200)\naxes = axes.ravel()\n\naxes[0].imshow(test_arr, cmap=plt.cm.gray)\naxes[1].imshow(edgeEnahnced, cmap=plt.cm.gray)\n\naxes[0].axis('off')\naxes[1].axis('off')","metadata":{"pycharm":{"name":"#%%\n"},"execution":{"iopub.status.busy":"2026-01-08T17:45:59.557950Z","iopub.execute_input":"2026-01-08T17:45:59.558854Z","iopub.status.idle":"2026-01-08T17:46:00.168136Z","shell.execute_reply.started":"2026-01-08T17:45:59.558805Z","shell.execute_reply":"2026-01-08T17:46:00.167296Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"de_texturize = cv2.bilateralFilter(test_arr,9,50,50)","metadata":{"pycharm":{"name":"#%%\n"},"execution":{"iopub.status.busy":"2026-01-08T17:46:00.169705Z","iopub.execute_input":"2026-01-08T17:46:00.170184Z","iopub.status.idle":"2026-01-08T17:46:00.223214Z","shell.execute_reply.started":"2026-01-08T17:46:00.170118Z","shell.execute_reply":"2026-01-08T17:46:00.222452Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"fig, axes = plt.subplots(nrows=1, ncols=2, figsize=[12,6], dpi=200)\naxes = axes.ravel()\n\naxes[0].imshow(test_arr, cmap=plt.cm.gray)\naxes[1].imshow(de_texturize, cmap=plt.cm.gray)\n\naxes[0].axis('off')\naxes[1].axis('off')","metadata":{"pycharm":{"name":"#%%\n"},"execution":{"iopub.status.busy":"2026-01-08T17:46:00.224463Z","iopub.execute_input":"2026-01-08T17:46:00.224821Z","iopub.status.idle":"2026-01-08T17:46:00.778953Z","shell.execute_reply.started":"2026-01-08T17:46:00.224786Z","shell.execute_reply":"2026-01-08T17:46:00.778169Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"fig, axes = plt.subplots(nrows=1, ncols=3, figsize=[12,6], dpi=200)\naxes = axes.ravel()\n\naxes[0].imshow(test_arr, cmap=plt.cm.gray)\naxes[1].imshow(tf.image.adjust_saturation(test_arr_rgb, 1.4), cmap=plt.cm.gray)\naxes[2].imshow(tf.image.adjust_contrast(test_arr, 0.3), cmap=plt.cm.gray)\n\naxes[0].axis('off')\naxes[1].axis('off')\naxes[2].axis('off')","metadata":{"pycharm":{"name":"#%%\n"},"execution":{"iopub.status.busy":"2026-01-08T17:46:00.780220Z","iopub.execute_input":"2026-01-08T17:46:00.780792Z","iopub.status.idle":"2026-01-08T17:46:01.277350Z","shell.execute_reply.started":"2026-01-08T17:46:00.780757Z","shell.execute_reply":"2026-01-08T17:46:01.276321Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"image = Image.open('../input/unifesp-xray-body-part-classifier-dataset-jpeg/data/train/10166555243811009418614649510306269973.jpg')\nimage_arr = np.expand_dims(np.asarray(image),2) \nv_center = image_arr.shape[1]//2\nh_center = image_arr.shape[0]//2\n\nfig, axes = plt.subplots(nrows=1, ncols=4, figsize=[12,6], dpi=200)\naxes = axes.ravel()\n\naxes[0].imshow(image_arr[:h_center,:,:], cmap=plt.cm.gray)\naxes[1].imshow(image_arr[h_center:,:,:], cmap=plt.cm.gray)\naxes[2].imshow(image_arr[:,:v_center,:], cmap=plt.cm.gray)\naxes[3].imshow(image_arr[:,v_center:,:], cmap=plt.cm.gray)\n\naxes[0].axis('off')\naxes[1].axis('off')\naxes[2].axis('off')\naxes[3].axis('off')","metadata":{"pycharm":{"name":"#%%\n"},"execution":{"iopub.status.busy":"2026-01-08T17:46:01.281011Z","iopub.execute_input":"2026-01-08T17:46:01.281365Z","iopub.status.idle":"2026-01-08T17:46:01.810227Z","shell.execute_reply.started":"2026-01-08T17:46:01.281334Z","shell.execute_reply":"2026-01-08T17:46:01.809395Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"* ##### resize croped images without distroying aspect ratio","metadata":{"pycharm":{"name":"#%% md\n"}}},{"cell_type":"code","source":"img = Image.fromarray(np.squeeze(image_arr[:h_center,:,:], axis=2)).convert('L')\nimg.thumbnail((400, 400))\n\nplt.imshow(img, cmap=plt.cm.gray)","metadata":{"pycharm":{"name":"#%%\n"},"execution":{"iopub.status.busy":"2026-01-08T17:46:01.811532Z","iopub.execute_input":"2026-01-08T17:46:01.811862Z","iopub.status.idle":"2026-01-08T17:46:02.028193Z","shell.execute_reply.started":"2026-01-08T17:46:01.811831Z","shell.execute_reply":"2026-01-08T17:46:02.027201Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def edge_enhancing(array):\n    method = np.random.choice(['ada_thold', 'laplacian', 'edge_enahnced'])\n    \n    if method=='ada_thold':     \n        return np.expand_dims(cv2.adaptiveThreshold(array, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 11, 1), 2)\n    \n    elif method=='laplacian':\n        return np.expand_dims(cv2.Laplacian(array,cv2.CV_64F, ksize=5), 2)\n    \n    else:\n        image = Image.fromarray(np.squeeze(array, axis=2)).convert('L')\n        return np.expand_dims(np.asarray(image.filter(Filter.EDGE_ENHANCE_MORE)), 2)","metadata":{"pycharm":{"name":"#%%\n"},"execution":{"iopub.status.busy":"2026-01-08T17:46:02.029303Z","iopub.execute_input":"2026-01-08T17:46:02.029568Z","iopub.status.idle":"2026-01-08T17:46:02.035413Z","shell.execute_reply.started":"2026-01-08T17:46:02.029543Z","shell.execute_reply":"2026-01-08T17:46:02.034500Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def de_texturization(array):\n    n = np.random.choice([5, 9, 13, 15])\n    sigma = np.random.choice([50, 65, 75])\n    \n    return np.expand_dims(cv2.bilateralFilter(array, n, sigma, sigma), 2)","metadata":{"pycharm":{"name":"#%%\n"},"execution":{"iopub.status.busy":"2026-01-08T17:46:02.036683Z","iopub.execute_input":"2026-01-08T17:46:02.037242Z","iopub.status.idle":"2026-01-08T17:46:02.050590Z","shell.execute_reply.started":"2026-01-08T17:46:02.037208Z","shell.execute_reply":"2026-01-08T17:46:02.049809Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def random_flip(array):    \n    if random.choice([True, False]):\n        return tf.image.random_flip_left_right(array).numpy()\n    else:\n        return tf.image.random_flip_up_down(array).numpy()","metadata":{"pycharm":{"name":"#%%\n"},"execution":{"iopub.status.busy":"2026-01-08T17:46:02.051533Z","iopub.execute_input":"2026-01-08T17:46:02.051770Z","iopub.status.idle":"2026-01-08T17:46:02.059903Z","shell.execute_reply.started":"2026-01-08T17:46:02.051748Z","shell.execute_reply":"2026-01-08T17:46:02.059084Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def tumbnail(array, shape=(512,512)):\n    return cv2.resize(array, shape) ","metadata":{"pycharm":{"name":"#%%\n"},"execution":{"iopub.status.busy":"2026-01-08T17:46:02.060953Z","iopub.execute_input":"2026-01-08T17:46:02.061200Z","iopub.status.idle":"2026-01-08T17:46:02.070835Z","shell.execute_reply.started":"2026-01-08T17:46:02.061177Z","shell.execute_reply":"2026-01-08T17:46:02.069971Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def random_crop(array):\n    method = np.random.choice(['left', 'right', 'top', 'down'])\n    v_center = array.shape[1]//2\n    h_center = array.shape[0]//2\n    \n    if method == 'left':\n        return array[:,:v_center,:]\n    elif method == 'right':\n        return array[:,v_center:,:]\n    elif method == 'top':\n        return array[:h_center,:,:]\n    elif method == 'down':\n        return array[h_center:,:,:]\n    else:\n        return array","metadata":{"pycharm":{"name":"#%%\n"},"execution":{"iopub.status.busy":"2026-01-08T17:46:02.071843Z","iopub.execute_input":"2026-01-08T17:46:02.072110Z","iopub.status.idle":"2026-01-08T17:46:02.082009Z","shell.execute_reply.started":"2026-01-08T17:46:02.072088Z","shell.execute_reply":"2026-01-08T17:46:02.081230Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"image = Image.open('../input/unifesp-xray-body-part-classifier-dataset-jpeg/data/train/10166555243811009418614649510306269973.jpg')\nimage_arr = np.expand_dims(np.asarray(image), axis=2)\nfig, axes = plt.subplots(nrows=1, ncols=4, figsize=[12,6], dpi=200)\naxes = axes.ravel()\n\nfor i in range(len(axes)):\n    axes[i].imshow(edge_enhancing(image_arr), cmap=plt.cm.gray)\n    axes[i].axis('off')","metadata":{"pycharm":{"name":"#%%\n"},"execution":{"iopub.status.busy":"2026-01-08T17:46:02.083111Z","iopub.execute_input":"2026-01-08T17:46:02.083728Z","iopub.status.idle":"2026-01-08T17:46:02.804662Z","shell.execute_reply.started":"2026-01-08T17:46:02.083674Z","shell.execute_reply":"2026-01-08T17:46:02.803664Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"image_arr = np.expand_dims(np.asarray(image), axis=2)\nfig, axes = plt.subplots(nrows=1, ncols=4, figsize=[12,6], dpi=200)\naxes = axes.ravel()\n\nfor i in range(len(axes)):\n    axes[i].imshow(de_texturization(image_arr), cmap=plt.cm.gray)\n    axes[i].axis('off')","metadata":{"pycharm":{"name":"#%%\n"},"execution":{"iopub.status.busy":"2026-01-08T17:46:02.806228Z","iopub.execute_input":"2026-01-08T17:46:02.806552Z","iopub.status.idle":"2026-01-08T17:46:03.821280Z","shell.execute_reply.started":"2026-01-08T17:46:02.806523Z","shell.execute_reply":"2026-01-08T17:46:03.820313Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"image_arr = np.expand_dims(np.asarray(image), axis=2)\nfig, axes = plt.subplots(nrows=1, ncols=4, figsize=[12,6], dpi=200)\naxes = axes.ravel()\n\nfor i in range(len(axes)):\n    img = tumbnail(random_crop(image_arr))\n    axes[i].imshow(img, cmap=plt.cm.gray)\n    axes[i].axis('off')","metadata":{"pycharm":{"name":"#%%\n"},"execution":{"iopub.status.busy":"2026-01-08T17:46:03.822779Z","iopub.execute_input":"2026-01-08T17:46:03.823178Z","iopub.status.idle":"2026-01-08T17:46:04.522020Z","shell.execute_reply.started":"2026-01-08T17:46:03.823120Z","shell.execute_reply":"2026-01-08T17:46:04.521166Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def pre_procrssing(image):\n    temp = np.asarray(image)\n    \n    if np.random.choice([True, False], p=[0.45, 0.55]):\n        # other augmentaions\n        temp = de_texturization(temp)\n        \n        # crop\n        if random.choice([True, False]):\n            temp = tf.image.random_crop(temp, (128,128,1)).numpy()\n        else:\n            temp = random_crop(temp)\n        \n        temp = tumbnail(temp, (input_size, input_size))\n\n        return np.expand_dims(temp, 2)\n    \n    else:\n        return temp","metadata":{"pycharm":{"name":"#%%\n"},"execution":{"iopub.status.busy":"2026-01-08T17:46:04.523331Z","iopub.execute_input":"2026-01-08T17:46:04.523705Z","iopub.status.idle":"2026-01-08T17:46:04.531250Z","shell.execute_reply.started":"2026-01-08T17:46:04.523668Z","shell.execute_reply":"2026-01-08T17:46:04.530365Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Test Pre-processing Pipeline","metadata":{"pycharm":{"name":"#%% md\n"}}},{"cell_type":"code","source":"files = os.listdir('../input/unifesp-xray-body-part-classifier-dataset-jpeg/data/train')\nrand_files = random.choices(files, k=24)\n\nfig, axes = plt.subplots(nrows=4, ncols=6, figsize=[12,8], dpi=200)\naxes = axes.ravel()\n\nfor i in range(len(axes)):\n    img = Image.open(os.path.join('../input/unifesp-xray-body-part-classifier-dataset-jpeg/data/train',rand_files[i]))\n    img = pre_procrssing(img)\n    axes[i].imshow(img, cmap=plt.cm.gray)\n    axes[i].axis('off')","metadata":{"pycharm":{"name":"#%%\n"},"execution":{"iopub.status.busy":"2026-01-08T17:46:04.532234Z","iopub.execute_input":"2026-01-08T17:46:04.532502Z","iopub.status.idle":"2026-01-08T17:46:07.653787Z","shell.execute_reply.started":"2026-01-08T17:46:04.532479Z","shell.execute_reply":"2026-01-08T17:46:07.652663Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_df = pd.read_csv('../input/xray-body-images-in-png-unifesp-competion/train_df.csv', usecols=['image_path', 'Target'])\n# train_df['file_name'] = train_df['file_name'] + '.jpg'\ntrain_df","metadata":{"pycharm":{"name":"#%%\n"},"execution":{"iopub.status.busy":"2026-01-08T17:46:07.655465Z","iopub.execute_input":"2026-01-08T17:46:07.655814Z","iopub.status.idle":"2026-01-08T17:46:07.715310Z","shell.execute_reply.started":"2026-01-08T17:46:07.655781Z","shell.execute_reply":"2026-01-08T17:46:07.714183Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# train_df['file_name'] = '../input/unifesp-xray-body-part-classifier-dataset-jpeg/data/train/' + train_df['file_name']\ntrain_df['Target'] = train_df['Target'].str.strip()","metadata":{"pycharm":{"name":"#%%\n"},"execution":{"iopub.status.busy":"2026-01-08T17:46:07.716738Z","iopub.execute_input":"2026-01-08T17:46:07.717066Z","iopub.status.idle":"2026-01-08T17:46:07.726515Z","shell.execute_reply.started":"2026-01-08T17:46:07.717036Z","shell.execute_reply":"2026-01-08T17:46:07.725153Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"multi_labels = [i for i, target in enumerate(train_df['Target']) if len(target) > 2]\nlen(multi_labels)","metadata":{"pycharm":{"name":"#%%\n"},"execution":{"iopub.status.busy":"2026-01-08T17:46:07.727838Z","iopub.execute_input":"2026-01-08T17:46:07.728182Z","iopub.status.idle":"2026-01-08T17:46:07.740404Z","shell.execute_reply.started":"2026-01-08T17:46:07.728154Z","shell.execute_reply":"2026-01-08T17:46:07.739332Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"corrected_labels = []\n\nfor ml in multi_labels:    \n    corrected_labels.append([train_df.loc[ml, 'image_path'], train_df.loc[ml, 'Target'].split(' ')[0]])","metadata":{"pycharm":{"name":"#%%\n"},"execution":{"iopub.status.busy":"2026-01-08T17:46:07.741759Z","iopub.execute_input":"2026-01-08T17:46:07.742067Z","iopub.status.idle":"2026-01-08T17:46:07.753553Z","shell.execute_reply.started":"2026-01-08T17:46:07.742040Z","shell.execute_reply":"2026-01-08T17:46:07.752663Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_df = pd.concat([train_df.drop(train_df.loc[multi_labels].index),\n                     pd.DataFrame(corrected_labels, columns=['image_path', 'Target'])], ignore_index=True)\ntrain_df","metadata":{"pycharm":{"name":"#%%\n"},"execution":{"iopub.status.busy":"2026-01-08T17:46:07.754714Z","iopub.execute_input":"2026-01-08T17:46:07.755038Z","iopub.status.idle":"2026-01-08T17:46:07.781226Z","shell.execute_reply.started":"2026-01-08T17:46:07.755010Z","shell.execute_reply":"2026-01-08T17:46:07.780331Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_df","metadata":{"execution":{"iopub.status.busy":"2026-01-08T17:46:07.782345Z","iopub.execute_input":"2026-01-08T17:46:07.782620Z","iopub.status.idle":"2026-01-08T17:46:07.794907Z","shell.execute_reply.started":"2026-01-08T17:46:07.782594Z","shell.execute_reply":"2026-01-08T17:46:07.793799Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_df['image_path'] = train_df['image_path'].str.replace('./images','../input/xray-body-images-in-png-unifesp-competion/images')","metadata":{"execution":{"iopub.status.busy":"2026-01-08T17:46:07.796154Z","iopub.execute_input":"2026-01-08T17:46:07.796466Z","iopub.status.idle":"2026-01-08T17:46:07.810203Z","shell.execute_reply.started":"2026-01-08T17:46:07.796440Z","shell.execute_reply":"2026-01-08T17:46:07.809302Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Create more training samples","metadata":{}},{"cell_type":"code","source":"new_train_data = []\n\nif not os.path.isdir('./train'):\n    os.mkdir('./train')\n    \nfor j, (tar, file) in enumerate(train_df.values):\n    img = cv2.imread(file, cv2.IMREAD_GRAYSCALE)\n    img = np.expand_dims(img, 2)\n    \n    for i, scale in enumerate([0.5, 0.65, 0.8, 0.95]):\n        new_file_path = f\"./train/c-{i}-{file.split('/')[-1]}\"\n        temp = tf.image.central_crop(img, scale).numpy()\n        temp = edge_enhancing(temp)\n        cv2.imwrite(new_file_path, temp)\n        new_train_data.append([tar, new_file_path])\n        \n        print(f'{j}/{train_df.shape[0]} -- {i+1}', end='\\r')","metadata":{"execution":{"iopub.status.busy":"2026-01-08T17:46:07.811312Z","iopub.execute_input":"2026-01-08T17:46:07.811583Z","iopub.status.idle":"2026-01-08T17:46:51.606511Z","shell.execute_reply.started":"2026-01-08T17:46:07.811559Z","shell.execute_reply":"2026-01-08T17:46:51.605449Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"files = os.listdir('./train/')\nrand_files = random.choices(files, k=24)\n\nfig, axes = plt.subplots(nrows=4, ncols=6, figsize=[12,8], dpi=200)\naxes = axes.ravel()\n\nfor i in range(len(axes)):\n    img = Image.open(os.path.join('./train',rand_files[i]))\n    axes[i].imshow(img, cmap=plt.cm.gray)\n    axes[i].axis('off')","metadata":{"execution":{"iopub.status.busy":"2026-01-08T17:46:51.608014Z","iopub.execute_input":"2026-01-08T17:46:51.608784Z","iopub.status.idle":"2026-01-08T17:46:53.460202Z","shell.execute_reply.started":"2026-01-08T17:46:51.608743Z","shell.execute_reply":"2026-01-08T17:46:53.458787Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"new_train_data = pd.DataFrame(new_train_data, columns=['Target', 'image_path'])\nnew_train_data","metadata":{"execution":{"iopub.status.busy":"2026-01-08T17:46:53.462062Z","iopub.execute_input":"2026-01-08T17:46:53.463096Z","iopub.status.idle":"2026-01-08T17:46:53.477873Z","shell.execute_reply.started":"2026-01-08T17:46:53.463042Z","shell.execute_reply":"2026-01-08T17:46:53.477000Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_df = pd.concat([train_df, new_train_data], ignore_index=True)\ntrain_df","metadata":{"execution":{"iopub.status.busy":"2026-01-08T17:46:53.479340Z","iopub.execute_input":"2026-01-08T17:46:53.480074Z","iopub.status.idle":"2026-01-08T17:46:53.495931Z","shell.execute_reply.started":"2026-01-08T17:46:53.480015Z","shell.execute_reply":"2026-01-08T17:46:53.495067Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train, test = train_test_split(train_df[['image_path', 'Target']], test_size=0.1)\ntrain.shape, test.shape","metadata":{"pycharm":{"name":"#%%\n"},"execution":{"iopub.status.busy":"2026-01-08T17:46:53.497419Z","iopub.execute_input":"2026-01-08T17:46:53.497701Z","iopub.status.idle":"2026-01-08T17:46:53.511969Z","shell.execute_reply.started":"2026-01-08T17:46:53.497677Z","shell.execute_reply":"2026-01-08T17:46:53.511035Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Build Model","metadata":{"pycharm":{"name":"#%% md\n"}}},{"cell_type":"markdown","source":"### Config Data Loders","metadata":{"pycharm":{"name":"#%% md\n"}}},{"cell_type":"code","source":"generator = ImageDataGenerator(rescale=1 / 255,\n                               rotation_range=10,\n                               width_shift_range=0.25,\n                               height_shift_range=0.25,\n                               shear_range=0.2,\n                               horizontal_flip=True,\n                               vertical_flip=True,\n                               samplewise_center=True,\n                               samplewise_std_normalization=True,\n                               validation_split=valid_split,\n                               preprocessing_function=pre_procrssing\n                              )\n\ntest_generator = ImageDataGenerator(rescale=1 / 255,\n                                    samplewise_center=True,\n                                    samplewise_std_normalization=True)\n\ntrain_datagen = generator.flow_from_dataframe(dataframe=train,\n                                              x_col='image_path',\n                                              y_col='Target',\n                                              target_size=(input_size, input_size),\n                                              batch_size=batch_size,\n                                              color_mode='grayscale',\n                                              subset='training',\n                                              seed=48)\n\nvalid_datagen = generator.flow_from_dataframe(dataframe=train,\n                                              x_col='image_path',\n                                              y_col='Target',\n                                              target_size=(input_size, input_size),\n                                              batch_size=batch_size,\n                                              color_mode='grayscale',\n                                              subset='validation',\n                                              shuffle=False,\n                                              seed=48)\n\ntest_datagen = test_generator.flow_from_dataframe(dataframe=test,\n                                                  x_col='image_path',\n                                                  y_col='Target',\n                                                  color_mode='grayscale',\n                                                  batch_size=batch_size,\n                                                  target_size=(input_size, input_size),\n                                                  shuffle=False,\n                                                  seed=48)","metadata":{"pycharm":{"name":"#%%\n"},"execution":{"iopub.status.busy":"2026-01-08T17:46:53.513236Z","iopub.execute_input":"2026-01-08T17:46:53.513676Z","iopub.status.idle":"2026-01-08T17:46:54.406309Z","shell.execute_reply.started":"2026-01-08T17:46:53.513648Z","shell.execute_reply":"2026-01-08T17:46:54.405356Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Train mini batch","metadata":{"pycharm":{"name":"#%% md\n"}}},{"cell_type":"code","source":"fig, axes = plt.subplots(nrows=4, ncols=8, figsize=[32, 10], dpi=200)\naxes = axes.ravel()\n\nfor i, arr in enumerate(train_datagen.next()[0]):\n    img = tf.keras.utils.array_to_img(arr)\n    axes[i].imshow(img, cmap=plt.cm.gray)\n    \nplt.show()","metadata":{"pycharm":{"name":"#%%\n"},"execution":{"iopub.status.busy":"2026-01-08T17:46:54.407623Z","iopub.execute_input":"2026-01-08T17:46:54.408023Z","iopub.status.idle":"2026-01-08T17:46:58.909780Z","shell.execute_reply.started":"2026-01-08T17:46:54.407982Z","shell.execute_reply":"2026-01-08T17:46:58.908520Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Validation mini batch","metadata":{"pycharm":{"name":"#%% md\n"}}},{"cell_type":"code","source":"fig, axes = plt.subplots(nrows=4, ncols=8, figsize=[32, 10], dpi=200)\naxes = axes.ravel()\n\nfor i, arr in enumerate(valid_datagen.next()[0]):\n    img = tf.keras.utils.array_to_img(arr)\n    axes[i].imshow(img, cmap=plt.cm.gray)\n    \nplt.show()","metadata":{"pycharm":{"name":"#%%\n"},"execution":{"iopub.status.busy":"2026-01-08T17:46:58.911676Z","iopub.execute_input":"2026-01-08T17:46:58.912512Z","iopub.status.idle":"2026-01-08T17:47:03.605774Z","shell.execute_reply.started":"2026-01-08T17:46:58.912456Z","shell.execute_reply":"2026-01-08T17:47:03.604137Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Test mini batch","metadata":{"pycharm":{"name":"#%% md\n"}}},{"cell_type":"code","source":"fig, axes = plt.subplots(nrows=4, ncols=8, figsize=[32, 10], dpi=200)\naxes = axes.ravel()\n\nfor i, arr in enumerate(test_datagen.next()[0]):\n    img = tf.keras.utils.array_to_img(arr)\n    axes[i].imshow(img, cmap=plt.cm.gray)\n    \nplt.show()","metadata":{"pycharm":{"name":"#%%\n"},"execution":{"iopub.status.busy":"2026-01-08T17:47:03.612830Z","iopub.execute_input":"2026-01-08T17:47:03.613785Z","execution_failed":"2026-01-08T23:08:01.723Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Base Estimator Sequential Model","metadata":{"pycharm":{"name":"#%% md\n"}}},{"cell_type":"code","source":"early_stop = tf.keras.callbacks.EarlyStopping(patience=25,\n                                              monitor='val_loss',\n                                              restore_best_weights=True,\n                                              verbose=1)\n\nreduce_lr = tf.keras.callbacks.ReduceLROnPlateau(patience=5,\n                                                 monitor='val_loss',\n                                                 factor=0.5,\n                                                 verbose=1)","metadata":{"pycharm":{"name":"#%%\n"},"execution":{"execution_failed":"2026-01-08T23:08:01.725Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model_input = Input((input_size, input_size, 1))\nfeat_exc_input = Concatenate()([model_input, model_input, model_input])\nfeature_extractor = tf.keras.applications.Xception(include_top=False,\n                                                   weights=\"imagenet\",\n                                                   input_tensor=feat_exc_input)\n\nmodel = Sequential([feature_extractor,\n                    AveragePooling2D((3,3)),\n                    Flatten(),\n                    Dense(units=classes, activation=softmax)])\n\nmodel.compile(optimizer=optimizer,\n                  loss=loss,\n                  metrics=['accuracy', tfa.metrics.F1Score(num_classes=classes, threshold=0.5)])","metadata":{"execution":{"execution_failed":"2026-01-08T23:08:01.725Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model.summary()","metadata":{"execution":{"execution_failed":"2026-01-08T23:08:01.725Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Training and Evaluation","metadata":{"pycharm":{"name":"#%% md\n"}}},{"cell_type":"code","source":"history = model.fit(train_datagen,\n                    validation_data=valid_datagen,\n                    batch_size=batch_size,\n                    epochs=epochs,\n                    callbacks=[early_stop,reduce_lr])","metadata":{"pycharm":{"name":"#%%\n"},"execution":{"execution_failed":"2026-01-08T23:08:01.725Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model.evaluate(test_datagen)","metadata":{"execution":{"execution_failed":"2026-01-08T23:08:01.725Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"test_preds = np.argmax(model.predict(test_datagen), axis=1)\npred_y = [{v:k for k,v in train_datagen.class_indices.items()}[k] for k in test_preds]\ntrue_y = test.Target.values","metadata":{"pycharm":{"name":"#%%\n"},"execution":{"execution_failed":"2026-01-08T23:08:01.725Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"acc_score_test = accuracy_score(true_y, pred_y)\nconf_metric = confusion_matrix(true_y, pred_y, labels=list(train_datagen.class_indices.keys()))","metadata":{"execution":{"execution_failed":"2026-01-08T23:08:01.725Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"plt.figure(figsize=[12,12], dpi=100)\nsns.heatmap(np.round(conf_metric/np.sum(conf_metric, axis=1), 2),\n            cbar=False,\n            annot=True,\n            annot_kws={\"size\": 9},\n            cmap=plt.cm.Blues)\nplt.xlabel('True labels')\nplt.ylabel('Predicted labels')\nplt.show()","metadata":{"execution":{"execution_failed":"2026-01-08T23:08:01.725Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"plt.figure(figsize=[12,6], dpi=300)\nsns.lineplot(x=list(range(len(history.history['accuracy']))),\n             y=history.history['accuracy'],\n             label='train')\nsns.lineplot(x=list(range(len(history.history['val_accuracy']))),\n             y=history.history['val_accuracy'],\n             label='validation')\nplt.show()","metadata":{"pycharm":{"name":"#%%\n"},"execution":{"execution_failed":"2026-01-08T23:08:01.725Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"plt.figure(figsize=[12,6], dpi=300)\nsns.lineplot(x=list(range(len(np.mean(history.history['f1_score'], axis=1)))),\n             y=np.mean(history.history['f1_score'], axis=1),\n             label='train')\nsns.lineplot(x=list(range(len(np.mean(history.history['val_f1_score'], axis=1)))),\n             y=np.mean(history.history['val_f1_score'], axis=1),\n             label='validation')\nplt.show()","metadata":{"pycharm":{"name":"#%%\n"},"execution":{"execution_failed":"2026-01-08T23:08:01.725Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"plt.figure(figsize=[12,6], dpi=300)\nsns.lineplot(x=list(range(len(history.history['loss']))),\n             y=history.history['loss'],\n             label='train')\nsns.lineplot(x=list(range(len(history.history['val_loss']))),\n             y=history.history['val_loss'],\n             label='validation')\nplt.show()","metadata":{"pycharm":{"name":"#%%\n"},"execution":{"execution_failed":"2026-01-08T23:08:01.725Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Saving files","metadata":{"pycharm":{"name":"#%% md\n"}}},{"cell_type":"code","source":"temp = pd.DataFrame(history.history)\ntemp.to_csv('model_Xception.csv', index=False)","metadata":{"pycharm":{"name":"#%%\n"},"execution":{"execution_failed":"2026-01-08T23:08:01.726Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model.save('model_Xception.hdf5')","metadata":{"pycharm":{"name":"#%%\n"},"execution":{"execution_failed":"2026-01-08T23:08:01.726Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model.save_weights('model_Xception_weight.hdf5')","metadata":{"pycharm":{"name":"#%%\n"},"execution":{"execution_failed":"2026-01-08T23:08:01.726Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### Inference","metadata":{"pycharm":{"name":"#%% md\n"}}},{"cell_type":"code","source":"test_loc = '../input/xray-body-images-in-png-unifesp-competion/images/test'\n\ntest_data = ImageDataGenerator(rescale=1.0/255,\n                               samplewise_center=True,\n                               samplewise_std_normalization=True).flow_from_directory(directory=test_loc,\n                                                                                      target_size=(input_size, input_size),\n                                                                                      batch_size=batch_size,\n                                                                                      classes=['.'],\n                                                                                      color_mode='grayscale',\n                                                                                      shuffle=False)","metadata":{"pycharm":{"name":"#%%\n"},"execution":{"iopub.status.idle":"2026-01-08T22:11:50.870095Z","shell.execute_reply.started":"2026-01-08T22:11:49.667116Z","shell.execute_reply":"2026-01-08T22:11:50.869055Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"preds_p = model.predict(test_data, verbose=1)","metadata":{"pycharm":{"name":"#%%\n"},"execution":{"iopub.status.busy":"2026-01-08T22:11:50.871240Z","iopub.execute_input":"2026-01-08T22:11:50.871546Z","iopub.status.idle":"2026-01-08T22:11:57.886288Z","shell.execute_reply.started":"2026-01-08T22:11:50.871519Z","shell.execute_reply":"2026-01-08T22:11:57.885571Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"inverse_map = {v:k for k,v in train_datagen.class_indices.items()}\ninverse_map","metadata":{"execution":{"iopub.status.busy":"2026-01-08T22:11:57.887536Z","iopub.execute_input":"2026-01-08T22:11:57.887804Z","iopub.status.idle":"2026-01-08T22:11:57.894673Z","shell.execute_reply.started":"2026-01-08T22:11:57.887780Z","shell.execute_reply":"2026-01-08T22:11:57.893925Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"test_preds = []\n\nfor i in range(len(preds_p)):\n    multi_lab = np.where(preds_p[i]>0.5)[0].tolist()\n    \n    if len(multi_lab) > 1:\n        test_preds.append([test_data.filenames[i], ' '.join([inverse_map[m] for m in multi_lab])])\n    else:\n        test_preds.append([test_data.filenames[i], inverse_map[np.argmax(preds_p[i])]])","metadata":{"execution":{"iopub.status.busy":"2026-01-08T22:11:57.895856Z","iopub.execute_input":"2026-01-08T22:11:57.896305Z","iopub.status.idle":"2026-01-08T22:11:57.909601Z","shell.execute_reply.started":"2026-01-08T22:11:57.896252Z","shell.execute_reply":"2026-01-08T22:11:57.908789Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"test_preds = pd.DataFrame(test_preds, columns=['SOPInstanceUID', 'Target'])\ntest_preds","metadata":{"execution":{"iopub.status.busy":"2026-01-08T22:11:57.910766Z","iopub.execute_input":"2026-01-08T22:11:57.911010Z","iopub.status.idle":"2026-01-08T22:11:57.927003Z","shell.execute_reply.started":"2026-01-08T22:11:57.910988Z","shell.execute_reply":"2026-01-08T22:11:57.926179Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"test_preds['SOPInstanceUID'] = test_preds['SOPInstanceUID'].str.replace('-c.png', '')\ntest_preds['SOPInstanceUID'] = test_preds['SOPInstanceUID'].str.replace('./', '')\ntest_preds","metadata":{"execution":{"iopub.status.busy":"2026-01-08T22:11:57.928123Z","iopub.execute_input":"2026-01-08T22:11:57.928410Z","iopub.status.idle":"2026-01-08T22:11:57.948341Z","shell.execute_reply.started":"2026-01-08T22:11:57.928383Z","shell.execute_reply":"2026-01-08T22:11:57.947489Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"test_preds.to_csv('model_submission_v5.csv', index=False)","metadata":{"execution":{"iopub.status.busy":"2026-01-08T22:11:57.949566Z","iopub.execute_input":"2026-01-08T22:11:57.949914Z","iopub.status.idle":"2026-01-08T22:11:57.960166Z","shell.execute_reply.started":"2026-01-08T22:11:57.949878Z","shell.execute_reply":"2026-01-08T22:11:57.959322Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"pd.options.display.max_rows = 150\ntest_preds.Target.value_counts()","metadata":{"execution":{"iopub.status.busy":"2026-01-08T22:11:57.961349Z","iopub.execute_input":"2026-01-08T22:11:57.961581Z","iopub.status.idle":"2026-01-08T22:11:57.969895Z","shell.execute_reply.started":"2026-01-08T22:11:57.961560Z","shell.execute_reply":"2026-01-08T22:11:57.969014Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from IPython.display import FileLink\nFileLink('model_submission_v5.csv')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-08T22:11:57.970915Z","iopub.execute_input":"2026-01-08T22:11:57.971128Z","iopub.status.idle":"2026-01-08T22:11:57.979414Z","shell.execute_reply.started":"2026-01-08T22:11:57.971108Z","shell.execute_reply":"2026-01-08T22:11:57.978634Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import pandas as pd\nfrom IPython.display import FileLink\n\n# 1. توليد التوقعات - تم تغيير test_generator لـ test_datagen\ntest_preds = model.predict(test_datagen)\n\n# 2. إنشاء جدول البيانات - تم تغيير test_generator لـ test_datagen\nsubmission = pd.DataFrame({\n    'Id': test_datagen.filenames, \n    'Target': test_preds.argmax(axis=1)\n})\n\n# 3. حفظ الملف في مخرجات كاجل\nsubmission.to_csv('model_submission_v5_final.csv', index=False)\n\n# 4. الرابط الأزرق للتحميل\nFileLink('model_submission_v5_final.csv')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-08T22:28:00.965943Z","iopub.execute_input":"2026-01-08T22:28:00.966322Z","iopub.status.idle":"2026-01-08T22:28:04.647637Z","shell.execute_reply.started":"2026-01-08T22:28:00.966261Z","shell.execute_reply":"2026-01-08T22:28:04.646514Z"}},"outputs":[],"execution_count":null}]}