深度学习(四):神经网络的学习

这里所说的“学习”是指从训练数据中自动获取最优权重参数的过程。

神经网络的学习可以结合机器学习,如导入损失函数这一指标,学习的目的就是找到使损失函数的值最小使的权重参数

一,数据

通常要解决某个问题,特别是需要发现某种模式时,人们一般会综合考 虑各种因素后再给出回答。而机器学习的方法则极力避免人为介入,尝试从收集到的数据中发现答案,神经网络或深度学习更加避免人为介入。

譬如,要识别一个手写数是不是数字5


人,可以通过自己来识别处5
机器学习,可以考虑通过提取特征量,再将特征量转换为向量,然后通过机器学习算法来进行学习。需要使用合适的特征量;
而,神经网络,特征量也是由机器来学习的

二,损失函数

正如机器学习中的定义一样,神经网络中的损失函数也是用来描述当前模型预测和实际结果的差别

2.1 均方误差

可以做损失函数的函数有很多,最有名的是均方误差

y_k是神经网络的输出,t_k表示监督数据,k表示数据的维数

用python来实现为:

def mean_squared_error(y, t): 
    return 0.5 * np.sum((y-t)**2)

2.2 交叉熵误差

还有交叉熵误差

可以看出,此式只计算对应正确解标签的输出的自然对数。正确解标签对应的输出越大,值越接近0,也就是误差越小

用代码来实现

def cross_entropy_error(y, t): 
    delta = 1e-7 
    return -np.sum(t * np.log(y + delta)) #防止log0

上面两式子都是针对单个样本的误差,但是在训练中,应该是针对所有的数据,这时可以把所有误差求和再除以样本数,如:


2.3 mini-batch学习

数据集中数据一般都会有非常多,假如要全部处理,会耗费相当长时间,这时可以从全部数据中选出一部分,作为全部数据的“近似”,称为mini-batch,使用mini-batch来学习的方式,叫作mini-batch学习。

在实操中怎么进行设定呢,代码如下

##导入数据
import sys, os 
sys.path.append(os.pardir)

from dataset.mnist import load_mnist 

(x_train, t_train), (x_test, t_test) = load_mnist(normalize=False, one_hot_label=True) 

##设置随机抽取
train_size = x_train.shape[0] ##训练集的样本个数
batch_size = 10 ##抽取数目

batch_mask = np.random.choice(train_size, batch_size)  #随机生成0到样本个数之间的batch_size个数

#随机生成数为切片索引号生出mini-batch
x_batch = x_train[batch_mask] 
t_batch = t_train[batch_mask]

三,数值微分

因为在这本书里面,所有的都是用python自己写的,所以这里需要再过一下相关概念,并给出相关python实现,方便后续调用

3.1 导数

导数就是某个瞬间的变化量,数学上的定义如下:


这个导数的含义就是x的“微小变化”将导致函数f(x)的值在多大程度上发生变化

用代码来实现:

# 定义导数
def numerical_diff(f, x): 
    h = 1e-4 # 0.0001 
    return (f(x+h) - f(x-h)) / (2*h)

使用10^{-4} 是赋予的微小变化量,且可以避免舍入误差;

使用(f(x+h) - f(x-h)) / (2*h)而不是(f(x+h) - f(x)) / h,原因主要是第二种的误差相对于第一种的误差较大

3.2 偏导数

对于有多个未知数的函数中,需要区分对哪一个未知数求导,这种有多个变量的函数中,对某一个变量求导得到的导数称为偏导数

注意求某个变量的偏导,其他变量视为常量即可

四,梯度

有多个变量,当多个变量确定一个具体的点时,在这个点的各个变量的偏导数汇总成一个向量,这个向量称为梯度。如

代码实现如下:

def numerical_gradient(f, x): 
    h = 1e-4 # 0.0001 
    grad = np.zeros_like(x) # 生成和x形状相同的数组 
    
    for idx in range(x.size): 
        tmp_val = x[idx]
        # f(x+h)的计算 
        x[idx] = tmp_val + h 
        fxh1 = f(x) 
        
        # f(x-h)的计算
        x[idx] = tmp_val - h 
        fxh2 = f(x) 
        
        grad[idx] = (fxh1 - fxh2) / (2*h) 
        x[idx] = tmp_val # 还原值 
     return grad

因为梯度指向的是此点函数值减小最多的方向,所以我们可以采取不断沿着梯度的方向来寻找最小值的方法来找到损失函数最小值,这种方法称为梯度下降法

