Tensorflow:从多项分布生成样本[节省空间的方式?]

时间:2018-06-01 11:01:02

标签: tensorflow sampling memory-efficient multinomial

我有一个简单的问题。如何从TensorFlow中的多项分布中对{0,1}中的值进行采样?实际上我想要一个执行numpy.multinomial所做功能的函数。

让我们假设我有一个计数向量和一个概率向量,如下所示:

counts = [5, 4, 3] # D in my code
probs = [0.1, 0.2, 0.3, 0.1, 0.2, 0.1] # v in my code

然后我想返回一个大小为(len(counts), len(probs)) = (3, 6)的矩阵,其中每行的总和=计数。

我查看了TensorFlow代码,我找到了一种方法来做我想做的事情。这是我的代码:

import tensorflow.contrib.distributions as ds

def multinomial_sampling(D, v):
    dist = ds.Multinomial(total_count=D, probs=v)
    return  tf.reshape(tf.reduce_sum(dist._sample_n(1), 0 , False), [-1, v.shape[1]])

注意:我可以只使用tf.expand_dims代替tf.reshape

问题在于这样做不是节省空间,当我的矩阵足够大时,TensorFlow只是对我大喊我没有足够的记忆因为他试图创建一个大小的矩阵[1,185929, 3390]其中3390是我的概率向量的长度。

所以我想自己实施多项式抽样,但我不是 知道如何做到这一点,我认为我的想法不够有效(在时间复杂性方面)。这是我的骨架:

probsn = np.random.uniform(size=20)
probsn /= sum(probsn)

counts = tf.Variable([20, 12, 56, 3])
probs = tf.Variable(tf.convert_to_tensor(probsn))

cprobs = tf.cumsum(probs)

out = tf.zeros([tf.shape(counts)[0], tf.shape(probs)[0]])
for i in counts.shape[0]:
    count = tf.gather(counts, i) # get each count
    sample = tf.gather(out, i) # get each row of out

   for j in range(count): # problem here count is a Tensor and not a int
       rdn_number = tf.random_uniform(1)
       for k, prob in enumerate(range(cprobs)): # problem doesn't work in TF
           if  tf.less(rdn_number, prob): 
               tf.scatter_add(out, [i, k], 1)

init = tf.global_variables_initializer()

with tf.Session() as sess:
    sess.run(init)
    r = sess.run(out)
    print(r)

这是一个非常天真的算法。我认为可能有更好的减少方法 时间复杂度(有一种范围的字典?它映射到一行浮点值的行中的特定指标?不确定这样的事情是否可行但它实际上会避免我迭代找到我行中的指标...)。

此外,此实现并不像代码中提到的那样有效,因为迭代的数字实际上是张量。

TensorFlow中是否有人对多项式采样进行了简洁的实施?

1 个答案:

答案 0 :(得分:0)

好的,显然我的问题不是问题,因为我不应该有这么大的数字(185929)。所以我编辑了其他一些代码。为了完整性,如果你想要一个非常大的数字,如果你想使用sample(),你就是不能这样做:

import tensorflow.contrib.distributions as ds

def multinomial_sampling(D, v):
    dist = ds.Multinomial(total_count=D, probs=v)
    return  tf.reshape(dist.sample(), [-1, v.shape[1]])

如果您的计算机上没有足够的内存。

注意:我将张量重新塑造成相同的形状,以便TensorFlow赢了 当我在while循环中使用multinomial_sampling函数的输出时,对我大喊大叫。如果没有tf.reshape,则tf.while_loop中的Tensorflow会因为我需要提供shape_invariants而崩溃。

所以你需要实际按批次进行处理。我们的想法是在while循环中对某个批次(如1000)进行采样,并减少每次迭代的计数。以下是我所做的一段代码:

probsn = np.random.uniform(size=30) 
probsn /= sum(probsn) # vector of probability of size 30 (sum of the vector = 1)

u = np.random.randint(2000, 3500, size=100) # define number of counts (vector of size 100 with int in 2000, 3500)
print(u) # should be the same as the output of print(np.sum(res, 1)) of the tf.Session()

counts = tf.Variable(u, dtype=tf.float32)
probs = tf.Variable(tf.convert_to_tensor(probsn.astype(np.float32)))

import tensorflow.contrib.distributions as ds

dist = ds.Multinomial(total_count=counts, probs=probs)

out = dist.sample()
samples = tf.zeros((tf.shape(counts)[0], tf.shape(probs)[0]))

def batch_multinomial(counts, probs, samples):
    batch_count = tf.minimum(1000., counts) # use a batch of 1000
    dist = ds.Multinomial(total_count=batch_count, probs=probs)
    samples += dist.sample()

    return counts - batch_count, probs, samples

_, _ , samples = tf.while_loop(lambda counts, *args: tf.equal(tf.reduce_all(tf.less(counts, 0.1)), False) , batch_multinomial, [counts, probs, samples])

with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
    res = sess.run(samples)
    print(res)
    print(np.sum(res, 1))