感知器及双月实验

一、定义

  感知器是模仿人类神经元的用于线性可分分类的最简单的神经网络模型。线性可分分类即可以通过一个线性的超平面将数据分开。其基本模型如下图所示,其中 a 1 , a 2 , . . . a n a_{1},a_{2},...a_{n} a1,a2,...an是输入数据, w 1 , w 2 , . . . , w n w_{1},w_{2},...,w_{n} w1,w2,...,wn是权重可以理解为可分超平面的斜率, b b b是偏执保证超平面不过原点, s u m sum sum是简单的求和操作, f f f在感知器中被称为激活函数,实际上是一个限幅器,将输出映射为对应的类别的值域中。

在这里插入图片描述

  感知器的数学模型如下:
f ( x ) = { 1  if  w ⋅ x + b > 0 − 1  else  f(x)=\left\{\begin{array}{ll}{1} & {\text { if } w \cdot x+b>0} \\ {-1} & {\text { else }}\end{array}\right. f(x)={11 if wx+b>0 else 
  公式中的-1,1只是表示两个类别不具备任何具体的含义,可以用其他两个不同的数字代替,其中 ∑ i = 1 n w i x i + b = 0 \sum_{i=1}^{n} w_{i} x_{i}+b=0 i=1nwixi+b=0便是感知器学习到的可分超平面。感知器一般使用梯度下降,最小二乘和有感知器学习对权重 w \textbf{w} w进行迭代来调整超平面。

二、感知器收敛定理

  对于感知器收敛是可证明的下面就给出相应的收敛定理证明,另外,感知器收敛的前提是数据是线性可分的。

  在感知器中一般 b b b只会选取一个固定的值比如+1,-1作为偏置,这里选择+1,因此可以将 b b b w w w合并,因此相应的输入 x x x w w w变成:

x = [ + 1 , x 1 , x 2 , . . . , x n ] T x=[+1, x_{1}, x_{2},...,x_{n}]^{T} x=[+1,x1,x2,...,xn]T

w = [ w 0 , w 1 , w 2 , . . . , w n ] T w=[w_{0}, w_{1}, w_{2},...,w_{n}]^{T} w=[w0,w1,w2,...,wn]T

  其中 x x x w w w分别在第一位添加了一个维度,公式变得更加紧蹙,但是计算结果和过程都不会受到影响。原感知器模型就变成:

f ( x ) = ∑ i = 1 n w i x i + b ⇒ f ( x ) = ∑ i = 1 n w i x i = w T x f(x)=\sum_{i=1}^{n}w_{i}x_{i}+b \Rightarrow f(x)=\sum_{i=1}^{n}w_{i}x_{i}=\textbf{w}^T\textbf{x} f(x)=i=1nwixi+bf(x)=i=1nwixi=wTx

  感知器更新 w w w的方式很简单基本就是惩罚措施,对于正确分类的情况 w w w不做任何更新,对于错分的情况才更新 w w w,可以认为感知器做错了就打一巴掌,指导他所有都做对了为止。基本的更新规则如下(第一个公式就是对于正确分类,第二个公式就是对于错误分类, D 1 D_1 D1 D 2 D_2 D2分别为两个类别):
w n + 1 = w n x n w n T > 0 且 x n ∈ D 1 w n + 1 = w n x n w T ⩽ 0 且 x n ∈ D 2 \begin{array}{ll}{w_{n+1}=w_{n}} & { x_n w_n^{T}>0 且 x_n\in D_1} \\ {w_{n+1}=w_n} & { x_nw^{T} \leqslant 0且x_n \in D_2}\end{array} wn+1=wnwn+1=wnxnwnT>0xnD1xnwT0xnD2

w n + 1 = w n − η n x n x n w n T > 0 且 x n ∈ D 2 w n + 1 = w n + η n x n x n w T ⩽ 0 且 x n ∈ D 1 \begin{array}{ll}{w_{n+1}=w_{n}-\eta_n x_n} & { x_n w_n^{T}>0 且 x_n\in D_2} \\ {w_{n+1}=w_n+\eta_n x_n} & { x_nw^{T} \leqslant 0且x_n \in D_1}\end{array} wn+1=wnηnxnwn+1=wn+ηnxnxnwnT>0xnD2xnwT0xnD1

   η \eta η表示学习率,通常学习率只会和学习的快慢相关不会和最总的结果有很大的关系。因此我们现在假定学习率 η = 1 \eta=1 η=1且为常量,而且 w 0 = 0 w_0=0 w0=0,因此对于 w n w_n wn的迭代可以得到: w n + 1 = x 1 + x 2 + . . . + x n w_{n+1}=x_1+x_2+...+x_n wn+1=x1+x2+...+xn,因为两个类别是线性可分的因此一定存在一个线性超平面得到最终的解,假定最终的解为 w o \textbf{w}_o wo,因此可以定义一个常数 α \alpha α,存在

α = min ⁡ x n ∈ D 1 w o T x n ⇒ w o T w n + 1 = w o T x 1 + w o T x 2 + ⋯ + w o T x n ⇒ w o T w n + 1 ⩾ n α ⇒ ∥ w o ∥ 2 ∥ w n + 1 ∥ 2 ⩾ n 2 α 2 因 为 ∥ w o ∥ 2 ∥ w n + 1 ∥ 2 ⩾ [ w o T w n + 1 ] 2 ⇒ ∥ w n + 1 ∥ 2 ⩾ n 2 α 2 ∥ w o ∥ 2 \begin{aligned} &\alpha =\min_{x_n \in D_1} \textbf{w}_o^T \textbf{x}_n \\ &\Rightarrow\mathbf{w}_{o}^{T} \mathbf{w}_{n+1}=\mathbf{w}_{o}^{T} \mathbf{x}_1+\mathbf{w}_{o}^{T} \mathbf{x}_2+\cdots+\mathbf{w}_{o}^{T} \mathbf{x}_n \\ &\Rightarrow \mathbf{w}_{o}^{T} \mathbf{w}_{n+1} \geqslant n \alpha \\ &\Rightarrow\left\|\mathbf{w}_{o}\right\|^{2}\|\mathbf{w}_{n+1}\|^{2} \geqslant n^{2} \alpha^{2} 因为\left\|\mathbf{w}_{o}\right\|^{2}\|\mathbf{w}_{n+1}\|^{2} \geqslant\left[\mathbf{w}_{o}^{T} \mathbf{w}_{n+1}\right]^{2} \\ &\Rightarrow \|\mathbf{w}_{n+1}\|^{2} \geqslant \frac{n^{2} \alpha^{2}}{\left\|\mathbf{w}_{o}\right\|^{2}} \end{aligned} α=xnD1minwoTxnwoTwn+1=woTx1+woTx2++woTxnwoTwn+1nαwo2wn+12n2α2wo2wn+12[woTwn+1]2wn+12wo2n2α2

  这里证明了 w n w_n wn的下限,另一方面证明其的上限:

w n + 1 = w n + x n ⇒ ∥ w n + 1 ∥ 2 = ∥ w n ∥ 2 + ∥ x n ∥ 2 + 2 w n T x n , 对 上 式 两 边 同 时 平 方 ⇒ ∥ w n + 1 ∥ 2 ⩽ ∑ k = 1 n ∥ x k ∥ 2 ⩽ n β , 其 中 β = max ⁡ x n ∈ D 1 ∥ x n ∥ 2 \begin{aligned} &\boldsymbol{w}_{n+1}=\boldsymbol{w}_n+\mathbf{x}_n \\ &\Rightarrow \|\mathbf{w}_{n+1}\|^{2}=\|\mathbf{w}_n\|^{2}+\|\mathbf{x}_n\|^{2}+2 \mathbf{w}^{\mathrm{T}}_n \mathbf{x}_n, 对上式两边同时平方\\ &\Rightarrow \|\mathbf{w}_{n+1}\|^{2} \leqslant \sum_{k=1}^{n}\|\mathbf{x}_k\|^{2} \leqslant n \beta, 其中\beta=\max _{x_n \in \mathbb{D}_{1}}\|\mathbf{x}_n\|^{2} \end{aligned} wn+1=wn+xnwn+12=wn2+xn2+2wnTxn,wn+12k=1nxk2nβ,β=xnD1maxxn2

  因此有:

n 2 α 2 ∥ w o ∥ 2 ⩽ ∥ w n + 1 ∥ 2 ⩽ ∑ k = 1 n ∥ x k ∥ 2 ⩽ n β , 其 中 β = max ⁡ x n ∈ D 1 ∥ x n ∥ 2 , α = min ⁡ x n ∈ D 1 w o T x n ⇒ n max ⁡ 2 α 2 ∥ w o ∥ 2 = n max ⁡ β ∃ n m a x ⇒ n m a x = β ∣ ∣ W o ∣ ∣ 2 α 2 \begin{aligned} &\frac{n^{2} \alpha^{2}}{\left\|\mathbf{w}_{o}\right\|^{2}} \leqslant \|\mathbf{w}_{n+1}\|^{2} \leqslant \sum_{k=1}^{n}\|\mathbf{x}_k\|^{2} \leqslant n \beta, 其中\beta=\max _{x_n \in \mathbb{D}_{1}}\|\mathbf{x}_n\|^{2}, \alpha =\min_{x_n \in D_1} \textbf{w}_o^T \textbf{x}_n \\ &\Rightarrow \frac{n_{\max }^{2} \alpha^{2}}{\left\|\mathbf{w}_{\mathrm{o}}\right\|^{2}}=n_{\max } \beta \exist n_{max} \\ &\Rightarrow n_{max}=\frac{\beta||\textbf{W}_o||^2}{\alpha^2} \end{aligned} wo2n2α2wn+12k=1nxk2nβ,β=xnD1maxxn2,α=xnD1minwoTxnwo2nmax2α2=nmaxβnmaxnmax=α2βWo2

  因此对于线性可分的数据集,对于 η = 0 , w 0 = 0 \eta=0,w_0=0 η=0,w0=0一定能在一定的迭代次数之后终止。而对于 η \eta η非固定时,感知器总是能够在一定步数到达固定的 η \eta η中的某个状态,也就是将固定 η \eta η分解为多个任务,以不同的 η \eta η进行迭代,但最终的效果是相同的,唯一不同的是需要迭代训练的次数增加或者减少。

  感知器算法完整描述:

  • 输入:数据: x = [ + 1 , x 1 , x 2 , . . . , x n ] T x=[+1,x_1,x_2,...,x_n]^T x=[+1,x1,x2,...,xn]T, 权值 w = [ b , w 1 , w 2 , . . . , w n ] T w=[b,w_1, w_2,...,w_n]^T w=[b,w1,w2,...,wn]T,实际响应 y n y_n yn期望响应: d n d_n dn,学习率 η \eta η

    1. 初始化,对输入数据和权重进行初始化;
    2. 激活,通过输入 x x x和期望响应 d n d_n dn激活感知器;
    3. 计算实际响应, y n = s g n ( w n T x n ) y_n=sgn(w_n^Tx_n) yn=sgn(wnTxn), s g n sgn sgn为符号函数
    4. 更新权值: w n + 1 = w n + η ( d n − y n ) x n w_{n+1}=w_n+\eta(d_n-y_n)x_n wn+1=wn+η(dnyn)xn
    5. n = n + 1 n=n+1 n=n+1转2直到验证的准确率达到阈值为止。

    其中, d n = { + 1 x ∈ D 1 − 1 x ∈ D 2 d_n=\left\{\begin{array}{ll}{+1} & {x \in D_1} \\ {-1} & { { x \in D_2 }}\end{array}\right. dn={+11xD1xD2

  在学习过程需要注意的是,虽然感知器对线性可分模型一定收敛但是在实际应用中,需要慎重选取 η \eta η,希望稳定的更新就需要比较小的 η \eta η,可能速度过慢,希望快速更新就需要比较大的 η \eta η可能会出现更新过快震荡的情况。

三、贝叶斯分类器

1、高斯环境下的感知器与贝叶斯分类器的关系

  贝叶斯分类器对于二分类问题(两个类别分别为 D 1 D_1 D1, D 2 D_2 D2),其平均风险为:
R = c 11 p 1 ∫ D 1 p x ( x ∣ D 1 ) d x + c 22 p 2 ∫ D 2 p x ( x ∣ D 2 ) d x + c 21 p 1 ∫ D 1 p x ( x ∣ D 1 ) d x + c 12 p 2 ∫ D 2 p x ( x ∣ D 2 ) d x \begin{aligned} \mathcal{R}&=c_{11}p_1\int_{D_1}p_x(x|D_1)dx+c_{22}p_2\int_{D_2}p_x(x|D_2)dx\\&+c_{21}p_1\int_{D_1}p_x(x|D_1)dx+c_{12}p_2\int_{D_2}p_x(x|D_2)dx \end{aligned} R=c11p1D1px(xD1)dx+c22p2D2px(xD2)dx+c21p1D1px(xD1)dx+c12p2D2px(xD2)dx
  其中:

  • P i P_i Pi标是变量 x x x取自子空间 D i D_i Di的先验概率, i = 1 , 2 i=1,2 i=1,2 p 1 + p 2 = 1 p_1+p_2=1 p1+p2=1
  • c i j c_{ij} cij将$ 类 识 别 为 类识别为 i 类 的 代 价 , 类的代价, i=1,2$
  • p x ( x ∣ D i ) p_x(x|D_i) px(xDi)标是变量 x x x的条件概率密度函数, i = 1 , 2 i=1,2 i=1,2

  令: D = D 1 + D 2 D=D_1+D_2 D=D1+D2,可以将上式改写为:
R = c 11 p 1 ∫ D 1 p x ( x ∣ D 1 ) d x + c 22 p 2 ∫ D − D 1 p x ( x ∣ D 2 ) d x + c 21 p 1 ∫ D 1 p x ( x ∣ D 1 ) d x + c 12 p 2 ∫ D − D 1 p x ( x ∣ D 2 ) d x \begin{aligned} \mathcal{R}&=c_{11}p_1\int_{D_1}p_x(x|D_1)dx+c_{22}p_2\int_{D-D_1}p_x(x|D_2)dx\\&+c_{21}p_1\int_{D_1}p_x(x|D_1)dx+c_{12}p_2\int_{D-D_1}p_x(x|D_2)dx \end{aligned} R=c11p1D1px(xD1)dx+c22p2DD1px(xD2)dx+c21p1D1px(xD1)dx+c12p2DD1px(xD2)dx
  又因 c 11 < c 21 , c 22 < c 12 c_{11}<c_{21},c_{22}<c_{12} c11<c21,c22<c12且有 ∫ D p x ( x ∣ D 1 ) d x = ∫ D p x ( x ∣ D 2 ) d x = 1 \int_Dp_x(x|D_1)dx=\int_Dp_x(x|D_2)dx=1 Dpx(xD1)dx=Dpx(xD2)dx=1
  则上式简化为
R = c 21 p 1 + c 22 p 2 + ∫ D 1 [ p 2 ( c 12 − c 22 ) p x ( x ∣ D 2 ) − p 1 ( c 21 − c 11 ) p ( x ) ( x ∣ D 1 ) ] d x \begin{aligned} \mathcal{R} &=c_{21}p1 + c_{22}p2\\ &+\int_{D_1}[p_2(c_{12}-c_{22})p_x(x|D_2)-p_1(c_{21}-c_{11})p(x)(x|D_1)]dx \end{aligned} R=c21p1+c22p2+D1[p2(c12c22)px(xD2)p1(c21c11)p(x)(xD1)]dx
  上式中第一项为固定项,为了最小化代价应该最小化第二项,因此最优的分类策列是将使得 p x ( x ∣ D 2 ) p_x(x|D_2) px(xD2)越小越好, p x ( x ∣ D 1 ) p_x(x|D_1) px(xD1)越大越好,假设条件
p 1 ( c 21 − c 11 ) p x ( x ∣ D 1 ) > p 2 ( c 12 − c 22 ) p x ( x ∣ D 2 ) \begin{aligned} p_1(c_{21} - c_{11})p_x(x|D_1) \gt p_2(c_{12}-c_{22})p_x(x|D_2) \end{aligned} p1(c21c11)px(xD1)>p2(c12c22)px(xD2)
  定义
Λ ( x ) = p x ( x ∣ D 1 ) p x ( x ∣ D 2 ) 和 ξ = p 2 ( c 12 − c 22 ) p 1 ( c 21 − c 11 ) \begin{aligned} \Lambda(x)=\frac{p_x(x|D_1)}{p_x(x|D_2)}和\xi=\frac{p_2(c_{12}-c_{22})}{p_1(c_{21}-c_{11})} \end{aligned} Λ(x)=px(xD2)px(xD1)ξ=p1(c21c11)p2(c12c22)
  其中 Λ \Lambda Λ是拟然比, ξ \xi ξ是检验阈值,二者恒正,则贝叶斯分类器可以表述为:
{ x ∈ D 1 , Λ ( x ) > ξ x ∈ D 2 , Λ ( x ) ≤ ξ \begin{aligned} \left\{\begin{array}{ll} x \in D_1,\Lambda(x)>\xi\\ x \in D_2,\Lambda(x)\le\xi\end{array}\right. \end{aligned} {xD1,Λ(x)>ξxD2,Λ(x)ξ
  很明显这个分类器和感知器的分类策略很相似,因此贝叶斯分类器和感知器等价。

2、高斯分布下的贝叶斯分类器

  对于高斯分布的情况存在下面的情况:
{ E [ X ] = μ 1 , E [ ( X − μ 1 ) ( X − μ 1 ) T ] = C X ∈ D 1 E [ X ] = μ 2 , E [ ( X − μ 2 ) ( X − μ 2 ) T ] = C X ∈ D 2 \begin{aligned} \left\{\begin{array}{ll} \mathbb{E}[X]=\mu_1,\mathbb{E}[(X-\mu_1)(X-\mu_1)^T]=C & X \in D_1\\ \mathbb{E}[X]=\mu_2,\mathbb{E}[(X-\mu_2)(X-\mu_2)^T]=C & X\in D_2\end{array}\right. \end{aligned} {E[X]=μ1,E[(Xμ1)(Xμ1)T]=CE[X]=μ2,E[(Xμ2)(Xμ2)T]=CXD1XD2
  其中C为协方差,是非对角,即 D 1 D_1 D1 D 2 D_2 D2是相关的,假设C是非奇异的,即逆矩阵 C − 1 C^{-1} C1存在。
   x x x的条件概率密度韩式表示为多变量高斯分布为:
p x ( x ∣ D 1 ) = 1 ( 2 π ) m / 2 ( Δ ( C ) ) 1 / 2 e − 1 2 ( x − μ ) T C − 1 ( x − μ 1 ) , i = 1 , 2 , m 为 x 的 维 数 \begin{aligned} p_x(x|D_1)=\frac{1}{(2\pi)^{m/2}(\Delta(C))^{1/2}}e^{-\frac{1}{2}(x-\mu)^TC^{-1}(x-\mu_1)},i=1,2,m为x的维数 \end{aligned} px(xD1)=(2π)m/2(Δ(C))1/21e21(xμ)TC1(xμ1),i=1,2,mx
  可以进一步假设,数据时均衡的也就是分类成任何一个类的机会是等价的则有,且假设不同的错分类的代价相同,即:
p 1 = p 2 = 1 2 c 21 = c 12 , c 11 = c 22 = 0 \begin{aligned} & p_1=p_2=\frac{1}{2} \\ & c_{21}=c_{12},c_{11}=c_{22}=0 \end{aligned} p1=p2=21c21=c12,c11=c22=0
  则根据贝叶斯分类器中的情况可以得到 Λ \Lambda Λ ξ \xi ξ,并对其进行取对数有:
log ⁡ Λ ( x ) = − 1 2 ( x − μ 1 ) T C − 1 ( x − μ 1 ) + ( x − μ 2 ) T C − 1 ( x − μ 2 ) = ( μ 1 − μ 2 ) T C − 1 x + 1 2 ( μ 2 T C − 1 μ 2 − μ 1 T C − 1 μ 1 ) log ⁡ ξ = 0 \begin{aligned} \log{\Lambda(x)}&=-\frac{1}{2}(x-\mu_1)^TC^{-1}(x-\mu_1)+(x-\mu_2)^TC^{-1}(x-\mu_2)\\ &=(\mu_1-\mu_2)^TC^{-1}x+\frac{1}{2}(\mu_{2}^TC^{-1}\mu_2-\mu_{1}^TC^{-1}\mu_1)\\ &\log{\xi} = 0 \end{aligned} logΛ(x)=21(xμ1)TC1(xμ1)+(xμ2)TC1(xμ2)=(μ1μ2)TC1x+21(μ2TC1μ2μ1TC1μ1)logξ=0
  可以看到上述的表达式完全是一个线性的分类器的模型:
y = w T x + b w = ( μ 1 − μ 2 ) T C − 1 b = 1 2 ( μ 2 T C − 1 μ 2 − μ 1 T C − 1 μ 1 ) \begin{aligned} & y=\textbf{w}^T\textbf{x}+b \\ & \textbf{w} = (\mu_1-\mu_2)^TC^{-1} \\ & b=\frac{1}{2}(\mu_{2}^TC^{-1}\mu_2-\mu_{1}^TC^{-1}\mu_1) \end{aligned} y=wTx+bw=(μ1μ2)TC1b=21(μ2TC1μ2μ1TC1μ1)

3、总结

  需要注意的是虽然高斯环境下的贝叶斯分类器和感知器类似,但是二者不同:

  1. 感知器对数据的要求是线性可分,否则决策边界将不断震荡;而高斯环境下的贝叶斯分类器本身就是假设二者有重叠且相关的;
  2. 感知器是最小化分类误差概率,和最小化分类误差还是有区别的;
  3. 感知器收敛算法是分参数的;
  4. 感知器实现简单。

四、实验

  双月分类实验,目的是通过感知器对双月数据进行分类,实验分为两部分:第一部分为双月数据为线性可分的情况;第二部分为双月数据为线性不可分,非线性可分的情况:

1、线性可分moon

  如下图为线性可分的数据:
在这里插入图片描述
  下图为分类过程的损失和结果代码(中间的线为决策边界,即 w x + b = 0 wx+b=0 wx+b=0),可以看到损失函数下降的很快,基本很快就到0了:

  下面的几张图为感知调整的过程,可以看到调整的很快,第一个决策边界还不能完全拟合,第二个就基本定型了:
  另外需要注意的是,设定的$b$和最后的决策边界关系很大,不同的$b$会有不同的边界,$b$不合适可能无法完全拟合,下图分别为不同$b$值的决策边界,三张图的$b$值分别为0.3,0.5,1.0:

2、线性不可分moon

  非线性数据:
在这里插入图片描述
  分类结果,可以看到孫然損失函數很快收斂但是後面還是在不斷震蕩:

五、附件

  git链接:perceptron
  双月数据生成代码:


# -*- coding: utf-8 -*-
#生成半月数据

import numpy as np
import matplotlib.pyplot as plt
 
 
def halfmoon(rad, width, d, n_samp): 
    '''生成半月数据
    @param  rad:    半径
    @param  width:  宽度
    @param  d:      距离
    @param  n_samp: 数量
    ''' 
    if n_samp%2 != 0:  
        n_samp += 1  
    
    data = np.zeros((3,n_samp))
      
    aa = np.random.random((2,int(n_samp/2)))  
    radius = (rad-width/2) + width*aa[0,:] 
    theta = np.pi*aa[1,:]        
      
    x     = radius*np.cos(theta)  
    y     = radius*np.sin(theta)  
    label = np.ones((1,len(x)))         # label for Class 1  
      
    x1    = radius*np.cos(-theta) + rad  
    y1    = radius*np.sin(-theta) - d  
    label1= -1*np.ones((1,len(x1)))     # label for Class 2  
     
    data[0,:]=np.concatenate([x,x1])
    data[1,:]=np.concatenate([y,y1])
    data[2,:]=np.concatenate([label,label1],axis=1)
    
    return data
 
def halfmoon_shuffle(rad, width, d, n_samp): 
     
    data = halfmoon(rad, width, d, n_samp)      
    shuffle_seq = np.random.permutation(np.arange(n_samp))  
    data_shuffle = data[:,shuffle_seq]
    
    return data_shuffle
 
 
if __name__ == "__main__":
    dataNum = 1000
    data = halfmoon(10,5,5,dataNum)
    pos_data = data[:,0: int(dataNum/2)]
    neg_data = data[:, int(dataNum/2):dataNum]
    
    np.savetxt('halfmoon.txt', data.T,fmt='%4f',delimiter=',')
    
    plt.figure()
    plt.scatter(pos_data[0,:],pos_data[1,:],c="b",s=10)
    plt.scatter(neg_data[0,:],neg_data[1,:],c="r",s=10)
    plt.savefig('./imgs/moon.png')
    plt.show()

  感知器分类实验代码:

#通过感知机分类半月数据
import numpy as np
import matplotlib.pyplot as plt

def sgn(y):
    y[y > 0] = 1
    y[y < 0] = -1
    return y

class Perceptron(object):
    '''单层感知机
    '''
    def __init__(self, shape):
        super(Perceptron, self).__init__()

        self.w = np.ones(shape)      #weigth
        self.b = 1.5                                 #the bias
        self.activate_func = sgn

    def update(self,x,y,out,learning_rate):
        self.w += learning_rate * x.T * (y - out)

    def calclate(self, x):
        return self.activate_func(np.dot(self.w, x.T) + self.b)

    def loss_func(self, pre_y, gt_y):
        return (pre_y - gt_y) ** 2

    def train(self, x, y, epochs, learning_rate):
        losses = []
        for epoch in range(epochs):
            loss_tmp = []
            for i in range(x.shape[0]):
                out = self.calclate(x[i])
                loss_tmp.append(self.loss_func(out, y[i]))
                self.update(x[i], y[i], out, learning_rate)

            losses.append(sum(loss_tmp)/len(loss_tmp))
        return losses

    def predict(self, x):
        out = self.calclate(x)
        return out
    
    def test(self, x,y):
        label = self.predict(x)
        gt_count = np.sum(label==y)
        wrong_count = np.sum(label!=y)
        return wrong_count/(wrong_count+gt_count),gt_count/(wrong_count+gt_count)


    def get_params(self):
        return {'weight':self.w, 'bias':self.b}

    def draw(self):
        axis = [i for i in range(1000)]
        out = [self.w * i + self.b for i in axis]
        
        plt.plot(axis, out)
        plt.show()

def load_data(file):
    x = []
    y = []
    with open(file, 'r') as f:
        lines = f.readlines()
        for line in lines:
            line = line.strip().split(',')
            
            x_item = [float(line[0]), float(line[1])]
            y_item = float(line[2])
            
            x.append(x_item)
            y.append(y_item)
    
    return np.array(x), np.array(y)


def split_data(x, y):
    train_x, test_x = x[:int(x.shape[0]*0.7)], x[int(x.shape[0]*0.7):]
    train_y, test_y = y[:int(y.shape[0]*0.7)], y[int(y.shape[0]*0.7):]
    
    return train_x, train_y, test_x, test_y

if __name__ == '__main__':
    #进行非线性数据的分类实验时,只需要将数据的间隔缩小保证二者重合即可
    desc = 'nonlinear'
    file = './halfmoon.txt'
    x,y = load_data(file)

    train_x, train_y, test_x, test_y = split_data(x, y)

    neur = Perceptron((1,2))
    losses = neur.train(train_x,train_y,100, 0.0001)
    
    err,acc = neur.test(test_x, test_y)
    print('rate of error:', err)
    print('rate of accuracy:', acc)


    #画损失曲线
    axis = [i for i in range(len(losses))]
    plt.figure()
    plt.plot(axis, losses)
    plt.savefig('../imgs/%s_mse_loss.png' % desc)
    #plt.show()

    #画决策面   
    x_aixs = x[:,0]
    y_aixs = x[:,1]

    neg_x_axis = x_aixs[y==-1]
    neg_y_axis = y_aixs[y==-1]
    
    pos_x_axis = x_aixs[y==1]
    pos_y_axis = y_aixs[y==1]

    #感知机的参数
    params = neur.get_params()
    w = params['weight']
    b = params['bias']

    k = -1 * w[0][0] / w[0][1]
    b = -1 * b / w[0][1]

    divid_x = [i for i in range(-15,25)]
    divid_y = [k * i + b for i in divid_x]

    plt.figure()
    plt.plot(divid_x, divid_y, c='r')
    plt.scatter(neg_x_axis,neg_y_axis,c="b",s=10)
    plt.scatter(pos_x_axis,pos_y_axis,c="g",s=10)
    plt.savefig('../imgs/%s_divide.png' % desc)   #保存决策面
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值