Browse Source

Add ConcreteFunction.

v0.20-tensorflow2.3
Oceania2018 Haiping 5 years ago
parent
commit
050fd2c63e
13 changed files with 165 additions and 100 deletions
  1. +3
    -0
      src/TensorFlowNET.Core/APIs/tf.image.cs
  2. +3
    -0
      src/TensorFlowNET.Core/Data/DatasetManager.cs
  3. +10
    -0
      src/TensorFlowNET.Core/Data/TensorSliceDataset.cs
  4. +1
    -2
      src/TensorFlowNET.Core/Functions/ConcreteFunction.cs
  5. +0
    -2
      src/TensorFlowNET.Core/Graphs/AutoGraph.cs
  6. +47
    -23
      src/TensorFlowNET.Core/Graphs/AutoGraphAttribute.cs
  7. +5
    -0
      src/TensorFlowNET.Core/Graphs/FuncGraph.cs
  8. +6
    -3
      src/TensorFlowNET.Core/Keras/Preprocessings/Preprocessing.paths_and_labels_to_dataset.cs
  9. +15
    -9
      src/TensorFlowNET.Core/Operations/image_ops_impl.cs
  10. +12
    -3
      src/TensorFlowNET.Core/Tensors/tensor_util.cs
  11. +2
    -0
      src/TensorFlowNET.Core/ops.cs
  12. +61
    -2
      test/TensorFlowNET.UnitTest/ImageTest.cs
  13. +0
    -56
      test/TensorFlowNET.UnitTest/img_test/TestCrop.cs

+ 3
- 0
src/TensorFlowNET.Core/APIs/tf.image.cs View File

@@ -208,6 +208,9 @@ namespace Tensorflow
=> image_ops_impl.non_max_suppression_padded(boxes, scores, max_output_size, iou_threshold, score_threshold, pad_to_max_output_size,
name, sorted_input, canonicalized_coordinates, tile_size);

public Tensor resize(Tensor image, TensorShape size)
=> image_ops_impl.resize_images(image, tf.constant(size));

public Tensor resize_bilinear(Tensor images, Tensor size, bool align_corners = false, bool half_pixel_centers = false, string name = null)
=> gen_image_ops.resize_bilinear(images, size, align_corners: align_corners, half_pixel_centers: half_pixel_centers, name: name);



+ 3
- 0
src/TensorFlowNET.Core/Data/DatasetManager.cs View File

@@ -25,6 +25,9 @@ namespace Tensorflow
public IDatasetV2 from_tensor_slices(Tensor features, Tensor labels)
=> new TensorSliceDataset(features, labels);

public IDatasetV2 from_tensor_slices(string[] array)
=> new TensorSliceDataset(array);

public IDatasetV2 from_tensor_slices(NDArray array)
=> new TensorSliceDataset(array);



+ 10
- 0
src/TensorFlowNET.Core/Data/TensorSliceDataset.cs View File

@@ -11,6 +11,16 @@ namespace Tensorflow.Data
{
public class TensorSliceDataset : DatasetSource
{
public TensorSliceDataset(string[] array)
{
var element = tf.constant(array);
_tensors = new[] { element };
var batched_spec = new[] { element.ToTensorSpec() };
structure = batched_spec.Select(x => x._unbatch()).ToArray();

variant_tensor = ops.tensor_slice_dataset(_tensors, output_shapes);
}

public TensorSliceDataset(NDArray array)
{
var element = tf.constant(array);


+ 1
- 2
src/TensorFlowNET.Core/Functions/ConcreteFunction.cs View File

@@ -33,8 +33,6 @@ namespace Tensorflow.Functions
new Operation[] { input },
new Operation[] { output },
null);

c_api.TFE_ContextAddFunction(tf.Context.Handle, _handle, tf.Status.Handle);
}

tf.enable_eager_execution();
@@ -54,6 +52,7 @@ namespace Tensorflow.Functions
public void Dispose()
{
c_api.TFE_ContextRemoveFunction(tf.Context.Handle, Name, tf.Status.Handle);
c_api.TF_DeleteFunction(_handle);
}
}
}

+ 0
- 2
src/TensorFlowNET.Core/Graphs/AutoGraph.cs View File

@@ -26,8 +26,6 @@ namespace Tensorflow.Graphs
new Operation[] { input1, input2 },
new Operation[] { output },
null);

c_api.TFE_ContextAddFunction(tf.Context.Handle, func_handle, tf.Status.Handle);
}

tf.enable_eager_execution();


