【深度学习】(三)神经网络中的学习:损失函数、梯度下降

相关前驱文章:【机器学习】(六)线性模型:线性回归

“学习”指从训练数据中自动获取最优权重参数的过程,即调整权重和偏置以便拟合训练数据的过程。
机器学习的主要任务是在学习是寻找最优参数。神经网络也必须寻找最优参数(权重和偏置)。
最优参数指损失函数取最小值时的参数。

步骤
1.从训练数据中随机选取一部分数据(mini-batch)
2.为了减小mini_batch的损失函数的值,需要求出各个权重参数的梯度。
3.将权重参数沿着梯度方向进行微小更新
4.重复1-3

损失函数

损失函数是衡量神经网络性能的“恶劣程度”的指标。即有神经网络对监督数据在多大程度上不拟合。
返回值越小越好,证明越拟合。

识别精度(34%)是不连续的、离散的值。
损失函数(0.93432…)会发生连续的变化。作为指标更有优势。

针对单个数据的损失函数

均方误差

import numpy as np

# 均方误差
def mean_squared_error(y, t): # 参数为NumPy数组
    return 0.5 * np.sum((y-t)**2) # 输出和各个元素之差的平方

y = [0.1, 0.05, 0.6, 0.0, 0.05, 0.1, 0.0, 0.1, 0.0, 0.0]
t = [0, 0, 1, 0, 0, 0, 0, 0, 0, 0]

print(mean_squared_error(np.array(y), np.array(t))) # 0.09750000000000003

交叉熵误差

# 交叉熵误差
def cross_entropy_error(y, t):
    delta = 1e-7 # 设置一个微小值,防止对数的真数为0
    return -np.sum(t * np.log(y + delta))

mini-batch学习

神经网络的学习可以从训练数据中选出一批数据(mini-batch,小批量),然后对每个mini_batch进行学习。类似,抽样检测。

随机抽取

# 从指定数字中随机选取想要个数。返回一个包含被选数据的索引的数组
batch_mask = np.random.choice(60000, 10)
x_batch = x_train[batch_mask]
t_train = t_train[batch_mask]

mini_batch版交叉熵误差的实现

可以同时处理单个数据和批量数据(数据作为batch集中输入)。

监督数据t是one-hot表示

# one-hot形式的mini-batch交叉熵。t = [0, 0, 1, 0, 0, 0, 0, 0, 0, 0]
def cross_entropy_error(y, t):
    if y.ndim == 1: # 输入维度为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 + 1e-7)) / batch_size

监督数据是标签形式

# 标签形式的mini-batch交叉熵。t = 2
def cross_entropy_error(y, t):
    if y.ndim == 1: # 输入维度为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[np.arange(batch_size), t] + 1e-7)) / batch_size

若batcg_size=5
处理标签np.arange(batch_size)会生成一个NumPy数组[0, 1, 2, 3, 4]。y[np.arange(batch_size), t]抽出每个数据的正确解标签对应的神经网路输出[y[0,2], y[1,7], y[2,0], y[3,9], y[4,4]]

数值微分/导数

数据微分是利用微小的差分求导数的过程。
舍入误差指省略小数的精细部分的数值。(1e-50 = 0.0)
中心差分:以x为中心,求解它左右两边的差分。f(x+h)-f(x-h)
向前差分:f(x+h)-f(x)。因为h不可能无限接近于0,会产生误差。

导数:

# 导数
def numerical_diff(f, x): # 函数f,和传递给f的参数x
    h = 1e-4 # 0.0001
    return (f(x+h) - f(x-h)) / (2*h)

偏导数:将目标变量之外的变量固定到某些特定的值再定义新的函数,然后对新定义的函数应用求导。

def f(x): # f(x)=x0^2+x1^2
    return np.sum(x**2) # 计算NumPy数组中各个元素的平方,再求和

def f1(x0): # 对x0在x0=3,x1=4处求导
    return x0*x0 + 4.0**2.0

def f1(x1): # 对x1在x0=3,x1=4处求导
    return 3.0**2.0 + x1*x1

梯度

梯度:由全部变量的偏导数汇总而成的向量
梯度指示的方向是各点处的函数值减小最多的方向。
函数极小值、最小值、鞍点(一个方向是极大值另一个方向是极小值)的地方,梯度为0。

import numpy as np

# 梯度
def numerical_gradient(f, x): # 函数f,NumPy数组x
    h = 1e-4 # 0.0001
    grad = np.zeros_like(x) # 生成和x形状相同的数组,元素全是0

    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

梯度法(梯度下降法)

梯度表示的是各点处函数减小的中最多的方向。
通过不断沿梯度方向前进,逐渐减小函数值的过程就是梯度法。
梯度法可以求得函数的极小值,甚至是最小值。
在这里插入图片描述

# 梯度下降法。参数:函数,初始值,学习率(多大程度更新参数),梯度法重复次数
def gradient_dedcent(f, init_x, lr=0.01, step_num=100):
    x = init_x

    for i in range(step_num):
        grad = numerical_gradient(f, x) # 求梯度
        x -= lr * grad

    return x

学习率不能过大(发散)或者过小(更新不够)。
学习率是一种超参数(需要人工设定,尝试多个值)。

神经网络的梯度

神经网络的梯度指损失函数关于权重参数的梯度。

import numpy as np
from h import softmax # 激活函数
from loss_functions import cross_entropy_error_one # one-hot形式的mini-batch交叉熵

# 梯度
def numerical_gradient(f, x):
    h = 1e-4  # 0.0001
    grad = np.zeros_like(x)

    it = np.nditer(x, flags=['multi_index'], op_flags=['readwrite'])
    while not it.finished:
        idx = it.multi_index
        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  # 还原值
        it.iternext()

    return grad

class simpleNet:
    def __init__(self): # 用高斯函数进行初始化。权重为W的神经网络
        self.W = np.random.randn(2,3) # 形状为2*3的权重参数

    def predict(self, x): # 输入*权重
        return np.dot(x, self.W)

    def loss(self, x, t): # 求损失函数值
        z = self.predict(x) # 输出
        y = softmax(z) # 激活
        loss = cross_entropy_error_one(y, t) # 求损失值

        return loss

x = np.array([0.6, 0.9]) # 输入
t = np.array([0, 0, 1]) # 正确解标签

net = simpleNet()
print(net.W) # 初始化权重参数
p = net.predict(x)
print(np.argmax(p)) # 最大值索引

f = lambda w: net.loss(x, t) # 简单函数 参数:返回值
'''
def f(w): # 伪参数
    return net.loss(x, t)
'''

dW = numerical_gradient(f, net.W) # 得到的神经网络梯度
print(dW)

求出神经网络梯度后,就可以根据梯度法,更新权重参数。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值