Browse Source

add tf.summary #248

tags/v0.9
Oceania2018 6 years ago
parent
commit
9e895b30ae
6 changed files with 199 additions and 2 deletions
  1. BIN
      graph/InceptionV3.meta
  2. +15
    -0
      src/TensorFlowNET.Core/APIs/tf.summary.cs
  3. +60
    -0
      src/TensorFlowNET.Core/Operations/gen_logging_ops.cs
  4. +74
    -0
      src/TensorFlowNET.Core/Summaries/Summary.cs
  5. +3
    -0
      src/TensorFlowNET.Core/ops.GraphKeys.cs
  6. +47
    -2
      test/TensorFlowNET.Examples/ImageProcess/RetrainImageClassifier.cs

BIN
graph/InceptionV3.meta View File


+ 15
- 0
src/TensorFlowNET.Core/APIs/tf.summary.cs View File

@@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Text;
using Tensorflow.IO;
using Tensorflow.Summaries;

namespace Tensorflow
{
public static partial class tf
{
public static Summary summary = new Summary();
public static Tensor scalar(string name, Tensor tensor)
=> summary.scalar(name, tensor);
}
}

+ 60
- 0
src/TensorFlowNET.Core/Operations/gen_logging_ops.cs View File

@@ -17,5 +17,65 @@ namespace Tensorflow

return _op;
}

/// <summary>
/// Outputs a <c>Summary</c> protocol buffer with scalar values.
/// </summary>
/// <param name="tags">
/// Tags for the summary.
/// </param>
/// <param name="values">
/// Same shape as <c>tags. Values for the summary.
/// </param>
/// <param name="name">
/// If specified, the created operation in the graph will be this one, otherwise it will be named 'ScalarSummary'.
/// </param>
/// <returns>
/// Scalar. Serialized <c>Summary</c> protocol buffer.
/// The Operation can be fetched from the resulting Tensor, by fetching the Operation property from the result.
/// </returns>
/// <remarks>
/// The input <c>tags</c> and <c>values</c> must have the same shape. The generated summary
/// has a summary value for each tag-value pair in <c>tags</c> and <c>values</c>.
/// </remarks>
public static Tensor scalar_summary(string tags, Tensor values, string name = "ScalarSummary")
{
var dict = new Dictionary<string, object>();
dict["tags"] = tags;
dict["values"] = values;
var op = _op_def_lib._apply_op_helper("ScalarSummary", name: name, keywords: dict);
return op.output;
}

/// <summary>
/// Merges summaries.
/// </summary>
/// <param name="inputs">
/// Can be of any shape. Each must contain serialized <c>Summary</c> protocol
/// buffers.
/// </param>
/// <param name="name">
/// If specified, the created operation in the graph will be this one, otherwise it will be named 'MergeSummary'.
/// </param>
/// <returns>
/// Scalar. Serialized <c>Summary</c> protocol buffer.
/// The Operation can be fetched from the resulting Tensor, by fetching the Operation property from the result.
/// </returns>
/// <remarks>
/// This op creates a
/// [<c>Summary</c>](https://www.tensorflow.org/code/tensorflow/core/framework/summary.proto)
/// protocol buffer that contains the union of all the values in the input
/// summaries.
///
/// When the Op is run, it reports an <c>InvalidArgument</c> error if multiple values
/// in the summaries to merge use the same tag.
/// </remarks>
public static Tensor merge_summary(Tensor[] inputs, string name = "MergeSummary")
{
var dict = new Dictionary<string, object>();
dict["inputs"] = inputs;
var op = _op_def_lib._apply_op_helper("MergeSummary", name: name, keywords: dict);
return op.output;
}
}
}

+ 74
- 0
src/TensorFlowNET.Core/Summaries/Summary.cs View File

@@ -0,0 +1,74 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using static Tensorflow.Python;

namespace Tensorflow.Summaries
{
public class Summary
{
public Tensor merge_all(string key = ops.GraphKeys.SUMMARIES, string scope= null, string name= null)
{
var summary_ops = ops.get_collection(key, scope: scope);
if (summary_ops == null)
return null;
else
return merge((summary_ops as List<ITensorOrOperation>).Select(x => x as Tensor).ToArray(), name: name);
}

/// <summary>
/// Merges summaries.
/// </summary>
/// <param name="inputs"></param>
/// <param name="collections"></param>
/// <param name="name"></param>
/// <returns></returns>
public Tensor merge(Tensor[] inputs, string[] collections = null, string name = null)
{
return with(ops.name_scope(name, "Merge", inputs), delegate
{
var val = gen_logging_ops.merge_summary(inputs: inputs, name: name);
collect(val, collections?.ToList(), new List<string>());
return val;
});
}

public Tensor scalar(string name, Tensor tensor, string[] collections = null, string family = null)
{
var (tag, scope) = summary_scope(name, family: family, values: new Tensor[] { tensor });
var val = gen_logging_ops.scalar_summary(tags: tag, values: tensor, name: scope);
collect(val, collections?.ToList(), new List<string> { ops.GraphKeys.SUMMARIES });
return val;
}

/// <summary>
/// Adds keys to a collection.
/// </summary>
/// <param name="val"The value to add per each key.></param>
/// <param name="collections">A collection of keys to add.</param>
/// <param name="default_collections">Used if collections is None.</param>
public void collect(ITensorOrOperation val, List<string> collections, List<string> default_collections)
{
if (collections == null)
collections = default_collections;
foreach (var key in collections)
ops.add_to_collection(key, val);
}

public (string, string) summary_scope(string name, string family = null, string default_name = null, Tensor[] values = null)
{
string scope_base_name = string.IsNullOrEmpty(family) ? name : $"{family}/{name}";
return with(ops.name_scope(scope_base_name, default_name: default_name, values), scope =>
{
var tag = scope._name_scope;
if (string.IsNullOrEmpty(family))
tag = tag.Remove(tag.Length - 1);
else
tag = $"{family}/{tag.Remove(tag.Length - 1)}";

return (tag, scope._name_scope);
});
}
}
}

