在整个维度上将softmax应用于矩阵中的非零元素

时间:2018-07-18 18:36:48

标签: python tensorflow

也许这很简单,但事实并非如此。我花了太多时间试图弄清楚如何进行这项工作。这是代码:

.text(newValue)

我试图将.html(newValue)应用于每个# batch x time x events batch = 2 time = 3 events = 4 tensor = np.random.rand(batch, time, events) tensor[0][0][2] = 0 tensor[0][0][3] = 0 tensor[0][1][3] = 0 tensor[0][2][1] = 0 tensor[0][2][2] = 0 tensor[0][2][3] = 0 tensor[1][0][3] = 0 non_zero = ~tf.equal(tensor, 0.) s = tf.Session() g = tf.global_variables_initializer() s.run(g) s.run(non_zero) 维度中的非零值。但是,当我使用tf.nn.softmax时,它实际上将所有非零值收集在一起。那不是我想要的。我想保留尺寸。

以下是张量的屏幕截图: enter image description here

因此,time仅应应用于那些组,并且应将它们“放回”原来的位置。有谁知道该怎么做?

编辑:

在您的帮助下,我几乎找到了我需要的解决方案。但是我仍然缺少一步。将每个时间维度上的softmax分配给非零值:

tf.boolean_mask

还请注意,当您在整个时间范围内都为零时,此解决方案应该可以处理这种情况。然后应该保持不变。

3 个答案:

答案 0 :(得分:2)

可能的重复项:Applying tf.nn.softmax() only to positive elements of a tensor

借助tf.map_fntf.where

session.run(tf.map_fn(
     lambda x : tf.where(x > 0, tf.nn.softmax(x,axis=2,name="pidgeon"), x), tensor))

经过np.random.seed(1992)

的测试
# tensor
[[[0.86018176 0.42148685 0.         0.        ]
  [0.64714    0.68271286 0.6449022  0.        ]
  [0.92037941 0.         0.         0.        ]]

 [[0.38479139 0.26825327 0.43027759 0.        ]
  [0.56077674 0.49309016 0.2433904  0.85396874]
  [0.1267429  0.1861004  0.92251748 0.67904445]]]

# result
 [[[0.34841156, 0.33845624, 0.        , 0.        ],
    [0.28155918, 0.43949257, 0.48794109, 0.        ],
    [0.37002926, 0.        , 0.        , 0.        ]],

   [[0.33727059, 0.31513436, 0.2885575 , 0.        ],
    [0.40216839, 0.39458556, 0.23936921, 0.44145382],
    [0.26056102, 0.29028008, 0.47207329, 0.37060957]]])

0.34841156 == np.exp(0.86018176) / (np.exp(0.86018176) + np.exp(0.64714) + np.exp(0.92037941)) 

答案 1 :(得分:1)

这是我使用numpytensorflow的方法:

> tensor 
array([[[0.2891092 , 0.76259227, 0.        , 0.        ],
        [0.93660715, 0.18361367, 0.07234135, 0.        ],
        [0.23128076, 0.        , 0.        , 0.        ]],

       [[0.45708066, 0.76883403, 0.7584804 , 0.        ],
        [0.51019332, 0.73361557, 0.87442305, 0.66796383],
        [0.9297317 , 0.22428208, 0.69184613, 0.06162719]]])

查找非零元素的掩码

non_zero = ~tf.equal(tensor, 0.)

# convert to numpy
with tf.Session() as sess:
    non_zero_mask = non_zero.eval()

获取非零值

non_zero_val = tensor[non_zero_mask]

> non_zero_val
array([0.2891092 , 0.76259227, 0.93660715, 0.18361367, 0.07234135,
       0.23128076, 0.45708066, 0.76883403, 0.7584804 , 0.51019332,
       0.73361557, 0.87442305, 0.66796383, 0.9297317 , 0.22428208,
       0.69184613, 0.06162719])

对非零值应用softmax

# apply softmax
soft_max = tf.nn.softmax(non_zero_val)

