@@ -0,0 +1,9 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Text; | |||
namespace Tensorflow.Keras.ArgsDefinition { | |||
public class ELUArgs : LayerArgs { | |||
public float Alpha { get; set; } = 0.1f; | |||
} | |||
} |
@@ -0,0 +1,16 @@ | |||
using Tensorflow.NumPy; | |||
namespace Tensorflow.Keras.ArgsDefinition { | |||
public class Cropping2DArgs : LayerArgs { | |||
/// <summary> | |||
/// channel last: (b, h, w, c) | |||
/// channels_first: (b, c, h, w) | |||
/// </summary> | |||
public enum DataFormat { channels_first = 0, channels_last = 1 } | |||
/// <summary> | |||
/// Accept: int[1][2], int[1][1], int[2][2] | |||
/// </summary> | |||
public NDArray cropping { get; set; } | |||
public DataFormat data_format { get; set; } = DataFormat.channels_last; | |||
} | |||
} |
@@ -0,0 +1,16 @@ | |||
using Tensorflow.NumPy; | |||
namespace Tensorflow.Keras.ArgsDefinition { | |||
public class Cropping3DArgs : LayerArgs { | |||
/// <summary> | |||
/// channel last: (b, h, w, c) | |||
/// channels_first: (b, c, h, w) | |||
/// </summary> | |||
public enum DataFormat { channels_first = 0, channels_last = 1 } | |||
/// <summary> | |||
/// Accept: int[1][3], int[1][1], int[3][2] | |||
/// </summary> | |||
public NDArray cropping { get; set; } | |||
public DataFormat data_format { get; set; } = DataFormat.channels_last; | |||
} | |||
} |
@@ -0,0 +1,10 @@ | |||
using Tensorflow.NumPy; | |||
namespace Tensorflow.Keras.ArgsDefinition { | |||
public class CroppingArgs : LayerArgs { | |||
/// <summary> | |||
/// Accept length 1 or 2 | |||
/// </summary> | |||
public NDArray cropping { get; set; } | |||
} | |||
} |
@@ -0,0 +1,5 @@ | |||
namespace Tensorflow.Keras.ArgsDefinition { | |||
public class PermuteArgs : LayerArgs { | |||
public int[] dims { get; set; } | |||
} | |||
} |
@@ -0,0 +1,37 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Text; | |||
using Tensorflow.Keras.ArgsDefinition; | |||
using Tensorflow.Keras.Engine; | |||
using static Tensorflow.Binding; | |||
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; | |||
if ( alpha != 1f ) { | |||
output = tf.where(output > 0f, output, alpha * (tf.exp(output) - 1f)); | |||
} | |||
return output; | |||
} | |||
public override Shape ComputeOutputShape ( Shape input_shape ) { | |||
return input_shape; | |||
} | |||
} | |||
} |
@@ -0,0 +1,32 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Text; | |||
using Tensorflow.Keras.ArgsDefinition; | |||
using Tensorflow.Keras.Engine; | |||
using static Tensorflow.Binding; | |||
namespace Tensorflow.Keras.Layers { | |||
/// <summary> | |||
/// SELU Layer: | |||
/// similar to ELU, but has pre-defined alpha and scale | |||
/// </summary> | |||
public class SELU : Layer { | |||
protected const float alpha = 1.67326324f, scale = 1.05070098f; | |||
public SELU ( LayerArgs args ) : base(args) { | |||
// SELU has no arguments | |||
} | |||
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; | |||
return tf.where(output > 0f, scale * output, scale * alpha * (tf.exp(output) - 1f)); | |||
} | |||
public override Shape ComputeOutputShape ( Shape input_shape ) { | |||
return input_shape; | |||
} | |||
} | |||
} |
@@ -0,0 +1,50 @@ | |||
using Tensorflow.Keras.ArgsDefinition; | |||
using Tensorflow.Keras.Engine; | |||
namespace Tensorflow.Keras.Layers { | |||
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; | |||
} | |||
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])); | |||
} | |||
} | |||
} | |||
} |
@@ -0,0 +1,113 @@ | |||
using Tensorflow.Keras.ArgsDefinition; | |||
using Tensorflow.Keras.Engine; | |||
namespace Tensorflow.Keras.Layers { | |||
/// <summary> | |||
/// Crop the input along axis 1 and 2. | |||
/// <para> For example: </para> | |||
/// <para> shape (1, 5, 5, 5) -- crop2D ((1, 2), (1, 3)) --> shape (1, 2, 1, 5) </para> | |||
/// </summary> | |||
public class Cropping2D : Layer { | |||
Cropping2DArgs args; | |||
public Cropping2D ( Cropping2DArgs args ) : base(args) { | |||
this.args = args; | |||
} | |||
protected override void build ( Tensors inputs ) { | |||
built = true; | |||
} | |||
protected override Tensors Call ( Tensors inputs, Tensor state = null, bool? training = null ) { | |||
Tensor output = inputs; | |||
if ( output.rank != 4 ) { | |||
// throw an ValueError exception | |||
throw new ValueError("Expected dim=4, found dim=" + output.rank); | |||
} | |||
if ( args.cropping.shape == new Shape(1) ) { | |||
int crop = args.cropping[0]; | |||
if ( args.data_format == Cropping2DArgs.DataFormat.channels_last ) { | |||
output = output[new Slice(), | |||
new Slice(crop, ( int ) output.shape[1] - crop), | |||
new Slice(crop, ( int ) output.shape[2] - crop), | |||
new Slice()]; | |||
} | |||
else { | |||
output = output[new Slice(), | |||
new Slice(), | |||
new Slice(crop, ( int ) output.shape[2] - crop), | |||
new Slice(crop, ( int ) output.shape[3] - crop)]; | |||
} | |||
} | |||
// a tuple of 2 integers | |||
else if ( args.cropping.shape == new Shape(2) ) { | |||
int crop_1 = args.cropping[0]; | |||
int crop_2 = args.cropping[1]; | |||
if ( args.data_format == Cropping2DArgs.DataFormat.channels_last ) { | |||
output = output[new Slice(), | |||
new Slice(crop_1, ( int ) output.shape[1] - crop_1), | |||
new Slice(crop_2, ( int ) output.shape[2] - crop_2), | |||
new Slice()]; | |||
} | |||
else { | |||
output = output[new Slice(), | |||
new Slice(), | |||
new Slice(crop_1, ( int ) output.shape[2] - crop_1), | |||
new Slice(crop_2, ( int ) output.shape[3] - crop_2)]; | |||
} | |||
} | |||
else if ( args.cropping.shape[0] == 2 && args.cropping.shape[1] == 2 ) { | |||
int x_start = args.cropping[0, 0], x_end = args.cropping[0, 1]; | |||
int y_start = args.cropping[1, 0], y_end = args.cropping[1, 1]; | |||
if ( args.data_format == Cropping2DArgs.DataFormat.channels_last ) { | |||
output = output[new Slice(), | |||
new Slice(x_start, ( int ) output.shape[1] - x_end), | |||
new Slice(y_start, ( int ) output.shape[2] - y_end), | |||
new Slice()]; | |||
} | |||
else { | |||
output = output[new Slice(), | |||
new Slice(), | |||
new Slice(x_start, ( int ) output.shape[2] - x_end), | |||
new Slice(y_start, ( int ) output.shape[3] - y_end) | |||
]; | |||
} | |||
} | |||
return output; | |||
} | |||
public override Shape ComputeOutputShape ( Shape input_shape ) { | |||
if ( args.cropping.shape == new Shape(1) ) { | |||
int crop = args.cropping[0]; | |||
if ( args.data_format == Cropping2DArgs.DataFormat.channels_last ) { | |||
return new Shape(( int ) input_shape[0], ( int ) input_shape[1] - crop * 2, ( int ) input_shape[2] - crop * 2, ( int ) input_shape[3]); | |||
} | |||
else { | |||
return new Shape(( int ) input_shape[0], ( int ) input_shape[1], ( int ) input_shape[2] - crop * 2, ( int ) input_shape[3] - crop * 2); | |||
} | |||
} | |||
// a tuple of 2 integers | |||
else if ( args.cropping.shape == new Shape(2) ) { | |||
int crop_1 = args.cropping[0], crop_2 = args.cropping[1]; | |||
if ( args.data_format == Cropping2DArgs.DataFormat.channels_last ) { | |||
return new Shape(( int ) input_shape[0], ( int ) input_shape[1] - crop_1 * 2, ( int ) input_shape[2] - crop_2 * 2, ( int ) input_shape[3]); | |||
} | |||
else { | |||
return new Shape(( int ) input_shape[0], ( int ) input_shape[1], ( int ) input_shape[2] - crop_1 * 2, ( int ) input_shape[3] - crop_2 * 2); | |||
} | |||
} | |||
else if ( args.cropping.shape == new Shape(2, 2) ) { | |||
int crop_1_start = args.cropping[0, 0], crop_1_end = args.cropping[0, 1]; | |||
int crop_2_start = args.cropping[1, 0], crop_2_end = args.cropping[1, 1]; | |||
if ( args.data_format == Cropping2DArgs.DataFormat.channels_last ) { | |||
return new Shape(( int ) input_shape[0], ( int ) input_shape[1] - crop_1_start - crop_1_end, | |||
( int ) input_shape[2] - crop_2_start - crop_2_end, ( int ) input_shape[3]); | |||
} | |||
else { | |||
return new Shape(( int ) input_shape[0], ( int ) input_shape[1], | |||
( int ) input_shape[2] - crop_1_start - crop_1_end, ( int ) input_shape[3] - crop_2_start - crop_2_end); | |||
} | |||
} | |||
else { | |||
throw new ValueError(); | |||
} | |||
} | |||
} | |||
} |
@@ -0,0 +1,123 @@ | |||
using Tensorflow.Keras.ArgsDefinition; | |||
using Tensorflow.Keras.Engine; | |||
namespace Tensorflow.Keras.Layers { | |||
/// <summary> | |||
/// Similar to copping 2D | |||
/// </summary> | |||
public class Cropping3D : Layer { | |||
Cropping3DArgs args; | |||
public Cropping3D ( Cropping3DArgs args ) : base(args) { | |||
this.args = args; | |||
} | |||
protected override void build ( Tensors inputs ) { | |||
built = true; | |||
} | |||
protected override Tensors Call ( Tensors inputs, Tensor state = null, bool? training = null ) { | |||
Tensor output = inputs; | |||
if ( output.rank != 5 ) { | |||
// throw an ValueError exception | |||
throw new ValueError("Expected dim=5, found dim=" + output.rank); | |||
} | |||
if ( args.cropping.shape == new Shape(1) ) { | |||
int crop = args.cropping[0]; | |||
if ( args.data_format == Cropping3DArgs.DataFormat.channels_last ) { | |||
output = output[new Slice(), | |||
new Slice(crop, ( int ) output.shape[1] - crop), | |||
new Slice(crop, ( int ) output.shape[2] - crop), | |||
new Slice(crop, ( int ) output.shape[3] - crop), | |||
new Slice()]; | |||
} | |||
else { | |||
output = output[new Slice(), | |||
new Slice(), | |||
new Slice(crop, ( int ) output.shape[2] - crop), | |||
new Slice(crop, ( int ) output.shape[3] - crop), | |||
new Slice(crop, ( int ) output.shape[4] - crop)]; | |||
} | |||
} | |||
// int[1][3] equivalent to a tuple of 3 integers | |||
else if ( args.cropping.shape == new Shape(3) ) { | |||
var crop_1 = args.cropping[0]; | |||
var crop_2 = args.cropping[1]; | |||
var crop_3 = args.cropping[2]; | |||
if ( args.data_format == Cropping3DArgs.DataFormat.channels_last ) { | |||
output = output[new Slice(), | |||
new Slice(crop_1, ( int ) output.shape[1] - crop_1), | |||
new Slice(crop_2, ( int ) output.shape[2] - crop_2), | |||
new Slice(crop_3, ( int ) output.shape[3] - crop_3), | |||
new Slice()]; | |||
} | |||
else { | |||
output = output[new Slice(), | |||
new Slice(), | |||
new Slice(crop_1, ( int ) output.shape[2] - crop_1), | |||
new Slice(crop_2, ( int ) output.shape[3] - crop_2), | |||
new Slice(crop_3, ( int ) output.shape[4] - crop_3)]; | |||
} | |||
} | |||
else if ( args.cropping.shape[0] == 3 && args.cropping.shape[1] == 2 ) { | |||
int x = args.cropping[0, 0], x_end = args.cropping[0, 1]; | |||
int y = args.cropping[1, 0], y_end = args.cropping[1, 1]; | |||
int z = args.cropping[2, 0], z_end = args.cropping[2, 1]; | |||
if ( args.data_format == Cropping3DArgs.DataFormat.channels_last ) { | |||
output = output[new Slice(), | |||
new Slice(x, ( int ) output.shape[1] - x_end), | |||
new Slice(y, ( int ) output.shape[2] - y_end), | |||
new Slice(z, ( int ) output.shape[3] - z_end), | |||
new Slice()]; | |||
} | |||
else { | |||
output = output[new Slice(), | |||
new Slice(), | |||
new Slice(x, ( int ) output.shape[2] - x_end), | |||
new Slice(y, ( int ) output.shape[3] - y_end), | |||
new Slice(z, ( int ) output.shape[4] - z_end) | |||
]; | |||
} | |||
} | |||
return output; | |||
} | |||
public override Shape ComputeOutputShape ( Shape input_shape ) { | |||
if ( args.cropping.shape == new Shape(1) ) { | |||
int crop = args.cropping[0]; | |||
if ( args.data_format == Cropping3DArgs.DataFormat.channels_last ) { | |||
return new Shape(( int ) input_shape[0], ( int ) input_shape[1] - crop * 2, ( int ) input_shape[2] - crop * 2, ( int ) input_shape[3] - crop * 2, ( int ) input_shape[4]); | |||
} | |||
else { | |||
return new Shape(( int ) input_shape[0], ( int ) input_shape[1], ( int ) input_shape[2] - crop * 2, ( int ) input_shape[3] - crop * 2, ( int ) input_shape[4] - crop * 2); | |||
} | |||
} | |||
// int[1][3] equivalent to a tuple of 3 integers | |||
else if ( args.cropping.shape == new Shape(3) ) { | |||
var crop_start_1 = args.cropping[0]; | |||
var crop_start_2 = args.cropping[1]; | |||
var crop_start_3 = args.cropping[2]; | |||
if ( args.data_format == Cropping3DArgs.DataFormat.channels_last ) { | |||
return new Shape(( int ) input_shape[0], ( int ) input_shape[1] - crop_start_1 * 2, ( int ) input_shape[2] - crop_start_2 * 2, ( int ) input_shape[3] - crop_start_3 * 2, ( int ) input_shape[4]); | |||
} | |||
else { | |||
return new Shape(( int ) input_shape[0], ( int ) input_shape[1], ( int ) input_shape[2] - crop_start_1 * 2, ( int ) input_shape[3] - crop_start_2 * 2, ( int ) input_shape[4] - crop_start_3 * 2); | |||
} | |||
} | |||
else if ( args.cropping.shape == new Shape(3, 2) ) { | |||
int x = args.cropping[0, 0], x_end = args.cropping[0, 1]; | |||
int y = args.cropping[1, 0], y_end = args.cropping[1, 1]; | |||
int z = args.cropping[2, 0], z_end = args.cropping[2, 1]; | |||
if ( args.data_format == Cropping3DArgs.DataFormat.channels_last ) { | |||
return new Shape(( int ) input_shape[0], ( int ) input_shape[1] - x - x_end, ( int ) input_shape[2] - y - y_end, ( int ) input_shape[3] - z - z_end, ( int ) input_shape[4]); | |||
} | |||
else { | |||
return new Shape(( int ) input_shape[0], ( int ) input_shape[1], ( int ) input_shape[2] - x - x_end, ( int ) input_shape[3] - y - y_end, ( int ) input_shape[4] - z - z_end); | |||
} | |||
} | |||
else { | |||
throw new ValueError(); | |||
} | |||
} | |||
} | |||
} |
@@ -0,0 +1,36 @@ | |||
using Tensorflow.NumPy; | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Text; | |||
using Tensorflow.Keras.ArgsDefinition; | |||
namespace Tensorflow.Keras.Layers { | |||
public partial class LayersApi { | |||
/// <summary> | |||
/// Cropping layer for 1D input | |||
/// </summary> | |||
/// <param name="cropping">cropping size</param> | |||
public Cropping1D Cropping1D ( NDArray cropping ) | |||
=> new Cropping1D(new CroppingArgs { | |||
cropping = cropping | |||
}); | |||
/// <summary> | |||
/// Cropping layer for 2D input <br/> | |||
/// </summary> | |||
public Cropping2D Cropping2D ( NDArray cropping, Cropping2DArgs.DataFormat data_format = Cropping2DArgs.DataFormat.channels_last ) | |||
=> new Cropping2D(new Cropping2DArgs { | |||
cropping = cropping, | |||
data_format = data_format | |||
}); | |||
/// <summary> | |||
/// Cropping layer for 3D input <br/> | |||
/// </summary> | |||
public Cropping3D Cropping3D ( NDArray cropping, Cropping3DArgs.DataFormat data_format = Cropping3DArgs.DataFormat.channels_last ) | |||
=> new Cropping3D(new Cropping3DArgs { | |||
cropping = cropping, | |||
data_format = data_format | |||
}); | |||
} | |||
} |
@@ -4,52 +4,54 @@ using System.Collections.Generic; | |||
using System.Text; | |||
using Tensorflow.Keras.ArgsDefinition; | |||
namespace Tensorflow.Keras.Layers | |||
{ | |||
public partial class LayersApi | |||
{ | |||
/// <summary> | |||
/// Zero-padding layer for 2D input (e.g. picture). | |||
/// </summary> | |||
/// <param name="padding"></param> | |||
/// <returns></returns> | |||
public ZeroPadding2D ZeroPadding2D(NDArray padding) | |||
=> new ZeroPadding2D(new ZeroPadding2DArgs | |||
{ | |||
Padding = padding | |||
}); | |||
namespace Tensorflow.Keras.Layers { | |||
public partial class LayersApi { | |||
/// <summary> | |||
/// Zero-padding layer for 2D input (e.g. picture). | |||
/// </summary> | |||
/// <param name="padding"></param> | |||
/// <returns></returns> | |||
public ZeroPadding2D ZeroPadding2D ( NDArray padding ) | |||
=> new ZeroPadding2D(new ZeroPadding2DArgs { | |||
Padding = padding | |||
}); | |||
/// <summary> | |||
/// Upsampling layer for 2D inputs.<br/> | |||
/// Repeats the rows and columns of the data by size[0] and size[1] respectively. | |||
/// </summary> | |||
/// <param name="size"></param> | |||
/// <param name="data_format"></param> | |||
/// <param name="interpolation"></param> | |||
/// <returns></returns> | |||
public UpSampling2D UpSampling2D(Shape size = null, | |||
string data_format = null, | |||
string interpolation = "nearest") | |||
=> new UpSampling2D(new UpSampling2DArgs | |||
{ | |||
Size = size ?? (2, 2) | |||
}); | |||
/// <summary> | |||
/// Upsampling layer for 2D inputs.<br/> | |||
/// Repeats the rows and columns of the data by size[0] and size[1] respectively. | |||
/// </summary> | |||
/// <param name="size"></param> | |||
/// <param name="data_format"></param> | |||
/// <param name="interpolation"></param> | |||
/// <returns></returns> | |||
public UpSampling2D UpSampling2D ( Shape size = null, | |||
string data_format = null, | |||
string interpolation = "nearest" ) | |||
=> new UpSampling2D(new UpSampling2DArgs { | |||
Size = size ?? (2, 2) | |||
}); | |||
/// <summary> | |||
/// Layer that reshapes inputs into the given shape. | |||
/// </summary> | |||
/// <param name="target_shape"></param> | |||
/// <returns></returns> | |||
public Reshape Reshape(Shape target_shape) | |||
=> new Reshape(new ReshapeArgs | |||
{ | |||
TargetShape = target_shape | |||
}); | |||
/// <summary> | |||
/// Permutes the dimensions of the input according to a given pattern. | |||
/// </summary> | |||
public Permute Permute ( int[] dims ) | |||
=> new Permute(new PermuteArgs { | |||
dims = dims | |||
}); | |||
public Reshape Reshape(object[] target_shape) | |||
=> new Reshape(new ReshapeArgs | |||
{ | |||
TargetShapeObjects = target_shape | |||
/// <summary> | |||
/// Layer that reshapes inputs into the given shape. | |||
/// </summary> | |||
/// <param name="target_shape"></param> | |||
/// <returns></returns> | |||
public Reshape Reshape ( Shape target_shape ) | |||
=> new Reshape(new ReshapeArgs { | |||
TargetShape = target_shape | |||
}); | |||
} | |||
public Reshape Reshape ( object[] target_shape ) | |||
=> new Reshape(new ReshapeArgs { | |||
TargetShapeObjects = target_shape | |||
}); | |||
} | |||
} |
@@ -0,0 +1,38 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Linq; | |||
using Tensorflow.Keras.Engine; | |||
using Tensorflow.Keras.Utils; | |||
using static Tensorflow.Binding; | |||
using Tensorflow.Keras.ArgsDefinition; | |||
namespace Tensorflow.Keras.Layers { | |||
public class Permute : Layer { | |||
int[] dims, permute; | |||
public Permute ( PermuteArgs args ) : base(args) { | |||
this.dims = args.dims; | |||
} | |||
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; | |||
} | |||
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; | |||
} | |||
} | |||
} |
@@ -0,0 +1,39 @@ | |||
using Microsoft.VisualStudio.TestTools.UnitTesting; | |||
using Tensorflow; | |||
using Tensorflow.NumPy; | |||
using static Tensorflow.Binding; | |||
using static Tensorflow.KerasApi; | |||
namespace TensorFlowNET.Keras.UnitTest { | |||
[TestClass] | |||
public class LayersCroppingTest : EagerModeTestBase { | |||
[TestMethod] | |||
public void Cropping1D () { | |||
Shape input_shape = (1, 5, 2); | |||
var x = tf.zeros(input_shape); | |||
var cropping_1d = keras.layers.Cropping1D(new[] { 1, 2 }); | |||
var y = cropping_1d.Apply(x); | |||
Assert.AreEqual((1, 2, 2), y.shape); | |||
} | |||
[TestMethod] | |||
public void Cropping2D () { | |||
Shape input_shape = (1, 5, 6, 1); | |||
NDArray cropping = new NDArray(new[,] { { 1, 2 }, { 1, 3 } }); | |||
var x = tf.zeros(input_shape); | |||
var cropping_2d = keras.layers.Cropping2D(cropping); | |||
var y = cropping_2d.Apply(x); | |||
Assert.AreEqual((1, 2, 2, 1), y.shape); | |||
} | |||
[TestMethod] | |||
public void Cropping3D () { | |||
Shape input_shape = new Shape(1, 5, 6, 7, 1); | |||
NDArray cropping = new NDArray(new[,] { { 1, 2 }, { 1, 3 }, { 1, 4 } }); | |||
var x = tf.zeros(input_shape); | |||
var cropping_3d = keras.layers.Cropping3D(cropping); | |||
var y = cropping_3d.Apply(x); | |||
Assert.AreEqual(new Shape(1, 2, 2, 2, 1), y.shape); | |||
} | |||
} | |||
} |
@@ -4,37 +4,40 @@ using Tensorflow.NumPy; | |||
using static Tensorflow.Binding; | |||
using static Tensorflow.KerasApi; | |||
namespace TensorFlowNET.Keras.UnitTest | |||
{ | |||
[TestClass] | |||
public class LayersReshapingTest : EagerModeTestBase | |||
{ | |||
[TestMethod] | |||
public void ZeroPadding2D() | |||
{ | |||
Shape input_shape = (1, 1, 2, 2); | |||
var x = np.arange(input_shape.size).reshape(input_shape); | |||
var zero_padding_2d = keras.layers.ZeroPadding2D(new[,] { { 1, 0 }, { 1, 0 } }); | |||
var y = zero_padding_2d.Apply(x); | |||
Assert.AreEqual((1, 2, 3, 2), y.shape); | |||
} | |||
namespace TensorFlowNET.Keras.UnitTest { | |||
[TestClass] | |||
public class LayersReshapingTest : EagerModeTestBase { | |||
[TestMethod] | |||
public void ZeroPadding2D () { | |||
Shape input_shape = (1, 1, 2, 2); | |||
var x = np.arange(input_shape.size).reshape(input_shape); | |||
var zero_padding_2d = keras.layers.ZeroPadding2D(new[,] { { 1, 0 }, { 1, 0 } }); | |||
var y = zero_padding_2d.Apply(x); | |||
Assert.AreEqual((1, 2, 3, 2), y.shape); | |||
} | |||
[TestMethod] | |||
public void UpSampling2D() | |||
{ | |||
Shape input_shape = (2, 2, 1, 3); | |||
var x = np.arange(input_shape.size).reshape(input_shape); | |||
var y = keras.layers.UpSampling2D(size: (1, 2)).Apply(x); | |||
Assert.AreEqual((2, 2, 2, 3), y.shape); | |||
} | |||
[TestMethod] | |||
public void UpSampling2D () { | |||
Shape input_shape = (2, 2, 1, 3); | |||
var x = np.arange(input_shape.size).reshape(input_shape); | |||
var y = keras.layers.UpSampling2D(size: (1, 2)).Apply(x); | |||
Assert.AreEqual((2, 2, 2, 3), y.shape); | |||
} | |||
[TestMethod] | |||
public void Reshape() | |||
{ | |||
var inputs = tf.zeros((10, 5, 20)); | |||
var outputs = keras.layers.LeakyReLU().Apply(inputs); | |||
outputs = keras.layers.Reshape((20, 5)).Apply(outputs); | |||
Assert.AreEqual((10, 20, 5), outputs.shape); | |||
} | |||
} | |||
[TestMethod] | |||
public void Reshape () { | |||
var inputs = tf.zeros((10, 5, 20)); | |||
var outputs = keras.layers.LeakyReLU().Apply(inputs); | |||
outputs = keras.layers.Reshape((20, 5)).Apply(outputs); | |||
Assert.AreEqual((10, 20, 5), outputs.shape); | |||
} | |||
[TestMethod] | |||
public void Permute () { | |||
var inputs = tf.zeros((2, 3, 4, 5)); | |||
var outputs = keras.layers.Permute(new int[] { 3, 2, 1 }).Apply(inputs); | |||
Assert.AreEqual((2, 5, 4, 3), outputs.shape); | |||
} | |||
} | |||
} |