tensorflow 根据概率分配整数

tensorflow distribute integers according to probabilities

我想按照每个 part:p=[0.02,0.5,0.3,0.18]

的概率将一个整数(例如 20)分成四个部分

对应的python代码为:

frequency=np.random.choice([1,2,3,4],20,p=[0.02,0.5,0.3,0.18])
from collections import Counter
np.fromiter(Counter(frequency).values(), dtype=np.float32)

# Out[86]:
# array([8., 8., 4.], dtype=float32)

不过,我有超过1e8~很多零件,数量不是20而是1e10。 所以 python 真的很慢。 例如

frequency=np.random.choice([i for i in range (10**7)],16**10,p=[0.0000001 for i in range(10**7)])
from collections import Counter
r=np.fromiter(Counter(frequency).values(), dtype=np.float32)

现在它只产生 MemoryError:

我认为 tensorflow gpu 可以解决这个问题,因为输出结果只有 10**7 大小。 有谁知道如何做到这一点?

这里有几个问题需要考虑。

如果你 运行 GPU 上的代码,它永远不会工作,因为 GPU 不是为存储而设计的,而是为快速计算而设计的,所以 GPU 上的 space 小于 CPU.但是,此代码也可能在 CPU 上产生内存错误,就像在我的机器上一样。所以我们首先尝试克服它。

克服 CPU 上的 MemoryError:

产生 MemoryError 的行是第 1 行本身:

    In [1]: frequency = np.random.choice([i for i in range (10**7)],16**10,p=[0.0000
   ...: 001 for i in range(10**7)])
   ...: 
---------------------------------------------------------------------------
MemoryError                               Traceback (most recent call last)

原因是第 1 行的输出大小不是 10**7,而是 16**10。由于这是导致 MemoryError 的原因,因此目标永远不应创建该大小的列表。

为此,我们将样本的大小减少一个因子,并在块上循环 factor 次,以便它可以存储。在我的机器上,1000000 的一个因子就可以了。创建样本后,我们使用 Counter 将其转换为频率字典。好处是我们知道频率的字典,在转换为列表或numpy数组时,永远不会超过10**7的大小,不会出现内存错误

由于有些元素可能不是每次都在采样数组中,我们不会直接将Counter字典转换成列表,而是使用上一次迭代中的字典来更新这个字典,以保留特定元素的频率.

整个循环完成后,我们将创建的字典转换为列表。我添加了一个进度条以跟踪进度,因为计算可能会花费很多时间。此外,在您的特定情况下,您不需要将参数 p 添加到 np.random.choice() 函数,因为无论如何分布都是均匀的。

import numpy as np
import tensorflow as tf

from click import progressbar
from collections import Counter

def large_uniform_sample_frequencies(factor=1000000, total_elements=10**7, sample_size=16**10):
    # Initialising progressbar
    bar = range(factor)

    # Initialise an empty dictionary which 
    # will be updated in each iteration
    counter_dict = {}

    for iteration in bar:
        # Generate a random sample of size (16 ** 10) / factor
        frequency = np.random.choice([i for i in range (total_elements)],
            sample_size / factor)

        # Update the frequency dictionary
        new_counter = Counter(frequency)
        counter_dict.update(new_counter)

    return np.fromiter(counter_dict.values(), dtype=np.float32)

使用tensorflow-gpu:

正如您所提到的 tensorflow-gpu 我可以假设您想要使用 tensorflow-gpu 或 运行 结合 tensorflow-gpu 摆脱 MemoryError ] 使用 GPU 时。

解决MemoryError,可以试试tf.multinomial()函数,效果和np.random.choice()一样,但不太可能帮助克服问题是存储一定大小的数据而不执行某些替代计算。

如果您想 运行 这作为训练某些模型的一部分,例如,您可以使用分布式 Tensorflow 将这部分计算图放在 CPU 作为 PS 使用上面给出的代码执行任务。这是最终代码:

# Mention the devices for PS and worker tasks
ps_dev = '/cpu:0'
worker_dev = '/gpu:0'

# Toggle True to place computation on CPU 
# and False to place it on the least loaded GPU
is_ps_task = True

# Set device for a PS task
if (is_ps_task):
    device_setter = tf.train.replica_device_setter(worker_device=worker_dev,
        ps_device=ps_dev, 
        ps_tasks=1)

# Allocate the computation to CPU
with tf.device(device_setter):
    freqs = large_uniform_sample_frequencies()