{"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":"none","dataSources":[{"sourceId":7327,"databundleVersionId":861871,"sourceType":"competition"},{"sourceId":3659,"sourceType":"modelInstanceVersion","modelInstanceId":2604}],"dockerImageVersionId":30698,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# Transfer Learning with Dog Breed Dataset\nThis notebook is a short introduction to Transfer Learning with **mobilenet-v2 model from Tensorflow**.\n\nThere are following chapters:\n* Data preparation\n* Images' preprocessing\n* Fun with model\n\nWe will explore a callback and Tensorflowboard too. ","metadata":{}},{"cell_type":"markdown","source":"# Data preparation\nDuring the model creation I discovered that mobilenet-v2 model doesn't work properly with current version of Tensorflow. After a research I selected one of possible options to solve it. Therefore I install older version of keras and import tf_keras as tfk especially for model creation and using.\n\nLater in this chapter there will be:\n* libraries' import\n* dataset creation\n* checking for a few images and labels ","metadata":{}},{"cell_type":"code","source":"# to solve a problem durnig a model creation's error we have to install an older version of tensorflow keras\n!pip install tf_keras","metadata":{"execution":{"iopub.status.busy":"2024-05-10T14:02:56.347611Z","iopub.execute_input":"2024-05-10T14:02:56.347894Z","iopub.status.idle":"2024-05-10T14:03:12.339451Z","shell.execute_reply.started":"2024-05-10T14:02:56.347871Z","shell.execute_reply":"2024-05-10T14:03:12.338195Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# libraries' import\nimport os\nimport pandas as pd\nimport numpy as np\nimport datetime\nimport random\n\nimport tensorflow as tf\nimport tensorflow_hub as hub\nimport tf_keras as tfk\n\nfrom IPython.display import Image\nfrom sklearn.preprocessing import OneHotEncoder\nfrom sklearn.model_selection import train_test_split","metadata":{"execution":{"iopub.status.busy":"2024-05-10T14:03:12.341511Z","iopub.execute_input":"2024-05-10T14:03:12.341861Z","iopub.status.idle":"2024-05-10T14:03:24.987751Z","shell.execute_reply.started":"2024-05-10T14:03:12.341830Z","shell.execute_reply":"2024-05-10T14:03:24.986813Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# labels dataframe preparation\nlabels=pd.read_csv('/kaggle/input/dog-breed-identification/labels.csv')\nlabels.info()","metadata":{"execution":{"iopub.status.busy":"2024-05-10T14:03:24.989002Z","iopub.execute_input":"2024-05-10T14:03:24.989955Z","iopub.status.idle":"2024-05-10T14:03:25.043140Z","shell.execute_reply.started":"2024-05-10T14:03:24.989919Z","shell.execute_reply":"2024-05-10T14:03:25.042147Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"labels.sample(5)","metadata":{"execution":{"iopub.status.busy":"2024-05-10T14:03:25.045042Z","iopub.execute_input":"2024-05-10T14:03:25.045384Z","iopub.status.idle":"2024-05-10T14:03:25.059342Z","shell.execute_reply.started":"2024-05-10T14:03:25.045359Z","shell.execute_reply":"2024-05-10T14:03:25.058519Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# how many breeds do we have in the dataset?\nlen(labels['breed'].unique())","metadata":{"execution":{"iopub.status.busy":"2024-05-10T14:03:25.060465Z","iopub.execute_input":"2024-05-10T14:03:25.060809Z","iopub.status.idle":"2024-05-10T14:03:25.067967Z","shell.execute_reply.started":"2024-05-10T14:03:25.060778Z","shell.execute_reply":"2024-05-10T14:03:25.067057Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# which dog breed does have more pictures?\nbreed = labels.groupby(by='breed').agg({'id':'count'})\nbreed.sort_values(by='id', ascending=False).head(10)","metadata":{"execution":{"iopub.status.busy":"2024-05-10T14:03:25.069052Z","iopub.execute_input":"2024-05-10T14:03:25.069353Z","iopub.status.idle":"2024-05-10T14:03:25.086739Z","shell.execute_reply.started":"2024-05-10T14:03:25.069321Z","shell.execute_reply":"2024-05-10T14:03:25.085917Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# one sample of pictures\nImage('/kaggle/input/dog-breed-identification/train/2796546b6e0e5e25f200df4b79ef0099.jpg')","metadata":{"execution":{"iopub.status.busy":"2024-05-10T14:03:25.087675Z","iopub.execute_input":"2024-05-10T14:03:25.087917Z","iopub.status.idle":"2024-05-10T14:03:25.106992Z","shell.execute_reply.started":"2024-05-10T14:03:25.087896Z","shell.execute_reply":"2024-05-10T14:03:25.106190Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# create a list of filenames\nfilenames = ['/kaggle/input/dog-breed-identification/train/' + fname + '.jpg' for fname in labels['id'] ]\nlen(filenames)","metadata":{"execution":{"iopub.status.busy":"2024-05-10T14:03:25.108382Z","iopub.execute_input":"2024-05-10T14:03:25.108743Z","iopub.status.idle":"2024-05-10T14:03:25.119092Z","shell.execute_reply.started":"2024-05-10T14:03:25.108713Z","shell.execute_reply":"2024-05-10T14:03:25.118221Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# check random samples if labels fit to filename\nImage(filenames[1131])","metadata":{"execution":{"iopub.status.busy":"2024-05-10T14:03:25.120275Z","iopub.execute_input":"2024-05-10T14:03:25.121128Z","iopub.status.idle":"2024-05-10T14:03:25.140746Z","shell.execute_reply.started":"2024-05-10T14:03:25.121104Z","shell.execute_reply":"2024-05-10T14:03:25.139942Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# check the number of pictures to compare with filenames list\nif len(os.listdir('/kaggle/input/dog-breed-identification/train')) == len(filenames):\n    print('Great!, one step more to be sure that we have matched data')\nelse:\n    print('check train folder')","metadata":{"execution":{"iopub.status.busy":"2024-05-10T14:03:25.144002Z","iopub.execute_input":"2024-05-10T14:03:25.144323Z","iopub.status.idle":"2024-05-10T14:03:26.145033Z","shell.execute_reply.started":"2024-05-10T14:03:25.144296Z","shell.execute_reply":"2024-05-10T14:03:26.144008Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# general X and y preparation\nX = filenames\ny = labels['breed']","metadata":{"execution":{"iopub.status.busy":"2024-05-10T14:03:26.146046Z","iopub.execute_input":"2024-05-10T14:03:26.146315Z","iopub.status.idle":"2024-05-10T14:03:26.150960Z","shell.execute_reply.started":"2024-05-10T14:03:26.146277Z","shell.execute_reply":"2024-05-10T14:03:26.150116Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# One Hot Encoding for dogs breeds (y)\ny = pd.get_dummies(y)\nencoding_labels = y.columns\ny=y.to_numpy()","metadata":{"execution":{"iopub.status.busy":"2024-05-10T14:03:26.151906Z","iopub.execute_input":"2024-05-10T14:03:26.152157Z","iopub.status.idle":"2024-05-10T14:03:26.163567Z","shell.execute_reply.started":"2024-05-10T14:03:26.152136Z","shell.execute_reply":"2024-05-10T14:03:26.162672Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# create a smaller dataset for exmperiments (~1000)\nnumber_i = 1000\nX_train, X_val, y_train, y_val = train_test_split(X[:number_i], y[:number_i], test_size=0.2)\n\nlen(X_train), len(y_train), len(X_val), len(y_val)","metadata":{"execution":{"iopub.status.busy":"2024-05-10T14:03:26.164641Z","iopub.execute_input":"2024-05-10T14:03:26.164959Z","iopub.status.idle":"2024-05-10T14:03:26.175717Z","shell.execute_reply.started":"2024-05-10T14:03:26.164912Z","shell.execute_reply":"2024-05-10T14:03:26.174813Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Preprocessing images (turning images into tensors)\n\nA few steps for changing images into numerical form and split it to smaller chunks (batches)","metadata":{}},{"cell_type":"code","source":"# parameters for image and batch size\nimg_size = 224\nbatch_size = 32","metadata":{"execution":{"iopub.status.busy":"2024-05-10T14:03:26.176690Z","iopub.execute_input":"2024-05-10T14:03:26.176993Z","iopub.status.idle":"2024-05-10T14:03:26.183124Z","shell.execute_reply.started":"2024-05-10T14:03:26.176971Z","shell.execute_reply":"2024-05-10T14:03:26.182164Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def prepare_image(image_path):\n    '''\n    turns an image into a tensor\n    '''\n    # read an image\n    image = tf.io.read_file(image_path)\n    # turn an image to numerical version\n    image = tf.image.decode_jpeg(image, channels=3)\n    # convert colours from 0-255 to 0-1\n    image = tf.image.convert_image_dtype(image, tf.float32)\n    # resize\n    image = tf.image.resize(image, size=[img_size, img_size])\n    \n    return image","metadata":{"execution":{"iopub.status.busy":"2024-05-10T14:03:26.184428Z","iopub.execute_input":"2024-05-10T14:03:26.184713Z","iopub.status.idle":"2024-05-10T14:03:26.193403Z","shell.execute_reply.started":"2024-05-10T14:03:26.184691Z","shell.execute_reply":"2024-05-10T14:03:26.192422Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def get_label_image(image_path, label):\n    image = prepare_image(image_path)\n    \n    return image, label","metadata":{"execution":{"iopub.status.busy":"2024-05-10T14:03:26.194351Z","iopub.execute_input":"2024-05-10T14:03:26.194619Z","iopub.status.idle":"2024-05-10T14:03:26.206563Z","shell.execute_reply.started":"2024-05-10T14:03:26.194598Z","shell.execute_reply":"2024-05-10T14:03:26.205728Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def create_batches(X, y=None, batch_size=batch_size, valid_data=False, test_data=False):\n    '''\n    split a dataset to batches\n    '''\n    if test_data:\n        data = tf.data.Dataset.from_tensor_slices(tf.constant(X))\n        data_batch = data.map(prepare_image).batch(batch_size)\n    elif valid_data:\n        data = tf.data.Dataset.from_tensor_slices((tf.constant(X), tf.constant(y)))\n        data_batch = data.map(get_label_image).batch(batch_size)\n    else:\n        data = tf.data.Dataset.from_tensor_slices((tf.constant(X), tf.constant(y)))\n        data = data.shuffle(buffer_size=len(X))\n        data_batch = data.map(get_label_image).batch(batch_size)\n    \n    return data_batch","metadata":{"execution":{"iopub.status.busy":"2024-05-10T14:03:26.207596Z","iopub.execute_input":"2024-05-10T14:03:26.207838Z","iopub.status.idle":"2024-05-10T14:03:26.217071Z","shell.execute_reply.started":"2024-05-10T14:03:26.207817Z","shell.execute_reply":"2024-05-10T14:03:26.216158Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# create batches\n\n# train data\ntrain_data = create_batches(X_train, y_train)\n\n# test data\nvalid_data = create_batches(X_val, y_val, valid_data=True)","metadata":{"execution":{"iopub.status.busy":"2024-05-10T14:03:26.218099Z","iopub.execute_input":"2024-05-10T14:03:26.218439Z","iopub.status.idle":"2024-05-10T14:03:26.962974Z","shell.execute_reply.started":"2024-05-10T14:03:26.218409Z","shell.execute_reply":"2024-05-10T14:03:26.962177Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Create, train and validate a model","metadata":{}},{"cell_type":"markdown","source":"In this chapter we will (finally!) explore a tensorflow model 'mobilenet-v2' from kaggle repository.\nAt the begginning there will be defined:\n* Input shape\n* Output shape\n* URL of model\n\nNext step will be a few definition for callback (to enable logs' saving) and model creation.\nLater we will check the model with a smaller dataset (1000 samples) and at the end we will train it on the whole dataset.","metadata":{}},{"cell_type":"markdown","source":"## Model preparation","metadata":{}},{"cell_type":"code","source":"# model parameters\ninput_shape = [None, img_size, img_size, 3]\noutput_shape = len(encoding_labels)\nmodel_url = \"https://kaggle.com/models/google/mobilenet-v2/TensorFlow2/130-224-classification/1\"\n\n# number of epochs for training\nnum_epochs = 20","metadata":{"execution":{"iopub.status.busy":"2024-05-10T14:03:26.964080Z","iopub.execute_input":"2024-05-10T14:03:26.964349Z","iopub.status.idle":"2024-05-10T14:03:26.968724Z","shell.execute_reply.started":"2024-05-10T14:03:26.964317Z","shell.execute_reply":"2024-05-10T14:03:26.967884Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# load a tensorboard for callbacks\n%load_ext tensorboard","metadata":{"execution":{"iopub.status.busy":"2024-05-10T14:03:26.969786Z","iopub.execute_input":"2024-05-10T14:03:26.970074Z","iopub.status.idle":"2024-05-10T14:03:26.989232Z","shell.execute_reply.started":"2024-05-10T14:03:26.970050Z","shell.execute_reply":"2024-05-10T14:03:26.988416Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# callbacks preparation\ndef create_tf_callback():\n    logdir = os.path.join('/kaggle/working/',\n                         datetime.datetime.now().strftime('%Y%m%d-%H%M%S'))\n    \n    return tf.keras.callbacks.TensorBoard(logdir)\n\n# early stopping for callbacks\nearly_stopping = tf.keras.callbacks.EarlyStopping(monitor='val_accuracy',\n                                            patience=3)","metadata":{"execution":{"iopub.status.busy":"2024-05-10T14:03:26.991848Z","iopub.execute_input":"2024-05-10T14:03:26.992106Z","iopub.status.idle":"2024-05-10T14:03:26.997221Z","shell.execute_reply.started":"2024-05-10T14:03:26.992084Z","shell.execute_reply":"2024-05-10T14:03:26.996338Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# a function for model creation\ndef create_model(input_shape=input_shape, output_shape=output_shape, model_url=model_url):\n    print('create a model with: ', model_url)\n    \n    # setup the model\n    model = tfk.Sequential([\n        hub.KerasLayer(model_url),\n                       tfk.layers.Dense(units=output_shape, activation='softmax')\n                       ])\n    \n    # compile the model\n    model.compile(\n        loss=tfk.losses.CategoricalCrossentropy(), \n        optimizer=tfk.optimizers.Adam(), \n        metrics=['accuracy'] \n    )\n    \n    # build the model\n    model.build(input_shape)\n    \n    return model","metadata":{"execution":{"iopub.status.busy":"2024-05-10T14:03:26.998269Z","iopub.execute_input":"2024-05-10T14:03:26.998565Z","iopub.status.idle":"2024-05-10T14:03:27.008960Z","shell.execute_reply.started":"2024-05-10T14:03:26.998535Z","shell.execute_reply":"2024-05-10T14:03:27.008256Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# build a function for train model\ndef train_model():\n    # model creation\n    model = create_model()\n    \n    # create a new tensorboard\n    tensorboard = create_tf_callback()\n    \n    # model training\n    model.fit(x=train_data, \n          epochs=num_epochs, \n          validation_data=valid_data, \n          validation_freq=1,\n          callbacks=[tensorboard, early_stopping]\n         )\n    \n    return model","metadata":{"execution":{"iopub.status.busy":"2024-05-10T14:03:27.010112Z","iopub.execute_input":"2024-05-10T14:03:27.010416Z","iopub.status.idle":"2024-05-10T14:03:27.018087Z","shell.execute_reply.started":"2024-05-10T14:03:27.010393Z","shell.execute_reply":"2024-05-10T14:03:27.017393Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model = train_model()\nprint('\\nModel Summary:')\nmodel.summary()","metadata":{"execution":{"iopub.status.busy":"2024-05-10T14:03:27.019049Z","iopub.execute_input":"2024-05-10T14:03:27.019342Z","iopub.status.idle":"2024-05-10T14:04:11.647523Z","shell.execute_reply.started":"2024-05-10T14:03:27.019313Z","shell.execute_reply":"2024-05-10T14:04:11.646540Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Tensorboard logs \nIf you want to use/check tensorboard - uncomment the line of code below.","metadata":{}},{"cell_type":"code","source":"# %tensorboard --logdir /kaggle/working","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Predictions","metadata":{}},{"cell_type":"code","source":"y_pred = model.predict(valid_data)","metadata":{"execution":{"iopub.status.busy":"2024-05-10T14:04:11.654744Z","iopub.execute_input":"2024-05-10T14:04:11.655108Z","iopub.status.idle":"2024-05-10T14:04:12.648993Z","shell.execute_reply.started":"2024-05-10T14:04:11.655078Z","shell.execute_reply":"2024-05-10T14:04:12.648219Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# function for encoding labels\ndef pred_labels(prediction_propabilities):\n    \n    return encoding_labels[np.argmax(prediction_propabilities)]\n    ","metadata":{"execution":{"iopub.status.busy":"2024-05-10T14:04:12.650151Z","iopub.execute_input":"2024-05-10T14:04:12.650451Z","iopub.status.idle":"2024-05-10T14:04:12.655002Z","shell.execute_reply.started":"2024-05-10T14:04:12.650426Z","shell.execute_reply":"2024-05-10T14:04:12.653870Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# check a random sample from validation dataset\nindex = random.randint(0, len(y_val))\nlabel = pred_labels(y_pred[index])\n\nprint(f'Is {label} predicted properly? Prediction: {pred_labels(y_val[index])}. So:  {label==pred_labels(y_val[index])}\\n')\n\nImage(X_val[index])","metadata":{"execution":{"iopub.status.busy":"2024-05-10T14:04:12.659928Z","iopub.execute_input":"2024-05-10T14:04:12.660202Z","iopub.status.idle":"2024-05-10T14:04:12.669089Z","shell.execute_reply.started":"2024-05-10T14:04:12.660180Z","shell.execute_reply":"2024-05-10T14:04:12.667983Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Train and validate a model on a full dataset\n\nAn action plan includes:\n* split dataset to train and validation datasets\n* preprocess images\n* create a data batches\n* create a model\n* train a model\n* make predictions\n* compare results","metadata":{}},{"cell_type":"code","source":"# split dataset\nX_train, X_val, y_train, y_val = train_test_split(X, y, test_size=0.2)\n\n# create batches\n# train data\ntrain_data = create_batches(X_train, y_train)\n\n# test data\nvalid_data = create_batches(X_val, y_val, valid_data=True)\n\nprint(len(X_train), len(X_val), len(y_train), len(y_val))","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model2 = train_model()\n\nprint('\\nModel Summary:')\nmodel.summary()","metadata":{"execution":{"iopub.status.busy":"2024-05-10T14:08:24.693909Z","iopub.execute_input":"2024-05-10T14:08:24.694605Z","iopub.status.idle":"2024-05-10T14:09:37.139234Z","shell.execute_reply.started":"2024-05-10T14:08:24.694572Z","shell.execute_reply":"2024-05-10T14:09:37.138325Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"y_pred = model2.predict(valid_data)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# check a random sample from validation dataset\nindex = random.randint(0, len(y_val))\nlabel = pred_labels(y_pred[index])\n\nprint(f'Is {label} predicted properly? Prediction: {pred_labels(y_val[index])}. So:  {label==pred_labels(y_val[index])}\\n')\n\nImage(X_val[index])","metadata":{"execution":{"iopub.status.busy":"2024-05-10T14:12:11.313729Z","iopub.execute_input":"2024-05-10T14:12:11.314089Z","iopub.status.idle":"2024-05-10T14:12:11.323051Z","shell.execute_reply.started":"2024-05-10T14:12:11.314060Z","shell.execute_reply":"2024-05-10T14:12:11.322055Z"},"trusted":true},"execution_count":null,"outputs":[]}]}