前几天认把感知机这一章读完了,顺带做了点笔记

现在把笔记做第三次的整理

(不得不说博客园的LaTex公式和markdown排版真的不太舒服,该考虑在服务器上建一个博客了)

零、总结

  1. 适用于具有线性可分的数据集的二分类问题,可以说是很局限了
  2. 感知机本质上是一个分离超平面
  3. 在向量维数(特征数)过高时,选择对偶形式算法

    在向量个数(样本数)过多时,应选择原始算法
  4. 批量梯度下降和随机梯度下降的区别和优势

    参考链接:随机梯度下降(Stochastic gradient descent)和 批量梯度下降(Batch gradient descent )的公式对比、实现对比
  • 批量梯度下降(BGD, Batch Gradient Descent)

    $ \theta \leftarrow \theta + \eta \sum \frac{\partial L}{\partial \theta}$

    即多次做全局样本的参数更新

    缺点:计算耗时

    优点:可以趋向全局最优,受数据噪音影响少
  • 随机梯度下降(SGD, Srochastic Gradient Descent)

    $ \theta \leftarrow \theta + \eta \frac{\partial L}{\partial \theta}$

    即多次做单个样本的参数更新

    缺点:训练耗时较短

    优点:不一定趋向全局最优(往往是最优/较优,单峰问题除外),受数据噪音影响大

一、模型

输入空间 $ \mathcal{X} \subseteq R^n $

输出空间 $ \mathcal{Y} \subseteq {-1, +1} $

假设空间 $ \mathcal{F} \subseteq {f|f(x) = \omega \cdot x + b} $

参数 $ \omega \in R^n, b \in R $

模型 $ f(x) = sign(\omega \cdot x + b) $

其中

符号函数为