# convert to numpy
with tf.Session() as sess:
    soft_max_np = soft_max.eval()

> soft_max_np
array([0.04394964, 0.07056453, 0.08397696, 0.03954934, 0.0353846 ,
       0.04148019, 0.05198816, 0.07100635, 0.07027497, 0.05482403,
       0.06854914, 0.07891397, 0.06419332, 0.08340156, 0.0411909 ,
       0.06574485, 0.0350075 ])

通过将softmax应用于非零元素来更新tensor

tensor[non_zero_mask] = soft_max_np

tensor
array([[[0.04394964, 0.07056453, 0.        , 0.        ],
        [0.08397696, 0.03954934, 0.0353846 , 0.        ],
        [0.04148019, 0.        , 0.        , 0.        ]],

       [[0.05198816, 0.07100635, 0.07027497, 0.        ],
        [0.05482403, 0.06854914, 0.07891397, 0.06419332],
        [0.08340156, 0.0411909 , 0.06574485, 0.0350075 ]]])

答案 2 :(得分:0)

好的,我从tenticon的重复链接和他的答案中找到了解决方案。尽管当整个时间向量为零时此操作失败。因此,我仍然需要修复该问题。很高兴听到您的建议。但是这里是解决方案:

def sparse_softmax(T):
    # Creating partition based on condition:
    condition_mask = tf.cast(tf.greater(T, 0.), tf.int32)
    partitioned_T = tf.dynamic_partition(T, condition_mask, 2)
    # Applying the operation to the target partition:
    partitioned_T[1] = tf.nn.softmax(partitioned_T[1])

    # Stitching back together, flattening T and its indices to make things easier::
    condition_indices = tf.dynamic_partition(tf.range(tf.size(T)), tf.reshape(condition_mask, [-1]), 2)
    res_T = tf.dynamic_stitch(condition_indices, partitioned_T)
    res_T = tf.reshape(res_T, tf.shape(T))

    return res_T

my_softmax = tf.map_fn(lambda batch: 
                       tf.map_fn(lambda time_vector: sparse_softmax(time_vector), batch, dtype=tf.float64)
                       , tensor, dtype=tf.float64)

我想出的另一种解决方案在整个向量为零时仍然会受到影响:

def softmax(tensor):
#     tensor_ = tf.placeholder(dtype=tf.float64, shape=(4,))

    non_zeros = ~tf.equal(tensor, 0.)
    sparse_softmax = tf.nn.softmax(tf.boolean_mask(tensor, non_zeros))
    sparse_softmax_shape = tf.shape(sparse_softmax)[0]
    orig_shape = tf.shape(tensor)[0]
    shape_ = orig_shape-sparse_softmax_shape
    zeros = tf.zeros(shape=shape_, dtype=tf.float64)
    new_vec = tf.concat([sparse_softmax, zeros], axis=0)

    return new_vec

但是这不起作用....就是说,当向量全为零时,应该返回零向量,而对于某种空张量,我会得到整形错误。

def softmax_(tensor):

    zeros = tf.cast(tf.equal(tensor, 0.), tf.float64)
    cond_ = tf.reduce_sum(zeros)

    def true_fn():
        non_zeros = ~tf.equal(tensor, 0.)
        sparse_softmax = tf.nn.softmax(tf.boolean_mask(tensor, non_zeros))
        sparse_softmax_shape = tf.shape(sparse_softmax)[0]
        orig_shape = tf.shape(tensor)[0]
        shape_ = orig_shape-sparse_softmax_shape
        zeros = tf.zeros(shape=shape_, dtype=tf.float64)
        new_vec = tf.concat([sparse_softmax, zeros], axis=0)

        return new_vec

    def false_fn():

        return tf.zeros(shape=tf.shape(tensor), dtype=tf.float64)

    return tf.cond(tf.equal(cond_, tf.cast(tf.shape(tensor)[0], tf.float64)), false_fn, true_fn)

仍然不能使其适用于全零的向量。很高兴得知您的解决方案。

编辑:实际上最后一个代码段完全按照我的要求工作。