深度学习框架计算图复现

本文深入探讨了深度学习框架中计算图的实现,包括前馈计算图的前向与梯度计算、全连接神经网络的前向传播和梯度计算,以及卷积神经网络和残差网络的计算细节。通过对各种计算节点的梯度计算和参数更新的解释,展示了如何在实际网络中构建和优化计算图。
摘要由CSDN通过智能技术生成

参考与评述

参考书目《Deep Learning》Lan Goodfellow.
经典的深度学习框架是以计算图&梯度下降方法实现对前馈网络的有监督学习。
这里复现了前馈计算图的梯度计算实现。


一、前馈计算图实现

1. 前向与梯度计算

  • 结果数组 (保存输入节点与计算节点的输出值,能够反映节点在计算方向的拓扑排序)
  • 梯度数组 (保存输入节点与计算节点的梯度,能够反映节点在计算方向的拓扑排序)
  • 连接图 (反映每个节点的父节点)
  • 输出函数集合 (反映每个计算节点如何根据其输入得到输出)
  • 梯度函数集合 (反映每个计算节点如何根据输入和它的梯度计算对其任意父节点的梯度)

即可组成一个完整前馈计算图。
我们以下图所示全连接神经网络为例构建计算图(我们将每个神经元看作一个节点)。

(1)\---/(3)\---/(5)\
     X       X      (7)--(8)-->
(2)/---\(4)/---\(6)/

其中(1)(2)为输入点,(3)(4)(5)(6)为隐层,(7)为输出层,(8)为计算Loss的输出。这样,除了(1)(2)外其它都是计算节点。我们可以为该网络定义一个包含8个元素的数组,以及计算关系。

数组及连接图如下:

//结果数组与梯度数组,我们把输入节点放到计算节点之前
list=[1] [2] [3] [4] [5] [6] [7] [8]
grad=[1] [2] [3] [4] [5] [6] [7] [8]
//父节点集合
Par[1]=null  Par[2]=null
Par[3]=1,2   Par[4]=1,2   //注意由于是前馈网络,Pa(i)=j则i>j
Par[5]=3,4   Par[6]=3,4   
Par[7]=5,6   Par[8]=7

计算节点输出函数集合如下:(以下输出均为标量,输入 x x 为向量)

F u n ( i , x ) = s i g m o i d ( b i + j w i j x j ) , i [ 3 , 7 ] F u n ( 8 , x ) = 0.5 ( x E ) 2

计算节点梯度函数集合如下:
注: dcFun(i,x,p) ,即求节点i在输入x下的输出对其父节点p的输出的偏导数。

dcFun(i,x,p)=sigmoid(bi+jwijxj)wip,i[3,7]dcFun(8,x,p)=(xE) d c F u n ( i , x , p ) = s i g m o i d ′ ( b i + ∑ j w i j ∗ x j ) ∗ w i p , i ∈ [ 3 , 7 ] d c F u n ( 8 , x , p ) = ( x − E )

先解释下下面所用到的一些方法。

Par[i]->get_output_array(); //返回节点i的所有父节点的输出列表,即i节点输入向量
Par[i]->get_index_array();  //返回节点i的所有父节点的索引列表
L.has_element();            //列表中还有值存在
L.get_next_element();       //返回列表下一个值
put_input_in(list,i,j);     //向list的i到j索引处输入值

前馈实现:

//前馈计算
put_input_in(list,1,2);
for(i=3;i<=8;i++)
    list[i]=Fun(i,Par[i]->get_output_array());

前馈传播之后,为了最小化最终输出list[8] ,即由(8)定义的损失函数输出,我们需要计算每一节点的梯度。
反馈实现:

//反馈梯度计算
for(i=1;i<8;i++) grad[i]=0; //清空梯度数组
grad[8]=1;
for(i=8;i>=3;i--) //迭代每个计算节点,累加其各个父节点梯度
{
    input=Par[i]->get_output_array();
    par_array=Par[i]->get_index_array();
    while(par_array.has_element()) //迭代本节点的所有父节点
    {
        par_index=par_array.get_next_element();
        grad[par_index]+=grad[i]*dcFun(i,input,par_index); 
        //这里dcFun(c,x,p)即求节点c在输入x下的输出对其父节点p的输出的偏导数
    }
}

