在这一节,我们对上一个程序(Network1.py)进行了优化

3.改进神经网络的学习方法

(1)交叉熵代价函数的引入

Network1程序采用了S型神经元,S型神经元存在一个问题,当输出层神经元的输出接近0,或者1的时候,sigmoid函数曲线相当平导致此时sigmoid函数的导数很小,当选择二次代价函数时,输出误差δL=(aL-y)σ‘(zL),∂C/∂ωL,∂C/∂bL就会非常小,使得神经网络学习变得缓慢。

因此我们引入了交叉熵代价函数

当选择交叉熵代价函数时,δL= aL-y。解决了输出层学习缓慢的问题,但是没有解决隐藏层的神经元在σ(z)接近1或者0的时候饱和的问题。

(2)柔性最大值的引入

有时候我们想把输出层第j个神经元的输出看做一种概率估计,因此引入了柔性最大值(softmax),第j个神经元的激活值是:

并定义对数代价函数

其中y为训练输入x对应的目标输出,aL为神经网络输出。如果我们训练的是MNIST图像,输入为7的图像,那么对应的对数代价就是-lna7L,当神经网络输出就是7的时候,他会估计一个对应的概率a7L和1很接近,所以代价就会很小,反之,神经网络表现的很糟,改良版a7L就变的很小,代价就随之增大,所以对数代价函数也是满足我们期望的代价函数的条件的。

(3)过度拟合和规范化

过度拟合可以理解为模型对已有的数据会表现的很好,但是对新的数据很难泛化,对一个模型真正的测验就是他对没有见过的场景的预测能力。

为了缓解过度拟合,我们主要采取以下措施:

  • L1.规范化
  • L2规范化
  • L1规范化
  • 弃权
  • 人为增加训练样本

这里主要讲解以下L2规范化技术。二次代价函数,以及交叉熵代价函数,柔性最大值规范化后的形式如下:

其中C0为原始代价函数。第二项加入的就是所有权重(每个元素)的平方和,λ成为规范化参数,规范化可以当做一种寻找小的权重和最小原始代价函数之间的折中,λ越小,就越偏向于最小化原始代价函数,反之倾向于小的权重。

此时权重学习就变成了

(4)权重初始化

由于Network1程序中中我们在隐藏层和输出层激活函数选用的都是sigmoid函数,我们刚才考虑采用交叉熵代价函数,解决了输出层学习缓慢的问题,但是隐藏层的神经元在σ(z)接近1或者0的时候,也会存在饱和的问题,会导致学习缓慢。

在Network1中我们随机初始化权重和偏置为标准正态分布。假设我们使用一个有大量输入神经元的网络,比如有10000个,我们假设训练输入x,其中一半神经元的输入神经值为1,另一半输入为0。让我们考虑隐藏神经元输入的带权和 z = Σwjxj+b,所以z服从μ(0,501)正态分布,z是一个有非常宽的高斯分布,z>>1或者z<<-1的概率会很大,这样神经元的输出σ(z)会接近1或者0,这样我们的隐藏神经元会饱和,所以当出现这样的情况时,在权重中进⾏微⼩的调整仅仅会给隐藏神经元的激活值带来极其微弱的改变。⽽这种微弱的改变也会影响⽹络中剩下的神经元,然后会带来相应的代价函数的改变。结果就是,这些权重在我们进⾏梯度下降算法时会学习得⾮常缓慢。这其实和我们在前⾯所说的问题差不多,前⾯的情况是输出神经元在错误的值上饱和导致学习的下降。我们之前通过代价函数的选择解决了前⾯的问题。不幸的是,尽管那种⽅式在输出神经元上有效,但对于隐藏神经元的饱和却⼀点作⽤都没有。

假设我们有一个有nin个输入权重的神经元,因此我们可以通过初始化权重和偏置分布为μ(0,1/nin)解决这个问题。

(5)神经网络超参数的选择

(6)其他技术

(1)随机梯度下降的变化形式

主要介绍了以下Hessian技术和momentum技术。

(2)人工神经元的其他模型

双曲正切神经元(tanh),以及修正现行神经元(ReLU)

Network2.py程序较之前程序有了一些改进:

1.代价函数中加入了规范化项,缓解过度拟合
2.权重,偏置初始化进行了优化,服从N(0,1/nin)分布,缓解了隐藏层神经元饱和,加快训练速度

代码如下:

