Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 59 additions & 0 deletions src/main/java/com/thealgorithms/maths/SigmoidActivation.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package com.thealgorithms.maths;

/**
* Implementation of the Sigmoid Activation function.
* Sigmoid function is used as an activation function in machine learning and neural networks
* for modeling binary classification problems, smoothing outputs, and introducing non-linearity
* into models.
*
* @author <a href="https://github.com/crapxxi">Alikhan Turugeldiyev</a>
*/

public class SigmoidActivation {

Check failure on line 12 in src/main/java/com/thealgorithms/maths/SigmoidActivation.java

View workflow job for this annotation

GitHub Actions / build

(design) HideUtilityClassConstructor: Utility classes should not have a public or default constructor.
/**
* @summary Maps any real-valued number into a value between 0 and 1
* @param x In machine learning, x could be a weighted sum of inputs in a neural network neuron or a raw score in logistic regression.
* @return The output (range) of the sigmoid function is always strictly between 0 and 1.
*/
public static double activate(double x) {
// If the number x is NaN then, returning NaN to saving from unexpected output.
if(Double.isNaN(x)) return Double.NaN;

Check failure on line 20 in src/main/java/com/thealgorithms/maths/SigmoidActivation.java

View workflow job for this annotation

GitHub Actions / build

(whitespace) WhitespaceAround: 'if' is not followed by whitespace.

Check failure on line 20 in src/main/java/com/thealgorithms/maths/SigmoidActivation.java

View workflow job for this annotation

GitHub Actions / build

(whitespace) WhitespaceAfter: 'if' is not followed by whitespace.

Check failure on line 20 in src/main/java/com/thealgorithms/maths/SigmoidActivation.java

View workflow job for this annotation

GitHub Actions / build

(blocks) NeedBraces: 'if' construct must use '{}'s.
// Saving from unnecessary and heavy calculations.
// lim x->-inf sigmoid(x) will return number very close to 0
if(x < -745) return 0.0;

Check failure on line 23 in src/main/java/com/thealgorithms/maths/SigmoidActivation.java

View workflow job for this annotation

GitHub Actions / build

(whitespace) WhitespaceAround: 'if' is not followed by whitespace.

Check failure on line 23 in src/main/java/com/thealgorithms/maths/SigmoidActivation.java

View workflow job for this annotation

GitHub Actions / build

(whitespace) WhitespaceAfter: 'if' is not followed by whitespace.

Check failure on line 23 in src/main/java/com/thealgorithms/maths/SigmoidActivation.java

View workflow job for this annotation

GitHub Actions / build

(blocks) NeedBraces: 'if' construct must use '{}'s.
// lim x->inf sigmoid(x) will return number very close to 1
if(x > 745) return 1.0;

Check failure on line 25 in src/main/java/com/thealgorithms/maths/SigmoidActivation.java

View workflow job for this annotation

GitHub Actions / build

(whitespace) WhitespaceAround: 'if' is not followed by whitespace.

Check failure on line 25 in src/main/java/com/thealgorithms/maths/SigmoidActivation.java

View workflow job for this annotation

GitHub Actions / build

(whitespace) WhitespaceAfter: 'if' is not followed by whitespace.

Check failure on line 25 in src/main/java/com/thealgorithms/maths/SigmoidActivation.java

View workflow job for this annotation

GitHub Actions / build

(blocks) NeedBraces: 'if' construct must use '{}'s.
// sigmoid function's formula
return 1.0 / ( 1 + Math.exp((-1) * x));
}

public static double[][] activate(double[][] x) {
// apply calculation to every value in batch.
double[][] activatedNumbers = new double[x.length][x[0].length];
for(int i = 0; i < x.length; i++) {
for (int j = 0; j < x[0].length; j++) activatedNumbers[i][j] = activate(x[i][j]);
}
return activatedNumbers;
}

/**
* @summary Calculates gradients for mapped values. By the chain rule, you can calculate error.
* @param y Activated by sigmoid function value.
* @return The output is a gradient of the activated value.
*/
public static double grad(double y) {
// sigmoid function derivative is reducing to this value.
// sigmoid'(x) = sigmoid(x) * (1-sigmoid(x))
return y * (1 - y);
}

public static double[][] grad(double[][] y) {
// apply calculation to every value in batch.
double[][] grads = new double[y.length][y[0].length];
for(int i = 0; i < y.length; i++) {
for (int j = 0; j < y[0].length; j++) grads[i][j] = grad(y[i][j]);
}
return grads;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package com.thealgorithms.maths;

import org.junit.jupiter.api.Test;

import java.util.Arrays;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;

public class SigmoidActivationTest {

@Test
public void calculationTest() {
assertEquals(0.5,SigmoidActivation.activate(0), 0.01,"1 case correct" );
assertEquals(0.73,SigmoidActivation.activate(1),0.01,"2 case correct");
assertEquals(0.26,SigmoidActivation.activate(-1),0.01, "3 case correct");
assertEquals(0.88,SigmoidActivation.activate(2),0.01,"4 case correct");
assertEquals(0.11,SigmoidActivation.activate(-2),0.01,"5 case correct");

double[][] xBatch = new double[4][3];
double[][] expectedX = new double[4][3];

for(int i = 0; i < 4; i++) {
for(int j = 0; j < 3; j++) xBatch[i][j] = 0;
}

for(int i = 0; i < 4; i++) {
for(int j = 0; j < 3; j++) expectedX[i][j] = 0.5;
}

assertTrue(Arrays.deepEquals(expectedX, SigmoidActivation.activate(xBatch)), "batch case correct");

assertEquals(0.25, SigmoidActivation.grad(0.5), 0.01, "grad calculation correct");

double[][] yBatch = new double[4][3];
for(int i = 0; i < 4; i++) {
for(int j = 0; j < 3; j++) yBatch[i][j] = 0.5;
}

double[][] expectedY = new double[4][3];
for(int i = 0; i < 4; i++) {
for(int j = 0; j < 3; j++) expectedY[i][j] = 0.25;
}
assertTrue(Arrays.deepEquals(expectedY, SigmoidActivation.grad(yBatch)), "grad batch case correct");
}

@Test
public void willReturnNaN() {
double x = Double.NaN;

assertTrue(Double.isNaN(SigmoidActivation.activate(x)), "returned NaN");
}

@Test
public void extremumNumbersOnActivate() {
double x = 777;

assertEquals(1.0, SigmoidActivation.activate(x), 0.01, "big number case correct");
assertEquals(0.0, SigmoidActivation.activate((-1) * x), 0.01, "small number case correct");
}
}
Loading