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

神经元模型

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

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

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

感知机与多层网络

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

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

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

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

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

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

误差逆传播算法

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

训练集为

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

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

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

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

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

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

,其中

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

对于训练例

,假定神经网络的输出为

,即

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

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

其中

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

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

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

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

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

代码如下:

# 参考自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#

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏机器学习算法与Python学习

线性分类器

线性分类 上一篇笔记介绍了图像分类问题。图像分类的任务,就是从已有的固定分类标签集合中选择一个并分配给一张图像。我们还介绍了k-Nearest Neighbor...

38990
来自专栏我的python

自然语言处理之文本卷积

自然语言处理之文本卷积 1.文本的向量表示 2.文本的1维卷积 3.池化

380160
来自专栏重庆的技术分享区

吴恩达-神经网络和深度学习( 第三周 浅层神经网络:)

17640
来自专栏CVer

一文读懂卷积神经网络中的1x1卷积核

1. 卷积核(convolutional kernel):可以看作对某个局部的加权求和;它是对应局部感知,它的原理是在观察某个物体时我们既不能观察每个像素也不能...

45330
来自专栏计算机视觉战队

每日一学 | 线性分类笔记(上)

图像分类的任务,就是从已有的固定分类标签集合中选择一个并分配给一张图像。我们还介绍了k-Nearest Neighbor (k-NN)分类器,该分类器的基本思想...

9210
来自专栏企鹅号快讯

大牛教你使用7种卷积神经网络进行物体检测!

-欢迎加入AI技术专家社群>> 当我们讨论对图片进行预测时,到目前为止我们都是谈论分类。我们问过这个数字是0到9之间的哪一个,这个图片是鞋子还是衬衫,或者下面这...

419100
来自专栏深度学习之tensorflow实战篇

随机森林基本原理

基础内容: 这里只是准备简单谈谈基础的内容,主要参考一下别人的文章,对于随机森林与GBDT,有两个地方比较重要,首先是information gain,其次是决...

35890
来自专栏书山有路勤为径

卷积神经网络-目标检测

其中,bx、by表示汽车中点,bh、bw分别表示定位框的高和宽。以图片左上角为(0,0),以右下角为(1,1),这些数字均为位置或长度所在图片的比例大小。

14410
来自专栏AI科技评论

大会 | 斯坦福ICLR2018录用论文:高效稀疏Winograd卷积神经网络

AI 科技评论按:ICLR 2018 于 5 月初在加拿大温哥华举办。论文「Efficient Sparse-Winograd Convolutional N...

15330
来自专栏机器人网

卷积神经网络概念与原理

受Hubel和Wiesel对猫视觉皮层电生理研究启发,有人提出卷积神经网络(CNN),Yann Lecun 最早将CNN用于手写数字识别并一直保持...

12920

扫码关注云+社区

领取腾讯云代金券