+ 47
- 23
src/TensorFlowNET.Core/Graphs/AutoGraphAttribute.cs View File

@@ -1,4 +1,4 @@
/*using MethodBoundaryAspect.Fody.Attributes;
using MethodBoundaryAspect.Fody.Attributes;
using System;
using System.Collections.Generic;
using System.Linq;
@@ -8,49 +8,73 @@ using static Tensorflow.Binding;

namespace Tensorflow.Graphs
{
public sealed class AutoGraphAspect : OnMethodBoundaryAspect
[AllowChangingInputArguments]
public sealed class AutoGraphAttribute : OnMethodBoundaryAspect
{
FuncGraph graph;
IntPtr func_handle;
Tensor[] originalInputs;
string func_name;
static Dictionary<string, Func<Tensor[], Tensor>> functions = new Dictionary<string, Func<Tensor[], Tensor>>();

public override void OnEntry(MethodExecutionArgs args)
{
func_name = $"autograph_{args.Instance}.{args.Method.Name}";

if (functions.ContainsKey(func_name))
{
args.ReturnValue = functions[func_name](args.Arguments.Select(x => x as Tensor).ToArray());
args.FlowBehavior = FlowBehavior.Return;
return;
}
tf.compat.v1.disable_eager_execution();

// make function as an Operation by autograph
graph = new FuncGraph(func_name);
graph.as_default();

originalInputs = new Tensor[args.Arguments.Length];
// convert args to placeholder
for (var i = 0; i < args.Arguments.Length; i++)
{
if (args.Arguments[i] is EagerTensor tensor)
{
originalInputs[i] = tensor;
args.Arguments[i] = tf.placeholder(tensor.dtype, shape: tensor.TensorShape);
}
}

// make function as an Operation by autograph
graph = new FuncGraph("autograph_add");
graph.as_default();
}

public override void OnExit(MethodExecutionArgs args)
{
var output = (Tensor)args.Method.Invoke(args.Instance, args.Arguments);
var output = (Tensor)args.ReturnValue;
var inputs = args.Arguments.Select(x => x as Tensor).ToArray();
var opers = graph._nodes_by_name.Values.Select(x => x as Operation).ToArray();
func_handle = graph.ToGraph(opers,
new Operation[] { },
new Operation[] { },

graph.ToGraph(opers,
inputs.Select(x => x.op).ToArray(),
new Operation[] { output.op },
null);

graph.Dispose();
tf.enable_eager_execution();

c_api.TFE_ContextAddFunction(tf.Context.Handle, func_handle, tf.Status.Handle);
Func<Tensor[], Tensor> function = (x) =>
{
var result = tf.Runner.TFE_Execute(tf.Context,
tf.Context.DeviceName,
func_name,
x,
null,
1);

var a1 = tf.constant(1);
var b1 = tf.constant(2);
return result[0];
};
// cache function.
functions[func_name] = function;

var result = tf.Runner.TFE_Execute(tf.Context,
tf.Context.DeviceName,
"autograph_add",
new[] { a1, b1 },
null,
1);
graph.Dispose();
// run function
args.ReturnValue = function(originalInputs);
}
}
}*/
}

+ 5
- 0
src/TensorFlowNET.Core/Graphs/FuncGraph.cs View File

@@ -47,8 +47,13 @@ namespace Tensorflow.Graphs
IntPtr.Zero,
null,
status.Handle);
status.Check(true);

c_api.TF_GraphCopyFunction(outer_graph, func_handle, IntPtr.Zero, status.Handle);
status.Check(true);

c_api.TFE_ContextAddFunction(tf.Context.Handle, func_handle, status.Handle);
status.Check(true);

return func_handle;
}


+ 6
- 3
src/TensorFlowNET.Core/Keras/Preprocessings/Preprocessing.paths_and_labels_to_dataset.cs View File

@@ -16,7 +16,10 @@ namespace Tensorflow.Keras
int num_classes,
string interpolation)
{
Shape shape = (image_paths.Length, image_size.dims[0], image_size.dims[1], num_channels);
var path_ds = tf.data.Dataset.from_tensor_slices(image_paths);
var img_ds = path_ds.map(x => path_to_image(x, image_size, num_channels, interpolation));

/*Shape shape = (image_paths.Length, image_size.dims[0], image_size.dims[1], num_channels);
Console.WriteLine($"Allocating memory for shape{shape}, {NPTypeCode.Float}");
var data = np.zeros(shape, NPTypeCode.Float);

@@ -35,13 +38,13 @@ namespace Tensorflow.Keras
var label_ds = tf.keras.preprocessing.dataset_utils.labels_to_dataset(labels, label_mode, num_classes);
img_ds = tf.data.Dataset.zip(img_ds, label_ds);
}
else
else*/
throw new NotImplementedException("");

return img_ds;
}

