Различия между numpy.random.rand и numpy.random.randn в Python
Каковы все различия между numpy.random.rand
а также numpy.random.randn
?
Из документов я знаю, что единственное различие между ними заключается в вероятностном распределении, из которого берется каждое число, но общая структура (измерение) и используемый тип данных (с плавающей точкой) одинаковы. Мне трудно отлаживать нейронную сеть из-за веры в это.
В частности, я пытаюсь повторно реализовать нейронную сеть, представленную в книге " Нейронная сеть и глубокое обучение" Майкла Нильсона. Оригинальный код можно найти здесь. Моя реализация была такой же, как и оригинальная, за исключением того, что я определил и инициализировал веса и смещения с numpy.random.rand
в init
функция, а не numpy.random.randn
как в оригинале.
Тем не менее, мой код, который использует random.rand
инициализировать weights and biases
не работает, потому что сеть не будет учиться, а вес и смещения не изменятся.
Какая разница между двумя случайными функциями вызывает эту странность?
1 ответ
Во-первых, как вы видите из документации numpy.random.randn
генерирует образцы из нормального распределения, в то время как numpy.random.rand
от униформы (в диапазоне [0,1)).
Во-вторых, почему не работает равномерное распределение? Основной причиной этого является функция активации, особенно в том случае, когда вы используете сигмовидную функцию. Сюжет сигмовидной кишки выглядит следующим образом:
Таким образом, вы можете видеть, что если ваш ввод от 0, наклон функции уменьшается довольно быстро, и в результате вы получаете крошечный градиент и крошечное обновление веса. И если у вас много слоев - эти градиенты многократно умножаются на обратном проходе, поэтому даже "правильные" градиенты после умножения становятся маленькими и перестают оказывать какое-либо влияние. Поэтому, если у вас много весов, которые приносят ваш вклад в эти регионы, ваша сеть вряд ли поддается обучению. Вот почему обычная практика - инициализировать сетевые переменные с нулевым значением. Это сделано для того, чтобы вы получили разумные градиенты (около 1) для обучения своей сети.
Однако равномерное распределение не является чем-то совершенно нежелательным, вам просто нужно уменьшить диапазон и приблизить его к нулю. Одной из хороших практик является использование инициализации Xavier. При таком подходе вы можете инициализировать свои веса с помощью:
1) Нормальное распределение. Где среднее значение 0 и var = sqrt(2. / (in + out))
где in - количество входов в нейроны и out - количество выходов.
2) Unifrom распределения в диапазоне [-sqrt(6. / (in + out)), +sqrt(6. / (in + out))]
np.random.rand
для равномерного распределения (в полуоткрытом интервале[0.0, 1.0)
)np.random.randn
для стандартного нормального (также известного как гауссово) распределения (среднее значение 0 и дисперсия 1)
Вы можете очень легко визуально изучить различия между этими двумя:
import numpy as np
import matplotlib.pyplot as plt
sample_size = 100000
uniform = np.random.rand(sample_size)
normal = np.random.randn(sample_size)
pdf, bins, patches = plt.hist(uniform, bins=20, range=(0, 1), density=True)
plt.title('rand: uniform')
plt.show()
pdf, bins, patches = plt.hist(normal, bins=20, range=(-4, 4), density=True)
plt.title('randn: normal')
plt.show()
Которые производят:
а также
1) numpy.random.rand
из униформы (в диапазоне [0,1))
2) numpy.random.randn
генерирует выборки из нормального распределения