菜菜的深度学习笔记 | 基于Python的理论与实现(五)—>神经网络的学习

在这里插入图片描述

系列索引:菜菜的深度学习笔记 | 基于Python的理论与实现

一、神经网络的学习

神经网络的特征就是可以从数据中学习,是指可以由数据自动决定权重参数的值。

(1)数据驱动

数据是机器学习的命根子。

当我们遇到一个问题时往往根据各种因素综合考虑后才给出答案,但机器学习方法极力避免人的介入,尝试从数据中发现答案(模型)

以识别一个数字为例,一种方案是先从图象中提取特征量,再用机器学习技术学习这些特征量的模式,这里的特征量指的是可以从输入数据中准确地提取本质数据的转换器。在CV领域常用的特征量包括SIFT、SURF和HOG等。

机器学习方法中由机器从收集到的数据中找出规律性,虽然能减轻人的负担,但是将图象转换为向量时仍有人的参与(设计专门的特征量),而使用深度学习方法不需要人的参与

神经网络的优点是对所有问题可以用同样的流程来解决,进行端到端的学习,与待处理的问题无关。

(2)训练数据和测试数据

首先,使用训练数据进行学习,寻找最优的参数,然后使用测试数据评价训练得到的模型的实际能力。

为什么要区分数据进行模型评价是因为我们希望得到的模型是具有泛化能力的。泛化能力是指处理未被观察过的数据(不包含在训练数据中的数据)的能力。

仅仅用一个数据集去学习和评价参数,是无法进行正确评价的,这样会导致可以顺利处理某个数据集,但是无法处理其他数据集。只对某个数据集过度拟合的状态称为过拟合

(3)损失函数

神经网络的学习通过某个指标表示现在的状态,然后,以这个指标为基准寻找最优权重参数,所用的指标称为损失函数。损失函数可以使用任意函数,但一般用均方误差和交叉熵等。

均方误差:

E = 1 2 ∑ k ( y k − t k ) 2 E = \frac {1}{2}\sum_k{(y_k-t_k)^2} E=21k(yktk)2
这里y_k表示神经网络的输出,t_k表示监督数据,k表示数据的维数。

如softmax函数的输出结果y=[0.1,0.6,0.05,…],t=[0,1,0,0,…],这里t是监督数据,将正确解标签设为1,其他均为0。这种表示方法为one-hot表示。

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

交叉熵误差:

E = − ∑ k t k l n y k E = -\sum_k{t_klny_k} E=ktklnyk
因为t_k中只有正确解为1其余均为0,因此上式实际上只计算对应正确解标签的输出的自然对数。

def cross_entropy_error(y,t):
	delta = le-7
	return -np.sum(t*np.log(y+delta))

这里使用了一个极小值delta来防止出现log(0)的情况,避免值为-inf,是一个保护性的策略。

mini-batch学习:

机器学习使用训练数据进行学习,具体来说就是针对训练数据来计算损失函数的值,找出使该值尽可能小的参数。如果以交叉熵为例,可以写成下面的式:
E = − 1 N ∑ n ∑ k t n k l n y n k E = -\frac{1}{N}\sum_n\sum_k{t_{nk}lny_{nk}} E=N1nktnklnynk
如果以全部数据为对象计算损失函数的和,则计算过程花费的时间较长,因此我们从全部数据中取出一部分作为全部数据的近似,称为mini-batch,即小批量。然后,对每个mini-batch进行学习,这种学习方式称为mini-batch学习

import numpy as np
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=True,one_hot_label=True)
print(x_train.shape)
print(t_train.shape)


train_size = x_train.shape[0]
batch_size = 10
batch_mask = np.rnadom.choice(train_size,batch_size)
x_batch = x_train[batch_mask]
t_batch = t_train[batch_mask]

mini-batch版交叉熵误差的实现:

def cross_entropy_error(y,t):
    if y.ndim == 1:
        t = t.reshape(1,t.size)
        y = y.reshape(1,y.size)
        
    batch_size = y.shape[0]
    
    return -np.sum(t*np.log(y+le-7))/batch_szie #one-hot形式
    return -np.sum(np.log(y[np.arange(batch_size),t]+le-7))/batch_size #当监督数据为标签形式,如"1","5"

这里y是神经网络的输出,t是监督数据。当y的维度为1时,即求单个数据的交叉熵误差时需要改变数据的形状。

在进行神经网络的学习时,不能将识别精度作为指标。因为如果以识别精度为指标,则参数的导数在绝大多数地方都会变为0。这句话的意思是,假设100个数字识别成功32个,则识别精度32%,如果改变参数则识别精度可能变为33%,35%。这些数据是离散的,不连续的。而如果把损失函数作为指标,则当前的损失函数值可以连续性变化。

