Почему случайная функция NumPy, по-видимому, отображает шаблон в своих сгенерированных значениях? - PullRequest
0 голосов
/ 11 мая 2018

Я играл с NumPy и Pillow и столкнулся с интересным результатом, который явно демонстрирует паттерн в результатах NumPy random.random().

Image One Image Two Image Three Image Four

Здесь приведен пример полного кода для генерации и сохранения 100 таких изображений (с начальным числом 0), выше приведены первые четыре изображения, сгенерированные этим кодом.

import numpy as np
from PIL import Image

np.random.seed(0)
img_arrays = np.random.random((100, 256, 256, 3)) * 255
for i, img_array in enumerate(img_arrays):
    img = Image.fromarray(img_array, "RGB")
    img.save("{}.png".format(i))

Выше приведены четыре разных изображения, созданные с использованием PIL.Image.fromarray() на четырех разных массивах NumPy, созданных с использованием numpy.random.random((256, 256, 3)) * 255 для генерации сетки RGB 256 на 256 значений в четырех разных экземплярах Python (то же самое происходит и в том же экземпляре) .

Я заметил, что это происходит только (в моем ограниченном тестировании), когда ширина и высота изображения являются степенью двойки, я не уверен, как это интерпретировать.

Хотя это может быть трудно увидеть из-за сглаживания браузера (вы можете загружать изображения и просматривать их в средствах просмотра изображений без сглаживания), в каждом восьмом столбце есть четкие пурпурно-коричневые столбцы пикселей, начиная с 3-я колонка каждого изображения. Чтобы убедиться, я проверил это на 100 различных изображениях, и все они следовали этому шаблону.

Что здесь происходит? Я предполагаю, что подобные шаблоны являются причиной того, что люди всегда говорят, что используют криптографически безопасные генераторы случайных чисел, когда требуется истинная случайность, но есть ли конкретное объяснение, почему это происходит, в частности?

Ответы [ 3 ]

0 голосов
/ 11 мая 2018

Я почти уверен, что проблема связана с dtype, но не по тем причинам, о которых вы думаете.Вот один с np.random.randint(0, 256, (1, 256, 256, 3), dtype=np.uint32) , обратите внимание, что тип d не np.uint8:

enter image description here

МожетВы видите образец;)?PIL интерпретирует 32-битные (4-байтовые) значения (вероятно, как 4-пиксельные RGBK) иначе, чем 8-битные значения (RGB для одного пикселя).(См. Ответ PM 2Ring.)

Первоначально вы передавали 64-битные значения с плавающей запятой, они также интерпретируются по-разному (и, вероятно, неправильно, как вы предполагали).

0 голосов
/ 14 мая 2018

Документы Python для random () говорят так:

Python использует Mersenne Twister в качестве генератора ядра.Он выдает 53-битные значения точности и имеет период 2 ** 19937-1.Базовая реализация в C является быстрой и поточно-ориентированной.Mersenne Twister является одним из наиболее тщательно протестированных генераторов случайных чисел из существующих.Однако, будучи полностью детерминированным, он не подходит для всех целей и совершенно не подходит для криптографических целей.

Лучшие генераторы случайных чисел проходят тесты случайности , случайное число меньшего качествагенераторы часто используются потому, что они быстрые и считаются «достаточно хорошими».

В « Некоторые труднопроходимые тесты случайности », январь 2002 года, Марсалья и Цанг, они определили, чтоПодмножество « Diehard Battery of Tests » может быть использовано для оценки случайности ряда чисел, в частности, тестов gcd, gorilla и интервалов дня рождения.См. " Описания тестов Dieharder " для обсуждения энтропии и комментариев к этим тестам.

Во время наших головоломок по программированию и Гольф-кода некоторые люди делали попытку разработки кода, чтобы пройти тесты Diehardв этом вопросе: « Создайте генератор случайных чисел, который пройдет тесты Диарда ».

Следует ожидать появления паттернов во всех, кроме лучших (и, вероятно, более медленных) РНГ.

Современный стандарт статистического тестирования ГСЧ, " NIST SP 800-22 - Рекомендация для генерации случайных чисел с использованием детерминированных генераторов случайных битов " ( Обзор ), обеспечивает серию тестовкоторая среди прочего оценивает близость доли единиц к ½, то есть число единиц и нулей в последовательности должно быть примерно одинаковым.

Статья, опубликованная на веб-сайте ACM "Алгоритм 970: оптимизация набора статистических тестов NIST и алгоритма Берлекампа-Масси"январь 2017 г., Sýs, Říha and Матяш, обещает огромное ускорение алгоритмов NIST с их реимплантацией.

0 голосов
/ 11 мая 2018

Не вините Numpy, вините PIL / Pillow.;) Вы генерируете числа с плавающей точкой, но PIL ожидает целые числа, и его преобразование с плавающей точкой в ​​int делает не то, что мы хотим.Необходимы дальнейшие исследования, чтобы точно определить, что делает PIL ...

В то же время вы можете избавиться от этих строк, явно преобразовав свои значения в 8-битные целые числа без знака:

img_arrays = (np.random.random((100, 256, 256, 3)) * 255).astype(np.uint8)

Как отмечает FHTMitchell в комментариях, более эффективная форма -

img_arrays = np.random.randint(0, 256, (100, 256, 256, 3), dtype=np.uint8) 

Вот типичный вывод этого измененного кода:

random image made using Numpy


Функция PIL Image.fromarray имеет известную ошибку, как описано здесь .Поведение, которое вы видите, , вероятно, связано с этой ошибкой, но я думаю, что она может быть независимой.;)

FWIW, здесь - некоторые тесты и обходные пути, которые я сделал для ошибки, упомянутой в связанном вопросе.

...