ML神经网络

神经元模型

在这里插入图片描述

感知机与多层网络

感知机由两层神经元组成。输入层接收外界输入信号后传递给输出层,输出层是 M-P 神经元,亦称位"阈值逻辑单元(threshold logic uint)"

感知机能够轻易的实现逻辑与、或、非运算。

exmpleexmple:

import numpy as np
# 阶跃函数
def unit_step(x):
    y = x>=0
    return y.astype(np.int)

# 逻辑运算
def perc_logic(x,w,theta):
    y = x@w.T-theta
    out = unit_step(y)
    return out
x = np.array([[1,1],[0,1],[0,0],[1,0]])
# 逻辑与
w = np.array([1,1])
theta = 2
y = perc_logic(x,w,theta)
print(x.T)
print(y)
[[1 0 0 1]
 [1 1 0 0]]
[1 0 0 0]

这里的权重是我们自己给的。一般的,给定训练数据集,权重 wiw_i 以及阈值 θ\theta 可通过学习得到。感知机权重会根据如下方式进行调整:
wiwi+ΔwiΔwi=η(yy^)xi w_i\gets w_i+\Delta w_i\\ \Delta w_i=\eta (y-\hat y)x_i
其中,η(0,1)\eta \in (0,1) 称为学习率(learning rate)。感知机只能处理一些线性可分问题,其学习能力十分有限。

# 感知机实现 逻辑与的学习
import numpy as np
# 阶跃函数
def unit_step(x):
    y = x>=0
    return y.astype(np.int)

# 创造数据集
def setdata(n):
    x1 = np.random.randint(0,2,n)
    x2 = np.random.randint(0,2,n)
    y = np.logical_and(x1,x2)
    data = [x1,x2,y]
    return np.array(data).T

# 感知机
class prec:

    def __init__(self,w,lr,expoch):
        self.w = w
        self.lr = lr
        self.expoch = expoch

    def forward(self,x):
        y1 = x@self.w.T
        h1 = unit_step(y1)
        out = h1
        return out
    
    # 梯度更新
    def gradient_fit(self,x,y):
        out = self.forward(x)
        gradient_w = np.sum(self.lr*(y-out)*x,axis=0)
        self.w = self.w+gradient_w.T

    def run(self,x,y):
        for step in range(self.expoch):
            self.gradient_fit(x,y)


n = 1200
rate = 0.8
offset = int(n*rate)

data = setdata(n)
b = np.ones((n,1))
data =  np.hstack((data,b))

x_train,y_train,x_test,y_test = data[:offset,[0,1,-1]],data[:offset,2],data[offset:,[0,1,-1]],data[offset:,2]
y_train = y_train.reshape((offset,1))
y_test = y_test.reshape((n-offset,1))

init_w = np.zeros((1,3))
lr = 0.001
expoch = 1000

net = prec(init_w,lr,expoch)
net.run(x_train,y_train)

pre = unit_step(x_test@net.w.T)
acc = 1-np.sum(np.abs(y_test-pre))/len(y_test)

print(net.w)
print(acc)

误差逆传播(BP)算法

在这里插入图片描述

假设隐含层和输出层神经元都使用 SigmoidSigmoid 函数,则对训练例 (xk,yk),yk=(y1k,y2k,...,ylk)(x_k,y_k),y_k=(y_1^k,y_2^k,...,y_l^k) 有:

y^jk=f(βjθj) \hat y_j^k = f(\beta_j - \theta_j)

在网络上 (xk,yk)(x_k,y_k) 处的均方误差为:
Ek=12j=1l(y^jkyjk)2 E_k = \frac{1}{2}\sum_{j=1}^{l}(\hat y_j^k - y_j^k)^2

上面网络中需要学习的参数有:d×q+q×l+q+ld\times q + q\times l + q+l 个。BPBP 是一个迭代学习算法,在迭代的每一轮中采用广义的感知机学习规则对参数进行更新估计,任意参数 vv 的更新估计式为:
vv+Δv v \gets v + \Delta v

BPBP 算法在基于梯度下降(gradient descent) 策略更新时,以目标的负梯度方向对参数进行调整。例如,对于上述的 EkE_k ,给定学习率 η\eta 时,有:
Δwhj=ηEkwhjEkwhj=Eky^jky^jkβjβjwhjβjwhj=bh \Delta w_{hj}=-\eta \frac{\partial E_k}{\partial w_{hj}}\\ \frac{\partial E_k}{\partial w_{hj}}=\frac{\partial E_k}{\partial \hat y_{j}^k} ·\frac{\partial \hat y_{j}^k}{\partial \beta_j}·\frac{\partial \beta_j}{\partial w_{hj}}\\ \frac{\partial \beta_j}{\partial w_{hj}}=b_h

该网络中的 SigmoidSigmoid 函数具如下良好的性质:
f(x)=f(x)f(1f(x)) f'(x)=f(x)·f(1-f(x))

