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

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

从数据中学习

在这里插入图片描述

训练数据和测试数据

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

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

小结

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

wondows10用Electron打包threejs的项目记录

背景 电脑是用的mac,安装了parallels desktop ,想用electron 想同时打包出 苹果版本和windows版本。因为是在虚拟机里安装,它常被我重装,所以记录一下打包的整个过程。另外就是node生态太活跃,几个依赖没记录具体版本&#xff0…

软考29-上午题-【数据结构】-排序

一、排序的基本概念 1-1、稳定性 稳定性指的是相同的数据所在的位置经过排序后是否发生变化。若是排序后,次序不变,则是稳定的。 1-2、归位 每一趟排序能确定一个元素的最终位置。 1-3、内部排序 排序记录全部存放在内存中进行排序的过程。 1-4、外部…

六.生成makefile文件 并基于makefile文件编译opencv

1.点击【Generate】 生成makefile文件 2.进入目录下编译opencv源码,mingw32-make -j 8 3..编译出现报错 4.取消[WITH_OPENCL_D3D11_NV]选项,再次【configure】【generate】 然后再次编译:mingw32-make -j 8

缓存篇—缓存雪崩

什么是缓存雪崩 通常我们为了保证缓存中的数据与数据库中的数据一致性,会给 Redis 里的数据设置过期时间,当缓存数据过期后,用户访问的数据如果不在缓存里,业务系统需要重新生成缓存,因此就会访问数据库,并…

【结合OpenAI官方文档】解决Chatgpt的API接口请求速率限制

OpenAI API接口请求速率限制 速率限制以五种方式衡量:RPM(每分钟请求数)、RPD(每天请求数)、TPM(每分钟令牌数)、TPD(每天令牌数)和IPM(每分钟图像数&#x…

1.CSS单位总结

CSS 单位总结 经典真题 px 和 em 的区别 CSS 中的哪些单位 首先,在 CSS 中,单位分为两大类,绝对长度单位和相对长度单位。 绝对长度单位 我们先来说这个,绝对长度单位最好理解,和我们现实生活中是一样的。在我们…

基于SSH打通隧道实现异地组网

前言 最近有异地组网的需求,我目前的是用蒲公英X1盒子来进行组网,但是蒲公英X1非会员账号有设备限制3个(这个是硬伤),虽然说可以打通P2P但是在复杂的网络环境下概率不是特别高 所以研究下SSH异地组网的方式&#xff…

《图解HTTP》笔记2:http的构成

1,查看浏览器上面一个具体的http请求 浏览器地址栏输入网址:https://news.baidu.com/ 使用浏览器的开发者工具,查看网络中发送和接受的数据。 可以看到输入一个网址,浏览器和服务器进行了很多的交互。(绿色部分&#…

Docker容器故障排查与解决方案

Docker是一种相对使用较简单的容器,我们可以通过以下几种方式获取信息: 1、通过docker run执行命令,或许返回信息 2、通过docker logs 去获取日志,做有针对性的筛选 3、通过systemctl status docker查看docker服务状态 4、通过…

详细分析Python中的unittest测试框架

目录 1. 基本知识2. API2.1 断言2.2 setUp() 和 tearDown() 3. Demo 1. 基本知识 unittest 是 Python 标准库中的一个单元测试框架,用于编写和执行测试用例以验证代码的正确性 提供了一种结构化的方法来编写测试,使得测试代码更加模块化和易于维护 以…

【kubernetes】二进制部署k8s集群之cni网络插件flannel和calico工作原理(中)

↑↑↑↑接上一篇继续部署↑↑↑↑ 目录 一、k8s集群的三种接口 二、k8s的三种网络模式 1、pod内容器之间的通信 2、同一个node节点中pod之间通信 3、不同的node节点的pod之间通信 Overlay Network VXLAN 三、flannel网络插件 1、flannel插件模式之UDP模式&#xff0…

在 Windows 上使用 VC++ 编译 OpenSSL 源码的步骤

在 Windows 上使用 VC 编译 OpenSSL 源码的步骤如下: 准备工作 安装 Visual Studio 2017 或更高版本。安装 Perl 脚本解释器。安装 NASM 汇编器。 编译步骤 下载 OpenSSL 源码。解压 OpenSSL 源码。打开命令行工具,并进入 OpenSSL 源码目录。运行以下…

核密度分析

一.算法介绍 核密度估计(Kernel Density Estimation)是一种用于估计数据分布的非参数统计方法。它可以用于多种目的和应用,包括: 数据可视化:核密度估计可以用来绘制平滑的密度曲线或热力图,从而直观地表…

[HTML]Web前端开发技术27(HTML5、CSS3、JavaScript )JavaScript基础——喵喵画网页

希望你开心,希望你健康,希望你幸福,希望你点赞! 最后的最后,关注喵,关注喵,关注喵,佬佬会看到更多有趣的博客哦!!! 喵喵喵,你对我真的…

C++力扣题目 647--回文子串 516--最长回文子序列

647. 回文子串 力扣题目链接(opens new window) 给定一个字符串,你的任务是计算这个字符串中有多少个回文子串。 具有不同开始位置或结束位置的子串,即使是由相同的字符组成,也会被视作不同的子串。 示例 1: 输入&#xff1a…

Velocity

引入 <dependency><groupId>org.apache.velocity</groupId><artifactId>velocity-engine-core</artifactId><version>2.3</version> </dependency> 加载 Test public void velo01() throws IOException {// 设置velocity资…

Flutter插件开发指南01: 通道Channel的编写与实现

Flutter插件开发指南01: 通道Channel的编写与实现 视频 https://www.bilibili.com/video/BV1ih4y1E7E3/ 前言 本文将会通过一个加法计算&#xff0c;来实现 Channel 的双向通讯&#xff0c;让大家有个一个体会。 Flutter插件 Flutter插件是Flutter应用程序与原生平台之间的桥…

测试环境搭建整套大数据系统(六:搭建sqoop)

一&#xff1a;下载安装包 https://archive.apache.org/dist/sqoop/ 二&#xff1a;解压修改配置。 tar -zxvf sqoop-1.4.7.bin__hadoop-2.6.0.tar.gz -C /opt cd /opt mv sqoop-1.4.7.bin__hadoop-2.6.0/ sqoop-1.4.7修改环境变量 vi /etc/profile#SQOOP_HOME export SQOOP_…

远程连接 vscode 出错 “远程主机可能不符合 glibc 和 libstdc++ VS Code 服务器的先决条件”

原因&#xff1a; vscode 版本是 1.86&#xff0c;服务器上的 glibc 和 libstdc 版本不满足 要求(2.28 和 3.4.25)。 解决&#xff1a; 1、下载 1.85.2&#xff0c;解压直接运行 Code.exe。 2、回退 Remote-ssh 到 0.107.1。 参考&#xff1a; vscode 1.86版本远程ssh不兼容旧…

关于运行flutter app 运行到模拟器出现异常提示

Exception: Gradle task assembleDebug failed with exit code 1 解决方案&#xff1a; 1.讲当前文件的distributionUrl值改为 https://mirrors.cloud.tencent.com/gradle/gradle-7.4-all.zip