【笔记】深度学习入门:基于Python的理论与实现(二)

news2024/9/29 9:29:50

神经网络的学习(神经网络的学习阶段,不是我们学习神经网络)

从数据中学习

在这里插入图片描述

训练数据和测试数据

机器学习中,一般将数据分为训练数据和测试数据两部分来进行学习和 实验等。首先,使用训练数据进行学习,寻找最优的参数;然后,使用测试 数据评价训练得到的模型的实际能力。为了正确评价模型的泛化能力(指处理未被观察过的数据),就必须划分训练数据和测试数据。另外,训练数据也可以称为监督数据。只对某个数据集过度拟合的状态称为过拟合(over fitting)。避免过拟合也是机器学习的一个重要课题。

损失函数

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

均方误差

yk 是表示神经网络的输出,tk 表示监督数据,k 表示数据的维数,计算神经网络的输出和正确解监督数据的 各个元素之差的平方,再求总和
在这里插入图片描述

python实现:

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

交叉熵误差

log 表示以 e 为底数的自然对数(log e)。yk 是神经网络的输出,tk 是正确解标签
在这里插入图片描述

def cross_entropy_error(y, t): 
	delta = 1e-7
	return -np.sum(t * np.log(y + delta)) # delta是微小值 当出现 np.log(0) 时,np.log(0) 会变为负无限大,这样一来就会导致后续计算无法进行。作为保护性对策,添加一个微小值可以防止负无限大的发生

mini-batch 学习

求所有训练数据的损失函数的总和,以交叉熵误差为例,可以写成
在这里插入图片描述
如果遇到大数据, 数据量会有几百万、几千万之多,这种情况下以全部数据为对象计算损失函数是不现实的。因此,我们从全部数据中选出一部分,作为全部数据的“近似”。神经网络的学习也是从训练数据中选出一批数据(称为mini-batch,小 批量),这种学习方式称为 mini-batch 学习。

为何要设定损失函数

在进行神经网络的学习时,不能将识别精度作为指标。因为如果以 识别精度为指标,则参数的导数在绝大多数地方都会变为 0。假设某个神经网络正确识别出了 100 笔训练数据中的 32 笔,此时识别精度为 32 %。即便识别精 度有所改善,它的值也不会像 32.0123 . . . % 这样连续变化,而是变为 33 %、 34 % 这样的不连续的、离散的值。而如果把损失函数作为指标,则当前损 失函数的值可以表示为 0.92543 . . . 这样的值。并且,如果稍微改变一下参数 的值,对应的损失函数也会像 0.93432 . . . 这样发生连续性的变化。如果使用阶跃函数作为激活函数,神经网络的学习将无法进行。 如图4-4所示,阶跃函数的导数在绝大多数地方(除了0以外的地方)均为0。 也就是说,如果使用了阶跃函数,那么即便将损失函数作为指标,参数的微小变化也会被阶跃函数抹杀,导致损失函数的值不会产生任何变化。

数值微分

导数

基础不太清楚的可以自行学习下,这里就不写了
在这里插入图片描述
python的实现:

def numerical_diff(f, x):
	h = 1e-4 # 0.0001
	# 导数的形式是return (f(x+h) - f(x)) / h,这里的h不会无限接近0,所以数值微分含有误差。为了减小这个误差,我们可以计算 函数f在(x + h)和(x − h)之间的差分。因为这种计算方法以x为中心,计算它左右两边的差分,所以也称为中心差分(而 ( x + h ) 和 x 之间的差分称为前向差分
	return (f(x+h) - f(x-h)) / (2*h)

偏导数

# 求x0 = 3, x1 = 4时,关于x0 的偏导数,此时把不求导数的变量的值先在函数定义的时候带进去,保持只有一个变量。
>>> def function_tmp1(x0):
... 	return x0*x0 + 4.0**2.0
>>> numerical_diff(function_tmp1, 3.0) 6.00000000000378

梯度

由全部变量的偏导数汇总 而成的向量称为梯度(gradient)

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

梯度法

在梯度法中,函数的取值从当前位置沿着梯 度方向前进一定距离,然后在新的地方重新求梯度,再沿着新梯度方向前进, 如此反复,不断地沿梯度方向前进。像这样,通过不断地沿梯度方向前进, 逐渐减小函数值的过程就是梯度法

