感知器训练的 Delta 训练规则
Delta training rule for perceptron training
我正在尝试使用 delta 训练规则为 AND 布尔函数训练一个感知器。但即使在收敛之后,它也会错误地对输入进行分类(实际上是 1 个输入)。你能告诉我我哪里错了吗:http://ideone.com/CDgTQE
这是使用的训练函数:
public void trianWithDelta(Example[] examples){
for(int i=0;i<1000;++i){
dw1 = 0;
dw2 = 0;
for(Example ex:examples){
double o = computeOutput(ex);
double t = ex.o;
dw1 = dw1 + n*(t-o)*ex.x1;
dw2 = dw2 + n*(t-o)*ex.x2;
}
w1 += dw1;
w2 += dw2;
}
}
训练样例(布尔与):
Example[] examples = new Example[]{
new Example(-1, -1, -1),
new Example(-1 , 1, -1),
new Example( 1, -1, -1),
new Example( 1, 1, 1)
};
结果:
w1:0.49999999999999994 w2:0.5000000000000002
训练后使用训练样例进行测试:
-1
1(不正确)
-1
1
您的代码实际上正确,问题在于您对使用无偏感知器可以学习什么以及不能学习什么的理解。
如果您没有偏见,那么学习 AND 几乎是不可能的,因为:
- 确实有 一个 角度分隔您的数据,这是为第
y=-x
行实现的,在您的代码中它意味着 w1=w2
,甚至它们的值之间的细微差异都会破坏分类器(例如 1e-20
)
- 你的分类器实际上回答了三个值(当你使用符号函数时):-1、0、1,而在这种设置中不可能没有偏差地分离 AND,因为当激活为 0 时你需要回答 -1。
尝试在纸上画出正确的分隔符,您会注意到,在没有偏差的情况下,您的线必须穿过 (0,0),因此,它必须是 y=-x,因此对于 (- 1,1)和(1,-1)激活为0.
这两个问题都可以通过添加偏置节点来解决(这是你应该做的)。
您还可以更改 AND 的 "a bit" 定义 - 例如将 "False" 编码为 -2
Example[] examples = new Example[]{
new Example(-2, -2, -2),
new Example(-2 , 1, -2),
new Example( 1, -2, -2),
new Example( 1, 1, 1)
};
并且运行您的代码的行为符合预期
Trained weights : 0.6363636363636364 0.6363636363636364
-1
-1
-1
1
我正在尝试使用 delta 训练规则为 AND 布尔函数训练一个感知器。但即使在收敛之后,它也会错误地对输入进行分类(实际上是 1 个输入)。你能告诉我我哪里错了吗:http://ideone.com/CDgTQE
这是使用的训练函数:
public void trianWithDelta(Example[] examples){
for(int i=0;i<1000;++i){
dw1 = 0;
dw2 = 0;
for(Example ex:examples){
double o = computeOutput(ex);
double t = ex.o;
dw1 = dw1 + n*(t-o)*ex.x1;
dw2 = dw2 + n*(t-o)*ex.x2;
}
w1 += dw1;
w2 += dw2;
}
}
训练样例(布尔与):
Example[] examples = new Example[]{
new Example(-1, -1, -1),
new Example(-1 , 1, -1),
new Example( 1, -1, -1),
new Example( 1, 1, 1)
};
结果: w1:0.49999999999999994 w2:0.5000000000000002
训练后使用训练样例进行测试:
-1
1(不正确)
-1
1
您的代码实际上正确,问题在于您对使用无偏感知器可以学习什么以及不能学习什么的理解。
如果您没有偏见,那么学习 AND 几乎是不可能的,因为:
- 确实有 一个 角度分隔您的数据,这是为第
y=-x
行实现的,在您的代码中它意味着w1=w2
,甚至它们的值之间的细微差异都会破坏分类器(例如1e-20
) - 你的分类器实际上回答了三个值(当你使用符号函数时):-1、0、1,而在这种设置中不可能没有偏差地分离 AND,因为当激活为 0 时你需要回答 -1。
尝试在纸上画出正确的分隔符,您会注意到,在没有偏差的情况下,您的线必须穿过 (0,0),因此,它必须是 y=-x,因此对于 (- 1,1)和(1,-1)激活为0.
这两个问题都可以通过添加偏置节点来解决(这是你应该做的)。
您还可以更改 AND 的 "a bit" 定义 - 例如将 "False" 编码为 -2
Example[] examples = new Example[]{
new Example(-2, -2, -2),
new Example(-2 , 1, -2),
new Example( 1, -2, -2),
new Example( 1, 1, 1)
};
并且运行您的代码的行为符合预期
Trained weights : 0.6363636363636364 0.6363636363636364
-1
-1
-1
1