以计算(4)节点的输出梯度为例。我们先得到其子节点(5)和(6)的梯度。则
grad[4]=grad[5](54)+grad[6](64) g r a d [ 4 ] = g r a d [ 5 ] ∗ ( 5 对 4 输 出 的 偏 导 ) + g r a d [ 6 ] ∗ ( 6 对 4 输 出 的 偏 导 )
如何求5对4输出的偏导?我们由公式推导。
out5=sigmoid(out3w51+out4w52+b5) o u t 5 = s i g m o i d ( o u t 3 ∗ w 51 + o u t 4 ∗ w 52 + b 5 )
a5=out3w51+out4w52+b5 我 们 令 a 5 = o u t 3 ∗ w 51 + o u t 4 ∗ w 52 + b 5
out5out4=sigmoid(a5)w52 ∂ o u t 5 ∂ o u t 4 = s i g m o i d ′ ( a 5 ) ∗ w 52
这样我们可以得到grad[4]的表达式。
grad[4]=grad[5](sigmoid(a5)w52)+grad[6](sigmoid(a6)w62) g r a d [ 4 ] = g r a d [ 5 ] ∗ ( s i g m o i d ′ ( a 5 ) ∗ w 52 ) + g r a d [ 6 ] ∗ ( s i g m o i d ′ ( a 6 ) ∗ w 62 )
在反馈计算迭代到(5)(6)节点时,都会累加grad[4]这个值。
我们根据任意节点输出的梯度,以及其输入,就能调整这个节点的一些参数 。

2. 参数更新

在上一步中,我们得到了每个节点的输出,以及Loss对每个节点输出的梯度。
参数可以放在如上所示节点的内部,也可以单独作为一个节点的输出。
如果参数在节点内部:

LAW=LAoutAoutAW ∂ L ∂ A W = ∂ L ∂ A o u t ∂ A o u t ∂ A W

由于A的输出对其参数W的导数只由节点A决定,因此这些操作可以在计算所有梯度后并行执行。
如果参数由单个节点定义:

X  --A--->
    /     //参数放在W节点输出中,这样A就只是一个计算形式,需要计算材料X与W
   W      //这种形式在如Tensorflow框架中出现

这种形式中,我们将W当作一个输入节点,这样,在梯度计算时我们的A将会直接算出Loss对于W输出的梯度。


二、全连接神经网络

1. MLP前向计算

一个全连接神经网络(MLP)可以当作一个整体作为计算图中的一个计算节点,它有它的依赖,输出方法,以及求父节点梯度的计算方法,权值更新方法。为了方便易用,也可以每一层当作一个计算节点。(PyTorch)
我们还可以将权值放到某个输入节点中,为了区分它和输入,把它定义成变量节点。(Tensorflow)

Require: 网络深度l

Require: Wi , i1,...,lWii W i   ,   i ∈ 1 , . . . , l ( W i 的 每 一 列 表 示 i 层 某 个 神 经 元 的 全 部 权 值 )

Require: bi , i1,...,lbii b i   ,   i ∈ 1 , . . . , l ( b i 表 示 i 层 各 个 神 经 元 的 偏 置 )

Require: X,程序输入 (X每一行为一个输入样本,行数为多少批样本,应用SGD)

Require: Y,目标输出 (Y每一行为一个样本对应标签,行数为多少批样本标签)

H_{0}=X

for k=1:l do

Ak=bk+Hk1WkAkkHk=f(Ak)Ak线 A k = b k + H k − 1 W k ( A k 行 数 为 批 次 数 目 , 列 数 为 k 层 神 经 元 数 目 , 这 里 加 法 为 行 行 加 ) H k = f ( A k ) ( 对 A k 逐 元 素 计 算 非 线 性 函 数 )

end for

E=Hl E = H l
L=Loss(E,Y)+λΩ(θ)λΩ(θ) L = L o s s ( E , Y ) + λ Ω ( θ ) ( λ Ω ( θ ) 为 正 则 项 , 用 于 优 化 学 习 )

