深度学习为什么需要GPU

后使用快捷导航没有帐号?
查看: 53|回复: 5
上这门课有没有必要用GPU,用CPU算够么?
注册会员, 积分 173, 距离下一级还需 27 积分
论坛徽章:3
上这门课有没有必要用GPU,用CPU算够么?
金牌会员, 积分 1467, 距离下一级还需 1533 积分
论坛徽章:20
使用应该是够用的,就是会比较慢
论坛徽章:32
够,只是速度不够GPU快,有的程序运行需要花费点时间。
注册会员, 积分 174, 距离下一级还需 26 积分
论坛徽章:1
CPU也是可以的,不过速度有点慢,而且对电脑的性能要求高
中级会员, 积分 298, 距离下一级还需 202 积分
论坛徽章:14
同没有gpu,就想先学习keras
注册会员, 积分 199, 距离下一级还需 1 积分
论坛徽章:3
一般的电脑都会带个gpu吧,五六年前的也可以加速很多。
注册会员, 积分 74, 距离下一级还需 126 积分
论坛徽章:2
感觉我1700x的cpu在lstm方面比1070快,但用gpu算电脑不卡~~~
新手上路, 积分 0, 距离下一级还需 50 积分
论坛徽章:0
没用GPU,神经元层数一多,迭代个几十次就得等半天,CPU风扇狂转。
注册会员, 积分 92, 距离下一级还需 108 积分
论坛徽章:8
好文章,谢谢楼主分享
dataguru.cn All Right Reserved.208被浏览24,168分享邀请回答11912 条评论分享收藏感谢收起462 条评论分享收藏感谢收起CPU并非万能,深度学习为啥更看好GPU、FPGA发挥?-控制器/处理器-与非网
全称深度神经网络,本质上是多层次的人工神经网络算法,即模仿人脑的神经网络,从最基本的单元上模拟了人类大脑的运行机制。近年来,其所取得的前所未有的突破掀起了人工智能新一轮的发展热潮。
最早的神经网络的思想起源于 1943 年的 MCP 人工神经元模型,当时是希望能够用计算机来模拟人的神经元反应的过程,但直到最近,它才真正让人工智能火起来。主要原因在于:算法的突破、数据量的激增和计算机能力/成本的下降。其中计算能力的提升的作为人工智能实现的物理基础,对人工智能发展的意义不言而喻。
本文我们就来分析目前主流的深度学习芯片的优缺点。
不适合深度学习
深度学习与传统计算模式最大的区别就是不需要编程,它是从输入的大量数据中自发地总结出规律,而传统计算模式更多都需要人为提取所需解决问题的特征或者总结规律来进行编程。也正因为如此,深度学习对计算能力要求非常高,以至于有人将深度学习称之为&暴力计算&。
因此,传统的 CPU 并不适用于深度学习。
从内部结构上来看,CPU 中 70%晶体管都是用来构建 Cache(高速缓冲存储器)和一部分控制单元,负责逻辑运算的部分(ALU 模块)并不多。控制单元等模块的存在都是为了保证指令能够一条接一条的有序执行。
这种通用性结构对于传统的编程计算模式非常适合,但对于并不需要太多的程序指令,却需要海量数据运算的深度学习的计算需求,这种结构就显得有心无力了。
深度学习主流芯片
与 CPU 少量的逻辑运算单元相比,GPU 整个就是一个庞大的计算矩阵,GPU 具有数以千计的计算核心、可实现 10-100 倍应用吞吐量,而且它还支持对深度学习至关重要的并行计算能力,可以比传统处理器更加快速,大大加快了训练过程。GPU 是目前最普遍采用的深度学习运算单元之一。
目前,谷歌、Facebook、微软、Twitter 和百度等互联网巨头,都在使用 GPU 作为其深度学习载体,让服务器学习海量的照片、视频、声音文档,以及社交媒体上的信息,来改善搜索和自动化照片标记等各种各样的软件功能。而某些汽车制造商也在利用这项技术开发无人驾驶汽车。
不过,由于 GPU 的设计初衷是为了应对图像处理中需要大规模并行计算。因此,根据乐晴智库介绍,其在应用于深度学习算法时有数个方面的局限性:
第一, 应用过程中无法充分发挥并行计算优势。深度学习包含训练和应用两个计算环节,GPU 在深度学习算法训练上非常高效,但在应用时一次性只能对于一张输入图像进行处理, 并行度的优势不能完全发挥。
第二, 硬件结构固定不具备可编程性。深度学习算法还未完全稳定,若深度学习算法发生大的变化,GPU 无法灵活的配置硬件结构。
另外,在能耗上面,虽然 GPU 要好于 CPU,但其能耗仍旧很大。
备受看好的
FPGA,即现场可编辑门阵列,是一种新型的可编程逻辑器件,由于其具有静态可重复编程和动态在系统重构的特性,使得硬件的功能可以像软件一样通过编程来修改。
FPGA 作为人工智能深度学习方面的计算工具,主要原因就在于其本身特性:可编程专用性,高性能,低功耗。
北京大学与加州大学的一个关于 FPGA 加速深度学习算法的合作研究。展示了 FPGA 与 CPU 在执行深度学习算法时的耗时对比。在运行一次迭代时,使用 CPU 耗时 375 毫秒,而使用 FPGA 只耗时 21 毫秒,取得了 18 倍左右的加速比。
根据瑞士苏黎世联邦理工学院 (ETHZurich) 研究发现,基于 FPGA 的应用加速比 CPU/GPU 方案,单位功耗性能可提升 25 倍,而时延则缩短了 50 到 75 倍,与此同时还能实现出色的 I/O 集成。而微软的研究也表明,FPGA 的单位功耗性能是 GPU 的 10 倍以上,由多个 FPGA 组成的集群能达到 GPU 的图像处理能力并保持低功耗的特点。
根据英特尔预计,到 2020 年,将有 1/3 的云数据中心节点采用 FPGA 技术。
不可估量的 ASIC
ASIC(Application Specific Integrated Circuits,专用集成电路),是指应特定用户要求或特定电子系统的需要而设计、制造的集成电路。ASIC 用于专门的任务,比如去除噪声的电路,播放视频的电路,但是 ASIC 明显的短板是不可更改任务。但与通用集成电路相比,具有以下几个方面的优越性:体积更小、功耗更低、可靠性提高、性能提高、保密性增强、成本降低。
从算力上来说,ASIC 产品的计算能力是 GK210 的 2.5 倍。功耗上,ASIC 功耗做到了 GK210 的 1/15。
当然 ASIC 是能效最高的,但目前,都在早期阶段,算法变化各异。想搞一款通用的 ASIC 适配多种场景,还是有很多路需要走的。但从比特币挖矿机经历的从 CPU、GPU、FPGA 到最后 ASIC 的四个阶段来推论,ASIC 将是人工智能发展的重要趋势之一。另外,在通信领域,FPGA 曾经也是风靡一时,但是随着 ASIC 的不断发展和蚕食,FPGA 的份额和市场空间已经岌岌可危。
据了解,谷歌最近曝光的专用于人工智能深度学习计算的 TPU,其实也是一款 ASIC。
更多最新行业资讯,欢迎点击与非网!
与非网专栏作者招募
你也许是工程师甲,每天默默画电路板、写代码;
你也许是高校老师乙,每天站在三尺讲台,传授知识;
你也许是项目经理丙,每天为得到客户认可而赶工、奔忙;
不管你身处何地是何种身份,只要你是电子领域的从业者,就一定有对这一行业的一些感受和看法。
可能你已修炼成资深行业观察家,如老师那样真知灼见;
可能你善于分析行业趋势,如侃侃而谈;
可能你精通某一项技术,如那样精讲技术而不失幽默;
可能你善于发现身边的工程师故事,如般娓娓道来。
也可能你和他们都不同,有自己想发表的观点,这样的你都是我们在等的人,只要你准备好了,&与非网专栏作者&就会成为你的一个标签。你不再是普通的路人&甲、乙、丙&,而是工程师和电子产业的发言人。
我们给专栏作者的展示机会:
1. 与非网主站【与非原创】栏目的集中展示:
2. 与非网主页:首页焦点、行业发现的重点推荐
3. 与非网微信:原创推送,直达核心行业读者
4. 如果专栏内容热度很高,我们还可以帮助联系相关出版社洽谈集结出版。
成功取决于行动力,赶紧将你的职场态度和行业观点进行整理、提炼成专栏大纲吧,以&专栏作者+大纲名称&为主题,发送到:editor#eefocus.com(请将#替换为@)即可,或者你还有些疑惑想更多了解专栏作者的情况,也可以加小编的微信+qq:详谈。
与非网专栏作者,我们等你!
关注与非网微信 ( ee-focus )
限量版产业观察、行业动态、技术大餐每日推荐
享受快时代的精品慢阅读
与非网小编
电子行业垂直媒体--与非网小编一枚,愿从海量行业资讯中淘得几粒金沙,与你分享!
在超微挟2款全新GPU进军这块高度竞争市场下,基于具备一定绘图表现,甚至有助让游戏玩家购买超微APU下,便不再需要购买额外GPU,这似乎也形成另类有助缓解GPU短缺市况一大间接助益。
据Gizmodo报导,Ryzen 5 2400G零售价为170美元,Ryzen 3 2200G售价只有100美元,分别为255美元的i5-8600K及17
发表于: 14:12:29
终于,英伟达首次承认“挖矿”业务让公司赚了不少钱,并且,第四季度带来的收入高于第三季度。
发表于: 10:17:32
谷歌的机器学习利器Cloud TPU将首次全面对外开放。谷歌传奇芯片工程师Jeff Dean连发了十条twitter宣布了这一消息,第三方厂商和开发者可以每小时花费6.5美元来使用它,但需要先行填表申请。此前,TPU都被用于谷歌内部产品,随着Cloud TPU的开放,这意味着AI芯片和公有云市场将迎来新的变局。
发表于: 09:33:14
近期加密货币挖矿热潮带动对NVIDIA及超微(AMD)高端显卡需求量大增及价涨,这导致NVIDIA及超微供货不及市场需求涌现,因应此情况,NVIDIA近日曾要求零售商显卡优先供货给游戏玩家、实施限购策略以保护核心客群需求,超微则是宣布将加速生产更多GPU来缓解市场需求。
发表于: 08:40:02
终于,英伟达首次承认“挖矿”业务让公司赚了不少钱,并且,第四季度带来的收入高于第三季度。更重要的是,无论是深度学习、虚拟现实还是加密货币,都代表着GPU计算的时代正在到来,这是一股超强的趋势。
发表于: 13:57:03
在双摄和全面屏普及后,手机行业需要新的技术来激发消费者的购买意欲,那么5G和AI就成为目前手机行业新的催化剂,不过5G受限于技术标准和移动运营商的步伐,要到2019年下半年才能与普通消费者见面,而AI技术才是2018年真正的主角。
发表于: 08:34:22
北京时间2月15日早间消息,关于博通以1210亿美元收购高通的交易提议,两家公司之间的首次会谈本周结束。高通表示,董事会将举行会议,讨论下一步举措,但没有透露两家公司是否已接近达成协议。
发表于: 13:28:36
德国CB整理了Intel最新的CPU路线图。2018年到2019年:Coffee Lake是重点,Cascade Lake-SP第三季度推出。从第一张图可以看出,服务器/数据中心部分,也就是Xeon至强中,E3系列将在2018年Q2出新(E3 1200 v7已经更名为Xeon E),顶级的可扩展平台将更新到Cascade Lake-SP架
发表于: 14:02:03
产业界如此热火产天的发展,离不开学术界此前的长久积累。在过去的十几年里,清华微电子所的可重构计算团队一直在研究一项核心技术——“软件定义芯片”,前年,他们推出了一款代号为Thinker 1的AI芯片,这款芯片不仅能够支持人脸识别、语音识别的AI算法,而且芯片的功耗非常小——只需要7号AA电池就够让它运行一整年。
发表于: 14:18:11
三星将于2月25日在MWC大会上正式发布Galaxy S9/S9+。而除了已经曝光的骁龙845版本外,Galaxy S9系列还会推出搭载Exynos 9810处理器的版本,目前Exynos 9810的跑分已经曝光。
发表于: 14:02:38
与非门科技(北京)有限公司 All Rights Reserved.
京ICP证:070212号
北京市公安局备案编号: 京ICP备:号在 SegmentFault,学习技能、解决问题
每个月,我们帮助 1000 万的开发者解决各种各样的技术问题。并助力他们在技术能力、职业生涯、影响力上获得提升。
点击阅读原文
使用腾讯云GPU学习深度学习——2.Tensorflow 简明原理
日 发布,来源:
这是《使用腾讯云GPU学习深度学习》系列文章的第二篇,主要介绍了 Tensorflow 的原理,以及如何用最简单的Python代码进行功能实现。本系列文章主要介绍如何使用
进行深度学习运算,前面主要介绍原理部分,后期则以实践为主。
往期内容:
1. 神经网络原理
神经网络模型,是上一章节提到的典型的监督学习问题,即我们有一组输入以及对应的目标输出,求最优模型。通过最优模型,当我们有新的输入时,可以得到一个近似真实的预测输出。
我们先看一下如何实现这样一个简单的神经网络:
输入 x = [1,2,3],
目标输出 y = [-0.85, 0.72]
中间使用一个包含四个单元的隐藏层。
结构如图:
求所需参数 w1_0 w2_0 b1_0 b2_0, 使得给定输入 x 下得到的输出 ,和目标输出
之间的平均均方误差 (Mean Square Errors, MSE) 最小化 。
我们首先需要思考,有几个参数?由于是两层神经网络,结构如下图(图片来源), 其中输入层为 3,中间层为 4,输出层是 2:
因此,其中总共包含 (3x4+4) + (4*2+2) = 26 个参数需要训练。我们可以如图初始化参数。参数可以随机初始化,也可以随便指定:
import numpy as np
w1_0 = np.array([[ 0.1, 0.2, 0.3, 0.4],
[ 0.5, 0.6, 0.7, 0.8],
[ 0.9, 1.0, 1.1, 1.2]])
w2_0 = np.array([[ 1.3, 1.4],
[ 1.5, 1.6],
[ 1.7, 1.8],
[ 1.9, 2.0]])
b1_0 = np.array( [-2.0, -6.0, -1.0, -7.0])
b2_0 = np.array( [-2.5, -5.0])
我们进行一次正向传播:
x = [1,2,3]
y = [-0.85, 0.72]
o1 = np.dot(x, w1_0 ) + b1_0
os1 = np.power(1+np.exp(o1*-1), -1)
o2 = np.dot(os1, w2_0) + b2_0
os2 = np.tanh(o2)
再进行一次反向传播:
alpha = 0.1
grad_os2 = (y - os2) * (1-np.power(os2, 2))
grad_os1 = np.dot(w2_0, grad_os2.T).T * (1-os1)*os1
grad_w2 = ...
grad_b2 = ...
w2_0 = w2_0 + alpha * grad_w2
b2_0 = b2_0 + alpha * grad_b2
如此反复多次,直到最终误差收敛。进行反向传播时,需要将所有参数的求导结果都写上去,然后根据求导结果更新参数。我这里就没有写全,因为一层一层推导实在是太过麻烦。更重要的是,当我们需要训练新的神经网络结构时,这些都需要重新推导一次,费时费力。
然而仔细想一想,这个推导的过程也并非无规律可循。即上一级的神经网络梯度输出,会被用作下一级计算梯度的输入,同时下一级计算梯度的输出,会被作为上一级神经网络的输入。于是我们就思考能否将这一过程抽象化,做成一个可以自动求导的框架?OK,以 Tensorflow 为代表的一系列深度学习框架,正是根据这一思路诞生的。
2.深度学习框架
近几年最火的深度学习框架是什么?毫无疑问,Tensorflow 高票当选。
但实际上,这些深度学习框架都具有一些普遍特征。Gokula Krishnan Santhanam认为,:
张量(Tensor)
基于张量的各种操作
计算图(Computation Graph)
自动微分(Automatic Differentiation)工具
BLAS、cuBLAS、cuDNN等拓展包
其中,张量 Tensor 可以理解为任意维度的数组——比如一维数组被称作向量(Vector),二维的被称作矩阵(Matrix),这些都属于张量。有了张量,就有对应的基本操作,如取某行某列的值,张量乘以常数等。运用拓展包其实就相当于使用底层计算软件加速运算。
我们今天重点介绍的,就是计算图模型,以及自动微分两部分。首先介绍以 Torch 框架为例,谈谈如何实现自动求导,然后再用最简单的方法,实现这两部分。
2.1. 深度学习框架如何实现自动求导
诸如 Tensorflow 这样的深度学习框架的入门,网上有大量的 几行代码、几分钟入门这样的资料,可以快速实现手写数字识别等简单任务。但如果想深入了解 Tensorflow 的背后原理,可能就不是这么容易的事情了。这里我们简单的谈一谈这一部分。
我们知道,当我们拿到数据、训练神经网络时,网络中的所有参数都是 变量。训练模型的过程,就是如何得到一组最佳变量,使预测最准确的过程。这个过程实际上就是,输入数据经过 正向传播,变成预测,然后预测与实际情况的误差 反向传播 误差回来,更新变量。如此反复多次,得到最优的参数。这里就会遇到一个问题,神经网络这么多层,如何保证正向、反向传播都可以正确运行?
值得思考的是,这两种传播方式,都具有 管道传播 的特征。正向传播一层一层算就可以了,上一层网络的结果作为下一层的输入。而反向传播过程可以利用 链式求导法则,从后往前,不断将误差分摊到每一个参数的头上。
图片来源:
进过抽象化后,我们发现,深度学习框架中的 每一个模块都需要两个函数,一个连接正向,一个连接反向。这里的正向和反向,如同武侠小说中的 任督二脉。而训练模型的过程,数据通过正向传播生成预测结果,进而将误差反向传回更新参数,就如同让真气通过任督二脉在体内游走,随着训练误差逐渐缩小收敛,深度神经网络也将打通任督二脉。
接下来,我们将首先审视一下 Torch 框架的源码如何实现这两部分内容,其次我们通过 Python 直接编写一个最简单的深度学习框架。
举 Torch 的 nn 项目的例子是因为Torch 的代码文件结构比较简单,Tensorflow 的规律和Torch比较近似,但文件结构相对更加复杂,有兴趣的可以仔细读读。
这个目录下的几乎所有 .lua 文件,都有这两个函数:
function xxx:updateOutput(input)
input.THNN.xxx_updateOutput(
input:cdata(),
self.output:cdata()
return self.output
function xxx:updateGradInput(input, gradOutput)
input.THNN.xxx_updateGradInput(
input:cdata(),
gradOutput:cdata(),
self.gradInput:cdata(),
self.output:cdata()
return self.gradInput
这里其实是相当于留了两个方法的定义,没有写具体功能。具体功能的代码,在
中用 C 实现实现,具体以 Sigmoid 函数举例。
我们知道 Sigmoid 函数的形式是:
代码实现起来是这样:
void THNN_(Sigmoid_updateOutput)( THNNState
*state, THTensor
*input, THTensor
THTensor_(resizeAs)(output, input);
TH_TENSOR_APPLY2(real, output, real, input,
*output_data = 1./(1.+ exp(- *input_data));
Sigmoid 函数求导变成:
所以这里在实现的时候就是:
void THNN_(Sigmoid_updateGradInput)(
THNNState *state,
THTensor *input,
THTensor *gradOutput,
THTensor *gradInput,
THTensor *output)
THNN_CHECK_NELEMENT(input, gradOutput);
THTensor_(resizeAs)(gradInput, output);
TH_TENSOR_APPLY3(real, gradInput, real, gradOutput, real, output,
real z = * output_
*gradInput_data = *gradOutput_data * (1. - z) *
大家应该注意到了一点, updateOutput 函数, output_data 在等号左边, input_data 在等号右边。 而 updateGradInput 函数, gradInput_data 在等号左边, gradOutput_data 在等号右边。 这里,output = f(input) 对应的是 正向传播 input = f(output) 对应的是 反向传播。
1.2 用 Python 直接编写一个最简单的深度学习框架
这部分内容属于“造轮子”,并且借用了优达学城的一个小型项目 。
数据结构部分
首先,我们实现一个父类 Node,然后基于这个父类,依次实现 Input Linear Sigmoid 等模块。这里运用了简单的 Python 。这些模块中,需要将 forward 和 backward 两个方法针对每个模块分别重写。
代码如下:
class Node(object):
Base class for nodes in the network.
Arguments:
`inbound_nodes`: A list of nodes with edges into this node.
def __init__(self, inbound_nodes=[]):
Node's constructor (runs when the object is instantiated). Sets
properties that all nodes need.
# A list of nodes with edges into this node.
self.inbound_nodes = inbound_nodes
# The eventual value of this node. Set by running
# the forward() method.
self.value = None
# A list of nodes that this node outputs to.
self.outbound_nodes = []
# New property! Keys are the inputs to this node and
# their values are the partials of this node with
# respect to that input.
self.gradients = {}
# Sets this node as an outbound node for all of
# this node's inputs.
for node in inbound_nodes:
node.outbound_nodes.append(self)
def forward(self):
Every node that uses this class as a base class will
need to define its own `forward` method.
raise NotImplementedError
def backward(self):
Every node that uses this class as a base class will
need to define its own `backward` method.
raise NotImplementedError
class Input(Node):
A generic input into the network.
def __init__(self):
Node.__init__(self)
def forward(self):
def backward(self):
self.gradients =
for n in self.outbound_nodes:
self.gradients[self] += n.gradients[self]
class Linear(Node):
Represents a node that performs a linear transform.
def __init__(self, X, W, b):
Node.__init__(self, [X, W, b])
def forward(self):
Performs the math behind a linear transform.
X = self.inbound_nodes[0].value
W = self.inbound_nodes[1].value
b = self.inbound_nodes[2].value
self.value = np.dot(X, W) + b
def backward(self):
Calculates the gradient based on the output values.
self.gradients =
for n in self.outbound_nodes:
grad_cost = n.gradients[self]
self.gradients[self.inbound_nodes[0]] += np.dot(grad_cost, self.inbound_nodes[1].value.T)
self.gradients[self.inbound_nodes[1]] += np.dot(self.inbound_nodes[0].value.T, grad_cost)
self.gradients[self.inbound_nodes[2]] += np.sum(grad_cost, axis=0, keepdims=False)
class Sigmoid(Node):
Represents a node that performs the sigmoid activation function.
def __init__(self, node):
Node.__init__(self, [node])
def _sigmoid(self, x):
This method is separate from `forward` because it
will be used with `backward` as well.
`x`: A numpy array-like object.
return 1. / (1. + np.exp(-x))
def forward(self):
Perform the sigmoid function and set the value.
input_value = self.inbound_nodes[0].value
self.value = self._sigmoid(input_value)
def backward(self):
Calculates the gradient using the derivative of
the sigmoid function.
self.gradients =
for n in self.outbound_nodes:
grad_cost = n.gradients[self]
sigmoid = self.value
self.gradients[self.inbound_nodes[0]] += sigmoid * (1 - sigmoid) * grad_cost
class Tanh(Node):
def __init__(self, node):
The tanh cost function.
Should be used as the last node for a network.
Node.__init__(self, [node])
def forward(self):
Calculates the tanh.
input_value = self.inbound_nodes[0].value
self.value = np.tanh(input_value)
def backward(self):
Calculates the gradient of the cost.
self.gradients =
for n in self.outbound_nodes:
grad_cost = n.gradients[self]
tanh = self.value
self.gradients[self.inbound_nodes[0]] += (1 + tanh) * (1 - tanh) * grad_cost.T
class MSE(Node):
def __init__(self, y, a):
The mean squared error cost function.
Should be used as the last node for a network.
Node.__init__(self, [y, a])
def forward(self):
Calculates the mean squared error.
y = self.inbound_nodes[0].value.reshape(-1, 1)
a = self.inbound_nodes[1].value.reshape(-1, 1)
self.m = self.inbound_nodes[0].value.shape[0]
self.diff = y - a
self.value = np.mean(self.diff**2)
def backward(self):
Calculates the gradient of the cost.
self.gradients[self.inbound_nodes[0]] = (2 / self.m) * self.diff
self.gradients[self.inbound_nodes[1]] = (-2 / self.m) * self.diff
调度算法与优化部分
优化部分则会在以后的系列中单独详细说明。这里主要将简单讲一下图计算的算法调度。就是实际上Tensorflow的各个模块会生成一个有向无环图,如下图(来源):
在计算过程中,几个模块存在着相互依赖关系,比如要计算模块1,就必须完成模块3和模块4,而要完成模块3,就需要在之前顺次完成模块5、2;因此这里可以使用 Kahn 算法作为调度算法(下面的 topological_sort 函数),从计算图中,推导出类似 5-&2-&3-&4-&1 的计算顺序。
def topological_sort(feed_dict):
Sort the nodes in topological order using Kahn's Algorithm.
`feed_dict`: A dictionary where the key is a `Input` Node and the value is the respective value feed to that Node.
Returns a list of sorted nodes.
input_nodes = [n for n in feed_dict.keys()]
nodes = [n for n in input_nodes]
while len(nodes) & 0:
n = nodes.pop(0)
if n not in G:
G[n] = {'in': set(), 'out': set()}
for m in n.outbound_nodes:
if m not in G:
G[m] = {'in': set(), 'out': set()}
G[n]['out'].add(m)
G[m]['in'].add(n)
nodes.append(m)
S = set(input_nodes)
while len(S) & 0:
n = S.pop()
if isinstance(n, Input):
n.value = feed_dict[n]
L.append(n)
for m in n.outbound_nodes:
G[n]['out'].remove(m)
G[m]['in'].remove(n)
if len(G[m]['in']) == 0:
def forward_and_backward(graph):
Performs a forward pass and a backward pass through a list of sorted Nodes.
Arguments:
`graph`: The result of calling `topological_sort`.
for n in graph:
n.forward()
for n in graph[::-1]:
n.backward()
def sgd_update(trainables, learning_rate=1e-2):
Updates the value of each trainable with SGD.
Arguments:
`trainables`: A list of `Input` Nodes representing weights/biases.
`learning_rate`: The learning rate.
for t in trainables:
t.value = t.value - learning_rate * t.gradients[t]
import numpy as np
from sklearn.utils import resample
np.random.seed(0)
w1_0 = np.array([[ 0.1, 0.2, 0.3, 0.4],
[ 0.5, 0.6, 0.7, 0.8],
[ 0.9, 1.0, 1.1, 1.2]])
w2_0 = np.array([[ 1.3, 1.4],
[ 1.5, 1.6],
[ 1.7, 1.8],
[ 1.9, 2.0]])
b1_0 = np.array( [-2.0, -6.0, -1.0, -7.0])
b2_0 = np.array( [-2.5, -5.0])
X_ = np.array([[1.0, 2.0, 3.0]])
y_ = np.array([[-0.85, 0.75]])
n_features = X_.shape[1]
W1_ = w1_0
b1_ = b1_0
W2_ = w2_0
b2_ = b2_0
X, y = Input(), Input()
W1, b1 = Input(), Input()
W2, b2 = Input(), Input()
l1 = Linear(X, W1, b1)
s1 = Sigmoid(l1)
l2 = Linear(s1, W2, b2)
t1 = Tanh(l2)
cost = MSE(y, t1)
feed_dict = {
X: X_, y: y_,
W1: W1_, b1: b1_,
W2: W2_, b2: b2_
epochs = 10
m = X_.shape[0]
batch_size = 1
steps_per_epoch = m // batch_size
graph = topological_sort(feed_dict)
trainables = [W1, b1, W2, b2]
l_Mat_W1 = [w1_0]
l_Mat_W2 = [w2_0]
l_Mat_out = []
l_val = []
for i in range(epochs):
for j in range(steps_per_epoch):
X_batch, y_batch = resample(X_, y_, n_samples=batch_size)
X.value = X_batch
y.value = y_batch
forward_and_backward(graph)
sgd_update(trainables, 0.1)
loss += graph[-1].value
mat_W1 = []
mat_W2 = []
for i in graph:
if (i.value.shape[0] == 3) and (i.value.shape[1] == 4):
mat_W1 = i.value
if (i.value.shape[0] == 4) and (i.value.shape[1] == 2):
mat_W2 = i.value
l_Mat_W1.append(mat_W1)
l_Mat_W2.append(mat_W2)
l_Mat_out.append(graph[9].value)
来观察一下。当然还有更高级的可视化方法:
import matplotlib.pyplot as plt
%matplotlib inline
fig = plt.figure( figsize=(14,10))
ax0 = fig.add_subplot(131)
#aax0 = fig.add_axes([0, 0, 0.3, 0.1])
c0 = ax0.imshow(np.array(l_Mat_out).reshape([-1,2]).T, interpolation='nearest',aspect='auto', cmap="Reds", vmax=1, vmin=-1)
ax0.set_title("Output")
cbar = fig.colorbar(c0, ticks=[-1, 0, 1])
ax1 = fig.add_subplot(132)
c1 = ax1.imshow(np.array(l_Mat_W1).reshape(len(l_Mat_W1), 12).T, interpolation='nearest',aspect='auto', cmap="Reds")
ax1.set_title("w1")
cbar = fig.colorbar(c1, ticks=[np.min(np.array(l_Mat_W1)), np.max(np.array(l_Mat_W1))])
ax2 = fig.add_subplot(133)
c2 = ax2.imshow(np.array(l_Mat_W2).reshape(len(l_Mat_W2), 8).T, interpolation='nearest',aspect='auto', cmap="Reds")
ax2.set_title("w2")
cbar = fig.colorbar(c2, ticks=[np.min(np.array(l_Mat_W2)), np.max(np.array(l_Mat_W2))])
ax0.set_yticks([0,1])
ax0.set_yticklabels(["out0", "out1"])
ax1.set_xlabel("epochs")
#for i in range(len(l_Mat_W1)):
我们注意到,随着训练轮数 Epoch 不断增多, Output 值从最初的 [0.72, -0.88] 不断接近 y = [-0.85, 0.72], 其背后的原因,是模型参数不断的从初始化的值变化、更新,如图中的 w1 w2 两个矩阵。
好了,最简单的轮子已经造好了。 我们的轮子,实现了 Input Linear Sigmoid Tanh 以及 MSE 这几个模块。 接下来的内容,我们将基于现在最火的轮子 Tensorflow,详细介绍一下更多的模块。
最后,本篇只是造了个最基本的轮子,我们集智的知乎专栏上,有一个系列文章,正在介绍如何在Matlab上手写深度学习框架,传送门: ,欢迎大家围观。
目前腾讯云 GPU 服务器还在内测阶段,暂时没有申请到内测资格的读者也可以使用普通的云服务器运行本讲的代码。但从第三讲开始,我们将逐渐开始使用 Tensorflow 框架分析相关数据,对应的计算量大大增加,必须租用
才可以快速算出结果。服务器的租用方式,以及 Python 编程环境的搭建,我们将以腾讯云 GPU 为例,在接下来的内容中和大家详细介绍。
我要该,理由是:
关闭理由:
删除理由:
忽略理由:
推广(招聘、广告、SEO 等)方面的内容
与已有问题重复(请编辑该提问指向已有相同问题)
答非所问,不符合答题要求
宜作评论而非答案
带有人身攻击、辱骂、仇恨等违反条款的内容
无法获得确切结果的问题
非开发直接相关的问题
非技术提问的讨论型问题
其他原因(请补充说明)

我要回帖

 

随机推荐