首页 > 其他分享 >【深度学习】神经网络的学习

【深度学习】神经网络的学习

时间:2024-02-27 10:57:30浏览次数:29  
标签:loss partial self step 学习 神经网络 params 深度

目录

源代码文件请点击此处

常用损失函数

均方误差函数(mean squared error)

\[E(\vec{y},\vec{t}) = \frac{1}{2m} \sum_{i=1}^{m} (y_i - t_i)^2 \]

其中 \(y_i\) 为计算得出的概率,\(t_i\) 为以 one-hot 表示的监督数据(正确解标签)。

代码实现如下:

# 均方误差函数
# 监督数据 t 为 one-hot 表示
def mean_squared_error(y, t):
  m = y.shape[1]
  cost_sum = np.sum((y-t) ** 2)
  return cost_sum / (2 * m)

交叉熵误差函数(cross entropy error)/对数损失函数(log loss function)

\[E(\vec{y},\vec{t}) = - \sum_{i=1}^{m} t_i \ln y_i \]

其中 \(y_i\) 为计算得出的概率,\(t_i\) 为以 one-hot 表示的监督数据(正确解标签)。

代码实现如下:

# 对数损失函数
# 监督数据 t 为 one-hot 表示
def log_loss_function(y, t):
  delta = 1e-7  # 此处是防止出现 ln0 的情况
  return -np.sum(t * np.log(y + delta))

数值微分(numerical gradient)

神经网络的学习依赖于梯度下降算法,因此我们首先介绍一种计算梯度的方法——数值微分法。使用数值微分计算梯度值的速度比较慢,但实现起来简单。与之相对应的是通过公式运算的解析式求解梯度(解析性求导,analytic gradient),该方法运算起来快速,但实现起来较复杂。

计算数值微分的方法有三种:

前向差分(forward difference)

这是我们最熟悉的形式:

\[\frac{\mathrm{d} f(x)}{\mathrm{d} x} = \lim_{h \rightarrow 0} \frac{f(x+h) - f(x)}{h} \]

后向差分(backward difference)

这是另外一种形式,也很常见:

\[\frac{\mathrm{d} f(x)}{\mathrm{d} x} = \lim_{h \rightarrow 0} \frac{f(x) - f(x-h)}{h} \]

中心差分(central difference)

实际情况下,我们不会使用前向差分和后向差分,这是因为这两种方法计算出来的误差值较大,因此采用改进后的中心差分,如下式:

\[\frac{\mathrm{d} f(x)}{\mathrm{d} x} = \lim_{h \rightarrow 0} \frac{f(x+h) - f(x-h)}{2h} \]

代码实现如下:

# 数值微分(中心差分方法)
# f 为以上损失函数二选一
def _numerical_gradient(f, x):
    h = 1e-4 # 0.0001
    grad = np.zeros_like(x)

    for i in range(x.size):
        tmp = x[i]

        # 计算 f(x+h)
        x[i] = float(tmp) + h
        fxh1 = f(x)

        # 计算 f(x-h)
        x[i] = float(tmp) - h
        fxh2 = f(x)

        # 计算中心差分
        grad[i] = (fxh1 - fxh2) / (2 * h)
        x[i] = tmp
        #print(grad)

    return grad

基于梯度下降算法的神经网络学习过程

神经网络的学习实现起来并不复杂,现在以一个 2 层神经网络为例,来看看具体的学习过程。

step 1. 初始化神经网络参数

初始化一个有 2 层(输入层+隐藏层+输出层)的神经网络的代码如下所示。注意,权重的初始值不可设置为 0(或者说不可设置为同样的数字),这是为了防止“权重均一化”问题。因此,必须随机生成初始值。我们可以使用较小的初始值,例如使用标准差为 0.01 的高斯分布作为权重初始值。关于初始值的设定问题以后再来讨论。

def __init__(self, input_size, hidden_size, output_size, weight_init_std=0.01):
  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)

step 2. 神经网络的学习

这里分三步走:推理、梯度下降、识别精度。

step 2-1. 进行推理(前向传播)

初始化参数后,先用这些参数进行推理(即神经网络的前向传播):

def predict(self, X):
  W1, W2 = self.params['W1'], self.params['W2']
  B1, B2 = self.params['B1'], self.params['B2']
  A1 = self.dense(X, W1, B1, sigmoid_function) # layer 1
  A2 = self.dense(A1, W2, B2, softmax_function_trick) # layer 2
  return A2

step 2-2. 使用数值微分方法进行梯度下降

推理完毕后得到结果 y,然后对损失函数 loss(y, t) 计算关于权重的梯度值。这里所做的操作是:假设损失函数为 \(L(y,t)\),权重矩阵为:

\[W = \bigg[ \begin{matrix} w_{11} \ w_{12} \ w_{13} \\ w_{21} \ w_{22} \ w_{23} \\ \end{matrix} \bigg] \]

则计算梯度值后得到的梯度矩阵为:

\[\frac{\partial L}{\partial W} = \bigg[ \begin{matrix} \frac{\partial L}{\partial w_{11}} \ \frac{\partial L}{\partial w_{12}} \ \frac{\partial L}{\partial w_{13}} \\ \frac{\partial L}{\partial w_{21}} \ \frac{\partial L}{\partial w_{22}} \ \frac{\partial L}{\partial w_{23}} \\ \end{matrix} \bigg] \]

实现代码如下:

# 计算损失/误差值(回调函数)
# loss_f 为损失函数
def loss(self, loss_f, X, t):
  y = self.predict(X)  # 先进行推理
  return loss_f(y, t)  # 后用推理结果与正确解标签计算损失值

