{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.7.6","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"gpu","dataSources":[{"sourceId":5441,"databundleVersionId":38425,"sourceType":"competition"},{"sourceId":1293219,"sourceType":"datasetVersion","datasetId":747201}],"dockerImageVersionId":29963,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# Intro #\nRefer to the famous Dogs and Cats classification problem. Goal is simple: we need to teach machine distinguish dogs from cats. In this notebook we will try to address it by using neural networks.\n\n**General plan**:  \n1.Explore dataset, make some preprocessing if need.   \n2.Choose two different neural network types, implement and train it on validation and train data.  \n3.Make predictions on test data.  \n4.Outline conclusions.\n\n**Why neural networks?**  \nThey have proven themselves in practice of real-word problem solving and competitions, in particular in\ncomputer vision problem. Thus, Сonvolution Neural Networks (CNN) perfectly proved themselves especially in matters of computer vision. Many CNN architectures were specially designed for that purpose. An overview of CNN concepts, their architectures and implementations is beyond the scope of this article. We will choose two of them, give short overview and describe in detail their implementation and training. The rationale for their choice is given in the Machining Learning section.\n\n**Some comments**  \nWe have reviewed many laptops on this topic, the authors of which have done a great job, for which many thanks can be given to them. But unfortunately, many authors paid little attention to the comments of their actions, and also did not highlight such subtleties as loading datasets, unzipping them, connecting external weights. In the process of this work, we were faced with many nuances and glitches in these \"auxiliary\", but inevitable issues. Therefore, we tried to comment on almost every action, in particular, on \"auxiliary\" issues. So some comments with direct links to Stack Overflow may be found in text.","metadata":{}},{"cell_type":"markdown","source":"# Import libraries and tools #","metadata":{}},{"cell_type":"code","source":"# Import libraries and tools\n# Data preprocessing and linear algebra\nimport os, re, random\nimport pandas as pd\nimport numpy as np\nimport zipfile\nnp.random.seed(2)\n\n# Visualisation\nimport matplotlib.pyplot as plt\nimport matplotlib.image as mpimg\nimport seaborn as sns\n%matplotlib inline\n\n# Tools for cross-validation, error calculation\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.metrics import confusion_matrix\nimport itertools\nfrom keras.utils.np_utils import to_categorical\n\n# Machine Learning\nfrom keras.models import Sequential\nfrom keras import layers\nfrom keras.layers import Dense, Dropout, Flatten, Conv2D, MaxPool2D\nfrom keras.layers import MaxPooling2D, GlobalMaxPooling2D, Activation\nfrom keras.optimizers import RMSprop\nfrom keras.preprocessing.image import ImageDataGenerator, load_img\nfrom keras import optimizers\n# from keras.callbacks import ReduceLROnPlateau, EarlyStopping\nfrom tensorflow.keras.callbacks import EarlyStopping, ReduceLROnPlateau\nfrom keras.models import Model\nfrom keras.applications.resnet50 import ResNet50","metadata":{"execution":{"iopub.status.busy":"2024-04-17T01:57:45.9936Z","iopub.execute_input":"2024-04-17T01:57:45.993964Z","iopub.status.idle":"2024-04-17T01:57:46.802332Z","shell.execute_reply.started":"2024-04-17T01:57:45.993923Z","shell.execute_reply":"2024-04-17T01:57:46.801343Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"First, lets outline our goal. \"Our goal is to correctly distinguish dogs from cats.\"","metadata":{}},{"cell_type":"markdown","source":"# Data load #","metadata":{}},{"cell_type":"markdown","source":"### Load and unzip data ###","metadata":{}},{"cell_type":"markdown","source":"Since we created notebook from \"Dogs vs Cats\" page, data will load automatically and may be found in /input directory after session starts.","metadata":{}},{"cell_type":"code","source":"# Save datasets path\nPATH = \"/kaggle/input/dogs-vs-cats-redux-kernels-edition\"\nPATH_TRAIN = \"train_images/\"\nPATH_TEST = \"test_images/\"","metadata":{"execution":{"iopub.status.busy":"2024-04-17T01:57:52.290552Z","iopub.execute_input":"2024-04-17T01:57:52.290954Z","iopub.status.idle":"2024-04-17T01:57:52.294695Z","shell.execute_reply.started":"2024-04-17T01:57:52.290905Z","shell.execute_reply":"2024-04-17T01:57:52.293788Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Check datasets in file system\nos.listdir(PATH)","metadata":{"execution":{"iopub.status.busy":"2024-04-17T01:57:56.043744Z","iopub.execute_input":"2024-04-17T01:57:56.044108Z","iopub.status.idle":"2024-04-17T01:57:56.051745Z","shell.execute_reply.started":"2024-04-17T01:57:56.044074Z","shell.execute_reply":"2024-04-17T01:57:56.050838Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Save archives paths and names\ntrain_image_path = os.path.join(PATH, \"train.zip\")\ntest_image_path = os.path.join(PATH, \"test.zip\")","metadata":{"execution":{"iopub.status.busy":"2024-04-17T01:57:59.323673Z","iopub.execute_input":"2024-04-17T01:57:59.324023Z","iopub.status.idle":"2024-04-17T01:57:59.328502Z","shell.execute_reply.started":"2024-04-17T01:57:59.323993Z","shell.execute_reply":"2024-04-17T01:57:59.327565Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Create subfolder for train dataset\n# Disclaimer. It is need because ImageDataGenerator() which we will use later correctly reads images only from subfolders\nos.mkdir('/kaggle/working/train_images')","metadata":{"execution":{"iopub.status.busy":"2024-04-17T01:58:07.079266Z","iopub.execute_input":"2024-04-17T01:58:07.079608Z","iopub.status.idle":"2024-04-17T01:58:07.083652Z","shell.execute_reply.started":"2024-04-17T01:58:07.079578Z","shell.execute_reply":"2024-04-17T01:58:07.082587Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Create subfolder for test dataset\nos.mkdir('/kaggle/working/test_images')","metadata":{"execution":{"iopub.status.busy":"2024-04-17T01:58:10.343817Z","iopub.execute_input":"2024-04-17T01:58:10.344206Z","iopub.status.idle":"2024-04-17T01:58:10.348239Z","shell.execute_reply.started":"2024-04-17T01:58:10.344173Z","shell.execute_reply":"2024-04-17T01:58:10.347386Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Unzip train dataset\narchive = zipfile.ZipFile(train_image_path,\"r\")\nfor file in archive.namelist():\n        archive.extract(file, 'train_images/')","metadata":{"execution":{"iopub.status.busy":"2024-04-17T01:58:13.032014Z","iopub.execute_input":"2024-04-17T01:58:13.032369Z","iopub.status.idle":"2024-04-17T01:58:27.321756Z","shell.execute_reply.started":"2024-04-17T01:58:13.03234Z","shell.execute_reply":"2024-04-17T01:58:27.321047Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Unzip test dataset\narchive = zipfile.ZipFile(test_image_path,\"r\")\nfor file in archive.namelist():\n        archive.extract(file, 'test_images/')","metadata":{"execution":{"iopub.status.busy":"2024-04-17T01:58:27.323659Z","iopub.execute_input":"2024-04-17T01:58:27.323933Z","iopub.status.idle":"2024-04-17T01:58:34.388849Z","shell.execute_reply.started":"2024-04-17T01:58:27.323906Z","shell.execute_reply":"2024-04-17T01:58:34.388131Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Data exploration #","metadata":{}},{"cell_type":"markdown","source":"### Save data to NumPy and Pandas arrays ###","metadata":{}},{"cell_type":"markdown","source":"We begin with some small preparations. We should extract our images filemames and labels. They will be used in model training.  \n**Note**. For now we will not work with test data in order to prevent mistakenly using it instead of validation.\nAs we know, test data must be shown to algorhytm only once - at final prediction. So, we will work on test subset at pre-final - prediction step.","metadata":{}},{"cell_type":"code","source":"# Save images names to variable\ntrain_images = os.listdir(f'{PATH_TRAIN}/train/')","metadata":{"execution":{"iopub.status.busy":"2024-04-17T01:58:34.390107Z","iopub.execute_input":"2024-04-17T01:58:34.390425Z","iopub.status.idle":"2024-04-17T01:58:34.411066Z","shell.execute_reply.started":"2024-04-17T01:58:34.390395Z","shell.execute_reply":"2024-04-17T01:58:34.410421Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Then extract images names and save them into Numpy array\nimagenames = np.array([f'{f}' for f in train_images])","metadata":{"execution":{"iopub.status.busy":"2024-04-17T01:58:34.412188Z","iopub.execute_input":"2024-04-17T01:58:34.412488Z","iopub.status.idle":"2024-04-17T01:58:34.424451Z","shell.execute_reply.started":"2024-04-17T01:58:34.412459Z","shell.execute_reply":"2024-04-17T01:58:34.42376Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Check our image names array\nimagenames","metadata":{"execution":{"iopub.status.busy":"2024-04-17T01:58:34.42661Z","iopub.execute_input":"2024-04-17T01:58:34.426886Z","iopub.status.idle":"2024-04-17T01:58:34.434835Z","shell.execute_reply.started":"2024-04-17T01:58:34.426858Z","shell.execute_reply":"2024-04-17T01:58:34.434174Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Assign labels to images according to competitions task (0-cat, 1-dog)\n# Implement array of image categories\ncategories = []\nfor imagename in imagenames:\n    # Loop through data and split our images names\n    split_category = imagename.split('.')[0]\n    # Assign labels\n    if split_category == 'cat':\n        categories.append(str(0))\n    else:\n        categories.append(str(1))","metadata":{"execution":{"iopub.status.busy":"2024-04-17T01:58:34.436552Z","iopub.execute_input":"2024-04-17T01:58:34.436912Z","iopub.status.idle":"2024-04-17T01:58:34.478474Z","shell.execute_reply.started":"2024-04-17T01:58:34.436874Z","shell.execute_reply":"2024-04-17T01:58:34.477735Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Save our filenames \nanimals = pd.DataFrame({\n    'Image name': imagenames,\n    'Category': categories\n})\nanimals.head(5)","metadata":{"execution":{"iopub.status.busy":"2024-04-17T01:58:36.648843Z","iopub.execute_input":"2024-04-17T01:58:36.649242Z","iopub.status.idle":"2024-04-17T01:58:36.675845Z","shell.execute_reply.started":"2024-04-17T01:58:36.649206Z","shell.execute_reply":"2024-04-17T01:58:36.674951Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Check total amount of 0 and 1 labels\nanimals['Category'].value_counts()","metadata":{"execution":{"iopub.status.busy":"2024-04-17T01:58:44.777774Z","iopub.execute_input":"2024-04-17T01:58:44.778123Z","iopub.status.idle":"2024-04-17T01:58:44.795405Z","shell.execute_reply.started":"2024-04-17T01:58:44.778094Z","shell.execute_reply":"2024-04-17T01:58:44.794639Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"As we see, our tasks initial 12500 images dataset is balanced: both 12500 dogs and cats. Good.  \nOk. Now we can take a look at one little cute kitten.","metadata":{}},{"cell_type":"code","source":"# Draw a cat\n# Don't forget to install 'pillow' module (conda install pillow) to give a 'pyplot' ability of working with '.jpg'\nimg = plt.imread(f'{PATH_TRAIN}/train/{imagenames[1]}')\nplt.imshow(img);","metadata":{"execution":{"iopub.status.busy":"2024-04-17T01:58:54.198863Z","iopub.execute_input":"2024-04-17T01:58:54.199325Z","iopub.status.idle":"2024-04-17T01:58:54.530818Z","shell.execute_reply.started":"2024-04-17T01:58:54.199276Z","shell.execute_reply":"2024-04-17T01:58:54.530034Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Isn't it pretty? Our efforts were not in vain. Move on.","metadata":{}},{"cell_type":"markdown","source":"### Split data on train and validation subsets ###","metadata":{}},{"cell_type":"code","source":"# Split data on train and validation subsets\n# Using 10% or 20% from train data is classical approach\nX_train, X_val = train_test_split(animals, test_size=0.2,  random_state=2)\nX_train = X_train.reset_index()\nX_val = X_val.reset_index()\n\n# We may want use only 1800 images because of CPU computational reasons. If so, this code should be run\n# X_train = X_train.sample(n=1800).reset_index()\n# X_val = X_val.sample(n=100).reset_index()","metadata":{"execution":{"iopub.status.busy":"2024-04-17T01:58:57.856765Z","iopub.execute_input":"2024-04-17T01:58:57.857107Z","iopub.status.idle":"2024-04-17T01:58:57.870176Z","shell.execute_reply.started":"2024-04-17T01:58:57.857077Z","shell.execute_reply":"2024-04-17T01:58:57.869358Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Count amount of rows. Need for two reasons.  \nFirst: will be used in model fit process as parameter devided by batch size.  \nSecond: if we cut 1800-images subset for comp. reasons we should check if there are exact 1800\nimages present.","metadata":{}},{"cell_type":"code","source":"# Count\ntotal_X_train = X_train.shape[0]\ntotal_X_val = X_val.shape[0]","metadata":{"execution":{"iopub.status.busy":"2024-04-17T01:59:01.479846Z","iopub.execute_input":"2024-04-17T01:59:01.480215Z","iopub.status.idle":"2024-04-17T01:59:01.484586Z","shell.execute_reply.started":"2024-04-17T01:59:01.480183Z","shell.execute_reply":"2024-04-17T01:59:01.483661Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"total_X_train","metadata":{"execution":{"iopub.status.busy":"2024-04-17T01:59:05.364455Z","iopub.execute_input":"2024-04-17T01:59:05.364819Z","iopub.status.idle":"2024-04-17T01:59:05.369834Z","shell.execute_reply.started":"2024-04-17T01:59:05.36479Z","shell.execute_reply":"2024-04-17T01:59:05.369021Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"total_X_val","metadata":{"execution":{"iopub.status.busy":"2024-04-17T01:59:08.785761Z","iopub.execute_input":"2024-04-17T01:59:08.786107Z","iopub.status.idle":"2024-04-17T01:59:08.792639Z","shell.execute_reply.started":"2024-04-17T01:59:08.786077Z","shell.execute_reply":"2024-04-17T01:59:08.791533Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Define CNN model constants\nepochs = 5\nbatch_size = 16","metadata":{"execution":{"iopub.status.busy":"2024-04-17T01:59:18.226884Z","iopub.execute_input":"2024-04-17T01:59:18.227285Z","iopub.status.idle":"2024-04-17T01:59:18.23164Z","shell.execute_reply.started":"2024-04-17T01:59:18.227249Z","shell.execute_reply":"2024-04-17T01:59:18.230599Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Callbacks ###","metadata":{}},{"cell_type":"markdown","source":"Before we start teaching our model we should care about avoiding of model overfitting. In general, such techniques are known as **Callbacks**. There are two useful ones: **early stop** and **learning rate reduction**.  \nIf we cut from our 12500 dataset a small 1800 part, we probably will not fall in overfitting,\nbut for general purpose lets take care about it.  \n**Nota Bene**  \nIn Kaggle enviroment we should import EarlyStop and ReduceLROnPlateau from tensorflow.keras.callbacks, not from keras.callbacks, since the last doesn't accepted in model.fit(). What shold we do without StackOverflow?","metadata":{}},{"cell_type":"markdown","source":"#### Early Stop ####\nTo prevent overfitting lets stop model learning after 10 epochs when val_loss value not decreased. Lets use EarlyStopping() method, since it is simple and good working.","metadata":{}},{"cell_type":"code","source":"earlystop = EarlyStopping(patience=10, \n                          verbose=1, \n                          mode='auto'\n                         )","metadata":{"execution":{"iopub.status.busy":"2024-04-17T02:00:08.115579Z","iopub.execute_input":"2024-04-17T02:00:08.115912Z","iopub.status.idle":"2024-04-17T02:00:08.12076Z","shell.execute_reply.started":"2024-04-17T02:00:08.115883Z","shell.execute_reply":"2024-04-17T02:00:08.119622Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"#### Learning Rate Reduction #### \nLets reduce the learning rate when accuracy, for example, not increase for two continuous steps. Use well-known ReduceLROnPlateau() method, whoes library was imported at the first stage. We can use its default parameters.","metadata":{}},{"cell_type":"code","source":"learning_rate_reduction = ReduceLROnPlateau(monitor='val_accuracy', \n                                            patience=2, \n                                            verbose=1, \n                                            factor=0.5, \n                                            min_lr=0.00001\n                                           )","metadata":{"execution":{"iopub.status.busy":"2024-04-17T02:00:14.43542Z","iopub.execute_input":"2024-04-17T02:00:14.435758Z","iopub.status.idle":"2024-04-17T02:00:14.440338Z","shell.execute_reply.started":"2024-04-17T02:00:14.435729Z","shell.execute_reply":"2024-04-17T02:00:14.439336Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Save our callbacks\ncallbacks = [earlystop, learning_rate_reduction]","metadata":{"execution":{"iopub.status.busy":"2024-04-17T02:00:17.339192Z","iopub.execute_input":"2024-04-17T02:00:17.339536Z","iopub.status.idle":"2024-04-17T02:00:17.343044Z","shell.execute_reply.started":"2024-04-17T02:00:17.339505Z","shell.execute_reply":"2024-04-17T02:00:17.342091Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"callbacks","metadata":{"execution":{"iopub.status.busy":"2024-04-17T02:00:19.421786Z","iopub.execute_input":"2024-04-17T02:00:19.422138Z","iopub.status.idle":"2024-04-17T02:00:19.426976Z","shell.execute_reply.started":"2024-04-17T02:00:19.422107Z","shell.execute_reply":"2024-04-17T02:00:19.426162Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Model fit ###","metadata":{}},{"cell_type":"markdown","source":"**Nota Bene**  \nLet us leave a few comments right here at the top of paragraph just before we start our model fit.  \nIf we obtain error like above when call fit_generator() method:\n\"ValueError: Error when checking target: expected block5_pool to have 4 dimensions, but got array with shape (16, 1)\"\nwe can change class_mode in generators implemented before from 'binary' to None.  \n\nAccording to the Keras docs, setting the class_mode to 'binary' will return a 1-D array.  \nBy changing the class_mode to None, no labels are returned and the generator will only yield batches of image data. This is what you are expecting with your model, and this works well with the fit_generator() method.  \nHowever, when using class_mode None, the data still needs to reside in a subdirectory of directory for it to work correctly.  \n\nIf we do make such change, we also should make second thing - define a fixed_generator method (code is in comments below). It fixes known generator issue.  \nBut actually we can avoid this steps if we little tune VGG16 models outputs, as we did before.\n\nGod bless Stackoverflow.","metadata":{}},{"cell_type":"code","source":"# Just leave it here\n# def fixed_generator(generator):\n#     for batch in generator:\n#         yield (batch, batch)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"A few notes about fit_generator() parameters. We pass into it our train DataGenerator, number of epochs, validation DataGenerator and two interesting ones: validation_steps and steps_per_epoch. How to choose them?  \nThere is a traditional approach. Traditionally, the steps per epoch is calculated as train_length // batch_size and validation steps follow same logic for validation data.  \n\nRemember, that an epoch means one iteration over all of the training data. Thus, if we have 10,000 images and a batch size of 100 then the epoch should contain 10,000 / 100 = 100 steps.  \nA training step is one gradient update. In one step batch_size many examples are processed.  \n\nA good article about difference between batch, epoch and step can be found in [12].\n","metadata":{}},{"cell_type":"markdown","source":"## Model 2. ResNet-50 ##","metadata":{}},{"cell_type":"markdown","source":"### Description ###","metadata":{}},{"cell_type":"markdown","source":"ResNet (aka Residual Networks) is a classic neural network used for many computer vision real-world tasks. Was implemented by Kaiming He, Xiangyu Zhang, Shaoqing Ren, Jian Sun [9]. This model won ImageNet challenge in 2015. Scheme of net [10]: ![image.png](attachment:image.png)","metadata":{},"attachments":{"image.png":{"image/png":"iVBORw0KGgoAAAANSUhEUgAABXQAAAEcCAIAAADof6uxAAAgAElEQVR4AexdB3wVVfa+Ly8VCCR0pEjvvYpA6MGAIDWKQbDTo4CuvQI2BCyIqNgQldiQKKIiLGDHssJfRZGErIt1dV1cNrIivv9vuDjv8828l8nMLfOSwy8/Pblz7znf+c6dmXu/zJvHQvSPGCAGiAFigBggBogBYoAYIAaIAWKAGCAGiAG3DBSsf4m5HUvjiAFigBggBogBYoAYIAaIAWKAGCAGiAFigBgIkbhAk4AYIAaIAWKAGCAGiAFigBggBogBYoAYIAY8MUDigif6aDAxQAwQA8QAMUAMEAPEADFADBADxAAxQAyQuEBzgBggBogBYoAYIAaIAWKAGCAGiAFigBggBjwxQOKCJ/poMDFADBADxAAxQAwQA8QAMUAMEAPEADFADJC4QHOAGCAGiAFigBggBogBYoAYIAaIAWKAGCAGPDFA4oIn+mgwMUAMEAPEADFADBADxAAxQAwQA8QAMUAMkLhAc4AYIAaIAWKAGCAGiAFigBggBogBYoAYIAY8MUDigif6aDAxQAwQA8QAMUAMEAPEADFADBADxAAxQAyQuEBzgBggBogBYoAYIAaIAWKAGCAGiAFigBggBjwxQOKCJ/poMDFADBADxAAxQAwQA8QAMUAMEAPEADFADJC4QHOAGCAGiAFigBggBogBYoAYIAaIAWKAGCAGPDFA4oIn+mgwMUAMEAPEADFADBADxAAxQAwQA8QAMUAMkLhAc4AYIAaIAWKAGCAGiAFigBggBogBYoAYIAY8MUDigif6aDAxQAwQA8QAMUAMEAPEADFADBADxAAxQAyQuEBzgBggBogBYoAYIAaIAWKAGCAGiAFigBggBjwxQOKCJ/poMDFADBADxAAxQAwQA8QAMUAMEAPEADFADJC4QHOAGCAGiAFigBggBogBYoAYIAaIAWKAGCAGPDFA4oIn+mgwMaCLgfvuu2/QoEG6olNcYsAJA3//+9/nzZs3ZMiQ9u3bjx07dunSpf/73/+cDKQ+cc3Ab7/99sgjj2RnZ3fo0KFTp07jxo174YUX4jojAu+agWeeeSY7O/uf//ynaw80MF4YmDNnTrbdv6+++ipeUiCcxAAx4J0BEhe8c0geKhQDM2bMyMvL83lKR48e7dWrV5s2bXyOk+DJZsDP0/Xpp59OT0/v0qXL4sWLH3jggQsvvDA5OblNmzbffvutbFoqg3/flv7IkSMDBgxISkqaMWPG6tWr77777lNPPTUQCMyZM6cy1EVNjr6tfkT6f//732vUqMEYO3DgQMQh+tUdA34ufWZm5siRI2+0/Pvxxx/dJUujiAFiIB4ZIHEhHqtGmCUycOaZZ44aNUpiAM+uS0pK8vLyGGMkLnjmMu4d+Ha6fvXVV9WrVx87duzhw4dNlnfu3JmcnDx+/HizhQzXDPi29Nddd11SUtI777yDqS1btowx9uabb2Ij2a4Z8G31MaOjR48OGjSoUaNGJC4gLR5t35b+u+++Y4y99NJLHhOk4cQAMRDvDJC4EO8VJPyCGfDtnTsUCi1YsKBx48bsj38kLgiufRy68+10veKKK9LS0r7++usIUi+44IJgMPjLL79EtNOv5WXAt6Vv2bLl+eefH5HO4cOHk5OTb7311oh2+tUdA76tPqazZMmSpk2brl69msQFpMWj7dvSb9++nTFGn4DwWF8aTgxUAAZIXKgARaQUysHAvn37pkyZ0qJFi2rVqrVu3Xr69OnFxcV8/Icffjhx4sTGjRs3aNBg4sSJ06dPN/3++OOPN9xwQ5cuXTIyMurUqdOvX781a9aYR03j22+/zc/PP/nkk2vUqNG6deurrrrq559/fvfddydOnPjrr7+a3UKh0N/+9rezzz67Xbt2derUGTZs2D333INHo9lFRUUf/vFvwoQJJC5EI6rCtMfvdB01alTPnj2thbj77rsZY3v27LEeohZkIE5L/+uvvw4fPnzDhg2YSygUOnr0aHp6+pIlSyLa6VdbBuK0+pjLrl270tLStm3b9tRTT5G4gMzEtuO39Pfdd1+dOnViZ0dHiQFioDIwQOJCZagy5XicgS+//LJWrVqdO3devHhxYWHhlVde2bZt2/r163/55ZehUKioqGjJkiXdunVr167dkiVLVq1axYf99NNP7du3b9OmzYoVKzZv3rxhw4aLL744MTHxtttuQ2Y/+OCDhg0b1q1bd/HixRs3bly1alV2dnarVq1WrVrFGMM/1T7++ONpaWmnnXbaww8/XFhYePXVV6enp48dO/bIkSPoMLY9ffp0EhdiUxTvR+N6ur722mu2z8BfdNFF9ORCmTMzrktvm92bb77JGPvggw9sj1IjMlABqn/48OFOnTpdcskl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86mnnjp48GBpaWlhYeHw4cOrVq1qfneXCSaGQeJCDHIqxqH4na779u1jjC1duvSdKP8iBL6KUS+BWcRv6UOh0OzZs1NSUq677jr+/s5Dhw6tX7++WbNmtWrVivbgtEDqKoCruK6+lX8SF6ycRGuJ69LPmjUrISFh+vTpmzZtOnz48MGDBx977LGMjIysrKyIP7pES5/aiQFioGIwQOJCxagjZeGUgY0bNzZp0oQxlpKSkpycnJqaeu655+I3U3744YdpaWnVqlWrXr06d7p9+/ZWrVoxxjIyMgKBQOPGjQsKCg4fPnziiScyxhYsWGDG3r59e4sWLRhjVapUCQQCrVu33rFjx+rVq9PS0sw+oVCotLT0vPPOS01NDQQC/Fsnunfv/vbbb2OfMm0SF8qkqAJ0iNPpunXr1mgfuubt//rXvypAdaSmEKel59e3q6++ukaNGoyx9PT0QCCQkJAwZsyYAwcOSGWsIjmP3+pbq0DigpWTGC3xW/rffvtt0aJF9evXZ4zx5U0wGJw3b575B5gYWdMhYoAYqEgMkLhQkapJuThi4Lfffvvss89efvnl999/P+I1jXz8oUOHXnvttc8++8x099tvv+3atevVV181X80QCoUOHz68d+9e66eLv/322y1btpifs7jkkktatGhhujKNI0eO7Nq1a8uWLV9++SV9DtmkhYwIBmi6RhBSeX6N69KXlpbu2bNny5Ytb7311n//+9/KUzVRmcZ19UWRUDn9xHXpf/311z179rz22mvvvPMOnfiVcwJT1sQAiQs0B4gBAQx8/PHHs2fPjng1QygUOnr0aIsWLc455xwBMcgFMSCIAZqugoiMPzdU+virmTjEVH1xXMaZJyp9nBWM4BID8cwAiQvxXD3C7hsG/vWvf2VmZk6ePBk/TH706NFp06Yxxnbv3u0bpASEGAjRdK20k4BKX2lLHwrRiV95i08nfuWtPWVODChngMQF5ZRTwArKwObNm2vVqtWhQ4dLL730pptuysvLa968edWqVZ988skKmjGlFccM0HSN4+J5g06l98ZffI+m6sd3/Tygp9J7II+GEgPEQDkYIHGhHGRRV2IgNgP//ve/ly5des455wwdOvT888+/88479+7dG3sIHSUGdDFA01UX89rjUum1l0AjAKq+RvL1hqbS6+WfohMDlYQBEhcqSaEpTWKAGCAG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"}}},{"cell_type":"markdown","source":"### Implementation ###","metadata":{}},{"cell_type":"markdown","source":"We will again use pre-trained network, staying at transfer learning paradigm.\nOur steps. Initialize the ResNet-50 model, add an additional last Dense-layer, with softmax activation function and set the first layer of the model to be not trainable, since our model is pre-trained.  \n\nLets denote a few things about model constants.  \nImage size is equal 224 as it was in VGG16 model, number of epochs due to computtional reasons let equal to 5; number of classes is equal to 2, it is self-descriptive; let batch size here be equal to 64.\n\nDownload pre-trained weights from Resnet-50 officical datasource on Kaggle [11]. Notice that there are two pre-trained weights files:  \na) ..._tf_kernels.h5;  \nb) ..._tf_kernels_NOTOP.h5.  \n\nWhat are they?   \nThe _tf_kernels.h5 weights is useful for 'pure' prediction of test image and this prediction will rely completely on ResNet-50 pre-trained weights, it does not expected any training from our side.  \n\nSince we use a Transfer Learning paradigm, we should use models pre-trained weights except its TOP layer, so we will use second (aka notop) weights as initial weight for training new layer using train images.","metadata":{}},{"cell_type":"code","source":"# Define model constants\n# image_size = 224 like in previous model\nnum_classes = 2\nnum_epochs = 5\nnum_batch_size = 64\nWEIGHTS_PATH = \"../input/resnet-weights-uploaded/resnet50_weights_tf_dim_ordering_tf_kernels_notop.h5\"","metadata":{"execution":{"iopub.status.busy":"2024-04-17T02:00:27.372832Z","iopub.execute_input":"2024-04-17T02:00:27.373192Z","iopub.status.idle":"2024-04-17T02:00:27.377185Z","shell.execute_reply.started":"2024-04-17T02:00:27.37316Z","shell.execute_reply":"2024-04-17T02:00:27.376278Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**Nota Bene**  \nPay attention on weights path. It is manually downloaded from ResNet's Keras Dataset [11] and then manually uploaded into /input directory. First we tryed the most logical way - to attach weights from [11] butdoing so will not work in model definition because of defect mensioned here: https://www.kaggle.com/learn-forum/124381 and https://stackoverflow.com/questions/60119041/failed-to-load-keras-resnet50-model-offline-using-weight-file. So there was nothing better for us than to save the files manually, taking into account the fact that they should be saved forever, since we will need many times (download every time from Imagenet external source seems traffic-wasting unefficiant way). Don't know why, but it worked for one time, so we will skip it and use weights from Imagenet like we did in first model.","metadata":{}},{"cell_type":"code","source":"# Define model\nmodel_resnet = Sequential()\n# Add pre-trained weights\nmodel_resnet.add(ResNet50(include_top=False, pooling='max', weights='imagenet'))\n# The last dense layer must specify the number of labels (or classes) and activation f-n\nmodel_resnet.add(Dense(num_classes, activation='softmax'))\n# Since we load pre-trained model we must specify first layer as non-trainable\nmodel_resnet.layers[0].trainable = True","metadata":{"execution":{"iopub.status.busy":"2024-04-17T02:00:46.145066Z","iopub.execute_input":"2024-04-17T02:00:46.145395Z","iopub.status.idle":"2024-04-17T02:00:54.520206Z","shell.execute_reply.started":"2024-04-17T02:00:46.145368Z","shell.execute_reply":"2024-04-17T02:00:54.519447Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Compile model\nmodel_resnet.compile(\n    optimizer='sgd', \n    loss='categorical_crossentropy', \n    metrics=['accuracy']\n)","metadata":{"execution":{"iopub.status.busy":"2024-04-17T02:01:08.695918Z","iopub.execute_input":"2024-04-17T02:01:08.69643Z","iopub.status.idle":"2024-04-17T02:01:08.722168Z","shell.execute_reply.started":"2024-04-17T02:01:08.696387Z","shell.execute_reply":"2024-04-17T02:01:08.721042Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Print models summary\nmodel_resnet.summary()","metadata":{"execution":{"iopub.status.busy":"2024-04-17T02:01:11.861633Z","iopub.execute_input":"2024-04-17T02:01:11.862014Z","iopub.status.idle":"2024-04-17T02:01:11.893997Z","shell.execute_reply.started":"2024-04-17T02:01:11.861978Z","shell.execute_reply":"2024-04-17T02:01:11.892786Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Train model ###","metadata":{}},{"cell_type":"code","source":"# Before we begin lets save our train and validation subsets into threir copies\nX_train_resnet = X_train\nX_val_resnet = X_val\nY_val_resnet = X_val['Category']\nY_train_resnet = animals['Category']","metadata":{"execution":{"iopub.status.busy":"2024-04-17T02:02:18.6277Z","iopub.execute_input":"2024-04-17T02:02:18.628062Z","iopub.status.idle":"2024-04-17T02:02:18.632926Z","shell.execute_reply.started":"2024-04-17T02:02:18.62803Z","shell.execute_reply":"2024-04-17T02:02:18.632057Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"total_X_train_resnet = X_train_resnet.shape[0]\ntotal_X_val_resnet = X_val_resnet.shape[0]","metadata":{"execution":{"iopub.status.busy":"2024-04-17T02:02:23.242977Z","iopub.execute_input":"2024-04-17T02:02:23.243313Z","iopub.status.idle":"2024-04-17T02:02:23.248211Z","shell.execute_reply.started":"2024-04-17T02:02:23.243284Z","shell.execute_reply":"2024-04-17T02:02:23.24702Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"X_train_resnet.head()","metadata":{"execution":{"iopub.status.busy":"2024-04-17T02:02:26.151347Z","iopub.execute_input":"2024-04-17T02:02:26.151687Z","iopub.status.idle":"2024-04-17T02:02:26.162539Z","shell.execute_reply.started":"2024-04-17T02:02:26.151657Z","shell.execute_reply":"2024-04-17T02:02:26.161675Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"total_X_train_resnet","metadata":{"execution":{"iopub.status.busy":"2024-04-17T02:02:30.44074Z","iopub.execute_input":"2024-04-17T02:02:30.441112Z","iopub.status.idle":"2024-04-17T02:02:30.446593Z","shell.execute_reply.started":"2024-04-17T02:02:30.441077Z","shell.execute_reply":"2024-04-17T02:02:30.44582Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"X_train_resnet.shape","metadata":{"execution":{"iopub.status.busy":"2024-04-17T02:02:32.770483Z","iopub.execute_input":"2024-04-17T02:02:32.770818Z","iopub.status.idle":"2024-04-17T02:02:32.776343Z","shell.execute_reply.started":"2024-04-17T02:02:32.770788Z","shell.execute_reply":"2024-04-17T02:02:32.775506Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"X_val_resnet.shape","metadata":{"execution":{"iopub.status.busy":"2024-04-17T02:02:35.21269Z","iopub.execute_input":"2024-04-17T02:02:35.213049Z","iopub.status.idle":"2024-04-17T02:02:35.218099Z","shell.execute_reply.started":"2024-04-17T02:02:35.213014Z","shell.execute_reply":"2024-04-17T02:02:35.217273Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Train DataGenereator (for ResNet) ###","metadata":{}},{"cell_type":"markdown","source":"For model building clarity, lets repeat the process with image generation instead of using from previous step. It is quick. Omit comments, since actions are identical to the previous paragraph.","metadata":{}},{"cell_type":"code","source":"train_resnet_datagen = ImageDataGenerator(\n    rescale=1./255,\n)","metadata":{"execution":{"iopub.status.busy":"2024-04-17T02:02:42.217133Z","iopub.execute_input":"2024-04-17T02:02:42.21749Z","iopub.status.idle":"2024-04-17T02:02:42.22201Z","shell.execute_reply.started":"2024-04-17T02:02:42.217453Z","shell.execute_reply":"2024-04-17T02:02:42.220957Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_resnet_generator = train_resnet_datagen.flow_from_dataframe(\n    X_train_resnet,\n    \"/kaggle/working/train_images/train\",\n    x_col='Image name',\n    y_col='Category',\n    class_mode='categorical',\n    target_size=(224, 224),\n    batch_size=num_batch_size\n)","metadata":{"execution":{"iopub.status.busy":"2024-04-17T02:02:53.326593Z","iopub.execute_input":"2024-04-17T02:02:53.326907Z","iopub.status.idle":"2024-04-17T02:02:53.579356Z","shell.execute_reply.started":"2024-04-17T02:02:53.326879Z","shell.execute_reply":"2024-04-17T02:02:53.578389Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Validation DataGenereator (for ResNet) ###","metadata":{}},{"cell_type":"code","source":"validation_resnet_datagen = ImageDataGenerator(\n    rescale=1./255\n)","metadata":{"execution":{"iopub.status.busy":"2024-04-17T02:02:57.386909Z","iopub.execute_input":"2024-04-17T02:02:57.387253Z","iopub.status.idle":"2024-04-17T02:02:57.391717Z","shell.execute_reply.started":"2024-04-17T02:02:57.387222Z","shell.execute_reply":"2024-04-17T02:02:57.390468Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"validation_resnet_generator = validation_resnet_datagen.flow_from_dataframe(\n    X_val_resnet, \n    \"/kaggle/working/train_images/train\", \n    x_col='Image name',\n    y_col='Category',\n    class_mode='categorical',\n    target_size=(224, 224),\n    batch_size=num_batch_size\n)","metadata":{"execution":{"iopub.status.busy":"2024-04-17T02:03:04.929342Z","iopub.execute_input":"2024-04-17T02:03:04.92973Z","iopub.status.idle":"2024-04-17T02:03:05.002346Z","shell.execute_reply.started":"2024-04-17T02:03:04.929694Z","shell.execute_reply":"2024-04-17T02:03:05.001315Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Fit the model\nhistory_resnet = model_resnet.fit_generator(\n        train_resnet_generator,\n        epochs = num_epochs,\n        validation_data = validation_resnet_generator,\n        validation_steps = total_X_val_resnet//num_batch_size,\n        steps_per_epoch = total_X_train_resnet//num_batch_size,\n        callbacks = callbacks\n)","metadata":{"execution":{"iopub.status.busy":"2024-04-17T02:03:08.59122Z","iopub.execute_input":"2024-04-17T02:03:08.591584Z","iopub.status.idle":"2024-04-17T02:05:34.242034Z","shell.execute_reply.started":"2024-04-17T02:03:08.591548Z","shell.execute_reply":"2024-04-17T02:05:34.239902Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Leave this output here to outline that we obtain low accuracy when train on 5 epochs and\n# first layer trainable = False param\n# Epoch 1/5\n# 312/312 [==============================] - 190s 611ms/step - loss: 5.4424 - accuracy: 0.5646 - val_loss: 3.1316 - val_accuracy: 0.6012 - lr: 0.0050\n# Epoch 2/5\n# 312/312 [==============================] - 195s 624ms/step - loss: 5.1490 - accuracy: 0.5693 - val_loss: 5.3533 - val_accuracy: 0.5655 - lr: 0.0050\n# Epoch 3/5\n# 312/312 [==============================] - ETA: 0s - loss: 5.5350 - accuracy: 0.5592\n# Epoch 00003: ReduceLROnPlateau reducing learning rate to 0.0024999999441206455.\n# 312/312 [==============================] - 194s 622ms/step - loss: 5.5350 - accuracy: 0.5592 - val_loss: 5.5042 - val_accuracy: 0.5615 - lr: 0.0050\n# Epoch 4/5\n# 312/312 [==============================] - 193s 617ms/step - loss: 1.8847 - accuracy: 0.6557 - val_loss: 1.7388 - val_accuracy: 0.6354 - lr: 0.0025\n# Epoch 5/5\n# 312/312 [==============================] - 192s 615ms/step - loss: 2.0500 - accuracy: 0.6221 - val_loss: 5.0342 - val_accuracy: 0.5294 - lr: 0.0025","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Save calculated weigthts\nmodel_resnet.save_weights('model_resnet_wieghts.h5')\nmodel_resnet.save('model_resnet_keras.h5')","metadata":{"execution":{"iopub.status.busy":"2024-04-17T02:05:34.243422Z","iopub.status.idle":"2024-04-17T02:05:34.24391Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Visualize accuracy and loss curves ###","metadata":{}},{"cell_type":"code","source":"# Plot accuracy and loss curves\nfig, (ax3, ax4) = plt.subplots(2, 1, figsize=(7, 7))\nhistory_resnet = history\n\nax3.plot(history.history['loss'], color='r', label=\"Train loss\")\nax3.plot(history.history['val_loss'], color='b', label=\"Validation loss\")\nax3.set_xticks(np.arange(1, epochs, 1))\nlegend = ax3.legend(loc='best', shadow=True)\n\nax4.plot(history.history['accuracy'], color='r', label=\"Train accuracy\")\nax4.plot(history.history['val_accuracy'], color='b',label=\"Validation accuracy\")\nax4.set_xticks(np.arange(1, epochs, 1))\nlegend = ax4.legend(loc='best', shadow=True)\n\nplt.tight_layout()\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2024-04-17T02:05:34.245086Z","iopub.status.idle":"2024-04-17T02:05:34.245539Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":" ### Predict on validation data ###","metadata":{}},{"cell_type":"code","source":"# Predict on validation X_val_resnet\nY_pred_resnet =  model_resnet.predict_generator(validation_resnet_generator)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Define treshold\nthreshold = 0.5\n# Convert\nY_pred_conv_res = np.where(Y_pred_resnet > threshold, 1,0)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"Y_pred_conv_res[:,0]","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Visualize prediction on validation data ###","metadata":{}},{"cell_type":"code","source":"# Plot probability histogram\npd.Series(Y_pred_conv_res[:,0]).hist()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Prepare Y_val in str dtype\n# Convert to int\nY_val_resnet_str = Y_val_resnet.astype(int)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Compute and plot the Confusion matrix\nconfusion_mtx_resnet = confusion_matrix(Y_val_resnet_str, Y_pred_conv_res[:,0]) \n\nf,ax = plt.subplots(figsize=(8, 8))\nsns.heatmap(confusion_mtx_resnet, annot=True)\nplt.xlabel(\"Predicted Label\")\nplt.ylabel(\"Validation (aka True) Label\")\nplt.title(\"Confusion Matrix\")\nplt.show()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Test DataGenerator (for ResNet) ###","metadata":{}},{"cell_type":"code","source":"# Add X_test_resnet\nX_test_resnet = X_test","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test_resnet_datagen = ImageDataGenerator(\n    rescale=1./255\n)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test_resnet_generator = test_resnet_datagen.flow_from_dataframe(\n    X_test_resnet, \n    \"/kaggle/working/test_images/test\", \n    x_col='test_imagename',\n    y_col=None,\n    class_mode=None,\n    batch_size=num_batch_size,\n    target_size=(image_size, image_size),\n    shuffle=False\n)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Predict on test data ###","metadata":{}},{"cell_type":"code","source":"predict_resnet = model_resnet.predict_generator(test_resnet_generator, steps=np.ceil(samples/num_batch_size))","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Save submission results (Model - ResNet) ###","metadata":{}},{"cell_type":"code","source":"# Save predictions\nsubmit_resnet = X_test_resnet.copy()\nsubmit_resnet['id'] = submit_resnet['test_imagename'].str.split('.').str[0]\nsubmit_resnet['label'] = submit_resnet['Category']\nsubmit_resnet.drop(['test_imagename', 'Category'], axis=1, inplace=True)\nsubmit_resnet.to_csv('submission_resnet_50.csv', index=False)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Check answer\nplt.figure(figsize=(10,5))\nsns.countplot(submit_resnet['label'])\nplt.title(\"(Final answer on test data (Model - ResNet))\")","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Conclusion #\nEvery great road has great finish. We completed our task of teaching machine how to recognise cats and dogs on pretty photos. We did it twice: using VGG16 and ResNet-50 CNN models. This was in learning purpose. And to be continuous we choosed absolutely different models: one deep and huge in computing and second more complex in structure but less resource-taking.  \nSo what we obtain?  \n1. Model implementation process (as well as data preparation) is very close in both cases. (Remember, we used Transfer learning paradigm - pre-trained models, so we just connected models implementation from Keras library, downloaded pre-trained weights, and specified models few layers, in particular, outputs).\n2. Models gave approximately a similar level of accuracy (ResNet-50 gave better result).  \n3. CPU and memory usage is very sensitive on old-school PC's like ours (with Core i5 from 2010-s and 4 Gb RAM). Our goal was not trying to benchmark since our models are very famous and probably already have many benchmarks. Therefore, the goal was only to become familiar with the capabilities and implementation of models. And what we can denote? Taking into account paragraphs one and two we can conclude that in all else being equal case it is adecuately to use more quick and modern net at least in order to save our time for new discoveries. Its complicity is not big problem if we use transfer learning concept.","metadata":{}},{"cell_type":"markdown","source":"# Literature #","metadata":{}},{"cell_type":"markdown","source":"[1] https://towardsdatascience.com/a-guide-to-an-efficient-way-to-build-neural-network-architectures-part-ii-hyper-parameter-42efca01e5d7  \n[2] https://neurohive.io/en/popular-networks/vgg16/  \n[3] https://medium.com/analytics-vidhya/cnns-architectures-lenet-alexnet-vgg-googlenet-resnet-and-more-666091488df5  \n[4] https://gist.github.com/baraldilorenzo/07d7802847aaad0a35d3  \n[5] https://arxiv.org/abs/1409.1556  \n[6] https://towardsdatascience.com/keras-data-generators-and-how-to-use-them-b69129ed779c  \n[7] https://keras.io/preprocessing/image/  \n[8] https://neurohive.io/en/popular-networks/resnet/  \n[9] https://arxiv.org/abs/1512.03385  \n[10] https://towardsdatascience.com/understanding-and-coding-a-resnet-in-keras-446d7ff84d33  \n[11] https://www.kaggle.com/keras/resnet50/  \n[12] https://machinelearningmastery.com/difference-between-a-batch-and-an-epoch/","metadata":{}},{"cell_type":"code","source":"","metadata":{"trusted":true},"execution_count":null,"outputs":[]}]}