在这里插入图片描述

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

python实现(使用这个函数可以求函数的极小值,顺利的话,还可以求函数的最小值。):

# 参数 f 是要进行最优化的函数,init_x 是初始值,lr 是学习率 learning rate,step_num 是梯度法的重复次数
def gradient_descent(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 sys, os
sys.path.append(os.pardir)
import numpy as np
from common.functions import softmax, cross_entropy_error 
from common.gradient import numerical_gradient
class simpleNet:
	def __init__(self):
		self.W = np.random.randn(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(y, t)
		return loss

例子:

>>> net = simpleNet()
>>> print(net.W) # 权重参数 
[[ 0.47355232 0.9977393 0.84668094],
[ 0.85557411 0.03563661 0.69422093]])
>>> x = np.array([0.6, 0.9])
>>> p = net.predict(x)
>>> print(p)
[ 1.05414809 0.63071653 1.1328074]
>>> np.argmax(p) # 最大值的索引 
2
>>> t = np.array([0, 0, 1]) # 正确解标签
>>> net.loss(x, t) 
0.92806853663411326

# 求梯度(f(W) 的参数 W 是一个伪参数。因为 numerical_gradient(f, x) 会在内部执行 f(x), 为了与之兼容而定义了 f(W)))
>>> def f(W):
... 	return net.loss(x, t) 
...
>>> dW = numerical_gradient(f, net.W)
>>> print(dW)
[[ 0.21924763 0.14356247 -0.36281009] # 结果表示如果将 w11 增加 h,那么损失函数的值会增加 0.2h(近似);果将 w23 增加 h,损失函数的值将减小 0.5h,故w23 应向正方向更新,w11 应向负方向更新
[ 0.32887144 0.2153437 -0.54421514]]

学习算法的实现

神经网络的学习步骤

  • 前提

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

  • 步骤 1(mini-batch)

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

  • 步骤 2(计算梯度)

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

  • 步骤 3(更新参数)

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

  • 步骤 4(重复)

重复步骤 1、步骤 2、步骤 3。

2层神经网络的类

以前面说的数字分类为例的神经网络类:

import sys, os
sys.path.append(os.pardir)
from common.functions import *
from common.gradient import numerical_gradient
class TwoLayerNet:
	# 参数(输入层的神经元数、隐藏层的神经元数、输出层的神经元数)(中间三个,边上的两个不算)
	# 因为进行手写数字识别时,输入图像的大小是 784(28 × 28),输出为 10 个类别, 所以指定参数 input_size=784、output_size=10 	
	def __init__(self, input_size, hidden_size, output_size, weight_init_std=0.01):
  		# 初始化权重 
  		# 保存神经网络的参数的字典型变量(实例变量)。
  		self.params = {} 
  		# 第 1 层的权重(后面类推)
  		self.params['W1'] = weight_init_std * \ np.random.randn(input_size, hidden_size)
  		# 第 1 层的偏置(后面类推)
		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)
		# 保存梯度的字典型变量(numerical_gradient() 方法的返回值)
		grads = {}
		# 第 1 层权重的梯度(后面类推)
		grads['W1'] = numerical_gradient(loss_W, self.params['W1']) 
		# 第 1 层偏置的梯度(后面类推)
		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

使用:

# 因为进行手写数字识别时,输入图像的大小是 784(28 × 28),输出为 10 个类别,将隐藏层的个数 设置为一个合适的值即可。
net = TwoLayerNet(input_size=784, hidden_size=100, output_size=10) net.params['W1'].shape # (784, 100)
net.params['b1'].shape # (100,)
net.params['W2'].shape # (100, 10)
net.params['b2'].shape # (10,)

# 推理处理
x = np.random.rand(100, 784) # 伪输入数据(100笔) 
y = net.predict(x)

# 计算梯度
x = np.random.rand(100, 784) # 伪输入数据(100笔)
t = np.random.rand(100, 10) # 伪正确解标签(100笔)
grads = net.numerical_gradient(x, t) # 计算梯度
grads['W1'].shape # (784, 100) 
grads['b1'].shape # (100,) 
grads['W2'].shape # (100, 10) 
grads['b2'].shape # (10,)

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 = []

# 每个mini-batch是一个epoch
train_acc_list = []
test_acc_list = []
# 平均每个epoch的重复次数
iter_per_epoch = max(train_size / batch_size, 1)

