关于感知器激活阈值的问题
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)}`);
}
}());
我有一个用 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)}`);
}
}());