感知机介绍及实现

2023-11-18

感知机(perceptron)由Rosenblatt于1957年提出,是神经网络与支持向量机的基础。

感知机是最早被设计并被实现的人工神经网络。感知机是一种非常特殊的神经网络,它在人工神经网络的发展史上有着非常重要的地位,尽管它的能力非常有限,主要用于线性分类。

感知机还包括多层感知机,简单的线性感知机用于线性分类器,多层感知机(含有隐层的网络)可用于非线性分类器。本文中介绍的均是简单的线性感知机。



图 1

感知机工作方式

         (1)、学习阶段:修改权值和偏置,根据”已知的样本”对权值和偏置不断修改----有监督学习。当给定某个样本的输入/输出模式对时,感知机输出单元会产生一个实际输出向量,用期望输出(样本输出)与实际输出之差来修正网络连接权值和偏置。

         (2)、工作阶段:计算单元变化,由响应函数给出新输入下的输出。

         感知机学习策略

感知机学习的目标就是求得一个能够将训练数据集中正负实例完全分开的分类超平面,为了找到分类超平面,即确定感知机模型中的参数w和b,需要定义一个基于误分类的损失函数,并通过将损失函数最小化来求w和b。

         (1)、数据集线性可分性:在二维平面中,可以用一条直线将+1类和-1类完美分开,那么这个样本空间就是线性可分的。因此,感知机都基于一个前提,即问题空间线性可分;

         (2)、定义损失函数,找到参数w和b,使得损失函数最小。

         损失函数的选取

         (1)、损失函数的一个自然选择就是误分类点的总数,但是这样的点不是参数w,b的连续可导函数,不易优化;

         (2)、损失函数的另一个选择就是误分类点到划分超平面S(w*x+b=0)的总距离。



以上理论部分主要来自: http://staff.ustc.edu.cn/~qiliuql/files/DM2013/2013SVM.pdf

以下代码根据上面的描述实现:

perceptron.hpp:

#ifndef _PERCEPTRON_HPP_
#define _PERCEPTRON_HPP_

#include <vector>

namespace ANN {

typedef std::vector<float> feature;
typedef int label;

class Perceptron {
private:
	std::vector<feature> feature_set;
	std::vector<label> label_set;
	int iterates;
	float learn_rate;
	std::vector<float> weight;
	int size_weight;
	float bias;

	void initWeight();
	float calDotProduct(const feature feature_, const std::vector<float> weight_);
	void updateWeight(const feature feature_, int label_);

public:
	Perceptron(int iterates_, float learn_rate_, int size_weight_, float bias_);
	void getDataset(const std::vector<feature> feature_set_, const std::vector<label> label_set_);
	bool train();
	label predict(const feature feature_);
};

}


#endif // _PERCEPTRON_HPP_
perceptron.cpp:

#include "perceptron.hpp"
#include <assert.h>
#include <time.h>
#include <iostream>

