Hallo. Neulich
Lesen Sie den Artikel
Wenn Sie keine Batch-Normalisierung verwenden, verlieren Sie Ihr Leben If you aren't using batch normalization you should
Also habe ich versucht, die (?) Batch-Normalisierung von Theano zu implementieren und zu verifizieren.
Wird teilweise erwähnt.
Batch Normalization
Normalisieren Sie jede Charge so, dass der Mittelwert 0 und die Varianz 1 beträgt. Sei $ B $ eine Menge von Eingaben für Mini-Batch und $ m $ eine Batch-Größe.
B = \{x_{1...m}\}\\
Unten scheint $ \ epsilon $ ein Parameter für die Stabilisierung zu sein.
\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
In Bezug auf die obige Formel scheinen $ \ gamma $ und $ \ beta $ zum Skalieren und Verschieben der durch die Parameter normalisierten Werte zu dienen. Es ist notwendig, jedes durch die Fehlerrückausbreitungsmethode zu lernen, aber hier werden wir die Ableitung detaillierter Gleichungen weglassen.
In einer normalen vollständig verbundenen Ebene müssen der Mittelwert und die Varianz für die Eingabedimension berechnet werden. Mit anderen Worten, wenn die Eingabeform "(BacthSize, 784)" ist, ist es notwendig, den Durchschnitt und die Varianz von 784 Teilen zu berechnen.
Andererseits ist es in der Faltungsschicht erforderlich, den Durchschnitt und die Streuung für die Anzahl der Kanäle zu berechnen. Mit anderen Worten, wenn die Eingabeform "(BatchSize, 64 (Anzahl der Kanäle), 32, 32)" ist, müssen der Mittelwert und die Varianz von 64 Teilen berechnet werden.
Als Verdienst der Chargennormalisierung scheint es, dass ein großer Lernkoeffizient eingestellt und das Lernen beschleunigt werden kann.
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
Ein Beispiel für die Verwendung (meistens Pseudocode) ist
...
input = previous_layer.output #Symbolvariable, Ausgabe der vorherigen Ebene, Form=(batchsize, 784)
h = BatchNormalizationLayer(input, shape=(batchsize, 784))
#Beim Aktivieren
h.output = activation(h.output) # activation=Einige Aktivierungsfunktionen
...
params = ... + h.params + ... #Wird beim Aktualisieren von Netzwerkparametern verwendet.
Die Daten wurden mit einem einfachen mehrschichtigen neuronalen Netzwerk unter Verwendung von MNIST experimentiert.
Gut Eingabeebene → (vollständig verbundene Ebene → Chargennormalisierungsschicht → Aktivierung) * 10 → Ausgabeebene Es ist wie es ist.
Es war vielleicht etwas schwierig, das Experiment einzurichten, aber Sie haben möglicherweise festgestellt, dass es beschädigt wäre, wenn Sie die Chargennormalisierung nicht verwenden würden.
Recommended Posts