|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354 |
- using System;
- using System.Collections.Generic;
- using System.Text;
- using HDF.PInvoke;
- using Tensorflow.NumPy;
- using HDF5CSharp;
- using static Tensorflow.Binding;
- using static Tensorflow.KerasApi;
- using System.Linq;
- using System.Text.RegularExpressions;
-
- namespace Tensorflow.Keras.Saving
- {
- public class hdf5_format
- {
- private static int HDF5_OBJECT_HEADER_LIMIT = 64512;
- public static void load_model_from_hdf5(string filepath = "", Dictionary<string, object> custom_objects = null, bool compile = false)
- {
- long root = Hdf5.OpenFile(filepath,true);
- load_model_from_hdf5(root, custom_objects, compile);
- }
- public static void load_model_from_hdf5(long filepath = -1, Dictionary<string, object> custom_objects = null, bool compile = false)
- {
- //long fileId = filepath;
- //try
- //{
- // groupId = H5G.open(fileId, "/");
- // (bool success, string[] attrId) = Hdf5.ReadStringAttributes(groupId, "model_config", "");
- // H5G.close(groupId);
- // if (success == true) {
- // Console.WriteLine(attrId[0]);
- // }
- //}
- //catch (Exception ex)
- //{
- // if (filepath != -1) {
- // Hdf5.CloseFile(filepath);
- // }
- // if (groupId != -1) {
- // H5G.close(groupId);
- // }
- // throw new Exception(ex.ToString());
- //}
-
- }
- public static void save_model_to_hdf5(long filepath = -1, Dictionary<string, object> custom_objects = null, bool compile = false)
- {
-
- }
-
- /// <summary>
- /// Preprocess layer weights between different Keras formats.
- /// </summary>
- /// <param name="layer"></param>
- /// <param name="weights"></param>
- /// <param name="original_keras_version"></param>
- /// <param name="original_backend"></param>
- public static List<NDArray> preprocess_weights_for_loading(ILayer layer, List<NDArray> weights, string original_keras_version = null, string original_backend = null)
- {
- // convert CuDNN layers
- return _convert_rnn_weights(layer, weights);
- }
-
- /// <summary>
- /// Converts weights for RNN layers between native and CuDNN format.
- /// </summary>
- /// <param name="layer"></param>
- /// <param name="weights"></param>
- static List<NDArray> _convert_rnn_weights(ILayer layer, List<NDArray> weights)
- {
- var target_class = layer.GetType().Name;
- return weights;
- }
-
- public static void save_optimizer_weights_to_hdf5_group(long filepath = -1, Dictionary<string, object> custom_objects = null, bool compile = false)
- {
-
- }
-
- public static void load_optimizer_weights_from_hdf5_group(long filepath = -1, Dictionary<string, object> custom_objects = null, bool compile = false)
- {
-
- }
-
- public static void load_weights_from_hdf5_group(long f, List<ILayer> layers)
- {
- string original_keras_version = "2.5.0";
- string original_backend = null;
- var (success, attr) = Hdf5.ReadStringAttributes(f, "keras_version", "", true);
- if (success)
- original_keras_version = attr.First();
- // keras version should be 2.5.0+
- var ver_major = int.Parse(original_keras_version.Split('.')[0]);
- var ver_minor = int.Parse(original_keras_version.Split('.')[1]);
- if (ver_major < 2 || (ver_major == 2 && ver_minor < 5))
- throw new ValueError("keras version should be 2.5.0 or later.");
-
- (success, attr) = Hdf5.ReadStringAttributes(f, "backend", "", true);
- if (success)
- original_backend = attr.First();
-
- var filtered_layers = new List<ILayer>();
- foreach (var layer in layers)
- {
- var weights = _legacy_weights(layer);
- if (weights.Count > 0)
- filtered_layers.append(layer);
- }
-
- string[] layer_names = load_attributes_from_hdf5_group(f, "layer_names");
- var filtered_layer_names = new List<string>();
- foreach(var name in layer_names)
- {
- if (!filtered_layers.Select(x => x.Name).Contains(name))
- continue;
- long g = H5G.open(f, name);
- var weight_names = load_attributes_from_hdf5_group(g, "weight_names");
- if (weight_names.Count() > 0)
- filtered_layer_names.Add(name);
- H5G.close(g);
- }
-
- layer_names = filtered_layer_names.ToArray();
- if (layer_names.Length != filtered_layers.Count())
- throw new ValueError("You are trying to load a weight file " +
- $"containing {layer_names}" +
- $" layers into a model with {filtered_layers.Count} layers.");
-
- var weight_value_tuples = new List<(IVariableV1, NDArray)>();
- foreach (var (k, name) in enumerate(layer_names))
- {
- var weight_values = new List<NDArray>();
- long g = H5G.open(f, name);
- var weight_names = load_attributes_from_hdf5_group(g, "weight_names");
- foreach (var i_ in weight_names)
- {
- (success, Array result) = Hdf5.ReadDataset<float>(g, i_);
- if (success)
- weight_values.Add(np.array(result));
- }
- H5G.close(g);
- var layer = filtered_layers[k];
- var symbolic_weights = _legacy_weights(layer);
- preprocess_weights_for_loading(layer, weight_values, original_keras_version, original_backend);
- if (weight_values.Count() != symbolic_weights.Count())
- throw new ValueError($"Layer #{k} (named {layer.Name}" +
- "in the current model) was found to " +
- $"correspond to layer {name} in the save file." +
- $"However the new layer {layer.Name} expects " +
- $"{symbolic_weights.Count()} weights, but the saved weights have " +
- $"{weight_values.Count()} elements.");
- weight_value_tuples.AddRange(zip(symbolic_weights, weight_values));
- }
-
- keras.backend.batch_set_value(weight_value_tuples);
- }
-
- public static void toarrayf4(long filepath = -1, Dictionary<string, object> custom_objects = null, bool compile = false)
- {
-
- }
-
- public static void load_weights_from_hdf5_group_by_name(long filepath = -1, Dictionary<string, object> custom_objects = null, bool compile = false)
- {
-
- }
-
- public static void save_weights_to_hdf5_group(long f, List<ILayer> layers)
- {
- List<string> layerName=new List<string>();
- foreach (var layer in layers)
- {
- layerName.Add(layer.Name);
- }
- save_attributes_to_hdf5_group(f, "layer_names", layerName.ToArray());
- Hdf5.WriteAttribute(f, "backend", "tensorflow");
- Hdf5.WriteAttribute(f, "keras_version", "2.5.0");
-
- foreach (var layer in layers)
- {
- var weights = _legacy_weights(layer);
- if (weights.Count == 0)
- continue;
-
- var weight_names = new List<string>();
- // weight_values= keras.backend.batch_get_value(weights);
- foreach (var weight in weights)
- weight_names.Add(weight.Name);
-
- var g = Hdf5.CreateOrOpenGroup(f, Hdf5Utils.NormalizedName(layer.Name));
- save_attributes_to_hdf5_group(g, "weight_names", weight_names.ToArray());
- foreach (var (name, val) in zip(weight_names, weights))
- {
- var tensor = val.AsTensor();
- if (name.IndexOf("/") > 1)
- {
- var crDataGroup = g;
- string[] name_split = name.Split('/');
- for(int i = 0; i < name_split.Length - 1; i++)
- {
- crDataGroup = Hdf5.CreateOrOpenGroup(crDataGroup, Hdf5Utils.NormalizedName(name_split[i]));
- }
- WriteDataset(crDataGroup, name_split[name_split.Length - 1], tensor);
- Hdf5.CloseGroup(crDataGroup);
- }
- else
- {
- WriteDataset(g, name, tensor);
- }
- }
- Hdf5.CloseGroup(g);
- }
- }
-
- private static void save_attributes_to_hdf5_group(long f, string name, Array data)
- {
- int num_chunks = 1;
-
- var chunked_data = Split(data, num_chunks);
- int getSize = 0;
-
- string getType = data.Length > 0 ? data.GetValue(0).GetType().Name.ToLower() : "string";
-
- switch (getType)
- {
- case "single":
- getSize = sizeof(float);
- break;
- case "double":
- getSize = sizeof(double);
- break;
- case "string":
- getSize = -1;
- break;
- case "int32":
- getSize = sizeof(int);
- break;
- case "int64":
- getSize = sizeof(long);
- break;
- default:
- getSize = -1;
- break;
- }
- int getCount = chunked_data.Count;
-
- if (getSize != -1)
- {
- num_chunks = (int)Math.Ceiling((double)(getCount * getSize) / HDF5_OBJECT_HEADER_LIMIT);
- if (num_chunks > 1) chunked_data = Split(data, num_chunks);
- }
-
- if (num_chunks > 1)
- {
- foreach (var (chunk_id, chunk_data) in enumerate(chunked_data))
- WriteAttrs(f, getType, $"{name}{chunk_id}", chunk_data.ToArray());
- }
- else
- {
- WriteAttrs(f, getType, name, data);
- }
- }
-
- private static void WriteDataset(long f, string name, Tensor data)
- {
- switch (data.dtype)
- {
- case TF_DataType.TF_FLOAT:
- Hdf5.WriteDatasetFromArray<float>(f, name, data.numpy().ToMultiDimArray<float>());
- break;
- case TF_DataType.TF_DOUBLE:
- Hdf5.WriteDatasetFromArray<double>(f, name, data.numpy().ToMultiDimArray<double>());
- break;
- case TF_DataType.TF_INT32:
- Hdf5.WriteDatasetFromArray<int>(f, name, data.numpy().ToMultiDimArray<int>());
- break;
- case TF_DataType.TF_INT64:
- Hdf5.WriteDatasetFromArray<long>(f, name, data.numpy().ToMultiDimArray<long>());
- break;
- default:
- Hdf5.WriteDatasetFromArray<float>(f, name, data.numpy().ToMultiDimArray<float>());
- break;
- }
- }
-
- private static void WriteAttrs(long f,string typename, string name, Array data)
- {
- switch (typename)
- {
- case "single":
- Hdf5.WriteAttributes<float>(f, name, data);
- break;
- case "double":
- Hdf5.WriteAttributes<double>(f, name, data);
- break;
- case "string":
- Hdf5.WriteAttributes<string>(f, name, data);
- break;
- case "int32":
- Hdf5.WriteAttributes<int>(f, name, data);
- break;
- case "int64":
- Hdf5.WriteAttributes<long>(f, name, data);
- break;
- default:
- Hdf5.WriteAttributes<string>(f, name,data);
- break;
- }
- }
-
- private static List<List<object>> Split(Array list, int chunkSize)
- {
- var splitList = new List<List<object>>();
- var chunkCount = (int)Math.Ceiling((double)list.Length / (double)chunkSize);
-
- for (int c = 0; c < chunkCount; c++)
- {
- var skip = c * chunkSize;
- var take = skip + chunkSize;
- var chunk = new List<object>(chunkSize);
-
- for (int e = skip; e < take && e < list.Length; e++)
- {
- chunk.Add(list.GetValue(e));
- }
- splitList.Add(chunk);
- }
-
- return splitList;
- }
-
- public static string[] load_attributes_from_hdf5_group(long group, string name)
- {
- var (success, attr) = Hdf5.ReadStringAttributes(group, name, "", true);
- if (success)
- return attr.ToArray();
-
- return null;
- }
-
- public static void load_attributes_from_hdf5_group(long filepath = -1, Dictionary<string, object> custom_objects = null, bool compile = false)
- {
-
- }
-
- public static List<IVariableV1> _legacy_weights(ILayer layer)
- {
- var weights = layer.TrainableWeights.Select(x => x).ToList();
- weights.AddRange(layer.NonTrainableWeights);
- return weights;
- }
- }
- }
-
|