methods/cost.js

function validate(targets, outputs) {
  if (targets == undefined || outputs == undefined) throw new ReferenceError('Missing at least one required parameters: `targets`, `outputs`');

  targets = Array.isArray(targets) ? targets : [targets];
  outputs = Array.isArray(outputs) ? outputs : [outputs];

  if (targets.length !== outputs.length) throw new RangeError(`Required "targets.length === outputs.length"; Received "targets.length=${targets.length}" & "outputs.length=${outputs.length}`);

  return [targets, outputs];
}

/**
 * Cost functions play an important role in neural networks. They give neural networks an indication of 'how wrong' they are; a.k.a. how far they are from the desired outputs. Also in fitness functions, cost functions play an important role.
 *
 * @namespace cost
 *
 * @see [Loss Function on Wikipedia](https://en.wikipedia.org/wiki/Loss_function)
 */
const cost = {

  /**
  * Cross entropy error
  *
  * @see {@link http://bit.ly/2p5W29A|Cross-entropy Error Function}
  * @param {number[]|number} targets Ideal value
  * @param {number[]|number} outputs Actual values
  *
  * @return {number} [Cross entropy error](https://ml-cheatsheet.readthedocs.io/en/latest/loss_functions.html)
  *
  * @example
  * let { methods, Network } = require("@liquid-carrot/carrot");
  *
  * let myNetwork = new Network(5, 10, 5);
  * myNetwork.train(trainingData, { cost: methods.cost.CROSS_ENTROPY });
  */
  CROSS_ENTROPY: function(targets, outputs) {
    [targets, outputs] = validate(targets, outputs);

    const error = outputs.reduce(function(total, value, index) {
      return total -= targets[index] * Math.log(Math.max(outputs[index], 1e-15)) + (1 - targets[index]) * Math.log(1 - Math.max(outputs[index], 1e-15));
    }, 0);

    return error / outputs.length;
  },

  /**
  * Mean Squared Error
  *
  * @param {number[]|number} targets Ideal value
  * @param {number[]|number} outputs Actual values
  *
  * @return {number} [Mean squared error](https://medium.freecodecamp.org/machine-learning-mean-squared-error-regression-line-c7dde9a26b93)
  *
  * @example
  * let { methods, Network } = require("@liquid-carrot/carrot");
  *
  * let myNetwork = new Network(5, 10, 5);
  * myNetwork.train(trainingData, { cost: methods.cost.MSE });
  */
  MSE: function(targets, outputs) {
    [targets, outputs] = validate(targets, outputs);

    const error = outputs.reduce(function(total, value, index) {
      return total += Math.pow(targets[index] - outputs[index], 2);
    }, 0);

    return error / outputs.length;
  },

  /**
  * Binary Error
  *
  * @param {number[]|number} targets Ideal value
  * @param {number[]|number} outputs Actual values
  *
  * @return {number} misses The amount of times targets value was missed
  *
  * @see [Hinge loss on Wikipedia](https://en.wikipedia.org/wiki/Hinge_loss)
  *
  * @example
  * let { methods, Network } = require("@liquid-carrot/carrot");
  *
  * let myNetwork = new Network(5, 10, 5);
  * myNetwork.train(trainingData, {
  *   log: 1,
  *   iterations: 500,
  *   error: 0.03,
  *   rate: 0.05,
  *   cost: methods.cost.BINARY
  * });
  */
  BINARY: function(targets, outputs) {
    [targets, outputs] = validate(targets, outputs);

    const error = outputs.reduce(function(total, value, index) {
      return total += Math.round(targets[index] * 2) !== Math.round(outputs[index] * 2);
    }, 0);

    return error;
  },

  /**
  * Mean Absolute Error
  *
  * @param {number[]|number} targets Ideal value
  * @param {number[]|number} outputs Actual values
  *
  * @return {number} [Mean absoulte error](https://en.wikipedia.org/wiki/Mean_absolute_error)
  *
  * @example
  * let { methods, Network } = require("@liquid-carrot/carrot");
  *
  * let myNetwork = new Network(5, 10, 5);
  * myNetwork.train(trainingData, {
  *   log: 1,
  *   iterations: 500,
  *   error: 0.03,
  *   rate: 0.05,
  *   cost: methods.cost.MAE
  * });
  */
  MAE: function(targets, outputs) {
    [targets, outputs] = validate(targets, outputs);

    const error = outputs.reduce(function(total, value, index) {
      return total += Math.abs(targets[index] - outputs[index]);
    }, 0);

    return error / outputs.length;
  },

  /**
  * Mean Absolute Percentage Error
  *
  * @param {number[]|number} targets Ideal value
  * @param {number[]|number} outputs Actual values
  *
  * @return {number} [Mean absolute percentage error](https://en.wikipedia.org/wiki/Mean_absolute_percentage_error)
  *
  * @example
  * let { methods, Network } = require("@liquid-carrot/carrot");
  *
  * let myNetwork = new Network(5, 10, 5);
  * myNetwork.train(trainingData, {
  *   log: 1,
  *   iterations: 500,
  *   error: 0.03,
  *   rate: 0.05,
  *   cost: methods.cost.MAPE
  * });
  */
  MAPE: function(targets, outputs) {
    [targets, outputs] = validate(targets, outputs);

    const error = outputs.reduce(function(total, value, index) {
      return total += Math.abs((outputs[index] - targets[index]) / Math.max(targets[index], 1e-15));
    }, 0);

    return error / outputs.length;
  },

  /**
  * Weighted Absolute Percentage Error (WAPE)
  *
  * @param {number[]|number} targets Ideal value
  * @param {number[]|number} outputs Actual values
  *
  * @return {number} - [Weighted absolute percentage error](https://help.sap.com/doc/saphelp_nw70/7.0.31/en-US/76/487053bbe77c1ee10000000a174cb4/content.htm?no_cache=true)
  *
  * @example
  * let { methods, Network } = require("@liquid-carrot/carrot");
  *
  * let myNetwork = new Network(5, 10, 5);
  * myNetwork.train(trainingData, {
  *   cost: methods.cost.WAPE
  * });
  */
  WAPE: function(targets, outputs) {
    [targets, outputs] = validate(targets, outputs);

    let error = 0;
    let sum = 0;

    for (let index = 0; index < outputs.length; index++) {
      error += Math.abs(targets[index] - outputs[index]);
      sum += targets[index];
    }

    return error / sum;
  },

  /**
  * Mean Squared Logarithmic Error
  *
  * @param {number[]|number} targets Ideal value
  * @param {number[]|number} outputs Actual values
  *
  * @return {number} - [Mean squared logarithmic error](https://peltarion.com/knowledge-center/documentation/modeling-view/build-an-ai-model/loss-functions/mean-squared-logarithmic-error)
  *
  * @example
  * let { methods, Network } = require("@liquid-carrot/carrot");
  *
  * let myNetwork = new Network(5, 10, 5);
  * myNetwork.train(trainingData, {
  *   log: 1,
  *   iterations: 500,
  *   error: 0.03,
  *   rate: 0.05,
  *   cost: methods.cost.MSLE
  * });
  */
  MSLE: function(targets, outputs) {
    [targets, outputs] = validate(targets, outputs);

    const error = outputs.reduce(function(total, value, index) {
      return total += Math.log(Math.max(targets[index], 1e-15)) - Math.log(Math.max(outputs[index], 1e-15));
    }, 0);

    return error;
  },

  /**
  * Hinge loss, for classifiers
  *
  * @param {number[]|number} targets Ideal value
  * @param {number[]|number} outputs Actual values
  *
  * @return {number} - [Hinge loss](https://towardsdatascience.com/support-vector-machines-intuitive-understanding-part-1-3fb049df4ba1)
  *
  * @example
  * let { methods, Network } = require("@liquid-carrot/carrot");
  *
  * let myNetwork = new Network(5, 10, 5);
  * myNetwork.train(trainingData, {
  *   log: 1,
  *   iterations: 500,
  *   error: 0.03,
  *   rate: 0.05,
  *   cost: methods.cost.HINGE
  * });
  */
  HINGE: function(targets, outputs) {
    [targets, outputs] = validate(targets, outputs);

    const error = outputs.reduce(function(total, value, index) {
      return total += Math.max(0, 1 - targets[index] * outputs[index]);
    }, 0);

    return error;
  },
};

module.exports = cost;