+ 3
- 0
src/TensorFlowNET.Core/ops.GraphKeys.cs View File

@@ -47,6 +47,9 @@ namespace Tensorflow
/// </summary>
public static string UPDATE_OPS = "update_ops";

// Key to collect summaries.
public const string SUMMARIES = "summaries";

// Used to store v2 summary names.
public static string _SUMMARY_COLLECTION = "_SUMMARY_V2";



+ 47
- 2
test/TensorFlowNET.Examples/ImageProcess/RetrainImageClassifier.cs View File

@@ -45,6 +45,8 @@ namespace TensorFlowNET.Examples.ImageProcess
tf.train.import_meta_graph("graph/InceptionV3.meta");
Tensor bottleneck_tensor = graph.OperationByName("module_apply_default/hub_output/feature_vector/SpatialSqueeze");
Tensor resized_image_tensor = graph.OperationByName("Placeholder");
Tensor final_tensor = graph.OperationByName("final_result");
Tensor ground_truth_input = graph.OperationByName("input/GroundTruthInput");

var sw = new Stopwatch();

@@ -63,11 +65,45 @@ namespace TensorFlowNET.Examples.ImageProcess
bottleneck_dir, jpeg_data_tensor,
decoded_image_tensor, resized_image_tensor,
bottleneck_tensor, tfhub_module);

// Create the operations we need to evaluate the accuracy of our new layer.
var (evaluation_step, _) = add_evaluation_step(final_tensor, ground_truth_input);

// Merge all the summaries and write them out to the summaries_dir
var merged = tf.summary.merge_all();
});

return false;
}

/// <summary>
/// Inserts the operations we need to evaluate the accuracy of our results.
/// </summary>
/// <param name="result_tensor"></param>
/// <param name="ground_truth_tensor"></param>
/// <returns></returns>
private (Tensor, Tensor) add_evaluation_step(Tensor result_tensor, Tensor ground_truth_tensor)
{
Tensor evaluation_step = null, correct_prediction = null, prediction = null;

with(tf.name_scope("accuracy"), scope =>
{
with(tf.name_scope("correct_prediction"), delegate
{
prediction = tf.argmax(result_tensor, 1);
correct_prediction = tf.equal(prediction, ground_truth_tensor);
});

with(tf.name_scope("accuracy"), delegate
{
evaluation_step = tf.reduce_mean(tf.cast(correct_prediction, tf.float32));
});
});

tf.summary.scalar("accuracy", evaluation_step);
return (evaluation_step, prediction);
}

/// <summary>
/// Ensures all the training, testing, and validation bottlenecks are cached.
/// </summary>
@@ -95,12 +131,15 @@ namespace TensorFlowNET.Examples.ImageProcess
get_or_create_bottleneck(sess, image_lists, label_name, index, image_dir, category,
bottleneck_dir, jpeg_data_tensor, decoded_image_tensor,
resized_input_tensor, bottleneck_tensor, module_name);
how_many_bottlenecks++;
if (how_many_bottlenecks % 100 == 0)
print($"{how_many_bottlenecks} bottleneck files created.");
}
}
}
}

private void get_or_create_bottleneck(Session sess, Dictionary<string, Dictionary<string, string[]>> image_lists,
private float[] get_or_create_bottleneck(Session sess, Dictionary<string, Dictionary<string, string[]>> image_lists,
string label_name, int index, string image_dir, string category, string bottleneck_dir,
Tensor jpeg_data_tensor, Tensor decoded_image_tensor, Tensor resized_input_tensor,
Tensor bottleneck_tensor, string module_name)
@@ -116,6 +155,9 @@ namespace TensorFlowNET.Examples.ImageProcess
image_dir, category, sess, jpeg_data_tensor,
decoded_image_tensor, resized_input_tensor,
bottleneck_tensor);
var bottleneck_string = File.ReadAllText(bottleneck_path);
var bottleneck_values = Array.ConvertAll(bottleneck_string.Split(','), x => float.Parse(x));
return bottleneck_values;
}

private void create_bottleneck_file(string bottleneck_path, Dictionary<string, Dictionary<string, string[]>> image_lists,
@@ -132,13 +174,16 @@ namespace TensorFlowNET.Examples.ImageProcess
var bottleneck_values = run_bottleneck_on_image(
sess, image_data, jpeg_data_tensor, decoded_image_tensor,
resized_input_tensor, bottleneck_tensor);
var values = bottleneck_values.Data<float>();
var bottleneck_string = string.Join(",", values);
File.WriteAllText(bottleneck_path, bottleneck_string);
}

/// <summary>
/// Runs inference on an image to extract the 'bottleneck' summary layer.
/// </summary>
/// <param name="sess">Current active TensorFlow Session.</param>
/// <param name="image_path">Path of raw JPEG data.</param>
/// <param name="image_data">Data of raw JPEG data.</param>
/// <param name="image_data_tensor">Input data layer in the graph.</param>
/// <param name="decoded_image_tensor">Output of initial image resizing and preprocessing.</param>
/// <param name="resized_input_tensor">The input node of the recognition graph.</param>


Loading…
Cancel
Save