前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >机器学习 学习笔记(19)神经网络

机器学习 学习笔记(19)神经网络

作者头像
发布2018-09-04 10:41:48
4980
发布2018-09-04 10:41:48
举报
文章被收录于专栏:WD学习记录WD学习记录

神经元模型

神经网络是由具有适应性的简单单元组成的广泛并行互连的网络,它的组织能够模拟生物神经系统对真实世界物体所作出的交互反应。

神经网络中最基本的成分是神经元模型。M-P神经元模型,在这个模型中,神经元接收到来自n个其他神经元传递过来的输入信号,这些输入信号通过带权重的连接进行传递,神经元接收到的总输入值将于神经元的阈值进行比较,然后通过激活函数处理以产生神经元的输出。

理想的激活函数是阶跃函数,但是阶跃函数具有不连续、不光滑等不太好的性质,因此实际常用Sigmoid函数作为激活函数。

感知机与多层网络

感知机由两层神经元组成,输入层接收外界输入信号后传递给输出层,输出层是M-P神经元,亦称为“阈值逻辑单元”。

感知机能很容易地实现逻辑与、或、非运算。

感知机只有输出层神经元进行激活函数处理,即只拥有一层功能神经元,其学习能力非常有限,与、或、非问题都是线性可分的。

要解决非线性可分问题,需考虑使用多层功能神经元,如异或问题。

输入层与输出层之间的神经元被称为隐层或者隐含层,隐含层和输出层神经元都是拥有激活函数的功能神经元。

神经网络的学习过程,就是根据训练数据来调整神经元之间的连接权以及每个功能神经元的阈值。

误差逆传播算法

多层网络的学习能力比单层感知机强的多。欲训练多层网络,需要更强大的算法,如误差逆传播(error BackPropagation,BP)算法。

训练集为

D=\{(x_1,y_1),(x_2,y_2),...,(x_m,y_m)\}
D=\{(x_1,y_1),(x_2,y_2),...,(x_m,y_m)\}

,输入示例由d个属性描述,输出l维实值向量,其中隐层有q个神经元。输出层第j个神经元的阈值为

\theta _j
\theta _j

,隐层第h个神经元的阈值为

\gamma _h
\gamma _h

,输入层第i个神经元与隐层第h个神经元之间的连接权为

v_{ih}
v_{ih}

,隐层第h个神经元和输出层第j个神经元之间的连接权为

w_{hj}
w_{hj}

,记隐层第h个神经元接收到的输入为

\alpha _h=\sum_{i=1}^dv_{ih}x_i
\alpha _h=\sum_{i=1}^dv_{ih}x_i

,输出层第j个神经元接收到的输入为

\beta _j=\sum_{h=1}^qw_{hj}b_h
\beta _j=\sum_{h=1}^qw_{hj}b_h

,其中

b_h
b_h

为隐层第h个神经元的输出,隐层和输出层神经元使用Sigmoid函数。

对于训练例

(x_k,y_k)
(x_k,y_k)

,假定神经网络的输出为

\hat{y}_k=(\hat{y}^k_1,\hat{y}^k_2,...,\hat{y}^k_l)
\hat{y}_k=(\hat{y}^k_1,\hat{y}^k_2,...,\hat{y}^k_l)

,即

\hat{y}^k_j=f(\beta _j-\theta _j)
\hat{y}^k_j=f(\beta _j-\theta _j)

其中这个神经网络一共有(d+l+1)q+l个参数需要确定,输入层到隐层的d x q个权值,隐层到输出层的 q x l个圈子,q个隐层神经元的阈值,l个输出神经元的阈值。

BP算法基于梯度下降策略,以目标的负梯度方向对参数进行调整,

\Delta w_{hj}=\eta g_ib_h
\Delta w_{hj}=\eta g_ib_h
\Delta \theta _j=-\eta g_j
\Delta \theta _j=-\eta g_j
\Delta v_{ih}=\eta e_h x_i
\Delta v_{ih}=\eta e_h x_i
\Delta \gamma _h=-\eta e_h
\Delta \gamma _h=-\eta e_h

其中

g_j=\hat{y}^k_j(1-\hat{y}^k_j)(y^k_j-\hat{y}^k_j)
g_j=\hat{y}^k_j(1-\hat{y}^k_j)(y^k_j-\hat{y}^k_j)

e_h=b_h(1-b_h)\sum_{j=1}^lw_{hj}g_j
e_h=b_h(1-b_h)\sum_{j=1}^lw_{hj}g_j

BP算法的目标是要最小化训练集D上的累积误差,

E=\frac{1}{m}\sum_{k=1}^m E_k
E=\frac{1}{m}\sum_{k=1}^m E_k

只需一个包含足够多神经元的隐层,多层前馈网络就能以任意精度逼近任意复杂度的连续函数。如何设置隐层神经元个数仍然是个未决问题,实际应用中同城靠“试错法”调整。

BP神经网络经常遭遇过拟合,其训练误差持续降低,但测试误差却可能上升。有两种策略常用来缓解BP神经网络的过拟合。第一种策略是早停,将数据分为训练集和验证集,训练集用来计算梯度、更新权值和阈值,验证集用来估计误差,若训练集误差降低,但验证集误差上升,则停止训练,同时返回具有最小验证集误差的连接权和阈值。第二种策略是正则化,其基本思想是在误差目标函数中增加一个用于描述网络复杂度的部分,例如链接权与阈值的平方和,如:

