Skip to content

Instantly share code, notes, and snippets.

@TokyoYoshida
Created October 21, 2020 10:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save TokyoYoshida/c6ded6ea17db0d223d5e97161db41ec1 to your computer and use it in GitHub Desktop.
Save TokyoYoshida/c6ded6ea17db0d223d5e97161db41ec1 to your computer and use it in GitHub Desktop.
keras-to-coreml-image-classifier.ipynb
Display the source blob
Display the rendered blob
Raw
{
"nbformat": 4,
"nbformat_minor": 0,
"metadata": {
"accelerator": "GPU",
"colab": {
"name": "keras-to-coreml-image-classifier.ipynb",
"provenance": [],
"collapsed_sections": [],
"toc_visible": true,
"authorship_tag": "ABX9TyN0rdrwHztPiZwyJref7/Co",
"include_colab_link": true
},
"kernelspec": {
"display_name": "Python 3",
"name": "python3"
}
},
"cells": [
{
"cell_type": "markdown",
"metadata": {
"id": "view-in-github",
"colab_type": "text"
},
"source": [
"<a href=\"https://colab.research.google.com/gist/TokyoYoshida/c6ded6ea17db0d223d5e97161db41ec1/keras-to-coreml-image-classifier.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "a9asgQ1zJ5xx"
},
"source": [
"# 事前準備"
]
},
{
"cell_type": "code",
"metadata": {
"id": "fCh9Ic4eaTz4",
"outputId": "a58900f5-f5e0-4478-c64b-e3b527a8fb59",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 68
}
},
"source": [
"!pip uninstall -y tensorflow\n",
"!pip uninstall -y keras"
],
"execution_count": 43,
"outputs": [
{
"output_type": "stream",
"text": [
"\u001b[33mWARNING: Skipping tensorflow as it is not installed.\u001b[0m\n",
"Uninstalling Keras-2.2.4:\n",
" Successfully uninstalled Keras-2.2.4\n"
],
"name": "stdout"
}
]
},
{
"cell_type": "code",
"metadata": {
"id": "7z2NnNPqFkx9",
"outputId": "81c9669b-9f06-43ac-bd31-07b204a6d245",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 411
}
},
"source": [
"!pip install tensorflow-gpu==1.14.0"
],
"execution_count": 44,
"outputs": [
{
"output_type": "stream",
"text": [
"Requirement already satisfied: tensorflow-gpu==1.14.0 in /usr/local/lib/python3.6/dist-packages (1.14.0)\n",
"Requirement already satisfied: absl-py>=0.7.0 in /usr/local/lib/python3.6/dist-packages (from tensorflow-gpu==1.14.0) (0.10.0)\n",
"Requirement already satisfied: astor>=0.6.0 in /usr/local/lib/python3.6/dist-packages (from tensorflow-gpu==1.14.0) (0.8.1)\n",
"Requirement already satisfied: tensorboard<1.15.0,>=1.14.0 in /usr/local/lib/python3.6/dist-packages (from tensorflow-gpu==1.14.0) (1.14.0)\n",
"Requirement already satisfied: keras-preprocessing>=1.0.5 in /usr/local/lib/python3.6/dist-packages (from tensorflow-gpu==1.14.0) (1.1.2)\n",
"Requirement already satisfied: numpy<2.0,>=1.14.5 in /usr/local/lib/python3.6/dist-packages (from tensorflow-gpu==1.14.0) (1.18.5)\n",
"Requirement already satisfied: termcolor>=1.1.0 in /usr/local/lib/python3.6/dist-packages (from tensorflow-gpu==1.14.0) (1.1.0)\n",
"Requirement already satisfied: gast>=0.2.0 in /usr/local/lib/python3.6/dist-packages (from tensorflow-gpu==1.14.0) (0.3.3)\n",
"Requirement already satisfied: six>=1.10.0 in /usr/local/lib/python3.6/dist-packages (from tensorflow-gpu==1.14.0) (1.15.0)\n",
"Requirement already satisfied: tensorflow-estimator<1.15.0rc0,>=1.14.0rc0 in /usr/local/lib/python3.6/dist-packages (from tensorflow-gpu==1.14.0) (1.14.0)\n",
"Requirement already satisfied: google-pasta>=0.1.6 in /usr/local/lib/python3.6/dist-packages (from tensorflow-gpu==1.14.0) (0.2.0)\n",
"Requirement already satisfied: keras-applications>=1.0.6 in /usr/local/lib/python3.6/dist-packages (from tensorflow-gpu==1.14.0) (1.0.8)\n",
"Requirement already satisfied: wrapt>=1.11.1 in /usr/local/lib/python3.6/dist-packages (from tensorflow-gpu==1.14.0) (1.12.1)\n",
"Requirement already satisfied: wheel>=0.26 in /usr/local/lib/python3.6/dist-packages (from tensorflow-gpu==1.14.0) (0.35.1)\n",
"Requirement already satisfied: protobuf>=3.6.1 in /usr/local/lib/python3.6/dist-packages (from tensorflow-gpu==1.14.0) (3.12.4)\n",
"Requirement already satisfied: grpcio>=1.8.6 in /usr/local/lib/python3.6/dist-packages (from tensorflow-gpu==1.14.0) (1.32.0)\n",
"Requirement already satisfied: werkzeug>=0.11.15 in /usr/local/lib/python3.6/dist-packages (from tensorboard<1.15.0,>=1.14.0->tensorflow-gpu==1.14.0) (1.0.1)\n",
"Requirement already satisfied: setuptools>=41.0.0 in /usr/local/lib/python3.6/dist-packages (from tensorboard<1.15.0,>=1.14.0->tensorflow-gpu==1.14.0) (50.3.0)\n",
"Requirement already satisfied: markdown>=2.6.8 in /usr/local/lib/python3.6/dist-packages (from tensorboard<1.15.0,>=1.14.0->tensorflow-gpu==1.14.0) (3.2.2)\n",
"Requirement already satisfied: h5py in /usr/local/lib/python3.6/dist-packages (from keras-applications>=1.0.6->tensorflow-gpu==1.14.0) (2.10.0)\n",
"Requirement already satisfied: importlib-metadata; python_version < \"3.8\" in /usr/local/lib/python3.6/dist-packages (from markdown>=2.6.8->tensorboard<1.15.0,>=1.14.0->tensorflow-gpu==1.14.0) (2.0.0)\n",
"Requirement already satisfied: zipp>=0.5 in /usr/local/lib/python3.6/dist-packages (from importlib-metadata; python_version < \"3.8\"->markdown>=2.6.8->tensorboard<1.15.0,>=1.14.0->tensorflow-gpu==1.14.0) (3.2.0)\n"
],
"name": "stdout"
}
]
},
{
"cell_type": "code",
"metadata": {
"id": "HtNp6suuDb3e",
"outputId": "567ab022-42d0-4025-9c69-ca06feffced6",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 476
}
},
"source": [
"from tensorflow.python.client import device_lib\n",
"device_lib.list_local_devices()"
],
"execution_count": 45,
"outputs": [
{
"output_type": "execute_result",
"data": {
"text/plain": [
"[name: \"/device:CPU:0\"\n",
" device_type: \"CPU\"\n",
" memory_limit: 268435456\n",
" locality {\n",
" }\n",
" incarnation: 17192021863681980893, name: \"/device:XLA_GPU:0\"\n",
" device_type: \"XLA_GPU\"\n",
" memory_limit: 17179869184\n",
" locality {\n",
" }\n",
" incarnation: 429992164335302567\n",
" physical_device_desc: \"device: XLA_GPU device\", name: \"/device:XLA_CPU:0\"\n",
" device_type: \"XLA_CPU\"\n",
" memory_limit: 17179869184\n",
" locality {\n",
" }\n",
" incarnation: 14613223258219429651\n",
" physical_device_desc: \"device: XLA_CPU device\", name: \"/device:GPU:0\"\n",
" device_type: \"GPU\"\n",
" memory_limit: 15956161332\n",
" locality {\n",
" bus_id: 1\n",
" links {\n",
" }\n",
" }\n",
" incarnation: 1678026550454743412\n",
" physical_device_desc: \"device: 0, name: Tesla P100-PCIE-16GB, pci bus id: 0000:00:04.0, compute capability: 6.0\"]"
]
},
"metadata": {
"tags": []
},
"execution_count": 45
}
]
},
{
"cell_type": "code",
"metadata": {
"id": "IvkGPu7BC8h_",
"outputId": "a56fa477-a808-4708-bbb3-c47d27fa60b6",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 35
}
},
"source": [
"import tensorflow as tf\n",
"\n",
"tf.test.gpu_device_name()"
],
"execution_count": 46,
"outputs": [
{
"output_type": "execute_result",
"data": {
"application/vnd.google.colaboratory.intrinsic+json": {
"type": "string"
},
"text/plain": [
"'/device:GPU:0'"
]
},
"metadata": {
"tags": []
},
"execution_count": 46
}
]
},
{
"cell_type": "code",
"metadata": {
"id": "8ilVrJX0Fq0E",
"outputId": "4aad7159-8942-4783-e4b3-17e0de8a4465",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 238
}
},
"source": [
"!pip install -U coremltools"
],
"execution_count": 47,
"outputs": [
{
"output_type": "stream",
"text": [
"Requirement already up-to-date: coremltools in /usr/local/lib/python3.6/dist-packages (4.0)\n",
"Requirement already satisfied, skipping upgrade: packaging in /usr/local/lib/python3.6/dist-packages (from coremltools) (20.4)\n",
"Requirement already satisfied, skipping upgrade: tqdm in /usr/local/lib/python3.6/dist-packages (from coremltools) (4.41.1)\n",
"Requirement already satisfied, skipping upgrade: numpy>=1.14.5 in /usr/local/lib/python3.6/dist-packages (from coremltools) (1.18.5)\n",
"Requirement already satisfied, skipping upgrade: attrs in /usr/local/lib/python3.6/dist-packages (from coremltools) (20.2.0)\n",
"Requirement already satisfied, skipping upgrade: protobuf>=3.1.0 in /usr/local/lib/python3.6/dist-packages (from coremltools) (3.12.4)\n",
"Requirement already satisfied, skipping upgrade: attr in /usr/local/lib/python3.6/dist-packages (from coremltools) (0.3.1)\n",
"Requirement already satisfied, skipping upgrade: scipy in /usr/local/lib/python3.6/dist-packages (from coremltools) (1.4.1)\n",
"Requirement already satisfied, skipping upgrade: six>=1.10.0 in /usr/local/lib/python3.6/dist-packages (from coremltools) (1.15.0)\n",
"Requirement already satisfied, skipping upgrade: sympy in /usr/local/lib/python3.6/dist-packages (from coremltools) (1.1.1)\n",
"Requirement already satisfied, skipping upgrade: pyparsing>=2.0.2 in /usr/local/lib/python3.6/dist-packages (from packaging->coremltools) (2.4.7)\n",
"Requirement already satisfied, skipping upgrade: setuptools in /usr/local/lib/python3.6/dist-packages (from protobuf>=3.1.0->coremltools) (50.3.0)\n",
"Requirement already satisfied, skipping upgrade: mpmath>=0.19 in /usr/local/lib/python3.6/dist-packages (from sympy->coremltools) (1.1.0)\n"
],
"name": "stdout"
}
]
},
{
"cell_type": "code",
"metadata": {
"id": "h1i3QSK1FyDy",
"outputId": "8020549a-811b-431c-f1e3-91770419733e",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 311
}
},
"source": [
"!pip install keras==2.2.4"
],
"execution_count": 48,
"outputs": [
{
"output_type": "stream",
"text": [
"Collecting keras==2.2.4\n",
" Using cached https://files.pythonhosted.org/packages/5e/10/aa32dad071ce52b5502266b5c659451cfd6ffcbf14e6c8c4f16c0ff5aaab/Keras-2.2.4-py2.py3-none-any.whl\n",
"Requirement already satisfied: scipy>=0.14 in /usr/local/lib/python3.6/dist-packages (from keras==2.2.4) (1.4.1)\n",
"Requirement already satisfied: keras-applications>=1.0.6 in /usr/local/lib/python3.6/dist-packages (from keras==2.2.4) (1.0.8)\n",
"Requirement already satisfied: six>=1.9.0 in /usr/local/lib/python3.6/dist-packages (from keras==2.2.4) (1.15.0)\n",
"Requirement already satisfied: numpy>=1.9.1 in /usr/local/lib/python3.6/dist-packages (from keras==2.2.4) (1.18.5)\n",
"Requirement already satisfied: keras-preprocessing>=1.0.5 in /usr/local/lib/python3.6/dist-packages (from keras==2.2.4) (1.1.2)\n",
"Requirement already satisfied: h5py in /usr/local/lib/python3.6/dist-packages (from keras==2.2.4) (2.10.0)\n",
"Requirement already satisfied: pyyaml in /usr/local/lib/python3.6/dist-packages (from keras==2.2.4) (3.13)\n",
"\u001b[31mERROR: fancyimpute 0.4.3 requires tensorflow, which is not installed.\u001b[0m\n",
"Installing collected packages: keras\n",
"Successfully installed keras-2.2.4\n"
],
"name": "stdout"
},
{
"output_type": "display_data",
"data": {
"application/vnd.colab-display-data+json": {
"pip_warning": {
"packages": [
"keras"
]
}
}
},
"metadata": {
"tags": []
}
}
]
},
{
"cell_type": "code",
"metadata": {
"id": "v3YrdcUxKGeA"
},
"source": [
"from keras.preprocessing.image import ImageDataGenerator\n",
"from keras.models import Sequential\n",
"from keras import layers\n",
"from keras import backend as K\n",
"from keras.utils import np_utils\n",
"import keras\n",
"\n",
"import numpy as np\n",
"import math\n"
],
"execution_count": 49,
"outputs": []
},
{
"cell_type": "markdown",
"metadata": {
"id": "1Cpe0nwZlY93"
},
"source": [
"# 訓練用データの読み込み"
]
},
{
"cell_type": "code",
"metadata": {
"id": "uNwlDU1HBuWe"
},
"source": [
"from keras.datasets import cifar10\n",
"\n",
"(x_train, y_train), (x_test, y_test) = cifar10.load_data()\n",
"num_classes = 10"
],
"execution_count": 50,
"outputs": []
},
{
"cell_type": "code",
"metadata": {
"id": "nz6V8Mk_XGVF"
},
"source": [
"# 正規化\n",
"x_train = x_train.astype('float32')\n",
"x_test = x_test.astype('float32')\n",
"x_train /= 255.0\n",
"x_test /= 255.0"
],
"execution_count": 51,
"outputs": []
},
{
"cell_type": "markdown",
"metadata": {
"id": "-xBgPyLFlgKW"
},
"source": [
"データを表示させてみる"
]
},
{
"cell_type": "code",
"metadata": {
"id": "HLDW1mpNlB9V",
"outputId": "0108215b-556f-4e46-f156-22035699aa7b",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 284
}
},
"source": [
"import matplotlib.pyplot as plt\n",
"\n",
"cifar10_labels = [\n",
" 'airplane',\n",
" 'automobile',\n",
" 'bird',\n",
" 'cat',\n",
" 'deer',\n",
" 'dog',\n",
" 'frog',\n",
" 'horse',\n",
" 'ship',\n",
" 'truck'\n",
"]\n",
"for index, img in enumerate(x_train[:30]):\n",
" plt.subplot(3, 10, index + 1)\n",
" plt.imshow(img)\n",
" plt.axis('off')\n",
" plt.title(cifar10_labels[y_train[index][0]])\n",
" plt.tight_layout()\n",
"\n",
"plt.show()"
],
"execution_count": 52,
"outputs": [
{
"output_type": "stream",
"text": [
"/usr/local/lib/python3.6/dist-packages/ipykernel_launcher.py:20: UserWarning: Tight layout not applied. tight_layout cannot make axes width small enough to accommodate all axes decorations\n"
],
"name": "stderr"
},
{
"output_type": "display_data",
"data": {
"image/png": "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\n",
"text/plain": [
"<Figure size 432x288 with 30 Axes>"
]
},
"metadata": {
"tags": [],
"needs_background": "light"
}
}
]
},
{
"cell_type": "code",
"metadata": {
"id": "msvwgkK6lo_j"
},
"source": [
"# one-Hot表現に変換\n",
"y_train = np_utils.to_categorical(y_train, num_classes)\n",
"y_test = np_utils.to_categorical(y_test, num_classes)"
],
"execution_count": 53,
"outputs": []
},
{
"cell_type": "markdown",
"metadata": {
"id": "TBsUUgLrdgQt"
},
"source": [
"イメージジェネレータで、元の画像から回転したり位置を変えたりしてデータセットを水増しする"
]
},
{
"cell_type": "code",
"metadata": {
"id": "AiYe33pCmfVY"
},
"source": [
"train_datagen = ImageDataGenerator(\n",
" featurewise_center=False,\n",
" featurewise_std_normalization=False,\n",
" rotation_range=20,\n",
" width_shift_range=0.2,\n",
" height_shift_range=0.2,\n",
" horizontal_flip=True)"
],
"execution_count": 54,
"outputs": []
},
{
"cell_type": "code",
"metadata": {
"id": "-xTfa3mNoLBS"
},
"source": [
"test_datagen = ImageDataGenerator(\n",
" featurewise_center=False,\n",
" featurewise_std_normalization=False,\n",
" rotation_range=20,\n",
" width_shift_range=0.2,\n",
" height_shift_range=0.2,\n",
" horizontal_flip=True)"
],
"execution_count": 55,
"outputs": []
},
{
"cell_type": "code",
"metadata": {
"id": "EJc3xjHzmpJV"
},
"source": [
"train_datagen.fit(x_train)\n",
"test_datagen.fit(x_test)"
],
"execution_count": 56,
"outputs": []
},
{
"cell_type": "code",
"metadata": {
"id": "hrTOgBm1bcgW"
},
"source": [
"!mkdir -p checkpoints\n",
"!mkdir -p logs"
],
"execution_count": 57,
"outputs": []
},
{
"cell_type": "markdown",
"metadata": {
"id": "zSWb8FtvJ-XU"
},
"source": [
"# モデルの作成"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "8i0IC4LuJ4Z3"
},
"source": [
""
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "9VU2bQlkdBWI"
},
"source": [
"コールバックの設定"
]
},
{
"cell_type": "code",
"metadata": {
"id": "ie0vY5aLeaZq"
},
"source": [
"# tensorboardで可視化するために使用する\n",
"tansorboard_cb = keras.callbacks.TensorBoard(log_dir='./logs', histogram_freq=0, batch_size=32, write_graph=True, write_grads=False, write_images=False, embeddings_freq=0, embeddings_layer_names=None, embeddings_metadata=None)"
],
"execution_count": 58,
"outputs": []
},
{
"cell_type": "code",
"metadata": {
"id": "3BU9PGQQH6RA"
},
"source": [
"# Epoch毎(1回あたりの訓練)毎に、モデルの情報(チェックポイント)を保存する。こうすることで、途中で高い精度が出た場合は、あとから取り出すことができる)\n",
"checkpoint = keras.callbacks.ModelCheckpoint(\n",
" filepath=\"./checkpoints/checkpoint-{epoch:05d}-{val_acc:.4f}.h5\",\n",
" save_best_only=True\n",
")\n"
],
"execution_count": 59,
"outputs": []
},
{
"cell_type": "code",
"metadata": {
"id": "zHKJrGZAc_YC"
},
"source": [
"# 途中で学習率が下がった場合は、切り上げて終了する\n",
"early_stopping = keras.callbacks.EarlyStopping(monitor='val_loss', patience=10, verbose=1)\n"
],
"execution_count": 60,
"outputs": []
},
{
"cell_type": "markdown",
"metadata": {
"id": "FxWq0jWLdRw5"
},
"source": [
"モデルの作成と学習の実施"
]
},
{
"cell_type": "code",
"metadata": {
"id": "7RUwdVp9FzDa",
"outputId": "afd31e1f-705c-4ed9-98c1-1d5711a391cc",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 51
}
},
"source": [
"interrupt_save_path = 'bk_model.h5'\n",
"\n",
"img_width, img_height = 32, 32\n",
"\n",
"epochs = 1\n",
"batch_size = 32\n",
"\n",
"if K.image_data_format() == 'channels_first':\n",
" input_shape = (3, img_width, img_height)\n",
"else:\n",
" input_shape = (img_width, img_height, 3)\n",
"\n",
"def make_model(input_shape, num_classes):\n",
" inputs = keras.Input(shape=input_shape)\n",
" # Image augmentation block\n",
" x = inputs\n",
"\n",
" # Entry block\n",
" x = layers.Conv2D(32, 3, strides=2, padding=\"same\")(x)\n",
" x = layers.BatchNormalization()(x)\n",
" x = layers.Activation(\"relu\")(x)\n",
"\n",
" x = layers.Conv2D(64, 3, padding=\"same\")(x)\n",
" x = layers.BatchNormalization()(x)\n",
" x = layers.Activation(\"relu\")(x)\n",
"\n",
" previous_block_activation = x # Set aside residual\n",
"\n",
" for size in [128, 256, 512, 728]:\n",
" x = layers.Activation(\"relu\")(x)\n",
" x = layers.SeparableConv2D(size, 3, padding=\"same\")(x)\n",
" x = layers.BatchNormalization()(x)\n",
"\n",
" x = layers.Activation(\"relu\")(x)\n",
" x = layers.SeparableConv2D(size, 3, padding=\"same\")(x)\n",
" x = layers.BatchNormalization()(x)\n",
"\n",
" x = layers.MaxPooling2D(3, strides=2, padding=\"same\")(x)\n",
"\n",
" # Project residual\n",
" residual = layers.Conv2D(size, 1, strides=2, padding=\"same\")(\n",
" previous_block_activation\n",
" )\n",
" x = layers.add([x, residual]) # Add back residual\n",
" previous_block_activation = x # Set aside next residual\n",
"\n",
" x = layers.SeparableConv2D(1024, 3, padding=\"same\")(x)\n",
" x = layers.BatchNormalization()(x)\n",
" x = layers.Activation(\"relu\")(x)\n",
"\n",
" x = layers.GlobalAveragePooling2D()(x)\n",
" if num_classes == 2:\n",
" activation = \"sigmoid\"\n",
" units = 1\n",
" else:\n",
" activation = \"softmax\"\n",
" units = num_classes\n",
"\n",
" x = layers.Dropout(0.5)(x)\n",
" outputs = layers.Dense(units, activation=activation)(x)\n",
" return keras.Model(inputs, outputs)\n",
"\n",
"model = make_model(input_shape=input_shape, num_classes=num_classes)\n",
"\n",
"model.compile(loss='categorical_crossentropy',\n",
" optimizer='adam',\n",
" metrics=['accuracy'])\n",
"\n",
"# try〜exceptでKeyboardInterrupt例外をひろい、手動で止めてもそこまでのモデルを保存している\n",
"try:\n",
" model.fit_generator(\n",
" train_datagen.flow(x_train, y_train, batch_size=32),\n",
" steps_per_epoch=len(x_train) / batch_size , epochs=epochs,\n",
" validation_data=test_datagen.flow(x_test, y_test, batch_size=32),\n",
" validation_steps=len(x_test) / batch_size,\n",
" callbacks=[early_stopping, tansorboard_cb, checkpoint] \n",
" )\n",
"except KeyboardInterrupt:\n",
" model.save(interrupt_save_path)\n",
" print('Output saved to: \"{}./*\"'.format(interrupt_save_path))"
],
"execution_count": 61,
"outputs": [
{
"output_type": "stream",
"text": [
"Epoch 1/1\n",
"1563/1562 [==============================] - 60s 38ms/step - loss: 1.6503 - acc: 0.3989 - val_loss: 2.1159 - val_acc: 0.3737\n"
],
"name": "stdout"
}
]
},
{
"cell_type": "code",
"metadata": {
"id": "hFEJEKYKfPI9",
"outputId": "1a084120-cd7b-4c54-a598-97fafc304c60",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 51
}
},
"source": [
"# TensorBoardの有効化\n",
"%load_ext tensorboard"
],
"execution_count": 62,
"outputs": [
{
"output_type": "stream",
"text": [
"The tensorboard extension is already loaded. To reload it, use:\n",
" %reload_ext tensorboard\n"
],
"name": "stdout"
}
]
},
{
"cell_type": "code",
"metadata": {
"id": "1MKZ41KnfWK_",
"outputId": "4abfd9fb-bc99-4222-dd07-a7b2dc786726",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 34
}
},
"source": [
"!pip uninstall tensorboard-plugin-wit"
],
"execution_count": 63,
"outputs": [
{
"output_type": "stream",
"text": [
"\u001b[33mWARNING: Skipping tensorboard-plugin-wit as it is not installed.\u001b[0m\n"
],
"name": "stdout"
}
]
},
{
"cell_type": "code",
"metadata": {
"id": "7opVEasaFJno",
"outputId": "23837d33-3869-4dbc-f1a6-4661b4694576",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 34
}
},
"source": [
"# TensorBoardの起動\n",
"%tensorboard --logdir ./logs"
],
"execution_count": 64,
"outputs": [
{
"output_type": "display_data",
"data": {
"text/plain": [
"Reusing TensorBoard on port 6006 (pid 282), started 1:02:22 ago. (Use '!kill 282' to kill it.)"
]
},
"metadata": {
"tags": []
}
},
{
"output_type": "display_data",
"data": {
"text/html": [
"\n",
" <div id=\"root\"></div>\n",
" <script>\n",
" (function() {\n",
" window.TENSORBOARD_ENV = window.TENSORBOARD_ENV || {};\n",
" window.TENSORBOARD_ENV[\"IN_COLAB\"] = true;\n",
" document.querySelector(\"base\").href = \"https://localhost:6006\";\n",
" function fixUpTensorboard(root) {\n",
" const tftb = root.querySelector(\"tf-tensorboard\");\n",
" // Disable the fragment manipulation behavior in Colab. Not\n",
" // only is the behavior not useful (as the iframe's location\n",
" // is not visible to the user), it causes TensorBoard's usage\n",
" // of `window.replace` to navigate away from the page and to\n",
" // the `localhost:<port>` URL specified by the base URI, which\n",
" // in turn causes the frame to (likely) crash.\n",
" tftb.removeAttribute(\"use-hash\");\n",
" }\n",
" function executeAllScripts(root) {\n",
" // When `script` elements are inserted into the DOM by\n",
" // assigning to an element's `innerHTML`, the scripts are not\n",
" // executed. Thus, we manually re-insert these scripts so that\n",
" // TensorBoard can initialize itself.\n",
" for (const script of root.querySelectorAll(\"script\")) {\n",
" const newScript = document.createElement(\"script\");\n",
" newScript.type = script.type;\n",
" newScript.textContent = script.textContent;\n",
" root.appendChild(newScript);\n",
" script.remove();\n",
" }\n",
" }\n",
" function setHeight(root, height) {\n",
" // We set the height dynamically after the TensorBoard UI has\n",
" // been initialized. This avoids an intermediate state in\n",
" // which the container plus the UI become taller than the\n",
" // final width and cause the Colab output frame to be\n",
" // permanently resized, eventually leading to an empty\n",
" // vertical gap below the TensorBoard UI. It's not clear\n",
" // exactly what causes this problematic intermediate state,\n",
" // but setting the height late seems to fix it.\n",
" root.style.height = `${height}px`;\n",
" }\n",
" const root = document.getElementById(\"root\");\n",
" fetch(\".\")\n",
" .then((x) => x.text())\n",
" .then((html) => void (root.innerHTML = html))\n",
" .then(() => fixUpTensorboard(root))\n",
" .then(() => executeAllScripts(root))\n",
" .then(() => setHeight(root, 800));\n",
" })();\n",
" </script>\n",
" "
],
"text/plain": [
"<IPython.core.display.HTML object>"
]
},
"metadata": {
"tags": []
}
}
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "b6uaHVscT8XI"
},
"source": [
"# 予想してみる"
]
},
{
"cell_type": "code",
"metadata": {
"id": "F8MyAzc7gfzw",
"outputId": "aa4e4e33-e838-485f-efe9-eb3afc478e30",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 34
}
},
"source": [
"np.count_nonzero(np.argmax(model.predict(x_test),axis=1) - np.argmax(y_test, axis=1) == 0)/len(x_test)"
],
"execution_count": 65,
"outputs": [
{
"output_type": "execute_result",
"data": {
"text/plain": [
"0.4081"
]
},
"metadata": {
"tags": []
},
"execution_count": 65
}
]
},
{
"cell_type": "code",
"metadata": {
"id": "GzRcXtTURr2e",
"outputId": "2bff9017-bf40-4be3-a625-6c3006e2b763",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 102
}
},
"source": [
"np.argmax(model.predict(x_test[0:100]),axis=1)"
],
"execution_count": 66,
"outputs": [
{
"output_type": "execute_result",
"data": {
"text/plain": [
"array([8, 1, 1, 0, 6, 6, 1, 6, 6, 1, 0, 9, 6, 7, 9, 1, 5, 0, 9, 6, 9, 0,\n",
" 0, 1, 7, 2, 3, 0, 1, 6, 6, 0, 0, 6, 9, 1, 7, 1, 1, 8, 0, 6, 9, 6,\n",
" 0, 9, 6, 9, 7, 6, 1, 0, 1, 6, 8, 0, 1, 1, 6, 0, 7, 3, 1, 1, 6, 6,\n",
" 1, 0, 6, 7, 0, 6, 0, 8, 9, 2, 1, 1, 5, 0, 8, 1, 1, 0, 0, 7, 0, 0,\n",
" 9, 1, 0, 6, 8, 0, 7, 6, 6, 0, 0, 7])"
]
},
"metadata": {
"tags": []
},
"execution_count": 66
}
]
},
{
"cell_type": "code",
"metadata": {
"id": "QFJOS-yarK9Z",
"outputId": "0a2d62a8-4b26-42fc-9b91-ae0e8ed73000",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 102
}
},
"source": [
"np.argmax(y_test[0:100], axis=1)"
],
"execution_count": 67,
"outputs": [
{
"output_type": "execute_result",
"data": {
"text/plain": [
"array([3, 8, 8, 0, 6, 6, 1, 6, 3, 1, 0, 9, 5, 7, 9, 8, 5, 7, 8, 6, 7, 0,\n",
" 4, 9, 5, 2, 4, 0, 9, 6, 6, 5, 4, 5, 9, 2, 4, 1, 9, 5, 4, 6, 5, 6,\n",
" 0, 9, 3, 9, 7, 6, 9, 8, 0, 3, 8, 8, 7, 7, 4, 6, 7, 3, 6, 3, 6, 2,\n",
" 1, 2, 3, 7, 2, 6, 8, 8, 0, 2, 9, 3, 3, 8, 8, 1, 1, 7, 2, 5, 2, 7,\n",
" 8, 9, 0, 3, 8, 6, 4, 6, 6, 0, 0, 7])"
]
},
"metadata": {
"tags": []
},
"execution_count": 67
}
]
},
{
"cell_type": "code",
"metadata": {
"id": "UfptA6nXZ085"
},
"source": [
"model.save('my_model.h5')"
],
"execution_count": 68,
"outputs": []
},
{
"cell_type": "code",
"metadata": {
"id": "Cr8W3NEre3Zh"
},
"source": [
"#%tensorboard --logdir ./logs"
],
"execution_count": 69,
"outputs": []
},
{
"cell_type": "markdown",
"metadata": {
"id": "NS2X_5aMUE2G"
},
"source": [
" # CoreMLに変換する"
]
},
{
"cell_type": "code",
"metadata": {
"id": "S4uNDFf7aD5S"
},
"source": [
"from keras.models import load_model"
],
"execution_count": 70,
"outputs": []
},
{
"cell_type": "code",
"metadata": {
"id": "oyDh5o_lZlkd"
},
"source": [
"keras_model = load_model('my_model.h5')"
],
"execution_count": 71,
"outputs": []
},
{
"cell_type": "code",
"metadata": {
"id": "fCUYz1XJT__b",
"outputId": "07e868b6-fad8-4e59-ad4e-02adf3c4aa7d",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 1000
}
},
"source": [
"keras_model.summary()"
],
"execution_count": 72,
"outputs": [
{
"output_type": "stream",
"text": [
"__________________________________________________________________________________________________\n",
"Layer (type) Output Shape Param # Connected to \n",
"==================================================================================================\n",
"input_2 (InputLayer) (None, 32, 32, 3) 0 \n",
"__________________________________________________________________________________________________\n",
"conv2d_7 (Conv2D) (None, 16, 16, 32) 896 input_2[0][0] \n",
"__________________________________________________________________________________________________\n",
"batch_normalization_12 (BatchNo (None, 16, 16, 32) 128 conv2d_7[0][0] \n",
"__________________________________________________________________________________________________\n",
"activation_13 (Activation) (None, 16, 16, 32) 0 batch_normalization_12[0][0] \n",
"__________________________________________________________________________________________________\n",
"conv2d_8 (Conv2D) (None, 16, 16, 64) 18496 activation_13[0][0] \n",
"__________________________________________________________________________________________________\n",
"batch_normalization_13 (BatchNo (None, 16, 16, 64) 256 conv2d_8[0][0] \n",
"__________________________________________________________________________________________________\n",
"activation_14 (Activation) (None, 16, 16, 64) 0 batch_normalization_13[0][0] \n",
"__________________________________________________________________________________________________\n",
"activation_15 (Activation) (None, 16, 16, 64) 0 activation_14[0][0] \n",
"__________________________________________________________________________________________________\n",
"separable_conv2d_10 (SeparableC (None, 16, 16, 128) 8896 activation_15[0][0] \n",
"__________________________________________________________________________________________________\n",
"batch_normalization_14 (BatchNo (None, 16, 16, 128) 512 separable_conv2d_10[0][0] \n",
"__________________________________________________________________________________________________\n",
"activation_16 (Activation) (None, 16, 16, 128) 0 batch_normalization_14[0][0] \n",
"__________________________________________________________________________________________________\n",
"separable_conv2d_11 (SeparableC (None, 16, 16, 128) 17664 activation_16[0][0] \n",
"__________________________________________________________________________________________________\n",
"batch_normalization_15 (BatchNo (None, 16, 16, 128) 512 separable_conv2d_11[0][0] \n",
"__________________________________________________________________________________________________\n",
"max_pooling2d_5 (MaxPooling2D) (None, 8, 8, 128) 0 batch_normalization_15[0][0] \n",
"__________________________________________________________________________________________________\n",
"conv2d_9 (Conv2D) (None, 8, 8, 128) 8320 activation_14[0][0] \n",
"__________________________________________________________________________________________________\n",
"add_5 (Add) (None, 8, 8, 128) 0 max_pooling2d_5[0][0] \n",
" conv2d_9[0][0] \n",
"__________________________________________________________________________________________________\n",
"activation_17 (Activation) (None, 8, 8, 128) 0 add_5[0][0] \n",
"__________________________________________________________________________________________________\n",
"separable_conv2d_12 (SeparableC (None, 8, 8, 256) 34176 activation_17[0][0] \n",
"__________________________________________________________________________________________________\n",
"batch_normalization_16 (BatchNo (None, 8, 8, 256) 1024 separable_conv2d_12[0][0] \n",
"__________________________________________________________________________________________________\n",
"activation_18 (Activation) (None, 8, 8, 256) 0 batch_normalization_16[0][0] \n",
"__________________________________________________________________________________________________\n",
"separable_conv2d_13 (SeparableC (None, 8, 8, 256) 68096 activation_18[0][0] \n",
"__________________________________________________________________________________________________\n",
"batch_normalization_17 (BatchNo (None, 8, 8, 256) 1024 separable_conv2d_13[0][0] \n",
"__________________________________________________________________________________________________\n",
"max_pooling2d_6 (MaxPooling2D) (None, 4, 4, 256) 0 batch_normalization_17[0][0] \n",
"__________________________________________________________________________________________________\n",
"conv2d_10 (Conv2D) (None, 4, 4, 256) 33024 add_5[0][0] \n",
"__________________________________________________________________________________________________\n",
"add_6 (Add) (None, 4, 4, 256) 0 max_pooling2d_6[0][0] \n",
" conv2d_10[0][0] \n",
"__________________________________________________________________________________________________\n",
"activation_19 (Activation) (None, 4, 4, 256) 0 add_6[0][0] \n",
"__________________________________________________________________________________________________\n",
"separable_conv2d_14 (SeparableC (None, 4, 4, 512) 133888 activation_19[0][0] \n",
"__________________________________________________________________________________________________\n",
"batch_normalization_18 (BatchNo (None, 4, 4, 512) 2048 separable_conv2d_14[0][0] \n",
"__________________________________________________________________________________________________\n",
"activation_20 (Activation) (None, 4, 4, 512) 0 batch_normalization_18[0][0] \n",
"__________________________________________________________________________________________________\n",
"separable_conv2d_15 (SeparableC (None, 4, 4, 512) 267264 activation_20[0][0] \n",
"__________________________________________________________________________________________________\n",
"batch_normalization_19 (BatchNo (None, 4, 4, 512) 2048 separable_conv2d_15[0][0] \n",
"__________________________________________________________________________________________________\n",
"max_pooling2d_7 (MaxPooling2D) (None, 2, 2, 512) 0 batch_normalization_19[0][0] \n",
"__________________________________________________________________________________________________\n",
"conv2d_11 (Conv2D) (None, 2, 2, 512) 131584 add_6[0][0] \n",
"__________________________________________________________________________________________________\n",
"add_7 (Add) (None, 2, 2, 512) 0 max_pooling2d_7[0][0] \n",
" conv2d_11[0][0] \n",
"__________________________________________________________________________________________________\n",
"activation_21 (Activation) (None, 2, 2, 512) 0 add_7[0][0] \n",
"__________________________________________________________________________________________________\n",
"separable_conv2d_16 (SeparableC (None, 2, 2, 728) 378072 activation_21[0][0] \n",
"__________________________________________________________________________________________________\n",
"batch_normalization_20 (BatchNo (None, 2, 2, 728) 2912 separable_conv2d_16[0][0] \n",
"__________________________________________________________________________________________________\n",
"activation_22 (Activation) (None, 2, 2, 728) 0 batch_normalization_20[0][0] \n",
"__________________________________________________________________________________________________\n",
"separable_conv2d_17 (SeparableC (None, 2, 2, 728) 537264 activation_22[0][0] \n",
"__________________________________________________________________________________________________\n",
"batch_normalization_21 (BatchNo (None, 2, 2, 728) 2912 separable_conv2d_17[0][0] \n",
"__________________________________________________________________________________________________\n",
"max_pooling2d_8 (MaxPooling2D) (None, 1, 1, 728) 0 batch_normalization_21[0][0] \n",
"__________________________________________________________________________________________________\n",
"conv2d_12 (Conv2D) (None, 1, 1, 728) 373464 add_7[0][0] \n",
"__________________________________________________________________________________________________\n",
"add_8 (Add) (None, 1, 1, 728) 0 max_pooling2d_8[0][0] \n",
" conv2d_12[0][0] \n",
"__________________________________________________________________________________________________\n",
"separable_conv2d_18 (SeparableC (None, 1, 1, 1024) 753048 add_8[0][0] \n",
"__________________________________________________________________________________________________\n",
"batch_normalization_22 (BatchNo (None, 1, 1, 1024) 4096 separable_conv2d_18[0][0] \n",
"__________________________________________________________________________________________________\n",
"activation_23 (Activation) (None, 1, 1, 1024) 0 batch_normalization_22[0][0] \n",
"__________________________________________________________________________________________________\n",
"global_average_pooling2d_2 (Glo (None, 1024) 0 activation_23[0][0] \n",
"__________________________________________________________________________________________________\n",
"dropout_2 (Dropout) (None, 1024) 0 global_average_pooling2d_2[0][0] \n",
"__________________________________________________________________________________________________\n",
"dense_2 (Dense) (None, 10) 10250 dropout_2[0][0] \n",
"==================================================================================================\n",
"Total params: 2,791,874\n",
"Trainable params: 2,783,138\n",
"Non-trainable params: 8,736\n",
"__________________________________________________________________________________________________\n"
],
"name": "stdout"
}
]
},
{
"cell_type": "code",
"metadata": {
"id": "dxvD9uUbaLvz"
},
"source": [
" from coremltools.converters import keras as converter"
],
"execution_count": 73,
"outputs": []
},
{
"cell_type": "code",
"metadata": {
"id": "vuUTubbqaNzs"
},
"source": [
"class_labels = cifar10_labels # 最初の方で設定した識別用のLabel"
],
"execution_count": 74,
"outputs": []
},
{
"cell_type": "code",
"metadata": {
"id": "LIypbXlxaWaZ",
"outputId": "9f90cdf5-9ab3-4855-efd6-2322d6213380",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 850
}
},
"source": [
"mlmodel = converter.convert(keras_model,\n",
" output_names=['cifarProbabilities'], \n",
" class_labels=class_labels, \n",
" predicted_feature_name='cifarName',\n",
" input_names=['input_1'],\n",
" image_input_names='input_1', \n",
" image_scale=1/255.0,\n",
" use_float_arraytype=True,\n",
")"
],
"execution_count": 75,
"outputs": [
{
"output_type": "stream",
"text": [
"0 : input_2, <keras.engine.input_layer.InputLayer object at 0x7f021b9efc50>\n",
"1 : conv2d_7, <keras.layers.convolutional.Conv2D object at 0x7f021b9efcc0>\n",
"2 : batch_normalization_12, <keras.layers.normalization.BatchNormalization object at 0x7f021b9efd68>\n",
"3 : activation_13, <keras.layers.core.Activation object at 0x7f021b9efe48>\n",
"4 : conv2d_8, <keras.layers.convolutional.Conv2D object at 0x7f021b9f60f0>\n",
"5 : batch_normalization_13, <keras.layers.normalization.BatchNormalization object at 0x7f021b9f6278>\n",
"6 : activation_14, <keras.layers.core.Activation object at 0x7f021b9f6390>\n",
"7 : activation_15, <keras.layers.core.Activation object at 0x7f021b9f63c8>\n",
"8 : separable_conv2d_10, <keras.layers.convolutional.SeparableConv2D object at 0x7f021b9f6400>\n",
"9 : batch_normalization_14, <keras.layers.normalization.BatchNormalization object at 0x7f021b9f6668>\n",
"10 : activation_16, <keras.layers.core.Activation object at 0x7f021b9f67f0>\n",
"11 : separable_conv2d_11, <keras.layers.convolutional.SeparableConv2D object at 0x7f021b9f6828>\n",
"12 : batch_normalization_15, <keras.layers.normalization.BatchNormalization object at 0x7f021b9f6a90>\n",
"13 : max_pooling2d_5, <keras.layers.pooling.MaxPooling2D object at 0x7f021b9f6c18>\n",
"14 : conv2d_9, <keras.layers.convolutional.Conv2D object at 0x7f021b9f6cc0>\n",
"15 : add_5, <keras.layers.merge.Add object at 0x7f021b9f6e48>\n",
"16 : activation_17, <keras.layers.core.Activation object at 0x7f021b9f6e80>\n",
"17 : separable_conv2d_12, <keras.layers.convolutional.SeparableConv2D object at 0x7f021b9f6eb8>\n",
"18 : batch_normalization_16, <keras.layers.normalization.BatchNormalization object at 0x7f021b9fa160>\n",
"19 : activation_18, <keras.layers.core.Activation object at 0x7f021b9fa2e8>\n",
"20 : separable_conv2d_13, <keras.layers.convolutional.SeparableConv2D object at 0x7f021b9fa320>\n",
"21 : batch_normalization_17, <keras.layers.normalization.BatchNormalization object at 0x7f021b9efef0>\n",
"22 : max_pooling2d_6, <keras.layers.pooling.MaxPooling2D object at 0x7f021b9fa710>\n",
"23 : conv2d_10, <keras.layers.convolutional.Conv2D object at 0x7f021b9fa7b8>\n",
"24 : add_6, <keras.layers.merge.Add object at 0x7f021b9fa940>\n",
"25 : activation_19, <keras.layers.core.Activation object at 0x7f021b9fa978>\n",
"26 : separable_conv2d_14, <keras.layers.convolutional.SeparableConv2D object at 0x7f021b9fa9b0>\n",
"27 : batch_normalization_18, <keras.layers.normalization.BatchNormalization object at 0x7f021b9fac18>\n",
"28 : activation_20, <keras.layers.core.Activation object at 0x7f021b9fada0>\n",
"29 : separable_conv2d_15, <keras.layers.convolutional.SeparableConv2D object at 0x7f021b9fadd8>\n",
"30 : batch_normalization_19, <keras.layers.normalization.BatchNormalization object at 0x7f02201452b0>\n",
"31 : max_pooling2d_7, <keras.layers.pooling.MaxPooling2D object at 0x7f021b9fd208>\n",
"32 : conv2d_11, <keras.layers.convolutional.Conv2D object at 0x7f021b9fd2b0>\n",
"33 : add_7, <keras.layers.merge.Add object at 0x7f021b9fd438>\n",
"34 : activation_21, <keras.layers.core.Activation object at 0x7f021b9fd470>\n",
"35 : separable_conv2d_16, <keras.layers.convolutional.SeparableConv2D object at 0x7f021b9fd4a8>\n",
"36 : batch_normalization_20, <keras.layers.normalization.BatchNormalization object at 0x7f021b9fd710>\n",
"37 : activation_22, <keras.layers.core.Activation object at 0x7f021b9fd898>\n",
"38 : separable_conv2d_17, <keras.layers.convolutional.SeparableConv2D object at 0x7f021b9fd8d0>\n",
"39 : batch_normalization_21, <keras.layers.normalization.BatchNormalization object at 0x7f021b9fdb38>\n",
"40 : max_pooling2d_8, <keras.layers.pooling.MaxPooling2D object at 0x7f021b9fdcc0>\n",
"41 : conv2d_12, <keras.layers.convolutional.Conv2D object at 0x7f021b9fdd68>\n",
"42 : add_8, <keras.layers.merge.Add object at 0x7f021b9fdef0>\n",
"43 : separable_conv2d_18, <keras.layers.convolutional.SeparableConv2D object at 0x7f021b9fdf28>\n",
"44 : batch_normalization_22, <keras.layers.normalization.BatchNormalization object at 0x7f021ba001d0>\n",
"45 : activation_23, <keras.layers.core.Activation object at 0x7f021ba00358>\n",
"46 : global_average_pooling2d_2, <keras.layers.pooling.GlobalAveragePooling2D object at 0x7f021ba00390>\n",
"47 : dense_2, <keras.layers.core.Dense object at 0x7f021ba00438>\n",
"48 : dense_2__activation__, <keras.layers.core.Activation object at 0x7f038a2989b0>\n"
],
"name": "stdout"
}
]
},
{
"cell_type": "code",
"metadata": {
"id": "I4CAGk9qbVMn"
},
"source": [
"coreml_model_path = 'my_model.mlmodel'\n",
"mlmodel.save(coreml_model_path)"
],
"execution_count": 76,
"outputs": []
},
{
"cell_type": "code",
"metadata": {
"id": "aNig5mTpMAfJ"
},
"source": [
"import coremltools\n",
"spec = coremltools.utils.load_spec(coreml_model_path)"
],
"execution_count": 77,
"outputs": []
},
{
"cell_type": "code",
"metadata": {
"id": "npsDxDWakjDY"
},
"source": [
"builder = coremltools.models.neural_network.NeuralNetworkBuilder(spec=spec)"
],
"execution_count": 78,
"outputs": []
},
{
"cell_type": "code",
"metadata": {
"id": "-QHKfsAIkpXn",
"outputId": "bd870799-cf47-4199-a561-27724a60c035",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 136
}
},
"source": [
"builder.inspect_input_features()"
],
"execution_count": 79,
"outputs": [
{
"output_type": "stream",
"text": [
"[Id: 0] Name: input_1\n",
" Type: imageType {\n",
" width: 32\n",
" height: 32\n",
" colorSpace: RGB\n",
"}\n",
"\n"
],
"name": "stdout"
}
]
},
{
"cell_type": "code",
"metadata": {
"id": "uXweHcmokqnw"
},
"source": [
"# from coremltools.proto import FeatureTypes_pb2 as ft\n",
"# grayscale = ft.ImageFeatureType.ColorSpace.Value('RGB')\n",
"# input_image_type = builder.spec.description.input[0].type.imageType\n",
"# input_image_type.width = 32\n",
"# input_image_type.height = 32\n",
"# input_image_type.colorSpace = grayscale"
],
"execution_count": 80,
"outputs": []
},
{
"cell_type": "code",
"metadata": {
"id": "GBmc82Epkz9F"
},
"source": [
"# builder.inspect_input_features()"
],
"execution_count": 81,
"outputs": []
},
{
"cell_type": "code",
"metadata": {
"id": "SIVK5_Wtk8P7"
},
"source": [
"# mlmodel_modified = coremltools.models.MLModel(spec)\n",
"# mlmodel_modified.save('./my_model2.mlmodel')\n"
],
"execution_count": 82,
"outputs": []
}
]
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment