tutorial recurrent neural network for español curso convnet cnn beginners python neural-network deep-learning pytorch

python - for - pytorch recurrent neural network



¿Cómo inicializar pesos en PyTorch? (7)

¿Cómo inicializar los pesos y sesgos (por ejemplo, con la inicialización He o Xavier) en una red en PyTorch?


Iterar sobre parámetros

Si no puede usar apply por ejemplo, si el modelo no implementa Sequential directamente:

Lo mismo para todos

# see UNet at https://github.com/milesial/Pytorch-UNet/tree/master/unet def init_all(model, init_func, *params, **kwargs): for p in model.parameters(): init_func(p, *params, **kwargs) model = UNet(3, 10) init_all(model, torch.nn.init.normal_, mean=0., std=1) # or init_all(model, torch.nn.init.constant_, 1.)

Dependiendo de la forma

def init_all(model, init_funcs): for p in model.parameters(): init_func = init_funcs.get(len(p.shape), init_funcs["default"]) init_func(p) model = UNet(3, 10) init_funcs = { 1: lambda x: torch.nn.init.normal_(x, mean=0., std=1.), # can be bias 2: lambda x: torch.nn.init.xavier_normal_(x, gain=1.), # can be weight 3: lambda x: torch.nn.init.xavier_uniform_(x, gain=1.), # can be conv1D filter 4: lambda x: torch.nn.init.xavier_uniform_(x, gain=1.), # can be conv2D filter "default": lambda x: torch.nn.init.constant(x, 1.), # everything else } init_all(model, init_funcs)

Puede probar con torch.nn.init.constant_(x, len(x.shape)) para verificar que se hayan inicializado adecuadamente:

init_funcs = { "default": lambda x: torch.nn.init.constant_(x, len(x.shape)) }


Para inicializar capas, normalmente no necesita hacer nada.

PyTorch lo hará por ti. Si lo piensas, esto tiene mucho sentido. ¿Por qué deberíamos inicializar capas, cuando PyTorch puede hacerlo siguiendo las últimas tendencias?

Compruebe, por ejemplo, la capa lineal .

En el método __init__ llamará a Kamming He init function.

def reset_parameters(self): init.kaiming_uniform_(self.weight, a=math.sqrt(5)) if self.bias is not None: fan_in, _ = init._calculate_fan_in_and_fan_out(self.weight) bound = 1 / math.sqrt(fan_in) init.uniform_(self.bias, -bound, bound)

Lo mismo es para otros tipos de capas. Para conv2d por ejemplo, marque here .

Para tener en cuenta: la ganancia de una inicialización adecuada es la mayor velocidad de entrenamiento. Si su problema merece una inicialización especial, puede hacerlo después.


Una sola capa

Para inicializar los pesos de una sola capa, use una función de torch.nn.init . Por ejemplo:

conv1 = torch.nn.Conv2d(...) torch.nn.init.xavier_uniform(conv1.weight)

Alternativamente, puede modificar los parámetros escribiendo a conv1.weight.data (que es un torch.Tensor ). Ejemplo:

conv1.weight.data.fill_(0.01)

Lo mismo se aplica a los prejuicios:

conv1.bias.data.fill_(0.01)

nn.Sequential o personalizado nn.Module

Pase una función de inicialización a torch.nn.Module.apply . Inicializará los pesos en todo el nn.Module recursiva.

apply ( fn ): aplica fn recursiva a cada submódulo (como lo devuelve .children() ), así como a self. El uso típico incluye la inicialización de los parámetros de un modelo (ver también torch-nn-init).

Ejemplo:

def init_weights(m): if type(m) == nn.Linear: torch.nn.init.xavier_uniform(m.weight) m.bias.data.fill_(0.01) net = nn.Sequential(nn.Linear(2, 2), nn.Linear(2, 2)) net.apply(init_weights)


Comparamos diferentes modos de inicialización de peso usando la misma arquitectura de red neuronal (NN).

Todos ceros o unos

Si sigue el principio de la navaja de afeitar de Occam , podría pensar que establecer todos los pesos en 0 o 1 sería la mejor solución. Este no es el caso.

Con cada peso igual, todas las neuronas en cada capa están produciendo la misma salida. Esto hace que sea difícil decidir qué pesos ajustar.

# initialize two NN''s with 0 and 1 constant weights model_0 = Net(constant_weight=0) model_1 = Net(constant_weight=1)

  • Después de 2 épocas:

Validation Accuracy 9.625% -- All Zeros 10.050% -- All Ones Training Loss 2.304 -- All Zeros 1552.281 -- All Ones

Inicialización uniforme

Una distribución uniforme tiene la misma probabilidad de elegir cualquier número de un conjunto de números.

Veamos qué tan bien se entrena la red neuronal usando una inicialización de peso uniforme, donde low=0.0 y high=1.0 .

A continuación, veremos otra forma (además del código de clase Net) para inicializar los pesos de una red. Para definir pesos fuera de la definición del modelo, podemos:

  1. Defina una función que asigne pesos por el tipo de capa de red, luego
  2. Aplique esos pesos a un modelo inicializado usando model.apply(fn) , que aplica una función a cada capa de modelo.

# takes in a module and applies the specified weight initialization def weights_init_uniform(m): classname = m.__class__.__name__ # for every Linear layer in a model.. if classname.find(''Linear'') != -1: # apply a uniform distribution to the weights and a bias=0 m.weight.data.uniform_(0.0, 1.0) m.bias.data.fill_(0) model_uniform = Net() model_uniform.apply(weights_init_uniform)

  • Después de 2 épocas:

Validation Accuracy 36.667% -- Uniform Weights Training Loss 3.208 -- Uniform Weights

Regla general para establecer pesos

La regla general para establecer los pesos en una red neuronal es establecerlos para que estén cerca de cero sin ser demasiado pequeños.

Una buena práctica es comenzar sus pesos en el rango de [-y, y] donde y=1/sqrt(n)
(n es el número de entradas a una neurona dada).

# takes in a module and applies the specified weight initialization def weights_init_uniform_rule(m): classname = m.__class__.__name__ # for every Linear layer in a model.. if classname.find(''Linear'') != -1: # get the number of the inputs n = m.in_features y = 1.0/np.sqrt(n) m.weight.data.uniform_(-y, y) m.bias.data.fill_(0) # create a new model with these weights model_rule = Net() model_rule.apply(weights_init_uniform_rule)

a continuación, comparamos el rendimiento de NN, pesos inicializados con distribución uniforme [-0.5,0.5) versus aquel cuyo peso se inicializa usando la regla general

  • Después de 2 épocas:

Validation Accuracy 75.817% -- Centered Weights [-0.5, 0.5) 85.208% -- General Rule [-y, y) Training Loss 0.705 -- Centered Weights [-0.5, 0.5) 0.469 -- General Rule [-y, y)

distribución normal para inicializar los pesos

La distribución normal debe tener una media de 0 y una desviación estándar de y=1/sqrt(n) , donde n es el número de entradas a NN

## takes in a module and applies the specified weight initialization def weights_init_normal(m): ''''''Takes in a module and initializes all linear layers with weight values taken from a normal distribution.'''''' classname = m.__class__.__name__ # for every Linear layer in a model if classname.find(''Linear'') != -1: y = m.in_features # m.weight.data shoud be taken from a normal distribution m.weight.data.normal_(0.0,1/np.sqrt(y)) # m.bias.data should be 0 m.bias.data.fill_(0)

a continuación mostramos el rendimiento de dos NN, uno inicializado con distribución uniforme y el otro con distribución normal

  • Después de 2 épocas:

Validation Accuracy 85.775% -- Uniform Rule [-y, y) 84.717% -- Normal Distribution Training Loss 0.329 -- Uniform Rule [-y, y) 0.443 -- Normal Distribution


Perdón por llegar tan tarde, espero que mi respuesta ayude.

Para inicializar pesos con una normal distribution use:

torch.nn.init.normal_(tensor, mean=0, std=1)

O para usar una constant distribution escriba:

torch.nn.init.constant_(tensor, value)

O para usar una uniform distribution :

torch.nn.init.uniform_(tensor, a=0, b=1) # a: lower_bound, b: upper_bound

Puede consultar otros métodos para inicializar tensores here


Si ve una advertencia de desaprobación (@ Fábio Perez) ...

def init_weights(m): if type(m) == nn.Linear: torch.nn.init.xavier_uniform_(m.weight) m.bias.data.fill_(0.01) net = nn.Sequential(nn.Linear(2, 2), nn.Linear(2, 2)) net.apply(init_weights)


import torch.nn as nn # a simple network rand_net = nn.Sequential(nn.Linear(in_features, h_size), nn.BatchNorm1d(h_size), nn.ReLU(), nn.Linear(h_size, h_size), nn.BatchNorm1d(h_size), nn.ReLU(), nn.Linear(h_size, 1), nn.ReLU()) # initialization function, first checks the module type, # then applies the desired changes to the weights def init_normal(m): if type(m) == nn.Linear: nn.init.uniform_(m.weight) # use the modules apply function to recursively apply the initialization rand_net.apply(init_normal)