Тензорный поток: генерировать сэмплы из полиномиального распределения - PullRequest
0 голосов
/ 01 июня 2018

У меня быстрый вопрос.Как я могу выбрать значения в {0, 1} из полиномиального распределения в TensorFlow?На самом деле мне нужна функция, которая делает то, что делает 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 голосов
/ 01 июня 2018

Хорошо, очевидно, моя проблема не проблема, потому что у меня не должно быть такого большого числа (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 не кричал на меня, когда я использую вывод функции multinomial_sampling в цикле while.Без tf.reshape в tf.while_loop Tensorflow вылетает, говоря, что мне нужно предоставить shape_invariants.

Так что вам действительно нужно обрабатывать пакетами.Идея состоит в том, чтобы сэмплировать определенный пакет (например, 1000) в цикле while и уменьшить количество на каждой итерации.Вот фрагмент кода, который я сделал:

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))
...