| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> 人工智能 -> 深度学习利器之自动微分(1) -> 正文阅读 |
|
[人工智能]深度学习利器之自动微分(1) |
深度学习利器之自动微分(1)文章目录0x00 摘要本文和下文以 Automatic Differentiation in Machine Learning: a Survey 这篇论文为基础,逐步分析自动微分这个机器学习的基础利器。 0.1 缘起笔者计划分析 PyTorch 的分布式实现,但是在分析分布式autograd 时发现,如果不把自动微分以及普通 autograd 引擎梳理清楚,分布式autograd的分析就是寸步难行,因此返回头来学习,遂有此文。 0.2 自动微分我们知道,深度学习框架训练模型的基本流程是:
搭建计算图(依赖关系)和计算损失函数的过程,称为"正向传播”,这个是依据用户模型完成,本质上是用户自己处理。而依据损失函数求导的过程,称为"反向传播”,这个对于用户来说太繁重,所以各种深度学习框架都提供了自动求导功能。深度学习框架帮助我们解决的核心问题就是两个:
于是这就牵扯出来自动梯度计算这个概念。 在数学与计算代数学中,自动微分或者自动求导(Automatic Differentiation,简称AD)也被称为微分算法或数值微分。它是一种数值计算的方式,其功能是计算复杂函数(多层复合函数)在某一点处的导数,梯度,Hessian矩阵值等等。 0x01 基本概念为了行文完整,我们首先要介绍一些基本概念或者思想,可能部分概念大家已经熟知,请直接跳到第二章。 1.1 机器学习赫伯特·西蒙(Herbert Simon,1975年图灵奖获得者、1978年诺贝尔经济学奖获得者)对"学习”下过一个定义:"如果一个系统,能够通过执行某个过程,就此改进了它的性能,那么这个过程就是学习”。 所以说,机器学习就是从经验数据中学习,提取数据中的重要的模式和趋势,从而改进预估函数(有关特定输入和预期输出的功能函数)的性能。 比如:一个函数可以用来区分猫和狗,我们需要使用大量的训练数据来挖掘培养这个函数,改进其性能。 1.2 深度学习传统机器学习使用知识和经验从原始数据中提取各种特征进行训练。提取特征就是机器学习的重要组成部分:特征工程。因为原始数据涉及到的特征数目太庞大,而且特征种类千差万别,所以特征工程是个极具挑战的部分。深度学习则是让神经网络自己学习/提取数据的各种特征,或者通过组合各种底层特征来形成一些高层特征。 1.3 损失函数对于机器学习的功能函数,我们给定一个输入,会得到一个输出,比如输入猫,输出"是否为猫”。但是这个实际输出值可能与我们的预期值不一样。因此,我们需要构建一个评估体系,来辨别函数的好坏,这就引出了损失函数。 损失函数(loss function) 或者是代价函数(cost function)就是用来度量预期输出(真实值)和实际输出(预测值)的"落差”程度 或者说是精确度。 损失函数可以把模型拟合程度量化成一个函数值,如果我们选取不同的模型参数,则损失函数值会做相应的改变。损失函数值越小,说明 实际输出 和预期输出 的差值就越小,也就表明构建的模型精确度就越高。比如常见的均方误差(Mean Squared Error)损失函数,从几何意义上来说,它可以看成预测值和实际值的平均距离的平方。 1.4 权重和偏置损失函数里一般有两种参数:
神经网络结构的设计目的在于,让神经网络以"更佳”的性能来学习。而这里的所谓"学习”,就是不断调整权重和偏置,从而找到神经元之间最合适的权重和偏置,让损失函数的值达到最小。 1.5 导数和梯度**神经网络的特征之一,就是从数据样本中学习。**也就是说,可以由训练数据来自动确定网络权值参数的值。 既然我们有了损失函数这个评估体系,那么就可以利用其来反向调整网络中权重,使得损失最小,即如果某些权重使得损失函数达到最小值,这些权重就是我们寻找的最理想参数。 假设损失函数为 y = f(x),我们寻找其最小值,就是求这个函数的极值点,那么就是求其一阶导数 f’(x) = 0 这个微分方程的解。但是计算机不擅长求微分方程,所以只能通过插值等方法进行海量尝试,把函数的极值点求出来。 什么是导数呢?
什么是梯度呢?
在单变量的实值函数中,对于函数的某个特定点,它的梯度方向就表示从该点出发,函数值增长最为迅猛的方向或者说是函数导数变化率最大的方向。 对于机器学习/深度学习来说,梯度方向就是损失函数变化最快的方向,因为我们希望损失最小,所以我们就通常利用数值微分来计算神经网络权值参数的梯度,按照梯度下降来确定调参的方向,按照这个方向来优化。 1.6 梯度下降梯度下降的大致思路是:首先给参数 w, b 随机设定一些初值,然后采用迭代的算法,计算当前网络的输出,然后根据网络输出与预期输出之间的差值,反方向地去改变前面各层的参数,直至网络收敛稳定。 具体来说,就是:
? 当然,梯度下降有很多优化方法,具体逻辑各有不同。 1.7 反向传播说到back propagation算法,我们通常强调的是反向传播。其实在本质上,它是一个双向算法。也就是说,它其实是分两大步走:
具体如下图: 我们可以看到,这个图中涉及到了大量的梯度计算,于是又涉及到一个问题:这些梯度如何计算?深度学习框架,帮助我们解决的核心问题就是两个:
1.8 可微分编程1.8.1 可微分编程永生Yann Lecun在其博文 "深度学习已死,可微分编程永生” 之中提到:
1.8.2 深度学习成功的关键MIT媒体实验室的David Dalrymple 也介绍过可微分编程。Dalrymple认为,深度学习的成功有两大关键,一是反向传播,二是权重相关(weight-tying),这两大特性与函数编程(functional programing)中调用可重用函数十分相同。可微分编程有成为"timeless”的潜力。 反向传播以非常优雅的方式应用了链式规则(一个简单的微积分技巧),从而把连续数学和离散数学进行了深度整合,使复杂的潜在解决方案族可以通过向量微积分自主改进。 反向传播的关键是将潜在解决方案的模式(template)组织为一个有向图。通过反向遍历这个图,算法能够自动计算"梯度向量”,而这个"梯度向量" 能引导算法寻找越来越好的解决方案。 权重相关(weight-tying)是第二个关键之处,它使得同一个权重相关的网络组件可以同时在多个地方被使用,组件的每个副本都保持一致。Weight-tying 会使网络学习到更加泛化的能力,因为单词或者物体可能出现在文本块或图像的多个位置。权重相关(weight-tied)的组件,实际上与编程中可重用函数的概念相同(就类似于你编写一个函数,然后在程序中多个地方都进行调用),而且对组件的重用方式也与函数编程中通用的"高阶函数”生成的方式完全一致。 1.8.3 可微分编程可微分编程是一个比较新的概念,是反向传播和weight-tying的延伸。用户仅指定了函数的结构以及其调用顺序,函数程序实际上被编译成类似于反向传播所需的计算图。图的各个组成部分也必须是可微的,可微分编程把实现/部署的细节留给优化器——语言会使用反向传播根据整个程序的目标自动学习细节,基于梯度进行优化,就像优化深度学习中的权重一样。 特斯拉人工智能部门主管Andrej Karpathy也提出过一个"软件2.0”概念。 软件1.0(Software 1.0)是用Python、C++等语言编写,由对计算机的明确指令组成。通过编写每行代码,程序员可以确定程序空间中的某个特定点。 **Software 2.0 是用神经网络权重编写的。**没有人参与这段代码的编写。在软件2.0的情况下,人类对一个理想程序的行为指定一些约束(例如,输入输出数据集),并依据可用的计算资源来搜索程序空间中满足约束条件的程序。在这个空间中,搜索过程可以利用反向传播和随机梯度下降满足要求。 Karpathy认为,在现实世界中,大部分问题都是收集数据比明确地编写程序更容易。未来,大部分程序员不再需要维护复杂的软件库,编写复杂的程序,或者分析程序运行时间。他们需要做的是收集、整理、操作、标记、分析和可视化提供给神经网络的数据。 综上,既然知道了自动计算梯度的重要性,我们下面就来借助一篇论文 Automatic Differentiation in Machine Learning: a Survey 来具体学习一下。 0x02 微分方法2.1 常见方法我们首先看看微分的几种比较常用的方法:
具体如下图: 2.2 手动微分手动微分就是对每一个目标函数都需要利用求导公式手动写出求导公式,然后依照公式编写代码,带入数值,求出最终梯度。 这种方法准确有效,但是不适合工程实现,因为通用性和灵活性很差,每一次我们修改算法模型,都要修改对应的梯度求解算法。如果模型复杂或者项目频繁反复迭代,那么算法工程师 别说 996 了,就是 365 x 24 也顶不住。 2.3 数值微分数值微分方式应该是最直接而且简单的一种自动求导方式。从导数的原始定义中,我们可以直观看到前向差分公式为: 当h取很小的数值,比如0.000001 时,导数是可以利用差分来近似计算出来的。只需要给出函数值以及自变量的差值,数值微分算法就可计算出导数值。单侧差分公式根据导数的定义直接近似计算某一点处的导数值。 数值微分的优点是:
但是,数值微分有几个问题:
为了缓解截断错误,人们提出了中心微分近似(center difference approximation),这方法仍然无法解决舍入误差,只是减少误差,但是它比单侧差分公式有更小的误差和更好的稳定性。具体公式如下: 虽然数值微分有一些缺点,但是好处是简单实现,所以可以用来校验其他算法所得到梯度的正确性,比如"gradient check"就是利用数值微分法。 2.4 符号微分符号微分(Symbolic Differentiation)属符号计算的范畴,利用求导规则对表达式进行自动计算,其计算结果是导函数的表达式。符号计算用于求解数学中的公式解(也称解析解),得到的是 解的表达式而非具体的数值。 符号微分适合符号表达式的自动求导,符号微分的原理是用下面的简单求导规则替代手动微分: 符号微分利用代数软件,实现微分的一些公式,然后根据基本函数的求导公式以及四则运算、复合函数的求导法则,将公式的计算过程转化成微分过程,这样就可以对用户提供的具有closed form的数学表达式进行"自动微分"求解。就是先求解析解,然后转换为程序,再通过程序计算出函数的梯度。 符号微分计算出的表达式需要用字符串或其他数据结构存储,如表达式树。数学软件如Mathematica,Maple,matlab中实现了这种技术。python语言的符号计算库也提供了这类算法。 符号微分的问题是:
表达式膨胀如下图所示,稍不注意,符号微分求解就会如下中间列所示,表达式急剧膨胀,导致问题求解也随着变慢,计算上的冗余且成本高昂: 其实,对于机器学习中的应用,不需要得到导数的表达式,而只需计算函数在某一点处的导数值。 2.5 自动微分2.5.1 中间方法自动微分是介于数值微分和符号微分之间的方法,采用类似有向图的计算来求解微分值。
关于解析解我们还要做一些说明。几乎所有机器学习算法在训练或预测时都可以归结为求解最优化问题,如果目标函数可导,则问题就变为求训练函数的驻点。但是通常情况下我们无法得到驻点的解析解,因此只能采用数值优化算法,如梯度下降法,牛顿法,拟牛顿法等等。这些数值优化算法都依赖于函数的一阶导数值或二阶导数值(包括梯度与Hessian矩阵)。因此需要解决如何求一个复杂函数的导数问题,自动微分技术是解决此问题的一种通用方法。 由于自动微分法只对基本函数或常数运用符号微分法则,所以它可以灵活结合编程语言的循环结构,条件结构等。使用自动微分和不使用自动微分对代码总体改动非常小,由于它实际是一种图计算,可以对其做很多优化,所以该方法在现代深度学习系统中得到广泛应用。 2.5.2 数学基础自动微分 (AD)是用程序来自动化推导Jacobian矩阵或者其中的一部分,是计算因变量对某个自变量导数的一种数值计算方式,所以其数学基础是链式求导法则和雅克比矩阵。 2.5.2.1 链式求导在计算链式法则之前,我们先回顾一下复合函数。复合函数在本质上就是有关函数的函数(function of functions)。它将一个函数的返回值作为参数传递给另一个函数,并且将另一个函数的返回值作为参数再传递给下一个函数,也就是 函数套函数,把几个简单的函数复合为一个较为复杂的函数。 链式法则是微积分中的求导法则,用于求一个复合函数的导数,是在微积分的求导运算中一种常用的方法。复合函数的导数将是构成复合这有限个函数在相应点的 导数的乘积,就像锁链一样一环套一环,故称链式法则。 比如求导: 2.5.2.2 雅克比矩阵在向量微积分中,雅可比矩阵是一阶偏导数以一定方式排列成的矩阵,其行列式称为雅可比行列式。雅可比矩阵的重要性在于它体现了一个可微方程与给出点的最优线性逼近。 雅可比矩阵表示两个向量所有可能的偏导数。它是一个向量相对于另一个向量的梯度,其实现的是 n维向量 到 m 维向量的映射。 在矢量运算中,雅克比矩阵是基于函数对所有变量一阶偏导数的数值矩阵,当输入个数 = 输出个数时又称为雅克比行列式。 假设输入向量 x ∈ R n x∈Rn x∈Rn,而输出向量 y ∈ R m y∈Rm y∈Rm,则Jacobian矩阵定义为: 0xEE 个人信息★★★★★★关于生活和技术的思考★★★★★★ 微信公众账号:罗西的思考 如果您想及时得到个人撰写文章的消息推送,或者想看看个人推荐的技术资料,敬请关注。 0xFF 参考https://en.wikipedia.org/wiki/Automatic_differentiation 自动微分(Automatic Differentiation) 自动微分(Automatic Differentiation)简介——tensorflow核心原理 【深度学习理论】一文搞透梯度下降Gradient descent 梯度下降算法(Gradient Descent)的原理和实现步骤 【深度学习理论】纯公式手推+代码撸——神经网络的反向传播+梯度下降 Automatic Differentiation in Machine Learning: a Survey 自动微分(Automatic Differentiation)简介 Automatic Differentiation in Machine Learning: a Survey 自动微分(Automatic Differentiation)简介 PyTorch 的 backward 为什么有一个 grad_variables 参数? BACKPACK: PACKING MORE INTO BACKPROP 【深度学习理论】一文搞透pytorch中的tensor、autograd、反向传播和计算图 [PyTorch 学习笔记] 1.5 autograd 与逻辑回归 OpenMMLab:PyTorch 源码解读之 torch.autograd:梯度计算详解 https://zhuanlan.zhihu.com/p/348555597) 自动微分(Automatic Differentiation)简介 https://zhuanlan.zhihu.com/p/163892899 |
|
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 | -2024/11/27 10:28:21- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |