{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python Docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load\n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\n# Input data files are available in the read-only \"../input/\" directory\n# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory\n\nimport os\n\n# You can write up to 20GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using \"Save & Run All\" \n# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2022-07-07T10:56:52.182307Z","iopub.execute_input":"2022-07-07T10:56:52.182802Z","iopub.status.idle":"2022-07-07T10:56:52.190102Z","shell.execute_reply.started":"2022-07-07T10:56:52.182765Z","shell.execute_reply":"2022-07-07T10:56:52.188457Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import pickle\nimport multiprocessing\n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\nimport keras.backend as K #to define custom loss function\nimport tensorflow as tf #We'll use tensorflow backend here\nimport dask.dataframe as dd\nimport matplotlib.pyplot as plt\n\nfrom tqdm import tnrange, tqdm_notebook\nfrom collections import OrderedDict\nfrom keras.models import Sequential\nfrom keras.layers import Conv2D, MaxPooling2D, Dropout, Dense, Flatten, Input, AveragePooling1D, Reshape, DepthwiseConv2D, SeparableConv2D\nfrom tensorflow.keras.optimizers import Adam, SGD\nfrom keras.callbacks import ReduceLROnPlateau,ModelCheckpoint,EarlyStopping\nfrom sklearn.model_selection import StratifiedShuffleSplit\nfrom datetime import datetime\nfrom sklearn.model_selection import StratifiedKFold\nfrom sklearn.preprocessing import MinMaxScaler\n","metadata":{"execution":{"iopub.status.busy":"2022-07-07T10:56:52.446014Z","iopub.execute_input":"2022-07-07T10:56:52.446502Z","iopub.status.idle":"2022-07-07T10:56:52.455904Z","shell.execute_reply.started":"2022-07-07T10:56:52.44646Z","shell.execute_reply":"2022-07-07T10:56:52.454777Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df=pd.read_csv(\"../input/mayo-clinic-strip-ai/train.csv\")\ndf","metadata":{"execution":{"iopub.status.busy":"2022-07-07T10:56:52.642702Z","iopub.execute_input":"2022-07-07T10:56:52.643185Z","iopub.status.idle":"2022-07-07T10:56:52.66732Z","shell.execute_reply.started":"2022-07-07T10:56:52.643145Z","shell.execute_reply":"2022-07-07T10:56:52.666292Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df[\"label\"].value_counts()","metadata":{"execution":{"iopub.status.busy":"2022-07-07T10:56:52.795708Z","iopub.execute_input":"2022-07-07T10:56:52.79647Z","iopub.status.idle":"2022-07-07T10:56:52.807996Z","shell.execute_reply.started":"2022-07-07T10:56:52.796412Z","shell.execute_reply":"2022-07-07T10:56:52.806125Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### **A custom loss function can be created by defining a function that takes the true values and predicted values as required parameters. The function should return an array of losses. The function can then be passed at the compile stage**\n### **NN training depends on being able to compute the derivatives of all functions in the graph including the loss function. Keras backend functions is annotated such that it automatically known how to compute gradients. That is not the case for numpy functions** \n\n## Thus we have used **keras backened** for every operation.\n","metadata":{}},{"cell_type":"markdown","source":"I would advise you to use Keras backend functions instead of Numpy functions to avoid any misadventure. Keras backend functions work almost similar to Numpy functions.","metadata":{}},{"cell_type":"code","source":"epsilon = 1e-7 #Define epsilon so that the backpropagation will not result in NaN for 0 divisor case\nn_classes=2 #As there are two classes in the dataset\nweights = np.ones(n_classes, dtype='float32')  #For this competition, you can use weights from probing the leaderboard\nclass_counts = df.groupby('label')['image_id'].count().values \nclass_proportions = class_counts/np.max(class_counts)\nK.set_floatx('float32') #You can also set backend to any float","metadata":{"execution":{"iopub.status.busy":"2022-07-07T10:56:52.893394Z","iopub.execute_input":"2022-07-07T10:56:52.894173Z","iopub.status.idle":"2022-07-07T10:56:52.905515Z","shell.execute_reply.started":"2022-07-07T10:56:52.89412Z","shell.execute_reply":"2022-07-07T10:56:52.903977Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#weighted multi-class log loss\ndef weighted_mc_log_loss(y_true, y_pred):\n    # Clipping the prediction value\n    y_pred_clipped = K.clip(y_pred, epsilon, 1-epsilon)  \n    #true labels weighted by weights and percent elements per class\n    y_true_weighted = (y_true * weights)/class_proportions\n    #multiply tensors element-wise and then sum\n    loss_num = (y_true_weighted * K.log(y_pred_clipped))\n    loss = -1*K.sum(loss_num)/K.sum(weights)\n    \n    return loss\n\n#The output will be in Tensor format","metadata":{"execution":{"iopub.status.busy":"2022-07-07T10:56:53.032387Z","iopub.execute_input":"2022-07-07T10:56:53.033132Z","iopub.status.idle":"2022-07-07T10:56:53.040709Z","shell.execute_reply.started":"2022-07-07T10:56:53.03308Z","shell.execute_reply":"2022-07-07T10:56:53.039634Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## To use the custom loss to your model, you need to use it with the **model.compile**.\n\n\n> model.compile(loss=weighted_mc_log_loss, optimizer=Adam(lr=0.002), metrics=['accuracy'])","metadata":{}},{"cell_type":"markdown","source":"# **Example**:","metadata":{}},{"cell_type":"code","source":"y_true = K.variable(np.eye(n_classes, dtype='float32'))\ny_pred = K.variable(np.eye(n_classes, dtype='float32'))\nres = weighted_mc_log_loss(y_true, y_pred) \nK.eval(res) #The results are in tensor format. Thus we need to use the K.eval method","metadata":{"execution":{"iopub.status.busy":"2022-07-07T10:56:53.153092Z","iopub.execute_input":"2022-07-07T10:56:53.15382Z","iopub.status.idle":"2022-07-07T10:56:53.169481Z","shell.execute_reply.started":"2022-07-07T10:56:53.15377Z","shell.execute_reply":"2022-07-07T10:56:53.168412Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## **References:**","metadata":{}},{"cell_type":"markdown","source":"* https://keras.io/api/utils/backend_utils/\n* https://stackoverflow.com/questions/37657260/how-to-implement-custom-metric-in-keras\n* https://neptune.ai/blog/keras-loss-functions\n* https://stackoverflow.com/questions/57121708/do-i-need-to-use-backend-function-for-a-custom-keras-loss\n* https://stackoverflow.com/questions/63288078/can-you-write-a-custom-loss-function-in-keras-using-numpy-operations\n* https://www.kaggle.com/code/pankajb64/cnn-based-classification-of-light-curves\n* https://www.kaggle.com/code/ogrellier/plasticc-in-a-kernel-meta-and-data/script\n* ","metadata":{}},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}