鱼书-第四章

第四章 神经网络的学习

机器学习的方法是避免人为介入,尝试从收集到的数据中发现答案(模式)。神经网络或深度学习则比以往的机器学习方法更能避免人为介入。

1. 从数据中学习:

  • 方案一:机器学习

从图像中提取特征量,再用机器学习技术学习这些特征量的模式。 使用这些特征量将图像数据转换为向量,然后对转换后的向量使用机器学习中的SVM、KNN等分类器进行学习。(对不同问题要考虑特征量的选取)

这里所说的“特征量”是指可以从输入数据(输入图像)中准确地提取本质数据(重要的数据)的转换器。图像的特征量通常表示为向量的形式。在计算机视觉领域,常用的特征量包括SIFT、SURF和HOG等。

机器学习中,一般将数据分为训练数据测试数据两部分来进行学习和实验。首先,使用训练数据进行学习,寻找最优的参数;然后,使用测试数据评价训练得到的模型的实际能力。

泛化能力是指处理未被观察过的数据(不包含在训练数据中的数据)的能力。为了正确评价模型的泛化能力,就必须划分训练数据和测试数据。另外,训练数据也可以称为监督数据。
获得泛化能力是机器学习的最终目标。

  • 方案二:神经网络

神经网络直接学习图像本身。(对所有问题可以使用同样流程),神经网络可以将数据直接作为原始数据,进行“端对端”的学习。

神经网络的学习通过损失函数表示现在的状态。然后,以这个损失函数为基准,寻找最优权重参数。这个损失函数可以使用任意函数,但一般用均方误差和交叉熵误差等。

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

在这里插入图片描述

2. 损失函数:用来评价网络性能

  • 均方误差
    在这里插入图片描述

均方误差会计算神经网络输出的和正确解监督数据的各个元素之差的平方,再求总和。

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

损失函数的值越小,和监督数据之间的误差越小。

监督数据用于训练和评估机器学习模型,而神经网络输出数据是模型生成的预测或估计,用于评估模型的性能。
模型的目标是通过学习从监督数据中产生与实际目标标签相匹配的输出数据,以提高其性能和泛化能力。

  • 交叉熵误差
    在这里插入图片描述
def cross_entropy_error(y, t):
 delta = 1e-7
 return -np.sum(t * np.log(y + delta))

加上了一个微小值delta,作为保护性对策。这是因为,当出现np.log(0)时,np.log(0)会变为负无限大的-inf,这样一来就会导致后续计算无法进行。

  • mini-batch学习

前面都是针对单个数据的损失函数,如果要求所有训练数据的损失函数的总和,以交叉熵误差为例:
在这里插入图片描述

这里,假设数据有N个,tnk表示第n个数据的第k个元素的值(ynk是神经网络的输出,tnk是监督数据)。式子只是把求单个数据的损失函数的式(4.2)扩大到了N份数据,不过最后还要除以N进行正规化。通过除以N,可以求单个数据的“平均损失函数”。通过这样的平均化可以获得和训练数据的数量无关的统一指标。

mini-batch的损失函数是利用一部分样本数据来近似地计算整体。
当监督数据是标签形式(非one-hot表示,而是像“2”“7”这样的标签)时,交叉熵误差可通过如下代码实现:

def cross_entropy_error(y, t):
 if y.ndim == 1:
 t = t.reshape(1, t.size)
 y = y.reshape(1, y.size)
 batch_size = y.shape[0]
 return -np.sum(np.log(y[np.arange(batch_size), t] + 1e-7)) / batch_size
  • 损失函数的重要性
    在神经网络的学习中,寻找最优参数(权重和偏置)时,要寻找使损失函数的值尽可能小的参数。为了找到使损失函数的值尽可能小的地方,需要计算参数的导数(确切地讲是梯度),然后以这个导数为指引,逐步更新参数的值。

    假设有一个神经网络,现在我们来关注这个神经网络中的某一个权重参数。此时,对该权重参数的损失函数求导,表示的是“如果稍微改变这个权重参数的值,损失函数的值会如何变化”。如果导数的值为负,通过使该权重参数向正方向改变,可以减小损失函数的值;反过来,如果导数的值为正,则通过使该权重参数向负方向改变,可以减小损失函数的值。不过,当导数的值为0时,无论权重参数向哪个方向变化,损失函数的值都不会改变,此时该权重参数的更新会停在此处。