具体的流程就是,函数的取值从当前位置沿着梯 度方向前进一定距离,然后在新的地方重新求梯度,再沿着新梯度方向前进, 如此反复,不断地沿梯度方向前进。

用数学式来表示,如下:

η为学习率,决定更新参数的强度

在神经网络中,学习率这种参数称为超参数,是由人工决定的,过大或者过小都无法得到好的结果

神经网络里面,是要找损失函数的最小值,求的梯度是指权重参数的梯度

五,学习算法的实现

神经网络的学习分为下面4个步骤:

1,从训练数据中随机选出一部分数据,这部分数据称为mini-batch。我们的目标是减小mini-batch的损失函数的值

2,计算梯度:为了减小mini-batch的损失函数的值,需要求出各个权重参数的梯度。梯度表示损失函数的值减小最多的方向。

3,更新参数:将权重参数沿梯度方向进行微小更新。

4,重复1、2、3

因为以上步骤是随机选择的mini batch数据,所以也称为随机梯度下降法,在很多框架里面,也是用SGD来实现。

接下来来用一个2层神经网络为对象,使用MNIST数据集进行学习

为了方便调用,将这个2层神经网络封装成一个类

import sys, os
sys.path.append(os.pardir)  # 为了导入父目录的文件而进行的设定
from common.functions import *
from common.gradient import numerical_gradient


class TwoLayerNet:

    def __init__(self, input_size, hidden_size, output_size, weight_init_std=0.01):
    
        #params保存神经网络的参数
        self.params = {}
        self.params['W1'] = weight_init_std * np.random.randn(input_size, hidden_size)
        self.params['b1'] = np.zeros(hidden_size)
        self.params['W2'] = weight_init_std * np.random.randn(hidden_size, output_size)
        self.params['b2'] = np.zeros(output_size)

    #预测函数
    def predict(self, x):
        W1, W2 = self.params['W1'], self.params['W2']
        b1, b2 = self.params['b1'], self.params['b2']
    
        a1 = np.dot(x, W1) + b1
        z1 = sigmoid(a1)
        a2 = np.dot(z1, W2) + b2
        y = softmax(a2)
        
        return y
        
    # 计算损失函数的值,x:输入数据, t:监督数据
    def loss(self, x, t):
        y = self.predict(x)
        
        return cross_entropy_error(y, t)
        
    # 计算识别精度
    def accuracy(self, x, t):
        y = self.predict(x)
        y = np.argmax(y, axis=1)
        t = np.argmax(t, axis=1)
        
        accuracy = np.sum(y == t) / float(x.shape[0])
        return accuracy
        
    # 计算权重参数的梯度,x:输入数据, t:监督数据
    def numerical_gradient(self, x, t):
        loss_W = lambda W: self.loss(x, t)
        
        grads = {}
        grads['W1'] = numerical_gradient(loss_W, self.params['W1'])
        grads['b1'] = numerical_gradient(loss_W, self.params['b1'])
        grads['W2'] = numerical_gradient(loss_W, self.params['W2'])
        grads['b2'] = numerical_gradient(loss_W, self.params['b2'])
        
        return grads
        
    

将其封装好后,在进行使用,并且以mini-batch为对象,使用梯度法更新参数

import numpy as np 
from dataset.mnist import load_mnist 
from two_layer_net import TwoLayerNet 

(x_train, t_train), (x_test, t_test) = \ load_mnist(normalize=True, one_hot_ laobel = True)

train_loss_list = [] 

# 超参数 
iters_num = 10000 
train_size = x_train.shape[0] 
batch_size = 100 
learning_rate = 0.1

network = TwoLayerNet(input_size=784, hidden_size=50, output_size=10)

for i in range(iters_num):
    # 获取mini-batch 
    batch_mask = np.random.choice(train_size, batch_size) 
    x_batch = x_train[batch_mask] 
    t_batch = t_train[batch_mask] 
    
    # 计算梯度 
    grad = network.numerical_gradient(x_batch, t_batch) 
    # grad = network.gradient(x_batch, t_batch) # 高速版! 
    
    # 更新参数 
    for key in ('W1', 'b1', 'W2', 'b2'): 
        network.params[key] -= learning_rate * grad[key] 
        
    # 记录学习过程 
    loss = network.loss(x_batch, t_batch) 
    train_loss_list.append(loss)

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

推荐阅读更多精彩内容