# 超参数(人工设置的)梯度法的更新次数(循环的次数)
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)
	
	# 计算每个epoch的识别精度
	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))

学习过程:
在这里插入图片描述

小结

• 机器学习中使用的数据集分为训练数据和测试数据。
• 神经网络用训练数据进行学习,并用测试数据评价学习到的模型的泛化能力。
• 神经网络的学习以损失函数为指标,更新权重参数,以使损失函数的值减小。
• 利用某个给定的微小值的差分求导数的过程,称为数值微分。
• 利用数值微分,可以计算权重参数的梯度。
• 数值微分虽然费时间,但是实现起来很简单。下一章中要实现的稍微复杂一些的误差反向传播法可以高速地计算梯度。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1473166.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SQL进阶(三):Join 小技巧:提升数据的处理速度

复杂数据结构处理:Join 小技巧:提升数据的处理速度 本文是在原本sql闯关的基础上总结得来,加入了自己的理解以及疑问解答(by GPT4) 原活动链接 用到的数据:链接 提取码:l03e 目录 1. 课前小问…

C++笔记之执行一个可执行文件时指定动态库所存放的文件夹lib的路径

C++笔记之执行一个可执行文件时指定动态库所存放的文件夹lib的路径 参考博文: 1.C++笔记之执行一个可执行文件时指定动态库所存放的文件夹lib的路径 2.Linux笔记之LD_LIBRARY_PATH详解 3.qt-C++笔记之使用QProcess去执行一个可执行文件时指定动态库所存放的文件夹lib的路径 c…

React PureComponent 和 React.memo()区别

1 注意 ● PureComponent和memo仅作为性能优化的方式存在 ● 不要依赖它来阻止渲染,会产生BUG ● PureComponnet 和memo 都是通过对 props 值的浅比较来决定该组件是否需要更新的。 2 PureComponent 和React.memo() 区别 PureComponent 和React.memo()都是React优化…

Sora专辑|AI界一夜变天

没有丝毫预热和剧透,Open AI深夜直接丢下核弹炸了街,从业者深感要变天。 2月16日凌晨,Open AI发布了首个“文生视频”模型Sora。官方介绍,Sora能根据文字指令创造出包含丰富细节的逼真场景、角色,且能用多角度镜头,生成一镜到底的60秒长视频。 目前官网上已经更新了48个…

python Matplotlib Tkinter-->导出pdf报表

环境 python:python-3.12.0-amd64 包: matplotlib 3.8.2 reportlab 4.0.9 import matplotlib.pyplot as plt from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2Tk import tkinter as tk import tkinter.messagebox as messagebox impor…

【java-集合框架】ArrayList类

📢java基础语法,集合框架是什么?顺序表的底层模拟实现都是看本篇前的基础必会内容,本篇不再赘述,详情见评论区文章。 📢编程环境:idea 【java-集合框架】ArrayList类 1. 先回忆一下java代码中常…

Facebook Messenger链接分享:如何创建链接并设置自动化内容

Facebook Messenger链接是指基于Facebook用户名创建的会话链接,用户可以在其Facebook页面的设置部分复制此链接进行分享。然后将该链接直接粘贴到独立站、电子邮件、名片或社交媒体中,让目标受众可以一键进入对话。为了满足某些商家的需求,Fa…

Qt QWidget 简约美观的加载动画 第五季 - 小方块风格

给大家分享两个小方块风格的加载动画 &#x1f60a; 第五季来啦 &#x1f60a; 效果如下: 一个三个文件,可以直接编译运行 //main.cpp #include "LoadingAnimWidget.h" #include <QApplication> #include <QGridLayout> int main(int argc, char *arg…

时间序列分析实战(四):Holt-Winters建模及预测

&#x1f349;CSDN小墨&晓末:https://blog.csdn.net/jd1813346972 个人介绍: 研一&#xff5c;统计学&#xff5c;干货分享          擅长Python、Matlab、R等主流编程软件          累计十余项国家级比赛奖项&#xff0c;参与研究经费10w、40w级横向 文…

C++ //练习 9.24 编写程序,分别使用at、下标运算符、front和begin提取一个vector中的第一个元素。在一个空vector上测是你的程序。

