Skip to content
Snippets Groups Projects
02-First-convolutions.ipynb 12.1 KiB
Newer Older
{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<img width=\"800px\" src=\"../fidle/img/header.svg\"></img>\n",
    "\n",
    "# <!-- TITLE --> [K3GTSRB2] - First convolutions\n",
    "<!-- DESC --> Episode 2 : First convolutions and first classification of our traffic signs, using Keras3\n",
    "<!-- AUTHOR : Jean-Luc Parouty (CNRS/SIMaP) -->\n",
    "\n",
    "## Objectives :\n",
    "  - Recognizing traffic signs \n",
    "  - Understand the **principles** and **architecture** of a **convolutional neural network** for image classification\n",
    "  \n",
    "The German Traffic Sign Recognition Benchmark (GTSRB) is a dataset with more than 50,000 photos of road signs from about 40 classes.  \n",
    "The final aim is to recognise them !  \n",
    "\n",
    "Description is available there : http://benchmark.ini.rub.de/?section=gtsrb&subsection=dataset\n",
    "\n",
    "\n",
    "**IMPORTANT :** To be able to use this notebook and the following, **you must have generated the enhanced datasets** in <dataset_dir>/enhanced via the notebook **[01-Preparation-of-data.ipynb](01-Preparation-of-data.ipynb)**  \n",
    "\n",
    "## What we're going to do :\n",
    "\n",
    " - Read H5 dataset\n",
    " - Build a model\n",
    " - Train the model\n",
    " - Evaluate the model\n",
    "\n",
    "## Step 1 - Import and init\n",
    "### 1.1 - Python stuff"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import os\n",
    "os.environ['KERAS_BACKEND'] = 'torch'\n",
    "\n",
    "import keras\n",
    "\n",
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "import h5py\n",
    "import os,time,sys\n",
    "\n",
    "from importlib import reload\n",
    "\n",
    "# Init Fidle environment\n",
    "import fidle\n",
    "\n",
    "run_id, run_dir, datasets_dir = fidle.init('K3GTSRB2')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 1.2 - Parameters\n",
    "`scale` is the proportion of the dataset that will be used during the training. (1 mean 100%)  \n",
Jean-Luc Parouty's avatar
Jean-Luc Parouty committed
    "A 20% 24x24 dataset, with 5 epochs and a scale of 1, need  **3'30** on a CPU laptop.\\\n",
    "`fit_verbosity` is the verbosity during training : 0 = silent, 1 = progress bar, 2 = one line per epoch"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "enhanced_dir = './data'\n",
    "# enhanced_dir = f'{datasets_dir}/GTSRB/enhanced'\n",
    "\n",
    "dataset_name  = 'set-24x24-L'\n",
    "batch_size    = 64\n",
    "epochs        = 5\n",
Jean-Luc Parouty's avatar
Jean-Luc Parouty committed
    "scale         = 1\n",
    "fit_verbosity = 1"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Override parameters (batch mode) - Just forget this cell"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "fidle.override('enhanced_dir', 'dataset_name', 'batch_size', 'epochs', 'scale', 'fit_verbosity')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Step 2 - Load dataset\n",
    "We're going to retrieve a previously recorded dataset.  \n",
    "For example: set-24x24-L"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def read_dataset(enhanced_dir, dataset_name, scale=1):\n",
    "    '''\n",
    "    Reads h5 dataset\n",
    "    Args:\n",
    "        filename     : datasets filename\n",
    "        dataset_name : dataset name, without .h5\n",
    "    Returns:    \n",
    "        x_train,y_train, x_test,y_test data, x_meta,y_meta\n",
    "    '''\n",
    "\n",
    "    # ---- Read dataset\n",
    "    #\n",
    "    chrono=fidle.Chrono()\n",
    "    chrono.start()\n",
    "    filename = f'{enhanced_dir}/{dataset_name}.h5'\n",
    "    with  h5py.File(filename,'r') as f:\n",
    "        x_train = f['x_train'][:]\n",
    "        y_train = f['y_train'][:]\n",
    "        x_test  = f['x_test'][:]\n",
    "        y_test  = f['y_test'][:]\n",
    "        x_meta  = f['x_meta'][:]\n",
    "        y_meta  = f['y_meta'][:]\n",
    "\n",
    "    # ---- Rescale \n",
    "    #\n",
    "    print('Original shape  :', x_train.shape, y_train.shape)\n",
    "    x_train,y_train, x_test,y_test = fidle.utils.rescale_dataset(x_train,y_train,x_test,y_test, scale=scale)\n",
    "    print('Rescaled shape  :', x_train.shape, y_train.shape)\n",
    "\n",
    "    # ---- Shuffle\n",
    "    #\n",
    "    x_train,y_train=fidle.utils.shuffle_np_dataset(x_train,y_train)\n",
    "\n",
    "    # ---- done\n",
    "    #\n",
    "    duration = chrono.get_delay()\n",
    "    size     = fidle.utils.hsize(os.path.getsize(filename))\n",
    "    print(f'\\nDataset \"{dataset_name}\" is loaded and shuffled. ({size} in {duration})')\n",
    "    return x_train,y_train, x_test,y_test, x_meta,y_meta\n",
    "\n",
    "# ---- Read dataset\n",
    "#\n",
    "x_train,y_train,x_test,y_test, x_meta,y_meta = read_dataset(enhanced_dir, dataset_name, scale)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Step 3 - Have a look to the dataset\n",
    "We take a quick look as we go by..."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print(\"x_train : \", x_train.shape)\n",
    "print(\"y_train : \", y_train.shape)\n",
    "print(\"x_test  : \", x_test.shape)\n",
    "print(\"y_test  : \", y_test.shape)\n",
    "\n",
    "fidle.scrawler.images(x_train, y_train, range(12), columns=6,  x_size=2, y_size=2, save_as='01-dataset-medium')\n",
    "fidle.scrawler.images(x_train, y_train, range(36), columns=12, x_size=1, y_size=1, save_as='02-dataset-small')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Step 4 - Create model\n",
    "We will now build a model and train it...\n",
    "\n",
    "Some models :"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "\n",
    "# ------------------------------------------------------------------\n",
    "# -- A simple model, for 24x24 or 48x48 images                    --\n",
    "# ------------------------------------------------------------------\n",
    "#\n",
    "def get_model_01(lx,ly,lz):\n",
    "    \n",
    "    model = keras.models.Sequential()\n",
    "\n",
    "    model.add( keras.layers.Input((lx,ly,lz)) )\n",
    "    \n",
    "    model.add( keras.layers.Conv2D(96, (3,3), activation='relu' ))\n",
    "    model.add( keras.layers.MaxPooling2D((2, 2)))\n",
    "    model.add( keras.layers.Dropout(0.2))\n",
    "\n",
    "    model.add( keras.layers.Conv2D(192, (3, 3), activation='relu'))\n",
    "    model.add( keras.layers.MaxPooling2D((2, 2)))\n",
    "    model.add( keras.layers.Dropout(0.2))\n",
    "\n",
    "    model.add( keras.layers.Flatten()) \n",
    "    model.add( keras.layers.Dense(1500, activation='relu'))\n",
    "    model.add( keras.layers.Dropout(0.5))\n",
    "\n",
    "    model.add( keras.layers.Dense(43, activation='softmax'))\n",
    "    return model\n",
    "    \n",
    "\n",
    "# ------------------------------------------------------------------\n",
    "# -- A more sophisticated model, for 48x48 images                 --\n",
    "# ------------------------------------------------------------------\n",
    "#\n",
    "def get_model_02(lx,ly,lz):\n",
    "    model = keras.models.Sequential()\n",
    "    \n",
    "    model.add( keras.layers.Input((lx,ly,lz)) )\n",
    "    \n",
    "    model.add( keras.layers.Conv2D(32, (3,3),   activation='relu'))\n",
    "    model.add( keras.layers.MaxPooling2D((2, 2)))\n",
    "    model.add( keras.layers.Dropout(0.5))\n",
    "\n",
    "    model.add( keras.layers.Conv2D(64, (3, 3), activation='relu'))\n",
    "    model.add( keras.layers.MaxPooling2D((2, 2)))\n",
    "    model.add( keras.layers.Dropout(0.5))\n",
    "\n",
    "    model.add( keras.layers.Conv2D(128, (3, 3), activation='relu'))\n",
    "    model.add( keras.layers.MaxPooling2D((2, 2)))\n",
    "    model.add( keras.layers.Dropout(0.5))\n",
    "\n",
    "    model.add( keras.layers.Conv2D(256, (3, 3), activation='relu'))\n",
    "    model.add( keras.layers.MaxPooling2D((2, 2)))\n",
    "    model.add( keras.layers.Dropout(0.5))\n",
    "\n",
    "    model.add( keras.layers.Flatten()) \n",
    "    model.add( keras.layers.Dense(1152, activation='relu'))\n",
    "    model.add( keras.layers.Dropout(0.5))\n",
    "\n",
    "    model.add( keras.layers.Dense(43, activation='softmax'))\n",
    "    return model\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Step 5 - Train the model\n",
    "**Get the shape of my data :**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "(n,lx,ly,lz) = x_train.shape\n",
    "print(\"Images of the dataset have this folowing shape : \",(lx,ly,lz))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Get and compile a model, with the data shape :**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "model = get_model_01(lx,ly,lz)\n",
    "\n",
    "model.summary()\n",
    "\n",
    "model.compile(optimizer = 'adam',\n",
    "              loss      = 'sparse_categorical_crossentropy',\n",
    "              metrics   = ['accuracy'])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Train it :**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "chrono=fidle.Chrono()\n",
    "chrono.start()\n",
    "\n",
    "# ---- Shuffle train data\n",
    "x_train,y_train=fidle.utils.shuffle_np_dataset(x_train,y_train)\n",
    "\n",
    "# ---- Train\n",
    "history = model.fit(  x_train, y_train,\n",
    "                      batch_size      = batch_size,\n",
    "                      epochs          = epochs,\n",
    "                      verbose         = fit_verbosity,\n",
    "                      validation_data = (x_test, y_test))\n",
    "\n",
    "chrono.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Step 5 - Evaluate"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "max_val_accuracy = max(history.history[\"val_accuracy\"])\n",
    "print(\"Max validation accuracy is : {:.4f}\".format(max_val_accuracy))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "score = model.evaluate(x_test, y_test, verbose=0)\n",
    "\n",
    "print('Test loss      : {:5.4f}'.format(score[0]))\n",
    "print('Test accuracy  : {:5.4f}'.format(score[1]))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "fidle.end()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<div class=\"todo\">\n",
    "    What you can do:\n",
    "    <ul>\n",
    "        <li>Try the different models</li>\n",
    "        <li>Try with different datasets</li>\n",
    "        <li>Test different hyperparameters (epochs, batch size, optimization, etc.)</li>\n",
    "        <li>Create your own model</li>\n",
    "    </ul>\n",
    "</div>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "<img width=\"80px\" src=\"../fidle/img/logo-paysage.svg\"></img>"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3.9.2 ('fidle-env')",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.2"
  },
  "vscode": {
   "interpreter": {
    "hash": "b3929042cc22c1274d74e3e946c52b845b57cb6d84f2d591ffe0519b38e4896d"
   }
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}