于是:
gi=Eky^jky^jkβj=(y^jkyjk)f(βjθj)=y^jk(1y^jk)(yjky^jk) g_i = -\frac{\partial E_k}{\partial \hat y_{j}^k} ·\frac{\partial \hat y_{j}^k}{\partial \beta_j}\\ =-(\hat y_j^k-y_j^k)f'(\beta_j-\theta_j)\\ =\hat y_j^k(1-\hat y_j^k)(y_j^k-\hat y_j^k)

最后得到 BPBP 算法中关于 whjw_{hj} 的更新公式:
Δwhj=ηgibh \Delta w_{hj}=\eta g_ib_h

类似的:
Δθj=ηgiΔvih=ηehxiΔγh=ηeh \Delta \theta_j = -\eta g_i\\ \Delta v_{ih} = \eta e_hx_i\\ \Delta \gamma_h=-\eta e_h\\
其中:
eh=Ekbhbhαh=bh(1bh)j=1lwhjgi e_h = -\frac{\partial E_k}{\partial b_h}·\frac{\partial b_h}{\partial \alpha_h}\\ =b_h(1-b_h)\sum_{j=1}^{l}w_{hj}g_i

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6t26Z9ip-1585107119639)(image-20200325113122459.png)]

需要注意的是,BPBP 算法的目标是要最小化训练集 DD 上的累计误差:
E=1mk=1mEk E = \frac{1}{m}\sum_{k=1}^{m}E_k

缓解过拟合策略:

  • 早停

将数据集分成训练集和验证集,训练集用来计算梯度,更新连接权和阈值,验证集用来估计误差,若训练集误差降低但验证集误差升高,则停止训练,同时返回具有最小验证集误差的连接权和阈值。

  • 正则化

在误差目标函数中增加一个用于描述网络复杂度的部分,例如:E=λ1mk=1mEk+(1λ)iwi2E=\lambda \frac{1}{m}\sum_{k=1}^{m}E_k+(1-\lambda)\sum_{i}w_i^2λ(0,1)\lambda \in (0,1) 用于对经验误差与网络复杂度这两项进行折中,常通过交叉验证法来估计。

避免局部最小

  • 以多组不同参数值初始化多个神经网络
  • 使用“模拟退火”
  • 使用随机梯度下降
  • 遗传算法

其他常见神经网络

  • RBFRBF 网络

  • ARTART 网络

  • SOMSOM 网络

  • 级联相关网络

  • ElmanElman 网络

  • BoltzmannBoltzmann

一个单隐层 BPBP 算法的搭建

import numpy as np
import matplotlib.pyplot as plt

plt.style.use('ggplot')
%matplotlib inline
# 对中文的支持
plt.rcParams['font.sans-serif']=['SimHei']
plt.rcParams['axes.unicode_minus'] = False

def sigmoid(x):
    y = 1/(1+np.exp(-x))
    return y

class SimpleNet:

    def __init__(self,w,b,lr,expoch):

        self.w = w
        self.b = b
        self.lr = lr
        self.expoch = expoch

    def forwad(self,x):

        y1 = self.w[0].T@x+self.b[0]
        h1 = sigmoid(y1)
        y2 = self.w[1].T@h1+self.b[1]
        h2 = sigmoid(y2)
        out = h2
        return out,h1

    def loss(self,y,ylabel):

        Ek = np.sum((y-ylabel)**2)/2

        return Ek

    def gradient_gj_eh(self,x,y,ylabel,h1):

        gj = y*(1-y)*(ylabel-y)

        eh = h1*(1-h1)*(self.w[1])@gj
        grad_w1 = self.lr*x@eh.T
        grad_w2 = self.lr*h1@gj.T

        grad_b1 = -self.lr*eh
        grad_b2 = -self.lr*gj

        self.w[0] += grad_w1
        self.w[1] += grad_w2

        self.b[0] += grad_b1
        self.b[1] += grad_b2


    def fit(self,x_train,y_train):
        m = x_train.shape[-1]

        for step in range(self.expoch):
            ls = 0
            for k in range(m):
                x = np.array(x_train[:,k],ndmin=2).T
                ylabel = np.array(y_train[:, k], ndmin=2).T
                out,h1 = self.forwad(x)
                ls += self.loss(out,ylabel)

                self.gradient_gj_eh(x,out,ylabel,h1)

            E = ls / m
            if step%50==0:
                print(E,out)

xm = 10 # 输入层样本数量
xd = 2 # 输入层样本属性(输入层神经元数量)
hq = 5 # 隐含层神经元数量
outl = 1 # 输出层神经元数量

x = np.ones((xd,xm))
y = np.ones((outl,xm))

w1 = np.zeros((xd,hq))
w2 = np.zeros((hq,outl))
w = [w1,w2]

b1 = np.zeros((hq,1))
b2 = np.zeros((outl,1))
b = [b1,b2]

net = SimpleNet(w,b,lr=0.01,expoch=100)
net.fit(x,y)
发布了21 篇原创文章 · 获赞 0 · 访问量 512
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 大白 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览