笨方法学机器学习(二)全连接神经网络

网络构成

算法假设

我们的大脑接收眼睛观察传播来的数据后,会对其进行一层层的神经元去解析数据,然后得到我们对于所见的判断。然而我们对这个分析过程的了解以及脑部的研究较为浅,无法得知其脑部工作的原理。但是,我们是否可以对其进行部分抽象化为以下过程:


脑部在接收一系列数据的时候进行了一个函数式(function)的抽象,得到了其认知。

那么,我们的神经网络就是模拟这个过程,将输入信号,神经元的function处理,以及输出,都数字化。用统计与学习的方式,将这个过程一步步还原;


全连接神经网络

其全连接神经网络规则如下:

  • 神经元按照层来布局。最左边的层叫做输入层,负责接收输入数据;最右边的层叫输出层,我们可以从这层获取神经网络输出数据。输入层和输出层之间的层叫做隐藏层,因为它们对于外部来说是不可见的。
  • 同一层的神经元之间没有连接。
  • 第N层的每个神经元和第N-1层的所有神经元相连(这就是full connected的含义),第N-1层神经元的输出就是第N层神经元的输入。
  • 每个连接都有一个权值。

神经元

神经元是构成神经网络的基本单位:


一个神经元的组成为:

  • 输 入:n维度向量x
  • 线性加权:
  • 激活函数: $H(x)$,要求非线性,容易求导数
  • 输出 a

激活函数的选择

(1)sigmoid函数

(2)tanh函数

(3)relu函数

计算样例

下面我们来用最简单是sigmoid函数来尝试手算一个很简单的神经网络:


  • 中间蓝色的神经元代表了隐层神经元,其左边的是W权值,b代表了其偏置项。
  • X 为输入层
  • 红色神经元代表输出,只有一个神经元代表这个神经网络只有一个输出

x1与z1的连线权值为$0.1$,x1的输出为$0.5$,所以x1到z1的输入为$0.1$*$0.5$,同理。x2到z1的输入为$-0.06$,所以根据计算公式,z1的输入为:$0.1 0.5 +0.2-(0.3)+0.01$,再将其进行激活函数处理,得到Z1的输出:$0.50224$

神经网络的训练

  • 我们需要知道一个神经网络的每个连接上的权值.
  • 我们可以说神经网络就是一个模型,这些权值就是模型的参数(即模型要学习的东西),
  • 对于这个神经网络的连接方式,网络层数,每层的节点数,这些,我们是事先设置的,成为超参数.

目标函数与误差计算

在监督学习中,对于每一个样本,我们得到其特征$x$,标记$y$.我们通过模型$h(x)$计算得到输出值:

,显然$y$是其真实值,
是其神经网络的预测值,我们希望预测值跟真实值更接近,
数学中常用的办法是将两个值的差的平方的$1/2$来代表其接近程度:

我们将$e$当做单个成本的误差,将所有的训练样本的误差值相加,得到其误差误差项$E$:


训练的目标,就是找到合适的$w$,使误差$E$最小;

训练方法:反向传播算法(Back Propagation)

简单的说,反向传播算法的过程就是:

  • 给定的一个输入集$X$,取其中的一个向量$x$
  • 先正向计算$x$的神经网络,得到其输出值$y$
  • 训练向量$x$有人为标定的标签$l$(label),计算其预测值跟真实值之间的误差,
  • 将误差项每一层地反向传播,得到每一层的误差,然后利用每一层的误差去更新每一层的权值去拟合模型

我们先给出各层的计算公式,然后再进行数学公式的推导(不擅长数学的可以跳过,等代码实现再回来看推导)

(1) 输出层的误差计算:



其中,
是节点i的误差值,$Yi$是节点$i$的输出值,$Ti$是对应节点$i$的目标值

(2) 隐藏层的误差计算与传递



我们知道:

$ai$是节点i的输出值,$Wki$节点i到它下一层节点$i$连接的权重,
是节点$i$到下一层节点$k$的误差项

更新权重:


数学公式的推导:

我们取网络所有输出层节点的误差平方和作为目标函数:


