googlecreativelab / teachablemachine-community

Example code snippets and machine learning code for Teachable Machine
https://g.co/teachablemachine
Apache License 2.0
1.5k stars 669 forks source link

[BUG]: Teachable Machine model.json file not compatible with Tenserflow/Keras Expectations #251

Open MarkKocherovsky opened 2 years ago

MarkKocherovsky commented 2 years ago

Describe the bug

To Reproduce Steps to reproduce the behavior:

  1. download model.json file from a teachable machine model

  2. read it in as a string in python with the following code: with open(modelPath) as f: lines=f.readLines() modelJson = ''.join(lines) model = models.model_from_json(modelJson)

  3. Run the program, receive a ValueError: Improper config format error

Reason for Bug

This occurs because the JSON given by teachable machine is not in the same format as that expected by TF. Tensorflow expects the following format (created by saving a tf model saved as a .h5 as a JSON): { "class_name": "Sequential", "config": { "name": "sequential", "layers": [ { "class_name": "InputLayer", "config": { "batch_input_shape": [ null, 256, 256, 1 ], "dtype": "float32", "sparse": false, "ragged": false, "name": "rescaling_input" } }, { "class_name": "Rescaling", "config": { "name": "rescaling", "trainable": true, "dtype": "float32", "scale": 0.00392156862745098, "offset": 0 } }, { "class_name": "Conv2D", "config": { "name": "conv2d", "trainable": true, "dtype": "float32", "filters": 32, "kernel_size": [ 3, 3 ], "strides": [ 1, 1 ], "padding": "valid", "data_format": "channels_last", "dilation_rate": [ 1, 1 ], "groups": 1, "activation": "relu", "use_bias": true, "kernel_initializer": { "class_name": "GlorotUniform", "config": { "seed": null } }, "bias_initializer": { "class_name": "Zeros", "config": {} }, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null } }, { "class_name": "MaxPooling2D", "config": { "name": "max_pooling2d", "trainable": true, "dtype": "float32", "pool_size": [ 2, 2 ], "padding": "valid", "strides": [ 2, 2 ], "data_format": "channels_last" } }, { "class_name": "Conv2D", "config": { "name": "conv2d_1", "trainable": true, "dtype": "float32", "filters": 32, "kernel_size": [ 3, 3 ], "strides": [ 1, 1 ], "padding": "valid", "data_format": "channels_last", "dilation_rate": [ 1, 1 ], "groups": 1, "activation": "relu", "use_bias": true, "kernel_initializer": { "class_name": "GlorotUniform", "config": { "seed": null } }, "bias_initializer": { "class_name": "Zeros", "config": {} }, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null } }, { "class_name": "MaxPooling2D", "config": { "name": "max_pooling2d_1", "trainable": true, "dtype": "float32", "pool_size": [ 2, 2 ], "padding": "valid", "strides": [ 2, 2 ], "data_format": "channels_last" } }, { "class_name": "Conv2D", "config": { "name": "conv2d_2", "trainable": true, "dtype": "float32", "filters": 32, "kernel_size": [ 3, 3 ], "strides": [ 1, 1 ], "padding": "valid", "data_format": "channels_last", "dilation_rate": [ 1, 1 ], "groups": 1, "activation": "relu", "use_bias": true, "kernel_initializer": { "class_name": "GlorotUniform", "config": { "seed": null } }, "bias_initializer": { "class_name": "Zeros", "config": {} }, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null } }, { "class_name": "MaxPooling2D", "config": { "name": "max_pooling2d_2", "trainable": true, "dtype": "float32", "pool_size": [ 2, 2 ], "padding": "valid", "strides": [ 2, 2 ], "data_format": "channels_last" } }, { "class_name": "Flatten", "config": { "name": "flatten", "trainable": true, "dtype": "float32", "data_format": "channels_last" } }, { "class_name": "Dense", "config": { "name": "dense", "trainable": true, "dtype": "float32", "units": 128, "activation": "relu", "use_bias": true, "kernel_initializer": { "class_name": "GlorotUniform", "config": { "seed": null } }, "bias_initializer": { "class_name": "Zeros", "config": {} }, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null } }, { "class_name": "Dense", "config": { "name": "dense_1", "trainable": true, "dtype": "float32", "units": 4, "activation": "softmax", "use_bias": true, "kernel_initializer": { "class_name": "GlorotUniform", "config": { "seed": null } }, "bias_initializer": { "class_name": "Zeros", "config": {} }, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null } } ] }, "keras_version": "2.6.0", "backend": "tensorflow" }

However, teachable machine has the following format, seen here: { "modelTopology": { "class_name": "Sequential", "config": { "name": "sequential_2", "layers": [ { "class_name": "Dense", "config": { "units": 100, "activation": "relu", "use_bias": true, "kernel_initializer": { "class_name": "VarianceScaling", "config": { "scale": 1, "mode": "fan_in", "distribution": "normal", "seed": null } }, "bias_initializer": { "class_name": "Zeros", "config": {} }, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null, "name": "dense_Dense1", "trainable": true, "batch_input_shape": [ null, 14739 ], "dtype": "float32" } }, { "class_name": "Dropout", "config": { "rate": 0.5, "noise_shape": null, "seed": null, "name": "dropout_Dropout1", "trainable": true } }, { "class_name": "Dense", "config": { "units": 4, "activation": "softmax", "use_bias": false, "kernel_initializer": { "class_name": "VarianceScaling", "config": { "scale": 1, "mode": "fan_in", "distribution": "normal", "seed": null } }, "bias_initializer": { "class_name": "Zeros", "config": {} }, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null, "name": "dense_Dense2", "trainable": true } } ] }, "keras_version": "tfjs-layers 1.3.1", "backend": "tensor_flow.js" }, "format": "layers-model", "generatedBy": "TensorFlow.js tfjs-layers v1.3.1", "convertedBy": null, "weightsManifest": [ { "paths": [ "./model.weights.bin" ], "weights": [ { "name": "dense_Dense1/kernel", "shape": [ 14739, 100 ], "dtype": "float32" }, { "name": "dense_Dense1/bias", "shape": [ 100 ], "dtype": "float32" }, { "name": "dense_Dense2/kernel", "shape": [ 100, 4 ], "dtype": "float32" } ] } ] } The modelTopology section and the data at the bottom is unecessary.

Work Around

We found a work around by simply pruning the model.json file given by TM to the format given in the first example. However, our team believes this to be a problem that should be fixed.

Desktop (please complete the following information):

mukulpatnaik commented 1 year ago

I'm having the same issue. How do I get the weights in a h5 format?