@@ -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 System.Text; | ||||
using Tensorflow.Keras.ArgsDefinition; | 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.Binding; | ||||
using static Tensorflow.KerasApi; | 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); | |||||
} | |||||
} | |||||
} | } |