单层感知机作为线性分类器






4.74/5 (56投票s)
在本文中,我将向您展示如何使用单层感知器作为2个类别的线性分类器。

引言
感知器是最简单的 feed forward 神经网络类型。它由 Frank Rosenblatt 设计,作为两个线性可分类的二分分类器。这意味着网络可以解决的问题类型必须是线性可分的。基本感知器由 3 层组成
- 传感器层
- 关联层
- 输出神经元
在传感器层中有许多输入 (xn)、权重 (wn) 和一个输出。 有时 w0 被称为偏差,x0 = +1/-1(在本例中 x0=-1)。

对于感知器上的每个输入(包括偏差),都有一个相应的权重。 为了计算感知器的输出,每个输入乘以其对应的权重。 然后计算所有输入的加权和,并通过一个限制器函数评估感知器的最终输出。
神经元的输出由输出神经元的激活形成,这是输入的函数
(1) | ![]() |
激活函数 F 可以是线性的,这样我们就有一个线性网络,或者是非线性的。 在此示例中,我决定使用阈值(符号)函数
(2) | ![]() |
在这种情况下,网络的输出是 +1 或 -1,具体取决于输入。 如果总输入(所有输入的加权和)为正,则该模式属于 +1 类,否则属于 -1 类。 由于这种行为,我们可以使用感知器进行分类任务。
让我们考虑我们有一个带有 2 个输入的感知器,我们想将输入模式分成 2 个类。 在这种情况下,类之间的分隔是直线,由等式给出
(3) | ![]() |
当我们设置 x0=-1 并标记 w0=? 时,我们可以将等式 (3) 重写为形式
(4) | ![]() |
在这里,我将描述感知器的学习方法。 感知器的学习方法是一个调整权重的迭代过程。 将一个学习样本呈现给网络。 对于每个权重,通过将校正添加到旧值来计算新值。 阈值以相同的方式更新
(5) | ![]()
|
其中y是感知器的输出,d是期望的输出,?是学习参数。
使用程序
当您运行该程序时,您会看到一个可以输入样本的区域。 在此区域上单击鼠标左键,您将添加第一个类别的样本(蓝色十字)。 在此区域上单击鼠标右键,您将添加第一个类别的样本(红色十字)。 样本被添加到samples
列表中。 您还可以设置学习率和迭代次数。 当您设置所有这些值后,您可以单击“学习”按钮开始学习。
Using the Code
所有样本都存储在通用列表samples
中,该列表仅保存Sample
类对象。
public class Sample
{
double x1;
double x2;
double cls;
public Sample(double x1, double x2, int cls)
{
this.x1 = x1;
this.x2 = x2;
this.cls = cls;
}
public double X1
{
get { return x1; }
set { this.x1 = value; }
}
public double X2
{
get { return x2; }
set { this.x2 = value; }
}
public double Class
{
get { return cls; }
set { this.cls = value; }
}
}
在运行感知器学习之前,重要的是设置学习率和迭代次数。 感知器有一个很棒的属性。 如果存在解决方案,感知器总是能找到它,但当解决方案不存在时就会出现问题。 在这种情况下,感知器将尝试在无限循环中找到解决方案,为了避免这种情况,最好设置最大迭代次数。
下一步是为权重(w0、w1 和 w2)分配随机值。
Random rnd = new Random();
w0 = rnd.NextDouble();
w1 = rnd.NextDouble();
w2 = rnd.NextDouble();
当随机值被分配给权重时,我们可以循环遍历样本并计算每个样本的输出,并将其与期望的输出进行比较。
double x1 = samples[i].X1;
double x2 = samples[i].X2;
int y;
if (((w1 * x1) + (w2 * x2) - w0) < 0)
{
y = -1;
}
else
{
y = 1;
}
我决定设置x0=-1
,因此,感知器的输出由等式给出:y=w1*w1+w2*w2-w0. 当感知器输出和期望输出不匹配时,我们必须计算新的权重
if (y != samples[i].Class)
{
error = true;
w0 = w0 + alpha * (samples[i].Class - y) * x0 / 2;
w1 = w1 + alpha * (samples[i].Class - y) * x1 / 2;
w2 = w2 + alpha * (samples[i].Class - y) * x2 / 2;
}
Y 是感知器的输出,samples[i].Class
是期望的输出。 最后 2 个步骤(循环遍历样本和计算新权重),我们必须重复,直到error
变量为<> 0
并且当前迭代次数(iterations
)小于maxIterations
。
int i;
int iterations = 0;
bool error = true;
maxIterations = int.Parse(txtIterations.Text);
Random rnd = new Random();
w0 = rnd.NextDouble();
w1 = rnd.NextDouble();
w2 = rnd.NextDouble();
alpha = (double)trackLearningRate.Value / 1000;
while (error && iterations < maxIterations)
{
error = false;
for (i = 0; i <= samples.Count - 1; i++)
{
double x1 = samples[i].X1;
double x2 = samples[i].X2;
int y;
if (((w1 * x1) + (w2 * x2) - w0) < 0)
{
y = -1;
}
else
{
y = 1;
}
if (y != samples[i].Class)
{
error = true;
w0 = w0 + alpha * (samples[i].Class - y) * x0 / 2;
w1 = w1 + alpha * (samples[i].Class - y) * x1 / 2;
w2 = w2 + alpha * (samples[i].Class - y) * x2 / 2;
}
}
objGraphics.Clear(Color.White);
DrawSeparationLine();
iterations++;
}
函数DrawSeparationLine
绘制 2 个类的分离线。
历史
- 2010 年 11 月 07 日 - 发布原始版本