namespace ANN {

void Perceptron::updateWeight(const feature feature_, int label_)
{
	for (int i = 0; i < size_weight; i++) {
		weight[i] += learn_rate * feature_[i] * label_; // formula 5
	}

	bias += learn_rate * label_; // formula 5
}

float Perceptron::calDotProduct(const feature feature_, const std::vector<float> weight_)
{
	assert(feature_.size() == weight_.size());
	float ret = 0.;

	for (int i = 0; i < feature_.size(); i++) {
		ret += feature_[i] * weight_[i];
	}

	return ret;
}

void Perceptron::initWeight()
{
	srand(time(0));
	float range = 100.0;
	for (int i = 0; i < size_weight; i++) {
		float tmp = range * rand() / (RAND_MAX + 1.0);
		weight.push_back(tmp);
	}
}

Perceptron::Perceptron(int iterates_, float learn_rate_, int size_weight_, float bias_)
{
	iterates = iterates_;
	learn_rate = learn_rate_;
	size_weight = size_weight_;
	bias = bias_;
	weight.resize(0);
	feature_set.resize(0);
	label_set.resize(0);
}

void Perceptron::getDataset(const std::vector<feature> feature_set_, const std::vector<label> label_set_)
{
	assert(feature_set_.size() == label_set_.size());

	feature_set.resize(0);
	label_set.resize(0);

	for (int i = 0; i < feature_set_.size(); i++) {
		feature_set.push_back(feature_set_[i]);
		label_set.push_back(label_set_[i]);
	}
}

bool Perceptron::train()
{
	initWeight();

	for (int i = 0; i < iterates; i++) {
		bool flag = true;

		for (int j = 0; j < feature_set.size(); j++) {
			float tmp = calDotProduct(feature_set[j], weight) + bias;
			if (tmp * label_set[j] <= 0) {
				updateWeight(feature_set[j], label_set[j]);
				flag = false;
			}
		}

		if (flag) {
			std::cout << "iterate: " << i << std::endl;
			std::cout << "weight: ";
			for (int m = 0; m < size_weight; m++) {
				std::cout << weight[m] << "    ";
			}
			std::cout << std::endl;
			std::cout << "bias: " << bias << std::endl;

			return true;
		}
	}

	return false;
}

label Perceptron::predict(const feature feature_)
{
	assert(feature_.size() == size_weight);

	return calDotProduct(feature_, weight) + bias >= 0 ? 1 : -1; //formula 2
}

}

test_NN.cpp:

#include <iostream>
#include "perceptron.hpp"

int test_perceptron();

int main()
{
	test_perceptron();
	std::cout << "ok!" << std::endl;
}

int test_perceptron()
{
	// prepare data
	const int len_data = 20;
	const int feature_dimension = 2;
	float data[len_data][feature_dimension] = { { 10.3, 10.7 }, { 20.1, 100.8 }, { 44.9, 8.0 }, { -2.2, 15.3 }, { -33.3, 77.7 },
	{ -10.4, 111.1 }, { 99.3, -2.2 }, { 222.2, -5.5 }, { 10.1, 10.1 }, { 66.6, 30.2 },
	{ 0.1, 0.2 }, { 1.2, 0.03 }, { 0.5, 4.6 }, { -22.3, -11.1 }, { -88.9, -12.3 },
	{ -333.3, -444.4 }, { -111.2, 0.5 }, { -6.6, 2.9 }, { 3.3, -100.2 }, { 5.6, -88.8 } };
	int label_[len_data] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
		-1, -1, -1, -1, -1, -1, -1, -1, -1, -1 };

	std::vector<ANN::feature> set_feature;
	std::vector<ANN::label> set_label;

	for (int i = 0; i < len_data; i++) {
		ANN::feature feature_single;
		for (int j = 0; j < feature_dimension; j++) {
			feature_single.push_back(data[i][j]);
		}

		set_feature.push_back(feature_single);
		set_label.push_back(label_[i]);

		feature_single.resize(0);
	}

	// train
	int iterates = 1000;
	float learn_rate = 0.5;
	int size_weight = feature_dimension;
	float bias = 2.5;
	ANN::Perceptron perceptron(iterates, learn_rate, size_weight, bias);
	perceptron.getDataset(set_feature, set_label);
	bool flag = perceptron.train();
	if (flag) {
		std::cout << "data set is linearly separable" << std::endl;
	}
	else {
		std::cout << "data set is linearly inseparable" << std::endl;
		return -1;
	}

	// predict
	ANN::feature feature1;
	feature1.push_back(636.6);
	feature1.push_back(881.8);
	std::cout << "the correct result label is 1, " << "the real result label is: " << perceptron.predict(feature1) << std::endl;

	ANN::feature feature2;
	feature2.push_back(-26.32);
	feature2.push_back(-255.95);
	std::cout << "the correct result label is -1, " << "the real result label is: " << perceptron.predict(feature2) << std::endl;

	return 0;
}

运行结果如下图:


GitHub:https://github.com/fengbingchun/NN

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