,
用随机梯度下降算法对目标函数进行优化:



我们可以从上图得到,$W84$仅影响$a4$节点到$8$节点的输入值,设:$netj$为节点$j$的加权输入:


$Ed$是$netj$的函数,而$netj$是$Wji$的函数,根据链式求导法则:



$xji$是节点i到节点j的输出值,即$j$的输入值

输出层:

netj仅影响节点j的输出值,,所以Ed是yi的函数,yi是netj的函数:



计算第一项
将Ed带入公式,得到:


计算第二项:


综合,得:


将其推导代入 随机推导公式,得:


隐层:

我们定义节点j的所有直接下游节点的集合为:$Downstream(j)$,所以netj只能通过影响$Downstream(j)$来影响$Ed$,设Netk是节点J的下游输入,而$Ed$是netk的函数,而netk是netj的函数,所以我们用全导数公式:



因为:
,代入,得:

自此,我们完成了公式的推导

代码:

import numpy as np

#定义tan函数以及tan函数的导数
def tanh(x):
    return np.tanh(x)

def tanh_deriv(x):
    return  1.0-np.tanh(x)*np.tanh(x)

#定义logistich函数以及其导数
def logistic(x):
    return 1/(1+np.exp(-x))

def logistic_derivatrive(x):
    return logistic(x)*(1-logistic(x))

class NeturalNetwork(object):
    def __init__(self,layers,activations='tanh'):
        '''
        :param layers: 一个list  包括每一层的神经元数
        :param activations:激活函数
        '''
        if activations=='tanh':
            self.activation = tanh
            self.activation_deriv = tanh_deriv
        if activations=='logistic':
            self.activation = logistic
            self.activation_deriv = logistic_derivatrive
        self.weights = []
        for i in range(1,len(layers)-1):
            #i跟前一层的权重
            self.weights.append((2*np.random.random((layers[i-1]+1,layers[i]+1))-1)*0.25)
            #i层跟i+1层进行赋值 权重
            self.weights.append((2*np.random.random((layers[i]+1,layers[i+1]))-1)*0.25)

    def fit(self,X,y,learning_rate = 0.2,epochs=10000):
        '''
        :param X:
        :param y:
        :param learning_rate: 学习率
        :param epochs: 学习步骤
        :return:
        '''
        #二维矩阵
        X = np.atleast_2d(X)
        #ones 矩阵全是1   shape函数返回的是行列数(返回一个List)跟X一样维度的矩阵
        temp = np.ones([X.shape[0],X.shape[1]+1])
        #temp等于第一列到最后一列跟x一样的矩阵
        temp  [:,0:-1]=X
        X= temp
        Y=np.array(y)

        #第几次循环
        for k in range(epochs):
            i = np.random.randint(X.shape[0])
            #随机取一个数,代表第i行,对i行数据进行更新
            a = [X[i]]
            #形成这一行数据为输入的神经网络,dot代表内积
            for l in range(len(self.weights)):
                a.append(self.activation(np.dot(a[l],self.weights[l])))
            #误差
            error = y[i]-a[-1]
            deltas = [error * self.activation_deriv(a[-1])]
            #开始往回算每一层的误差
            #deltas是所有权重的误差列表
            for l in range(len(a)-2,0,-1):
                deltas.append(deltas[-1].dot(self.weights[l].T)*self.activation_deriv(a[l]))
            deltas.reverse()
            for i in range(len(self.weights)):
                layers = np.atleast_2d(a[i])
                delta = np.atleast_2d(deltas[i])
                self.weights[i] += learning_rate*layers.T.dot(delta)
    def predict(self,x):
        x = np.array(x)
        temp = np.ones(x.shape[0]+1)
        temp[0:-1] = x
        a =temp
        for l in range(0,len(self.weights)):
            a = self.activation(np.dot(a,self.weights[l]))
        return a
用手写训练集来测试我们的神经网络:
import numpy as np
from sklearn.datasets import load_digits
from sklearn.metrics import confusion_matrix,classification_report
from sklearn.preprocessing import LabelBinarizer
from neuralNetwork.nn import NeturalNetwork
from sklearn.cross_validation import train_test_split

