[浙大机器学习课程] 感知器算法-python可视化

背景

继续学习浙大机器学习的课程。终于完成了第一部分支持向量机的学习。现在正式进入第二部分人工神经网络了。

这部分一上来就学到了一个超级有意思的**感知器 (Perceptron)**算法。然后课程里有一个用matlab做的可视化的例子。我并没有找到这个例子的源代码,而且我也不用matlab,所以就想着自己用python写一个。

一开始还在纠结要不要花这个时间。感觉可能挺麻烦的,对学习课程也没啥帮助。不过实际做起来发现还挺简单的。

问题

依然是解决一个基本的二分类问题:有一组样本 { X i , Y i } , Y i = ± 1 \{X_i,Y_i\},Y_i = \pm1 {Xi,Yi}Yi=±1,找到一个 ω \omega ω b b b,使得对于每一个样本,都有 Y i ⋅ ( ω X + b ) > 0 Y_i \cdot (\omega X + b) > 0 Yi(ωX+b)>0

注意这个问题和支持向量机解决的问题不完全相同。支持向量机是要找到最优的超平面,而感知器算法只要找到一个这样的平面就可以了。

算法

Rosenblatt 提出了感知器算法。网上搜了一下这个大佬居然是个心理学家!?

算法过程

我想做这个算法的可视化也是因为觉得这个算法太简单太优雅了。

先定义一些东西以便描述更方便。

定义增广向量 X i ⃗ \vec{X_i} Xi
[ X i 1 ] , y i = 1 [ − X i − 1 ] , y i = − 1 \begin{bmatrix} X_i \\ 1 \end{bmatrix} , y_i = 1 \\ \\ \begin{bmatrix} -X_i \\ -1 \end{bmatrix} , y_i = -1 [Xi1],yi=1[Xi1],yi=1

然后问题就可以这样描述:

寻找向量 ω = [ ω , b ] \omega = \begin{bmatrix} \omega, b \end{bmatrix} ω=[ω,b],使得 ω T X i ⃗ > 0 \omega^T \vec{X_i} > 0 ωTXi >0

寻找的过程极其简单:
请添加图片描述
先随机取一个 ω \omega ω,然后把存在的每一个点(对应的增广向量)代入。如果 ω T X i ⃗ ≤ 0 \omega^T \vec{X_i} \le 0 ωTXi 0,那就修改 ω \omega ω,让 ω \omega ω 加上 X i ⃗ \vec{X_i} Xi 。直到所有的点都满足 ω T X i ⃗ > 0 \omega^T \vec{X_i} > 0 ωTXi >0为止。

可以证明只要样本是线性可分的,那感知器算法最后一定会收敛。这里我就先略去证明了。

python 可视化

概述

程序也挺简单的。先讲一下思路:

  1. 先随机生成两批点。而且要保证这些点是可以用一条直线分开的。
    • 每一批点我都生成了50个。
    • 我事先划定两条线 y = 2 x + 0.5 y = 2x + 0.5 y=2x+0.5 y = 2 x − 1 y = 2x - 1 y=2x1(随便定的,没有什么特别理由)。我让第一类点都在 y = 2 x + 0.5 y = 2x + 0.5 y=2x+0.5之上,第二类点都在 y = 2 x − 1 y = 2x - 1 y=2x1之下,以此保证两类点一定能被分开。
    • 我还限定了x, y值的范围,以此保证最后生成的点以及坐标图都在一定范围之内。
  2. 使用pyplot画图。
    • 使用了动态模式,使得每次感知器算法更新后图像都能更新。

代码

代码也很短很简单。

import random

import matplotlib.pyplot as plt
import numpy as np


def generate_points_A() -> (list, list):
  Y = [ random.uniform(0.5, 20) for _ in range(50) ]
  X = [ random.uniform(0, (y - 0.5) * 0.5) for y in Y ]

  return X, Y

def generate_points_B() -> (list, list):
  Y = [ random.uniform(0, 20) for _ in range(50) ]
  X = [ random.uniform((y + 1) * 0.5, 20) for y in Y ]

  return X, Y

START = -3
END = 23

def update_plt(om1, om2, om3, x):
  y = -om1 * x / om2 - om3 / om2
  plt.cla()
  plt.xlim(START, END)
  plt.ylim(START, END)
  plt.plot(x, y, color=(0.5, 0.5, 0.5))
  plt.scatter(x1, y1, s=16., color=(0., 0.5, 0.0))
  plt.scatter(x2, y2, s=16., color=(0., 0.0, 0.5))
  plt.pause(0.5)

if __name__ == '__main__':
  x1, y1 = generate_points_A()
  x2, y2 = generate_points_B()

  x = np.arange(START, END, 0.1)
  sample_list = [ (s[0], s[1], 1) for s in zip(x1, y1) ] + [ (-s[0], -s[1], -1) for s in zip(x2, y2) ]
  plt.ion()

  flag = True
  om = [ 0, 1, 0 ]
  update_plt(om[0], om[1], om[2], x)

  input()

  while flag:
    flag = False
    for sample in sample_list:
      if om[0] * sample[0] + om[1] * sample[1] + om[2] * sample[2] < 0:
        om[0] += sample[0]
        om[1] += sample[1]
        om[2] += sample[2]
        flag = True
        update_plt(om[0], om[1], om[2], x)

  print(f'运行结束,已收敛')

  plt.ioff()
  plt.show()

呈现效果

跑了两次,录屏然后做成了gif。还是非常有趣的~
请添加图片描述
请添加图片描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值