3.梯度

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

梯度指示的方向是各点处的函数值减小最多的方向

梯度法:
在这里插入图片描述
η表示更新量,在神经网络的学习中,称为学习率(事先确定,不能过大或过小)。学习率决定在一次学习中,应该学习多少,以及在多大程度上更新参数。

像学习率这样的参数称为超参数,是人工设定的。一般来说,超参数需要尝试多个值,以便找到一种可以使学习顺利进行的设定。

梯度下降法示例:

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

参数f是要进行最优化的函数,init_x是初始值,lr是学习率learning rate,step_num是梯度法的重复次数,numerical_gradient(f,x)会求函数的梯度,用该梯度乘以学习率得到的值进行更新操作,由step_num指定重复的
次数。

求神经网络的梯度

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

这里使用了 common/functions.py中的 softmax和 cross_entropy_error方法,以及common/gradient.py中的numerical_gradient方法。simpleNet类只有一个实例变量,即形状为2×3的权重参数。它有两个方法,一个是用于预测的predict(x),另一个是用于求损失函数值的loss(x,t)。这里参数x接收输入数据,t接收正确解标签。

>>> net = simpleNet()
>>> print(net.W) # 权重参数
>>> x = np.array([0.6, 0.9])
>>> p = net.predict(x)
>>> print(p)
>>> np.argmax(p) # 最大值的索引
>>> t = np.array([0, 0, 1]) # 正确解标签
>>> net.loss(x, t)
>>> def f(W):
... return net.loss(x, t)
...
>>> dW = numerical_gradient(f, net.W)
>>> print(dW)# 神经网络的梯度矩阵

4.算法的实现

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

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

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

  • 步骤3(更新参数)
    将权重参数沿梯度方向进行微小更新。

  • 步骤4(重复)
    重复步骤1、步骤2、步骤3。

两层神经网络

import sys, os
sys.path.append(os.pardir)
from common.functions import *
from common.gradient import numerical_gradient

class 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)
 #W是权重矩阵,B是初始化为0的偏置矩阵
 
 #定义前向传播函数进行预测
	 def predict(self, x):#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
#其中输入数据经过权重和偏置的线性变换,然后通过激活函数(Sigmoid)引入非线性,最终通过 Softmax 函数将结果转化为概率分布,用于多类别分类问题的决策。

