tensorflow的广播机制

TensorFlow支持广播机制(Broadcast)

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),简化咱们的填充操做。所以,咱们能够分离地进行这个线性操做,利用广播机制隐式地完成拼接操做。app

pa = tf.layers.dense(a, 10, activation=None)
pb = tf.layers.dense(b, 10, activation=None)
d = tf.nn.relu(pa + pb)

事实上,这个代码足够通用,而且能够在具备抽象形状(arbitrary shape)的张量间应用:dom

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

一个更为通用函数形式如上所述:函数

目前为止,咱们讨论了广播机制的优势,可是一样的广播机制也有其缺点,隐式假设几乎老是使得调试变得更加困难,考虑下面的例子:spa

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]]。) code

解决这种麻烦的方法就是尽量地显示使用。咱们在须要reduce某些张量的时候,显式地指定维度,而后寻找这个bug就会变得简单:orm

a = tf.constant([[1.], [2.]])
b = tf.constant([1., 2.])
c = tf.reduce_sum(a + b, 0)

这样,c的值就是[5, 7],咱们就容易猜到其出错的缘由。一个更通用的法则就是老是在reduce操做和在使用tf.squeeze中指定维度。 继承

相关文章
相关标签/搜索