以阶跃函数为例,阶跃函数作为激活函数时神经网络无法正常进行,因为他只在某个瞬间变化,其导数除了在原点处不为0,其他地方均为0,没有意义。而sigmoid函数则在任何地方导数均不为0,且连续变化。

(4)数值微分

导数和偏导的概念不再赘述,这里我们使用由全部向量的偏导数汇总而成的向量称为梯度

import numpy as np
import matplotlib.pylab as plt
from mpl_toolkits.mplot3d import Axes3D


def _numerical_gradient_no_batch(f, x):
    h = 1e-4 # 0.0001
    grad = np.zeros_like(x)
    
    for idx in range(x.size):
        tmp_val = x[idx]
        x[idx] = float(tmp_val) + h
        fxh1 = f(x) # f(x+h)
        
        x[idx] = tmp_val - h 
        fxh2 = f(x) # f(x-h)
        grad[idx] = (fxh1 - fxh2) / (2*h)
        
        x[idx] = tmp_val # 还原值
        
    return grad


def numerical_gradient(f, X):
    if X.ndim == 1:
        return _numerical_gradient_no_batch(f, X)
    else:
        grad = np.zeros_like(X)
        
        for idx, x in enumerate(X):
            grad[idx] = _numerical_gradient_no_batch(f, x)
        
        return grad


def function_2(x):
    if x.ndim == 1:
        return np.sum(x**2)
    else:
        return np.sum(x**2, axis=1)


def tangent_line(f, x):
    d = numerical_gradient(f, x)
    print(d)
    y = f(x) - d*x
    return lambda t: d*t + y
     
if __name__ == '__main__':
    x0 = np.arange(-2, 2.5, 0.25)
    x1 = np.arange(-2, 2.5, 0.25)
    X, Y = np.meshgrid(x0, x1)
    
    X = X.flatten()
    Y = Y.flatten()
    
    grad = numerical_gradient(function_2, np.array([X, Y]) )
    
    plt.figure()
    plt.quiver(X, Y, -grad[0], -grad[1],  angles="xy",color="#666666")#,headwidth=10,scale=40,color="#444444")
    plt.xlim([-2, 2])
    plt.ylim([-2, 2])
    plt.xlabel('x0')
    plt.ylabel('x1')
    plt.grid()
    plt.legend()
    plt.draw()
    plt.show()

和机器学习类似,神经网络在学习时也要找到最优参数(权重和偏置),这里是指使损失函数值最小的参数。一般而言,损失函数很复杂参数庞大,我们可以通过巧妙地使用梯度来寻找函数的最小值,即梯度法

梯度表示的是各点处的函数值减小最多的方向,无法保证梯度所指的方向就是函数的最小值或者真正应该前进的方向。实际上,梯度指示的方向基本上都不是函数值最小处。

在梯度法中,函数的取值从当前位置沿着梯度方向前进一定距离,然后在新的地方重新求梯度,再沿着新梯度方向前进,如此重复,不断地沿梯度方向前进。寻找最小值的梯度法称为梯度下降法,寻找最大值的梯度法称为梯度上升法

我们用数学公式表示梯度法:
x 0 = x 0 − η δ f δ x 0 x 1 = x 1 − η δ f δ x 1 x_0=x_0-\eta\frac{\delta f}{\delta x_0} \\ x_1=x_1-\eta\frac{\delta f}{\delta x_1} x0=x0ηδx0δfx1=x1ηδx1δf
其中\delata表示学习率,学习率决定在一次学习中应该学习多少,以及多大程度上更新参数。

上式表示更新一次的式子,这个步骤会反复执行,逐渐减小函数值。学习率需要事先确定为一个值,一般而言,这个值过大或过小都无法抵达一个好的位置,在神经网络的学习中,一般会一边改变学习率的值,一边确认学习是否正确进行了。

像学习率这样的参数称为超参数,这和神经网络的参数性质不同,相当于神经网络的权重参数是通过训练数据和学习算法得到的,学习率这样的超参数则是人工设定的。

(5)神经网络的梯度

神经网络的像学习也要求梯度,这里的梯度是指损失函数关于权重参数的梯度。

未完待续...

基于Python的理论与实现 系列持续更新,欢迎点赞收藏关注

上一篇:菜菜的深度学习笔记 | 基于Python的理论与实现(四)
下一篇:菜菜的深度学习笔记 | 基于Python的理论与实现(六)—>简单两层网络的实现

本人水平有限,文章中不足之处欢迎下方👇评论区批评指正~

如果感觉对你有帮助,点个赞👍 支持一下吧 ~

不定期分享 有趣、有料、有营养内容,欢迎 订阅关注 🤝 我的博客 ,期待在这与你相遇 ~

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

猿知

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值