感知机介绍及实现 的相关文章

  • 宽表, 窄表, 维度表, 事实表的区别

    在数据开发里 会涉及到一些概念 宽表 窄表 维度表 事实表 宽表 把多个维度的字段都放在一张表存储 增加数据冗余是为了减少关联 便于查询 查询一张表就可以查出不同维度的多个字段 窄表 和我们 mysql 普通表三范式相同 把相同维度的字段组
  • 信奥:1001Hello,World! 1002输出第二个整数 1003对齐输出

    include
  • Qt WebAssembly实验记录

    文章目录 1 安装及介绍 2 问题及解决方案 2 1 在C 中调用js函数 2 2 中文无法显示 乱码 2 3 无法输入中文 2 4 qt对应的emsdk版本 2 5 文件的下载以及上传 2 6 设置调试时的网页浏览器 2 7 编译时报空间
  • 睿象云入围

    睿象云入围 腾讯云原生加速器首期成员名单 6月30日 开源向善 应云而生 腾讯云原生加速器公布了首期入选企业名单 睿象云等 38 家优秀云原生企业从全球500多家参与企业中脱颖而出 携手腾讯共建云原生生态 面向云原生未来加速启航 产业数字化
  • 基于 ZooKeeper 搭建 Kafka 高可用集群

    kafka简介与应用场景 Apache Kafka是分布式发布 订阅消息系统 在 kafka官网上对 kafka 的定义 一个分布式发布 订阅消息传递系统 它最初由LinkedIn公司开发 Linkedin于2010年贡献给了Apache基
  • UE4学习笔记--连接MySQL数据库(C++)

    UE4学习笔记 连接MySQL数据库 我个人是个比较水的人 在学校没好好学程序 不误正业的玩建模 现在美术和程序都不行 想想还是重新认真学程序吧 先从记笔记开始 话说我还是第一次写博客 我是跟着几位大佬的博客做的 记录一下自己的问题 以免以
  • CompletableFuture异步

    更多文章 关注 码视野 CompletableFuture是Java 8提供的一种异步编程方式 它以函数式编程API的形式提供了丰富的异步操作接口 相比于传统的Future异步方式 CompletableFuture更为灵活和易用 可以轻松
  • linux创建文件夹主机名,Linux创建、删除文件和文件夹命令

    今天学习了几个命令 是创建 删除文件和文件夹的 在linux里 文件夹是目录 下面说下我学习的命令 接下来是小编为大家收集的Linux创建 删除文件和文件夹命令 欢迎大家阅读 Linux创建 删除文件和文件夹命令 创建文件夹 mkdir 一

