tensorflow的广播机制
TensorFlow支持广播机制(Broadcast),可以广播元素间操作(elementwise operations)。正常情况下,当你想要进行一些操作如加法,乘法时,你需要确保操作数的形状是相匹配的,如:你不能将一个具有形状[3, 2]的张量和一个具有[3,4]形状的张量相加。但是,这里有一个特殊情况,那就是当你的其中一个操作数是一个具有单独维度(singular dimension)的张量的时候,TF会隐式地在它的单独维度方向填满(tile),以确保和另一个操作数的形状相匹配。所以,对一个[3,2]的张量和一个[3,1]的张量相加在TF中是合法的。(译者:这个机制继承自numpy的广播功能。其中所谓的单独维度就是一个维度为1,或者那个维度缺失)
import tensorflow as tf a = tf.constant([[1., 2.], [3., 4.]])
b = tf.constant([[1.], [2.]])
# c = a + tf.tile(b, [1, 2])
c = a + b
广播机制允许我们在隐式情况下进行填充(tile),而这可以使得我们的代码更加简洁,并且更有效率地利用内存,因为我们不需要另外储存填充操作的结果。一个可以表现这个优势的应用场景就是在结合具有不同长度的特征向量的时候。为了拼接具有不同长度的特征向量,我们一般都先填充输入向量,拼接这个结果然后进行之后的一系列非线性操作等。这是一大类神经网络架构的共同套路(common pattern)
a = tf.random_uniform([5, 3, 5])
b = tf.random_uniform([5, 1, 6]) # concat a and b and apply nonlinearity
tiled_b = tf.tile(b, [1, 3, 1])
c = tf.concat([a, tiled_b], 2)
d = tf.layers.dense(c, 10, activation=tf.nn.relu)
但是这个可以通过广播机制更有效地完成。我们利用事实f(m(x+y))=f(mx+my)f(m(x+y))=f(mx+my),简化我们的填充操作。因此,我们可以分离地进行这个线性操作,利用广播机制隐式地完成拼接操作。
pa = tf.layers.dense(a, 10, activation=None)
pb = tf.layers.dense(b, 10, activation=None)
d = tf.nn.relu(pa + pb)
事实上,这个代码足够通用,并且可以在具有抽象形状(arbitrary shape)的张量间应用:
def merge(a, b, units, activation=tf.nn.relu):
pa = tf.layers.dense(a, units, activation=None)
pb = tf.layers.dense(b, units, activation=None)
c = pa + pb
if activation is not None:
c = activation(c)
return c
一个更为通用函数形式如上所述:
目前为止,我们讨论了广播机制的优点,但是同样的广播机制也有其缺点,隐式假设几乎总是使得调试变得更加困难,考虑下面的例子:
a = tf.constant([[1.], [2.]])
b = tf.constant([1., 2.])
c = tf.reduce_sum(a + b)
你猜这个结果是多少?如果你说是6,那么你就错了,答案应该是12.这是因为当两个张量的阶数不匹配的时候,在进行元素间操作之前,TF将会自动地在更低阶数的张量的第一个维度开始扩展,所以这个加法的结果将会变为[[2, 3], [3, 4]],所以这个reduce的结果是12.
(译者:答案详解如下,第一个张量的shape为[2, 1],第二个张量的shape为[2,]。因为从较低阶数张量的第一个维度开始扩展,所以应该将第二个张量扩展为shape=[2,2],也就是值为[[1,2], [1,2]]。第一个张量将会变成shape=[2,2],其值为[[1, 1], [2, 2]]。)
解决这种麻烦的方法就是尽可能地显示使用。我们在需要reduce某些张量的时候,显式地指定维度,然后寻找这个bug就会变得简单:
a = tf.constant([[1.], [2.]])
b = tf.constant([1., 2.])
c = tf.reduce_sum(a + b, 0)
这样,c的值就是[5, 7],我们就容易猜到其出错的原因。一个更通用的法则就是总是在reduce操作和在使用tf.squeeze中指定维度。
tensorflow的广播机制的更多相关文章
- numpy和tensorflow中的广播机制
广播的引出 numpy两个数组的相加.相减以及相乘都是对应元素之间的操作. import numpy as np x = np.array([[2,2,3],[1,2,3]]) y = np.arra ...
- [开发技巧]·Numpy广播机制的深入理解与应用
[开发技巧]·Numpy广播机制的深入理解与应用 1.问题描述 我们在使用Numpy进行数据的处理时,经常会用到广播机制来简化操作,例如在所有元素都加上一个数,或者在某些纬度上作相同的操作.广播机制很 ...
- numpy中的广播机制
广播的引出 numpy两个数组的相加.相减以及相乘都是对应元素之间的操作. import numpy as np x = np.array([[2,2,3],[1,2,3]]) y = np.arra ...
- Android随笔之——Android广播机制Broadcast详解
在Android中,有一些操作完成以后,会发送广播,比如说发出一条短信,或打出一个电话,如果某个程序接收了这个广播,就会做相应的处理.这个广播跟我们传统意义中的电台广播有些相似之处.之所以叫做广播,就 ...
- Android广播机制的深入学习
部分内容转载自http://www.cnblogs.com/lwbqqyumidi/p/4168017.html 1.Android广播机制概述 Android广播分为两个方面:广播发送者和广播接收者 ...
- Android总结篇系列:Android广播机制
1.Android广播机制概述 Android广播分为两个方面:广播发送者和广播接收者,通常情况下,BroadcastReceiver指的就是广播接收者(广播接收器).广播作为Android组件间的通 ...
- 九、Android学习第八天——广播机制与WIFI网络操作(转)
(转自:http://wenku.baidu.com/view/af39b3164431b90d6c85c72f.html) 九.Android学习第八天——广播机制与WIFI网络操作 今天熟悉了An ...
- Android 中的消息传递,详解广播机制
--------------------------------------广播机制简介--------------------------------------------- Android中的广 ...
- Android广播机制简介
为什么说Android中的广播机制更加灵活呢?这是因为Android中的每个应用程序都可以对自己感兴趣的广播进行注册,这样该程序就只会接收到自己所关心的广播内容,这些广播可能是来自于系统的,也可能是来 ...
随机推荐
- (九) SpringBoot起飞之路-整合/集成Swagger 2 And 3
兴趣的朋友可以去了解一下其他几篇,你的赞就是对我最大的支持,感谢大家! (一) SpringBoot起飞之路-HelloWorld (二) SpringBoot起飞之路-入门原理分析 (三) Spri ...
- 《我想进大厂》之Redis夺命连环11问
这是面试题系列第三篇--redis专题. 说说Redis基本数据类型有哪些吧 字符串:redis没有直接使用C语言传统的字符串表示,而是自己实现的叫做简单动态字符串SDS的抽象类型.C语言的字符串不记 ...
- Docker笔记4:在 CentOS 上安装 Docker
Docker 是一个开源的应用容器引擎,主要有两个分支,一个是社区免费版(Docker CE),一个是企业版(Docker EE). 第1步:系统环境要求 Docker 支持的 CentOS 版本: ...
- Oracle - ascii为0的陷阱
一.概述 ascii0是个空字符,如果将这个字符插入到oracle数据库中会是什么现象,是null吗? 二.正式实验 创建一张测试表 create table test(id int, name va ...
- idea如何新建一个springmvc 工程
java 版本 1.8.0_261 idea 版本2020.1 Tomcat 9 maven 3.6 新建工程 File->new->project 默认会下载springframewo ...
- python 不可变类型
不可变类型有:字符串,元祖,数字 可变类型:列表,字典 字典中,可变类型不能为key值 #在函数中 可变类型,为全局变量时,会变化 不可变类型,为全局变量时,不会变化
- 【值得收藏】C语言入门基础知识大全!从C语言程序结构到删库跑路!
01 C语言程序的结构认识 用一个简单的c程序例子,介绍c语言的基本构成.格式.以及良好的书写风格,使小伙伴对c语言有个初步认识. 例1:计算两个整数之和的c程序: #include main() { ...
- hugo网站配置聊天
date: "2020-10-18T22:11:05+08:00" title: "hugo网站配置聊天" tags: ["dao"] ca ...
- python 爬虫 循环分页
import osfrom time import sleepimport fakerimport requestsfrom lxml import etreefake = faker.Faker() ...
- Go语言中Goroutine与线程的区别
1.什么是Goroutine? Goroutine是建立在线程之上的轻量级的抽象.它允许我们以非常低的代价在同一个地址空间中并行地执行多个函数或者方法.相比于线程,它的创建和销毁的代价要小很多,并且它 ...