def numerical_gradient_descent(self, loss_f, X, t):
  # 定义匿名函数,参数为 W,返回值为 loss_f(y, t)
  loss_W = lambda W: self.loss(loss_f, 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

计算各个参数的梯度值后,更新各个参数:

for key in ('W1', 'B1', 'W2', 'B2'):
  self.params[key] -= learning_rate * self.grads[key]

step 2-3. 计算识别精度和损失值

首先,计算识别精度的代码实现如下:

# 神经网络参数的精度评价
def accuracy(self, X, t, num):
  y = self.predict(X) # 再次进行推理
  print(y)
  y = np.argmax(y, axis=1)
  t = np.argmax(t, axis=1)
  accuracy = np.sum(y == t) / float(num)
  return accuracy

每轮梯度下降完成后,计算识别精度和损失值:

# 识别精度
accuracy = self.accuracy(X, t, X.shape[0])
print(f"epoch {epoch}: train accuracy = {accuracy}")

# 计算损失值
loss = self.loss(loss_f, X, t)
self.loss_history.append(loss)

随后,重复执行 step 2-1 至 2-3,继续迭代更新各个参数值,直到精度达到要求或达到迭代次数为止,然后进行 step 3。

step 3. 学习完毕,使用神经网络进行预测

使用已学习完毕的神经网络(即调用函数 predict(X))对测试集进行推理,此处就不再赘述了。

基于数值微分实现的梯度下降算法虽然容易实现,但运算速度非常慢。下一篇将介绍一种更为快速的方法——误差反向传播法。

标签:loss,partial,self,step,学习,神经网络,params,深度
From: https://www.cnblogs.com/Mount256/p/18036412

相关文章

  • 机器学习策略篇:详解单一数字评估指标(Single number evaluation metric)
    单一数字评估指标无论是调整超参数,或者是尝试不同的学习算法,或者在搭建机器学习系统时尝试不同手段,会发现,如果有一个单实数评估指标,进展会快得多,它可以快速告诉,新尝试的手段比之前的手段好还是差。所以当团队开始进行机器学习项目时,经常推荐他们为问题设置一个单实数评估指标。......
  • 模拟退火学习笔记
    Whatis%你退火说到%你退火我就会想到一个人,那就是\(S.Kirkpatrick,C.D.Gelatt\)和\(M.P.Vecchi\)。(wy2024届传奇oi/数学大师,@yanxu_cn)模拟退火是一种基于物理冶金学中固体物质退火过程的启发式优化算法。它是一种全局优化算法,通常用于求解复杂的组合优化问题。该算法的灵感......
  • 基础数论学习笔记
    1.辗转相减利用辗转相减法求最大公约数,即\(gcd(a,b)\)。假设\(a>b\),则gcd(a,b)=gcd(a−b,b),不断的利用大的数减去小的数,就能得到最大公约数。1.证:若\(n,m(n>m)\)互质,则$(n-m),m$互质若不互质,则设\(n-m=k*a,m=k*b\)\(\thereforen-k*b=k*a......
  • 单调队列学习笔记
    WhatIsMonotonicQueue单调队列是一种特殊的队列数据结构,用于维护一定的单调性,通常是单调递增或单调递减。单调队列的主要特点是,队列中的元素满足特定的单调性要求,使得队列的头部元素(或者尾部元素,取决于具体问题)始终是当前队列中的最大(或最小)值。这种特性使得单调队列可以高效......
  • 前中后缀表达式学习笔记
    前言表达式是数学和计算机编程中常见的概念,用于表示运算和计算过程。前缀、中缀和后缀表达式都是不同的方式来表示数学表达式,它们在计算机科学和计算器设计中都有一定的应用。中缀表达式(InfixExpression):这是最常见的数学表达式表示方法,也是人们通常在书写数学公式时使用的方式......
  • Python 机器学习 决策树 数值型特征的处理
    ​ Python机器学习中,特征提取是将原始数据转换为能够被模型有效利用的格式的过程。对于决策树模型而言,特征提取尤其重要,因为好的特征可以显著提升模型的预测性能。在实际应用中,需要根据具体情况选择合适的特征提取方法。数值型特征是机器学习中常见的一种特征类型,它指的是可以......
  • Linux学习-day4
    1.简述操作系统是什么?操作系统就是人与计算机之前交互的介质,有了操作系统,人才能使用计算机;同时,操作系统也是应用程序运行以及用户操作必备的基础环境支撑,是计算机系统的核心。有什么作用?管理和控制计算机系统中的硬件和软件资源,例如,它负责直接管理计算机系统的各种......
  • 寒假学习25
    Scala数组Scala语言中提供的数组是用来存储固定大小的同类型元素,数组对于每一门编程语言来说都是重要的数据结构之一。声明数组变量并不是声明number0、number1、...、number99一个个单独的变量,而是声明一个就像numbers这样的变量,然后使用numbers[0]、numbers[1]、...、n......
  • Vue3学习(十九) - TreeSelect 树选择
    写在前面我知道自己现在的状态很不好,以为放个假能好好放松下心情,结果昨晚做梦还在工作,调试代码,和领导汇报工作。天呐,明明是在放假,可大脑还在考虑工作的事,我的天那,这是怎么了?Vue页面参数传递1、任务拆解页面跳转时带上当前电子书id参数ebookId新增/编辑文档时,读取电子书id......
  • 寒假学习23
    Scala异常处理Scala的异常处理和其它语言比如Java类似。Scala的方法可以通过抛出异常的方法的方式来终止相关代码的运行,不必通过返回值。抛出异常Scala抛出异常的方法和Java一样,使用throw方法,例如,抛出一个新的参数异常:thrownewIllegalArgumentException捕获异......