digits =load_digits()
#1797张 8*8的手写数字图片
X = digits.data
Y = digits.target
#标准化
X -=X.min()
X /=X.max()

nn = NeturalNetwork([64,100,10],'logistic')

#分离测试集跟训练集
X_train,X_test,y_train,y_test = train_test_split(X,Y)
labels_train = LabelBinarizer().fit_transform(y_train)
labels_test  = LabelBinarizer().fit_transform(y_test)

print("start fitting")

nn.fit(X_train,labels_train,epochs=3000)

print("end training")
predictions=[]

for i in range(X_test.shape[0]):
    o = nn.predict(X_test[i])
    predictions.append(np.argmax(o))

#10*10矩阵(分类是10) ,对角线表示预测的对,行是预测值,列是真实值
print(confusion_matrix(y_test,predictions))
'''
v[[43  0  0  0  0  0  0  0  0  0]
 [ 0 37  0  0  0  0  1  0  0  8]
 [ 0  1 38  3  0  0  0  0  0  0]
 [ 0  0  1 47  0  1  0  1  0  0]
 [ 0  0  0  0 47  0  0  0  0  1]
 [ 0  0  0  0  0 48  1  0  0  0]
 [ 0  2  0  0  0  0 38  0  0  0]
 [ 0  0  0  0  1  0  0 37  0  1]
 [ 1  7  0  1  0  4  1  0 26  6]
 [ 0  0  0  4  0  0  0  0  0 43]]
'''
print(classification_report(y_test,predictions))
'''统计
             precision    recall  f1-score   support

          0       0.98      1.00      0.99        43
          1       0.79      0.80      0.80        46
          2       0.97      0.90      0.94        42
          3       0.85      0.94      0.90        50
          4       0.98      0.98      0.98        48
          5       0.91      0.98      0.94        49
          6       0.93      0.95      0.94        40
          7       0.97      0.95      0.96        39
          8       1.00      0.57      0.72        46
          9       0.73      0.91      0.81        47

avg / total       0.91      0.90      0.90       450

'''

用向量式编程的思想改进我们的代码:

# -*- coding:utf-8 -*-
#!/usr/bin/local/bin/python

import numpy as np

class FullConnectedLayer(object):
    def __init__(self,input_size,
                 output_size,
                 learing_rate,
                 activator):
        self.input_size = input_size
        self.output_size = output_size
        self.activator = activator
        self.learning_rate = learing_rate
        self.W = np.random.uniform(-0.1,0.1,(output_size,input_size))
        self.b = np.zeros((output_size,1))
        self.output = np.zeros((output_size,1))
    def forward(self,input_array):
        self.input = input_array
        self.output = self.activator.forward(
            np.dot(self.W,input_array)+self.b
        )

    def backward(self,delta_array):
        self.delta = self.activator.backward(self.input) * np.dot(
            self.W.T,delta_array
        )
        self.W_grad = np.dot(delta_array,self.input.T)
        self.b_grad = delta_array

    def update(self):
        self.W += self.learning_rate * self.W_grad
        self.b += self.learning_rate * self.b_grad
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,590评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,808评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,151评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,779评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,773评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,656评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,022评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,678评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,038评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,756评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,411评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,005评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,973评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,053评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,495评论 2 343

推荐阅读更多精彩内容

  • 楔子 自古正邪不两立,几百年前正道大败魔教,将之赶出中原,如今魔教欲卷土重来,江湖人人自危,风雨欲来。 01 落日...
    胡小枫阅读 645评论 8 10
  • 数据类型 数据类型由三部分组成身份(id)、类型(type)、值。看对象有没有改变使用id(object)查看对象...
    letry阅读 351评论 0 0
  • 记得小时候买磁带,硬拖带拉爸妈,站在营业柜台前垫着脚尖指着里面看的见摸不着的磁带,然后满心欢喜的看着爸妈付钱,...
    钱爸比阅读 404评论 0 1