E=\lambda \frac{1}{m} \sum_{k=1}^mE_k+(1-\lambda )\sum_{i}w^2_i
E=\lambda \frac{1}{m} \sum_{k=1}^mE_k+(1-\lambda )\sum_{i}w^2_i

确定隐层节点数目的经验公式:

q=\sqrt{d+l}+a
q=\sqrt{d+l}+a

 ,其中a为1-10之间的调节常数

代码如下:

代码语言:javascript
复制
# 参考自https://gitee.com/hdt3213/ClassifiersDemo/blob/master/BPNN/bpnn.py#
import math
import random

random.seed(0)


def rand(a, b):
    return (b - a) * random.random() + a


def make_matrix(m, n, fill=0.0):
    mat = []
    for i in range(m):
        mat.append([fill] * n)
    return mat


def sigmoid(x):
    return 1.0 / (1.0 + math.exp(-x))


def sigmoid_derivative(x):
    return x * (1 - x)


class BPNeuralNetwork:
    def __init__(self):
        self.input_n = 0
        self.hidden_n = 0
        self.output_n = 0
        self.input_cells = []
        self.hidden_cells = []
        self.output_cells = []
        self.input_weights = []
        self.output_weights = []
        self.input_correction = []
        self.output_correction = []

    def setup(self, ni, nh, no):
        self.input_n = ni + 1
        self.hidden_n = nh
        self.output_n = no
        # init cells
        self.input_cells = [1.0] * self.input_n
        self.hidden_cells = [1.0] * self.hidden_n
        self.output_cells = [1.0] * self.output_n
        # init weights
        self.input_weights = make_matrix(self.input_n, self.hidden_n)
        self.output_weights = make_matrix(self.hidden_n, self.output_n)
        # random activate
        for i in range(self.input_n):
            for h in range(self.hidden_n):
                self.input_weights[i][h] = rand(-0.2, 0.2)
        for h in range(self.hidden_n):
            for o in range(self.output_n):
                self.output_weights[h][o] = rand(-2.0, 2.0)
        # init correction matrix
        self.input_correction = make_matrix(self.input_n, self.hidden_n)
        self.output_correction = make_matrix(self.hidden_n, self.output_n)

    def predict(self, inputs):
        # activate input layer
        for i in range(self.input_n - 1):
            self.input_cells[i] = inputs[i]
        # activate hidden layer
        for j in range(self.hidden_n):
            total = 0.0
            for i in range(self.input_n):
                total += self.input_cells[i] * self.input_weights[i][j]
            self.hidden_cells[j] = sigmoid(total)
        # activate output layer
        for k in range(self.output_n):
            total = 0.0
            for j in range(self.hidden_n):
                total += self.hidden_cells[j] * self.output_weights[j][k]
            self.output_cells[k] = sigmoid(total)
        return self.output_cells[:]

    def back_propagate(self, case, label, learn, correct):
        # feed forward
        self.predict(case)
        # get output layer error
        output_deltas = [0.0] * self.output_n
        for o in range(self.output_n):
            error = label[o] - self.output_cells[o]
            output_deltas[o] = sigmoid_derivative(self.output_cells[o]) * error
        # get hidden layer error
        hidden_deltas = [0.0] * self.hidden_n
        for h in range(self.hidden_n):
            error = 0.0
            for o in range(self.output_n):
                error += output_deltas[o] * self.output_weights[h][o]
            hidden_deltas[h] = sigmoid_derivative(self.hidden_cells[h]) * error
        # update output weights
        for h in range(self.hidden_n):
            for o in range(self.output_n):
                change = output_deltas[o] * self.hidden_cells[h]
                self.output_weights[h][o] += learn * change + correct * self.output_correction[h][o]
                self.output_correction[h][o] = change
        # update input weights
        for i in range(self.input_n):
            for h in range(self.hidden_n):
                change = hidden_deltas[h] * self.input_cells[i]
                self.input_weights[i][h] += learn * change + correct * self.input_correction[i][h]
                self.input_correction[i][h] = change
        # get global error
        error = 0.0
        for o in range(len(label)):
            error += 0.5 * (label[o] - self.output_cells[o]) ** 2
        return error

    def train(self, cases, labels, limit=10000, learn=0.05, correct=0.1):
        for j in range(limit):
            error = 0.0
            for i in range(len(cases)):
                label = labels[i]
                case = cases[i]
                error += self.back_propagate(case, label, learn, correct)

    def test(self):
        cases = [
            [0, 0],
            [0, 1],
            [1, 0],
            [1, 1],
        ]
        labels = [[1,0], [0,1], [0,1], [1,0]]
        self.setup(2, 5, 2)
        self.train(cases, labels, 10000, 0.05, 0.1)
        for case in cases:
            print(self.predict(case))


if __name__ == '__main__':
    nn = BPNeuralNetwork()
    nn.test()

参考

  1. 《机器学习》
  2. 一个 11 行 Python 代码实现的神经网络
  3. 机器学习与神经网络(四):BP神经网络的介绍和Python代码实现
  4. https://gitee.com/hdt3213/ClassifiersDemo/blob/master/BPNN/bpnn.py#
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2018年08月16日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 神经元模型
  • 感知机与多层网络
  • 误差逆传播算法
  • 参考
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档