深度学习开篇-感知机(perceptron)原理和实现

近几年科技领域很流行大数据、机器学习、深度学习之类的字眼,其实,这些东西原理很早的时候就有了,只不过当时不叫这些名词,等我们慢慢学习就会发现,这些玩意儿结合了高数、概率统计学、矩阵论、线性代数等,然后以代码实现来解决实际问题。深度学习可以认为被包含在机器学习之中。至于目前他们的应用和研究领域,包括图像识别、NLP(自然语言处理)等等,大家自行查阅。废话不多说,现在我从一个最简单的模型向大家展示这类玩意儿怎么玩起来

1.感知机

为了了解什么是感知机,我们需要先理解一下几点:

第一点:感知机是二类分类的线性分类模型(为了新手理解,还是多说两句,什么叫做二类分类,从程序的角度,感知机的输入是某个事物,而它的输出只有两种状态,从现实的角度,我们把具体的人这个事物输入给感知机要她判别性别,最后感知机只能输出两种结果:“男人”或“女人”,不会有第三种~~,如果我们需要有第三种结果,则这个问题不能用感知机来解决(有其他办法)。至于什么叫做线性,接下来会讲到)

第二点:把某个事物输入到感知机模型的理解。(太抽象了吧,映射到程序是怎样的啊)这种输入其实有很多种形式,我举个最简单的例子帮助读者理解。对于某个特定的人,比如我,身高2.0米,体重150,帅气程度100分(满分100) 可爱程度0(满分100),数据提取出来 (2.0 150 100 0) 其中的每一个标识都称之为一个特征点,然后我们就定义一个向量 a = (2.0,150,100,0)来表示“我”这个人,所以输入就是向量a(特征向量)。(ps:这只是最基础的一种形式,不局限于此)

第三点:“学习”的简单理解。机器学习、深度学习中都有学习二字,此二字代表什么意思?直观理解,就是我们从已知信息中学习其中的规律规则,从而预测未知。还是以上述例子阐述。现在我们碰到这样的一个问题:我有1000条人的信息,现在我在路上看到一个背影,目测身高165,体重90、帅气程度30,可爱程度80,想知道他(她)是男是女。这种情况就可以考虑采用感知机处理类似问题。(埋下铺垫,实际中的应用场景很有限)。我们提取1000个人信息中的五个特征点(身高、体重、帅气程度、可爱程度,性别)转化成1000个特征向量,1000个标记向量(只有性别,男用+1表示,女用-1表示,对应于特征向量)作为感知机的输入进行训练,让其学习其中的关联,得到一个训练后的模型,当输入向量(1.65,90,30,80)后,感知机就可以根据训练好的模型预测出最后的结果(+1 或 -1)

第四点:我们从数学的角度深入推敲这个问题的实际转化(其实也就是一个数学建模的过程)

可以理解如下

人               特征向量                        标记                                                      序号

我           (2.0,150,100,0)              +1(男)           已知                                1

夏目     (1.78,135,80,20)         +1 ( 男)           已知                                2

鲁路修  (1.80,140,99,1)          +1(男)          已知                                3

魔女cc  (1.63,88,10,99)           -1 (女)         已知                                4

....                                                        ...                      ...                                   ...

路人      (1.65,90,20,90)             ?(要求解的量)   

那么,建模开始


第五点:"学习"的数学表达式直观理解(以下以感知机为例,其实很多类型神经网络都类似)

通过上述建模,现在我们的问题变成了如何调整系数W(w0,w1,w2.... )和b,(注意,此处的系数W是向量),使得模型f(X) = sign(W*X+b)具有更好的表达能力。此处好的表达能力指的什么?还是举上述列子,对于已知的1000个特征向量,输入模型f计算后得到的结果尽可能和对应标签一致(其实也就是一个拟合过程),然后我们再输入表示刚才路人的特征向量,经过f计算的结果就是对于此路人的性别预测结果。

