热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

神经网络基础学习笔记(三)神经网络的学习

前言:上一章讲了神经网络前向传播内容,这一章讲如何根据数据训练出相关权重参数的过程。我们在实战中直接得出了参数权重,接下爱我们要学习4.1从数据中学习介绍神经网络的学习,即利用数据

目录

前言:


4.1从数据中学习

4.1.1数据驱动

4.1.2训练数据和测试数据

4.2损失函数

4.2.1均方误差

4.2.2交叉熵误差

4.2.3mini-batch学习

4.2.5为什么要设定损失函数

4.3数值微分

4.3.1导数

4.3.2一个微分的例子

4.3.3偏导数

4.4梯度

4.4.1梯度法

4.4.2神经网络的梯度

4.5 学习算法的实现

4.5.1 2层神经网络的类

4.5.2 mini-batch的实现

4.5.3 基于测试数据的评价

小结:



前言:

上一章讲了神经网络前向传播内容,这一章讲如何根据数据训练出相关权重参数的过程。我们在实战中直接得出了参数权重,接下爱我们要学习

4.1从数据中学习

介绍神经网络的学习,即利用数据决定参数值的方法。我们将针对上一个实验的训练集进行学习

4.1.1数据驱动

图像的特征量通常表示为向量的形式。

前面学习过分类算法SVM以及KNN,我们手动提取特征向量。

深 度 学 习 有 时 也 称 为 端 到 端 机 器 学 习(end-to-end machine learning)。这里所说的端到端是指从一端到另一端的意思,也就是 从原始数据(输入)中获得目标结果(输出)的意思。

神经网络的优点是对所有的问题都可以用同样的流程来解决。

4.1.2训练数据和测试数据

1.训练数据和测试数据:训练数据用来训练模型的,而测试数据就是不包含在训练模型内的数据用来评判训练后模型好坏的数据

2.泛化能力:如果测试的成绩好那么他的泛化能力就好。

3.过拟合:适应训练数据强,但泛化能力弱。

4.2损失函数

神经网络的学习的目的就是以该损失函数为基准,找出能使它 的值达到最小的权重参数

种评判方法均方误差交叉熵误差

4.2.1均方误差

实现代码:

4.2.2交叉熵误差

交叉熵误差的值是由正确解标签所对应的输出结果决定的

实现代码:

4.2.3mini-batch学习

单个单个计算的话,数据处理时间过长,我们希望时间大部分花费咋计算上面。计算所有数据的(损失函数值的和/总数)的平均损失函数值

分析上一个实验的数据包

随机抽取10笔

为了找到使损失函数的值尽可能小的地方,需要计算参数的导数(确切地讲是梯度),然后以这个导数为指引,
逐步更新参数的值。

4.2.5为什么要设定损失函数

因为损失函数可导且连续,便于调试。

以一个例子,比如有100个训练数据进行测试,发现精度为32%,如果以识别精度为指标,那么稍微修改权重参数精度也只会是32%,稍微改动大一点点权重参数精度可能直接变为33%,这种是离散不连续的变化;而损失函数不一样,稍微改变权重关系时,损失函数值就会立刻改变(如0.9524变为0.9612),这种值是连续性的,因为离散型的变化其导数(斜率)一般都为0,而连续型的变化导数一般不为0,所以能很容易判别出权重参数变化时的模型好坏。

4.3数值微分


4.3.1导数

 

1.10e-50精度会有误差,比如python的float精度为小数点后4位,这里已经是50位了,所以要改成10e-4 舍入误差

2.f(x+h)-f(x)/h(向前差分)这个误差也很大,因为根据1的改变,h不是一个趋近于0的数,所以误差变大,应该用中心法改成f(x+h)-f(x-h)/2h(中心差分)

利用微小的差分求导数的过程称为数值微分(numerical  differentiation)

数值微分数值梯度

改进后代码

中值定理的感觉

注意:

这种利用微小差分的导数过程为数值微分,而用数学公式推导的如y=x²导数为y=2x这种交解析性求导,这种叫做真导数

4.3.2一个微分的例子

如y=0.01x²+0.1x的导数实现

可以发现改进后的微分代码误差非常小

数值微分代码:

4.3.3偏导数

比如实现的偏导数

先看这个函数的代码实现与图像:

偏导数实现:原理其实跟一元导数一样,就是带入一个真值消除一个变量而已

公式难在数值微分,肉眼偏导验算一下,第一条公式为2*X0

4.4梯度

在刚才的例子中,我们按变量分别计算了x0和x1的偏导数。现在,我 们希望一起计算x0和x1的偏导数。比如