# -*- coding: utf- -*-
"""
Created on Tue Mar :: @author: Administrator
""" '''
书籍:神经网络与深度学习
第三章:改进版的神经网络
与Network.py文件中有如下改进
.代价函数中加入了规范化项,缓解过度拟合
.权重,偏置初始化进行了优化,服从N(,/nin)分布,缓解了隐藏层神经元饱和,加快训练速度
''' import numpy as np
import json
import random import sys '''
定义二次代价函数和交叉熵代价函数的类
'''
class QuadraticCost(object):
#定义静态方法
@staticmethod
def fn(a,y):
'''
计算一个样本的二次代价函数 C0 = 0.5∑j(yj - aj)^
a:神经网络输出层值
y:目标值
'''
return 0.5*np.linalg.norm(a-y)** @staticmethod
def delta(z,a,y):
'''
计算输出层误差δL
z:输出层带权输入
a:神经网络输出层值
y:目标值
'''
return (a-y)*sigmod_prime(z) class CrossEntropyCost(object):
#定义静态方法
@staticmethod
def fn(a,y):
'''
计算一个样本的交叉熵代价函数 C0 = -∑j[yjln(ajL) + (-yj)ln( - ajL)]
a:神经网络输出层值
y:目标值
'''
#np.nan_to_num:Replace nan with zero and inf with finite numbers.
#把np.nan(非常小的数字,接近0)用0取代
#np.inf,或者-np.inf(正负无穷大的数字)用有限数替代
return np.sum(-*np.nan_to_num( y*np.log(a) + ( - y)*np.log( - a))) @staticmethod
def delta(z,a,y):
'''
计算输出层误差δL
z:输出层带权输入
a:神经网络输出层值
y:目标值
'''
return (a-y) '''
定义神经网络的类
'''
class Network(object):
def __init__(self,sizes,cost = CrossEntropyCost):
'''
sizes:list类型 每个元素对应神经网络中每一层的神经元个数
cost:CrossEntropyCost或者QuadraticCost 指定代价函数 默认采用交叉熵代价函数
'''
self.num_layers = len(sizes)
self.sizes = sizes
self.default_weight_initializer()
self.cost = cost def default_weight_initializer(self):
'''
默认权重初始化函数,改进之后的,w,b服从N(,/nin)正态分布
'''
self.biases = [np.random.randn(y,) for y in self.sizes[:]]
self.weights = [np.random.randn(y,x)/np.sqrt(x) for x,y in zip(self.sizes[:-],self.sizes[:])] def large_weight_initializer(self):
'''
权重初始化函数,w,b服从N(,)正态分布
weights:权重,随机初始化,服从(,)高斯分布 weights[i]:是一个连接着第i层和第i+1层神经元权重的numpy矩阵 i=,...
biases:偏置,随机初始化,服从(,)高斯分布 biases[i]:是第i+1层神经元偏置向量 i=,....
'''
self.biases = [np.random.randn(y,) for y in self.sizes[:]]
self.weights = [np.random.randn(y,x) for x,y in zip(self.sizes[:-],self.sizes[:])] def feedforward(self,a):
'''
前向反馈函数,对于网络给定一个输入向量a,返回对应的输出
a:神经网络的输入
'''
for b,w in zip(self.biases,self.weights):
#dot矩阵乘法 元素乘法使用*
a = sigmod(np.dot(w,a) + b)
return a def SGD(self,training_data,epochs,mini_batch_size,eta,lamda,evaluation_data=None,
monitor_evaluation_cost = False,
monitor_evaluation_accuracy = False,
monitor_training_cost = False,
monitor_training_accuracy = False):
'''
随机梯度下降算法:使用小批量训练样本来计算梯度(计算随机选取的小批量数据的梯度来估计整体的梯度)
training_data:元素为(x,y)元组的列表 (x,y):表示训练输入以及对应的输出类别 这里的输出类别是二值化后的10*1维向量
epochs:迭代期数量 即迭代次数
mini_batch:小批量数据的大小
eta:学习率
lamda:规范化lamda参数
evaluation_data:评估数据集 validation_data或者test_data
monitor_evaluation_cost:标志位 打印每次迭代评估数据集的代价
monitor_evaluation_accuracy:标志位 打印每次迭代评估数据集的预测准确的个数
monitor_training_cost 打印每次迭代训练数据集的代价
monitor_training_accuracy 打印每次迭代训练数据集的预测准确的个数
'''
if evaluation_data:
#计算评估集样本个数
n_data = len(evaluation_data)
#计算训练集样本个数
n = len(training_data)
evaluation_cost = []
evaluation_accuracy = []
training_cost = []
training_accuracy = []
#进行迭代
for j in range(epochs):
#将训练集数据打乱,然后将它分成多个适当大小的小批量数据
random.shuffle(training_data)
mini_batches = [training_data[k:k+mini_batch_size] for k in range(,n,mini_batch_size)]
#训练神经网络
for mini_batch in mini_batches:
self.update_mini_batch(mini_batch,eta,lamda,n) print('Epoch {0} training complete'.format(j)) #每一次迭代后 输出相应的测试信息,预测准确个数和代价
if monitor_evaluation_cost:
cost = self.total_cost(evaluation_data,lamda,convert=True)
evaluation_cost.append(cost)
print('Cost on evaluation data:{0}'.format(cost)) if monitor_evaluation_accuracy:
accuracy = self.accuracy(evaluation_data)
evaluation_accuracy.append(accuracy)
print('Accuracy on evaluation data:{0}/{1}'.format(accuracy,n_data)) if monitor_training_cost:
cost = self.total_cost(training_data,lamda)
training_cost.append(cost)
print('Cost on training data:{0}'.format(cost)) if monitor_training_accuracy:
accuracy = self.accuracy(training_data,convert=True)
training_accuracy.append(accuracy)
print('Accuracy on training data:{0}/{1}'.format(accuracy,n)) #返回的均为list 包含每次迭代后对应的代价值或者预测准确个数
return evaluation_cost,evaluation_accuracy,training_cost,training_accuracy def update_mini_batch(self,mini_batch,eta,lamda,n):
'''
mini_batch:小批量数据 元素为(x,y)元组的列表 (x,y)
eta:学习率
lamda:规范化lamda参数
n:训练集数据总长度
对每一个mini_batch应用梯度下降,更新权重和偏置
'''
#初始化为0
nabla_b = [np.zeros(b.shape) for b in self.biases]
nabla_w = [np.zeros(w.shape) for w in self.weights]
#依次对每一个样本求梯度,并求和
for x,y in mini_batch:
#计算每一个样本代价函数的梯度
delta_nabla_b,delta_nabla_w = self.backprop(x,y)
#梯度分量求和 Σ∂Cx/∂ω
nabla_b = [nb + dnb for nb,dnb in zip(nabla_b,delta_nabla_b)]
#梯度分量求和 Σ∂Cx/∂b
nabla_w = [nw + dnw for nw,dnw in zip(nabla_w,delta_nabla_w)]
#更新权重 w = w - η/m*Σ∂Cx/∂ω
self.weights = [( - eta*lamda/n)*w - (eta/len(mini_batch))*nw for w,nw in zip(self.weights,nabla_w)]
#更新偏置 b = b - η/m*Σ∂Cx/∂b
self.biases = [b - (eta/len(mini_batch))*nb for b,nb in zip(self.biases,nabla_b)] def backprop(self,x,y):
'''
计算给定一个样本代价函数的梯度 单独训练样本x的二次代价函数
返回一个元组(nabla_b,nabla_w) = (∂Cx/∂ω,∂Cx/∂b) :和权重weights,偏置biases维数相同的numpy数组
'''
#初始化与self.baises,self.weights维数一样的两个数组 用于存放每个训练样本偏导数的累积和
nabla_b = [np.zeros(b.shape) for b in self.biases]
nabla_w = [np.zeros(w.shape) for w in self.weights]
#前向反馈
activation = x
#保存除了输入层外所有层的σ(z)的值
activations = [x]
#保存除了输入层外所有层的z的值
zs = []
#计算除了输入层外每一层z和σ(z)的值
for b,w in zip(self.biases,self.weights):
z = np.dot(w,activation) + b
zs.append(z)
activation = sigmod(z)
activations.append(activation) #反向传播 计算输出层误差δL,以及∂Cx/∂bL,∂Cx/∂ωL
delta = self.cost.delta(zs[-],activations[-],y)
nabla_b[-] = delta
nabla_w[-] = np.dot(delta,activations[-].transpose()) #计算隐藏层误差δl,以及 ∂Cx/∂bl,∂Cx/∂ωl
     for l in range(,self.num_layers):
