Skip to content

Commit 6a09905

Browse files
authored
Merge pull request #387 from apphp/ML-385-convert-cost-functions-to-NumPower
Ml 385 convert cost functions to num power
2 parents 2f101f5 + b520be6 commit 6a09905

File tree

22 files changed

+1600
-18
lines changed

22 files changed

+1600
-18
lines changed

docs/neural-network/cost-functions/cross-entropy.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ This cost function does not have any parameters.
1212

1313
## Example
1414
```php
15-
use Rubix\ML\NeuralNet\CostFunctions\CrossEntropy;
15+
use Rubix\ML\NeuralNet\CostFunctions\CrossEntropy\CrossEntropy;
1616

1717
$costFunction = new CrossEntropy();
18-
```
18+
```

docs/neural-network/cost-functions/huber-loss.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@ The pseudo Huber Loss function transitions between L1 and L2 loss at a given piv
55

66
$$
77
L_{\delta}=
8-
\left\{\begin{matrix}
9-
\frac{1}{2}(y - \hat{y})^{2} & if \left | (y - \hat{y}) \right | < \delta\\
10-
\delta ((y - \hat{y}) - \frac1 2 \delta) & otherwise
11-
\end{matrix}\right.
8+
\begin{cases}
9+
\frac{1}{2}(y - \hat{y})^{2} & \text{if } |y - \hat{y}| < \delta\\
10+
\delta ((y - \hat{y}) - \frac{1}{2} \delta) & \text{otherwise}
11+
\end{cases}
1212
$$
1313

1414
## Parameters
@@ -21,4 +21,4 @@ $$
2121
use Rubix\ML\NeuralNet\CostFunctions\HuberLoss;
2222

2323
$costFunction = new HuberLoss(0.5);
24-
```
24+
```

docs/neural-network/cost-functions/least-squares.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ This cost function does not have any parameters.
1212

1313
## Example
1414
```php
15-
use Rubix\ML\NeuralNet\CostFunctions\LeastSquares;
15+
use Rubix\ML\NeuralNet\CostFunctions\LeastSquares\LeastSquares;
1616

1717
$costFunction = new LeastSquares();
18-
```
18+
```
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<span style="float:right;"><a href="https://github.com/RubixML/ML/blob/master/src/NeuralNet/CostFunctions/MeanAbsoluteError/MeanAbsoluteError.php">[source]</a></span>
2+
3+
# Mean Absolute Error
4+
Mean Absolute Error (MAE) measures the average magnitude of errors between predicted and actual values without considering their direction. It is a linear score which means all individual differences are weighted equally. MAE is more robust to outliers compared to Mean Squared Error (MSE) because it doesn't square the differences.
5+
6+
$$
7+
MAE = \frac{1}{n}\sum_{i=1}^{n}|y_i - \hat{y}_i|
8+
$$
9+
10+
## Parameters
11+
This cost function does not have any parameters.
12+
13+
## Example
14+
```php
15+
use Rubix\ML\NeuralNet\CostFunctions\MeanAbsoluteError\MeanAbsoluteError;
16+
17+
$costFunction = new MeanAbsoluteError();
18+
```

docs/neural-network/cost-functions/relative-entropy.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ This cost function does not have any parameters.
1212

