| @@ -0,0 +1,9 @@ | |||
| using System; | |||
| using System.Collections.Generic; | |||
| using System.Text; | |||
| namespace Tensorflow.Keras.ArgsDefinition { | |||
| public class SoftmaxArgs : LayerArgs { | |||
| public Axis axis { get; set; } = -1; | |||
| } | |||
| } | |||
| @@ -24,12 +24,10 @@ namespace Tensorflow.Keras.Layers { | |||
| } | |||
| 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)); | |||
| } | |||
| 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; | |||
| } | |||
| @@ -0,0 +1,24 @@ | |||
| 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 { | |||
| 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; | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,22 @@ | |||
| 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 { | |||
| public class HardSigmoid : Layer { | |||
| public HardSigmoid ( LayerArgs args ) : base(args) { | |||
| // hard sigmoid has no arguments | |||
| } | |||
| protected override Tensors Call ( Tensors inputs, Tensor state = null, bool? training = null ) { | |||
| Tensor x = inputs; | |||
| return tf.clip_by_value( | |||
| tf.add(tf.multiply(x, 0.2f), 0.5f), 0f, 1f); | |||
| } | |||
| public override Shape ComputeOutputShape ( Shape input_shape ) { | |||
| return input_shape; | |||
| } | |||
| } | |||
| } | |||
| @@ -23,7 +23,9 @@ namespace Tensorflow.Keras.Layers { | |||
| } | |||
| 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)); | |||
| return tf.where(output > 0f, | |||
| tf.multiply(scale, output), | |||
| tf.multiply(scale, tf.multiply(alpha, tf.sub(tf.exp(output), 1f)))); | |||
| } | |||
| public override Shape ComputeOutputShape ( Shape input_shape ) { | |||
| return input_shape; | |||
| @@ -0,0 +1,24 @@ | |||
| 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 { | |||
| public class Softmax : Layer { | |||
| Axis axis; | |||
| public Softmax ( SoftmaxArgs args ) : base(args) { | |||
| axis = args.axis; | |||
| } | |||
| protected override Tensors Call ( Tensors inputs, Tensor state = null, bool? training = null ) { | |||
| Tensor x = inputs; | |||
| Tensor e = tf.exp(tf.sub(x, tf.reduce_max(x, axis: this.axis, keepdims: true))); | |||
| Tensor s = tf.reduce_sum(e, axis: this.axis, keepdims: true); | |||
| return tf.div(e, s); | |||
| } | |||
| public override Shape ComputeOutputShape ( Shape input_shape ) { | |||
| return input_shape; | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,22 @@ | |||
| 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 { | |||
| public class Softplus : Layer { | |||
| public Softplus ( LayerArgs args ) : base(args) { | |||
| // Softplus has no arguments | |||
| } | |||
| protected override Tensors Call ( Tensors inputs, Tensor state = null, bool? training = null ) { | |||
| Tensor x = inputs; | |||
| return tf.log( | |||
| tf.add(tf.exp(x), 1f)); | |||
| } | |||
| public override Shape ComputeOutputShape ( Shape input_shape ) { | |||
| return input_shape; | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,22 @@ | |||
| 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 { | |||
| public class Softsign : Layer { | |||
| public Softsign ( LayerArgs args ) : base(args) { | |||
| // Softsign has no arguments | |||
| } | |||
| protected override Tensors Call ( Tensors inputs, Tensor state = null, bool? training = null ) { | |||
| Tensor x = inputs; | |||
| // x / (abs(x) + 1) | |||
| return tf.div(x, tf.add(1f, tf.abs(x))); | |||
| } | |||
| public override Shape ComputeOutputShape ( Shape input_shape ) { | |||
| return input_shape; | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,23 @@ | |||
| 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 { | |||
| public class Swish : Layer { | |||
| public Swish ( LayerArgs args ) : base(args) { | |||
| // Swish has no arguments | |||
| } | |||
| protected override Tensors Call ( Tensors inputs, Tensor state = null, bool? training = null ) { | |||
| Tensor x = inputs; | |||
| // x / (1 + exp(-x)) | |||
| return tf.div(x, (tf.add(1f, tf.exp(tf.negative(x))))); | |||
| } | |||
| public override Shape ComputeOutputShape ( Shape input_shape ) { | |||
| return input_shape; | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,22 @@ | |||
| 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 { | |||
| public class Tanh : Layer { | |||
| public Tanh ( LayerArgs args ) : base(args) { | |||
| // Tanh has no arguments | |||
| } | |||
| protected override Tensors Call ( Tensors inputs, Tensor state = null, bool? training = null ) { | |||
| Tensor x = inputs; | |||
| return tf.tanh(x); | |||
| } | |||
| public override Shape ComputeOutputShape ( Shape input_shape ) { | |||
| return input_shape; | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,22 @@ | |||
| using Tensorflow.NumPy; | |||
| using System.Collections.Generic; | |||
| using Tensorflow.Keras.ArgsDefinition; | |||
| using Tensorflow.Keras.Engine; | |||
| using static Tensorflow.Binding; | |||
| using static Tensorflow.KerasApi; | |||
| namespace Tensorflow.Keras.Layers { | |||
| public partial class LayersApi { | |||
| public ELU ELU ( float alpha = 0.1f ) | |||
| => new ELU(new ELUArgs { Alpha = alpha }); | |||
| public SELU SELU () | |||
| => new SELU(new LayerArgs { }); | |||
| public Softmax Softmax ( Axis axis ) => new Softmax(new SoftmaxArgs { axis = axis }); | |||
| public Softplus Softplus () => new Softplus(new LayerArgs { }); | |||
| public HardSigmoid HardSigmoid () => new HardSigmoid(new LayerArgs { }); | |||
| public Softsign Softsign () => new Softsign(new LayerArgs { }); | |||
| public Swish Swish () => new Swish(new LayerArgs { }); | |||
| public Tanh Tanh () => new Tanh(new LayerArgs { }); | |||
| public Exponential Exponential () => new Exponential(new LayerArgs { }); | |||
| } | |||
| } | |||
| @@ -1,22 +1,88 @@ | |||
| using Microsoft.VisualStudio.TestTools.UnitTesting; | |||
| using System; | |||
| using System.Collections.Generic; | |||
| using System.Text; | |||
| using static Tensorflow.Binding; | |||
| using Tensorflow.NumPy; | |||
| using static Tensorflow.KerasApi; | |||
| using Tensorflow; | |||
| namespace TensorFlowNET.Keras.UnitTest | |||
| { | |||
| [TestClass] | |||
| public class ActivationTest : EagerModeTestBase | |||
| { | |||
| [TestMethod] | |||
| public void LeakyReLU() | |||
| { | |||
| var layer = keras.layers.LeakyReLU(); | |||
| Tensor output = layer.Apply(np.array(-3.0f, -1.0f, 0.0f, 2.0f)); | |||
| Equal(new[] { -0.9f, -0.3f, 0.0f, 2.0f }, output.ToArray<float>()); | |||
| } | |||
| } | |||
| namespace TensorFlowNET.Keras.UnitTest { | |||
| [TestClass] | |||
| public class ActivationTest : EagerModeTestBase { | |||
| [TestMethod] | |||
| public void LeakyReLU () { | |||
| var layer = keras.layers.LeakyReLU(); | |||
| Tensor output = layer.Apply(np.array(-3.0f, -1.0f, 0.0f, 2.0f)); | |||
| Equal(new[] { -0.9f, -0.3f, 0.0f, 2.0f }, output.ToArray<float>()); | |||
| } | |||
| [TestMethod] | |||
| public void ELU () { | |||
| Tensors input = tf.constant(new float[] { -3f, -2f, -1f, 0f, 1f, 2f }); | |||
| Tensor output = keras.layers.ELU().Apply(input); | |||
| NDArray expected = new NDArray(new float[] { -0.0950213f, -0.08646648f, -0.06321206f, 0f, 1f, 2f }); | |||
| Assert.AreEqual(expected.numpy(), output.numpy()); | |||
| } | |||
| [TestMethod] | |||
| public void SELU () { | |||
| Tensor input = tf.constant(new float[] { -3f, -2f, -1f, 0f, 1f, 2f }); | |||
| Tensor output = keras.layers.SELU().Apply(input); | |||
| NDArray expected = new NDArray(new float[] { -1.6705688f, -1.5201665f, -1.1113307f, 0f, 1.050701f, 2.101402f }); | |||
| Assert.AreEqual(expected.numpy(), output.numpy()); | |||
| } | |||
| [TestMethod] | |||
| public void Softmax () { | |||
| Tensor input = tf.constant(new float[] { -3f, -2f, -1f, 0f, 1f, 2f }); | |||
| Tensor output = keras.layers.Softmax(new Axis(-1)).Apply(input); | |||
| NDArray expected = new NDArray(new float[] { 0.0042697787f, 0.011606461f, 0.031549633f, 0.085760795f, 0.23312202f, 0.6336913f }); | |||
| Assert.AreEqual(expected.numpy(), output.numpy()); | |||
| } | |||
| [TestMethod] | |||
| public void Softplus () { | |||
| Tensor input = tf.constant(new float[] { -3f, -2f, -1f, 0f, 1f, 2f }); | |||
| Tensor output = keras.layers.Softplus().Apply(input); | |||
| NDArray expected = new NDArray(new float[] { 0.04858733f, 0.12692805f, 0.31326166f, 0.6931472f, 1.3132616f, 2.126928f }); | |||
| Assert.AreEqual(expected, output.numpy()); | |||
| } | |||
| [TestMethod] | |||
| public void Softsign () { | |||
| Tensor input = tf.constant(new float[] { -3f, -2f, -1f, 0f, 1f, 2f }); | |||
| Tensor output = keras.layers.Softsign().Apply(input); | |||
| NDArray expected = new NDArray(new float[] { -0.75f, -0.66666667f, -0.5f, 0f, 0.5f, 0.66666667f }); | |||
| Assert.AreEqual(expected, output.numpy()); | |||
| } | |||
| [TestMethod] | |||
| public void Exponential () { | |||
| Tensor input = tf.constant(new float[] { -3f, -2f, -1f, 0f, 1f, 2f }); | |||
| Tensor output = keras.layers.Exponential().Apply(input); | |||
| NDArray expected = new NDArray(new float[] { 0.049787067f, 0.13533528f, 0.36787945f, 1f, 2.7182817f, 7.389056f }); | |||
| Assert.AreEqual(expected, output.numpy()); | |||
| } | |||
| [TestMethod] | |||
| public void HardSigmoid () { | |||
| Tensor input = tf.constant(new float[] { -3f, -2f, -1f, 0f, 1f, 2f }); | |||
| Tensor output = keras.layers.HardSigmoid().Apply(input); | |||
| // Note, this should be [0, 0.1, 0.3, 0.5, 0.7, 0.9] | |||
| // But somehow the second element will have 0.099999994 | |||
| // Probably because there is an accuracy loss somewhere | |||
| NDArray expected = new NDArray(new float[] { 0f, 0.099999994f, 0.3f, 0.5f, 0.7f, 0.9f }); | |||
| Assert.AreEqual(expected, output.numpy()); | |||
| } | |||
| [TestMethod] | |||
| public void Swish () { | |||
| Tensor input = tf.constant(new float[] { -3f, -2f, -1f, 0f, 1f, 2f }); | |||
| Tensor output = keras.layers.Swish().Apply(input); | |||
| NDArray expected = new NDArray(new float[] { -0.14227762f, -0.23840584f, -0.26894143f, 0f, 0.7310586f, 1.761594f }); | |||
| Assert.AreEqual(expected, output.numpy()); | |||
| } | |||
| } | |||
| } | |||