\[ sign(x)=\left\{\begin{matrix}
+1 , x \geqslant 0\\
-1 , x \geqslant 0
\end{matrix}\right. \]

线性方程

$ \omega \cdot x + b $

可以表示为特征空间 $ R^n $中的一个分离超平面

二、策略

(定义的损失函数,并极小化损失函数)

(注意损失函数非负的性质)

为了使损失函数更容易优化,我们选择误分类点到超平面的距离作为损失函数

任意向量\(x \in R^n\)距分离超平面的距离为

$ S=\frac{1}{|\omega|}|\omega \cdot x + b| $

接下来优化一下这个距离,让它更好的成为一个损失函数

  1. 为了连续可导,去绝对值

    $ S=-\frac{1}{|\omega|} y_i(\omega \cdot x + b) $
  2. 去掉不相关的系数(避免浪费计算),得到

    $ L(\omega, b)=-\sum_{x_i \in M} y_i(\omega \cdot x + b) \(
    其中\) M $为误分类点集合

三、算法

(如何实现最优化问题)

注意最终训练出的模型参数的值取决于初值和误分类点的选取,所以一般值不同

为了极小化损失函数,我们采用梯度下降的方法

  1. 原始形式算法
  • 赋初值 $ \omega \leftarrow 0 , b \leftarrow 0 $
  • 选取数据点 $ (x_i, y_i) $
  • 判断该数据点是否为当前模型的误分类点,即判断若$ y_i(\omega \cdot x + b) <=0 $

    则更新

\[ \begin{matrix}
\omega &\leftarrow \omega + \eta n_ix_iy_i \\
b &\leftarrow b + \eta n_iy_i
\end{matrix}\]

  1. 对偶形式算法

    注意到原始形式算法中,最终训练好的模型参数是这样的,其中$ n_i $表示在第i个数据点上更新过几次

\[\begin{matrix}
\omega &= \eta \sum_i n_ix_iy_i \\
b &= \eta \sum_i n_iy_i
\end{matrix}
\]

于是我们可以作出以下简化

  • 赋初值 $ n \leftarrow 0, b \leftarrow 0 $
  • 选取数据点 $ (x_i, y_i) $
  • 判断该数据点是否为当前模型的误分类点,即判断若$ y_i(\eta \sum n_iy_ix_i \cdot x + b) <=0 $

    则更新

\[ \begin{matrix}
n_i &\leftarrow n_i + 1 \\
b &\leftarrow b + \eta y_i
\end{matrix}\]

为了减少计算量,我们可以预先计算式中的内积,得到Gram矩阵

$ G=[x_i, x_j]_{N \times N} \(
3. **原始形式和对偶形式的选择**
相见知乎[如何理解感知机学习算法的对偶形式?](https://www.zhihu.com/question/26526858)
在向量维数(特征数)过高时,计算内积非常耗时,应选择对偶形式算法加速
在向量个数(样本数)过多时,每次计算累计和(对偶形式中的\)\omega$)就没有必要,应选择原始算法

四、代码实现

因为感知机对数据要求很严格,为了实现这个模型,我用到了iris的数据集,用来给鸢尾花分类

又因为感知机只能做二分类,所以还是要把原数据的两个类别合并

为了学习numpy,还是用了python实现

import numpy as np
from matplotlib import pyplot as plt class Perceptron:
# use the primitive algorithm
arguments={
"item_class":{
"Iris-setosa": -1,
"Iris-versicolor": 1,
"Iris-virginica": 1,
},
"epoch": 800,
"colors": ['blue', 'red'],
"draw_start_x": 4,
"draw_end_x": 7.5,
"epsilon": 0.0,
"learning_rate": 0.25,
} def __init__(self, vec_dim, learning_rate=None, epsilon=None):
# self.data=np.empty(dim)
# self.counter=np.zeros(dim)
self.data=None
self.vec_dim=vec_dim
self.lr=learning_rate
if epsilon:
self.epsilon=epsilon
else:
self.epsilon=self.arguments["epsilon"]
if learning_rate:
self.lr=learning_rate
else:
self.lr=self.arguments["learning_rate"] self.weight=np.zeros((self.vec_dim-1, 1))
self.bias=0 def read_data(self, filepath):
raw_data=[]
with open(filepath, "r") as file:
for line in file.readlines():
if line=='\n':
break
item=line.replace('\n', '').split(',')
itemc=self.arguments["item_class"][item[-1]]
vec=[float(x) for x in item[0:2]]+[itemc] raw_data.append(vec)
self.data=np.array(raw_data).T def process(self):
# it is dual form
vec=self.data[:, 0:2]
self.gram=np.dot(vec, vec.T) def train(self):
self.bias=0
self.weight=np.zeros((self.vec_dim-1, 1))
# self.counter=np.zeros(dim)
for epoch in range(1, self.arguments["epoch"]+1):
error_counter=0
for idx in range(self.data.shape[1]):
vec=self.data[:, idx]
x, y=vec[0:-1, np.newaxis], vec[-1]
if y*(np.dot(self.weight.T, x)+self.bias)<=self.epsilon:
self.weight+=self.lr*y*x
self.bias+=self.lr*y
error_counter+=1
print("epoch #%03d: error:%03d total:%03d"%(
epoch, error_counter, self.data.shape[1]))
print("weight:", self.weight.ravel())
print("bias:", self.bias, "\n") if error_counter==0:
print("train done!")
break def show(self):
for idx in range(self.data.shape[1]):
color=self.arguments["colors"][0]
if self.data[2, idx]<0:
color=self.arguments["colors"][1]
plt.scatter(self.data[0, idx], self.data[1, idx], color=color)
y=[-(self.weight[0, 0]*self.arguments["draw_start_x"] + self.bias)/self.weight[1, 0],
-(self.weight[0, 0]*self.arguments["draw_end_x"] + self.bias)/self.weight[1, 0]]
plt.plot([self.arguments["draw_start_x"], self.arguments["draw_end_x"]], y)
plt.show()

更新了代码实现部分

[笔记-统计学习方法]感知机模型(perceptron) 原理与实现的更多相关文章

  1. 统计学习方法 --- 感知机模型原理及c++实现

    参考博客 Liam Q博客 和李航的<统计学习方法> 感知机学习旨在求出将训练数据集进行线性划分的分类超平面,为此,导入了基于误分类的损失函数,然后利用梯度下降法对损失函数进行极小化,从而 ...

  2. 统计学习方法 | 感知机 | python实现

    感知机是二类分类的线性分类模型,利用随机梯度下降法对基于误分类的损失函数进行极小化. 书中算法可以将所有样本和系数向量写成增广向量的形式,并将所有负样本乘以-1,统一形式,方便计算. (1)训练数据集 ...

  3. 《统计学习方法》极简笔记P2:感知机数学推导

    感知机模型 输入空间是$\chi\subseteq\mathbb{R}^n$,输出空间是$y={+1,-1}$ 感知机定义为:$f(x)=sign(wx+b)$ 感知机学习策略 输入空间任一点$x_0 ...

  4. 机器学习笔记(一)&#183; 感知机算法 &#183; 原理篇

    这篇学习笔记强调几何直觉,同时也注重感知机算法内部的动机.限于篇幅,这里仅仅讨论了感知机的一般情形.损失函数的引入.工作原理.关于感知机的对偶形式和核感知机,会专门写另外一篇文章.关于感知机的实现代码 ...

  5. 统计学习方法6—logistic回归和最大熵模型

    目录 logistic回归和最大熵模型 1. logistic回归模型 1.1 logistic分布 1.2 二项logistic回归模型 1.3 模型参数估计 2. 最大熵模型 2.1 最大熵原理 ...

  6. 统计学习方法与Python实现(一)——感知机

    统计学习方法与Python实现(一)——感知机 iwehdio的博客园:https://www.cnblogs.com/iwehdio/ 1.定义 假设输入的实例的特征空间为x属于Rn的n维特征向量, ...

  7. 《统计学习方法》极简笔记P4:朴素贝叶斯公式推导

    <统计学习方法>极简笔记P4:朴素贝叶斯公式推导 朴素贝叶斯基本方法 通过训练数据集 T={(x_1,y_1),(x_2,y_2),(x_N,y_N)...,(x_1,y_1)} 学习联合 ...

  8. HanLP《自然语言处理入门》笔记--5.感知机模型与序列标注

    笔记转载于GitHub项目:https://github.com/NLP-LOVE/Introduction-NLP 5. 感知机分类与序列标注 第4章我们利用隐马尔可夫模型实现了第一个基于序列标注的 ...

  9. 感知机(perceptron)原理总结

    目录 1. 感知机原理 2. 损失函数 3. 优化方法 4. 感知机的原始算法 5. 感知机的对偶算法 6. 从图形中理解感知机的原始算法 7. 感知机算法(PLA)的收敛性 8. 应用场景与缺陷 9 ...

随机推荐

  1. [雅礼NOIP2018集训 day3]

    考试的时候刚了T1两个小时线段树写了三个子任务结果发现看错了题目,于是接下来一个半小时我自闭了 result=历史新低 这告诉我们,打暴力要端正态度,尤其是在发现自己之前出锅的情况下要保持心态的平和, ...

  2. [LeetCode] 2. Add Two Numbers 两个数字相加 java语言实现 C++语言实现

    [LeetCode] Add Two Numbers 两个数字相加   You are given two non-empty linked lists representing two non-ne ...

  3. CCS+C6678LE开发记录11:多核协作(IPC)入门

    为更好地发挥C6678的多核性能,需要用到多核协作.幸运的是,我们可以使用官方提供的IPC模块. IPC=Inter-Processor Communication, 核间通信,粗略来说就是多核之间进 ...

  4. 获取xml字符串中的属性值

    pagexml = @"<?xml version='1.0' encoding='utf-8'?> <DATAPACKET Version='2.0'> <M ...

  5. iReport5.6.0使用说明

    1,需要安装jdk1.7,因为目前还不支持最新的jdk1.8 2,安装好软件之后,打开安装目录下的etc/ireport.conf文件,配置关联自己的jdk1.7的路径,如下: #jdkhome=&q ...

  6. XShell与虚拟机连接的IP问题

    这几天在Xshell连接虚拟机这个问题上头疼了好长时间,原因是我在虚拟机内的eth0网卡没有分配IP地址,从而导致无法连接XShell,今天解决了这个问题,做一下记录. 首先我使用的是微软的Hyper ...

  7. lua中调用C++函数

    lua中调用C++函数 我们产品中提供了很多lua-C API给用户在lua中调用,之前一直没用深究其实现原理,只是根据已有的代码在编码.显然这不是一个好的习惯,没用达到知其所以然的目的. 一.基本原 ...

  8. java中的json使用

    import org.json.simple.JSONArray;import org.json.simple.JSONObject; /** * 使用的是json-lib-2.4.jar * @au ...

  9. vue-cli3+typescript+路由懒加载报错问题

    vue-cli3的版本是3.4.1 出现的情况是网页显示正常,但是终端一直提示找不到模块: 如果去掉路由懒加载的方式,就没有报错: 原因是以前我们习惯直接写文件名而不加后缀, 现在使用ts时就需要写v ...

  10. Docker本地私有仓库实战

    Docker仓库主要用于存放Docker镜像,Docker仓库分为公共仓库和私有仓库,基于registry可以搭建本地私有仓库,使用私有仓库的优点如下: 1)节省网络带宽,针对于每个镜像不用去Dock ...