z = zs[-l]
sp = sigmod_prime(z)
delta = np.dot(self.weights[-l+].transpose(),delta)*sp
nabla_b[-l] = delta
nabla_w[-l] = np.dot(delta,activations[-l-].transpose())
return (nabla_b,nabla_w) def accuracy(self,data,convert=False):
'''
返回用神经网络预测data数据集中样本输出正确的个数
data:数据集[(x,y),...]
convert:判断data中每个样本的输出是否是二值化后的向量?如果是True,否则False 这个与data数据格式有关
'''
if convert:
results = [(np.argmax(self.feedforward(x)),np.argmax(y)) for x,y in data]
else:
results = [(np.argmax(self.feedforward(x)),y) for x,y in data]
return sum(int(x==y) for x,y in results) def total_cost(self,data,lamda,convert=False):
'''
返回用神经网络预测data数据集后的代价值
data:数据集[(x,y),...]
lamda:规范化lamda参数
convert:判断data中每个样本的输出是否是二值化后的向量?如果是False,否则True 这个与data数据格式有关
'''
cost = 0.0
for x,y in data:
if convert:
#二值化
y = vectorized_result(y)
cost += self.cost.fn(self.feedforward(x),y)
cost /= len(data)
#加入规范化项
cost += 0.5*lamda/len(data)*sum(np.linalg.norm(w)** for w in self.weights)
return cost def save(self,filename):
'''
把神经网络的参数序列化后写到指定文件中
'''
data = {'sizes':self.sizes,
'weights':self.weights,
'biased':self.biases,
'cost':str(self.cost.__name__)
}
with open(filename,'w') as f:
#写入序列化后的值
json.dump(data,f) def load(filename):
'''
从文件中读取字符串并反序列化,创建一个神经网络类对象,并恢复权重,偏置参数
'''
with open(filename,'r') as f:
data = json.load(f)
#从当前模块中找到名称data['cost']的对象,并赋值给cost
cost = getattr(sys.modules[__name__],data['cost'])
#创建神经网络
net = Network(data['sizes'],cost=cost)
#初始化权重和偏置
net.weights = data['weights']
net.biases = data['biases']
return net def vectorized_result(j):
"""
- 二值化为 *
Return a -dimensional unit vector with a 1.0 in the jth
position and zeroes elsewhere. This is used to convert a digit
(...) into a corresponding desired output from the neural
network.
"""
e = np.zeros((, ))
e[j] = 1.0
return e def sigmod(z):
'''
定义S型函数
当输入z是一个list,tuple或者numpy数组时,numpy自动地按元素应用sigmod函数,即以向量形式
z:list,tuple或者numpy数组
'''
return 1.0/(1.0+np.exp(-z)) def sigmod_prime(z):
'''
定义S型函数的导数
'''
return sigmod(z)*(-sigmod(z)) def  network2_baseline():
    #traning_data:[(784*1,10*1),...],50000个元素
    #validation_data[(784*1,1*1),....],10000个元素
    #test_data[(784*1,1*1),....],10000个元素
    training_data,validation_data,test_data = mnist_loader.load_data_wrapper()
    print('训练集数据长度',len(training_data))
    print(training_data[0][0].shape)      #训练集每一个样本的特征维数   (784,1)
    print(training_data[0][1].shape)      #训练集每一个样本对应的输出维数  (10,1)
    
    print('测试集数据长度',len(test_data))
    print(test_data[0][0].shape)         #测试机每一个样本的特征维数,1,1   (784,1)
    #print(test_data[0][1].shape)         #测试机每一个样本对应的输出维数   () 这里与训练集的输出略有不同,这里输出是一个数 并不是二指化后的10*1维向量
    print(test_data[0][1])               #7
       
    #测试
    net = Network2.Network([784,30,10])
    '''
    print(net.num_layers)      #3
    print(net.sizes)
    print(net.weights)
    print(net.biases)
    '''
    
    net.SGD(training_data,30,10,0.5,lamda=5,evaluation_data=validation_data,
            monitor_evaluation_cost = True,
            monitor_evaluation_accuracy=True,
            monitor_training_cost=True,
            monitor_training_accuracy=True) #开始测试
