title: 感知器算法做模式识别
date: 2017-12-23 21:04:54
tags: 模式识别
categories: c++
感知器算法是线性分类器中的一种。
这种算法的基本思想是:
对于初始的或者迭代中的增广权矢量W,用训练模式检验其合理性。当不合理时,对其进行校正,利用梯度下降法。梯度下降法也是人工神经网络中线性阈值神经元的学习算法。
感知器算法的基本步骤:
- 给定一个增广的训练模式集合{x1, x2, …, xN},其中每个模式类别已知,分别属于?1类和?2类。
- 输入训练模式xk,计算判别函数值WT(k)xk
- 训练样本分量增广化和符号规范化。
- 按照判别规则调整增广权矢量
- 如果在用全部模式训练完一轮后,如果仍有模式被错分,则需要进行第二轮、第三轮迭代,直到所有模式都能够正确分类为止
样例输入文件
in.txt
2 2 2
0 0 0 1
1 0 1 1
样例输出
输入样本维度,第一类样本个数,第二类样本个数:
输入第一类样本:
输入第二类样本:
k = 1 x = 1 d = 1
k = 2 x = 2 d = 2
k = 3 x = 3 d = -2
更新增广权矢量: w = (0,1,0)
k = 4 x = 4 d = -1
更新增广权矢量: w = (-1,0,-1)
k = 5 x = 1 d = -1
更新增广权矢量: w = (-1,0,0)
k = 6 x = 2 d = 0
更新增广权矢量: w = (-1,1,1)
k = 7 x = 3 d = 0
更新增广权矢量: w = (-2,1,0)
k = 8 x = 4 d = 1
k = 9 x = 1 d = 0
更新增广权矢量: w = (-2,1,1)
k = 10 x = 2 d = 2
k = 11 x = 3 d = 1
k = 12 x = 4 d = 0
更新增广权矢量: w = (-3,0,0)
k = 13 x = 1 d = 0
更新增广权矢量: w = (-3,0,1)
k = 14 x = 2 d = 1
k = 15 x = 3 d = 2
k = 16 x = 4 d = 2
k = 17 x = 1 d = 1
k = 18 x = 2 d = 1
k = 19 x = 3 d = 2
k = 20 x = 4 d = 2
最终所求解向量为: -3 0 1
C++程序
#include "iomanip"
#include "iostream"
using namespace std;
/*
感知器算法:
1. 录入样本,每个样本属于类别c1 OR c2
2. 将训练样本增加一个分量1
3. 属于c2的样本*(-1)
4. 给增广权矢量赋值w[1]=(1,1,1),取增量p=1,迭代步数k=1
*/
int c[100][100]; //存储样本
int w[100]; //增广权矢量
int p = 1; //增量
int k = 1; //迭代步数
int D; //样本维度
int n; //第一类样本个数
int m; //第二类样本个数
//计算w'(k)X
int d(int x[]) {
int sum = 0;
for (int i = 0; i <= D; i++) sum += (w[i] * x[i]);
return sum;
}
//更新增广权矢量
void add(int x[]) {
for (int i = 0; i <= D; i++) w[i] += x[i];
}
int main() {
freopen("in.txt", "r", stdin);
int i, j, t;
cout << "输入样本维度,第一类样本个数,第二类样本个数: \n";
cin >> D >> n >> m;
//初始化增广权矢量全为1
for (i = 0; i <= D; i++) w[i] = 1;
cout << "输入第一类样本:\n";
for (i = 0; i < n; i++)
for (j = 0; j < D; j++) cin >> c[i][j];
cout << "输入第二类样本:\n";
for (i = 0; i < m; i++)
for (j = 0; j < D; j++) cin >> c[i + n][j];
int N = n + m;
//训练样本分量增广化
for (i = 0; i < N; i++) c[i][D] = 1;
//训练样本符号规范化
for (i = n; i < N; i++)
for (j = 0; j <= D; j++) c[i][j] = -c[i][j];
//感知器算法训练
while (1) {
bool flag = false; //标记是否有正常分类
for (i = 0; i < N; i++) {
cout << "k = " << setiosflags(ios::left) << setw(6) << k++;
cout << "x = " << setiosflags(ios::left) << setw(6) << i + 1;
t = d(c[i]);
cout << "d = " << t << endl;
if (t <= 0) { //错误分类
//更新增广权矢量
add(c[i]);
cout << "更新增广权矢量: w = (";
// cout << "w = (" << i + 1 << endl;
for (j = 0; j <= D; j++) {
cout << w[j];
if (j < D) cout << ',';
}
cout << ")\n";
flag = true;
}
}
if (!flag) break;
}
//输出解向量
cout << "最终所求解向量为: ";
for (i = 0; i <= D; i++) cout << w[i] << ' ';
cout << endl;
return 0;
}