比如我们求一个函数y=x0²+x1²变量有x0,x1,当我们对他全部变量(这里最多只有2个)进行偏导汇总而成的变量叫梯度。

梯度指向的图

从这个图可以看出,梯度指向的点的函数值越来越小,反之越来越大,这是梯度重要性质!

4.4.1梯度法

寻找最小值的梯度法称为梯度下降法(gradient descent method), 寻找最大值的梯度法称为梯度上升法(gradient ascent method)。

神经网络(深度学习)中,梯度法主要是指梯度下降法

从上面的梯度我们可以知道梯度其实就是寻找梯度为0的地方,但是梯度为0不一定是最小值(高数里的靶点),他可能是极小值或者是鞍点(某方向看是极小值,另一方向看是极大值,导数为0的点),所以我们可以计算一次梯度后再次计算一次梯度,这样最后就能找到真正的最小值点了,这就是梯度法。

学习率决定在一次学习中,应该学习多少,以及在多大程度上更新参数

注意:找最小其实跟找最大是一样的,就是取负的问题而已,不用太在意这个。

(梯度下降法)代码实现:

numerical_gradient(f,x)会求函数的梯度,用该梯度乘以学习率得到的值进行更新操作,由step_num指定重复的 次数。

这个例子中得到的最后的x值都是非常小的数,都几乎趋向于0,根据解析式方式(自己动笔试试)我们知道最小值为(0,0),跟上面的例子几乎一致(实际的例子中最小值不一定是0)。

每次求导后的过程:

实现代码:

# coding: utf-8
import numpy as np
import matplotlib.pylab as plt
from gradient_2d import numerical_gradient #求梯度,原理与数值微分相同
#梯度下降法
def gradient_descent(f, init_x, lr=0.01, step_num=100):
x = init_x
x_history = []
for i in range(step_num):
# 记录前一个x,用于绘图痕迹
x_history.append( x.copy() )
# 梯度下降法,为梯度乘以学习率
grad = numerical_gradient(f, x)
x -= lr * grad
return x, np.array(x_history)
# 求偏导,np.sum(x**2)
def function_2(x):
return x[0]**2 + x[1]**2
init_x = np.array([-3.0, 4.0])
# 学习率为0.1
lr = 0.1
# 梯度法的重复次数
step_num = 20
x, x_history = gradient_descent(function_2, init_x, lr=lr, step_num=step_num)
plt.plot( [-5, 5], [0,0], '--b')
plt.plot( [0,0], [-5, 5], '--b')
plt.plot(x_history[:,0], x_history[:,1], 'o')
plt.xlim(-3.5, 3.5)
plt.ylim(-4.5, 4.5)
plt.xlabel("X0")
plt.ylabel("X1")
plt.show()

 

这里有个学习率太大  太小的例子:

太大时结果会发散成很大的数,太小的话结果几乎没更新就结束了

所以学习率n太大太小都不好学习率被称为超参数,一般认为多次设定后取一个合理值

学习率这样的参数称为超参数。

相对于神经网络的权重参数是通过训练 数据和学习算法自动获得的,学习率这样的超参数则是人工设定的。

4.4.2神经网络的梯度

所说的梯度是指损失函数关于权重参数的梯度

如图,我们有2*3的W权重参数,L为损失函数,梯度用表示,如图:

为simpleNet的类(源代码在ch04/gradient_simplenet.py 中

代码实现:

# coding: utf-8
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):
# 初始化2*3权重参数
self.W = np.random.randn(2,3)
def predict(self, x):
# 一层 权重乘以变量 == 一层感知机
return np.dot(x, self.W)
def loss(self, x, t):
# 计算交叉熵softmax()函数的损失值
z = self.predict(x)
y = softmax(z)
loss = cross_entropy_error(y, t)
return loss
x = np.array([0.6, 0.9])
t = np.array([0, 0, 1])
net = simpleNet()
f = lambda w: net.loss(x, t)
dW = numerical_gradient(f, net.W)
print(dW)




来自-优秀的方同学:
https://me.csdn.net/qq_37431224





来自-优秀的方同学:
https://me.csdn.net/qq_37431224


4.5 学习算法的实现


随机梯度下降法(stochastic gradient descent)。“随机”指的是“随机选择的” 的意思,因此,随机梯度下降法是“对随机选择的数据进行的梯度下降法”。简称SGD

实现代码:

4.5.1 2层神经网络的类

two_layer_net:

