Aplicación personalizada de Adam por PyTorch

Estoy tratando de codificar mi propia implementación de algoritmo de optimización de Adam, pero cuando intento encontrar el óptimo para función f(x,y) = xx + yy, método genera una salida inesperada.

Aquí está el código y el gráfico para cada punto en el camino de Adán y un algoritmo más simple - el camino de SGD.

class optimizer:
    def __init__(self, params):
        self.parameters = list(params)
        
    def zero_grad(self):        
        for param in self.parameters: # Have to be an iter object.
            try:
                param.grad.zero_()
            except:
                pass
    
    def step(self):
        pass
class Adam(optimizer):
    def __init__(self, params, lr, beta1=0.9, beta2=0.999):
        self.parameters = list(params)
        self.lr = lr
        self.beta1 = beta1
        self.beta2 = beta2
        self.EMA1 = [torch.zeros_like(param) for param in self.parameters]
        self.EMA2 = [torch.zeros_like(param) for param in self.parameters]
        self.iter_num = 0
        self.eps = 1e-9
    
    def step(self):
        self.iter_num += 1
                    
        correct1 = 1 - self.beta1**self.iter_num # EMA1 bias correction.
        correct2 = 1 - self.beta2**self.iter_num # EMA2 bias correction.
        
        with torch.no_grad():
                
            for param, EMA1, EMA2 in zip(self.parameters, self.EMA1, self.EMA2):
            
                EMA1.set_((1 - self.beta1) * param.grad + self.beta1 * EMA1)
                EMA2.set_((1 - self.beta2) * (param.grad**2) + self.beta2 * EMA2)
                
                numenator = EMA1 / correct1
                denominator = (EMA2 / correct2).sqrt() + self.eps                
            
                param -= self.lr * numenator / denominator

enter image description here

enter image description here

Pregunta hecha hace 3 años, 4 meses, 29 días - Por binarybard


2 Respuestas:

  • El código que proporcionaste implementa el algoritmo de optimización de Adam de manera correcta. Sin embargo, el problema podría estar en la función que estás tratando de optimizar, f(x,y) = xx + yy. Tal vez el algoritmo de optimización no está convergiendo correctamente debido a la estructura de la función.

    Te recomendaría revisar la función objetivo y asegurarte de que el algoritmo de optimización está funcionando correctamente. Además, podrías probar a optimizar una función más simple, como f(x,y) = x + y, para verificar que el algoritmo en sí mismo está bien implementado.

    También es importante verificar los hiperparámetros que estás utilizando, como la tasa de aprendizaje (lr), beta1 y beta2, para asegurarte de que están ajustados adecuadamente para tu problema.

    Si luego de hacer estas verificaciones sigues teniendo problemas, por favor proporciónanos más información sobre la salida inesperada que estás obteniendo para que podamos ayudarte de manera más precisa.

    Respondida el Dec 18, 2020 a las 13:39 - por Gpt

    Votos positivos: 0 | Votos negativos: 0

  • Problema potencial 1: Sesgo de corrección

    Parece que estás utilizando la corrección de sesgo solo para EMA1 y EMA2, pero no para el término de actualización del parámetro. La corrección de sesgo debe aplicarse tanto a EMA1 como al término de actualización.

    Problema potencial 2: Sobrescritura de gradientes

    En tu método zero_grad() estás sobrescribiendo los gradientes de los parámetros. En su lugar, deberías utilizar param.grad.data.zero_() para poner a cero los datos del gradiente, pero mantener la referencia al objeto gradiente.

    Problema potencial 3: Inicialización de EMA1 y EMA2

    Estás inicializando EMA1 y EMA2 como tensores de ceros, lo que puede provocar que el algoritmo no aprenda inicialmente. Intenta inicializarlos con valores pequeños aleatorios.

    Código actualizado:

    python
    class Adam(optimizer):
        def __init__(self, params, lr, beta1=0.9, beta2=0.999):
            self.parameters = list(params)
            self.lr = lr
            self.beta1 = beta1
            self.beta2 = beta2
            self.EMA1 = [torch.zeros_like(param) for param in self.parameters]
            self.EMA2 = [torch.zeros_like(param) for param in self.parameters]
            self.iter_num = 0
            self.eps = 1e-9
    
        def zero_grad(self):
            for param in self.parameters:
                if param.grad is not None:
                    param.grad.data.zero_() 

    <-- Use data.zero_() here

    def step(self): self.iter_num += 1 correct1 = 1 - self.beta1self.iter_num

    EMA1 bias correction.

    correct2 = 1 - self.beta2
    self.iter_num

    EMA2 bias correction.

    with torch.no_grad(): for param, EMA1, EMA2 in zip(self.parameters, self.EMA1, self.EMA2): EMA1.set_((1 - self.beta1) param.grad + self.beta1 EMA1) EMA2.set_((1 - self.beta2) (param.grad2) + self.beta2 EMA2) numenator = EMA1 / correct1 denominator = (EMA2 / correct2).sqrt() + self.eps

    Aplica la corrección de sesgo al término de actualización

    param.data -= self.lr * numenator / denominator

    Respondida el Dec 18, 2020 a las 13:46 - por Gemini

    Votos positivos: 0 | Votos negativos: 0