├── model.tflite ├── .gitignore ├── Podfile ├── main.py ├── LICENSE ├── README.md ├── model.py └── notebooks └── Create_TFLite_model.ipynb /model.tflite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/teticio/kivy-tensorflow-helloworld/HEAD/model.tflite -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .buildozer 2 | .ipynb_checkpoints 3 | .vscode 4 | __pycache__ 5 | bin 6 | Pipfile 7 | 8 | -------------------------------------------------------------------------------- /Podfile: -------------------------------------------------------------------------------- 1 | platform :ios, '13.0' 2 | 3 | target 'myapp' do 4 | pod 'TensorFlowLiteObjC' 5 | end 6 | -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | import os 2 | import kivy 3 | import numpy as np 4 | from kivy.app import App 5 | from kivy.uix.label import Label 6 | from model import TensorFlowModel 7 | 8 | 9 | class MyApp(App): 10 | 11 | def build(self): 12 | model = TensorFlowModel() 13 | model.load(os.path.join(os.getcwd(), 'model.tflite')) 14 | np.random.seed(42) 15 | x = np.array(np.random.random_sample((1, 28, 28)), np.float32) 16 | y = model.pred(x) 17 | # result should be 18 | # 0.01647118, 1.0278152 , -0.7065112 , -1.0278157 , 0.12216613, 19 | # 0.37980393, 0.5839217 , -0.04283606, -0.04240461, -0.58534086 20 | return Label(text=f'{y}') 21 | 22 | 23 | if __name__ == '__main__': 24 | MyApp().run() -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 Robert Dargavel Smith 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Kivy Tensorflow Hello World 2 | 3 | This is a "Hello World" for running Tensorflow Lite on iOS, Android, MacOS, Windows and Linux using Python and Kivy. 4 | 5 | ## Create a Tensorflow Lite model 6 | 7 | You can use the Jupyter notebook in notebooks to create a Tensorflow Lite model file. A dummy example is provided for testing purposes. 8 | 9 | ## Install buildozer 10 | 11 | Install basic Python requirements (all platforms) 12 | 13 | ```bash 14 | pip install buildozer cython 15 | ``` 16 | 17 | Follow the instructions for your platform [here](https://pypi.org/project/buildozer/). 18 | 19 | ## MacOS, Windows and Linux 20 | 21 | ```bash 22 | pip install tensorflow numpy kivy 23 | python3 main.py 24 | ``` 25 | 26 | ## Android 27 | 28 | Currently you can only build for Android using `buildozer` on Linux. 29 | 30 | Use the included `buildozer.spec` file or make the following changes to one created by `buildozer init` 31 | 32 | ``` 33 | source.include_exts = py,png,jpg,kv,atlas,tflite 34 | requirements = python3,kivy,numpy 35 | android.api = 30 36 | android.minapi = 24 37 | android.gradle_dependencies = org.tensorflow:tensorflow-lite:+,org.tensorflow:tensorflow-lite-support:+ 38 | ``` 39 | 40 | Note that if your `tflite` model file is too big to be packaged with your APK, you will have to find some other way of getting it on to the device. If this is the case then change this line to ensure it is not included in the package. 41 | 42 | ``` 43 | source.include_exts = py,png,jpg,kv,atlas 44 | ``` 45 | 46 | Change the architecture you are building for to match that of your device or emulator 47 | 48 | ``` 49 | android.arch = x86 50 | ``` 51 | 52 | Build the APK 53 | 54 | ```bash 55 | buildozer android debug 56 | ``` 57 | 58 | and install it with 59 | 60 | ```bash 61 | adb install bin/myapp-0.1-x86-debug.apk 62 | ``` 63 | 64 | ## iOS 65 | 66 | Remember that you will need an Apple developer account to be able to install your app on a real iPhone. 67 | 68 | Install prerequisite system packages 69 | 70 | ```bash 71 | brew install cocoapods pkg-config autoconf automake 72 | ``` 73 | 74 | Install additional Python requirements 75 | 76 | ```bash 77 | pip install pbxproj cookiecutter 78 | ``` 79 | 80 | Build your app and install the Tensorflow Lite pod 81 | 82 | ```bash 83 | buildozer ios debug 84 | cd .buildozer/ios/platform/kivy-ios/myapp-ios/ 85 | cp YourApp/Podfile . 86 | pod install 87 | open -a Xcode myapp.xcworkspace 88 | ``` 89 | 90 | As indicated in the warning messages, you will need to make some changes to the project configuration. You can either do this by editing `myapp-ios\myapp.xcodeproj` or by editing the Build Settings for `myapp` in Xcode. Search for `GCC_PREPROCESSOR_DEFINITIONS` and add `$(inherited)` to the Debug target. Then repeat the process for `HEADER_SEARCH_PATHS`, `OTHER_LDFLAGS` and (possibly) `EXCLUDED_ARCHS[sdk=iphonesimulator*]` for all targets. Now you should be able to build and run your app. All being well you should see the following output (give or take rounding errors) 91 | 92 | ```python 93 | [[ 0.01647118, 1.0278152 , -0.7065112 , -1.0278157 , 0.12216613, 0.37980393, 0.5839217 , -0.04283606, -0.04240461, -0.58534086 ]] 94 | ``` 95 | 96 | Every time you build you will need to run `buildozer ios debug` and then build and deploy from Xcode. 97 | -------------------------------------------------------------------------------- /model.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from kivy.utils import platform 3 | 4 | if platform == 'android': 5 | from jnius import autoclass 6 | 7 | File = autoclass('java.io.File') 8 | Interpreter = autoclass('org.tensorflow.lite.Interpreter') 9 | InterpreterOptions = autoclass('org.tensorflow.lite.Interpreter$Options') 10 | Tensor = autoclass('org.tensorflow.lite.Tensor') 11 | DataType = autoclass('org.tensorflow.lite.DataType') 12 | TensorBuffer = autoclass( 13 | 'org.tensorflow.lite.support.tensorbuffer.TensorBuffer') 14 | ByteBuffer = autoclass('java.nio.ByteBuffer') 15 | 16 | # dummy import so buildozer isn't cutting it away since it's used by options.setNumThreads 17 | InterpreterApiOptions = autoclass('org.tensorflow.lite.InterpreterApi$Options') 18 | 19 | class TensorFlowModel(): 20 | def load(self, model_filename, num_threads=None): 21 | model = File(model_filename) 22 | options = InterpreterOptions() 23 | if num_threads is not None: 24 | options.setNumThreads(num_threads) 25 | self.interpreter = Interpreter(model, options) 26 | self.allocate_tensors() 27 | 28 | def allocate_tensors(self): 29 | self.interpreter.allocateTensors() 30 | self.input_shape = self.interpreter.getInputTensor(0).shape() 31 | self.output_shape = self.interpreter.getOutputTensor(0).shape() 32 | self.output_type = self.interpreter.getOutputTensor(0).dataType() 33 | 34 | def get_input_shape(self): 35 | return self.input_shape 36 | 37 | def resize_input(self, shape): 38 | if self.input_shape != shape: 39 | self.interpreter.resizeInput(0, shape) 40 | self.allocate_tensors() 41 | 42 | def pred(self, x): 43 | # assumes one input and one output for now 44 | input = ByteBuffer.wrap(x.tobytes()) 45 | output = TensorBuffer.createFixedSize(self.output_shape, 46 | self.output_type) 47 | self.interpreter.run(input, output.getBuffer().rewind()) 48 | return np.reshape(np.array(output.getFloatArray()), 49 | self.output_shape) 50 | 51 | elif platform == 'ios': 52 | from pyobjus import autoclass, objc_arr 53 | from ctypes import c_float, cast, POINTER 54 | 55 | NSString = autoclass('NSString') 56 | NSError = autoclass('NSError') 57 | Interpreter = autoclass('TFLInterpreter') 58 | InterpreterOptions = autoclass('TFLInterpreterOptions') 59 | NSData = autoclass('NSData') 60 | NSMutableArray = autoclass("NSMutableArray") 61 | 62 | class TensorFlowModel: 63 | def load(self, model_filename, num_threads=None): 64 | self.error = NSError.alloc() 65 | model = NSString.stringWithUTF8String_(model_filename) 66 | options = InterpreterOptions.alloc().init() 67 | if num_threads is not None: 68 | options.numberOfThreads = num_threads 69 | self.interpreter = Interpreter.alloc( 70 | ).initWithModelPath_options_error_(model, options, self.error) 71 | self.allocate_tensors() 72 | 73 | def allocate_tensors(self): 74 | self.interpreter.allocateTensorsWithError_(self.error) 75 | self.input_shape = self.interpreter.inputTensorAtIndex_error_( 76 | 0, self.error).shapeWithError_(self.error) 77 | self.input_shape = [ 78 | self.input_shape.objectAtIndex_(_).intValue() 79 | for _ in range(self.input_shape.count()) 80 | ] 81 | self.output_shape = self.interpreter.outputTensorAtIndex_error_( 82 | 0, self.error).shapeWithError_(self.error) 83 | self.output_shape = [ 84 | self.output_shape.objectAtIndex_(_).intValue() 85 | for _ in range(self.output_shape.count()) 86 | ] 87 | self.output_type = self.interpreter.outputTensorAtIndex_error_( 88 | 0, self.error).dataType 89 | 90 | def get_input_shape(self): 91 | return self.input_shape 92 | 93 | def resize_input(self, shape): 94 | if self.input_shape != shape: 95 | # workaround as objc_arr doesn't work as expected on iPhone 96 | array = NSMutableArray.new() 97 | for x in shape: 98 | array.addObject_(x) 99 | self.interpreter.resizeInputTensorAtIndex_toShape_error_( 100 | 0, array, self.error) 101 | self.allocate_tensors() 102 | 103 | def pred(self, x): 104 | # assumes one input and one output for now 105 | bytestr = x.tobytes() 106 | # must cast to ctype._SimpleCData so that pyobjus passes pointer 107 | floatbuf = cast(bytestr, POINTER(c_float)).contents 108 | data = NSData.dataWithBytes_length_(floatbuf, len(bytestr)) 109 | print(dir(self.interpreter)) 110 | self.interpreter.copyData_toInputTensor_error_( 111 | data, self.interpreter.inputTensorAtIndex_error_( 112 | 0, self.error), self.error) 113 | self.interpreter.invokeWithError_(self.error) 114 | output = self.interpreter.outputTensorAtIndex_error_( 115 | 0, self.error).dataWithError_(self.error).bytes() 116 | # have to do this to avoid memory leaks... 117 | while data.retainCount() > 1: 118 | data.release() 119 | return np.reshape( 120 | np.frombuffer( 121 | (c_float * np.prod(self.output_shape)).from_address( 122 | output.arg_ref), c_float), self.output_shape) 123 | 124 | else: 125 | import tensorflow as tf 126 | 127 | class TensorFlowModel: 128 | def load(self, model_filename, num_threads=None): 129 | self.interpreter = tf.lite.Interpreter(model_filename, 130 | num_threads=num_threads) 131 | self.interpreter.allocate_tensors() 132 | 133 | def resize_input(self, shape): 134 | if list(self.get_input_shape()) != shape: 135 | self.interpreter.resize_tensor_input(0, shape) 136 | self.interpreter.allocate_tensors() 137 | 138 | def get_input_shape(self): 139 | return self.interpreter.get_input_details()[0]['shape'] 140 | 141 | def pred(self, x): 142 | # assumes one input and one output for now 143 | self.interpreter.set_tensor( 144 | self.interpreter.get_input_details()[0]['index'], x) 145 | self.interpreter.invoke() 146 | return self.interpreter.get_tensor( 147 | self.interpreter.get_output_details()[0]['index']) -------------------------------------------------------------------------------- /notebooks/Create_TFLite_model.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "### Dummy model" 8 | ] 9 | }, 10 | { 11 | "cell_type": "code", 12 | "execution_count": 30, 13 | "metadata": {}, 14 | "outputs": [], 15 | "source": [ 16 | "import tensorflow as tf" 17 | ] 18 | }, 19 | { 20 | "cell_type": "code", 21 | "execution_count": 36, 22 | "metadata": {}, 23 | "outputs": [], 24 | "source": [ 25 | "model = tf.keras.models.Sequential([\n", 26 | " tf.keras.layers.Flatten(input_shape=(28, 28)),\n", 27 | " tf.keras.layers.Dense(10)\n", 28 | "])" 29 | ] 30 | }, 31 | { 32 | "cell_type": "markdown", 33 | "metadata": {}, 34 | "source": [ 35 | "### Make a random prediction for testing purposes" 36 | ] 37 | }, 38 | { 39 | "cell_type": "code", 40 | "execution_count": 37, 41 | "metadata": {}, 42 | "outputs": [ 43 | { 44 | "data": { 45 | "text/plain": [ 46 | "array([[[0.37454012, 0.9507143 , 0.7319939 , 0.5986585 , 0.15601864,\n", 47 | " 0.15599452, 0.05808361, 0.8661761 , 0.601115 , 0.7080726 ,\n", 48 | " 0.02058449, 0.96990985, 0.83244264, 0.21233912, 0.18182497,\n", 49 | " 0.1834045 , 0.30424225, 0.52475643, 0.43194503, 0.29122913,\n", 50 | " 0.6118529 , 0.13949387, 0.29214466, 0.36636186, 0.45606998,\n", 51 | " 0.785176 , 0.19967379, 0.5142344 ],\n", 52 | " [0.59241456, 0.04645041, 0.60754484, 0.17052412, 0.06505159,\n", 53 | " 0.94888556, 0.965632 , 0.80839735, 0.30461377, 0.09767211,\n", 54 | " 0.684233 , 0.4401525 , 0.12203824, 0.4951769 , 0.03438852,\n", 55 | " 0.9093204 , 0.25877997, 0.66252226, 0.31171107, 0.52006805,\n", 56 | " 0.54671025, 0.18485446, 0.96958464, 0.77513283, 0.93949896,\n", 57 | " 0.89482737, 0.5979 , 0.9218742 ],\n", 58 | " [0.08849251, 0.19598286, 0.04522729, 0.32533032, 0.3886773 ,\n", 59 | " 0.27134904, 0.8287375 , 0.35675332, 0.2809345 , 0.54269606,\n", 60 | " 0.14092423, 0.802197 , 0.07455064, 0.9868869 , 0.77224475,\n", 61 | " 0.19871569, 0.00552212, 0.81546146, 0.7068573 , 0.7290072 ,\n", 62 | " 0.77127033, 0.07404465, 0.35846573, 0.11586906, 0.86310345,\n", 63 | " 0.6232981 , 0.33089802, 0.06355835],\n", 64 | " [0.31098232, 0.32518333, 0.72960615, 0.63755745, 0.88721275,\n", 65 | " 0.47221494, 0.11959425, 0.7132448 , 0.76078504, 0.5612772 ,\n", 66 | " 0.7709672 , 0.4937956 , 0.52273285, 0.42754102, 0.02541913,\n", 67 | " 0.10789143, 0.03142919, 0.6364104 , 0.31435597, 0.5085707 ,\n", 68 | " 0.9075665 , 0.24929222, 0.41038293, 0.75555116, 0.22879817,\n", 69 | " 0.07697991, 0.28975144, 0.16122128],\n", 70 | " [0.92969763, 0.80812037, 0.6334038 , 0.8714606 , 0.8036721 ,\n", 71 | " 0.18657006, 0.892559 , 0.5393422 , 0.80744016, 0.8960913 ,\n", 72 | " 0.31800348, 0.11005192, 0.22793517, 0.42710778, 0.81801474,\n", 73 | " 0.8607306 , 0.00695213, 0.5107473 , 0.417411 , 0.22210781,\n", 74 | " 0.11986537, 0.33761516, 0.9429097 , 0.32320294, 0.5187906 ,\n", 75 | " 0.70301896, 0.3636296 , 0.9717821 ],\n", 76 | " [0.9624473 , 0.2517823 , 0.4972485 , 0.30087832, 0.2848405 ,\n", 77 | " 0.03688695, 0.6095643 , 0.50267905, 0.05147875, 0.27864647,\n", 78 | " 0.9082659 , 0.23956189, 0.14489487, 0.48945275, 0.9856505 ,\n", 79 | " 0.24205527, 0.67213553, 0.7616196 , 0.23763755, 0.72821635,\n", 80 | " 0.36778313, 0.6323058 , 0.6335297 , 0.5357747 , 0.09028977,\n", 81 | " 0.8353025 , 0.32078007, 0.1865185 ],\n", 82 | " [0.04077514, 0.590893 , 0.6775644 , 0.01658783, 0.51209307,\n", 83 | " 0.22649577, 0.6451728 , 0.17436643, 0.69093776, 0.38673535,\n", 84 | " 0.93672997, 0.13752094, 0.34106636, 0.11347352, 0.92469364,\n", 85 | " 0.87733936, 0.25794163, 0.65998405, 0.8172222 , 0.5552008 ,\n", 86 | " 0.52965057, 0.24185228, 0.09310277, 0.8972158 , 0.90041804,\n", 87 | " 0.63310146, 0.3390298 , 0.34920958],\n", 88 | " [0.72595567, 0.8971103 , 0.88708645, 0.7798755 , 0.64203167,\n", 89 | " 0.08413997, 0.16162871, 0.8985542 , 0.60642904, 0.00919705,\n", 90 | " 0.10147154, 0.66350174, 0.00506158, 0.16080806, 0.5487338 ,\n", 91 | " 0.6918952 , 0.65196127, 0.22426932, 0.71217924, 0.23724909,\n", 92 | " 0.3253997 , 0.74649143, 0.6496329 , 0.84922343, 0.6576129 ,\n", 93 | " 0.5683086 , 0.09367477, 0.3677158 ],\n", 94 | " [0.26520237, 0.24398965, 0.97301054, 0.39309773, 0.8920466 ,\n", 95 | " 0.6311386 , 0.7948113 , 0.5026371 , 0.5769039 , 0.49251768,\n", 96 | " 0.19524299, 0.7224521 , 0.28077236, 0.02431597, 0.6454723 ,\n", 97 | " 0.17711067, 0.9404586 , 0.9539286 , 0.91486436, 0.3701587 ,\n", 98 | " 0.01545662, 0.92831856, 0.42818415, 0.96665484, 0.96361995,\n", 99 | " 0.85300946, 0.29444888, 0.38509774],\n", 100 | " [0.8511367 , 0.316922 , 0.16949275, 0.55680126, 0.9361548 ,\n", 101 | " 0.6960298 , 0.57006115, 0.09717649, 0.6150072 , 0.99005383,\n", 102 | " 0.14008401, 0.5183297 , 0.8773731 , 0.7407686 , 0.69701576,\n", 103 | " 0.7024841 , 0.35949114, 0.29359186, 0.80936116, 0.8101134 ,\n", 104 | " 0.86707234, 0.91324055, 0.5113424 , 0.5015163 , 0.7982952 ,\n", 105 | " 0.6499639 , 0.7019669 , 0.7957927 ],\n", 106 | " [0.89000535, 0.33799517, 0.37558296, 0.09398194, 0.57828015,\n", 107 | " 0.03594228, 0.46559802, 0.5426446 , 0.28654125, 0.59083325,\n", 108 | " 0.03050025, 0.03734819, 0.82260054, 0.36019063, 0.12706052,\n", 109 | " 0.52224326, 0.76999354, 0.21582103, 0.6228905 , 0.08534747,\n", 110 | " 0.05168172, 0.5313546 , 0.5406351 , 0.6374299 , 0.7260913 ,\n", 111 | " 0.9758521 , 0.5163003 , 0.32295647],\n", 112 | " [0.7951862 , 0.27083224, 0.43897143, 0.07845638, 0.02535074,\n", 113 | " 0.9626484 , 0.8359801 , 0.69597423, 0.40895295, 0.17329432,\n", 114 | " 0.15643704, 0.2502429 , 0.54922664, 0.7145959 , 0.6601974 ,\n", 115 | " 0.2799339 , 0.9548653 , 0.7378969 , 0.5543541 , 0.61172074,\n", 116 | " 0.41960007, 0.24773099, 0.35597268, 0.7578461 , 0.01439349,\n", 117 | " 0.11607264, 0.04600264, 0.0407288 ],\n", 118 | " [0.8554606 , 0.70365787, 0.47417384, 0.09783416, 0.49161586,\n", 119 | " 0.47347176, 0.17320187, 0.43385166, 0.39850473, 0.6158501 ,\n", 120 | " 0.6350936 , 0.04530401, 0.37461263, 0.6258599 , 0.5031363 ,\n", 121 | " 0.85648984, 0.6586936 , 0.16293442, 0.07056875, 0.6424193 ,\n", 122 | " 0.02651131, 0.58577555, 0.94023025, 0.5754742 , 0.3881699 ,\n", 123 | " 0.6432882 , 0.45825288, 0.5456168 ],\n", 124 | " [0.9414648 , 0.38610265, 0.9611906 , 0.9053506 , 0.19579114,\n", 125 | " 0.0693613 , 0.100778 , 0.01822183, 0.09444296, 0.68300676,\n", 126 | " 0.07118865, 0.31897563, 0.84487534, 0.02327194, 0.8144685 ,\n", 127 | " 0.28185478, 0.11816483, 0.6967372 , 0.62894285, 0.87747204,\n", 128 | " 0.73507106, 0.8034809 , 0.28203458, 0.17743954, 0.75061476,\n", 129 | " 0.80683476, 0.99050516, 0.41261768],\n", 130 | " [0.3720181 , 0.77641296, 0.34080353, 0.93075734, 0.85841274,\n", 131 | " 0.42899403, 0.75087106, 0.7545429 , 0.10312387, 0.9025529 ,\n", 132 | " 0.50525236, 0.82645744, 0.3200496 , 0.89552325, 0.38920167,\n", 133 | " 0.01083765, 0.905382 , 0.09128667, 0.31931365, 0.950062 ,\n", 134 | " 0.9506071 , 0.57343787, 0.6318372 , 0.44844553, 0.29321077,\n", 135 | " 0.32866454, 0.67251843, 0.75237453],\n", 136 | " [0.79157907, 0.78961813, 0.0912061 , 0.4944203 , 0.05755876,\n", 137 | " 0.5495289 , 0.4415305 , 0.8877042 , 0.350915 , 0.11706702,\n", 138 | " 0.14299168, 0.7615106 , 0.61821806, 0.10112268, 0.0841068 ,\n", 139 | " 0.70096916, 0.072763 , 0.8218601 , 0.7062422 , 0.08134878,\n", 140 | " 0.08483771, 0.98663956, 0.3742708 , 0.37064216, 0.8127996 ,\n", 141 | " 0.9472486 , 0.9860011 , 0.7533782 ],\n", 142 | " [0.3762596 , 0.08350071, 0.77714694, 0.55840427, 0.42422202,\n", 143 | " 0.90635437, 0.11119748, 0.49262512, 0.01135364, 0.46866065,\n", 144 | " 0.05630327, 0.11881792, 0.11752625, 0.6492103 , 0.7460449 ,\n", 145 | " 0.5833688 , 0.96217257, 0.37487057, 0.2857121 , 0.8685991 ,\n", 146 | " 0.22359584, 0.96322256, 0.01215447, 0.96987885, 0.04315991,\n", 147 | " 0.89114314, 0.5277011 , 0.9929648 ],\n", 148 | " [0.07379656, 0.5538543 , 0.96930254, 0.5230979 , 0.62939864,\n", 149 | " 0.6957487 , 0.45454106, 0.62755805, 0.5843143 , 0.90115803,\n", 150 | " 0.04544638, 0.28096318, 0.9504115 , 0.8902638 , 0.45565677,\n", 151 | " 0.6201326 , 0.27738118, 0.18812115, 0.46369842, 0.35335222,\n", 152 | " 0.58365613, 0.07773463, 0.9743948 , 0.98621076, 0.6981617 ,\n", 153 | " 0.5360964 , 0.3095276 , 0.81379503],\n", 154 | " [0.6847312 , 0.16261694, 0.9109272 , 0.82253724, 0.9497999 ,\n", 155 | " 0.7257195 , 0.6134152 , 0.41824305, 0.93272847, 0.8660639 ,\n", 156 | " 0.04521867, 0.02636698, 0.37646335, 0.8105533 , 0.98727614,\n", 157 | " 0.1504169 , 0.5941307 , 0.38089085, 0.9699144 , 0.8421189 ,\n", 158 | " 0.8383287 , 0.46869317, 0.4148195 , 0.27340707, 0.0563755 ,\n", 159 | " 0.8647224 , 0.812901 , 0.99971765],\n", 160 | " [0.9966368 , 0.5554317 , 0.7689874 , 0.94476575, 0.8496474 ,\n", 161 | " 0.2473481 , 0.45054415, 0.12915942, 0.954051 , 0.60617465,\n", 162 | " 0.2286428 , 0.67170066, 0.61812824, 0.35816273, 0.11355759,\n", 163 | " 0.6715732 , 0.5203077 , 0.77231836, 0.5201635 , 0.8521815 ,\n", 164 | " 0.5519068 , 0.560938 , 0.8766536 , 0.40348285, 0.13401523,\n", 165 | " 0.02878268, 0.75513726, 0.62030953],\n", 166 | " [0.70407975, 0.21296416, 0.13637148, 0.01454467, 0.35058755,\n", 167 | " 0.58991766, 0.39224404, 0.43747494, 0.9041587 , 0.34825546,\n", 168 | " 0.5139895 , 0.783653 , 0.3965428 , 0.6220867 , 0.8623637 ,\n", 169 | " 0.94952065, 0.14707348, 0.92658764, 0.4921163 , 0.2582444 ,\n", 170 | " 0.45913577, 0.98003256, 0.49261808, 0.32875162, 0.63340086,\n", 171 | " 0.24014562, 0.07586333, 0.12887973],\n", 172 | " [0.12804584, 0.15190269, 0.13882717, 0.64087474, 0.18188009,\n", 173 | " 0.34566727, 0.8967884 , 0.47396165, 0.6675577 , 0.17231987,\n", 174 | " 0.19228902, 0.04086862, 0.16893506, 0.27859035, 0.17701049,\n", 175 | " 0.08870254, 0.12063587, 0.46077877, 0.20633371, 0.36426985,\n", 176 | " 0.50341725, 0.6903948 , 0.03931214, 0.7994104 , 0.62790036,\n", 177 | " 0.08175904, 0.8735786 , 0.9208724 ],\n", 178 | " [0.06107796, 0.27687764, 0.8062013 , 0.74825966, 0.18452102,\n", 179 | " 0.20934932, 0.3704721 , 0.484523 , 0.6182548 , 0.36891365,\n", 180 | " 0.46253473, 0.7474709 , 0.0366832 , 0.25243694, 0.7133496 ,\n", 181 | " 0.8952068 , 0.51167744, 0.5321135 , 0.10717201, 0.44741237,\n", 182 | " 0.5326173 , 0.2424705 , 0.26924324, 0.37728417, 0.0200712 ,\n", 183 | " 0.32207915, 0.21144801, 0.32749736],\n", 184 | " [0.11976213, 0.8905273 , 0.59359246, 0.6791023 , 0.7891712 ,\n", 185 | " 0.4984422 , 0.08692029, 0.5371065 , 0.5868411 , 0.74543947,\n", 186 | " 0.43165955, 0.1275803 , 0.2837759 , 0.3630823 , 0.64591724,\n", 187 | " 0.5707783 , 0.3560967 , 0.9865152 , 0.6057748 , 0.2372268 ,\n", 188 | " 0.10178247, 0.15285914, 0.24595773, 0.16068137, 0.18656702,\n", 189 | " 0.28509516, 0.1733736 , 0.8967654 ],\n", 190 | " [0.08023375, 0.5245114 , 0.4103968 , 0.9823786 , 0.1120389 ,\n", 191 | " 0.3978556 , 0.96947044, 0.8655071 , 0.8170721 , 0.25790283,\n", 192 | " 0.17088759, 0.66864324, 0.929376 , 0.5567629 , 0.5716127 ,\n", 193 | " 0.27997908, 0.7694929 , 0.18704374, 0.32367924, 0.42543644,\n", 194 | " 0.5076104 , 0.24240974, 0.11483683, 0.61062 , 0.28863055,\n", 195 | " 0.5812382 , 0.15436271, 0.4811401 ],\n", 196 | " [0.53258944, 0.05182354, 0.33660427, 0.13441467, 0.06337497,\n", 197 | " 0.98996025, 0.32235384, 0.8098745 , 0.25464067, 0.6815027 ,\n", 198 | " 0.76022786, 0.59563875, 0.47157618, 0.41184092, 0.34886828,\n", 199 | " 0.92952913, 0.8306194 , 0.9650269 , 0.12429722, 0.73086745,\n", 200 | " 0.9383405 , 0.18123306, 0.06649627, 0.74112064, 0.57447314,\n", 201 | " 0.84182876, 0.13977237, 0.7952673 ],\n", 202 | " [0.20162731, 0.16365594, 0.1642658 , 0.8145747 , 0.6651972 ,\n", 203 | " 0.52306545, 0.35883048, 0.87720054, 0.39244512, 0.8165994 ,\n", 204 | " 0.4391349 , 0.37694442, 0.46267977, 0.30137786, 0.7476094 ,\n", 205 | " 0.5027204 , 0.23221269, 0.8995746 , 0.38389122, 0.5435529 ,\n", 206 | " 0.9064721 , 0.624238 , 0.11689804, 0.93983215, 0.6277081 ,\n", 207 | " 0.33490562, 0.13927208, 0.7940252 ],\n", 208 | " [0.6200728 , 0.5334611 , 0.8938926 , 0.7885972 , 0.15167488,\n", 209 | " 0.31172207, 0.24848914, 0.7439463 , 0.03353243, 0.56988966,\n", 210 | " 0.7624587 , 0.8767656 , 0.34208176, 0.8212573 , 0.11063173,\n", 211 | " 0.8464523 , 0.12748866, 0.39728728, 0.7972954 , 0.14991742,\n", 212 | " 0.2292514 , 0.72225255, 0.72003657, 0.6411476 , 0.69394845,\n", 213 | " 0.54272443, 0.25179905, 0.345696 ]]], dtype=float32)" 214 | ] 215 | }, 216 | "execution_count": 37, 217 | "metadata": {}, 218 | "output_type": "execute_result" 219 | } 220 | ], 221 | "source": [ 222 | "import numpy as np\n", 223 | "np.random.seed(42)\n", 224 | "x = np.array(np.random.random_sample((1, 28, 28)), np.float32)\n", 225 | "x" 226 | ] 227 | }, 228 | { 229 | "cell_type": "code", 230 | "execution_count": 40, 231 | "metadata": {}, 232 | "outputs": [ 233 | { 234 | "data": { 235 | "text/plain": [ 236 | "array([[ 0.01647118, 1.0278152 , -0.7065112 , -1.0278157 , 0.12216613,\n", 237 | " 0.37980393, 0.5839217 , -0.04283606, -0.04240461, -0.58534086]],\n", 238 | " dtype=float32)" 239 | ] 240 | }, 241 | "execution_count": 40, 242 | "metadata": {}, 243 | "output_type": "execute_result" 244 | } 245 | ], 246 | "source": [ 247 | "model.predict(x)" 248 | ] 249 | }, 250 | { 251 | "cell_type": "markdown", 252 | "metadata": {}, 253 | "source": [ 254 | "### Create a TFLite model" 255 | ] 256 | }, 257 | { 258 | "cell_type": "code", 259 | "execution_count": 41, 260 | "metadata": {}, 261 | "outputs": [ 262 | { 263 | "name": "stdout", 264 | "output_type": "stream", 265 | "text": [ 266 | "INFO:tensorflow:Assets written to: /tmp/tmpqx3v7ldz/assets\n" 267 | ] 268 | }, 269 | { 270 | "name": "stderr", 271 | "output_type": "stream", 272 | "text": [ 273 | "INFO:tensorflow:Assets written to: /tmp/tmpqx3v7ldz/assets\n" 274 | ] 275 | } 276 | ], 277 | "source": [ 278 | "converter = tf.lite.TFLiteConverter.from_keras_model(model)\n", 279 | "tflite_model = converter.convert()\n", 280 | "with open('../model.tflite', 'wb') as f:\n", 281 | " f.write(tflite_model)" 282 | ] 283 | }, 284 | { 285 | "cell_type": "code", 286 | "execution_count": null, 287 | "metadata": {}, 288 | "outputs": [], 289 | "source": [] 290 | } 291 | ], 292 | "metadata": { 293 | "kernelspec": { 294 | "display_name": "Python 3", 295 | "language": "python", 296 | "name": "python3" 297 | }, 298 | "language_info": { 299 | "codemirror_mode": { 300 | "name": "ipython", 301 | "version": 3 302 | }, 303 | "file_extension": ".py", 304 | "mimetype": "text/x-python", 305 | "name": "python", 306 | "nbconvert_exporter": "python", 307 | "pygments_lexer": "ipython3", 308 | "version": "3.8.5" 309 | } 310 | }, 311 | "nbformat": 4, 312 | "nbformat_minor": 4 313 | } 314 | --------------------------------------------------------------------------------