Различия между 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генерирует выборки из нормального распределения

Другие вопросы по тегам