88 votes

Différences entre numpy.random.rand et numpy.random.randn en Python

Quelles sont les différences entre numpy.random.rand et numpy.random.randn ?

D'après la documentation, je sais que la seule différence entre eux provient de la distribution probabiliste dont chaque nombre est tiré, mais la structure globale (dimension) et le type de données utilisé (float) sont les mêmes. J'ai du mal à déboguer un réseau neuronal parce que je crois cela.

Plus précisément, j'essaie de réimplémenter le réseau de neurones fourni dans le module de gestion de l'information. Réseau neuronal et apprentissage profond, livre de Michael Nielson . Le code original peut être trouvé ici . Mon implémentation était la même que celle d'origine, sauf que j'ai défini et initialisé les poids et les biais avec numpy.random.rand sur init plutôt que numpy.random.randn comme dans l'original.

Cependant, mon code qui utilise random.rand pour initialiser weights and biases ne fonctionne pas car le réseau n'apprend pas et les poids et les biais ne changent pas.

Quelle(s) différence(s) entre deux fonctions aléatoires provoque(nt) cette bizarrerie ?

1 votes

Le premier tire d'une distribution uniforme et le second d'une distribution normale. "Pourquoi les poids initiaux tirés d'une distribution normale fonctionnent-ils mieux dans l'apprentissage profond ?" est plus adapté pour Validation croisée par contre. Ce n'est pas du tout lié à numpy ou à un cadre d'apprentissage profond.

1 votes

@ayhan merci pour le commentaire. Je pensais qu'il s'agissait d'un problème lié à numpy et non aux poids initiaux, car même si j'initialise les poids avec des zéros, j'obtiens de moins bonnes performances qu'en initialisant avec random.randn mais le réseau apprend quand même. Alors que si j'utilise le random.rand le réseau ne fait que répéter le résultat initial encore et encore et n'a rien appris.

125voto

asakryukin Points 1544

D'abord, comme vous le voyez dans la documentation numpy.random.randn génère des échantillons de la distribution normale, tandis que numpy.random.rand à partir d'une distribution uniforme (dans l'intervalle [0,1]).

Deuxièmement, pourquoi la distribution uniforme n'a pas fonctionné ? La raison principale est la fonction d'activation, en particulier dans votre cas où vous utilisez la fonction sigmoïde. Le tracé de la fonction sigmoïde ressemble à ce qui suit :

enter image description here

Vous pouvez donc voir que si votre entrée est éloignée de 0, la pente de la fonction diminue assez rapidement et, par conséquent, vous obtenez un gradient minuscule et une mise à jour minuscule du poids. Et si vous avez beaucoup de couches - ces gradients sont multipliés plusieurs fois dans le passage arrière, donc même les gradients "corrects" après multiplications deviennent petits et cessent d'avoir une influence. Donc si vous avez beaucoup de poids qui amènent votre entrée dans ces régions, votre réseau est difficilement entraînable. C'est pourquoi il est d'usage d'initialiser les variables du réseau autour de la valeur zéro. Ceci est fait pour s'assurer que vous obtenez des gradients raisonnables (proches de 1) pour entraîner votre réseau.

Cependant, la distribution uniforme n'est pas quelque chose de complètement indésirable, il suffit de rendre la plage plus petite et plus proche de zéro. L'une des bonnes pratiques consiste à utiliser l'initialisation de Xavier. Dans cette approche, vous pouvez initialiser vos poids avec :

  1. Distribution normale. Où la moyenne est 0 et var = sqrt(2. / (in + out)) où in - est le nombre d'entrées des neurones et out - le nombre de sorties.

  2. Distribution uniforme dans l'intervalle [-sqrt(6. / (in + out)), +sqrt(6. / (in + out))]

8 votes

Merci. Je sais que le gradient disparaissant est une chose pour laquelle je n'ai jamais pensé que le simple fait de passer de l'image à l'image est une bonne chose. random.randn à random.rand peut rendre le réseau totalement inutile dès le début.

0 votes

Je pense que c'est pour ça que les gens ont arrêté d'utiliser la sigmoïde comme fonction d'activation. Ce livre est d'ailleurs une excellente introduction ! Mais j'aurais préféré qu'il codifie le ReLU à la place. Mais comme les premiers réseaux neuronaux utilisaient la sigmoïde, c'est logique.

0 votes

J'ai fait la même expérience avec une entrée normalisée, 2-3 FCs, ReLU et rand init, même comportement, ne converge pas

55voto

YaOzI Points 129
  • np.random.rand est pour une distribution uniforme (dans l'intervalle semi-ouvert [0.0, 1.0) )
  • np.random.randn est pour la distribution normale standard (alias gaussienne) (moyenne 0 et variance 1).

Vous pouvez très facilement explorer visuellement les différences entre les deux :

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()

Qui produisent :

enter image description here

et

enter image description here

-1voto

Prasheek07 Points 37

1) numpy.random.rand de uniforme (dans l'intervalle [0,1])

2) numpy.random.randn génère des échantillons de la distribution normale

3 votes

Cela n'ajoute rien qui n'ait été dit il y a trois ans.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X