| @@ -72,7 +72,7 @@ namespace Tensorflow.Keras.Common | |||
| } | |||
| if (dims is null) | |||
| { | |||
| throw new ValueError("Cannot deserialize 'null' to `Shape`."); | |||
| return null; | |||
| } | |||
| long[] convertedDims = new long[dims.Length]; | |||
| for(int i = 0; i < dims.Length; i++) | |||
| @@ -19,6 +19,7 @@ using Newtonsoft.Json.Linq; | |||
| using System; | |||
| using System.Collections; | |||
| using System.Collections.Generic; | |||
| using System.Data; | |||
| using System.Diagnostics; | |||
| using System.Linq; | |||
| using Tensorflow.Keras.ArgsDefinition; | |||
| @@ -65,6 +66,10 @@ namespace Tensorflow.Keras.Utils | |||
| "ELU" => new ELU(config.ToObject<ELUArgs>()), | |||
| "Dense" => new Dense(config.ToObject<DenseArgs>()), | |||
| "Softmax" => new Softmax(config.ToObject<SoftmaxArgs>()), | |||
| "Conv2D" => new Conv2D(config.ToObject<Conv2DArgs>()), | |||
| "BatchNormalization" => new BatchNormalization(config.ToObject<BatchNormalizationArgs>()), | |||
| "MaxPooling2D" => new MaxPooling2D(config.ToObject<MaxPooling2DArgs>()), | |||
| "Dropout" => new Dropout(config.ToObject<DropoutArgs>()), | |||
| _ => throw new NotImplementedException($"The deserialization of <{class_name}> has not been supported. Usually it's a miss during the development. " + | |||
| $"Please submit an issue to https://github.com/SciSharp/TensorFlow.NET/issues") | |||
| }; | |||
| @@ -80,6 +85,10 @@ namespace Tensorflow.Keras.Utils | |||
| "ELU" => new ELU(args as ELUArgs), | |||
| "Dense" => new Dense(args as DenseArgs), | |||
| "Softmax" => new Softmax(args as SoftmaxArgs), | |||
| "Conv2D" => new Conv2D(args as Conv2DArgs), | |||
| "BatchNormalization" => new BatchNormalization(args as BatchNormalizationArgs), | |||
| "MaxPooling2D" => new MaxPooling2D(args as MaxPooling2DArgs), | |||
| "Dropout" => new Dropout(args as DropoutArgs), | |||
| _ => throw new NotImplementedException($"The deserialization of <{class_name}> has not been supported. Usually it's a miss during the development. " + | |||
| $"Please submit an issue to https://github.com/SciSharp/TensorFlow.NET/issues") | |||
| }; | |||
| @@ -95,6 +104,10 @@ namespace Tensorflow.Keras.Utils | |||
| "ELU" => config.ToObject<ELUArgs>(), | |||
| "Dense" => config.ToObject<DenseArgs>(), | |||
| "Softmax" => config.ToObject<SoftmaxArgs>(), | |||
| "Conv2D" => config.ToObject<Conv2DArgs>(), | |||
| "BatchNormalization" => config.ToObject<BatchNormalizationArgs>(), | |||
| "MaxPooling2D" => config.ToObject<MaxPooling2DArgs>(), | |||
| "Dropout" => config.ToObject<DropoutArgs>(), | |||
| _ => throw new NotImplementedException($"The deserialization of <{class_name}> has not been supported. Usually it's a miss during the development. " + | |||
| $"Please submit an issue to https://github.com/SciSharp/TensorFlow.NET/issues") | |||
| }; | |||
| @@ -0,0 +1,9 @@ | |||
| ´$root"_tf_keras_network*’${"name": "model", "trainable": true, "expects_training_arg": true, "dtype": "float32", "batch_input_shape": null, "must_restore_from_config": false, "preserve_input_structure_in_config": false, "autocast": false, "class_name": "Functional", "config": {"name": "model", "layers": [{"class_name": "InputLayer", "config": {"batch_input_shape": {"class_name": "__tuple__", "items": [null, 28, 28, 1]}, "dtype": "float32", "sparse": false, "ragged": false, "name": "input_1"}, "name": "input_1", "inbound_nodes": []}, {"class_name": "Flatten", "config": {"name": "flatten", "trainable": true, "dtype": "float32", "data_format": "channels_last"}, "name": "flatten", "inbound_nodes": [[["input_1", 0, 0, {}]]]}, {"class_name": "Dense", "config": {"name": "dense", "trainable": true, "dtype": "float32", "units": 100, "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}, "name": "dense", "inbound_nodes": [[["flatten", 0, 0, {}]]]}, {"class_name": "Dense", "config": {"name": "dense_1", "trainable": true, "dtype": "float32", "units": 10, "activation": "linear", "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}, "name": "dense_1", "inbound_nodes": [[["dense", 0, 0, {}]]]}, {"class_name": "Softmax", "config": {"name": "softmax", "trainable": true, "dtype": "float32", "axis": -1}, "name": "softmax", "inbound_nodes": [[["dense_1", 0, 0, {}]]]}], "input_layers": [["input_1", 0, 0]], "output_layers": [["softmax", 0, 0]]}, "shared_object_id": 9, "input_spec": [{"class_name": "InputSpec", "config": {"dtype": null, "shape": {"class_name": "__tuple__", "items": [null, 28, 28, 1]}, "ndim": 4, "max_ndim": null, "min_ndim": null, "axes": {}}}], "build_input_shape": {"class_name": "TensorShape", "items": [null, 28, 28, 1]}, "is_graph_network": true, "full_save_spec": {"class_name": "__tuple__", "items": [[{"class_name": "TypeSpec", "type_spec": "tf.TensorSpec", "serialized": [{"class_name": "TensorShape", "items": [null, 28, 28, 1]}, "float32", "input_1"]}], {}]}, "save_spec": {"class_name": "TypeSpec", "type_spec": "tf.TensorSpec", "serialized": [{"class_name": "TensorShape", "items": [null, 28, 28, 1]}, "float32", "input_1"]}, "keras_version": "2.11.0", "backend": "tensorflow", "model_config": {"class_name": "Functional", "config": {"name": "model", "layers": [{"class_name": "InputLayer", "config": {"batch_input_shape": {"class_name": "__tuple__", "items": [null, 28, 28, 1]}, "dtype": "float32", "sparse": false, "ragged": false, "name": "input_1"}, "name": "input_1", "inbound_nodes": [], "shared_object_id": 0}, {"class_name": "Flatten", "config": {"name": "flatten", "trainable": true, "dtype": "float32", "data_format": "channels_last"}, "name": "flatten", "inbound_nodes": [[["input_1", 0, 0, {}]]], "shared_object_id": 1}, {"class_name": "Dense", "config": {"name": "dense", "trainable": true, "dtype": "float32", "units": 100, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}, "shared_object_id": 2}, "bias_initializer": {"class_name": "Zeros", "config": {}, "shared_object_id": 3}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "name": "dense", "inbound_nodes": [[["flatten", 0, 0, {}]]], "shared_object_id": 4}, {"class_name": "Dense", "config": {"name": "dense_1", "trainable": true, "dtype": "float32", "units": 10, "activation": "linear", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}, "shared_object_id": 5}, "bias_initializer": {"class_name": "Zeros", "config": {}, "shared_object_id": 6}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "name": "dense_1", "inbound_nodes": [[["dense", 0, 0, {}]]], "shared_object_id": 7}, {"class_name": "Softmax", "config": {"name": "softmax", "trainable": true, "dtype": "float32", "axis": -1}, "name": "softmax", "inbound_nodes": [[["dense_1", 0, 0, {}]]], "shared_object_id": 8}], "input_layers": [["input_1", 0, 0]], "output_layers": [["softmax", 0, 0]]}}}2 | |||
| †root.layer-0"_tf_keras_input_layer*Ö{"class_name": "InputLayer", "name": "input_1", "dtype": "float32", "sparse": false, "ragged": false, "batch_input_shape": {"class_name": "__tuple__", "items": [null, 28, 28, 1]}, "config": {"batch_input_shape": {"class_name": "__tuple__", "items": [null, 28, 28, 1]}, "dtype": "float32", "sparse": false, "ragged": false, "name": "input_1"}}2 | |||
| Íroot.layer-1"_tf_keras_layer*£{"name": "flatten", "trainable": true, "expects_training_arg": false, "dtype": "float32", "batch_input_shape": null, "stateful": false, "must_restore_from_config": false, "preserve_input_structure_in_config": false, "autocast": true, "class_name": "Flatten", "config": {"name": "flatten", "trainable": true, "dtype": "float32", "data_format": "channels_last"}, "inbound_nodes": [[["input_1", 0, 0, {}]]], "shared_object_id": 1, "input_spec": {"class_name": "InputSpec", "config": {"dtype": null, "shape": null, "ndim": null, "max_ndim": null, "min_ndim": 1, "axes": {}}, "shared_object_id": 14}, "build_input_shape": {"class_name": "TensorShape", "items": [null, 28, 28, 1]}}2 | |||
| ¯root.layer_with_weights-0"_tf_keras_layer*ø{"name": "dense", "trainable": true, "expects_training_arg": false, "dtype": "float32", "batch_input_shape": null, "stateful": false, "must_restore_from_config": false, "preserve_input_structure_in_config": false, "autocast": true, "class_name": "Dense", "config": {"name": "dense", "trainable": true, "dtype": "float32", "units": 100, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}, "shared_object_id": 2}, "bias_initializer": {"class_name": "Zeros", "config": {}, "shared_object_id": 3}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "inbound_nodes": [[["flatten", 0, 0, {}]]], "shared_object_id": 4, "input_spec": {"class_name": "InputSpec", "config": {"dtype": null, "shape": null, "ndim": null, "max_ndim": null, "min_ndim": 2, "axes": {"-1": 784}}, "shared_object_id": 15}, "build_input_shape": {"class_name": "TensorShape", "items": [null, 784]}}2 | |||
| ²root.layer_with_weights-1"_tf_keras_layer*û{"name": "dense_1", "trainable": true, "expects_training_arg": false, "dtype": "float32", "batch_input_shape": null, "stateful": false, "must_restore_from_config": false, "preserve_input_structure_in_config": false, "autocast": true, "class_name": "Dense", "config": {"name": "dense_1", "trainable": true, "dtype": "float32", "units": 10, "activation": "linear", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}, "shared_object_id": 5}, "bias_initializer": {"class_name": "Zeros", "config": {}, "shared_object_id": 6}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "inbound_nodes": [[["dense", 0, 0, {}]]], "shared_object_id": 7, "input_spec": {"class_name": "InputSpec", "config": {"dtype": null, "shape": null, "ndim": null, "max_ndim": null, "min_ndim": 2, "axes": {"-1": 100}}, "shared_object_id": 16}, "build_input_shape": {"class_name": "TensorShape", "items": [null, 100]}}2 | |||
| Šroot.layer-4"_tf_keras_layer*à{"name": "softmax", "trainable": true, "expects_training_arg": false, "dtype": "float32", "batch_input_shape": null, "stateful": false, "must_restore_from_config": false, "preserve_input_structure_in_config": false, "autocast": true, "class_name": "Softmax", "config": {"name": "softmax", "trainable": true, "dtype": "float32", "axis": -1}, "inbound_nodes": [[["dense_1", 0, 0, {}]]], "shared_object_id": 8, "build_input_shape": {"class_name": "TensorShape", "items": [null, 10]}}2 | |||
| ¹Troot.keras_api.metrics.0"_tf_keras_metric*‚{"class_name": "Mean", "name": "loss", "dtype": "float32", "config": {"name": "loss", "dtype": "float32"}, "shared_object_id": 17}2 | |||
| ™Uroot.keras_api.metrics.1"_tf_keras_metric*â{"class_name": "MeanMetricWrapper", "name": "sparse_categorical_accuracy", "dtype": "float32", "config": {"name": "sparse_categorical_accuracy", "dtype": "float32", "fn": "sparse_categorical_accuracy"}, "shared_object_id": 18}2 | |||
| @@ -12,6 +12,8 @@ using Tensorflow.Keras.Metrics; | |||
| using Tensorflow; | |||
| using Tensorflow.Keras.Optimizers; | |||
| using static Tensorflow.KerasApi; | |||
| using Tensorflow.NumPy; | |||
| using static TensorFlowNET.Keras.UnitTest.SaveModel.SequentialModelSave; | |||
| namespace TensorFlowNET.Keras.UnitTest.SaveModel; | |||
| @@ -19,15 +21,20 @@ namespace TensorFlowNET.Keras.UnitTest.SaveModel; | |||
| public class SequentialModelLoad | |||
| { | |||
| [TestMethod] | |||
| public void SimpleModelFromSequential() | |||
| public void SimpleModelFromAutoCompile() | |||
| { | |||
| //new SequentialModelSave().SimpleModelFromSequential(); | |||
| var model = keras.models.load_model(@"D:\development\tf.net\tf_test\tf.net.simple.sequential"); | |||
| var model = keras.models.load_model(@"Assets/simple_model_from_auto_compile"); | |||
| model.summary(); | |||
| model.compile(new Adam(0.0001f), new LossesApi().SparseCategoricalCrossentropy(), new string[] { "accuracy" }); | |||
| // check the weights | |||
| var kernel1 = np.load(@"Assets/simple_model_from_auto_compile/kernel1.npy"); | |||
| var bias0 = np.load(@"Assets/simple_model_from_auto_compile/bias0.npy"); | |||
| Assert.IsTrue(kernel1.Zip(model.TrainableWeights[2].numpy()).All(x => x.First == x.Second)); | |||
| Assert.IsTrue(bias0.Zip(model.TrainableWeights[1].numpy()).All(x => x.First == x.Second)); | |||
| var data_loader = new MnistModelLoader(); | |||
| var num_epochs = 1; | |||
| var batch_size = 8; | |||
| @@ -40,6 +47,22 @@ public class SequentialModelLoad | |||
| }).Result; | |||
| model.fit(dataset.Train.Data, dataset.Train.Labels, batch_size, num_epochs); | |||
| } | |||
| [TestMethod] | |||
| public void AlexnetFromSequential() | |||
| { | |||
| new SequentialModelSave().AlexnetFromSequential(); | |||
| var model = keras.models.load_model(@"./alexnet_from_sequential"); | |||
| model.summary(); | |||
| model.compile(new Adam(0.001f), new LossesApi().SparseCategoricalCrossentropy(from_logits: true), new string[] { "accuracy" }); | |||
| var num_epochs = 1; | |||
| var batch_size = 8; | |||
| var dataset = new RandomDataSet(new Shape(227, 227, 3), 16); | |||
| model.fit(dataset.Data, dataset.Labels, batch_size, num_epochs); | |||
| } | |||
| } | |||
| @@ -78,7 +78,7 @@ public class SequentialModelSave | |||
| } | |||
| [TestMethod] | |||
| public void AlexModelFromSequential() | |||
| public void AlexnetFromSequential() | |||
| { | |||
| Model model = KerasApi.keras.Sequential(new List<ILayer>() | |||
| { | |||
| @@ -121,7 +121,7 @@ public class SequentialModelSave | |||
| model.fit(dataset.Data, dataset.Labels, batch_size, num_epochs); | |||
| model.save("./pb_alex_sequential", save_format: "tf"); | |||
| model.save("./alexnet_from_sequential", save_format: "tf"); | |||
| // The saved model can be test with the following python code: | |||
| #region alexnet_python_code | |||
| @@ -27,4 +27,28 @@ | |||
| <ProjectReference Include="..\..\src\TensorFlowNET.Keras\Tensorflow.Keras.csproj" /> | |||
| </ItemGroup> | |||
| <ItemGroup> | |||
| <None Update="Assets\simple_model_from_auto_compile\fingerprint.pb"> | |||
| <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> | |||
| </None> | |||
| <None Update="Assets\simple_model_from_auto_compile\keras_metadata.pb"> | |||
| <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> | |||
| </None> | |||
| <None Update="Assets\simple_model_from_auto_compile\saved_model.pb"> | |||
| <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> | |||
| </None> | |||
| <None Update="Assets\simple_model_from_auto_compile\variables\variables.data-00000-of-00001"> | |||
| <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> | |||
| </None> | |||
| <None Update="Assets\simple_model_from_auto_compile\variables\variables.index"> | |||
| <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> | |||
| </None> | |||
| <None Update="Assets\simple_model_from_auto_compile\kernel1.npy"> | |||
| <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> | |||
| </None> | |||
| <None Update="Assets\simple_model_from_auto_compile\bias0.npy"> | |||
| <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> | |||
| </None> | |||
| </ItemGroup> | |||
| </Project> | |||