Bonjour. L'autre jour
Lire l'article
Si vous n'utilisez pas la normalisation par lots, vous perdrez la vie If you aren't using batch normalization you should
J'ai donc essayé d'implémenter et de vérifier (?) La normalisation des lots par Theano.
Est en partie mentionné.
Batch Normalization
Normaliser chaque lot de sorte que la moyenne soit 0 et la variance 1. Soit $ B $ un ensemble d'entrées pour le mini-lot et $ m $ une taille de lot.
B = \{x_{1...m}\}\\
Ci-dessous, $ \ epsilon $ semble être un paramètre de stabilisation.
\epsilon = 10^{-5}\\
\mu_{B} \leftarrow \frac{1}{m} \sum_{i=1}^{m} x_i\\
\sigma^2_{B} \leftarrow \frac{1}{m} \sum_{i=1}^{m} (x_i - \mu_{B})^2\\
\hat{x_i} \leftarrow \frac{x_i - \mu_{B}}{\sqrt{\sigma^2_{B} + \epsilon}}\\
y_i \leftarrow \gamma \hat{x_i} + \beta
Concernant la formule ci-dessus, il semble que $ \ gamma $ et $ \ beta $ servent respectivement à mettre à l'échelle et à décaler les valeurs normalisées par les paramètres. Il est nécessaire d'apprendre chacun par la méthode de propagation des erreurs, mais ici nous omettons la dérivation d'équations détaillées.
Dans une couche entièrement connectée normale, il est nécessaire de calculer la moyenne et la variance de la dimension d'entrée.
En d'autres termes, si la forme d'entrée est (BacthSize, 784), il est nécessaire de calculer la moyenne et la variance de 784 pièces.
Par contre, en couche convolutionnelle, il est nécessaire de calculer la moyenne et la dispersion pour le nombre de canaux.
En d'autres termes, si la forme d'entrée est (BatchSize, 64 (nombre de canaux), 32, 32), il est nécessaire de calculer la moyenne et la variance de 64 pièces.
En tant que mérite de la normalisation par lots, il semble qu'un coefficient d'apprentissage élevé puisse être défini et l'apprentissage peut être accéléré.
class BatchNormalizationLayer(object):
	def __init__(self, input, shape=None):
		self.shape = shape
		if len(shape) == 2: # for fully connnected
			gamma = theano.shared(value=np.ones(shape[1], dtype=theano.config.floatX), name="gamma", borrow=True)
			beta = theano.shared(value=np.zeros(shape[1], dtype=theano.config.floatX), name="beta", borrow=True)
			mean = input.mean((0,), keepdims=True)
			var = input.var((0,), keepdims=True)
		elif len(shape) == 4: # for cnn
			gamma = theano.shared(value=np.ones(shape[1:], dtype=theano.config.floatX), name="gamma", borrow=True)
			beta = theano.shared(value=np.zeros(shape[1:], dtype=theano.config.floatX), name="beta", borrow=True)
			mean = input.mean((0,2,3), keepdims=True)
			var = input.var((0,2,3), keepdims=True)
			mean = self.change_shape(mean)
			var = self.change_shape(var)
		self.params = [gamma, beta]
		self.output = gamma * (input - mean) / T.sqrt(var + 1e-5) + beta
	
	def change_shape(self, vec):
		ret = T.repeat(vec, self.shape[2]*self.shape[3])
		ret = ret.reshape(self.shape[1:])
		return ret
Un exemple d'utilisation (principalement du pseudo-code) est
...
input = previous_layer.output #Variable de symbole, sortie du calque précédent, forme=(batchsize, 784)
h = BatchNormalizationLayer(input, shape=(batchsize, 784))
#Lors de l'activation
h.output = activation(h.output) # activation=Une fonction d'activation
...
params = ... + h.params + ... #Utilisé lors de la mise à jour des paramètres réseau.
Les données ont été expérimentées avec un simple réseau neuronal multicouche utilisant MNIST.
--Nombre de couches intermédiaires: 10 --Nombre d'unités dans la couche intermédiaire: 784 au total
bien Couche d'entrée → (Couche entièrement connectée → Couche de normalisation par lots → Activation) * 10 → Couche de sortie C'est comme ça.
Il a peut-être été un peu difficile de mettre en place l'expérience, mais vous avez peut-être constaté qu'elle serait endommagée si vous n'utilisiez pas la normalisation par lots.
Recommended Posts