#定义损失函数:
# x:输入数据, t:监督数据
 	def loss(self, x, t):
		y = self.predict(x)
 		return cross_entropy_error(y, t)#返回损失值,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
 
 # 计算权重参数的梯度
 	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
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
深入java虚拟机第二版 第1章 Java体系结构介绍 1.1 为什么使用Java 1.2 网络带来的挑战和机遇 1.3 体系结构 1.3.1 Java虚拟机 1.3.2 类装载器的体系结构 1.3.3 Java class文件 1.3.4 Java API 1.3.5 Java程序设计语言 1.4 Java体系结构的代价 1.5 结论 1.6 资源页 第2章 平台无关 2.1 为什么要平台无关 2.2 Java的体系结构对平台无关的支持 2.2.1 Java平台 2.2.2 Java语言 2.3.3 Java class文件 . 2.2.4 可伸缩性 2.3 影响平台无关性的因素 2.3.1 Java平台的部署 2.3.2 Java平台的版本 2.3.3 本地方法 2.3.4 非标准运行时库 2.3.5 对虚拟机的依赖 2.3.6 对用户界面的依赖 2.3.7 Java平台实现中的bug 2.3.8 测试 2.4 平台无关的七个步骤 2.5 平台无关性的策略 2.6 平台无关性和网络移动对象 2.7 资源页 第3章 安全 3.1 为什么需要安全性 3.2 基本沙箱 3.3 类装载器体系结构 3.4 class文件检验器 3.4.1 第一趟:class文件的结构检查 3.4.2 第二趟:类型数据的语义检查 3.4.3 第三趟:字节码验证 3.4.4 第四趟:符号引用的验证 3.4.5 二进制兼容 3.5 Java虚拟机中内置的安全特性 3.6 安全管理器和Java API 3.7 代码签名和认证 3.8 一个代码签名示例 3.9 策略 3.10 保护域 3.11 访问控制器 3.11.1 implies()方法 3.11.2 栈检查示例 3.11.3 一个回答“是”的栈检查 3.11.4 一个回答“不”的栈检查 3.11.5 doPrivileged()方法 3.11.6 doPrivileged()的一个无效使用 3.12 Java安全模型的不足和今后的发展 方向 3.13 和体系结构无关的安全性 3.14 资源页 第4章 网络移动性 4.1 为什么需要网络移动性 4.2 一种新的软件模式 4.3 Java体系结构对网络移动性的支持 4.4 applet:网络移动性代码的示例 4.5 Jini服务对象:网络移动对象的示例 4.5.1 Jini是什么 4.5.2 Jini如何工作 4.5.3 服务对象的优点 4.6 网络移动性:Java设计的中心 4.7 资源页 第5章 Java虚拟机 5.1 Java虚拟机是什么 5.2 Java虚拟机的生命周期 5.3 Java虚拟机的体系结构 5.3.1 数据类型 5.3.2 字长的考量 5.3.3 类装载器子系统 5.3.4 方法区 5.3.5 堆 5.3.6 程序计数器 5.3.7 Java栈 5.3.8 栈帧 5.3.9 本地方法栈 5.3.10 执行引擎 5.3.11 本地方法接口 5.4 真实机器 5.5 一个模拟:“Eternal Math” 5.6 随书光盘 5.7 资源页 第6章 Java class文件 6.1 Java class文件是什么 6.2 class文件的内容 6.3 特殊字符串 6.3.1 全限定名 6.3.2 简单名称 6.3.3 描述符 6.4 常量池 6.4.1 CONSTANT_Utf8_info表 6.4.2 CONSTANT_Integer_info表 6.4.3 CONSTANT_Float_info表 6.4.4 CONSTANT_Long_info表 6.4.5 CONSTANT_Double_info表 6.4.6 CONSTANT_Class_info表 6.4.7 CONSTANT_String_info表 6.4.8 CONSTANT_Fieldref_info表 6.4.9 CONSTANT_Methodref_info表 6.4.10 CONSTANT_InterfaceMethodref_ info表 6.4.11 CONSTANT_NameAndType_info 表 6.5 字段 6.6 方法 6.7 属性 6.7.1 属性格式 6.7.2 Code属性 6.7.3 ConstantValue属性 6.7.4 Deprecated属性 6.7.5 Exceptions属性 6.7.6 InnerClasses属性 6.7.7 LineNumberTable属性 6.7.8 LocalVariableTable属性 6.7.9 SourceFile属性 6.7.10 Synthetic属性 6.8 一个模拟:“Getting Loaded” 6.9 随书光盘 6.10 资源页 第7章 类型的生命周期 7.1 类型装载、连接与初始化 7.1.1 装载 7.1.2 验证 7.1.3 准备 7.1.4 解析 7.1.5 初始化 7.2 对象的生命周期 7.2.1 类实例化 7.2.2 垃圾收集和对象的终结 7.3 卸载类型 7.4 随书光盘 7.5 资源页 第8章 连接模型 8.1 动态连接和解析 8.1.1 解析和动态扩展 8.1.2 类装载器与双亲委派模型 8.1.3 常量池解析 8.1.4 解析CONSTANT_Class_info入口 8.1.5 解析CONSTANT_Fieldref_info 入口 S.1.6 解析CONSTANT_Methodref_info 入口 8.1.7 解析CONSTANT_Interface- Methodref_info入口 8.1.8 解析CONSTANT_String_info入口 8.1.9 解析其他类型的入口 8.1.10 装载约束 8.1.11 编译时常量解析 8.1.12 直接引用 8.1.13 _quick指令 8.1.14 示例:Salutation程序的连接 8.1.15 示例:Greet程序的动态扩展 8.1.16 使用1.1版本的用户自定义类装 载器 8.1.17 使用1.2版本的用户自定义类装 载器 8.1.18 示例:使用forName()的动态扩展 8.1.19 示例:卸载无法触及的greeter类 8.1.20 示例:类型安全性与装载约束 8.2 随书光盘 8.3 资源页 第9章 垃圾收集 9.1 为什么要使用垃圾收集 9.2 垃圾收集算法 9.3 引用计数收集器 9.4 跟踪收集器 9.5 压缩收集器 9.6 拷贝收集器 9.7 按代收集的收集器 9.8 自适应收集器 9.9 火车算法 9.9.1 车厢、火车和火车站 9.9.2 车厢收集 9.9.3 记忆集合和流行对象 9.10 终结 9.11 对象可触及性的生命周期 9.11.1 引用对象 9.11.2 可触及性状态的变化 9.11.3 缓存、规范映射和临终清理 9.12 一个模拟:“Heap of Fish” 9.12.1 分配鱼 9.12.2 设置引用 9.12.3 垃圾收集 9.12.4 压缩堆 9.13 随书光盘 9.14 资源页 第10章 栈和局部变量操作 10.1 常量入栈操作 10.2 通用栈操作 10.3 把局部变量压入栈 10.4 弹出栈顶部元素,将其赋给局部变量 10.5 wide指令 10.6 一个模拟:“Fibonacci Forever” 10.7 随书光盘 10.8 资源页 第11章 类型转换 11.1 转换操作码 11.2 一个模拟:“Conversion Diversion” 11.3 随书光盘 11.4 资源页 第12章 整数运算 12.1 二进制补码运算 12.2 Inner Int:揭示Java int类型内部性质 的applet 12.3 运算操作码 12.4 一个模拟:“Prime Time” 12.5 随书光盘 12.6 资源页 第13章 逻辑运算 13.1 逻辑操作码 13.2 一个模拟:“Logical Results” 13.3 随书光盘 13.4 资源页 第14章 浮点运算 14.1 浮点数 14.2 Inner Float:揭示Java float类型内部 性质的applet 14.3 浮点模式 14.3.1 浮点值集合 14.3.2 浮点值集的转换 14.3.3 相关规则的本质 14.4 浮点操作码 14.5 一个模拟:“Circle of Squares” 14.6 随书光盘 14.7 资源页 第15章 对象和数组 15.1 关于对象和数组的回顾 15.2 针对对象的操作码 15.3 针对数组的操作码 15.4 一个模拟:“Three—Dimensional Array” 15.5 随书光盘 15.6 资源页 第16章 控制流 16.1 条件分支 16.2 五条件分支 16.3 使用表的条件分支 16.4 一个模拟:“Saying Tomato” 16.5 随书光盘 16.6 资源页 第17章 异常 17.1 异常的抛出与捕获 17.2 异常表 17.3 一个模拟:“Play Ball!” 17.4 随书光盘 17.5 资源页 第18章 finally子句 18.1 微型子例程 18.2 不对称的调用和返回 18.3 一个模拟:“Hop Around” 18.4 随书光盘 18.5 资源页 第19章 方法的调用与返回 19.1 方法调用 19.1.1 Java方法的调用 19.1.2 本地方法的调用 19.2 方法调用的其他形式 19.3 指令invokespecial 19.3.1 指令invokespecial和[init]()方法 19.3.2 指令invokespecial和私有方法 19.3.3 指令invokespecial和super关键字 19.4 指令invokeinterface 19.5 指令的调用和速度 19.6 方法调用的实例 19.7 从方法中返回 19.8 随书光盘 19.9 资源页 第20章 线程同步 20.1 监视器 20.2 对象锁 20.3 指令集中对同步的支持 20.3.1 同步语句 20.3.2 同步方法 20.4 Object类中的协调支持 20.5 随书光盘 20.6 资源页 附录A 按操作码助记符排列的指令集 附录B 按功能排列的操作码助记符 附录C 按操作码字节值排列的操作码助

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值