2015-12-18 10 views
9

テンソルがA, B and C、テンソルフローがABの3つのテンソルがあり、両方とも形状が(m, n, r)Cのテンソルが(m, n, 1)のバイナリテンソルです。テンソルを他のテンソルに合わせて明示的にブロードキャストする方法はありますか?

Cの値に基づいて、AまたはBのいずれかの要素を選択したいとします。明白なツールはtf.selectですが、ブロードキャストのセマンティクスはありませんので、最初にAとBと同じ形にCを明示的にブロードキャストする必要があります。

これは初めての試みですが、テンソル(tf.shape(A)[2])をシェイプリストに混合するのが好きです。

import tensorflow as tf 
A = tf.random_normal([20, 100, 10]) 
B = tf.random_normal([20, 100, 10]) 
C = tf.random_normal([20, 100, 1]) 
C = tf.greater_equal(C, tf.zeros_like(C)) 

C = tf.tile(C, [1,1,tf.shape(A)[2]]) 
D = tf.select(C, A, B) 

ここで正しいアプローチは何ですか?

+2

一つハック 'パンダ= tf.ones_like(B)'、そして 'C = Expander * C' – wxs

答えて

9

編集: 0.12rc0以降のTensorFlowのすべてのバージョンでは、質問内のコードが直接的に機能します。 TensorFlowは自動的にテンソル引数とPython数値をテンソル引数に積み重ねます。 tf.pack()を使用する以下のソリューションは、0.12rc0より前のバージョンでのみ必要です。 tf.pack()は、TensorFlow 1.0ではtf.stack()に改名されています。


あなたのソリューションは非常に機能しています。以下で...

C = tf.tile(C, [1,1,tf.shape(C)[2]]) 

:あなたはラインを交換する必要があります

C = tf.tile(C, tf.pack([1, 1, tf.shape(A)[2]])) 

(問題の理由はTensorFlowが暗黙のうちにテンソルとPythonのリテラルのリストを変換しないということです各要素はスカラーであるため、結果はベクトルである。テンソル。tf.pack()はテンソルのリストを取るので、テンソルへの入力(11、及びtf.shape(C)[2])の各要素を変換します。)

+1

あなたは余分な' ['があり、' ''が不足していると思いますが、私はtfセッションを実行するとやや謎のエラーになります: 'InvalidArgumentError:タイプセレクトのサイズと形状は同じでなければなりません。入力0:dim {size:20} dim {size:100} dim {size:1}!=入力1:dim {size:20} dim {size:100} dim {size:10} ' – wxs

+0

私は答えを更新しました - また、 'tf.shape()'の引数は 'A'(または' B')でなければなりません。これは私のために働く - あなたは何を見ているのですか? – mrry

+0

うん、それは今修正されました:) 'tf.shape()'に間違ったパラメータを通知しませんでした。ありがとう! – wxs

2

ここに「SA汚いハック:私は*掛けるので、ものテンソルを掛け*の放送セマンティクスを使用することができます:作品

import tensorflow as tf 

def broadcast(tensor, shape): 
    return tensor + tf.zeros(shape, dtype=tensor.dtype) 

A = tf.random_normal([20, 100, 10]) 
B = tf.random_normal([20, 100, 10]) 
C = tf.random_normal([20, 100, 1]) 

C = broadcast(C, A.shape) 
D = tf.select(C, A, B) 
0
import tensorflow as tf 

def broadcast(tensor, shape): 
    """Broadcasts ``x`` to have shape ``shape``. 
                    | 
    Uses ``tf.Assert`` statements to ensure that the broadcast is 
    valid. 

    First calculates the number of missing dimensions in 
    ``tf.shape(x)`` and left-pads the shape of ``x`` with that many 
    ones. Then identifies the dimensions of ``x`` that require 
    tiling and tiles those dimensions appropriately. 

    Args: 
     x (tf.Tensor): The tensor to broadcast. 
     shape (Union[tf.TensorShape, tf.Tensor, Sequence[int]]): 
      The shape to broadcast to. 

    Returns: 
     tf.Tensor: ``x``, reshaped and tiled to have shape ``shape``. 

    """ 
    with tf.name_scope('broadcast') as scope: 
     shape_x = tf.shape(x) 
     rank_x = tf.shape(shape0)[0] 
     shape_t = tf.convert_to_tensor(shape, preferred_dtype=tf.int32) 
     rank_t = tf.shape(shape1)[0] 

     with tf.control_dependencies([tf.Assert(
      rank_t >= rank_x, 
      ['len(shape) must be >= tf.rank(x)', shape_x, shape_t], 
      summarize=255 
     )]): 
      missing_dims = tf.ones(tf.stack([rank_t - rank_x], 0), tf.int32) 

     shape_x_ = tf.concat([missing_dims, shape_x], 0) 
     should_tile = tf.equal(shape_x_, 1) 

     with tf.control_dependencies([tf.Assert(
      tf.reduce_all(tf.logical_or(tf.equal(shape_x_, shape_t), should_tile), 
      ['cannot broadcast shapes', shape_x, shape_t], 
      summarize=255 
     )]): 
      multiples = tf.where(should_tile, shape_t, tf.ones_like(shape_t)) 
      out = tf.tile(tf.reshape(x, shape_x_), multiples, name=scope) 

     try: 
      out.set_shape(shape) 
     except: 
      pass 

     return out 

A = tf.random_normal([20, 100, 10]) 
B = tf.random_normal([20, 100, 10]) 
C = tf.random_normal([20, 100, 1]) 

C = broadcast(C, A.shape) 
D = tf.select(C, A, B)