c,b
Hay un problema
Después de estandarizar la entrada, puede ocurrir la siguiente situación: una capa en el medio de la red aprende que los datos de características en sí están distribuidos en ambos lados de la función de activación sigmoidea, y la estandarización obligará a que la media de entrada se limite a 0 y la desviación estándar se limita a 1. De esta manera, los datos se transforman en una distribución en la parte media de la función de activación sigmoidea, que destruye la distribución de características aprendida por una cierta capa en el medio de la red.
Solución
Transformar la reconstrucción, introducir parámetros aprendibles γ, β, todos los γ y todos los β se inicializan en 1 y 0 respectivamente, y cada neurona en cada capa tiene su propio γ y β. Para la propagación hacia adelante, se utilizan los propios γ y β de cada neurona. Durante la retropropagación, se calculan los gradientes de todos los γ y todos los β, es decir, dγ y dβ. Una vez finalizada la retropropagación, un optimizador (como SGD, Adam, etc.) puede actualizar cada γ y β y los gradientes correspondientes dγ y dβ respectivamente.
propagación hacia adelante
import numpy as np
def batchnorm_forward(x, gamma, beta, bn_param):
r"""
args:
- x: Data of shape (N, D)
- gamma: Scale parameter of shape (D,)
- beta: Shift paremeter of shape (D,)
- bn_param: Dictionary with the following keys:
Returns:
- out: of shape (N, D)
- cache: A tuple of values needed in the backward pass
"""
mode = bn_param['mode']
eps = bn_param.get('eps', 1e-5)
momentum = bn_param.get('momentum', 0.9)
N, D = x.shape
running_mean = bn_param.get('running_mean', np.zeros(D, dtype=x.dtype))
running_var = bn_param.get('running_var', np.zeros(D, dtype=x.dtype))
out, cache = None, None
if mode == 'train':
sample_mean = np.mean(x, axis=0)
sample_var = np.var(x, axis=0)
out_ = (x - sample_mean) / np.sqrt(sample_var + eps)
running_mean = momentum * running_mean + (1 - momentum) * sample_mean
running_var = momentum * running_var + (1 - momentum) * sample_var
out = gamma * out_ + beta
cache = (out_, x, sample_var, sample_mean, eps, gamma, beta)
elif mode == 'test':
scale = gamma / np.sqrt(running_var + eps)
out = x * scale + (beta - running_mean * scale)
bn_param['running_mean'] = running_mean
bn_param['running_var'] = running_var
return out, cache
retropropagación
import numpy as np
def batchnorm_backward(dout, cache):
r"""
args:
- dout: Upstream derivatives, of shape (N, D)
- cache: Variable of intermediates from batchnorm_forward.
Returns:
- dx: Gradient with respect to inputs x, of shape (N, D)
- dgamma: Gradient with respect to scale parameter gamma, of shape (D,)
- dbeta: Gradient with respect to shift parameter beta, of shape (D,)
"""
dx, dgamma, dbeta = None, None, None
out_, x, sample_var, sample_mean, eps, gamma, beta = cache
N = x.shape[0]
dout_ = gamma * dout
dvar = np.sum(dout_ * (x - sample_mean) * -0.5 * (sample_var + eps) ** -1.5, axis=0)
dx_ = 1 / np.sqrt(sample_var + eps)
dvar_ = 2 * (x - sample_mean) / N
di = dout_ * dx_ + dvar * dvar_
dmean = -1 * np.sum(di, axis=0)
dmean_ = np.ones_like(x) / N
dx = di + dmean * dmean_
dgamma = np.sum(dout * out_, axis=0)
dbeta = np.sum(dout, axis=0)
return dx, dgamma, dbeta
【Referencias】
Notas del estudio de normalización de lotes y su implementación: se busca programador
Aprendizaje profundo (29) Notas de estudio de normalización de lotes - Blog de hjimce - Blog de CSDN