У меня был код, который случайным образом инициализировал некоторые массивы numpy с помощью:
rng = np.random.default_rng(seed=seed)
new_vectors = rng.uniform(-1.0, 1.0, target_shape).astype(np.float32) # [-1.0, 1.0)
new_vectors /= vector_size
И все работало хорошо, все тесты проекта проходили.
К сожалению, uniform()
возвращает np.float64
, хотя последующие шаги требуют только np.float32
, а в некоторых случаях этот массив очень велик (подумайте о миллионах 400-мерных векторов слов). Таким образом, временное возвращаемое значение np.float64
на мгновение использует в 3 раза больше необходимой оперативной памяти.
Таким образом, я заменил вышеизложенное тем, что по определению должно быть эквивалентно:
rng = np.random.default_rng(seed=seed)
new_vectors = rng.random(target_shape, dtype=np.float32) # [0.0, 1.0)
new_vectors *= 2.0 # [0.0, 2.0)
new_vectors -= 1.0 # [-1.0, 1.0)
new_vectors /= vector_size
И после этого изменения все тесно связанные функциональные тесты по-прежнему проходят, но один удаленный, второстепенный тест, основанный на далеко идущих вычислениях на основе векторов, инициализированных таким образом, начал давать сбой. И провал очень надежным способом. Это стохастический тест, который проходит с большой погрешностью в верхнем регистре, но всегда дает сбой в нижнем регистре. Итак: что-то изменилось, но каким-то очень тонким образом.
Поверхностные значения new_vectors
кажутся правильными и одинаково распределенными в обоих случаях. И опять же, все тесты функциональности крупным планом все равно проходят.
Так что мне бы хотелось, чтобы теории о том, какие неинтуитивные изменения могли быть сделаны этим изменением в 3 строки, которые могли бы проявиться далеко вниз по течению.
(Я все еще пытаюсь найти минимальный тест, который обнаруживает все отличия. Если вам нравится глубоко погрузиться в затронутый проект, увидеть точные тесты крупным планом, которые успешны, и один дополнительный тест, который терпит неудачу, и фиксирует с /без небольшого изменения, на https://github.com/RaRe-Technologies/gensim/pull/2944#issuecomment-704512389, Но на самом деле, я просто надеюсь, что эксперт по numpy может распознать какой-нибудь крошечный угловой случай, когда происходит что-то неинтуитивное, или предложить некоторые проверяемые теории того же самого. )
Любые идеи, предлагаемые тесты или возможные решения?
dtype
с похожими значениями. Спасибо! Вы видите мои дальнейшие изменения на этомrepl.it
? Почемуfloat32
, приведенный вниз изfloat64
, сохраняет больше младших битов? (Кроме того, я не уверен, что какие-либо из моих нижестоящих вычислений должны быть чувствительны к этим крошечным битам, чтобы без них работать хуже, но как ощутимую разницу между двумя кодовыми путями я буду продолжать изучать. Возможная причина.) - person gojomo   schedule 07.10.2020float32
, а не вынуждены генерировать 64-битные случайные числа только для того, чтобы получитьfloat32
этого достаточно. - person gojomo   schedule 07.10.2020.0
, не могут быть получены с помощью float32-rng. Если бы это было возможно, это было бы предвзято. - person Kelly Bundy   schedule 07.10.2020.0
, появиться таким образом, чтобы сохранить единообразие? А если нет, то следует ли из этого, что простой акт взятия «единообразных» значенийfloat64
и понижения их доfloat32
разрушает их единообразие? В таком случае: что, по нашему мнению, будет наиболее однородным —rng.uniform(0.0, 1.0, (1))
,rng.uniform(0.0, 1.0, (1)).astype(np.float32)
,rng.random(1)
илиrng.random(1, dtype=np.float32)
? (Я надеюсь, что на практике мои потребители будут устойчивы к небольшим различиям, но ваш комментарий о предвзятости вызывает у меня любопытство.) - person gojomo   schedule 07.10.2020seed
вариантам. Случайный альтернативный потокfloat32
только что переключилseed
с удачливого на неудачный для удаленного теста. И тот факт, что я все еще видел дрожание в пределе прохождения при повторных запусках из-за другой случайности в тесте, поначалу не позволял мне понять основную роль семени. - person gojomo   schedule 09.10.2020