{"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-06-09T19:39:34.728049Z","iopub.execute_input":"2024-06-09T19:39:34.728398Z","iopub.status.idle":"2024-06-09T19:39:50.352824Z","shell.execute_reply.started":"2024-06-09T19:39:34.728371Z","shell.execute_reply":"2024-06-09T19:39:50.351659Z"},"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-06-09T19:39:50.355047Z","iopub.execute_input":"2024-06-09T19:39:50.355360Z","iopub.status.idle":"2024-06-09T19:40:03.864833Z","shell.execute_reply.started":"2024-06-09T19:39:50.355330Z","shell.execute_reply":"2024-06-09T19:40:03.863750Z"},"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-06-09T19:40:03.866143Z","iopub.execute_input":"2024-06-09T19:40:03.866886Z","iopub.status.idle":"2024-06-09T19:40:03.921789Z","shell.execute_reply.started":"2024-06-09T19:40:03.866849Z","shell.execute_reply":"2024-06-09T19:40:03.920765Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"labels.sample(5)","metadata":{"execution":{"iopub.status.busy":"2024-06-09T19:40:03.922856Z","iopub.execute_input":"2024-06-09T19:40:03.923147Z","iopub.status.idle":"2024-06-09T19:40:03.940134Z","shell.execute_reply.started":"2024-06-09T19:40:03.923122Z","shell.execute_reply":"2024-06-09T19:40:03.939187Z"},"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-06-09T19:40:03.942780Z","iopub.execute_input":"2024-06-09T19:40:03.943198Z","iopub.status.idle":"2024-06-09T19:40:03.950225Z","shell.execute_reply.started":"2024-06-09T19:40:03.943168Z","shell.execute_reply":"2024-06-09T19:40:03.949063Z"},"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-06-09T19:40:03.952083Z","iopub.execute_input":"2024-06-09T19:40:03.952562Z","iopub.status.idle":"2024-06-09T19:40:03.967065Z","shell.execute_reply.started":"2024-06-09T19:40:03.952528Z","shell.execute_reply":"2024-06-09T19:40:03.966167Z"},"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-06-09T19:40:03.968198Z","iopub.execute_input":"2024-06-09T19:40:03.968497Z","iopub.status.idle":"2024-06-09T19:40:03.989365Z","shell.execute_reply.started":"2024-06-09T19:40:03.968472Z","shell.execute_reply":"2024-06-09T19:40:03.988494Z"},"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-06-09T19:40:03.990409Z","iopub.execute_input":"2024-06-09T19:40:03.990696Z","iopub.status.idle":"2024-06-09T19:40:04.001197Z","shell.execute_reply.started":"2024-06-09T19:40:03.990671Z","shell.execute_reply":"2024-06-09T19:40:04.000092Z"},"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-06-09T19:40:04.002428Z","iopub.execute_input":"2024-06-09T19:40:04.002721Z","iopub.status.idle":"2024-06-09T19:40:04.023675Z","shell.execute_reply.started":"2024-06-09T19:40:04.002696Z","shell.execute_reply":"2024-06-09T19:40:04.022678Z"},"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-06-09T19:40:04.025121Z","iopub.execute_input":"2024-06-09T19:40:04.025769Z","iopub.status.idle":"2024-06-09T19:40:04.476706Z","shell.execute_reply.started":"2024-06-09T19:40:04.025733Z","shell.execute_reply":"2024-06-09T19:40:04.475538Z"},"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-06-09T19:40:04.478005Z","iopub.execute_input":"2024-06-09T19:40:04.478430Z","iopub.status.idle":"2024-06-09T19:40:04.483349Z","shell.execute_reply.started":"2024-06-09T19:40:04.478390Z","shell.execute_reply":"2024-06-09T19:40:04.482308Z"},"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-06-09T19:40:04.484838Z","iopub.execute_input":"2024-06-09T19:40:04.485173Z","iopub.status.idle":"2024-06-09T19:40:04.495722Z","shell.execute_reply.started":"2024-06-09T19:40:04.485146Z","shell.execute_reply":"2024-06-09T19:40:04.494685Z"},"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-06-09T19:40:04.497053Z","iopub.execute_input":"2024-06-09T19:40:04.497345Z","iopub.status.idle":"2024-06-09T19:40:04.505746Z","shell.execute_reply.started":"2024-06-09T19:40:04.497321Z","shell.execute_reply":"2024-06-09T19:40:04.504662Z"},"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-06-09T19:40:04.510089Z","iopub.execute_input":"2024-06-09T19:40:04.510385Z","iopub.status.idle":"2024-06-09T19:40:04.514936Z","shell.execute_reply.started":"2024-06-09T19:40:04.510360Z","shell.execute_reply":"2024-06-09T19:40:04.513961Z"},"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-06-09T19:40:04.516090Z","iopub.execute_input":"2024-06-09T19:40:04.516403Z","iopub.status.idle":"2024-06-09T19:40:04.523629Z","shell.execute_reply.started":"2024-06-09T19:40:04.516372Z","shell.execute_reply":"2024-06-09T19:40:04.522646Z"},"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-06-09T19:40:04.524985Z","iopub.execute_input":"2024-06-09T19:40:04.525575Z","iopub.status.idle":"2024-06-09T19:40:04.534815Z","shell.execute_reply.started":"2024-06-09T19:40:04.525540Z","shell.execute_reply":"2024-06-09T19:40:04.533826Z"},"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-06-09T19:40:04.536019Z","iopub.execute_input":"2024-06-09T19:40:04.536336Z","iopub.status.idle":"2024-06-09T19:40:04.543900Z","shell.execute_reply.started":"2024-06-09T19:40:04.536303Z","shell.execute_reply":"2024-06-09T19:40:04.543131Z"},"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-06-09T19:40:04.544976Z","iopub.execute_input":"2024-06-09T19:40:04.545238Z","iopub.status.idle":"2024-06-09T19:40:04.714943Z","shell.execute_reply.started":"2024-06-09T19:40:04.545215Z","shell.execute_reply":"2024-06-09T19:40:04.713930Z"},"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-06-09T19:40:04.716058Z","iopub.execute_input":"2024-06-09T19:40:04.716338Z","iopub.status.idle":"2024-06-09T19:40:04.721471Z","shell.execute_reply.started":"2024-06-09T19:40:04.716314Z","shell.execute_reply":"2024-06-09T19:40:04.720347Z"},"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-06-09T19:40:04.722643Z","iopub.execute_input":"2024-06-09T19:40:04.722955Z","iopub.status.idle":"2024-06-09T19:40:04.743644Z","shell.execute_reply.started":"2024-06-09T19:40:04.722930Z","shell.execute_reply":"2024-06-09T19:40:04.742708Z"},"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-06-09T19:40:04.744816Z","iopub.execute_input":"2024-06-09T19:40:04.745148Z","iopub.status.idle":"2024-06-09T19:40:04.751455Z","shell.execute_reply.started":"2024-06-09T19:40:04.745120Z","shell.execute_reply":"2024-06-09T19:40:04.750375Z"},"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-06-09T19:40:04.752823Z","iopub.execute_input":"2024-06-09T19:40:04.753176Z","iopub.status.idle":"2024-06-09T19:40:04.762951Z","shell.execute_reply.started":"2024-06-09T19:40:04.753148Z","shell.execute_reply":"2024-06-09T19:40:04.761898Z"},"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-06-09T19:40:04.764291Z","iopub.execute_input":"2024-06-09T19:40:04.764664Z","iopub.status.idle":"2024-06-09T19:40:04.772547Z","shell.execute_reply.started":"2024-06-09T19:40:04.764628Z","shell.execute_reply":"2024-06-09T19:40:04.771502Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model = train_model()\nprint('\\nModel Summary:')\nmodel.summary()","metadata":{"execution":{"iopub.status.busy":"2024-06-09T19:40:04.773591Z","iopub.execute_input":"2024-06-09T19:40:04.773887Z","iopub.status.idle":"2024-06-09T19:43:24.519785Z","shell.execute_reply.started":"2024-06-09T19:40:04.773863Z","shell.execute_reply":"2024-06-09T19:43:24.517994Z"},"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":{"execution":{"iopub.status.busy":"2024-06-09T19:43:24.521005Z","iopub.status.idle":"2024-06-09T19:43:24.521523Z","shell.execute_reply.started":"2024-06-09T19:43:24.521255Z","shell.execute_reply":"2024-06-09T19:43:24.521278Z"},"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-06-09T19:43:24.523648Z","iopub.status.idle":"2024-06-09T19:43:24.524494Z","shell.execute_reply.started":"2024-06-09T19:43:24.524214Z","shell.execute_reply":"2024-06-09T19:43:24.524238Z"},"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-06-09T19:43:24.525647Z","iopub.status.idle":"2024-06-09T19:43:24.526169Z","shell.execute_reply.started":"2024-06-09T19:43:24.525882Z","shell.execute_reply":"2024-06-09T19:43:24.525902Z"},"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-06-09T19:43:24.527640Z","iopub.status.idle":"2024-06-09T19:43:24.528037Z","shell.execute_reply.started":"2024-06-09T19:43:24.527824Z","shell.execute_reply":"2024-06-09T19:43:24.527839Z"},"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":{"execution":{"iopub.status.busy":"2024-06-09T19:43:24.529760Z","iopub.status.idle":"2024-06-09T19:43:24.530156Z","shell.execute_reply.started":"2024-06-09T19:43:24.529961Z","shell.execute_reply":"2024-06-09T19:43:24.529977Z"},"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-06-09T19:43:24.531364Z","iopub.status.idle":"2024-06-09T19:43:24.531727Z","shell.execute_reply.started":"2024-06-09T19:43:24.531554Z","shell.execute_reply":"2024-06-09T19:43:24.531569Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"y_pred = model2.predict(valid_data)","metadata":{"execution":{"iopub.status.busy":"2024-06-09T19:43:24.533897Z","iopub.status.idle":"2024-06-09T19:43:24.534286Z","shell.execute_reply.started":"2024-06-09T19:43:24.534108Z","shell.execute_reply":"2024-06-09T19:43:24.534123Z"},"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-06-09T19:43:24.535934Z","iopub.status.idle":"2024-06-09T19:43:24.536442Z","shell.execute_reply.started":"2024-06-09T19:43:24.536176Z","shell.execute_reply":"2024-06-09T19:43:24.536197Z"},"trusted":true},"execution_count":null,"outputs":[]}]}