2. 对向量偏导的定义:

ymxn=y1x1y2x1...ymx1y1x2y2x2...ymx2............y1xny2xn...ymxnm×n ∂ y m ∂ x n = ( ∂ y 1 ∂ x 1 ∂ y 1 ∂ x 2 . . . ∂ y 1 ∂ x n ∂ y 2 ∂ x 1 ∂ y 2 ∂ x 2 . . . ∂ y 2 ∂ x n . . . . . . . . . . . . ∂ y m ∂ x 1 ∂ y m ∂ x 2 . . . ∂ y m ∂ x n ) m × n

zym=(zy1,zy2,...,zym)T ∂ z ∂ y m = ( ∂ z ∂ y 1 , ∂ z ∂ y 2 , . . . , ∂ z ∂ y m ) T

zxn=(ymxn)T(zym)=y1x1zy1+y2x1zy2+...y1x2zy1+y2x2zy2+......y1xnzy1+y2xnzy2+...n=mk=1zykykx1mk=1zykykx2...mk=1zykykxnn ∂ z ∂ x n = ( ∂ y m ∂ x n ) T ( ∂ z ∂ y m ) = ( ∂ y 1 ∂ x 1 ∂ z ∂ y 1 + ∂ y 2 ∂ x 1 ∂ z ∂ y 2 + . . . ∂ y 1 ∂ x 2 ∂ z ∂ y 1 + ∂ y 2 ∂ x 2 ∂ z ∂ y 2 + . . . . . . ∂ y 1 ∂ x n ∂ z ∂ y 1 + ∂ y 2 ∂ x n ∂ z ∂ y 2 + . . . ) n = ( ∑ k = 1 m ∂ z ∂ y k ∂ y k ∂ x 1 ∑ k = 1 m ∂ z ∂ y k ∂ y k ∂ x 2 . . . ∑ k = 1 m ∂ z ∂ y k ∂ y k ∂ x n ) n

3. 线性单元梯度计算:

已知 AB=C A B = C LC=G ∂ L ∂ C = G ,求 LALB ∂ L ∂ A 与 ∂ L ∂ B :( L L 对某个矩阵 X 的偏导 G G 的形式与 X 一模一样)

(a11a21a12a22a13a23)2×3×b11b21b31b12b22b323×2=(a11b11
今年的华为开发者大会 HDC 2020 上,除了**昇腾、鲲鹏等自研芯片硬件平台**之外,最令人期待的就是**深度学习框架 MindSpore 的开源**了。今天上午,华为 MindSpore **首席科学家陈雷**在活动中宣布这款产品正式开源,我们终于可以在开放平台上一睹它的真面目。 本文是根据机器之心报道的MindSpore 的开源介绍而整理的.md笔记 作为一款支持**端、边、云独立/协同的统一训练和推理框架,华为希望通过这款完整的软件堆栈,实现**一次性算子开发、一致的开发和调试体验**,以此帮助开发者实现**一次开发,应用在所有设备上平滑迁移**的能力。 三大创新能力:新编程范式,执行模式和协作方式 由**自动微分、自动并行、数据处理**等功能构成 开发算法即代码、运行高效、部署态灵活**的**特点**, 三层核心:从下往上分别是**后端运行时、计算引擎及前端表示层**。 最大特点:采用了业界最新的 **Source-to-Source 自动微分**,它能**利用编译器及编程语言的底层技术**,进一步**优化以支持更好的微分表达**。主流深度学习框架中主要有**三种自动微分技术,才用的不是静态计算、动态计算,而是基于**源码**转换:该技术源以**函数式编程框架**为基础,以**即时编译(JIT)**的方式**在中间表达(编译过程中程序的表达形式)上做自动微分变换**,支持**复杂控制流场景、高阶函数和闭包**。 MindSpore 主要概念就是张量、算子、单元和模型 其代码有两个比较突出的亮点:计算的调整,动态与静态可以一行代码切换;自动并行特性,我们写的串行代码,只需要多加一行就能完成自动并行。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值