network2_baseline()

参考文献

[1]深度神经网络(DNN)损失函数和激活函数的选择

[2]深度神经网络(DNN)的正则化

第五节,Neural Networks and Deep Learning 一书小节(中)的更多相关文章

  1. 第四节,Neural Networks and Deep Learning 一书小节(上)

    最近花了半个多月把Mchiael Nielsen所写的Neural Networks and Deep Learning这本书看了一遍,受益匪浅. 该书英文原版地址地址:http://neuralne ...

  2. 第六节,Neural Networks and Deep Learning 一书小节(下)

    4.神经网络可以计算任何函数的可视化证明 神经网络拥有一定的普遍性,即包含一个隐藏层的神经网络可以被用来按照任意给定的精度来近似任何连续函数. 这一章使用一个实例来阐述神经网络是如何来近似一个一元函数 ...

  3. 【DeepLearning学习笔记】Coursera课程《Neural Networks and Deep Learning》——Week2 Neural Networks Basics课堂笔记

    Coursera课程<Neural Networks and Deep Learning> deeplearning.ai Week2 Neural Networks Basics 2.1 ...

  4. 【DeepLearning学习笔记】Coursera课程《Neural Networks and Deep Learning》——Week1 Introduction to deep learning课堂笔记

    Coursera课程<Neural Networks and Deep Learning> deeplearning.ai Week1 Introduction to deep learn ...

  5. Neural Networks and Deep Learning学习笔记ch1 - 神经网络

    近期開始看一些深度学习的资料.想学习一下深度学习的基础知识.找到了一个比較好的tutorial,Neural Networks and Deep Learning,认真看完了之后觉得收获还是非常多的. ...

  6. Neural Networks and Deep Learning

    Neural Networks and Deep Learning This is the first course of the deep learning specialization at Co ...

  7. [C3] Andrew Ng - Neural Networks and Deep Learning

    About this Course If you want to break into cutting-edge AI, this course will help you do so. Deep l ...

  8. 《Neural Networks and Deep Learning》课程笔记

    Lesson 1 Neural Network and Deep Learning 这篇文章其实是 Coursera 上吴恩达老师的深度学习专业课程的第一门课程的课程笔记. 参考了其他人的笔记继续归纳 ...

  9. [C1W1] Neural Networks and Deep Learning - Introduction to Deep Learning

    第一周:深度学习引言(Introduction to Deep Learning) 欢迎(Welcome) 深度学习改变了传统互联网业务,例如如网络搜索和广告.但是深度学习同时也使得许多新产品和企业以 ...

