当前位置: 首页 > news >正文

AI-02a5a2.神经网络的学习

神经网络的学习

损失函数

神经网络以某个指标为线索寻找最优权重参数。神经网络的学习中所用的指标称为损失函数(loss function)这个损失函数可以使用任意函数,但一般用均方误差和交叉熵误差等。

损失函数是表示神经网络性能的“恶劣程度”的指标,即当前的神经网络对监督数据在多大程度上不拟合,在多大程度上不一致。之所以不能用识别精度作为指标,是因为这样一来绝大多数地方的导数都会变为0,导致参数无法更新。

均方误差

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 y_k yk是表示神经网络的输出, t k t_k tk表示监督数据, k k k表示数据的维数。

交叉熵误差

E = − ∑ k t k l n ( y k ) E = -\sum_kt_kln(y_k) E=ktkln(yk)

y k y_k yk是神经网络的输出, t k t_k tk是正确解标签。

梯度

式(4.6), f ( x 0 , x 1 ) = x 0 2 + x 1 2 f(x_0,x_1) = x_0^2 + x_1^2 f(x0,x1)=x02+x12 这个函数的图像如下图所示,
在这里插入图片描述

它的偏导数是 ∂ f ∂ x 0 \frac{\partial f}{\partial x_0} x0f ∂ f ∂ x 1 \frac{\partial f}{\partial x_1} x1f, 梯度就是像 ( ∂ f ∂ x 0 , ∂ f ∂ x 1 ) (\frac{\partial f}{\partial x_0}, \frac{\partial f}{\partial x_1}) (x0f,x1f) 这样的由全部变量的偏导数汇总而成的向量。

梯度法

机器学习的主要任务是在学习时寻找最优参数。同样地,神经网络也必须在学习时找到最优参数(权重和偏置)。这里所说的最优参数是指损失函数取最小值时的参数。但是,一般而言,损失函数很复杂,参数空间庞大,我们不知道它在何处能取得最小值。而通过巧妙地使用梯度来寻找函数最小值(或者尽可能小的值)的方法就是梯度法。

这里需要注意的是,梯度表示的是各点处的函数值减小最多的方向。因此,无法保证梯度所指的方向就是函数的最小值或者真正应该前进的方向。实际上,在复杂的函数中,梯度指示的方向基本上都不是函数值最小处。

根据目的是寻找最小值还是最大值,梯度法的叫法有所不同。严格地讲,寻找最小值的梯度法称为梯度下降法,寻找最大值的梯度法称为梯度上升法。但是通过反转损失函数的符号,求最小值的问题和求最大值的问题会变成相同的问题,因此“下降”还是“上升”的差异本质上并不重要。

梯度法的数学公式,式(4.7), x 0 = x 0 − η ∂ f ∂ x 0 x 1 = x 1 − η ∂ f ∂ x 1 \begin{aligned} x_0&=x_0 - \eta\frac{\partial f}{\partial x_0} \\ x_1&=x_1 - \eta\frac{\partial f}{\partial x_1} \end{aligned} x0x1=x0ηx0f=x1ηx1f
η \eta η 表示更新量,在神经网络叫学习率。学习率决定在一次学习中,应该学习多少,以及在多大程度上更新参数。

学习率需要事先确定为某个值,比如0.01或0.001。一般而言,这个值过大或过小,都无法抵达一个“好的位置”。在神经网络的学习中,一般会一边改变学习率的值,一边确认学习是否正确进行了。

像学习率这样的参数称为超参数。这是一种和神经网络的参数(权重和偏置)性质不同的参数。相对于神经网络的权重参数是通过训练数据和学习算法自动获得的,学习率这样的超参数则是人工设定的。一般来说,超参数需要尝试多个值,以便找到一种可以使学习顺利进行的设定。

神经网络的梯度

神经网络的学习也要求梯度。这里所说的梯度是指损失函数关于权重参数的梯度。比如,有一个只有一个形状为 2 × 3 2 × 3 2×3 的权重 W W W 的神经网络,损失函数用 L L L 表示。此时,梯度可以用 ∂ L ∂ W \frac{\partial L}{\partial W} WL 表示。其中, ∂ L ∂ W \frac{\partial L}{\partial W} WL的形状和 W W W相同。

python 示例