# coding: utf-8
import sys, os
sys.path.append(os.pardir) # 为了导入父目录的文件而进行的设定
from common.functions import *
from common.gradient import numerical_gradient
class TwoLayerNet:
"""
从第1个参数开始,依次表示:
输入层的神经元数、隐藏层的神经元数、输出层的神经元数
输入图像大小784 输出10个数字(0-9)
"""
def __init__(self, input_size, hidden_size, output_size, weight_init_std=0.01):
# 初始化权重,是有要求的但是后面在补上
self.params = {}
# 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) + 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:监督数据
# numerical_gradient(self, 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 grads
# 使用误差反向传播法计算梯度
def 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]

# forward
a1 = np.dot(x, W1) + b1
z1 = sigmoid(a1)
a2 = np.dot(z1, W2) + b2
y = softmax(a2)

# backward
dy = (y - t) / batch_num
grads['W2'] = np.dot(z1.T, dy)
grads['b2'] = np.sum(dy, axis=0)

da1 = np.dot(dy, W2.T)
dz1 = sigmoid_grad(a1) * da1
grads['W1'] = np.dot(x.T, dz1)
grads['b1'] = np.sum(dz1, axis=0)
return grads

 

 

4.5.2 mini-batch的实现

类:train_neuralnet:

# 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.1
train_loss_list = []
train_acc_list = []
test_acc_list = []
iter_per_epoch = max(train_size / batch_size, 1)
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)

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', line)
plt.xlabel("epochs")
plt.ylabel("accuracy")
plt.ylim(0, 1.0)
plt.legend(loc='lower right')
plt.show()

可以发现随着学习的进行,损失函数的值在不断减小。这 是学习正常进行的信号,表示神经网络的权重参数在逐渐拟合数据。也就是 说,神经网络的确在学习!通过反复地向它浇灌(输入)数据,神经网络正 在逐渐向最优参数靠近。

实线表示训练数据的识别精度,虚线表示测试数据的识别精 度

4.5.3 基于测试数据的评价

光看这个结果还不能说明该神经网络在 其他数据集上也一定能有同等程度的表现。

神经网络的学习中,必须确认是否能够正确识别训练数据以外的其他数 据,即确认是否会发生过拟合。

要评价神经网络的泛 化能力,就必须使用不包含在训练数据中的数据

 epoch是一个单位。一个 epoch表示学习中所有训练数据均被使用过 一次时的更新次数。比如,对于 10000笔训练数据,用大小为 100 笔数据的mini-batch进行学习时,重复随机梯度下降法 100次,所 有的训练数据就都被“看过”了A。此时,100次就是一个 epoch。

代码在上面:

之所以要计算每一个epoch的识别精度,是因 为如果在for语句的循环中一直计算识别精度,会花费太多时间

