Skip to content

Commit 36e38f9

Browse files
committed
Add alexnet loading test and check for loaded weights.
1 parent 53baa05 commit 36e38f9

File tree

12 files changed

+77
-8
lines changed

12 files changed

+77
-8
lines changed

src/TensorFlowNET.Core/Keras/Common/CustomizedShapeJsonConverter.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ public override void WriteJson(JsonWriter writer, object? value, JsonSerializer
7272
}
7373
if (dims is null)
7474
{
75-
throw new ValueError("Cannot deserialize 'null' to `Shape`.");
75+
return null;
7676
}
7777
long[] convertedDims = new long[dims.Length];
7878
for(int i = 0; i < dims.Length; i++)

src/TensorFlowNET.Keras/Utils/generic_utils.cs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ limitations under the License.
1919
using System;
2020
using System.Collections;
2121
using System.Collections.Generic;
22+
using System.Data;
2223
using System.Diagnostics;
2324
using System.Linq;
2425
using Tensorflow.Keras.ArgsDefinition;
@@ -65,6 +66,10 @@ public static Layer deserialize_keras_object(string class_name, JToken config)
6566
"ELU" => new ELU(config.ToObject<ELUArgs>()),
6667
"Dense" => new Dense(config.ToObject<DenseArgs>()),
6768
"Softmax" => new Softmax(config.ToObject<SoftmaxArgs>()),
69+
"Conv2D" => new Conv2D(config.ToObject<Conv2DArgs>()),
70+
"BatchNormalization" => new BatchNormalization(config.ToObject<BatchNormalizationArgs>()),
71+
"MaxPooling2D" => new MaxPooling2D(config.ToObject<MaxPooling2DArgs>()),
72+
"Dropout" => new Dropout(config.ToObject<DropoutArgs>()),
6873
_ => throw new NotImplementedException($"The deserialization of <{class_name}> has not been supported. Usually it's a miss during the development. " +
6974
$"Please submit an issue to https://github.com/SciSharp/TensorFlow.NET/issues")
7075
};
@@ -80,6 +85,10 @@ public static Layer deserialize_keras_object(string class_name, LayerArgs args)
8085
"ELU" => new ELU(args as ELUArgs),
8186
"Dense" => new Dense(args as DenseArgs),
8287
"Softmax" => new Softmax(args as SoftmaxArgs),
88+
"Conv2D" => new Conv2D(args as Conv2DArgs),
89+
"BatchNormalization" => new BatchNormalization(args as BatchNormalizationArgs),
90+
"MaxPooling2D" => new MaxPooling2D(args as MaxPooling2DArgs),
91+
"Dropout" => new Dropout(args as DropoutArgs),
8392
_ => throw new NotImplementedException($"The deserialization of <{class_name}> has not been supported. Usually it's a miss during the development. " +
8493
$"Please submit an issue to https://github.com/SciSharp/TensorFlow.NET/issues")
8594
};
@@ -95,6 +104,10 @@ public static Layer deserialize_keras_object(string class_name, LayerArgs args)
95104
"ELU" => config.ToObject<ELUArgs>(),
96105
"Dense" => config.ToObject<DenseArgs>(),
97106
"Softmax" => config.ToObject<SoftmaxArgs>(),
107+
"Conv2D" => config.ToObject<Conv2DArgs>(),
108+
"BatchNormalization" => config.ToObject<BatchNormalizationArgs>(),
109+
"MaxPooling2D" => config.ToObject<MaxPooling2DArgs>(),
110+
"Dropout" => config.ToObject<DropoutArgs>(),
98111
_ => throw new NotImplementedException($"The deserialization of <{class_name}> has not been supported. Usually it's a miss during the development. " +
99112
$"Please submit an issue to https://github.com/SciSharp/TensorFlow.NET/issues")
100113
};
Binary file not shown.
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
2+
�$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
3+
� 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
4+
� 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
5+
�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
6+
�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
7+
� 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
8+
�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
9+
�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

test/TensorFlowNET.Keras.UnitTest/SaveModel/SequentialModelLoad.cs

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,22 +12,29 @@
1212
using Tensorflow;
1313
using Tensorflow.Keras.Optimizers;
1414
using static Tensorflow.KerasApi;
15+
using Tensorflow.NumPy;
16+
using static TensorFlowNET.Keras.UnitTest.SaveModel.SequentialModelSave;
1517

1618
namespace TensorFlowNET.Keras.UnitTest.SaveModel;
1719

