@@ -191,7 +191,7 @@ namespace Tensorflow.Keras.Engine | |||||
tf.Context.eager_mode(isFunc: tf.Context.is_build_function()); | tf.Context.eager_mode(isFunc: tf.Context.is_build_function()); | ||||
} | } | ||||
build(inputs); | |||||
build(inputs.shape); | |||||
if (need_restore_mode) | if (need_restore_mode) | ||||
tf.Context.restore_mode(); | tf.Context.restore_mode(); | ||||
@@ -199,7 +199,7 @@ namespace Tensorflow.Keras.Engine | |||||
built = true; | built = true; | ||||
} | } | ||||
protected virtual void build(Tensors inputs) | |||||
public virtual void build(Shape input_shape) | |||||
{ | { | ||||
built = true; | built = true; | ||||
} | } | ||||
@@ -6,30 +6,38 @@ using Tensorflow.Keras.Engine; | |||||
using static Tensorflow.Binding; | using static Tensorflow.Binding; | ||||
namespace Tensorflow.Keras.Layers { | namespace Tensorflow.Keras.Layers { | ||||
/// <summary> | |||||
/// ELU Layer: | |||||
/// x = 0 when x > 0, x = alpha( e^x-1 ) elsewhere | |||||
/// </summary> | |||||
public class ELU : Layer { | |||||
ELUArgs args; | |||||
float alpha => args.Alpha; | |||||
public ELU ( ELUArgs args ) : base(args) { | |||||
this.args = args; | |||||
} | |||||
protected override void build ( Tensors inputs ) { | |||||
if ( alpha < 0f ) { | |||||
throw new ValueError("Alpha must be a number greater than 0."); | |||||
} | |||||
built = true; | |||||
} | |||||
protected override Tensors Call ( Tensors inputs, Tensor state = null, bool? training = null ) { | |||||
Tensor output = inputs; | |||||
output = tf.where(output > 0f, output, | |||||
tf.multiply(alpha, tf.sub(tf.exp(output), 1f))); | |||||
return output; | |||||
} | |||||
public override Shape ComputeOutputShape ( Shape input_shape ) { | |||||
return input_shape; | |||||
/// <summary> | |||||
/// ELU Layer: | |||||
/// x = 0 when x > 0, x = alpha( e^x-1 ) elsewhere | |||||
/// </summary> | |||||
public class ELU : Layer | |||||
{ | |||||
ELUArgs args; | |||||
float alpha => args.Alpha; | |||||
public ELU(ELUArgs args) : base(args) | |||||
{ | |||||
this.args = args; | |||||
} | |||||
public override void build(Shape input_shape) | |||||
{ | |||||
if (alpha < 0f) | |||||
{ | |||||
throw new ValueError("Alpha must be a number greater than 0."); | |||||
} | } | ||||
} | |||||
built = true; | |||||
} | |||||
protected override Tensors Call(Tensors inputs, Tensor state = null, bool? training = null) | |||||
{ | |||||
Tensor output = inputs; | |||||
output = tf.where(output > 0f, output, | |||||
tf.multiply(alpha, tf.sub(tf.exp(output), 1f))); | |||||
return output; | |||||
} | |||||
public override Shape ComputeOutputShape(Shape input_shape) | |||||
{ | |||||
return input_shape; | |||||
} | |||||
} | |||||
} | } |
@@ -6,19 +6,24 @@ using Tensorflow.Keras.Engine; | |||||
using static Tensorflow.Binding; | using static Tensorflow.Binding; | ||||
namespace Tensorflow.Keras.Layers { | namespace Tensorflow.Keras.Layers { | ||||
public class Exponential : Layer { | |||||
public Exponential ( LayerArgs args ) : base(args) { | |||||
// Exponential has no args | |||||
} | |||||
protected override void build ( Tensors inputs ) { | |||||
built = true; | |||||
} | |||||
protected override Tensors Call ( Tensors inputs, Tensor state = null, bool? training = null ) { | |||||
Tensor output = inputs; | |||||
return tf.exp(output); | |||||
} | |||||
public override Shape ComputeOutputShape ( Shape input_shape ) { | |||||
return input_shape; | |||||
} | |||||
} | |||||
public class Exponential : Layer | |||||
{ | |||||
public Exponential(LayerArgs args) : base(args) | |||||
{ | |||||
// Exponential has no args | |||||
} | |||||
public override void build(Shape input_shape) | |||||
{ | |||||
built = true; | |||||
} | |||||
protected override Tensors Call(Tensors inputs, Tensor state = null, bool? training = null) | |||||
{ | |||||
Tensor output = inputs; | |||||
return tf.exp(output); | |||||
} | |||||
public override Shape ComputeOutputShape(Shape input_shape) | |||||
{ | |||||
return input_shape; | |||||
} | |||||
} | |||||
} | } |
@@ -15,7 +15,7 @@ namespace Tensorflow.Keras.Layers { | |||||
public SELU ( LayerArgs args ) : base(args) { | public SELU ( LayerArgs args ) : base(args) { | ||||
// SELU has no arguments | // SELU has no arguments | ||||
} | } | ||||
protected override void build ( Tensors inputs ) { | |||||
public override void build(Shape input_shape) { | |||||
if ( alpha < 0f ) { | if ( alpha < 0f ) { | ||||
throw new ValueError("Alpha must be a number greater than 0."); | throw new ValueError("Alpha must be a number greater than 0."); | ||||
} | } | ||||
@@ -90,9 +90,10 @@ namespace Tensorflow.Keras.Layers | |||||
}.Contains(this.score_mode)) | }.Contains(this.score_mode)) | ||||
throw new ValueError("Received: score_mode={score_mode}. Acceptable values are: [\"dot\", \"concat\"]"); | throw new ValueError("Received: score_mode={score_mode}. Acceptable values are: [\"dot\", \"concat\"]"); | ||||
} | } | ||||
// Creates variable when `use_scale` is True or `score_mode` is `concat`. | // Creates variable when `use_scale` is True or `score_mode` is `concat`. | ||||
protected override void build(Tensors inputs) { | |||||
public override void build(Shape input_shape) | |||||
{ | |||||
if (this.use_scale) | if (this.use_scale) | ||||
this.scale = this.add_weight(name: "scale", | this.scale = this.add_weight(name: "scale", | ||||
shape: 1, | shape: 1, | ||||
@@ -110,7 +111,7 @@ namespace Tensorflow.Keras.Layers | |||||
trainable: true); | trainable: true); | ||||
else | else | ||||
this.concat_score_weight = null; | this.concat_score_weight = null; | ||||
base.build(inputs); | |||||
base.build(input_shape); | |||||
} | } | ||||
/// <summary> | /// <summary> | ||||
@@ -29,9 +29,8 @@ namespace Tensorflow.Keras.Layers | |||||
} | } | ||||
protected override void build(Tensors inputs) | |||||
public override void build(Shape input_shape) | |||||
{ | { | ||||
var input_shape = inputs.shape; | |||||
if (len(input_shape) != 4) | if (len(input_shape) != 4) | ||||
throw new ValueError($"Inputs should have rank 4. Received input shape: {input_shape}"); | throw new ValueError($"Inputs should have rank 4. Received input shape: {input_shape}"); | ||||
@@ -43,14 +42,12 @@ namespace Tensorflow.Keras.Layers | |||||
shape: kernel_shape, | shape: kernel_shape, | ||||
initializer: kernel_initializer, | initializer: kernel_initializer, | ||||
regularizer: kernel_regularizer, | regularizer: kernel_regularizer, | ||||
trainable: true, | |||||
dtype: inputs.dtype); | |||||
trainable: true); | |||||
if (use_bias) | if (use_bias) | ||||
bias = add_weight(name: "bias", | bias = add_weight(name: "bias", | ||||
shape: filters, | shape: filters, | ||||
initializer: bias_initializer, | initializer: bias_initializer, | ||||
trainable: true, | |||||
dtype: inputs.dtype); | |||||
trainable: true); | |||||
built = true; | built = true; | ||||
} | } | ||||
@@ -57,9 +57,8 @@ namespace Tensorflow.Keras.Layers | |||||
_tf_data_format = conv_utils.convert_data_format(data_format, rank + 2); | _tf_data_format = conv_utils.convert_data_format(data_format, rank + 2); | ||||
} | } | ||||
protected override void build(Tensors inputs) | |||||
public override void build(Shape input_shape) | |||||
{ | { | ||||
Shape input_shape = inputs.shape; | |||||
int channel_axis = data_format == "channels_first" ? 1 : -1; | int channel_axis = data_format == "channels_first" ? 1 : -1; | ||||
var input_channel = channel_axis < 0 ? | var input_channel = channel_axis < 0 ? | ||||
input_shape.dims[input_shape.ndim + channel_axis] : | input_shape.dims[input_shape.ndim + channel_axis] : | ||||
@@ -41,9 +41,8 @@ namespace Tensorflow.Keras.Layers | |||||
this.inputSpec = new InputSpec(min_ndim: 2); | this.inputSpec = new InputSpec(min_ndim: 2); | ||||
} | } | ||||
protected override void build(Tensors inputs) | |||||
public override void build(Shape input_shape) | |||||
{ | { | ||||
Shape input_shape = inputs.shape; | |||||
var last_dim = input_shape.dims.Last(); | var last_dim = input_shape.dims.Last(); | ||||
var axes = new Dictionary<int, int>(); | var axes = new Dictionary<int, int>(); | ||||
axes[-1] = (int)last_dim; | axes[-1] = (int)last_dim; | ||||
@@ -119,9 +119,8 @@ namespace Tensorflow.Keras.Layers | |||||
this.bias_constraint = args.BiasConstraint; | this.bias_constraint = args.BiasConstraint; | ||||
} | } | ||||
protected override void build(Tensors inputs) | |||||
public override void build(Shape input_shape) | |||||
{ | { | ||||
var input_shape = inputs.shape; | |||||
var shape_data = _analyze_einsum_string(this.equation, this.bias_axes, input_shape, this.partial_output_shape); | var shape_data = _analyze_einsum_string(this.equation, this.bias_axes, input_shape, this.partial_output_shape); | ||||
var kernel_shape = shape_data.Item1; | var kernel_shape = shape_data.Item1; | ||||
var bias_shape = shape_data.Item2; | var bias_shape = shape_data.Item2; | ||||
@@ -141,7 +140,7 @@ namespace Tensorflow.Keras.Layers | |||||
trainable: true); | trainable: true); | ||||
else | else | ||||
this.bias = null; | this.bias = null; | ||||
base.build(inputs); | |||||
base.build(input_shape); | |||||
} | } | ||||
public override Shape ComputeOutputShape(Shape input_shape) | public override Shape ComputeOutputShape(Shape input_shape) | ||||
@@ -54,7 +54,7 @@ namespace Tensorflow.Keras.Layers | |||||
SupportsMasking = mask_zero; | SupportsMasking = mask_zero; | ||||
} | } | ||||
protected override void build(Tensors inputs) | |||||
public override void build(Shape input_shape) | |||||
{ | { | ||||
tf.Context.eager_mode(); | tf.Context.eager_mode(); | ||||
embeddings = add_weight(shape: (input_dim, output_dim), | embeddings = add_weight(shape: (input_dim, output_dim), | ||||
@@ -2,49 +2,61 @@ | |||||
using Tensorflow.Keras.Engine; | using Tensorflow.Keras.Engine; | ||||
namespace Tensorflow.Keras.Layers { | namespace Tensorflow.Keras.Layers { | ||||
public class Cropping1D : Layer { | |||||
CroppingArgs args; | |||||
public Cropping1D ( CroppingArgs args ) : base(args) { | |||||
this.args = args; | |||||
} | |||||
public class Cropping1D : Layer | |||||
{ | |||||
CroppingArgs args; | |||||
public Cropping1D(CroppingArgs args) : base(args) | |||||
{ | |||||
this.args = args; | |||||
} | |||||
protected override void build ( Tensors inputs ) { | |||||
if ( args.cropping.rank != 1 ) { | |||||
// throw an ValueError exception | |||||
throw new ValueError(""); | |||||
} | |||||
else if ( args.cropping.shape[0] > 2 || args.cropping.shape[0] < 1 ) { | |||||
throw new ValueError("The `cropping` argument must be a tuple of 2 integers."); | |||||
} | |||||
built = true; | |||||
public override void build(Shape input_shape) | |||||
{ | |||||
if (args.cropping.rank != 1) | |||||
{ | |||||
// throw an ValueError exception | |||||
throw new ValueError(""); | |||||
} | |||||
else if (args.cropping.shape[0] > 2 || args.cropping.shape[0] < 1) | |||||
{ | |||||
throw new ValueError("The `cropping` argument must be a tuple of 2 integers."); | |||||
} | } | ||||
built = true; | |||||
} | |||||
protected override Tensors Call ( Tensors inputs, Tensor state = null, bool? training = null ) { | |||||
Tensor output = inputs; | |||||
if ( output.rank != 3 ) { | |||||
// throw an ValueError exception | |||||
throw new ValueError("Expected dim=3, found dim=" + output.rank); | |||||
} | |||||
if ( args.cropping.shape[0] == 1 ) { | |||||
int crop_start = args.cropping[0]; | |||||
output = output[new Slice(), new Slice(crop_start, ( int ) output.shape[1] - crop_start), new Slice()]; | |||||
} | |||||
else { | |||||
int crop_start = args.cropping[0], crop_end = args.cropping[1]; | |||||
output = output[new Slice(), new Slice(crop_start, ( int ) (output.shape[1]) - crop_end), new Slice()]; | |||||
} | |||||
return output; | |||||
protected override Tensors Call(Tensors inputs, Tensor state = null, bool? training = null) | |||||
{ | |||||
Tensor output = inputs; | |||||
if (output.rank != 3) | |||||
{ | |||||
// throw an ValueError exception | |||||
throw new ValueError("Expected dim=3, found dim=" + output.rank); | |||||
} | |||||
if (args.cropping.shape[0] == 1) | |||||
{ | |||||
int crop_start = args.cropping[0]; | |||||
output = output[new Slice(), new Slice(crop_start, (int)output.shape[1] - crop_start), new Slice()]; | |||||
} | } | ||||
else | |||||
{ | |||||
int crop_start = args.cropping[0], crop_end = args.cropping[1]; | |||||
output = output[new Slice(), new Slice(crop_start, (int)(output.shape[1]) - crop_end), new Slice()]; | |||||
} | |||||
return output; | |||||
} | |||||
public override Shape ComputeOutputShape ( Shape input_shape ) { | |||||
if ( args.cropping.shape[0] == 1 ) { | |||||
int crop = args.cropping[0]; | |||||
return new Shape(( int ) (input_shape[0]), ( int ) (input_shape[1] - crop * 2), ( int ) (input_shape[2])); | |||||
} | |||||
else { | |||||
int crop_start = args.cropping[0], crop_end = args.cropping[1]; | |||||
return new Shape(( int ) (input_shape[0]), ( int ) (input_shape[1] - crop_start - crop_end), ( int ) (input_shape[2])); | |||||
} | |||||
public override Shape ComputeOutputShape(Shape input_shape) | |||||
{ | |||||
if (args.cropping.shape[0] == 1) | |||||
{ | |||||
int crop = args.cropping[0]; | |||||
return new Shape((int)(input_shape[0]), (int)(input_shape[1] - crop * 2), (int)(input_shape[2])); | |||||
} | |||||
else | |||||
{ | |||||
int crop_start = args.cropping[0], crop_end = args.cropping[1]; | |||||
return new Shape((int)(input_shape[0]), (int)(input_shape[1] - crop_start - crop_end), (int)(input_shape[2])); | |||||
} | } | ||||
} | |||||
} | |||||
} | |||||
} | } |
@@ -12,7 +12,7 @@ namespace Tensorflow.Keras.Layers { | |||||
public Cropping2D ( Cropping2DArgs args ) : base(args) { | public Cropping2D ( Cropping2DArgs args ) : base(args) { | ||||
this.args = args; | this.args = args; | ||||
} | } | ||||
protected override void build ( Tensors inputs ) { | |||||
public override void build(Shape input_shape) { | |||||
built = true; | built = true; | ||||
} | } | ||||
protected override Tensors Call ( Tensors inputs, Tensor state = null, bool? training = null ) { | protected override Tensors Call ( Tensors inputs, Tensor state = null, bool? training = null ) { | ||||
@@ -11,7 +11,7 @@ namespace Tensorflow.Keras.Layers { | |||||
this.args = args; | this.args = args; | ||||
} | } | ||||
protected override void build ( Tensors inputs ) { | |||||
public override void build(Shape input_shape) { | |||||
built = true; | built = true; | ||||
} | } | ||||
@@ -23,7 +23,7 @@ namespace Tensorflow.Keras.Layers | |||||
this.args = args; | this.args = args; | ||||
} | } | ||||
protected override void build(Tensors inputs) | |||||
public override void build(Shape input_shape) | |||||
{ | { | ||||
/*var shape_set = new HashSet<Shape>(); | /*var shape_set = new HashSet<Shape>(); | ||||
var reduced_inputs_shapes = inputs.Select(x => x.shape).ToArray(); | var reduced_inputs_shapes = inputs.Select(x => x.shape).ToArray(); | ||||
@@ -14,7 +14,7 @@ namespace Tensorflow.Keras.Layers | |||||
} | } | ||||
protected override void build(Tensors inputs) | |||||
public override void build(Shape input_shape) | |||||
{ | { | ||||
// output_shape = input_shape.dims[1^]; | // output_shape = input_shape.dims[1^]; | ||||
} | } | ||||
@@ -53,9 +53,8 @@ namespace Tensorflow.Keras.Layers | |||||
axis = args.Axis.dims.Select(x => (int)x).ToArray(); | axis = args.Axis.dims.Select(x => (int)x).ToArray(); | ||||
} | } | ||||
protected override void build(Tensors inputs) | |||||
public override void build(Shape input_shape) | |||||
{ | { | ||||
Shape input_shape = inputs.shape; | |||||
var ndims = input_shape.ndim; | var ndims = input_shape.ndim; | ||||
foreach (var (idx, x) in enumerate(axis)) | foreach (var (idx, x) in enumerate(axis)) | ||||
if (x < 0) | if (x < 0) | ||||
@@ -49,9 +49,8 @@ namespace Tensorflow.Keras.Layers | |||||
axis = args.Axis.axis; | axis = args.Axis.axis; | ||||
} | } | ||||
protected override void build(Tensors inputs) | |||||
public override void build(Shape input_shape) | |||||
{ | { | ||||
Shape input_shape = inputs.shape; | |||||
var ndims = input_shape.ndim; | var ndims = input_shape.ndim; | ||||
foreach (var (idx, x) in enumerate(axis)) | foreach (var (idx, x) in enumerate(axis)) | ||||
if (x < 0) | if (x < 0) | ||||
@@ -35,14 +35,14 @@ namespace Tensorflow.Keras.Layers | |||||
var shape = data.output_shapes[0]; | var shape = data.output_shapes[0]; | ||||
if (shape.ndim == 1) | if (shape.ndim == 1) | ||||
data = data.map(tensor => array_ops.expand_dims(tensor, -1)); | data = data.map(tensor => array_ops.expand_dims(tensor, -1)); | ||||
build(data.variant_tensor); | |||||
build(data.variant_tensor.shape); | |||||
var preprocessed_inputs = data.map(_preprocess); | var preprocessed_inputs = data.map(_preprocess); | ||||
_index_lookup_layer.adapt(preprocessed_inputs); | _index_lookup_layer.adapt(preprocessed_inputs); | ||||
} | } | ||||
protected override void build(Tensors inputs) | |||||
public override void build(Shape input_shape) | |||||
{ | { | ||||
base.build(inputs); | |||||
base.build(input_shape); | |||||
} | } | ||||
Tensors _preprocess(Tensors inputs) | Tensors _preprocess(Tensors inputs) | ||||
@@ -7,32 +7,39 @@ using static Tensorflow.Binding; | |||||
using Tensorflow.Keras.ArgsDefinition; | using Tensorflow.Keras.ArgsDefinition; | ||||
namespace Tensorflow.Keras.Layers { | namespace Tensorflow.Keras.Layers { | ||||
public class Permute : Layer { | |||||
int[] dims, permute; | |||||
public Permute ( PermuteArgs args ) : base(args) { | |||||
this.dims = args.dims; | |||||
public class Permute : Layer | |||||
{ | |||||
int[] dims, permute; | |||||
public Permute(PermuteArgs args) : base(args) | |||||
{ | |||||
this.dims = args.dims; | |||||
} | |||||
public override void build(Shape input_shape) | |||||
{ | |||||
var rank = input_shape.rank; | |||||
if (dims.Length != rank - 1) | |||||
{ | |||||
throw new ValueError("Dimensions must match."); | |||||
} | } | ||||
protected override void build ( Tensors inputs ) { | |||||
var rank = inputs.rank; | |||||
if ( dims.Length != rank - 1 ) { | |||||
throw new ValueError("Dimensions must match."); | |||||
} | |||||
permute = new int[inputs.rank]; | |||||
dims.CopyTo(permute, 1); | |||||
built = true; | |||||
permute = new int[input_shape.rank]; | |||||
dims.CopyTo(permute, 1); | |||||
built = true; | |||||
} | |||||
protected override Tensors Call(Tensors inputs, Tensor state = null, bool? training = null) | |||||
{ | |||||
Tensor outputs = inputs; | |||||
return tf.transpose(outputs, new Axis(permute)); | |||||
} | |||||
public override Shape ComputeOutputShape(Shape input_shape) | |||||
{ | |||||
Shape output_shape = new Shape(input_shape.dims); | |||||
for (int i = 0; i < dims.Length; i += 1) | |||||
{ | |||||
var d = dims[i]; | |||||
var target_dim = input_shape[d]; | |||||
output_shape[i + 1] = target_dim; | |||||
} | } | ||||
protected override Tensors Call ( Tensors inputs, Tensor state = null, bool? training = null ) { | |||||
Tensor outputs = inputs; | |||||
return tf.transpose(outputs, new Axis(permute)); | |||||
} | |||||
public override Shape ComputeOutputShape ( Shape input_shape ) { | |||||
Shape output_shape = new Shape(input_shape.dims); | |||||
for ( int i = 0; i < dims.Length; i += 1 ) { | |||||
var d = dims[i]; | |||||
var target_dim = input_shape[d]; | |||||
output_shape[i + 1] = target_dim; | |||||
} | |||||
return output_shape; | |||||
} | |||||
} | |||||
return output_shape; | |||||
} | |||||
} | |||||
} | } |
@@ -15,9 +15,8 @@ namespace Tensorflow.Keras.Layers.Rnn | |||||
this.args = args; | this.args = args; | ||||
} | } | ||||
protected override void build(Tensors inputs) | |||||
public override void build(Shape input_shape) | |||||
{ | { | ||||
var input_shape = inputs.shape; | |||||
var input_dim = input_shape[-1]; | var input_dim = input_shape[-1]; | ||||
kernel = add_weight("kernel", (input_shape[-1], args.Units), | kernel = add_weight("kernel", (input_shape[-1], args.Units), | ||||
@@ -13,7 +13,7 @@ namespace Tensorflow.Keras.Layers.Rnn | |||||
} | } | ||||
protected override void build(Tensors inputs) | |||||
public override void build(Shape input_shape) | |||||
{ | { | ||||
} | } | ||||