Add image dataset, batch convertion bash script,
jupyter-notebook...
This commit is contained in:
parent
504dd98b9d
commit
cd8eca013e
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
.vscode/
|
||||||
|
tb-venv/
|
11
data/sp_names.csv
Normal file
11
data/sp_names.csv
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
sp_code,sp_latin,sp_fr
|
||||||
|
cyacae,Cyanistes caeruleus,Mésange bleue
|
||||||
|
parmaj,Parus major,Mésange charbonnière
|
||||||
|
erirub,Erithacus rubecula,Rougegorge familier
|
||||||
|
prumod,Prunella modularis,Accenteur mouchet
|
||||||
|
pasdom,Passer domesticus,Moineau domestique
|
||||||
|
turmer,Turdus merula,Merle noir
|
||||||
|
felcat,Felix catus,Chat domestique
|
||||||
|
fricoe,Fringilla coelebs,Pinson des arbres
|
||||||
|
stedec,Streptopelia decaocto,Tourterelle turque
|
||||||
|
carcar,Carduelis carduelis,Chardonneret élégant
|
|
1
data/species_dataset
Symbolic link
1
data/species_dataset
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
/home/ortion/Documents/PiCameraTrap/captures/species_dataset/
|
@ -0,0 +1,899 @@
|
|||||||
|
{
|
||||||
|
"cells": [
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {
|
||||||
|
"colab_type": "text",
|
||||||
|
"id": "z-7UORN7Ymoo"
|
||||||
|
},
|
||||||
|
"source": [
|
||||||
|
"Mount the drive to the instance."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 0,
|
||||||
|
"metadata": {
|
||||||
|
"colab": {},
|
||||||
|
"colab_type": "code",
|
||||||
|
"id": "9X2hja-OpXM9"
|
||||||
|
},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"from google.colab import drive\n",
|
||||||
|
"drive.mount('/content/gdrive')"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {
|
||||||
|
"colab_type": "text",
|
||||||
|
"id": "fjU2n68zYxU3"
|
||||||
|
},
|
||||||
|
"source": [
|
||||||
|
"Import various modules.\n",
|
||||||
|
"\n",
|
||||||
|
"I used Tnesorflow and its Keras library as the backend. The Keras module is for preprocessing images. "
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 0,
|
||||||
|
"metadata": {
|
||||||
|
"colab": {},
|
||||||
|
"colab_type": "code",
|
||||||
|
"id": "QIR81L-ArDn3"
|
||||||
|
},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"!pip install -q tensorflow-gpu==2.0.0-alpha0\n",
|
||||||
|
"import cv2\n",
|
||||||
|
"import numpy as np\n",
|
||||||
|
"import pandas as pd\n",
|
||||||
|
"import matplotlib.pyplot as plt\n",
|
||||||
|
"import matplotlib.patches as patches\n",
|
||||||
|
"from __future__ import absolute_import, division, print_function\n",
|
||||||
|
"import os\n",
|
||||||
|
"import tensorflow as tf\n",
|
||||||
|
"from sklearn.model_selection import train_test_split\n",
|
||||||
|
"from keras.utils import to_categorical\n",
|
||||||
|
"from keras.callbacks import ModelCheckpoint, ReduceLROnPlateau, EarlyStopping\n",
|
||||||
|
"from keras.preprocessing import image\n",
|
||||||
|
"keras = tf.keras\n",
|
||||||
|
"datapath = '/content/gdrive/My Drive/Bird_ID_project/nabirds'"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {
|
||||||
|
"colab_type": "text",
|
||||||
|
"id": "GVPN6iW0IvZ5"
|
||||||
|
},
|
||||||
|
"source": [
|
||||||
|
"Reading in the pandas dataframe. It actually doesn't provide much beside the unique species class names."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 0,
|
||||||
|
"metadata": {
|
||||||
|
"colab": {},
|
||||||
|
"colab_type": "code",
|
||||||
|
"id": "K99e_KEnkN4p"
|
||||||
|
},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"train_frame = pd.read_csv(datapath+'/train.csv')\n",
|
||||||
|
"val_frame = pd.read_csv(datapath+'/val.csv')\n",
|
||||||
|
"test_frame = pd.read_csv(datapath+'/test.csv')\n",
|
||||||
|
"# train_frame\n",
|
||||||
|
"Bird_list=train_frame.class_name_sp.unique()\n",
|
||||||
|
"Bird_id=train_frame.class_id_sp.unique()\n",
|
||||||
|
"# print(Bird_list, Bird_id)\n",
|
||||||
|
"Birds = dict(zip(Bird_id, Bird_list))"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {
|
||||||
|
"colab_type": "text",
|
||||||
|
"id": "R9pJGyS8b83K"
|
||||||
|
},
|
||||||
|
"source": [
|
||||||
|
"Unzip the tar.gz files **to the Google Colab instance**. This drastically increased the training speed."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 0,
|
||||||
|
"metadata": {
|
||||||
|
"colab": {},
|
||||||
|
"colab_type": "code",
|
||||||
|
"id": "cYGuyyUINUQ3"
|
||||||
|
},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"!tar -xzf \"gdrive/My Drive/Bird_ID_project/nabirds/data.tar.gz\"\n",
|
||||||
|
"!tar -xzf \"gdrive/My Drive/Bird_ID_project/nabirds/Darren_data.tar.gz\""
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 0,
|
||||||
|
"metadata": {
|
||||||
|
"colab": {},
|
||||||
|
"colab_type": "code",
|
||||||
|
"id": "GWP0UQZdBDk1"
|
||||||
|
},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"!mv /content/Darren_test/0289 /content/Darren_test/0867\n",
|
||||||
|
"!mv /content/Darren_test/0095 /content/Darren_test/0553\n",
|
||||||
|
"!rm -rf /content/Darren_test/NIL"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {
|
||||||
|
"colab_type": "text",
|
||||||
|
"id": "0vRSm4DVI9Jd"
|
||||||
|
},
|
||||||
|
"source": [
|
||||||
|
"Using Keras image generator to reduce RAM footprint (instead of using a large numpy array)."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 0,
|
||||||
|
"metadata": {
|
||||||
|
"colab": {},
|
||||||
|
"colab_type": "code",
|
||||||
|
"id": "BxCuJxxxl2ge"
|
||||||
|
},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"train_datagen = image.ImageDataGenerator(\n",
|
||||||
|
" rescale=1./255,\n",
|
||||||
|
"# width_shift_range=0.1,\n",
|
||||||
|
"# height_shift_range=0.1,\n",
|
||||||
|
"# zoom_range=0.1,\n",
|
||||||
|
" fill_mode='constant',\n",
|
||||||
|
" horizontal_flip=True,\n",
|
||||||
|
" dtype=np.float32)\n",
|
||||||
|
"\n",
|
||||||
|
"val_datagen = image.ImageDataGenerator(\n",
|
||||||
|
" rescale=1./255, \n",
|
||||||
|
" dtype=np.float32)\n",
|
||||||
|
"\n",
|
||||||
|
"test_datagen = image.ImageDataGenerator(\n",
|
||||||
|
" rescale=1./255,\n",
|
||||||
|
" dtype=np.float32)\n",
|
||||||
|
"\n",
|
||||||
|
"train_generator = train_datagen.flow_from_directory(\n",
|
||||||
|
" directory='/content/data/train/',\n",
|
||||||
|
" #directory=datapath + '/data/train/',\n",
|
||||||
|
" #classes=list(Bird_list),\n",
|
||||||
|
" target_size=(224, 224),\n",
|
||||||
|
" batch_size=32,\n",
|
||||||
|
" class_mode='categorical')\n",
|
||||||
|
"\n",
|
||||||
|
"validation_generator = val_datagen.flow_from_directory(\n",
|
||||||
|
" #directory=datapath + '/data/val/',\n",
|
||||||
|
" directory='/content/data/val/',\n",
|
||||||
|
" #classes=list(Bird_list),\n",
|
||||||
|
" target_size=(224, 224),\n",
|
||||||
|
" batch_size=32,\n",
|
||||||
|
" class_mode='categorical')\n",
|
||||||
|
"\n",
|
||||||
|
"test_generator = test_datagen.flow_from_directory(\n",
|
||||||
|
" #directory=datapath + '/data/test/',\n",
|
||||||
|
" directory='/content/data/test/',\n",
|
||||||
|
" shuffle=False,\n",
|
||||||
|
" #classes=list(Bird_list),\n",
|
||||||
|
" target_size=(224, 224),\n",
|
||||||
|
" batch_size=32,\n",
|
||||||
|
" class_mode='categorical')\n"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {
|
||||||
|
"colab_type": "text",
|
||||||
|
"id": "HlsRpRXDMicF"
|
||||||
|
},
|
||||||
|
"source": [
|
||||||
|
"Research has shown that starting from scratch will not work. So we use MobileNet V2 as our feature extractor. This is a relatively small network, which will help in the future when we want to run near real time inferences. We also add two layers: One global average and one prediction. "
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 0,
|
||||||
|
"metadata": {
|
||||||
|
"colab": {},
|
||||||
|
"colab_type": "code",
|
||||||
|
"id": "ytj6wsAdM7Un"
|
||||||
|
},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"IMG_SHAPE = (224,224,3)\n",
|
||||||
|
"base_model = tf.keras.applications.MobileNetV2(input_shape=IMG_SHAPE,\n",
|
||||||
|
" include_top=False, \n",
|
||||||
|
" weights='imagenet')\n",
|
||||||
|
"\n",
|
||||||
|
"base_model.trainable = False\n",
|
||||||
|
"\n",
|
||||||
|
"global_average_layer = tf.keras.layers.GlobalAveragePooling2D()\n",
|
||||||
|
"prediction_layer = keras.layers.Dense(404,activation='softmax')\n",
|
||||||
|
"base_learning_rate = 0.0001\n",
|
||||||
|
"model = tf.keras.Sequential([\n",
|
||||||
|
" base_model,\n",
|
||||||
|
" global_average_layer,\n",
|
||||||
|
" prediction_layer\n",
|
||||||
|
"])\n",
|
||||||
|
"model.compile(optimizer=tf.keras.optimizers.RMSprop(lr=base_learning_rate), \n",
|
||||||
|
" loss='categorical_crossentropy', \n",
|
||||||
|
" metrics=['accuracy'])\n",
|
||||||
|
"model.summary()"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 0,
|
||||||
|
"metadata": {
|
||||||
|
"colab": {},
|
||||||
|
"colab_type": "code",
|
||||||
|
"id": "bGi69hxZRSvy"
|
||||||
|
},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"def fit_model(model, batch_size=32, epochs=10): \n",
|
||||||
|
" history = model.fit_generator(\n",
|
||||||
|
" generator=train_generator,\n",
|
||||||
|
" steps_per_epoch=(len(train_frame) // batch_size),\n",
|
||||||
|
" epochs=epochs,\n",
|
||||||
|
" validation_data=validation_generator,\n",
|
||||||
|
" callbacks=None\n",
|
||||||
|
" )\n",
|
||||||
|
" score = model.evaluate_generator(train_generator, verbose=1)\n",
|
||||||
|
" probs = model.predict_generator(test_generator, verbose=1)\n",
|
||||||
|
" return model, score, probs, history\n"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 0,
|
||||||
|
"metadata": {
|
||||||
|
"colab": {},
|
||||||
|
"colab_type": "code",
|
||||||
|
"id": "dt80nu7nQlzm"
|
||||||
|
},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"fit_model, score, probs, history = fit_model(model, batch_size=32, epochs=10)"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 0,
|
||||||
|
"metadata": {
|
||||||
|
"colab": {},
|
||||||
|
"colab_type": "code",
|
||||||
|
"id": "YdfI5Fzw6CRx"
|
||||||
|
},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"def top3(probs, GT):\n",
|
||||||
|
" t3 = np.argsort(probs)[-3:]\n",
|
||||||
|
" #print(t3)\n",
|
||||||
|
" if GT in t3:\n",
|
||||||
|
" return 1\n",
|
||||||
|
" else:\n",
|
||||||
|
" return 0\n",
|
||||||
|
" \n",
|
||||||
|
"def top5(probs, GT):\n",
|
||||||
|
" t5 = np.argsort(probs)[-5:]\n",
|
||||||
|
" if GT in t5:\n",
|
||||||
|
" return 1\n",
|
||||||
|
" else:\n",
|
||||||
|
" return 0\n",
|
||||||
|
" \n",
|
||||||
|
"def top3_idx(probs):\n",
|
||||||
|
" return np.flip(np.argsort(probs)[-3:],0), np.flip(probs[np.argsort(probs)[-3:]],0)\n",
|
||||||
|
" #print(t3)\n",
|
||||||
|
"\n",
|
||||||
|
"def top5_idx(probs):\n",
|
||||||
|
" return np.flip(np.argsort(probs)[-5:])\n",
|
||||||
|
" #print(t3)"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {
|
||||||
|
"colab_type": "text",
|
||||||
|
"id": "-Kb1Q3eeP7DI"
|
||||||
|
},
|
||||||
|
"source": [
|
||||||
|
"After 10 epochs we achieve 44, 64, and 72 % top 1, 3, and 5 hit rate. Not bad! But it can be better. "
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 0,
|
||||||
|
"metadata": {
|
||||||
|
"colab": {},
|
||||||
|
"colab_type": "code",
|
||||||
|
"id": "2iQYi1kdSLtF"
|
||||||
|
},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"correct_prediction = 0\n",
|
||||||
|
"correct_top3 = 0\n",
|
||||||
|
"correct_top5 = 0\n",
|
||||||
|
"for ii in range(len(probs)):\n",
|
||||||
|
" P_this = np.argmax(probs[ii])\n",
|
||||||
|
" GT_this = test_generator.labels[ii]\n",
|
||||||
|
" if P_this == GT_this:\n",
|
||||||
|
" correct_prediction += 1\n",
|
||||||
|
" correct_top3 += top3(probs[ii],GT_this)\n",
|
||||||
|
" correct_top5 += top5(probs[ii],GT_this)\n",
|
||||||
|
" if ii < 10:\n",
|
||||||
|
" print(\"Prediction: {} ({})\".format(P_this,Birds[int(list(test_generator.class_indices.keys())[list(test_generator.class_indices.values()).index(P_this)])]))\n",
|
||||||
|
" print(\"Actual: {} ({})\".format(GT_this,Birds[int(list(test_generator.class_indices.keys())[list(test_generator.class_indices.values()).index(GT_this)])]))\n",
|
||||||
|
" print(\"Prediction: {} \".format(P_this))\n",
|
||||||
|
" print(\"Actual: {} \".format(GT_this))\n",
|
||||||
|
" #plt.figure()\n",
|
||||||
|
" #plt.imshow(X_test[ii,:,:,:])\n",
|
||||||
|
" #plt.show()\n",
|
||||||
|
"print(correct_prediction, correct_prediction/len(probs))\n",
|
||||||
|
"print(correct_top3, correct_top3/len(probs))\n",
|
||||||
|
"print(correct_top5, correct_top5/len(probs))\n",
|
||||||
|
"print(len(probs))"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {
|
||||||
|
"colab_type": "text",
|
||||||
|
"id": "2ou1-W3SQYOK"
|
||||||
|
},
|
||||||
|
"source": [
|
||||||
|
"We see overfitting after second epoch, which seems to be a common thing when training models for bird IDs. "
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 0,
|
||||||
|
"metadata": {
|
||||||
|
"colab": {},
|
||||||
|
"colab_type": "code",
|
||||||
|
"id": "7tJdIW8F6mIv"
|
||||||
|
},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"acc = history.history['accuracy']\n",
|
||||||
|
"val_acc = history.history['val_accuracy']\n",
|
||||||
|
"\n",
|
||||||
|
"loss = history.history['loss']\n",
|
||||||
|
"val_loss = history.history['val_loss']\n",
|
||||||
|
"\n",
|
||||||
|
"plt.figure(figsize=(8, 8))\n",
|
||||||
|
"plt.subplot(2, 1, 1)\n",
|
||||||
|
"plt.plot(acc, label='Training Accuracy')\n",
|
||||||
|
"plt.plot(val_acc, label='Validation Accuracy')\n",
|
||||||
|
"plt.legend(loc='lower right')\n",
|
||||||
|
"plt.ylabel('Accuracy')\n",
|
||||||
|
"plt.ylim([min(plt.ylim()),1])\n",
|
||||||
|
"plt.title('Training Accuracy')\n",
|
||||||
|
"\n",
|
||||||
|
"plt.subplot(2, 1, 2)\n",
|
||||||
|
"plt.plot(loss, label='Training Loss')\n",
|
||||||
|
"plt.plot(val_loss, label='Validation Loss')\n",
|
||||||
|
"plt.legend(loc='upper right')\n",
|
||||||
|
"plt.ylabel('Cross Entropy')\n",
|
||||||
|
"# plt.ylim([0,1.0])\n",
|
||||||
|
"plt.title('Training Loss')\n",
|
||||||
|
"plt.xlabel('epoch')\n",
|
||||||
|
"plt.show()"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {
|
||||||
|
"colab_type": "text",
|
||||||
|
"id": "FK_OysQzQ4_S"
|
||||||
|
},
|
||||||
|
"source": [
|
||||||
|
"We start to fine tune the model by allowing the last 55 layers to be trained."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 0,
|
||||||
|
"metadata": {
|
||||||
|
"colab": {},
|
||||||
|
"colab_type": "code",
|
||||||
|
"id": "BffxJucn6wlf"
|
||||||
|
},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"base_model.trainable = True"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 0,
|
||||||
|
"metadata": {
|
||||||
|
"colab": {},
|
||||||
|
"colab_type": "code",
|
||||||
|
"id": "WCA4VLaUYr7P"
|
||||||
|
},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"# Let's take a look to see how many layers are in the base model\n",
|
||||||
|
"print(\"Number of layers in the base model: \", len(base_model.layers))\n",
|
||||||
|
"\n",
|
||||||
|
"# Fine tune from this layer onwards\n",
|
||||||
|
"fine_tune_at = 100\n",
|
||||||
|
"\n",
|
||||||
|
"# Freeze all the layers before the `fine_tune_at` layer\n",
|
||||||
|
"for layer in base_model.layers[:fine_tune_at]:\n",
|
||||||
|
" layer.trainable = False"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 0,
|
||||||
|
"metadata": {
|
||||||
|
"colab": {},
|
||||||
|
"colab_type": "code",
|
||||||
|
"id": "fbNXMyuEZd2h"
|
||||||
|
},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"model.compile(loss='categorical_crossentropy',\n",
|
||||||
|
" optimizer = tf.keras.optimizers.RMSprop(lr=base_learning_rate/10),\n",
|
||||||
|
" metrics=['accuracy'])"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 0,
|
||||||
|
"metadata": {
|
||||||
|
"colab": {},
|
||||||
|
"colab_type": "code",
|
||||||
|
"id": "JmYtpM-GZit-"
|
||||||
|
},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"initial_epochs = 10\n",
|
||||||
|
"fine_tune_epochs = 10\n",
|
||||||
|
"total_epochs = initial_epochs + fine_tune_epochs\n",
|
||||||
|
"\n",
|
||||||
|
"\n",
|
||||||
|
"def fit_model_FT(model, batch_size=32, epochs=10): \n",
|
||||||
|
" history = model.fit_generator(\n",
|
||||||
|
" generator=train_generator,\n",
|
||||||
|
" steps_per_epoch=(len(train_frame) // batch_size),\n",
|
||||||
|
" epochs=total_epochs,\n",
|
||||||
|
" initial_epoch=initial_epochs,\n",
|
||||||
|
" validation_data=validation_generator,\n",
|
||||||
|
" callbacks=None\n",
|
||||||
|
" )\n",
|
||||||
|
" score = model.evaluate_generator(train_generator, verbose=1)\n",
|
||||||
|
" probs = model.predict_generator(test_generator, verbose=1)\n",
|
||||||
|
" return model, score, probs, history"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 0,
|
||||||
|
"metadata": {
|
||||||
|
"colab": {},
|
||||||
|
"colab_type": "code",
|
||||||
|
"id": "Ng5tOm_VZ2LZ"
|
||||||
|
},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"fit_model, score, probs, history = fit_model_FT(model, batch_size=32, epochs=10)"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 0,
|
||||||
|
"metadata": {
|
||||||
|
"colab": {},
|
||||||
|
"colab_type": "code",
|
||||||
|
"id": "ee6U1HZLWnK8"
|
||||||
|
},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"acc = history.history['accuracy']\n",
|
||||||
|
"val_acc = history.history['val_accuracy']\n",
|
||||||
|
"\n",
|
||||||
|
"loss = history.history['loss']\n",
|
||||||
|
"val_loss = history.history['val_loss']\n",
|
||||||
|
"\n",
|
||||||
|
"plt.figure(figsize=(8, 8))\n",
|
||||||
|
"plt.subplot(2, 1, 1)\n",
|
||||||
|
"plt.plot(acc, label='Training Accuracy')\n",
|
||||||
|
"plt.plot(val_acc, label='Validation Accuracy')\n",
|
||||||
|
"plt.legend(loc='lower right')\n",
|
||||||
|
"plt.ylabel('Accuracy')\n",
|
||||||
|
"plt.ylim([min(plt.ylim()),1])\n",
|
||||||
|
"plt.title('Training Accuracy')\n",
|
||||||
|
"\n",
|
||||||
|
"plt.subplot(2, 1, 2)\n",
|
||||||
|
"plt.plot(loss, label='Training Loss')\n",
|
||||||
|
"plt.plot(val_loss, label='Validation Loss')\n",
|
||||||
|
"plt.legend(loc='upper right')\n",
|
||||||
|
"plt.ylabel('Cross Entropy')\n",
|
||||||
|
"# plt.ylim([0,1.0])\n",
|
||||||
|
"plt.title('Training Loss')\n",
|
||||||
|
"plt.xlabel('epoch')\n",
|
||||||
|
"plt.show()"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {
|
||||||
|
"colab_type": "text",
|
||||||
|
"id": "bFU-cJgNRNr3"
|
||||||
|
},
|
||||||
|
"source": [
|
||||||
|
"After 10 fine tuning epochs the hit rates increased to 63 (top), 82 (top3), and 88 % (top5)."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 0,
|
||||||
|
"metadata": {
|
||||||
|
"colab": {},
|
||||||
|
"colab_type": "code",
|
||||||
|
"id": "fJWas9HFIm8p"
|
||||||
|
},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"correct_prediction = 0\n",
|
||||||
|
"correct_top3 = 0\n",
|
||||||
|
"correct_top5 = 0\n",
|
||||||
|
"for ii in range(len(probs)):\n",
|
||||||
|
" P_this = np.argmax(probs[ii])\n",
|
||||||
|
" GT_this = test_generator.labels[ii]\n",
|
||||||
|
" if P_this == GT_this:\n",
|
||||||
|
" correct_prediction += 1\n",
|
||||||
|
" correct_top3 += top3(probs[ii],GT_this)\n",
|
||||||
|
" correct_top5 += top5(probs[ii],GT_this)\n",
|
||||||
|
" if ii % 100 == 20:\n",
|
||||||
|
" t3, p3 = top3_idx(probs[ii])\n",
|
||||||
|
" print(\"Prediction: {}, {}, or {} ({} ({:.1f} %), {} ({:.1f} %), or {} ({:.1f} %))\".format(t3[0], t3[1], t3[2] ,Birds[int(list(test_generator.class_indices.keys())[list(test_generator.class_indices.values()).index(t3[0])])], p3[0] * 100,\n",
|
||||||
|
" Birds[int(list(test_generator.class_indices.keys())[list(test_generator.class_indices.values()).index(t3[1])])], p3[1] * 100,\n",
|
||||||
|
" Birds[int(list(test_generator.class_indices.keys())[list(test_generator.class_indices.values()).index(t3[2])])], p3[2] * 100))\n",
|
||||||
|
" print(\"Actual: {} ({})\".format(GT_this,Birds[int(list(test_generator.class_indices.keys())[list(test_generator.class_indices.values()).index(GT_this)])]))\n",
|
||||||
|
"\n",
|
||||||
|
" \n",
|
||||||
|
" plt.figure()\n",
|
||||||
|
" image = plt.imread('data/test/'+test_generator.filenames[ii])\n",
|
||||||
|
" plt.imshow(image)\n",
|
||||||
|
" plt.show()\n",
|
||||||
|
"print(correct_prediction, correct_prediction/len(probs))\n",
|
||||||
|
"print(correct_top3, correct_top3/len(probs))\n",
|
||||||
|
"print(correct_top5, correct_top5/len(probs))\n",
|
||||||
|
"print(len(probs))"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 0,
|
||||||
|
"metadata": {
|
||||||
|
"colab": {},
|
||||||
|
"colab_type": "code",
|
||||||
|
"id": "5BfjDfYfSaGs"
|
||||||
|
},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"Prediction = []\n",
|
||||||
|
"Prediction3 = []\n",
|
||||||
|
"Correct_prediction3 = []\n",
|
||||||
|
"for ii in range(len(probs)):\n",
|
||||||
|
" Prediction.append(np.argmax(probs[ii]))\n",
|
||||||
|
" Prediction3.append(top3_idx(probs[ii])[0])\n",
|
||||||
|
" Correct_prediction3.append(np.asscalar(np.in1d(test_generator.labels[ii],Prediction3[ii])))\n",
|
||||||
|
"\n",
|
||||||
|
" \n",
|
||||||
|
"Correct_predicted = []\n",
|
||||||
|
"Correct_predicted3 = []\n",
|
||||||
|
"Species_length = []\n",
|
||||||
|
"for ii in range(len(np.unique(test_generator.labels))):\n",
|
||||||
|
" Species_length.append(sum((test_generator.labels == ii)))\n",
|
||||||
|
" Correct_predicted.append((sum((test_generator.labels == ii) & (Prediction == test_generator.labels)))/sum(test_generator.labels == ii))\n",
|
||||||
|
" Correct_predicted3.append(sum((test_generator.labels == ii) & (Correct_prediction3))/sum(test_generator.labels == ii))\n"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {
|
||||||
|
"colab_type": "text",
|
||||||
|
"id": "y090L25JReE_"
|
||||||
|
},
|
||||||
|
"source": [
|
||||||
|
"For some species the model performed terribly. "
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 0,
|
||||||
|
"metadata": {
|
||||||
|
"colab": {},
|
||||||
|
"colab_type": "code",
|
||||||
|
"id": "hYumabaNVOMA"
|
||||||
|
},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"for ii in range(len(np.unique(test_generator.labels))):\n",
|
||||||
|
"# if sum((test_generator.labels == ii)) < 8:\n",
|
||||||
|
" if Correct_predicted3[ii] < 0.4:\n",
|
||||||
|
" print('{}: {:.2f}, {:.2f}, {}, {}'.format(ii, Correct_predicted[ii], Correct_predicted3[ii], sum((train_generator.labels == ii)), Birds[int(list(test_generator.class_indices.keys())[list(test_generator.class_indices.values()).index(ii)])]))"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 0,
|
||||||
|
"metadata": {
|
||||||
|
"colab": {},
|
||||||
|
"colab_type": "code",
|
||||||
|
"id": "eWALVyB-PwNz"
|
||||||
|
},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"initial_epochs = 20\n",
|
||||||
|
"fine_tune_epochs = 10\n",
|
||||||
|
"total_epochs = initial_epochs + fine_tune_epochs\n",
|
||||||
|
"\n",
|
||||||
|
"\n",
|
||||||
|
"def fit_model_FT2(model, batch_size=32, epochs=10): \n",
|
||||||
|
" history = model.fit_generator(\n",
|
||||||
|
" generator=train_generator,\n",
|
||||||
|
" steps_per_epoch=(len(train_frame) // batch_size),\n",
|
||||||
|
" epochs=total_epochs,\n",
|
||||||
|
" initial_epoch=initial_epochs,\n",
|
||||||
|
" validation_data=validation_generator,\n",
|
||||||
|
" callbacks=None\n",
|
||||||
|
" )\n",
|
||||||
|
" score = model.evaluate_generator(train_generator, verbose=1)\n",
|
||||||
|
" probs = model.predict_generator(test_generator, verbose=1)\n",
|
||||||
|
" return model, score, probs, history"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 0,
|
||||||
|
"metadata": {
|
||||||
|
"colab": {},
|
||||||
|
"colab_type": "code",
|
||||||
|
"id": "sqEGCIJmP3aC"
|
||||||
|
},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"#fit_model, score, probs, history = fit_model_FT(model, X_train, X_test, Y_train, Y_test, batch_size=32, epochs=15)\n",
|
||||||
|
"fit_model, score, probs, history = fit_model_FT2(model, batch_size=32, epochs=10)\n",
|
||||||
|
"model.save(datapath + '/model3_30.h5')\n",
|
||||||
|
"\n"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 0,
|
||||||
|
"metadata": {
|
||||||
|
"colab": {},
|
||||||
|
"colab_type": "code",
|
||||||
|
"id": "4DyFi0YJH5iv"
|
||||||
|
},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"probs = model.predict_generator(test_generator, verbose=1)\n",
|
||||||
|
"np.savetxt(datapath + '/probs30.txt', probs)"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {
|
||||||
|
"colab_type": "text",
|
||||||
|
"id": "fB66sNewSaue"
|
||||||
|
},
|
||||||
|
"source": [
|
||||||
|
"After another 10 fine tuning epochs (total = 30 epochs) we have 66, 84, 89 % top 1, 3, 5 hit rate. At this point it may be more helpful to refine the probability based on the location and time of year that the picture is taken. "
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 0,
|
||||||
|
"metadata": {
|
||||||
|
"colab": {},
|
||||||
|
"colab_type": "code",
|
||||||
|
"id": "bjudiCZmKEe3"
|
||||||
|
},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"correct_prediction = 0\n",
|
||||||
|
"correct_top3 = 0\n",
|
||||||
|
"correct_top5 = 0\n",
|
||||||
|
"for ii in range(len(probs)):\n",
|
||||||
|
" P_this = np.argmax(probs[ii])\n",
|
||||||
|
" GT_this = test_generator.labels[ii]\n",
|
||||||
|
" if P_this == GT_this:\n",
|
||||||
|
" correct_prediction += 1\n",
|
||||||
|
" correct_top3 += top3(probs[ii],GT_this)\n",
|
||||||
|
" correct_top5 += top5(probs[ii],GT_this)\n",
|
||||||
|
" if ii % 100 == 26:\n",
|
||||||
|
"# if test_generator.labels[ii] == 10: # Gadwall\n",
|
||||||
|
" #print(\"Prediction: {} ({})\".format(P_this,Birds[int(list(test_generator.class_indices.keys())[list(test_generator.class_indices.values()).index(top3_idx(probs[ii]))])]))\n",
|
||||||
|
" t3, p3 = top3_idx(probs[ii])\n",
|
||||||
|
" print(\"Prediction: {}, {}, or {} ({} ({:.1f} %), {} ({:.1f} %), or {} ({:.1f} %))\".format(t3[0], t3[1], t3[2] ,Birds[int(list(test_generator.class_indices.keys())[list(test_generator.class_indices.values()).index(t3[0])])], p3[0] * 100,\n",
|
||||||
|
" Birds[int(list(test_generator.class_indices.keys())[list(test_generator.class_indices.values()).index(t3[1])])], p3[1] * 100,\n",
|
||||||
|
" Birds[int(list(test_generator.class_indices.keys())[list(test_generator.class_indices.values()).index(t3[2])])], p3[2] * 100))\n",
|
||||||
|
" print(\"Actual: {} ({})\".format(GT_this,Birds[int(list(test_generator.class_indices.keys())[list(test_generator.class_indices.values()).index(GT_this)])]))\n",
|
||||||
|
"# print(\"Prediction: {} \".format(P_this))\n",
|
||||||
|
"# print(\"Actual: {} \".format(GT_this))\n",
|
||||||
|
"# print('data/test/'+test_generator.filenames[ii])\n",
|
||||||
|
" \n",
|
||||||
|
" plt.figure()\n",
|
||||||
|
" image = plt.imread('data/test/'+test_generator.filenames[ii])\n",
|
||||||
|
" plt.imshow(image)\n",
|
||||||
|
" plt.show()\n",
|
||||||
|
"print(correct_prediction, correct_prediction/len(probs))\n",
|
||||||
|
"print(correct_top3, correct_top3/len(probs))\n",
|
||||||
|
"print(correct_top5, correct_top5/len(probs))\n",
|
||||||
|
"print(len(probs))"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {
|
||||||
|
"colab_type": "text",
|
||||||
|
"id": "RlxJGKb8TNYY"
|
||||||
|
},
|
||||||
|
"source": [
|
||||||
|
"Using my photos to test."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 0,
|
||||||
|
"metadata": {
|
||||||
|
"colab": {},
|
||||||
|
"colab_type": "code",
|
||||||
|
"id": "TRgQdjw7APzO"
|
||||||
|
},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"Darren_test_generator = test_datagen.flow_from_directory(\n",
|
||||||
|
" #directory=datapath + '/data/test/',\n",
|
||||||
|
" directory='/content/Darren_test/',\n",
|
||||||
|
" shuffle=False,\n",
|
||||||
|
" #classes=list(Bird_list),\n",
|
||||||
|
" target_size=(224, 224),\n",
|
||||||
|
" batch_size=32,\n",
|
||||||
|
" class_mode='categorical')"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 0,
|
||||||
|
"metadata": {
|
||||||
|
"colab": {},
|
||||||
|
"colab_type": "code",
|
||||||
|
"id": "FbuTUb_6AaGy"
|
||||||
|
},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"Darren_probs = model.predict_generator(Darren_test_generator, verbose=1)"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 0,
|
||||||
|
"metadata": {
|
||||||
|
"colab": {},
|
||||||
|
"colab_type": "code",
|
||||||
|
"id": "bf_PABndAb7s"
|
||||||
|
},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"correct_prediction = 0\n",
|
||||||
|
"correct_top3 = 0\n",
|
||||||
|
"correct_top5 = 0\n",
|
||||||
|
"for ii in range(len(Darren_probs)):\n",
|
||||||
|
"# for ii in [0]:\n",
|
||||||
|
" P_this = np.argmax(Darren_probs[ii])\n",
|
||||||
|
" GT_this = test_generator.class_indices[list(Darren_test_generator.class_indices.keys())[Darren_test_generator.labels[ii]]]\n",
|
||||||
|
" if P_this == GT_this:\n",
|
||||||
|
" correct_prediction += 1\n",
|
||||||
|
" correct_top3 += top3(Darren_probs[ii],GT_this)\n",
|
||||||
|
" correct_top5 += top5(Darren_probs[ii],GT_this)\n",
|
||||||
|
"# if ii % 100 == 26:\n",
|
||||||
|
"# if test_generator.labels[ii] == 10: # Gadwall\n",
|
||||||
|
" #print(\"Prediction: {} ({})\".format(P_this,Birds[int(list(test_generator.class_indices.keys())[list(test_generator.class_indices.values()).index(top3_idx(probs[ii]))])]))\n",
|
||||||
|
" t3, p3 = top3_idx(Darren_probs[ii])\n",
|
||||||
|
" print(\"Prediction: {}, {}, or {} ({} ({:.1f} %), {} ({:.1f} %), or {} ({:.1f} %))\".format(\n",
|
||||||
|
" t3[0], t3[1], t3[2] ,Birds[int(list(test_generator.class_indices.keys())[list(test_generator.class_indices.values()).index(t3[0])])], p3[0] * 100,\n",
|
||||||
|
" Birds[int(list(test_generator.class_indices.keys())[list(test_generator.class_indices.values()).index(t3[1])])], p3[1] * 100,\n",
|
||||||
|
" Birds[int(list(test_generator.class_indices.keys())[list(test_generator.class_indices.values()).index(t3[2])])], p3[2] * 100))\n",
|
||||||
|
" print(\"Actual: {} ({})\".format(GT_this,Birds[int(list(test_generator.class_indices.keys())[list(test_generator.class_indices.values()).index(GT_this)])]))\n",
|
||||||
|
"# print(\"Prediction: {} \".format(P_this))\n",
|
||||||
|
"# print(\"Actual: {} \".format(GT_this))\n",
|
||||||
|
"# print('data/test/'+test_generator.filenames[ii])\n",
|
||||||
|
" \n",
|
||||||
|
" plt.figure()\n",
|
||||||
|
" image = plt.imread('Darren_test/'+Darren_test_generator.filenames[ii])\n",
|
||||||
|
" plt.imshow(image)\n",
|
||||||
|
" plt.show()\n",
|
||||||
|
"print(correct_prediction, correct_prediction/len(Darren_probs))\n",
|
||||||
|
"print(correct_top3, correct_top3/len(Darren_probs))\n",
|
||||||
|
"print(correct_top5, correct_top5/len(Darren_probs))\n",
|
||||||
|
"print(len(Darren_probs))"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {
|
||||||
|
"colab_type": "text",
|
||||||
|
"id": "Yg-w5GA6TIZy"
|
||||||
|
},
|
||||||
|
"source": [
|
||||||
|
"Below are scratch codes."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 0,
|
||||||
|
"metadata": {
|
||||||
|
"colab": {},
|
||||||
|
"colab_type": "code",
|
||||||
|
"id": "h_6UTR_-hBIs"
|
||||||
|
},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"#Birds\n",
|
||||||
|
"class_indices_inv_map = {v: k for k, v in test_generator.class_indices.items()} \n",
|
||||||
|
"\n",
|
||||||
|
"import pickle\n",
|
||||||
|
"\n",
|
||||||
|
"# write python dict to a file\n",
|
||||||
|
"output = open(datapath+'/class_indices_inv_map.pkl', 'wb')\n",
|
||||||
|
"pickle.dump(class_indices_inv_map, output)\n",
|
||||||
|
"output.close()\n",
|
||||||
|
"output = open(datapath+'/Birds.pkl', 'wb')\n",
|
||||||
|
"pickle.dump(Birds, output)\n",
|
||||||
|
"output.close()"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"metadata": {
|
||||||
|
"accelerator": "GPU",
|
||||||
|
"colab": {
|
||||||
|
"collapsed_sections": [],
|
||||||
|
"name": "Bird_ID_404_species_CNN_TL_clean.ipynb",
|
||||||
|
"provenance": [],
|
||||||
|
"version": "0.3.2"
|
||||||
|
},
|
||||||
|
"kernelspec": {
|
||||||
|
"display_name": "Python 3",
|
||||||
|
"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.8.5"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nbformat": 4,
|
||||||
|
"nbformat_minor": 1
|
||||||
|
}
|
467
src/.ipynb_checkpoints/TensorBirdId-checkpoint.ipynb
Normal file
467
src/.ipynb_checkpoints/TensorBirdId-checkpoint.ipynb
Normal file
File diff suppressed because one or more lines are too long
899
src/Bird_ID_404_species_CNN_TL_clean.ipynb
Normal file
899
src/Bird_ID_404_species_CNN_TL_clean.ipynb
Normal file
@ -0,0 +1,899 @@
|
|||||||
|
{
|
||||||
|
"cells": [
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {
|
||||||
|
"colab_type": "text",
|
||||||
|
"id": "z-7UORN7Ymoo"
|
||||||
|
},
|
||||||
|
"source": [
|
||||||
|
"Mount the drive to the instance."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 0,
|
||||||
|
"metadata": {
|
||||||
|
"colab": {},
|
||||||
|
"colab_type": "code",
|
||||||
|
"id": "9X2hja-OpXM9"
|
||||||
|
},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"from google.colab import drive\n",
|
||||||
|
"drive.mount('/content/gdrive')"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {
|
||||||
|
"colab_type": "text",
|
||||||
|
"id": "fjU2n68zYxU3"
|
||||||
|
},
|
||||||
|
"source": [
|
||||||
|
"Import various modules.\n",
|
||||||
|
"\n",
|
||||||
|
"I used Tnesorflow and its Keras library as the backend. The Keras module is for preprocessing images. "
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 0,
|
||||||
|
"metadata": {
|
||||||
|
"colab": {},
|
||||||
|
"colab_type": "code",
|
||||||
|
"id": "QIR81L-ArDn3"
|
||||||
|
},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"!pip install -q tensorflow-gpu==2.0.0-alpha0\n",
|
||||||
|
"import cv2\n",
|
||||||
|
"import numpy as np\n",
|
||||||
|
"import pandas as pd\n",
|
||||||
|
"import matplotlib.pyplot as plt\n",
|
||||||
|
"import matplotlib.patches as patches\n",
|
||||||
|
"from __future__ import absolute_import, division, print_function\n",
|
||||||
|
"import os\n",
|
||||||
|
"import tensorflow as tf\n",
|
||||||
|
"from sklearn.model_selection import train_test_split\n",
|
||||||
|
"from keras.utils import to_categorical\n",
|
||||||
|
"from keras.callbacks import ModelCheckpoint, ReduceLROnPlateau, EarlyStopping\n",
|
||||||
|
"from keras.preprocessing import image\n",
|
||||||
|
"keras = tf.keras\n",
|
||||||
|
"datapath = '/content/gdrive/My Drive/Bird_ID_project/nabirds'"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {
|
||||||
|
"colab_type": "text",
|
||||||
|
"id": "GVPN6iW0IvZ5"
|
||||||
|
},
|
||||||
|
"source": [
|
||||||
|
"Reading in the pandas dataframe. It actually doesn't provide much beside the unique species class names."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 0,
|
||||||
|
"metadata": {
|
||||||
|
"colab": {},
|
||||||
|
"colab_type": "code",
|
||||||
|
"id": "K99e_KEnkN4p"
|
||||||
|
},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"train_frame = pd.read_csv(datapath+'/train.csv')\n",
|
||||||
|
"val_frame = pd.read_csv(datapath+'/val.csv')\n",
|
||||||
|
"test_frame = pd.read_csv(datapath+'/test.csv')\n",
|
||||||
|
"# train_frame\n",
|
||||||
|
"Bird_list=train_frame.class_name_sp.unique()\n",
|
||||||
|
"Bird_id=train_frame.class_id_sp.unique()\n",
|
||||||
|
"# print(Bird_list, Bird_id)\n",
|
||||||
|
"Birds = dict(zip(Bird_id, Bird_list))"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {
|
||||||
|
"colab_type": "text",
|
||||||
|
"id": "R9pJGyS8b83K"
|
||||||
|
},
|
||||||
|
"source": [
|
||||||
|
"Unzip the tar.gz files **to the Google Colab instance**. This drastically increased the training speed."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 0,
|
||||||
|
"metadata": {
|
||||||
|
"colab": {},
|
||||||
|
"colab_type": "code",
|
||||||
|
"id": "cYGuyyUINUQ3"
|
||||||
|
},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"!tar -xzf \"gdrive/My Drive/Bird_ID_project/nabirds/data.tar.gz\"\n",
|
||||||
|
"!tar -xzf \"gdrive/My Drive/Bird_ID_project/nabirds/Darren_data.tar.gz\""
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 0,
|
||||||
|
"metadata": {
|
||||||
|
"colab": {},
|
||||||
|
"colab_type": "code",
|
||||||
|
"id": "GWP0UQZdBDk1"
|
||||||
|
},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"!mv /content/Darren_test/0289 /content/Darren_test/0867\n",
|
||||||
|
"!mv /content/Darren_test/0095 /content/Darren_test/0553\n",
|
||||||
|
"!rm -rf /content/Darren_test/NIL"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {
|
||||||
|
"colab_type": "text",
|
||||||
|
"id": "0vRSm4DVI9Jd"
|
||||||
|
},
|
||||||
|
"source": [
|
||||||
|
"Using Keras image generator to reduce RAM footprint (instead of using a large numpy array)."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 0,
|
||||||
|
"metadata": {
|
||||||
|
"colab": {},
|
||||||
|
"colab_type": "code",
|
||||||
|
"id": "BxCuJxxxl2ge"
|
||||||
|
},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"train_datagen = image.ImageDataGenerator(\n",
|
||||||
|
" rescale=1./255,\n",
|
||||||
|
"# width_shift_range=0.1,\n",
|
||||||
|
"# height_shift_range=0.1,\n",
|
||||||
|
"# zoom_range=0.1,\n",
|
||||||
|
" fill_mode='constant',\n",
|
||||||
|
" horizontal_flip=True,\n",
|
||||||
|
" dtype=np.float32)\n",
|
||||||
|
"\n",
|
||||||
|
"val_datagen = image.ImageDataGenerator(\n",
|
||||||
|
" rescale=1./255, \n",
|
||||||
|
" dtype=np.float32)\n",
|
||||||
|
"\n",
|
||||||
|
"test_datagen = image.ImageDataGenerator(\n",
|
||||||
|
" rescale=1./255,\n",
|
||||||
|
" dtype=np.float32)\n",
|
||||||
|
"\n",
|
||||||
|
"train_generator = train_datagen.flow_from_directory(\n",
|
||||||
|
" directory='/content/data/train/',\n",
|
||||||
|
" #directory=datapath + '/data/train/',\n",
|
||||||
|
" #classes=list(Bird_list),\n",
|
||||||
|
" target_size=(224, 224),\n",
|
||||||
|
" batch_size=32,\n",
|
||||||
|
" class_mode='categorical')\n",
|
||||||
|
"\n",
|
||||||
|
"validation_generator = val_datagen.flow_from_directory(\n",
|
||||||
|
" #directory=datapath + '/data/val/',\n",
|
||||||
|
" directory='/content/data/val/',\n",
|
||||||
|
" #classes=list(Bird_list),\n",
|
||||||
|
" target_size=(224, 224),\n",
|
||||||
|
" batch_size=32,\n",
|
||||||
|
" class_mode='categorical')\n",
|
||||||
|
"\n",
|
||||||
|
"test_generator = test_datagen.flow_from_directory(\n",
|
||||||
|
" #directory=datapath + '/data/test/',\n",
|
||||||
|
" directory='/content/data/test/',\n",
|
||||||
|
" shuffle=False,\n",
|
||||||
|
" #classes=list(Bird_list),\n",
|
||||||
|
" target_size=(224, 224),\n",
|
||||||
|
" batch_size=32,\n",
|
||||||
|
" class_mode='categorical')\n"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {
|
||||||
|
"colab_type": "text",
|
||||||
|
"id": "HlsRpRXDMicF"
|
||||||
|
},
|
||||||
|
"source": [
|
||||||
|
"Research has shown that starting from scratch will not work. So we use MobileNet V2 as our feature extractor. This is a relatively small network, which will help in the future when we want to run near real time inferences. We also add two layers: One global average and one prediction. "
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 0,
|
||||||
|
"metadata": {
|
||||||
|
"colab": {},
|
||||||
|
"colab_type": "code",
|
||||||
|
"id": "ytj6wsAdM7Un"
|
||||||
|
},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"IMG_SHAPE = (224,224,3)\n",
|
||||||
|
"base_model = tf.keras.applications.MobileNetV2(input_shape=IMG_SHAPE,\n",
|
||||||
|
" include_top=False, \n",
|
||||||
|
" weights='imagenet')\n",
|
||||||
|
"\n",
|
||||||
|
"base_model.trainable = False\n",
|
||||||
|
"\n",
|
||||||
|
"global_average_layer = tf.keras.layers.GlobalAveragePooling2D()\n",
|
||||||
|
"prediction_layer = keras.layers.Dense(404,activation='softmax')\n",
|
||||||
|
"base_learning_rate = 0.0001\n",
|
||||||
|
"model = tf.keras.Sequential([\n",
|
||||||
|
" base_model,\n",
|
||||||
|
" global_average_layer,\n",
|
||||||
|
" prediction_layer\n",
|
||||||
|
"])\n",
|
||||||
|
"model.compile(optimizer=tf.keras.optimizers.RMSprop(lr=base_learning_rate), \n",
|
||||||
|
" loss='categorical_crossentropy', \n",
|
||||||
|
" metrics=['accuracy'])\n",
|
||||||
|
"model.summary()"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 0,
|
||||||
|
"metadata": {
|
||||||
|
"colab": {},
|
||||||
|
"colab_type": "code",
|
||||||
|
"id": "bGi69hxZRSvy"
|
||||||
|
},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"def fit_model(model, batch_size=32, epochs=10): \n",
|
||||||
|
" history = model.fit_generator(\n",
|
||||||
|
" generator=train_generator,\n",
|
||||||
|
" steps_per_epoch=(len(train_frame) // batch_size),\n",
|
||||||
|
" epochs=epochs,\n",
|
||||||
|
" validation_data=validation_generator,\n",
|
||||||
|
" callbacks=None\n",
|
||||||
|
" )\n",
|
||||||
|
" score = model.evaluate_generator(train_generator, verbose=1)\n",
|
||||||
|
" probs = model.predict_generator(test_generator, verbose=1)\n",
|
||||||
|
" return model, score, probs, history\n"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 0,
|
||||||
|
"metadata": {
|
||||||
|
"colab": {},
|
||||||
|
"colab_type": "code",
|
||||||
|
"id": "dt80nu7nQlzm"
|
||||||
|
},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"fit_model, score, probs, history = fit_model(model, batch_size=32, epochs=10)"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 0,
|
||||||
|
"metadata": {
|
||||||
|
"colab": {},
|
||||||
|
"colab_type": "code",
|
||||||
|
"id": "YdfI5Fzw6CRx"
|
||||||
|
},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"def top3(probs, GT):\n",
|
||||||
|
" t3 = np.argsort(probs)[-3:]\n",
|
||||||
|
" #print(t3)\n",
|
||||||
|
" if GT in t3:\n",
|
||||||
|
" return 1\n",
|
||||||
|
" else:\n",
|
||||||
|
" return 0\n",
|
||||||
|
" \n",
|
||||||
|
"def top5(probs, GT):\n",
|
||||||
|
" t5 = np.argsort(probs)[-5:]\n",
|
||||||
|
" if GT in t5:\n",
|
||||||
|
" return 1\n",
|
||||||
|
" else:\n",
|
||||||
|
" return 0\n",
|
||||||
|
" \n",
|
||||||
|
"def top3_idx(probs):\n",
|
||||||
|
" return np.flip(np.argsort(probs)[-3:],0), np.flip(probs[np.argsort(probs)[-3:]],0)\n",
|
||||||
|
" #print(t3)\n",
|
||||||
|
"\n",
|
||||||
|
"def top5_idx(probs):\n",
|
||||||
|
" return np.flip(np.argsort(probs)[-5:])\n",
|
||||||
|
" #print(t3)"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {
|
||||||
|
"colab_type": "text",
|
||||||
|
"id": "-Kb1Q3eeP7DI"
|
||||||
|
},
|
||||||
|
"source": [
|
||||||
|
"After 10 epochs we achieve 44, 64, and 72 % top 1, 3, and 5 hit rate. Not bad! But it can be better. "
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 0,
|
||||||
|
"metadata": {
|
||||||
|
"colab": {},
|
||||||
|
"colab_type": "code",
|
||||||
|
"id": "2iQYi1kdSLtF"
|
||||||
|
},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"correct_prediction = 0\n",
|
||||||
|
"correct_top3 = 0\n",
|
||||||
|
"correct_top5 = 0\n",
|
||||||
|
"for ii in range(len(probs)):\n",
|
||||||
|
" P_this = np.argmax(probs[ii])\n",
|
||||||
|
" GT_this = test_generator.labels[ii]\n",
|
||||||
|
" if P_this == GT_this:\n",
|
||||||
|
" correct_prediction += 1\n",
|
||||||
|
" correct_top3 += top3(probs[ii],GT_this)\n",
|
||||||
|
" correct_top5 += top5(probs[ii],GT_this)\n",
|
||||||
|
" if ii < 10:\n",
|
||||||
|
" print(\"Prediction: {} ({})\".format(P_this,Birds[int(list(test_generator.class_indices.keys())[list(test_generator.class_indices.values()).index(P_this)])]))\n",
|
||||||
|
" print(\"Actual: {} ({})\".format(GT_this,Birds[int(list(test_generator.class_indices.keys())[list(test_generator.class_indices.values()).index(GT_this)])]))\n",
|
||||||
|
" print(\"Prediction: {} \".format(P_this))\n",
|
||||||
|
" print(\"Actual: {} \".format(GT_this))\n",
|
||||||
|
" #plt.figure()\n",
|
||||||
|
" #plt.imshow(X_test[ii,:,:,:])\n",
|
||||||
|
" #plt.show()\n",
|
||||||
|
"print(correct_prediction, correct_prediction/len(probs))\n",
|
||||||
|
"print(correct_top3, correct_top3/len(probs))\n",
|
||||||
|
"print(correct_top5, correct_top5/len(probs))\n",
|
||||||
|
"print(len(probs))"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {
|
||||||
|
"colab_type": "text",
|
||||||
|
"id": "2ou1-W3SQYOK"
|
||||||
|
},
|
||||||
|
"source": [
|
||||||
|
"We see overfitting after second epoch, which seems to be a common thing when training models for bird IDs. "
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 0,
|
||||||
|
"metadata": {
|
||||||
|
"colab": {},
|
||||||
|
"colab_type": "code",
|
||||||
|
"id": "7tJdIW8F6mIv"
|
||||||
|
},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"acc = history.history['accuracy']\n",
|
||||||
|
"val_acc = history.history['val_accuracy']\n",
|
||||||
|
"\n",
|
||||||
|
"loss = history.history['loss']\n",
|
||||||
|
"val_loss = history.history['val_loss']\n",
|
||||||
|
"\n",
|
||||||
|
"plt.figure(figsize=(8, 8))\n",
|
||||||
|
"plt.subplot(2, 1, 1)\n",
|
||||||
|
"plt.plot(acc, label='Training Accuracy')\n",
|
||||||
|
"plt.plot(val_acc, label='Validation Accuracy')\n",
|
||||||
|
"plt.legend(loc='lower right')\n",
|
||||||
|
"plt.ylabel('Accuracy')\n",
|
||||||
|
"plt.ylim([min(plt.ylim()),1])\n",
|
||||||
|
"plt.title('Training Accuracy')\n",
|
||||||
|
"\n",
|
||||||
|
"plt.subplot(2, 1, 2)\n",
|
||||||
|
"plt.plot(loss, label='Training Loss')\n",
|
||||||
|
"plt.plot(val_loss, label='Validation Loss')\n",
|
||||||
|
"plt.legend(loc='upper right')\n",
|
||||||
|
"plt.ylabel('Cross Entropy')\n",
|
||||||
|
"# plt.ylim([0,1.0])\n",
|
||||||
|
"plt.title('Training Loss')\n",
|
||||||
|
"plt.xlabel('epoch')\n",
|
||||||
|
"plt.show()"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {
|
||||||
|
"colab_type": "text",
|
||||||
|
"id": "FK_OysQzQ4_S"
|
||||||
|
},
|
||||||
|
"source": [
|
||||||
|
"We start to fine tune the model by allowing the last 55 layers to be trained."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 0,
|
||||||
|
"metadata": {
|
||||||
|
"colab": {},
|
||||||
|
"colab_type": "code",
|
||||||
|
"id": "BffxJucn6wlf"
|
||||||
|
},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"base_model.trainable = True"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 0,
|
||||||
|
"metadata": {
|
||||||
|
"colab": {},
|
||||||
|
"colab_type": "code",
|
||||||
|
"id": "WCA4VLaUYr7P"
|
||||||
|
},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"# Let's take a look to see how many layers are in the base model\n",
|
||||||
|
"print(\"Number of layers in the base model: \", len(base_model.layers))\n",
|
||||||
|
"\n",
|
||||||
|
"# Fine tune from this layer onwards\n",
|
||||||
|
"fine_tune_at = 100\n",
|
||||||
|
"\n",
|
||||||
|
"# Freeze all the layers before the `fine_tune_at` layer\n",
|
||||||
|
"for layer in base_model.layers[:fine_tune_at]:\n",
|
||||||
|
" layer.trainable = False"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 0,
|
||||||
|
"metadata": {
|
||||||
|
"colab": {},
|
||||||
|
"colab_type": "code",
|
||||||
|
"id": "fbNXMyuEZd2h"
|
||||||
|
},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"model.compile(loss='categorical_crossentropy',\n",
|
||||||
|
" optimizer = tf.keras.optimizers.RMSprop(lr=base_learning_rate/10),\n",
|
||||||
|
" metrics=['accuracy'])"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 0,
|
||||||
|
"metadata": {
|
||||||
|
"colab": {},
|
||||||
|
"colab_type": "code",
|
||||||
|
"id": "JmYtpM-GZit-"
|
||||||
|
},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"initial_epochs = 10\n",
|
||||||
|
"fine_tune_epochs = 10\n",
|
||||||
|
"total_epochs = initial_epochs + fine_tune_epochs\n",
|
||||||
|
"\n",
|
||||||
|
"\n",
|
||||||
|
"def fit_model_FT(model, batch_size=32, epochs=10): \n",
|
||||||
|
" history = model.fit_generator(\n",
|
||||||
|
" generator=train_generator,\n",
|
||||||
|
" steps_per_epoch=(len(train_frame) // batch_size),\n",
|
||||||
|
" epochs=total_epochs,\n",
|
||||||
|
" initial_epoch=initial_epochs,\n",
|
||||||
|
" validation_data=validation_generator,\n",
|
||||||
|
" callbacks=None\n",
|
||||||
|
" )\n",
|
||||||
|
" score = model.evaluate_generator(train_generator, verbose=1)\n",
|
||||||
|
" probs = model.predict_generator(test_generator, verbose=1)\n",
|
||||||
|
" return model, score, probs, history"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 0,
|
||||||
|
"metadata": {
|
||||||
|
"colab": {},
|
||||||
|
"colab_type": "code",
|
||||||
|
"id": "Ng5tOm_VZ2LZ"
|
||||||
|
},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"fit_model, score, probs, history = fit_model_FT(model, batch_size=32, epochs=10)"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 0,
|
||||||
|
"metadata": {
|
||||||
|
"colab": {},
|
||||||
|
"colab_type": "code",
|
||||||
|
"id": "ee6U1HZLWnK8"
|
||||||
|
},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"acc = history.history['accuracy']\n",
|
||||||
|
"val_acc = history.history['val_accuracy']\n",
|
||||||
|
"\n",
|
||||||
|
"loss = history.history['loss']\n",
|
||||||
|
"val_loss = history.history['val_loss']\n",
|
||||||
|
"\n",
|
||||||
|
"plt.figure(figsize=(8, 8))\n",
|
||||||
|
"plt.subplot(2, 1, 1)\n",
|
||||||
|
"plt.plot(acc, label='Training Accuracy')\n",
|
||||||
|
"plt.plot(val_acc, label='Validation Accuracy')\n",
|
||||||
|
"plt.legend(loc='lower right')\n",
|
||||||
|
"plt.ylabel('Accuracy')\n",
|
||||||
|
"plt.ylim([min(plt.ylim()),1])\n",
|
||||||
|
"plt.title('Training Accuracy')\n",
|
||||||
|
"\n",
|
||||||
|
"plt.subplot(2, 1, 2)\n",
|
||||||
|
"plt.plot(loss, label='Training Loss')\n",
|
||||||
|
"plt.plot(val_loss, label='Validation Loss')\n",
|
||||||
|
"plt.legend(loc='upper right')\n",
|
||||||
|
"plt.ylabel('Cross Entropy')\n",
|
||||||
|
"# plt.ylim([0,1.0])\n",
|
||||||
|
"plt.title('Training Loss')\n",
|
||||||
|
"plt.xlabel('epoch')\n",
|
||||||
|
"plt.show()"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {
|
||||||
|
"colab_type": "text",
|
||||||
|
"id": "bFU-cJgNRNr3"
|
||||||
|
},
|
||||||
|
"source": [
|
||||||
|
"After 10 fine tuning epochs the hit rates increased to 63 (top), 82 (top3), and 88 % (top5)."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 0,
|
||||||
|
"metadata": {
|
||||||
|
"colab": {},
|
||||||
|
"colab_type": "code",
|
||||||
|
"id": "fJWas9HFIm8p"
|
||||||
|
},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"correct_prediction = 0\n",
|
||||||
|
"correct_top3 = 0\n",
|
||||||
|
"correct_top5 = 0\n",
|
||||||
|
"for ii in range(len(probs)):\n",
|
||||||
|
" P_this = np.argmax(probs[ii])\n",
|
||||||
|
" GT_this = test_generator.labels[ii]\n",
|
||||||
|
" if P_this == GT_this:\n",
|
||||||
|
" correct_prediction += 1\n",
|
||||||
|
" correct_top3 += top3(probs[ii],GT_this)\n",
|
||||||
|
" correct_top5 += top5(probs[ii],GT_this)\n",
|
||||||
|
" if ii % 100 == 20:\n",
|
||||||
|
" t3, p3 = top3_idx(probs[ii])\n",
|
||||||
|
" print(\"Prediction: {}, {}, or {} ({} ({:.1f} %), {} ({:.1f} %), or {} ({:.1f} %))\".format(t3[0], t3[1], t3[2] ,Birds[int(list(test_generator.class_indices.keys())[list(test_generator.class_indices.values()).index(t3[0])])], p3[0] * 100,\n",
|
||||||
|
" Birds[int(list(test_generator.class_indices.keys())[list(test_generator.class_indices.values()).index(t3[1])])], p3[1] * 100,\n",
|
||||||
|
" Birds[int(list(test_generator.class_indices.keys())[list(test_generator.class_indices.values()).index(t3[2])])], p3[2] * 100))\n",
|
||||||
|
" print(\"Actual: {} ({})\".format(GT_this,Birds[int(list(test_generator.class_indices.keys())[list(test_generator.class_indices.values()).index(GT_this)])]))\n",
|
||||||
|
"\n",
|
||||||
|
" \n",
|
||||||
|
" plt.figure()\n",
|
||||||
|
" image = plt.imread('data/test/'+test_generator.filenames[ii])\n",
|
||||||
|
" plt.imshow(image)\n",
|
||||||
|
" plt.show()\n",
|
||||||
|
"print(correct_prediction, correct_prediction/len(probs))\n",
|
||||||
|
"print(correct_top3, correct_top3/len(probs))\n",
|
||||||
|
"print(correct_top5, correct_top5/len(probs))\n",
|
||||||
|
"print(len(probs))"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 0,
|
||||||
|
"metadata": {
|
||||||
|
"colab": {},
|
||||||
|
"colab_type": "code",
|
||||||
|
"id": "5BfjDfYfSaGs"
|
||||||
|
},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"Prediction = []\n",
|
||||||
|
"Prediction3 = []\n",
|
||||||
|
"Correct_prediction3 = []\n",
|
||||||
|
"for ii in range(len(probs)):\n",
|
||||||
|
" Prediction.append(np.argmax(probs[ii]))\n",
|
||||||
|
" Prediction3.append(top3_idx(probs[ii])[0])\n",
|
||||||
|
" Correct_prediction3.append(np.asscalar(np.in1d(test_generator.labels[ii],Prediction3[ii])))\n",
|
||||||
|
"\n",
|
||||||
|
" \n",
|
||||||
|
"Correct_predicted = []\n",
|
||||||
|
"Correct_predicted3 = []\n",
|
||||||
|
"Species_length = []\n",
|
||||||
|
"for ii in range(len(np.unique(test_generator.labels))):\n",
|
||||||
|
" Species_length.append(sum((test_generator.labels == ii)))\n",
|
||||||
|
" Correct_predicted.append((sum((test_generator.labels == ii) & (Prediction == test_generator.labels)))/sum(test_generator.labels == ii))\n",
|
||||||
|
" Correct_predicted3.append(sum((test_generator.labels == ii) & (Correct_prediction3))/sum(test_generator.labels == ii))\n"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {
|
||||||
|
"colab_type": "text",
|
||||||
|
"id": "y090L25JReE_"
|
||||||
|
},
|
||||||
|
"source": [
|
||||||
|
"For some species the model performed terribly. "
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 0,
|
||||||
|
"metadata": {
|
||||||
|
"colab": {},
|
||||||
|
"colab_type": "code",
|
||||||
|
"id": "hYumabaNVOMA"
|
||||||
|
},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"for ii in range(len(np.unique(test_generator.labels))):\n",
|
||||||
|
"# if sum((test_generator.labels == ii)) < 8:\n",
|
||||||
|
" if Correct_predicted3[ii] < 0.4:\n",
|
||||||
|
" print('{}: {:.2f}, {:.2f}, {}, {}'.format(ii, Correct_predicted[ii], Correct_predicted3[ii], sum((train_generator.labels == ii)), Birds[int(list(test_generator.class_indices.keys())[list(test_generator.class_indices.values()).index(ii)])]))"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 0,
|
||||||
|
"metadata": {
|
||||||
|
"colab": {},
|
||||||
|
"colab_type": "code",
|
||||||
|
"id": "eWALVyB-PwNz"
|
||||||
|
},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"initial_epochs = 20\n",
|
||||||
|
"fine_tune_epochs = 10\n",
|
||||||
|
"total_epochs = initial_epochs + fine_tune_epochs\n",
|
||||||
|
"\n",
|
||||||
|
"\n",
|
||||||
|
"def fit_model_FT2(model, batch_size=32, epochs=10): \n",
|
||||||
|
" history = model.fit_generator(\n",
|
||||||
|
" generator=train_generator,\n",
|
||||||
|
" steps_per_epoch=(len(train_frame) // batch_size),\n",
|
||||||
|
" epochs=total_epochs,\n",
|
||||||
|
" initial_epoch=initial_epochs,\n",
|
||||||
|
" validation_data=validation_generator,\n",
|
||||||
|
" callbacks=None\n",
|
||||||
|
" )\n",
|
||||||
|
" score = model.evaluate_generator(train_generator, verbose=1)\n",
|
||||||
|
" probs = model.predict_generator(test_generator, verbose=1)\n",
|
||||||
|
" return model, score, probs, history"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 0,
|
||||||
|
"metadata": {
|
||||||
|
"colab": {},
|
||||||
|
"colab_type": "code",
|
||||||
|
"id": "sqEGCIJmP3aC"
|
||||||
|
},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"#fit_model, score, probs, history = fit_model_FT(model, X_train, X_test, Y_train, Y_test, batch_size=32, epochs=15)\n",
|
||||||
|
"fit_model, score, probs, history = fit_model_FT2(model, batch_size=32, epochs=10)\n",
|
||||||
|
"model.save(datapath + '/model3_30.h5')\n",
|
||||||
|
"\n"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 0,
|
||||||
|
"metadata": {
|
||||||
|
"colab": {},
|
||||||
|
"colab_type": "code",
|
||||||
|
"id": "4DyFi0YJH5iv"
|
||||||
|
},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"probs = model.predict_generator(test_generator, verbose=1)\n",
|
||||||
|
"np.savetxt(datapath + '/probs30.txt', probs)"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {
|
||||||
|
"colab_type": "text",
|
||||||
|
"id": "fB66sNewSaue"
|
||||||
|
},
|
||||||
|
"source": [
|
||||||
|
"After another 10 fine tuning epochs (total = 30 epochs) we have 66, 84, 89 % top 1, 3, 5 hit rate. At this point it may be more helpful to refine the probability based on the location and time of year that the picture is taken. "
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 0,
|
||||||
|
"metadata": {
|
||||||
|
"colab": {},
|
||||||
|
"colab_type": "code",
|
||||||
|
"id": "bjudiCZmKEe3"
|
||||||
|
},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"correct_prediction = 0\n",
|
||||||
|
"correct_top3 = 0\n",
|
||||||
|
"correct_top5 = 0\n",
|
||||||
|
"for ii in range(len(probs)):\n",
|
||||||
|
" P_this = np.argmax(probs[ii])\n",
|
||||||
|
" GT_this = test_generator.labels[ii]\n",
|
||||||
|
" if P_this == GT_this:\n",
|
||||||
|
" correct_prediction += 1\n",
|
||||||
|
" correct_top3 += top3(probs[ii],GT_this)\n",
|
||||||
|
" correct_top5 += top5(probs[ii],GT_this)\n",
|
||||||
|
" if ii % 100 == 26:\n",
|
||||||
|
"# if test_generator.labels[ii] == 10: # Gadwall\n",
|
||||||
|
" #print(\"Prediction: {} ({})\".format(P_this,Birds[int(list(test_generator.class_indices.keys())[list(test_generator.class_indices.values()).index(top3_idx(probs[ii]))])]))\n",
|
||||||
|
" t3, p3 = top3_idx(probs[ii])\n",
|
||||||
|
" print(\"Prediction: {}, {}, or {} ({} ({:.1f} %), {} ({:.1f} %), or {} ({:.1f} %))\".format(t3[0], t3[1], t3[2] ,Birds[int(list(test_generator.class_indices.keys())[list(test_generator.class_indices.values()).index(t3[0])])], p3[0] * 100,\n",
|
||||||
|
" Birds[int(list(test_generator.class_indices.keys())[list(test_generator.class_indices.values()).index(t3[1])])], p3[1] * 100,\n",
|
||||||
|
" Birds[int(list(test_generator.class_indices.keys())[list(test_generator.class_indices.values()).index(t3[2])])], p3[2] * 100))\n",
|
||||||
|
" print(\"Actual: {} ({})\".format(GT_this,Birds[int(list(test_generator.class_indices.keys())[list(test_generator.class_indices.values()).index(GT_this)])]))\n",
|
||||||
|
"# print(\"Prediction: {} \".format(P_this))\n",
|
||||||
|
"# print(\"Actual: {} \".format(GT_this))\n",
|
||||||
|
"# print('data/test/'+test_generator.filenames[ii])\n",
|
||||||
|
" \n",
|
||||||
|
" plt.figure()\n",
|
||||||
|
" image = plt.imread('data/test/'+test_generator.filenames[ii])\n",
|
||||||
|
" plt.imshow(image)\n",
|
||||||
|
" plt.show()\n",
|
||||||
|
"print(correct_prediction, correct_prediction/len(probs))\n",
|
||||||
|
"print(correct_top3, correct_top3/len(probs))\n",
|
||||||
|
"print(correct_top5, correct_top5/len(probs))\n",
|
||||||
|
"print(len(probs))"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {
|
||||||
|
"colab_type": "text",
|
||||||
|
"id": "RlxJGKb8TNYY"
|
||||||
|
},
|
||||||
|
"source": [
|
||||||
|
"Using my photos to test."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 0,
|
||||||
|
"metadata": {
|
||||||
|
"colab": {},
|
||||||
|
"colab_type": "code",
|
||||||
|
"id": "TRgQdjw7APzO"
|
||||||
|
},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"Darren_test_generator = test_datagen.flow_from_directory(\n",
|
||||||
|
" #directory=datapath + '/data/test/',\n",
|
||||||
|
" directory='/content/Darren_test/',\n",
|
||||||
|
" shuffle=False,\n",
|
||||||
|
" #classes=list(Bird_list),\n",
|
||||||
|
" target_size=(224, 224),\n",
|
||||||
|
" batch_size=32,\n",
|
||||||
|
" class_mode='categorical')"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 0,
|
||||||
|
"metadata": {
|
||||||
|
"colab": {},
|
||||||
|
"colab_type": "code",
|
||||||
|
"id": "FbuTUb_6AaGy"
|
||||||
|
},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"Darren_probs = model.predict_generator(Darren_test_generator, verbose=1)"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 0,
|
||||||
|
"metadata": {
|
||||||
|
"colab": {},
|
||||||
|
"colab_type": "code",
|
||||||
|
"id": "bf_PABndAb7s"
|
||||||
|
},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"correct_prediction = 0\n",
|
||||||
|
"correct_top3 = 0\n",
|
||||||
|
"correct_top5 = 0\n",
|
||||||
|
"for ii in range(len(Darren_probs)):\n",
|
||||||
|
"# for ii in [0]:\n",
|
||||||
|
" P_this = np.argmax(Darren_probs[ii])\n",
|
||||||
|
" GT_this = test_generator.class_indices[list(Darren_test_generator.class_indices.keys())[Darren_test_generator.labels[ii]]]\n",
|
||||||
|
" if P_this == GT_this:\n",
|
||||||
|
" correct_prediction += 1\n",
|
||||||
|
" correct_top3 += top3(Darren_probs[ii],GT_this)\n",
|
||||||
|
" correct_top5 += top5(Darren_probs[ii],GT_this)\n",
|
||||||
|
"# if ii % 100 == 26:\n",
|
||||||
|
"# if test_generator.labels[ii] == 10: # Gadwall\n",
|
||||||
|
" #print(\"Prediction: {} ({})\".format(P_this,Birds[int(list(test_generator.class_indices.keys())[list(test_generator.class_indices.values()).index(top3_idx(probs[ii]))])]))\n",
|
||||||
|
" t3, p3 = top3_idx(Darren_probs[ii])\n",
|
||||||
|
" print(\"Prediction: {}, {}, or {} ({} ({:.1f} %), {} ({:.1f} %), or {} ({:.1f} %))\".format(\n",
|
||||||
|
" t3[0], t3[1], t3[2] ,Birds[int(list(test_generator.class_indices.keys())[list(test_generator.class_indices.values()).index(t3[0])])], p3[0] * 100,\n",
|
||||||
|
" Birds[int(list(test_generator.class_indices.keys())[list(test_generator.class_indices.values()).index(t3[1])])], p3[1] * 100,\n",
|
||||||
|
" Birds[int(list(test_generator.class_indices.keys())[list(test_generator.class_indices.values()).index(t3[2])])], p3[2] * 100))\n",
|
||||||
|
" print(\"Actual: {} ({})\".format(GT_this,Birds[int(list(test_generator.class_indices.keys())[list(test_generator.class_indices.values()).index(GT_this)])]))\n",
|
||||||
|
"# print(\"Prediction: {} \".format(P_this))\n",
|
||||||
|
"# print(\"Actual: {} \".format(GT_this))\n",
|
||||||
|
"# print('data/test/'+test_generator.filenames[ii])\n",
|
||||||
|
" \n",
|
||||||
|
" plt.figure()\n",
|
||||||
|
" image = plt.imread('Darren_test/'+Darren_test_generator.filenames[ii])\n",
|
||||||
|
" plt.imshow(image)\n",
|
||||||
|
" plt.show()\n",
|
||||||
|
"print(correct_prediction, correct_prediction/len(Darren_probs))\n",
|
||||||
|
"print(correct_top3, correct_top3/len(Darren_probs))\n",
|
||||||
|
"print(correct_top5, correct_top5/len(Darren_probs))\n",
|
||||||
|
"print(len(Darren_probs))"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {
|
||||||
|
"colab_type": "text",
|
||||||
|
"id": "Yg-w5GA6TIZy"
|
||||||
|
},
|
||||||
|
"source": [
|
||||||
|
"Below are scratch codes."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 0,
|
||||||
|
"metadata": {
|
||||||
|
"colab": {},
|
||||||
|
"colab_type": "code",
|
||||||
|
"id": "h_6UTR_-hBIs"
|
||||||
|
},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"#Birds\n",
|
||||||
|
"class_indices_inv_map = {v: k for k, v in test_generator.class_indices.items()} \n",
|
||||||
|
"\n",
|
||||||
|
"import pickle\n",
|
||||||
|
"\n",
|
||||||
|
"# write python dict to a file\n",
|
||||||
|
"output = open(datapath+'/class_indices_inv_map.pkl', 'wb')\n",
|
||||||
|
"pickle.dump(class_indices_inv_map, output)\n",
|
||||||
|
"output.close()\n",
|
||||||
|
"output = open(datapath+'/Birds.pkl', 'wb')\n",
|
||||||
|
"pickle.dump(Birds, output)\n",
|
||||||
|
"output.close()"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"metadata": {
|
||||||
|
"accelerator": "GPU",
|
||||||
|
"colab": {
|
||||||
|
"collapsed_sections": [],
|
||||||
|
"name": "Bird_ID_404_species_CNN_TL_clean.ipynb",
|
||||||
|
"provenance": [],
|
||||||
|
"version": "0.3.2"
|
||||||
|
},
|
||||||
|
"kernelspec": {
|
||||||
|
"display_name": "Python 3",
|
||||||
|
"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.8.5"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nbformat": 4,
|
||||||
|
"nbformat_minor": 1
|
||||||
|
}
|
467
src/TensorBirdId.ipynb
Normal file
467
src/TensorBirdId.ipynb
Normal file
File diff suppressed because one or more lines are too long
14
src/resize_img.sh
Executable file
14
src/resize_img.sh
Executable file
@ -0,0 +1,14 @@
|
|||||||
|
# !/bin/bash
|
||||||
|
|
||||||
|
FOLDER="/home/ortion/Documents/projects/TensorBird/data/species_dataset/"
|
||||||
|
|
||||||
|
cd $FOLDER
|
||||||
|
N_FILES=`ls -ApR | grep -v /$ | wc -l`
|
||||||
|
i=0
|
||||||
|
for PHOTO in */*/*.jpg
|
||||||
|
do
|
||||||
|
i=$(($i+1))
|
||||||
|
BASE=`basename $PHOTO`
|
||||||
|
echo "convert $BASE $i/$N_FILES"
|
||||||
|
convert "$PHOTO" -resize 100x75 $PHOTO
|
||||||
|
done
|
0
src/run_tf_lite_classify_bird_pict.py
Normal file
0
src/run_tf_lite_classify_bird_pict.py
Normal file
Loading…
Reference in New Issue
Block a user