1313
## Example
1414
```php
15-
use Rubix\ML\NeuralNet\CostFunctions\RelativeEntropy;
15+
use Rubix\ML\NeuralNet\CostFunctions\RelativeEntropy\RelativeEntropy;
1616

1717
$costFunction = new RelativeEntropy();
18-
```
18+
```

src/NeuralNet/ActivationFunctions/GELU/GELU.php

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,10 @@ class GELU implements ActivationFunction, IBufferDerivative
3333
* @var float
3434
*/
3535
protected const ALPHA = 0.7978845608;
36-
/** @var float 0.5 * ALPHA */
36+
37+
/**
38+
* @var float 0.5 * ALPHA
39+
*/
3740
protected const HALF_ALPHA = 0.3989422804;
3841

3942
/**
@@ -42,7 +45,10 @@ class GELU implements ActivationFunction, IBufferDerivative
4245
* @var float
4346
*/
4447
protected const BETA = 0.044715;
45-
/** @var float 3 * BETA */
48+
49+
/**
50+
* @var float 3 * BETA
51+
*/
4652
protected const TRIPLE_BETA = 0.134145;
4753

4854
/**
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Rubix\ML\NeuralNet\CostFunctions\Base\Contracts;
6+
7+
interface ClassificationLoss extends CostFunction
8+
{
9+
//
10+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Rubix\ML\NeuralNet\CostFunctions\Base\Contracts;
6+
7+
use NDArray;
8+
use Stringable;
9+
10+
/**
11+
* Cost Function
12+
*
13+
* @category Machine Learning
14+
* @package Rubix/ML
15+
* @author Samuel Akopyan <[email protected]>
16+
*/
17+
interface CostFunction extends Stringable
18+
{
19+
/**
20+
* Compute the loss score.
21+
*
22+
* @param NDArray $output
23+
* @param NDArray $target
24+
* @return float
25+
*/
26+
public function compute(NDArray $output, NDArray $target) : float;
27+
28+
/**
29+
* Calculate the gradient of the cost function with respect to the output.
30+
*
31+
* @param NDArray $output
32+
* @param NDArray $target
33+
* @return NDArray
34+
*/
35+
public function differentiate(NDArray $output, NDArray $target) : NDArray;
36+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Rubix\ML\NeuralNet\CostFunctions\Base\Contracts;
6+
7+
interface RegressionLoss extends CostFunction
8+
{
9+
//
10+
}
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Rubix\ML\NeuralNet\CostFunctions\CrossEntropy;
6+
7+
use NDArray;
8+
use NumPower;
9+
use Rubix\ML\NeuralNet\CostFunctions\Base\Contracts\ClassificationLoss;
10+
use Rubix\ML\Traits\AssertsShapes;
11+
use const Rubix\ML\EPSILON;
12+
13+
/**
14+
* Cross Entropy
15+
*
16+
* Cross Entropy, or log loss, measures the performance of a classification model
17+
* whose output is a probability value between 0 and 1. Cross-entropy loss
18+
* increases as the predicted probability diverges from the actual label. So
19+
* predicting a probability of .012 when the actual observation label is 1 would
20+
* be bad and result in a high loss value. A perfect score would have a log loss
21+
* of 0.
22+
*
23+
* @category Machine Learning
24+
* @package Rubix/ML
25+
* @author Andrew DalPino
26+
* @author Samuel Akopyan <[email protected]>
27+
*/
28+
class CrossEntropy implements ClassificationLoss
29+
{
30+
use AssertsShapes;
31+
32+
/**
33+
* Compute the loss score.
34+
*
35+
* L(y, ŷ) = -Σ(y * log(ŷ)) / n
36+
*
37+
* @param NDArray $output The output of the network
38+
* @param NDArray $target The target values
39+
* @return float
40+
*/
41+
public function compute(NDArray $output, NDArray $target) : float
42+
{
43+
$this->assertSameShape($output, $target);
44+
45+
// Clip values to avoid log(0)
46+
$output = NumPower::clip($output, EPSILON, 1.0);
47+
48+
$logOutput = NumPower::log($output);
49+
$product = NumPower::multiply($target, $logOutput);
50+
$negated = NumPower::multiply($product, -1.0);
51+
52+
return NumPower::mean($negated);
53+
}
54+
55+
/**
56+
* Calculate the gradient of the cost function with respect to the output.
57+
*
58+
* ∂L/∂ŷ = (ŷ - y) / (ŷ * (1 - ŷ))
59+
*
60+
* @param NDArray $output The output of the network
61+
* @param NDArray $target The target values
62+
* @return NDArray
63+
*/
64+
public function differentiate(NDArray $output, NDArray $target) : NDArray
65+
{
66+
$this->assertSameShape($output, $target);
67+
68+
// Numerator = ŷ - y (calculate before clipping to preserve zeros)
69+
$numerator = NumPower::subtract($output, $target);
70+
71+
// Clip values to avoid division by zero
72+
$output = NumPower::clip($output, EPSILON, 1.0 - EPSILON);
73+
74+
// Denominator = ŷ * (1 - ŷ)
75+
$oneMinusOutput = NumPower::subtract(1.0, $output);
76+
$denominator = NumPower::multiply($output, $oneMinusOutput);
77+
$denominator = NumPower::clip($denominator, EPSILON, 1.0);
78+
79+
return NumPower::divide($numerator, $denominator);
80+
}
81+
82+
/**
83+
* Return the string representation of the object.
84+
*
85+
* @return string
86+
*/
87+
public function __toString() : string
88+
{
89+
return 'Cross Entropy';
90+
}
91+
}

0 commit comments

Comments
 (0)