C Primer&#xff08;第5版&#xff09; 练习 9.24 练习 9.24 编写程序&#xff0c;分别使用at、下标运算符、front和begin提取一个vector中的第一个元素。在一个空vector上测是你的程序。 环境&#xff1a;Linux Ubuntu&#xff08;云服务器&#xff09; 工具&#xff1a;v…

详解POCV/SOCV的时序报告

​POCV/SOCV的时序报告中有如下变量&#xff1a; Mean: 高斯分布中的μ值&#xff08;平均值&#xff09; Sensit: sensitivity&#xff0c;也就是1个Sigma的值&#xff1b; Corner: Sigma边界的最差值 cell的delay Delay mean N * Delay sigma; cell 的Transition Sl…

UE5 C++ Widget练习 Button 和 ProgressBar创建血条

一. 1.C创建一个继承Widget类的子类&#xff0c; 命名为MyUserWidget 2.加上Button 和 UserWidget的头文件 #include "CoreMinimal.h" #include "Components/Button.h" #include "Blueprint/UserWidget.h" #include "MyUserWidget.genera…

OpenCV 16 - Qt使用opencv视觉库

1 下载好opencv视觉库 不知道怎么下载和编译opencv视觉库的可以直接使用这个 : opencvcv_3.4.2_qt 2 解压opencv包 3 打开opencv的安装目录 4.打开x86/bin 复制里面所有的dll文件&#xff0c;黏贴到C/windows/syswow64里面 5 新建Qt项目 6 修改pro文件:添加对应的头文件和库文件…

【HMAC-SHA1算法以及工作原理】

曾梦想执剑走天涯&#xff0c;我是程序猿【AK】 目录 简述概要知识图谱总结 简述概要 连接HMAC-SHA1工作原理以及工具代码 知识图谱 HMAC&#xff08;Hash-based Message Authentication Code&#xff0c;基于散列的消息认证码&#xff09;是一种结合了密钥和消息的认证方法…

Python算法题集_全排列

Python算法题集_全排列 题46&#xff1a;全排列1. 示例说明2. 题目解析- 题意分解- 优化思路- 测量工具 3. 代码展开1) 标准求解【标记数组递归】2) 改进版一【指针递归】3) 改进版二【高效迭代模块】4) 改进版三【高效迭代模块极简代码】 4. 最优算法5. 相关资源 本文为Python…

【GPTs分享】每日GPTs分享之Image Generator Tool

今日GPTs分享&#xff1a;Image Generator Tool。Image Generator Tool是一种基于人工智能的创意辅助工具&#xff0c;专门设计用于根据文字描述生成图像。这款工具结合了专业性与友好性&#xff0c;鼓励用户发挥创造力&#xff0c;同时提供高效且富有成效的交互体验。 主要功能…

【新书推荐】8.1 数组

第八章 数组 数组是程序设计中最常用的数据类型之一。数组表示在指定的内存地址处&#xff0c;连续存储具有相同数据类型的一组元素。每个数组元素可以视为一个单独的变量&#xff0c;使用数组名和数组下标来表示。例如int类型的数组元素a[2]&#xff0c;表示在内存地址a处&am…

input输入框过滤非金额内容保留一个小数点和2位小数

这篇是输入框过滤非金额内容保留一个小数点和2位小数&#xff0c;金额的其他格式化可以看这篇文章常用的金额数字的格式化方法 js方法直接使用 该方式可以直接使用过滤内容&#xff0c;也可以到onInput或onblur等地方过滤&#xff0c;自行使用 /*** 非金额字符格式化处理* p…

Java数据结构---初识集合框架

目录 一、什么是集合框架 二、集合框架的重要性 三、背后涉及的数据结构及算法 1.什么是数据结构 2.容器背后对应的数据结构 3.相关的Java知识 4.什么是算法 一、什么是集合框架 Java 集合框架 Java Collection Framework &#xff0c;又被称为容器 container &#xff0…

深度学习基础(三)循环神经网络(RNN)

之前的章节我们初步介绍了卷积神经网络&#xff08;CNN&#xff09;&#xff1a; 深度学习基础&#xff08;二&#xff09;卷积神经网络&#xff08;CNN&#xff09;-CSDN博客文章浏览阅读2次。卷积神经网络&#xff08;CNN&#xff09;的应用领域广泛&#xff0c;尤其在图像处…