Tensor path_to_image(string path, TensorShape image_size, int num_channels, string interpolation)
Tensor path_to_image(Tensor path, TensorShape image_size, int num_channels, string interpolation)
{
var img = tf.io.read_file(path);
img = tf.image.decode_image(


+ 15
- 9
src/TensorFlowNET.Core/Operations/image_ops_impl.cs View File

@@ -1668,8 +1668,6 @@ new_height, new_width");
public static Tensor decode_image(Tensor contents, int channels = 0, TF_DataType dtype = TF_DataType.TF_UINT8,
string name = null, bool expand_animations = true)
{
Tensor substr = null;

Func<ITensorOrOperation> _jpeg = () =>
{
int jpeg_channels = channels;
@@ -1695,8 +1693,7 @@ new_height, new_width");
{
var result = convert_image_dtype(gen_image_ops.decode_gif(contents), dtype);
if (!expand_animations)
// result = array_ops.gather(result, 0);
throw new NotImplementedException("");
result = array_ops.gather(result, 0);
return result;
});
};
@@ -1728,18 +1725,16 @@ new_height, new_width");

Func<ITensorOrOperation> check_gif = () =>
{
var is_gif = math_ops.equal(substr, "\x47\x49\x46", name: "is_gif");
return control_flow_ops.cond(is_gif, _gif, _bmp, name: "cond_gif");
return control_flow_ops.cond(is_gif(contents), _gif, _bmp, name: "cond_gif");
};

Func<ITensorOrOperation> check_png = () =>
{
return control_flow_ops.cond(_is_png(contents), _png, check_gif, name: "cond_png");
return control_flow_ops.cond(is_png(contents), _png, check_gif, name: "cond_png");
};

return tf_with(ops.name_scope(name, "decode_image"), scope =>
{
substr = tf.strings.substr(contents, 0, 3);
return control_flow_ops.cond(is_jpeg(contents), _jpeg, check_png, name: "cond_jpeg");
});
}
@@ -2089,7 +2084,7 @@ new_height, new_width");
});
}

public static Tensor _is_png(Tensor contents, string name = null)
static Tensor is_png(Tensor contents, string name = null)
{
return tf_with(ops.name_scope(name, "is_png"), scope =>
{
@@ -2098,6 +2093,17 @@ new_height, new_width");
});
}

static Tensor is_gif(Tensor contents, string name = null)
{
return tf_with(ops.name_scope(name, "is_gif"), scope =>
{
var substr = tf.strings.substr(contents, 0, 3);
var gif = tf.constant(new byte[] { 0x47, 0x49, 0x46 }, TF_DataType.TF_STRING);
var result = math_ops.equal(substr, gif, name: name);
return result;
});
}