随机推荐

  • Zotero使用笔记—文献管理、做笔记、文献引用、数据备份

    先贴一张zotero的大头照 步入正题 依次介绍zotero的几大功能 一 中英文 文献管理 先看了视频1和视频2这两个基本使用教程 浏览器又搜了一点 学到了 zotero用一个条目存储一篇文献的基本信息和PDF zotero中添加一个条目
  • 注册表:无法打开 XXX 由于某个错误无法打开该密钥。详细信息:拒绝访问

    错误原因 没有注册表用户权限 正确添加用户权限的步骤如下 跟着图片步骤 右击该项 权限 选中想要添加为当前所有者的用户后 点击应用 如果没用户显示 可以从 其他用户或组 中添加进来 权限添加完毕 转载于 https www cnblogs
  • 什么吃掉了我的硬盘?

    什么吃掉了我的硬盘 http www am82 com houzan archives 4550 posted on 2010 08 15 20 29 lexus 阅读 评论 编辑 收藏 转载于 https www cnblogs com
  • L2TP和PPTP的区别

    用最短的时间搞清楚L2TP和PPTP的区别 一 相关知识铺垫 1 虚拟隧道协议 一种通过公共网络的基础设施 在专用网络或专用设备之间实现加密数据通信的技术 通信的内容是可以是任何通信协议的数据包 隧道协议将这些协议的数据包重新封装在新的包中
  • 离散系统的变换域分析【数字信号处理四】

    离散系统的变换域分析 一 求系统H z 的零 极点 幅频响应和相位响应 二 用Matlab验证DFT运算的对称性质 三 产生数字线性调频信号 分析时域波形和频谱特性 四 设计简单的OFDM系统 并验证循环前缀的作用 一 求系统H z 的零
  • (黑客)自学笔记

    一 自学网络安全学习的误区和陷阱 1 不要试图先成为一名程序员 以编程为基础的学习 再开始学习 行为 从编程开始掌握 前端后端 通信协议 什么都学 缺点 花费时间太长 实际向安全过渡后可用到的关键知识并不多 很多安全函数知识甚至名词都不了解
  • Xception论文解读

  • make/makefile的使用

    make makefile 文章目录 make makefile 初步认识makefile的工作流程 依赖关系和依赖方法 make的使用 总结 make是一个命令 是一个解释makefile中指令的命令工具 makefile是一个文件 当前
  • oracle数据库中输入date类型的数据

    给oracle数据库已有记录中更新date类型的数据 插入date类型的格式 to date 2016 01 03 12 23 19 yyyy mm dd hh24 mi ss 2016 01 03 12 23 19 表示想要插入的时间 y
  • 华为鸿蒙os今日新闻,华为正式发布鸿蒙OS,却再次被质疑

    6月2日 市场瞩目的鸿蒙产品发布会成功举办 此次华为还连发三款搭载鸿蒙系统的硬件 华为 MatePad Pro 平板 华为 Watch 3 智能手表和华为 FreeBuds 4 TWS 耳机 但事情总有两面性 喜欢你的不论你做什么都会被看好
  • 小白入坑-利用express构建一个简单的Node项目

    做了部分前端的东西 当然不能局限眼前的成果 梦想能成为全栈的大佬 然后左手一个小姐姐 右手一个富萝莉 走远了 奈于java对前端来说比较难 耗费的学习时间也比较长 所以先从node下手过一下瘾儿 首先 win r打开windows的运行框
  • 什么是堡垒机

    什么是堡垒机 1 堡垒机是用来解决 运维混乱 的 堡垒机是用来干什么的 简而言之一句话 堡垒机是用于解决 运维混乱 的 何谓运维混乱 当公司的运维人员越来越多 当需要运维的设备越来越多 当参与运维的岗位越来越多样性 如果没有一套好的机制 就
  • Git入门超详细文档

    Git Git概述 Git是一个免费的 开源的分布式版本控制系统 可以款速高效的处理从小型到大型的各种项目 Git易于学习 占地面积小 性能极佳 它具有廉价的本地库 方便的暂存区域和多个工作流分支等特性 其性能优于Subversion CV
  • 试除法判定质数模板题

    试除法判定一个数是否为质数类似于这道题 代码 include
  • mac文件夹权限的@

    demo是网站根目录 终端下执行 cd到demo ls l 显示 drwxr xr x 9 andy admin 306 10 12 17 43 demo 这里的 貌似是mac特有的 第一次使用file put contents往根目录添加
  • QMutex使用时遇到的错误

    class A public explicit A QObject parent 0 A public QMutex m mutex class B public explicit B QObject parent 0 B private
  • C语言笔记 第三章 键盘输入与输出

    文章目录 1 printf 1 1 整型 1 2 字符型 1 3 浮点型 1 4 其他 1 4 1 标志 1 4 2 输出最小宽度 1 4 3 精度 1 4 4 类型长度 1 5 转义字符 2 scanf 2 1scanf 函数的一般形式
  • 网络安全----应急响应入侵排查

    系列文章目录 Web网络安全 红蓝攻防之信息收集 Web网络安全 Log4j高危漏洞原理及修复 Shell分类详解 图形界面 命令行式 Linux安全 应急溯源常用命令 记一次实战成功溯源反制getshell 文章目录 系列文章目录 一 应
  • ADS1256驱动程序

    1 初始化 接口 SPI2 STM32 ADS1256 NSS PB12 CS SCK PB13 SCLK MISO PB14 DOUT MOSI PB15 DIN PB10 DRDY PB11 RESET
  • 感知机介绍及实现

    感知机 perceptron 由Rosenblatt于1957年提出 是神经网络与支持向量机的基础 感知机是最早被设计并被实现的人工神经网络 感知机是一种非常特殊的神经网络 它在人工神经网络的发展史上有着非常重要的地位 尽管它的能力非常有限