关于感知器激活阈值的问题

Question about Perceptron activation threshold

我有一个用 Javascript 编写的感知器,运行良好,代码如下。我的问题是关于激活函数中的阈值。我看到的其他代码类似于 if (sum > 0) {return 1} else {return 0}. 我的感知器仅适用于 if (sum > 1) {return 1} else {return 0}. 为什么会这样?完整代码如下。

(function () {
    "use strict";

    function Perceptron(numInputs=2) {
        let weights = Array.from({length: numInputs}, () => 2 * Math.random() - 1);  // [-1, 1)
        this.learningRate = 0.5;

        this.train = function (inputs, goal) {
            // feed forward
            let guess = this.predict(inputs);

            // back propagation
            let error = goal - guess;
            if (error !== 0) {
                for (let i = 0; i < weights.length; i += 1) {
                    weights[i] += this.learningRate * error * inputs[i];
                }
            }
        }

        this.predict = function (inputs) {
            // transfer function
            let sumProducts = 0;
            for (let i = 0; i < inputs.length; i += 1) {
                sumProducts += inputs[i] * weights[i];
            }

            // activation function, threshold = 1
            return (sumProducts >= 1) ? 1 : 0;  // <-- this is the line I have a question about
        }
    }
    
    // train
    let data = [
        [0, 0, 0],
        [0, 1, 0],
        [1, 0, 0],
        [1, 1, 1]
    ];

    let p = new Perceptron(2);
    
    const epochs = 20;
    for (let i = 0; i < epochs; i += 1) {
        let r = Math.floor(Math.random() * data.length);
        p.train(data[r].slice(0, 2), data[r].slice(-1));
    }

    // test
    for (let i = 0; i < data.length; i += 1) {
        let inputs = data[i].slice(0, 2);
        console.log(`inputs = ${inputs}; output = ${p.predict(inputs)}`);
    }
}());

你的感知器缺少偏差项,你的方程式是 SUM_i w_i x_i, 而不是 SUM_i w_i x_i + b 的形式。使用您拥有的功能形式,不可能分离点,其中分离超平面不与原点相交(而您的不相交)。或者,您可以在数据中添加一列“1”,其作用相同,因为相应的 w_i 将表现为 b(因为所有 x_i 都将为 1)

对于关注此问题的其他人,这是最终代码。感谢@lejlot 的帮助!

/*jslint for:true, long:true, devel:true, this:true */
/*jshint esversion: 6*/

(function () {
    "use strict";

    function Perceptron(numInputs = 2) {
        this.weights = Array.from({length: numInputs}, () => 2 * Math.random() - 1);  // [-1, 1)
        this.learningRate = 0.5;
        this.bias = 1;

        this.train = function (inputs, goal) {
            // feed forward
            let guess = this.predict(inputs);

            // back propagation
            let error = goal - guess;
            if (error !== 0) {
                for (let i = 0; i < this.weights.length; i += 1) {
                    this.weights[i] += error * inputs[i] * this.learningRate;
                }
                
                // Bias should be learned, not fixed. The update rules is
                // identical to the weight, just lacks "* inputs[i]" (as
                // described in the answer it is equivalent to having a constant
                // input of 1, and multiplying by 1 does nothing).
                this.bias += error * this.learningRate;
            }
        };

        this.predict = function (inputs) {
            // transfer function
            let sumProducts = 0;
            for (let i = 0; i < inputs.length; i += 1) {
                sumProducts += inputs[i] * this.weights[i];
            }

            // Your perception lacks a bias term, your equation if of form
            // SUM_i w_i x_i, instead of SUM_i w_i x_i + b. With the
            // functional form you have it is impossible to separate points,
            // where the separating hyperplane does not cross the origin
            // (and yours does not). Alternatively you can add a column of
            // "1s" to your data, it will serve the same purpose, as the
            // corresponding w_i will just behave as "b" (since all x_i will
            // be 1)
            sumProducts += this.bias;

            // activation function
            return (sumProducts >= 0) ? 1 : 0;
        };
    }

    // train - boolean AND
    let data = [
        [0, 0, 0],
        [0, 1, 0],
        [1, 0, 0],
        [1, 1, 1]
    ];

    let p = new Perceptron(2);

    const epochs = 100;

    for (let i = 0; i < epochs; i += 1) {
        let r = Math.floor(Math.random() * data.length);
        p.train(data[r].slice(0, 2), data[r].slice(-1));
    }

    // test
    for (let i = 0; i < data.length; i += 1) {
        let inputs = data[i].slice(0, 2);
        console.log(`inputs = ${inputs}; output = ${p.predict(inputs)}`);
    }
}());