""" 神经网络的推理处理 """import pickle
import numpy as np
from dataset.mnist import load_mnistdef sigmoid(x):return 1 / (1 + np.exp(-x))def softmax(a):c = np.max(a)exp_a = np.exp(a - c)return exp_a / np.sum(exp_a)def get_data():# (训练图像, 训练标签), (测试图像, 测试标签)(x_train, t_train), (x_test, t_test) = load_mnist(normalize=True, flatten=True, one_hot_label=False)return x_test, t_test"""
读入保存在pickle文件sample_weight.pkl中的学习到的权重参数
sample_weight.pkl : 以字典变量的形式保存了权重和偏置参数
"""
def init_network():with open("sample_weight.pkl", 'rb') as f:network = pickle.load(f)return network"""
分类:以NumPy数组的形式输出各个标签对应的概率
比如输出[0.1, 0.3, 0.2, ..., 0.04]的数组,该数组表示“0”的概率为0.1,“1”的概率为0.3,等等。
"""
def predict(network, x):W1, W2, W3 = network['W1'], network['W2'], network['W3']b1, b2, b3 = network['b1'], network['b2'], network['b3']a1 = np.dot(x, W1) + b1z1 = sigmoid(a1)a2 = np.dot(z1, W2) + b2z2 = sigmoid(a2)a3 = np.dot(z2, W3) + b3y = softmax(a3)return y""" 损失函数:均方误差 """
def mean_squared_error(y, t):return 0.5 * np.sum((y-t)**2)"""
损失函数:交叉熵损失函数
- q1:为什么不能用识别精度作为指标?
- a1:在进行神经网络的学习时,不能将识别精度作为指标。因为如果以识别精度为指标,则参数的导数在绝大多数地方都会变为0。
"""
def cross_entropy_error(y, t, one_hot_label=False):if y.ndim == 1:t = t.reshape(1, t.size)y = y.reshape(1, y.size)batch_size = y.shape[0]# 函数内部在计算np.log时,加上了一个微小值delta。# 这是因为,当出现np.log(0)时,np.log(0)会变为负无限大的-inf,这样一来就会导致后续计算无法进行。# 作为保护性对策,添加一个微小值可以防止负无限大的发生。delta = 1e-7if one_hot_label:return -np.sum(t * np.log(y + delta)) / batch_sizeelse:# np.arange(batch_size)会生成一个从0到batch_size-1的数组。# 比如当batch_size为5时,np.arange(batch_size)会生成一个NumPy 数组[0, 1, 2, 3, 4]。# 因为t中标签是以[2, 7, 0, 9, 4]的形式存储的,所以y[np.arange(batch_size),t]能抽出各个数据的正确解标签对应的神经网络的输出#(在这个例子中,y[np.arange(batch_size), t] 会生成 NumPy 数 组 [y[0,2], y[1,7], y[2,0], y[3,9], y[4,4]])。return -np.sum(np.log(y[np.arange(batch_size), t] + delta))"""
数值微分(numerical differentiation): 利用微小的差分求导数的过程;
所谓数值微分就是用数值方法近似求解函数的导数的过程
"""
def numerical_diff(f, x):h = 1e-4 # 0.0001; np.float32(1e-50) = 0.0, 所以用 1e-4return (f(x+h) - f(x-h)) / (2*h)"""
偏导数
数值梯度(numerical gradient): 利用微小的差分求导数的过程
"""
def numerical_gradient(f, x):h = 1e-4 # 0.0001grad = np.zeros_like(x) # 生成和x形状相同的数组for idx in range(x.size):tmp_val = x[idx]# f(x+h)的计算x[idx] = tmp_val + hfxh1 = f(x)# f(x-h)的计算x[idx] = tmp_val - hfxh2 = f(x)grad[idx] = (fxh1 - fxh2) / (2*h)x[idx] = tmp_val # 还原值return grad"""
梯度下降法
参数f是要进行最优化的函数,init_x是初始值,lr是学习率learning rate,step_num是梯度法的重复次数。
numerical_gradient(f,x)会求函数的
梯度,用该梯度乘以学习率得到的值进行更新操作,由step_num指定重复的次数。
"""
def gradient_descent(f, init_x, lr=0.01, step_num=100):x = init_xfor i in range(step_num):grad = numerical_gradient(f, x)x -= lr * gradreturn xif __name__ == '__main__':x, t = get_data()network = init_network()batch_size = 100 # 批处理大小accuracy_cnt = 0for i in range(0, len(x), batch_size):x_batch = x[i:i+batch_size]y_batch = predict(network, x_batch) # 输出[0.1, 0.3, 0.2, ..., 0.04]的数组,该数组表示“0”的概率为0.1,“1”的概率为0.3,等等。p = np.argmax(y_batch, axis=1) # 获取概率最高的元素的索引,作为预测结果。axis=1表示按行计算,即每一行中概率最大的元素对应的索引accuracy_cnt += np.sum(p == t[i:i+batch_size])# print("y_batch = \n", y_batch)# print("t[i:i+batch_size] = \n", t[i:i+batch_size])print("损失函数 = \n", cross_entropy_error(y_batch, t[i:i+batch_size]))print("Accuracy:" + str(float(accuracy_cnt) / len(x))) # 输出准确率

学习算法的实现

神经网络的学习步骤如下所示,

神经网络存在合适的权重和偏置,调整权重和偏置以便拟合训练数据的过程称为“学习”。神经网络的学习分成下面4个步骤:

  1. 步骤1(mini-batch):从训练数据中随机选出一部分数据,这部分数据称为mini-batch。我们的目标是减小mini-batch的损失函数的值。
  2. 步骤2(计算梯度):为了减小mini-batch的损失函数的值,需要求出各个权重参数的梯度。梯度表示损失函数的值减小最多的方向。
  3. 步骤3(更新参数):将权重参数沿梯度方向进行微小更新。
  4. 步骤4(重复):重复步骤1、步骤2、步骤3。

two_layer_net.py

# coding: utf-8
import sys, os
sys.path.append(os.pardir)  # 为了导入父目录的文件而进行的设定
from common.functions import *
from common.gradient import numerical_gradientclass TwoLayerNet: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)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) + b1z1 = sigmoid(a1)a2 = np.dot(z1, W2) + b2y = 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 gradsdef gradient(self, x, t):W1, W2 = self.params['W1'], self.params['W2']b1, b2 = self.params['b1'], self.params['b2']grads = {}batch_num = x.shape[0]# forwarda1 = np.dot(x, W1) + b1z1 = sigmoid(a1)a2 = np.dot(z1, W2) + b2y = softmax(a2)# backwarddy = (y - t) / batch_numgrads['W2'] = np.dot(z1.T, dy)grads['b2'] = np.sum(dy, axis=0)da1 = np.dot(dy, W2.T)dz1 = sigmoid_grad(a1) * da1grads['W1'] = np.dot(x.T, dz1)grads['b1'] = np.sum(dz1, axis=0)return grads

train_neuralnet.py

# coding: utf-8
import sys, os
sys.path.append(os.pardir)  # 为了导入父目录的文件而进行的设定
import numpy as np
import matplotlib.pyplot as plt
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_label=True)
network = TwoLayerNet(input_size=784, hidden_size=50, output_size=10)iters_num = 10000  # 适当设定循环的次数
train_size = x_train.shape[0]
batch_size = 100
learning_rate = 0.1train_loss_list = []
train_acc_list = []
test_acc_list = []iter_per_epoch = max(train_size / batch_size, 1)for i in range(iters_num):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)if i % iter_per_epoch == 0:train_acc = network.accuracy(x_train, t_train)test_acc = network.accuracy(x_test, t_test)train_acc_list.append(train_acc)test_acc_list.append(test_acc)print("train acc, test acc | " + str(train_acc) + ", " + str(test_acc))# 绘制图形
markers = {'train': 'o', 'test': 's'}
x = np.arange(len(train_acc_list))
plt.plot(x, train_acc_list, label='train acc')
plt.plot(x, test_acc_list, label='test acc', linestyle='--')
plt.xlabel("epochs")
plt.ylabel("accuracy")
plt.ylim(0, 1.0)
plt.legend(loc='lower right')
plt.show()
http://www.xdnf.cn/news/312265.html

相关文章:

  • OrcaFex11.5
  • 颠覆监测体验!WM102无线温湿度记录仪开启智能物联新时代
  • 生成式人工智能技术在高校心理健康服务中的应用; 希尔的三阶段助人理论:探索、领悟和行动
  • AI预测3D新模型百十个定位预测+胆码预测+去和尾2025年5月6日第70弹
  • 传输层UDP协议
  • 开发搭载OneNet平台的物联网数据收发APP的设计与实现
  • Vue3中的package.json依赖是否有更新
  • 探索编程世界:从“爱编程的小黄鸭”B站账号启航
  • 关于串口读写NAND闪存的用法
  • SIwave仿真之提高效率及精度
  • 3.1监督微调
  • element-ui日期时间选择器禁止输入日期
  • Linux/AndroidOS中进程间的通信线程间的同步 - 内存映射
  • 【Linux】Linux入门——权限
  • ZYNQ-UART串口中断
  • 基于计算机视觉的试卷答题区表格识别与提取技术
  • HarmonyOS 5.0 低时延音视频开发​​
  • LeetCode 1. 两数之和(Java)
  • 高频电流探头:通信测试中的隐形守护者
  • 力扣118,1920题解
  • 工业质检/缺陷检测领域最新顶会期刊论文收集整理-AAAI2025【持续更新中】
  • 如何分析java对象占用内存大小
  • Linux操作系统如何杀掉close_wait 状态的连接
  • apk 安装后提示该应用未安装
  • neo4j 桌面版的配置信息
  • Labview培训5_以空间换时间的数据采集策略介绍
  • PLL工作原理
  • 【高级IO】多路转接之select
  • 实操3:6位数码管
  • Linux云计算训练营笔记day02(Linux、计算机网络、进制)