那么,现在问题变成了如何调整系数W和b,使得f(X)学习到的表达能力最好。这里扯起来又可以写几篇文章,我们以后一步步展开,目前我只做陈述,有兴趣的同学可以查看我的csdn博客(代价函数 )。目前咱们暂且要记住,如何调整系数W和b,使得f(X)学习到的表达能力最好问题,可以转换为调整模型参数W,b,使得代价函数最小。代价函数有许多定义形式,此处我们依照李航《统计学习方法》P26 P27(大家有兴趣的可以看看,其中有cost代价函数的推导过程。此处我直接给出

其中M表示误分类点的集合 ,xi表示第i个样本(第i个已知信息的特征向量),yi对应+1/-1

第六点:“学习算法”

怎样使得代价函数最小(其实变成了一个纯高数问题),对于L(W,b),xi和yi已知,W和b是变量,L是一个多元方程,求W和b,使得L为最小值,采用梯度下降算法(ps:高数中有一个梯度的概念,大家需要回顾,可以参考机器学习-梯度下降法实现线性回归

最后的步骤如下:


上述训练集中xi可以是多维的,即训练集T = {(x11,x12,x13,x14,...,x1n,y1),(x21,x22,x23,x24,...,x2n,y2,...,(xN1,xN2,xN3,xN4,...,xNn,yN))


读者要特别注意的几点:上述文字只是帮助初学者更容易上手理解,没有涉及推导过程,《统计学习方法》李航著  第一二章一定要看看,学会手工推算,损失函数、梯度下降都要分别查阅文献和推导

读到这估计很多人已经迷糊了,但最大的问题在于,为什么建模的时候使用多元线性方程,难道多元自变量和结果之间的关系一定是线性的吗?(如果读到这都没想过这个问题,那~~)当然不一定,怎么可能,而且绝大部分不是线性可分的,所以,大家要记住,单个感知机的表达能力很弱。此处可以联想一下,如果在二维坐标中有很多离散的红蓝点,我们有多少概率可以用一条线就将其划分开,在三维坐标中又有多少概率可以用平面将其划分开,依次类推到n维。既然单个感知机的能力这么挫,我为什么要开篇讲它? 因为单个感知机可以看成组成神经网络的神经元的一部分,以后详解。

2.代码实例

扯了半天不写代码和咸鱼又有什么区别

代码下载(整个项目打包了,安装vs2013 ,直接双击.sln即可调试查看)

感知机简单实现c++

如果我们用上述代码学习训练无法线性可分的数据集,就会导致W,b无法收敛,陷入死循环,若一定要用感知机训练,就只能手工设置循环次数,但这种方式最后会导致训练效果不好,预测的正确率就会大幅降低。以后会更新更好的神经网络模型来解决这个问题

以统计学习方法P29页题目为例


#include<iostream>

#include<vector>

#include<string>

#include<fstream>

using namespace std;

typedef vectorfeatureVct;

typedef int label;

class Perceptron;

void printRes(Perceptron pp);

class Perceptron

{private:

vectorFtSet; //特征向量数据集vectorlabelSet; //二分类label数据集 +1或-1

double LearnRate; //学习率

featureVct w; //感知机模型参数

double bias; //偏置项

int dimension; //特征向量维度

int count;

public:

Perceptron(int dimension,featureVct w,double bias = 0.0,double learnRate = 1);

int GetCount() const;  //获取迭代次数

const featureVct& GetW() const ;     //获取模型参数

void SetW(const featureVct& w);   //设置模型参数

double GetBias() const; //获取偏置项

void SetBias(double bias); //设置骗置项

bool ReadSource(const string& filePath); //读取数据源

void Train(); //训练模型,得到感知机模型

public:

double VectorDotProduct(const featureVct& f1, const featureVct& f2);  //向量点积运算)

featureVct VectorScalarMulti(double num, const featureVct f); //向量数乘运算

featureVct VectorAdd(const featureVct& f1, const featureVct& f2);  //向量加法运算

};

const featureVct& Perceptron::GetW() const

{

return w;

}

void Perceptron::SetW(const featureVct& w)

{

this->w = w;

}

double Perceptron::GetBias() const

{

return bias;

}

void Perceptron::SetBias(double bias)

{

this->bias = bias;

}

/*文件格式:每行表示一个样本点,特征值之间用空格隔开,最后一列存储类别信息1或-1*/

bool Perceptron::ReadSource(const string& filePath)

{

ifstream file(filePath);

if (!file)

return false;

while (!file.eof())

{

featureVct dataTmp;

double tmp;

for (int i = 0; i < dimension; ++i)

{

file >> tmp;

dataTmp.push_back(tmp);

}

FtSet.push_back(dataTmp);

label labelData;

file >> labelData;

labelSet.push_back(labelData);

}

return true;

}

void Perceptron::Train()

{

//感知机训练过程

int flag = true;

while (flag)

{

for (int i = 0; i < FtSet.size(); i++)

{

flag = false;

if (labelSet[i] * (VectorDotProduct(w,FtSet[i]) + bias) <= 0)

{

//此处的打印只是为了更直观的给大家展示学习过程,工程中最后不要直接在类中打印信息

printRes(*this);

flag = true;

w = VectorAdd(w, VectorScalarMulti(labelSet[i]*LearnRate,FtSet[i]));

bias += LearnRate * labelSet[i];

++count;

break;

}

}

//此处的打印只是为了更直观的给大家展示学习过程,工程中最后不要直接在类中打印信息

if(!flag)  printRes(*this);

}

}

Perceptron::Perceptron(int dimension, featureVct w, double bias, double learnRate)

{

this->dimension = dimension;

this->bias = bias;

this->LearnRate = learnRate;

this->w = w;

count = 0;

}

double Perceptron::VectorDotProduct(const featureVct& f1, const featureVct& f2)

{

double sum = 0.0;

for (int i = 0; i != f1.size(); ++i)

{

sum += f1[i] * f2[i];

}

return sum;

}

featureVct Perceptron::VectorScalarMulti(double num, const featureVct f)

{

featureVct tmp;

for (int i = 0; i != f.size(); ++i)

{

tmp.push_back(num*f[i]);

}

return tmp;

}

featureVct Perceptron::VectorAdd(const featureVct& f1, const featureVct& f2)

{

featureVct tmp(0);

for (int i = 0; i != f1.size(); ++i)

{

tmp.push_back(f1[i] + f2[i]);

}

return tmp;

}

int Perceptron::GetCount() const

{

return count;

}

void printRes(Perceptron pp)

{

cout << "迭代次数:" << pp.GetCount() << endl;

cout << "w:";

featureVct tmp = pp.GetW();

for (int i = 0; i < tmp.size() - 1; ++i)

{

cout << tmp[i] << " ";

}

cout << tmp[tmp.size() - 1] << endl;

cout << "bias:";

cout << pp.GetBias() << endl;

cout << "---------------------------" << endl;

}

int main()

{

featureVct w;

w.push_back(0.0); //设置w初始化参数

w.push_back(0.0);

Perceptron pp(2, w);  //创建特征向量为2维的感知机对象

if (!pp.ReadSource("sun.txt"))

{

cout << "读取文件失败";

exit(-1);

}

pp.Train();  //训练得到感知机模型

}

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,378评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,356评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,702评论 0 342
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,259评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,263评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,036评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,349评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,979评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,469评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,938评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,059评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,703评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,257评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,262评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,485评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,501评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,792评论 2 345