随机推荐

  1. font_awesome的icon库的使用

    1.使用cdn引入font_awesome图标库的css文件 例如:index.htm <html><head><title>font_awesome test&l ...

  2. C-Lodop打印服务没启动怎么办

    C-Lodop作为服务,解决了高版本火狐谷歌不支持np插件问题,支持跳出来浏览器的限制,支持所有浏览器,默认是只需安装一次,以后每次开机自启动,但是如果禁止了开机启动项等问题,会造成之后突然出现没启动 ...

  3. C-Lodop设置页面一加载就打印

    C-Lodop由于是服务不是np插件,调用打印语句(print或preview等)时机太早,在页面第一次加载完成后有几百毫秒时间等待WebSocket通讯服务准备完成,在没完成的时候会提示“C-Lod ...

  4. 为WebRTC 应用部署Turn Server

    部署WebRTC 或 SIP p2p 方案时经常会遇到p2p 无法穿透的环境, 这时就是TunServer 的用武之地了. 这里我们使用turnserver-0.7.3 下载confuse依赖库 wg ...

  5. python绘制图形

      python能快速解决日常工作中的小任务,比如数据展示. python做数据展示,主要用到matplotlib库,使用简单的代码,就可以很方便的绘制折线图.柱状图等.使用Java等,可能还需要配合 ...

  6. 从身份证号码中获取性别、出生日期、籍贯,并更新mongodb

    有这样的需求,人员信息是存在mongodb中,需要存放人员的身份证.性别.出生日期.籍贯等信息.通过脚本导入这些信息,但是只导入了身份证号码,其他信息空缺.现在需要补全其他信息. 其实身份证信息就包含 ...

  7. FTC诉高通垄断案苹果从中受益

    据外媒报道,美国当地时间周二,美国联邦贸易委员会(FTC)诉芯片制造商高通公司(Qualcomm)垄断案进入了终结辩论阶段.这意味着,这起审判也进入最后阶段,它可能颠覆高通在智能手机时代取得成功的至关 ...

  8. POJ 3020 -Antenna Placement-二分图匹配

    题意:一个N*M的矩阵里有K个观测点,你必须放置天线覆盖所有观测点.每个雷达只能天线两个观测点,这两点必须相邻.计算最少天线数. 做法:将所有相邻的观测点连起来,建图.跑一遍匈牙利算法就计算出了最大的 ...

  9. Educational Codeforces Round 61 (Rated for Div. 2)

    A. Regular Bracket Sequence 题意:给出四种括号的数量 ((  )) ()  )( 问是否可以组成合法的序列(只能排序不能插在另外一个的中间) 思路: 条件一:一个或 n个) ...

  10. base64URL处理

    加密 String str="hello world"; String encode= Base64.getUrlEncoder().encodeToString(str.getb ...