La mejor manera de sembrar N generadores de números aleatorios independientes de 1 valor

10

En mi programa, necesito ejecutar N subprocesos separados, cada uno con su propio RNG, que se utiliza para muestrear un gran conjunto de datos. Necesito poder sembrar todo este proceso con un solo valor para poder reproducir los resultados.

¿Es suficiente simplemente aumentar secuencialmente la semilla para cada índice?

Actualmente uso numpy's RandomStateque usa un generador de números pseudoaleatorio Mersenne Twister.

Fragmento de código a continuación:

# If a random number generator seed exists
if self.random_generator_seed:
    # Create a new random number generator for this instance based on its
    # own index
    self.random_generator_seed += instance_index
    self.random_number_generator = RandomState(self.random_generator_seed)

Básicamente, comienzo con una semilla introducida por el usuario (si existe) y para cada instancia / hilo agrego secuencialmente el índice (0 a N-1) de la instancia en ejecución. No sé si esta es una buena práctica o si hay una mejor manera de hacerlo.

EricR
fuente
1
¿Sabe de antemano cuántos valores pseudoaleatorios usará cada hilo, o al menos puede obtener una buena estimación de límite superior?
whuber
No, no puedo. Muestra las regiones que se suman hasta que se alcanza un umbral. Los tamaños de las regiones pueden variar significativamente.
EricR

Respuestas:

9

No es una buena práctica, ciertamente. Por ejemplo, considere lo que sucede cuando realiza dos ejecuciones con semillas raíz de 12345 y 12346. Cada ejecución tendrá N-1secuencias en común.

Las implementaciones de Mersenne Twister (incluyendo numpy.randomy random) generalmente usan un PRNG diferente para expandir la semilla entera en el vector de estado grande (624 enteros de 32 bits) que utiliza MT; Esta es la matriz de RandomState.get_state(). Una buena manera de hacer lo que quiere es ejecutar ese PRNG, sembrado con su entero de entrada una vez, y obtener N*624enteros de 32 bits. Divida esa secuencia en Nvectores de estado y úsela RandomState.set_state()para inicializar explícitamente cada RandomStateinstancia. Puede que tenga que consultar las fuentes C de la biblioteca estándar numpy.randomo _randomdesde ella para obtener ese PRNG (son las mismas). No estoy seguro de si alguien ha implementado una versión independiente de ese PRNG para Python.

Robert Kern
fuente
Creo que esta podría ser la mejor solución que he escuchado hasta ahora. No creo que importe mucho la forma en que dividí la transmisión, ¿aunque correcto? Parece mucho más improbable tener una secuencia duplicada en 624 enteros de 32 bits entre instancias, sin importar cómo se seleccionen del PRNG inicial y la semilla.
EricR
1
En realidad, caminaré un poco hacia atrás. No me queda claro que el inicializador PRNG está diseñado para tener arbitrariamente muchos valores extraídos de él. Considere usar otro PRNG de calidad (preferiblemente no relacionado con MT) para generar la secuencia de estado. Se puede implementar un HMAC-DRBG (un PRNG que usa un HMAC como primitivo criptográfico) usando solo la biblioteca estándar de manera relativamente sencilla. La seguridad criptográfica no es una preocupación; solo la facilidad de implementación y la calidad del flujo de bits. Tendrás que asegurarte de que no se realicen vectores todos cero, en la muy rara posibilidad.
Robert Kern
O simplemente use una de las RandomStateimplementaciones más nuevas en desarrollo que use un algoritmo que tenga flujos configurables. Es decir, inicializa cada RandomStateinstancia con la misma semilla y diferentes ID de flujo (simplemente incrementado está bien), y tiene garantizado flujos independientes. pypi.python.org/pypi/randomstate
Robert Kern
4

Una solución que se usa en el procesamiento paralelo es usar su generador aleatorio , donde es su semilla, por lotes:Φ(u)uN

  1. generarΦ(u),ΦN(u),Φ2N(u),...
  2. generarΦ2(u),Φ1+N(u),Φ1+2N(u),...
  3. ...
  4. generarΦN1(u),ΦN1+N(u),ΦN1+2N(u),...

donde . De esta manera, usa una sola semilla y sus secuencias son todas uniformes e independientes.Φn(u)=Φ(Φn1(u))

Xi'an
fuente
2

Ahora hay un paquete de Python llamado RandomGen que tiene métodos para lograr esto.

Es compatible con corrientes independientes creadas a partir de una sola semilla, así como un protocolo de salto de más edad generadores de números aleatorios, como MT19937.

Praveen
fuente
0

Algunas personas afirman que hay correlaciones en los números aleatorios generados por semillas secuenciales. /programming/10900852/near-seeds-in-random-number-generation-may-give-similar-random-numbers No estoy seguro de cuán cierto es eso.

Si le preocupa, ¿por qué no usar un único generador de números aleatorios para elegir las semillas de todos los otros generadores?

Aaron
fuente
Simplemente porque no quiero tener ninguna posibilidad de generar aleatoriamente la misma semilla para más de 1 generador. Por supuesto, podría hacer un trabajo de programación para evitar que esto suceda, pero no sé cómo sería mejor que recoger semillas secuencialmente en primer lugar.
EricR
1
Aparentemente , las correlaciones son posibles con semillas secuenciales ... Sin embargo, como lo muestra el artículo vinculado en esa respuesta del blog de John D Cook, usar un RNG para generar semillas para otros generadores es mucho peor, ¡porque te encuentras con el problema del cumpleaños! ¡Dice que generar aleatoriamente 1000 semillas sin signo de 16 bits tiene un 99.95% de posibilidades de superposición!
Praveen