public static Tensor convert_image_dtype(Tensor image, TF_DataType dtype, bool saturate = false,
string name = null)
{


+ 12
- 3
src/TensorFlowNET.Core/Tensors/tensor_util.cs View File

@@ -148,9 +148,18 @@ namespace Tensorflow
// If shape is not given, get the shape from the numpy array.
if (shape == null)
{
shape = nparray.shape;
is_same_size = true;
shape_size = nparray.size;
if(numpy_dtype == TF_DataType.TF_STRING)
{
// scalar string
shape = new int[0];
shape_size = 0;
}
else
{
shape = nparray.shape;
is_same_size = true;
shape_size = nparray.size;
}
}
else
{


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

@@ -470,6 +470,8 @@ namespace Tensorflow
return varVal._TensorConversionFunction(dtype: dtype, name: name, as_ref: as_ref);
case TensorShape ts:
return constant_op.constant(ts.dims, dtype: dtype, name: name);
case string str:
return constant_op.constant(value, dtype: tf.@string, name: name);
case int[] dims:
return constant_op.constant(dims, dtype: dtype, name: name);
case object[] objects:


+ 61
- 2
test/TensorFlowNET.UnitTest/ImageTest.cs View File

@@ -1,4 +1,6 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using FluentAssertions;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using NumSharp;
using System;
using System.Collections.Generic;
using System.IO;
@@ -26,12 +28,69 @@ namespace TensorFlowNET.UnitTest.Basics
contents = tf.io.read_file(imgPath);
}

[Ignore]
[TestMethod]
public void decode_image()
{
var img = tf.image.decode_image(contents);
Assert.AreEqual(img.name, "decode_image/cond_jpeg/Merge:0");
}

[TestMethod, Ignore]
public void resize_image()
{
var image = tf.constant(new int[5, 5]
{
{1, 0, 0, 0, 0 },
{0, 1, 0, 0, 0 },
{0, 0, 1, 0, 0 },
{0, 0, 0, 1, 0 },
{0, 0, 0, 0, 1 }
});
//image = image[tf.newaxis, ..., tf.newaxis];

var img = tf.image.resize(contents, (3, 5));
Assert.AreEqual(img.name, "decode_image/cond_jpeg/Merge:0");
}

[TestMethod]
public void TestCropAndResize()
{
var graph = tf.Graph().as_default();

// 3x3 'Image' with numbered coordinates
var input = np.array(0f, 1f, 2f, 3f, 4f, 5f, 6f, 7f, 8f);
var image = tf.reshape(input, new int[] { 1, 3, 3, 1 });

// 4x4 'Image' with numbered coordinates
var input2 = np.array(0f, 1f, 2f, 3f, 4f, 5f, 6f, 7f, 8f, 9f, 10f, 11f, 12f, 13f, 14f, 15f);
var image2 = tf.reshape(input2, new int[] { 1, 4, 4, 1 });
// create one box over the full image that flips it (y1 > y2)
var box = tf.reshape(np.array(1f, 0f, 0f, 1f), new int[] { 1, 4 });
var boxInd = tf.Variable(np.array(0));
// crop first 3x3 imageto size 1x1
var cropSize1_1 = tf.Variable(np.array(1, 1));
// don't crop second 4x4 image
var cropSize2_2 = tf.Variable(np.array(4, 4));

var init = tf.global_variables_initializer();
using (Session sess = tf.Session())
{
sess.run(init);

var cropped = tf.image.crop_and_resize(image, box, boxInd, cropSize1_1);

var result = sess.run(cropped);
// check if cropped to 1x1 center was succesfull
result.size.Should().Be(1);
result[0, 0, 0, 0].Should().Be(4f);

cropped = tf.image.crop_and_resize(image2, box, boxInd, cropSize2_2);
result = sess.run(cropped);
// check if flipped and no cropping occured
result.size.Should().Be(16);
result[0, 0, 0, 0].Should().Be(12f);

}
}
}
}

+ 0
- 56
test/TensorFlowNET.UnitTest/img_test/TestCrop.cs View File

@@ -1,56 +0,0 @@
using FluentAssertions;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using NumSharp;
using Tensorflow;
using Tensorflow.UnitTest;
using static Tensorflow.Binding;

namespace TensorFlowNET.UnitTest.img_test
{
[TestClass]
public class TestCrop : GraphModeTestBase
{
[TestMethod]
public void TestCropAndResize()
{
var graph = tf.Graph().as_default();

// 3x3 'Image' with numbered coordinates
var input = np.array(0f, 1f, 2f, 3f, 4f, 5f, 6f, 7f, 8f);
var image = tf.reshape(input, new int[] { 1, 3, 3, 1 });

// 4x4 'Image' with numbered coordinates
var input2 = np.array(0f, 1f, 2f, 3f, 4f, 5f, 6f, 7f, 8f, 9f, 10f, 11f, 12f, 13f, 14f, 15f);
var image2 = tf.reshape(input2, new int[] { 1, 4, 4, 1 });
// create one box over the full image that flips it (y1 > y2)
var box = tf.reshape(np.array(1f, 0f, 0f, 1f), new int[] {1, 4});
var boxInd = tf.Variable(np.array(0));
// crop first 3x3 imageto size 1x1
var cropSize1_1 = tf.Variable(np.array(1, 1));
// don't crop second 4x4 image
var cropSize2_2 = tf.Variable(np.array(4, 4));
var init = tf.global_variables_initializer();
using (Session sess = tf.Session())
{
sess.run(init);

var cropped = tf.image.crop_and_resize(image, box, boxInd, cropSize1_1);
var result = sess.run(cropped);
// check if cropped to 1x1 center was succesfull
result.size.Should().Be(1);
result[0, 0, 0, 0].Should().Be(4f);

cropped = tf.image.crop_and_resize(image2, box, boxInd, cropSize2_2);
result = sess.run(cropped);
// check if flipped and no cropping occured
result.size.Should().Be(16);
result[0, 0, 0, 0].Should().Be(12f);

}

}

}
}

Loading…
Cancel
Save