没有必要那么频繁地记录识别精度(只要从大方向上大致把握识别精度的推 移就可以了

小结:

本章所学的内容


  • 机器学习中使用的数据集分为训练数据和测试数据

  • 神经网络用训练数据进行学习,并用测试数据评价学习到的模型的 泛化能力。 

  • 神经网络的学习以损失函数为指标,更新权重参数,以使损失函数的值减小。

  • 利用某个给定的微小值的差分求导数的过程,称为数值微分

  • 利用数值微分,可以计算权重参数的梯度

  • 数值微分虽然费时间,但是实现起来很简单。

需要注意的时候,你会觉得比较多内容这一章,建议书写一下
 






























名称 函数
数值微分 numerical_diff(x)
偏导数

function_2(x)

偏导数
梯度 numerical_gradient(f,x)
梯度下降法 gradient_descent(f, init_x, lr=0.01, step_num=100)

下一章中要实现的稍 微复杂一些的误差反向传播法可以高速地计算梯度。


推荐阅读
  • 探索聚类分析中的K-Means与DBSCAN算法及其应用
    聚类分析是一种用于解决样本或特征分类问题的统计分析方法,也是数据挖掘领域的重要算法之一。本文主要探讨了K-Means和DBSCAN两种聚类算法的原理及其应用场景。K-Means算法通过迭代优化簇中心来实现数据点的划分,适用于球形分布的数据集;而DBSCAN算法则基于密度进行聚类,能够有效识别任意形状的簇,并且对噪声数据具有较好的鲁棒性。通过对这两种算法的对比分析,本文旨在为实际应用中选择合适的聚类方法提供参考。 ... [详细]
  • 【图像分类实战】利用DenseNet在PyTorch中实现秃头识别
    本文详细介绍了如何使用DenseNet模型在PyTorch框架下实现秃头识别。首先,文章概述了项目所需的库和全局参数设置。接着,对图像进行预处理并读取数据集。随后,构建并配置DenseNet模型,设置训练和验证流程。最后,通过测试阶段验证模型性能,并提供了完整的代码实现。本文不仅涵盖了技术细节,还提供了实用的操作指南,适合初学者和有经验的研究人员参考。 ... [详细]
  • 通过使用 `pandas` 库中的 `scatter_matrix` 函数,可以有效地绘制出多个特征之间的两两关系。该函数不仅能够生成散点图矩阵,还能通过参数如 `frame`、`alpha`、`c`、`figsize` 和 `ax` 等进行自定义设置,以满足不同的可视化需求。此外,`diagonal` 参数允许用户选择对角线上的图表类型,例如直方图或密度图,从而提供更多的数据洞察。 ... [详细]
  • 本文介绍如何使用OpenCV和线性支持向量机(SVM)模型来开发一个简单的人脸识别系统,特别关注在只有一个用户数据集时的处理方法。 ... [详细]
  • 通过使用CIFAR-10数据集,本文详细介绍了如何快速掌握Mixup数据增强技术,并展示了该方法在图像分类任务中的显著效果。实验结果表明,Mixup能够有效提高模型的泛化能力和分类精度,为图像识别领域的研究提供了有价值的参考。 ... [详细]
  • 大类|电阻器_使用Requests、Etree、BeautifulSoup、Pandas和Path库进行数据抓取与处理 | 将指定区域内容保存为HTML和Excel格式
    大类|电阻器_使用Requests、Etree、BeautifulSoup、Pandas和Path库进行数据抓取与处理 | 将指定区域内容保存为HTML和Excel格式 ... [详细]
  • 本文汇集了我在网络上搜集以及在实际面试中遇到的前端开发面试题目,并附有详细解答。无论是初学者还是有一定经验的开发者,都应深入理解这些问题背后的原理,通过系统学习和透彻研究,逐步形成自己的知识体系和技术框架。 ... [详细]
  • 每年,意甲、德甲、英超和西甲等各大足球联赛的赛程表都是球迷们关注的焦点。本文通过 Python 编程实现了一种生成赛程表的方法,该方法基于蛇形环算法。具体而言,将所有球队排列成两列的环形结构,左侧球队对阵右侧球队,首支队伍固定不动,其余队伍按顺时针方向循环移动,从而确保每场比赛不重复。此算法不仅高效,而且易于实现,为赛程安排提供了可靠的解决方案。 ... [详细]
  • 针对图像分类任务的训练方案进行了优化设计。通过引入PyTorch等深度学习框架,利用其丰富的工具包和模块,如 `torch.nn` 和 `torch.nn.functional`,提升了模型的训练效率和分类准确性。优化方案包括数据预处理、模型架构选择和损失函数的设计等方面,旨在提高图像分类任务的整体性能。 ... [详细]
  • 技术日志:使用 Ruby 爬虫抓取拉勾网职位数据并生成词云分析报告
    技术日志:使用 Ruby 爬虫抓取拉勾网职位数据并生成词云分析报告 ... [详细]
  • 机器学习中的标准化缩放、最小-最大缩放及鲁棒缩放技术解析 ... [详细]
  • 利用python爬取豆瓣电影Top250的相关信息,包括电影详情链接,图片链接,影片中文名,影片外国名,评分,评价数,概况,导演,主演,年份,地区,类别这12项内容,然后将爬取的信息写入Exce ... [详细]
  • 本文介绍了如何利用 `matplotlib` 库中的 `FuncAnimation` 类将 Python 中的动态图像保存为视频文件。通过详细解释 `FuncAnimation` 类的参数和方法,文章提供了多种实用技巧,帮助用户高效地生成高质量的动态图像视频。此外,还探讨了不同视频编码器的选择及其对输出文件质量的影响,为读者提供了全面的技术指导。 ... [详细]
  • 如何将Python与Excel高效结合:常用操作技巧解析
    本文深入探讨了如何将Python与Excel高效结合,涵盖了一系列实用的操作技巧。文章内容详尽,步骤清晰,注重细节处理,旨在帮助读者掌握Python与Excel之间的无缝对接方法,提升数据处理效率。 ... [详细]
  • 2018 HDU 多校联合第五场 G题:Glad You Game(线段树优化解法)
    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6356在《Glad You Game》中,Steve 面临一个复杂的区间操作问题。该题可以通过线段树进行高效优化。具体来说,线段树能够快速处理区间更新和查询操作,从而大大提高了算法的效率。本文详细介绍了线段树的构建和维护方法,并给出了具体的代码实现,帮助读者更好地理解和应用这一数据结构。 ... [详细]
author-avatar
feixiang1563122
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有