{ "nbformat": 4, "nbformat_minor": 0, "metadata": { "colab": { "name": "larvae21103106.ipynb", "provenance": [], "collapsed_sections": [] }, "kernelspec": { "name": "python3", "display_name": "Python 3" }, "language_info": { "name": "python" } }, "cells": [ { "cell_type": "markdown", "metadata": { "id": "bPHoKmx1SQSM" }, "source": [ "**Larva Classification : Zophobas Morio and Tenebrio Molitor**" ] }, { "cell_type": "markdown", "metadata": { "id": "oayu7BUaSqSs" }, "source": [ "Preparation" ] }, { "cell_type": "code", "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "1HqoZuleSDAl", "outputId": "991b0f8f-f70d-4d06-ac78-761daea7ab96" }, "source": [ "from google.colab import drive\n", "drive.mount('/content/drive')\n", "\n", "# import *\n", "import os\n", "import math\n", "import random\n", "import shutil\n", "\n", "# import as\n", "import numpy as np\n", "import pandas as pd\n", "import matplotlib.pyplot as plt\n", "import seaborn as sn\n", "import tensorflow as tf\n", "\n", "#from import\n", "from tensorflow import keras\n", "from tensorflow.keras import layers\n", "\n", "#directory settings\n", "BASE_DIR = '/content/drive/MyDrive/larva'\n", "names = [ \"Zophobas\",\"Tenebrio\" ]\n", "\n", "#settings for directory of training, validation, and testing\n", "try:\n", " shutil.rmtree(BASE_DIR + '/train')\n", " shutil.rmtree(BASE_DIR + '/val')\n", " shutil.rmtree(BASE_DIR + '/test')\n", "except OSError as e:\n", " print(\"Error From e.strerror: %s\" % (e.strerror))\n", "\n", "tf.random.set_seed(42)\n", "\n", "# Restructure the folder \n", "if not os.path.isdir(BASE_DIR + '/train/'):\n", " for name in names:\n", " os.makedirs(BASE_DIR + '/train/' + name)\n", " os.makedirs(BASE_DIR + '/val/' + name)\n", " os.makedirs(BASE_DIR + '/test/' + name)\n", "\n", "orig_folders = [\"/Zophobas/\",\"/Tenebrio/\" ]\n", "for folder_idx, folder in enumerate(orig_folders):\n", " files = os.listdir(BASE_DIR + folder)\n", " number_of_images = len([name for name in files])\n", " #set the proportion of images, all must equal to 1.0\n", " n_train = 0.6 * number_of_images\n", " n_test = 0.2 * number_of_images\n", " n_valid = 0.2 * number_of_images\n", " print(number_of_images, n_train, n_valid, n_test)\n", " for idx, file in enumerate(files):\n", " file_name = BASE_DIR + folder + file\n", " if idx < n_train:\n", " shutil.copy(file_name, BASE_DIR + \"/train/\" + names[folder_idx])\n", " elif idx < n_train + n_valid:\n", " shutil.copy(file_name, BASE_DIR + \"/val/\" + names[folder_idx])\n", " else:\n", " shutil.copy(file_name, BASE_DIR + \"/test/\" + names[folder_idx])\n", "\n", "vgg_model = tf.keras.applications.vgg19.VGG19()\n", "print(type(vgg_model))\n", "vgg_model.summary()\n", "\n", "\n", "# change to Sequential model\n", "model = keras.models.Sequential()\n", "for layer in vgg_model.layers[0:-1]:\n", " model.add(layer)\n", " \n", " \n", "model.summary()\n", "\n", "# we set trainable=False for all layers, no need retraining\n", "for layer in model.layers:\n", " layer.trainable = False\n", "\n", "# this is classification layer\n", "model.add(layers.Dense(2))\n", "\n", "model.summary()\n", "\n" ], "execution_count": null, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "Mounted at /content/drive\n", "320 192.0 64.0 64.0\n", "320 192.0 64.0 64.0\n", "Downloading data from https://storage.googleapis.com/tensorflow/keras-applications/vgg19/vgg19_weights_tf_dim_ordering_tf_kernels.h5\n", "574717952/574710816 [==============================] - 5s 0us/step\n", "574726144/574710816 [==============================] - 5s 0us/step\n", "\n", "Model: \"vgg19\"\n", "_________________________________________________________________\n", "Layer (type) Output Shape Param # \n", "=================================================================\n", "input_1 (InputLayer) [(None, 224, 224, 3)] 0 \n", "_________________________________________________________________\n", "block1_conv1 (Conv2D) (None, 224, 224, 64) 1792 \n", "_________________________________________________________________\n", "block1_conv2 (Conv2D) (None, 224, 224, 64) 36928 \n", "_________________________________________________________________\n", "block1_pool (MaxPooling2D) (None, 112, 112, 64) 0 \n", "_________________________________________________________________\n", "block2_conv1 (Conv2D) (None, 112, 112, 128) 73856 \n", "_________________________________________________________________\n", "block2_conv2 (Conv2D) (None, 112, 112, 128) 147584 \n", "_________________________________________________________________\n", "block2_pool (MaxPooling2D) (None, 56, 56, 128) 0 \n", "_________________________________________________________________\n", "block3_conv1 (Conv2D) (None, 56, 56, 256) 295168 \n", "_________________________________________________________________\n", "block3_conv2 (Conv2D) (None, 56, 56, 256) 590080 \n", "_________________________________________________________________\n", "block3_conv3 (Conv2D) (None, 56, 56, 256) 590080 \n", "_________________________________________________________________\n", "block3_conv4 (Conv2D) (None, 56, 56, 256) 590080 \n", "_________________________________________________________________\n", "block3_pool (MaxPooling2D) (None, 28, 28, 256) 0 \n", "_________________________________________________________________\n", "block4_conv1 (Conv2D) (None, 28, 28, 512) 1180160 \n", "_________________________________________________________________\n", "block4_conv2 (Conv2D) (None, 28, 28, 512) 2359808 \n", "_________________________________________________________________\n", "block4_conv3 (Conv2D) (None, 28, 28, 512) 2359808 \n", "_________________________________________________________________\n", "block4_conv4 (Conv2D) (None, 28, 28, 512) 2359808 \n", "_________________________________________________________________\n", "block4_pool (MaxPooling2D) (None, 14, 14, 512) 0 \n", "_________________________________________________________________\n", "block5_conv1 (Conv2D) (None, 14, 14, 512) 2359808 \n", "_________________________________________________________________\n", "block5_conv2 (Conv2D) (None, 14, 14, 512) 2359808 \n", "_________________________________________________________________\n", "block5_conv3 (Conv2D) (None, 14, 14, 512) 2359808 \n", "_________________________________________________________________\n", "block5_conv4 (Conv2D) (None, 14, 14, 512) 2359808 \n", "_________________________________________________________________\n", "block5_pool (MaxPooling2D) (None, 7, 7, 512) 0 \n", "_________________________________________________________________\n", "flatten (Flatten) (None, 25088) 0 \n", "_________________________________________________________________\n", "fc1 (Dense) (None, 4096) 102764544 \n", "_________________________________________________________________\n", "fc2 (Dense) (None, 4096) 16781312 \n", "_________________________________________________________________\n", "predictions (Dense) (None, 1000) 4097000 \n", "=================================================================\n", "Total params: 143,667,240\n", "Trainable params: 143,667,240\n", "Non-trainable params: 0\n", "_________________________________________________________________\n", "Model: \"sequential\"\n", "_________________________________________________________________\n", "Layer (type) Output Shape Param # \n", "=================================================================\n", "block1_conv1 (Conv2D) (None, 224, 224, 64) 1792 \n", "_________________________________________________________________\n", "block1_conv2 (Conv2D) (None, 224, 224, 64) 36928 \n", "_________________________________________________________________\n", "block1_pool (MaxPooling2D) (None, 112, 112, 64) 0 \n", "_________________________________________________________________\n", "block2_conv1 (Conv2D) (None, 112, 112, 128) 73856 \n", "_________________________________________________________________\n", "block2_conv2 (Conv2D) (None, 112, 112, 128) 147584 \n", "_________________________________________________________________\n", "block2_pool (MaxPooling2D) (None, 56, 56, 128) 0 \n", "_________________________________________________________________\n", "block3_conv1 (Conv2D) (None, 56, 56, 256) 295168 \n", "_________________________________________________________________\n", "block3_conv2 (Conv2D) (None, 56, 56, 256) 590080 \n", "_________________________________________________________________\n", "block3_conv3 (Conv2D) (None, 56, 56, 256) 590080 \n", "_________________________________________________________________\n", "block3_conv4 (Conv2D) (None, 56, 56, 256) 590080 \n", "_________________________________________________________________\n", "block3_pool (MaxPooling2D) (None, 28, 28, 256) 0 \n", "_________________________________________________________________\n", "block4_conv1 (Conv2D) (None, 28, 28, 512) 1180160 \n", "_________________________________________________________________\n", "block4_conv2 (Conv2D) (None, 28, 28, 512) 2359808 \n", "_________________________________________________________________\n", "block4_conv3 (Conv2D) (None, 28, 28, 512) 2359808 \n", "_________________________________________________________________\n", "block4_conv4 (Conv2D) (None, 28, 28, 512) 2359808 \n", "_________________________________________________________________\n", "block4_pool (MaxPooling2D) (None, 14, 14, 512) 0 \n", "_________________________________________________________________\n", "block5_conv1 (Conv2D) (None, 14, 14, 512) 2359808 \n", "_________________________________________________________________\n", "block5_conv2 (Conv2D) (None, 14, 14, 512) 2359808 \n", "_________________________________________________________________\n", "block5_conv3 (Conv2D) (None, 14, 14, 512) 2359808 \n", "_________________________________________________________________\n", "block5_conv4 (Conv2D) (None, 14, 14, 512) 2359808 \n", "_________________________________________________________________\n", "block5_pool (MaxPooling2D) (None, 7, 7, 512) 0 \n", "_________________________________________________________________\n", "flatten (Flatten) (None, 25088) 0 \n", "_________________________________________________________________\n", "fc1 (Dense) (None, 4096) 102764544 \n", "_________________________________________________________________\n", "fc2 (Dense) (None, 4096) 16781312 \n", "=================================================================\n", "Total params: 139,570,240\n", "Trainable params: 139,570,240\n", "Non-trainable params: 0\n", "_________________________________________________________________\n", "Model: \"sequential\"\n", "_________________________________________________________________\n", "Layer (type) Output Shape Param # \n", "=================================================================\n", "block1_conv1 (Conv2D) (None, 224, 224, 64) 1792 \n", "_________________________________________________________________\n", "block1_conv2 (Conv2D) (None, 224, 224, 64) 36928 \n", "_________________________________________________________________\n", "block1_pool (MaxPooling2D) (None, 112, 112, 64) 0 \n", "_________________________________________________________________\n", "block2_conv1 (Conv2D) (None, 112, 112, 128) 73856 \n", "_________________________________________________________________\n", "block2_conv2 (Conv2D) (None, 112, 112, 128) 147584 \n", "_________________________________________________________________\n", "block2_pool (MaxPooling2D) (None, 56, 56, 128) 0 \n", "_________________________________________________________________\n", "block3_conv1 (Conv2D) (None, 56, 56, 256) 295168 \n", "_________________________________________________________________\n", "block3_conv2 (Conv2D) (None, 56, 56, 256) 590080 \n", "_________________________________________________________________\n", "block3_conv3 (Conv2D) (None, 56, 56, 256) 590080 \n", "_________________________________________________________________\n", "block3_conv4 (Conv2D) (None, 56, 56, 256) 590080 \n", "_________________________________________________________________\n", "block3_pool (MaxPooling2D) (None, 28, 28, 256) 0 \n", "_________________________________________________________________\n", "block4_conv1 (Conv2D) (None, 28, 28, 512) 1180160 \n", "_________________________________________________________________\n", "block4_conv2 (Conv2D) (None, 28, 28, 512) 2359808 \n", "_________________________________________________________________\n", "block4_conv3 (Conv2D) (None, 28, 28, 512) 2359808 \n", "_________________________________________________________________\n", "block4_conv4 (Conv2D) (None, 28, 28, 512) 2359808 \n", "_________________________________________________________________\n", "block4_pool (MaxPooling2D) (None, 14, 14, 512) 0 \n", "_________________________________________________________________\n", "block5_conv1 (Conv2D) (None, 14, 14, 512) 2359808 \n", "_________________________________________________________________\n", "block5_conv2 (Conv2D) (None, 14, 14, 512) 2359808 \n", "_________________________________________________________________\n", "block5_conv3 (Conv2D) (None, 14, 14, 512) 2359808 \n", "_________________________________________________________________\n", "block5_conv4 (Conv2D) (None, 14, 14, 512) 2359808 \n", "_________________________________________________________________\n", "block5_pool (MaxPooling2D) (None, 7, 7, 512) 0 \n", "_________________________________________________________________\n", "flatten (Flatten) (None, 25088) 0 \n", "_________________________________________________________________\n", "fc1 (Dense) (None, 4096) 102764544 \n", "_________________________________________________________________\n", "fc2 (Dense) (None, 4096) 16781312 \n", "_________________________________________________________________\n", "dense (Dense) (None, 2) 8194 \n", "=================================================================\n", "Total params: 139,578,434\n", "Trainable params: 8,194\n", "Non-trainable params: 139,570,240\n", "_________________________________________________________________\n" ] } ] }, { "cell_type": "markdown", "metadata": { "id": "UAUmsdikSD24" }, "source": [ "**Loading dataset**" ] }, { "cell_type": "code", "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "8H1ybCfASbCi", "outputId": "2edbff52-7464-4b92-a92c-9d9fc4a7ab44" }, "source": [ "# call loss and optimizer\n", "loss = keras.losses.SparseCategoricalCrossentropy(from_logits=True)\n", "optim = keras.optimizers.Adam(learning_rate=0.001)\n", "metrics = [\"accuracy\"]\n", "\n", "model.compile(optimizer=optim, loss=loss, metrics=metrics)\n", "\n", "# get the preprocessing function of this model\n", "preprocess_input = tf.keras.applications.vgg16.preprocess_input\n", "\n", "# Generate batches of tensor image data with real-time data augmentation.\n", "\n", "train_gen = keras.preprocessing.image.ImageDataGenerator(preprocessing_function=preprocess_input)\n", "valid_gen = keras.preprocessing.image.ImageDataGenerator(preprocessing_function=preprocess_input)\n", "test_gen = keras.preprocessing.image.ImageDataGenerator(preprocessing_function=preprocess_input)\n", "\n", "train_batches = train_gen.flow_from_directory(\n", " '/content/drive/MyDrive/larva/train',\n", " target_size=(224, 224),\n", " class_mode='binary',\n", " batch_size=8,\n", " shuffle=True,\n", " seed = 42,\n", " color_mode=\"rgb\",\n", " classes=names \n", ")\n", "\n", "val_batches = valid_gen.flow_from_directory(\n", " '/content/drive/MyDrive/larva/val',\n", " target_size=(224, 224),\n", " class_mode='binary',\n", " batch_size=8,\n", " shuffle=True,\n", " seed = 42,\n", " color_mode=\"rgb\",\n", " classes=names\n", ")\n", "\n", "test_batches = test_gen.flow_from_directory(\n", " '/content/drive/MyDrive/larva/test',\n", " target_size=(224, 224),\n", " class_mode='binary',\n", " batch_size=8, \n", " shuffle=False,\n", " color_mode=\"rgb\",\n", " classes=names\n", ")\n" ], "execution_count": null, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "Found 384 images belonging to 2 classes.\n", "Found 128 images belonging to 2 classes.\n", "Found 128 images belonging to 2 classes.\n" ] } ] }, { "cell_type": "markdown", "metadata": { "id": "n1hnK7WvTkFz" }, "source": [ "**processing**" ] }, { "cell_type": "code", "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "IeGo75TwTqXk", "outputId": "bd14fb2b-6c7c-4c9d-bf56-58bfaeb5d236" }, "source": [ "epochs = 100#\n", "\n", "early_stopping = keras.callbacks.EarlyStopping(\n", " monitor=\"val_loss\",\n", " patience=10,\n", " verbose=2\n", ")\n", "\n", "model.fit(train_batches, validation_data=val_batches,\n", " callbacks=[early_stopping],\n", " epochs=epochs, verbose=1)\n", "\n", "model.evaluate(test_batches, verbose=2)\n", "\n" ], "execution_count": null, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "Epoch 1/100\n", "48/48 [==============================] - 322s 7s/step - loss: 0.3045 - accuracy: 0.8724 - val_loss: 0.1694 - val_accuracy: 0.9297\n", "Epoch 2/100\n", "48/48 [==============================] - 320s 7s/step - loss: 0.0777 - accuracy: 0.9740 - val_loss: 0.0760 - val_accuracy: 0.9688\n", "Epoch 3/100\n", "48/48 [==============================] - 320s 7s/step - loss: 0.0349 - accuracy: 0.9974 - val_loss: 0.0958 - val_accuracy: 0.9766\n", "Epoch 4/100\n", "48/48 [==============================] - 320s 7s/step - loss: 0.0238 - accuracy: 1.0000 - val_loss: 0.0749 - val_accuracy: 0.9609\n", "Epoch 5/100\n", "48/48 [==============================] - 321s 7s/step - loss: 0.0212 - accuracy: 0.9948 - val_loss: 0.0695 - val_accuracy: 0.9766\n", "Epoch 6/100\n", "48/48 [==============================] - 321s 7s/step - loss: 0.0168 - accuracy: 1.0000 - val_loss: 0.0810 - val_accuracy: 0.9766\n", "Epoch 7/100\n", "48/48 [==============================] - 321s 7s/step - loss: 0.0123 - accuracy: 1.0000 - val_loss: 0.0696 - val_accuracy: 0.9766\n", "Epoch 8/100\n", "48/48 [==============================] - 321s 7s/step - loss: 0.0107 - accuracy: 1.0000 - val_loss: 0.0819 - val_accuracy: 0.9766\n", "Epoch 9/100\n", "48/48 [==============================] - 321s 7s/step - loss: 0.0083 - accuracy: 1.0000 - val_loss: 0.0765 - val_accuracy: 0.9688\n", "Epoch 10/100\n", "48/48 [==============================] - 320s 7s/step - loss: 0.0074 - accuracy: 1.0000 - val_loss: 0.0885 - val_accuracy: 0.9766\n", "Epoch 11/100\n", "48/48 [==============================] - 321s 7s/step - loss: 0.0086 - accuracy: 1.0000 - val_loss: 0.0680 - val_accuracy: 0.9766\n", "Epoch 12/100\n", "48/48 [==============================] - 320s 7s/step - loss: 0.0053 - accuracy: 1.0000 - val_loss: 0.0741 - val_accuracy: 0.9688\n", "Epoch 13/100\n", "48/48 [==============================] - 320s 7s/step - loss: 0.0047 - accuracy: 1.0000 - val_loss: 0.0723 - val_accuracy: 0.9766\n", "Epoch 14/100\n", "48/48 [==============================] - 320s 7s/step - loss: 0.0047 - accuracy: 1.0000 - val_loss: 0.1163 - val_accuracy: 0.9766\n", "Epoch 15/100\n", "48/48 [==============================] - 321s 7s/step - loss: 0.0036 - accuracy: 1.0000 - val_loss: 0.0789 - val_accuracy: 0.9688\n", "Epoch 16/100\n", "48/48 [==============================] - 320s 7s/step - loss: 0.0033 - accuracy: 1.0000 - val_loss: 0.0933 - val_accuracy: 0.9766\n", "Epoch 17/100\n", "48/48 [==============================] - 320s 7s/step - loss: 0.0034 - accuracy: 1.0000 - val_loss: 0.0789 - val_accuracy: 0.9688\n", "Epoch 18/100\n", "48/48 [==============================] - 320s 7s/step - loss: 0.0033 - accuracy: 1.0000 - val_loss: 0.0672 - val_accuracy: 0.9766\n", "Epoch 19/100\n", "48/48 [==============================] - 320s 7s/step - loss: 0.0029 - accuracy: 1.0000 - val_loss: 0.0920 - val_accuracy: 0.9766\n", "Epoch 20/100\n", "48/48 [==============================] - 320s 7s/step - loss: 0.0023 - accuracy: 1.0000 - val_loss: 0.0915 - val_accuracy: 0.9688\n", "Epoch 21/100\n", "48/48 [==============================] - 320s 7s/step - loss: 0.0022 - accuracy: 1.0000 - val_loss: 0.0922 - val_accuracy: 0.9688\n", "Epoch 22/100\n", "48/48 [==============================] - 320s 7s/step - loss: 0.0022 - accuracy: 1.0000 - val_loss: 0.0990 - val_accuracy: 0.9766\n", "Epoch 23/100\n", "48/48 [==============================] - 320s 7s/step - loss: 0.0019 - accuracy: 1.0000 - val_loss: 0.0904 - val_accuracy: 0.9688\n", "Epoch 24/100\n", "48/48 [==============================] - 320s 7s/step - loss: 0.0018 - accuracy: 1.0000 - val_loss: 0.0935 - val_accuracy: 0.9688\n", "Epoch 25/100\n", "48/48 [==============================] - 320s 7s/step - loss: 0.0017 - accuracy: 1.0000 - val_loss: 0.0930 - val_accuracy: 0.9688\n", "Epoch 26/100\n", "48/48 [==============================] - 320s 7s/step - loss: 0.0015 - accuracy: 1.0000 - val_loss: 0.0942 - val_accuracy: 0.9688\n", "Epoch 27/100\n", "48/48 [==============================] - 320s 7s/step - loss: 0.0014 - accuracy: 1.0000 - val_loss: 0.0943 - val_accuracy: 0.9688\n", "Epoch 28/100\n", "48/48 [==============================] - 320s 7s/step - loss: 0.0014 - accuracy: 1.0000 - val_loss: 0.0955 - val_accuracy: 0.9688\n", "Epoch 00028: early stopping\n", "16/16 - 80s - loss: 0.0924 - accuracy: 0.9688\n" ] }, { "output_type": "execute_result", "data": { "text/plain": [ "[0.0923558846116066, 0.96875]" ] }, "metadata": {}, "execution_count": 3 } ] }, { "cell_type": "markdown", "metadata": { "id": "gJvyz-VOT3NL" }, "source": [ "**Reporting**" ] }, { "cell_type": "code", "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 476 }, "id": "YzOdN3Q_T6uc", "outputId": "fc794b11-05e0-43eb-ad4b-58fcf1f92216" }, "source": [ "# PREDICTION Report\n", "\n", "from sklearn.metrics import classification_report, confusion_matrix\n", "from sklearn.metrics import plot_confusion_matrix\n", "\n", "#Confution Matrix and Classification Report\n", "Y_pred = model.predict(test_batches)\n", "y_pred = np.argmax(Y_pred, axis=1)\n", "cm = confusion_matrix(test_batches.classes, y_pred)\n", "\n", "target_names = ['Zophobus Morio','Tenebrio Molitor'] \n", "\n", "print('Summary:')\n", "print(classification_report(test_batches.classes, y_pred, target_names=target_names))\n", "\n", "#Download the results\n", "labels = (train_batches.class_indices)\n", "labels = dict((v,k) for k,v in labels.items())\n", "predictions = [labels[k] for k in y_pred]\n", "\n", "filenames=test_batches.filenames\n", "results=pd.DataFrame({\"Filename\":filenames,\n", " \"Predictions\":predictions})\n", "results.to_csv(\"results.csv\",index=False)\n", "\n", "from google.colab import files\n", "files.download(\"results.csv\")\n", "\n", "\n", "\n", "#Confussion Matrix \n", "from sklearn.metrics import ConfusionMatrixDisplay\n", "disp = ConfusionMatrixDisplay(confusion_matrix=cm,\n", " display_labels=target_names)\n", "# NOTE: Fill all variables here with default values of the plot_confusion_matrix\n", "disp = disp.plot(cmap=plt.cm.Blues)\n", "plt.title(\"VGG19 Confusion Matrix\")\n", "plt.show()" ], "execution_count": null, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "Summary:\n", " precision recall f1-score support\n", "\n", " Zophobus Morio 1.00 0.94 0.97 64\n", "Tenebrio Molitor 0.94 1.00 0.97 64\n", "\n", " accuracy 0.97 128\n", " macro avg 0.97 0.97 0.97 128\n", " weighted avg 0.97 0.97 0.97 128\n", "\n" ] }, { "output_type": "display_data", "data": { "application/javascript": [ "\n", " async function download(id, filename, size) {\n", " if (!google.colab.kernel.accessAllowed) {\n", " return;\n", " }\n", " const div = document.createElement('div');\n", " const label = document.createElement('label');\n", " label.textContent = `Downloading \"${filename}\": `;\n", " div.appendChild(label);\n", " const progress = document.createElement('progress');\n", " progress.max = size;\n", " div.appendChild(progress);\n", " document.body.appendChild(div);\n", "\n", " const buffers = [];\n", " let downloaded = 0;\n", "\n", " const channel = await google.colab.kernel.comms.open(id);\n", " // Send a message to notify the kernel that we're ready.\n", " channel.send({})\n", "\n", " for await (const message of channel.messages) {\n", " // Send a message to notify the kernel that we're ready.\n", " channel.send({})\n", " if (message.buffers) {\n", " for (const buffer of message.buffers) {\n", " buffers.push(buffer);\n", " downloaded += buffer.byteLength;\n", " progress.value = downloaded;\n", " }\n", " }\n", " }\n", " const blob = new Blob(buffers, {type: 'application/binary'});\n", " const a = document.createElement('a');\n", " a.href = window.URL.createObjectURL(blob);\n", " a.download = filename;\n", " div.appendChild(a);\n", " a.click();\n", " div.remove();\n", " }\n", " " ], "text/plain": [ "" ] }, "metadata": {} }, { "output_type": "display_data", "data": { "application/javascript": [ "download(\"download_9f8f09d0-f181-4e97-ab3a-3d942d92efa0\", \"results.csv\", 4885)" ], "text/plain": [ "" ] }, "metadata": {} }, { "output_type": "display_data", "data": { "image/png": "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\n", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" } } ] } ] }