1820
[TestClass]
1921
public class SequentialModelLoad
2022
{
2123
[TestMethod]
22-
public void SimpleModelFromSequential()
24+
public void SimpleModelFromAutoCompile()
2325
{
24-
//new SequentialModelSave().SimpleModelFromSequential();
25-
var model = keras.models.load_model(@"D:\development\tf.net\tf_test\tf.net.simple.sequential");
26-
26+
var model = keras.models.load_model(@"Assets/simple_model_from_auto_compile");
2727
model.summary();
2828

2929
model.compile(new Adam(0.0001f), new LossesApi().SparseCategoricalCrossentropy(), new string[] { "accuracy" });
3030

31+
// check the weights
32+
var kernel1 = np.load(@"Assets/simple_model_from_auto_compile/kernel1.npy");
33+
var bias0 = np.load(@"Assets/simple_model_from_auto_compile/bias0.npy");
34+
35+
Assert.IsTrue(kernel1.Zip(model.TrainableWeights[2].numpy()).All(x => x.First == x.Second));
36+
Assert.IsTrue(bias0.Zip(model.TrainableWeights[1].numpy()).All(x => x.First == x.Second));
37+
3138
var data_loader = new MnistModelLoader();
3239
var num_epochs = 1;
3340
var batch_size = 8;
@@ -40,6 +47,22 @@ public void SimpleModelFromSequential()
4047
}).Result;
4148

4249
model.fit(dataset.Train.Data, dataset.Train.Labels, batch_size, num_epochs);
50+
}
51+
52+
[TestMethod]
53+
public void AlexnetFromSequential()
54+
{
55+
new SequentialModelSave().AlexnetFromSequential();
56+
var model = keras.models.load_model(@"./alexnet_from_sequential");
4357
model.summary();
58+
59+
model.compile(new Adam(0.001f), new LossesApi().SparseCategoricalCrossentropy(from_logits: true), new string[] { "accuracy" });
60+
61+
var num_epochs = 1;
62+
var batch_size = 8;
63+
64+
var dataset = new RandomDataSet(new Shape(227, 227, 3), 16);
65+
66+
model.fit(dataset.Data, dataset.Labels, batch_size, num_epochs);
4467
}
4568
}

test/TensorFlowNET.Keras.UnitTest/SaveModel/SequentialModelSave.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ public void SimpleModelFromSequential()
7878
}
7979

8080
[TestMethod]
81-
public void AlexModelFromSequential()
81+
public void AlexnetFromSequential()
8282
{
8383
Model model = KerasApi.keras.Sequential(new List<ILayer>()
8484
{
@@ -121,7 +121,7 @@ public void AlexModelFromSequential()
121121

122122
model.fit(dataset.Data, dataset.Labels, batch_size, num_epochs);
123123

124-
model.save("./pb_alex_sequential", save_format: "tf");
124+
model.save("./alexnet_from_sequential", save_format: "tf");
125125

126126
// The saved model can be test with the following python code:
127127
#region alexnet_python_code

test/TensorFlowNET.Keras.UnitTest/Tensorflow.Keras.UnitTest.csproj

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<Project Sdk="Microsoft.NET.Sdk">
1+
<Project Sdk="Microsoft.NET.Sdk">
22

33
<PropertyGroup>
44
<TargetFramework>net6.0</TargetFramework>
@@ -27,4 +27,28 @@
2727
<ProjectReference Include="..\..\src\TensorFlowNET.Keras\Tensorflow.Keras.csproj" />
2828
</ItemGroup>
2929

30+
<ItemGroup>
31+
<None Update="Assets\simple_model_from_auto_compile\fingerprint.pb">
32+
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
33+
</None>
34+
<None Update="Assets\simple_model_from_auto_compile\keras_metadata.pb">
35+
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
36+
</None>
37+
<None Update="Assets\simple_model_from_auto_compile\saved_model.pb">
38+
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
39+
</None>
40+
<None Update="Assets\simple_model_from_auto_compile\variables\variables.data-00000-of-00001">
41+
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
42+
</None>
43+
<None Update="Assets\simple_model_from_auto_compile\variables\variables.index">
44+
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
45+
</None>
46+
<None Update="Assets\simple_model_from_auto_compile\kernel1.npy">
47+
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
48+
</None>
49+
<None Update="Assets\simple_model_from_auto_compile\bias0.npy">
50+
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
51+
</None>
52+
</ItemGroup>
53+
3054
</Project>

0 commit comments

Comments
 (0)