Eu estava examinando um artigo do BERT que usa GELU (Gaussian Error Linear Unit), que afirma a equação como
fonte
Eu estava examinando um artigo do BERT que usa GELU (Gaussian Error Linear Unit), que afirma a equação como
Podemos expandir a distribuição cumulativa de , ou seja, , da seguinte maneira:
Observe que isso é uma definição , não uma equação (ou uma relação). Os autores forneceram algumas justificativas para esta proposta, por exemplo, uma analogia estocástica , porém matematicamente, essa é apenas uma definição.
Aqui está o enredo de GELU:
Para esse tipo de aproximação numérica, a idéia principal é encontrar uma função semelhante (principalmente baseada na experiência), parametrizá-la e ajustá-la a um conjunto de pontos da função original.
Sabendo que está muito próximo de
e a primeira derivada de coincide com a de em , que é , passamos a ajustar
(ou com mais termos) para um conjunto de pontos .
Eu ajustei essa função em 20 amostras entre ( usando este site ), e aqui estão os coeficientes:
Ao definir , foi estimado em . Com mais amostras de uma faixa maior (esse local é permitido apenas 20), o coeficiente estará mais próximo do do papel . Finalmente chegamos
com erro quadrático médio para .
Observe que se não utilizássemos o relacionamento entre as primeiras derivadas, o termo teria sido incluído nos parâmetros da seguinte maneira
que é menos bonito (menos analítico, mais numérico)!
Conforme sugerido por @BookYourLuck , podemos utilizar a paridade de funções para restringir o espaço de polinômios em que pesquisamos. Ou seja, como é uma função ímpar, ou seja, e também é uma função ímpar, função polinomial dentro também deve ser ímpar (deve ter poderes ímpares de ) para ter
Anteriormente, tivemos a sorte de acabar com coeficientes (quase) zero para potências pares e ; no entanto, em geral, isso pode levar a aproximações de baixa qualidade que, por exemplo, têm um termo como que está sendo cancelado por termos extras (pares ou ímpares) em vez de simplesmente optar por .
Uma relação semelhante ocorre entre e (sigmoide), proposta no artigo como outra aproximação, com erro quadrático médio para .
Aqui está um código Python para gerar pontos de dados, ajustar as funções e calcular os erros quadráticos médios:
import math
import numpy as np
import scipy.optimize as optimize
def tahn(xs, a):
return [math.tanh(math.sqrt(2 / math.pi) * (x + a * x**3)) for x in xs]
def sigmoid(xs, a):
return [2 * (1 / (1 + math.exp(-a * x)) - 0.5) for x in xs]
print_points = 0
np.random.seed(123)
# xs = [-2, -1, -.9, -.7, 0.6, -.5, -.4, -.3, -0.2, -.1, 0,
# .1, 0.2, .3, .4, .5, 0.6, .7, .9, 2]
# xs = np.concatenate((np.arange(-1, 1, 0.2), np.arange(-4, 4, 0.8)))
# xs = np.concatenate((np.arange(-2, 2, 0.5), np.arange(-8, 8, 1.6)))
xs = np.arange(-10, 10, 0.001)
erfs = np.array([math.erf(x/math.sqrt(2)) for x in xs])
ys = np.array([0.5 * x * (1 + math.erf(x/math.sqrt(2))) for x in xs])
# Fit tanh and sigmoid curves to erf points
tanh_popt, _ = optimize.curve_fit(tahn, xs, erfs)
print('Tanh fit: a=%5.5f' % tuple(tanh_popt))
sig_popt, _ = optimize.curve_fit(sigmoid, xs, erfs)
print('Sigmoid fit: a=%5.5f' % tuple(sig_popt))
# curves used in https://mycurvefit.com:
# 1. sinh(sqrt(2/3.141593)*(x+a*x^2+b*x^3+c*x^4+d*x^5))/cosh(sqrt(2/3.141593)*(x+a*x^2+b*x^3+c*x^4+d*x^5))
# 2. sinh(sqrt(2/3.141593)*(x+b*x^3))/cosh(sqrt(2/3.141593)*(x+b*x^3))
y_paper_tanh = np.array([0.5 * x * (1 + math.tanh(math.sqrt(2/math.pi)*(x + 0.044715 * x**3))) for x in xs])
tanh_error_paper = (np.square(ys - y_paper_tanh)).mean()
y_alt_tanh = np.array([0.5 * x * (1 + math.tanh(math.sqrt(2/math.pi)*(x + tanh_popt[0] * x**3))) for x in xs])
tanh_error_alt = (np.square(ys - y_alt_tanh)).mean()
# curve used in https://mycurvefit.com:
# 1. 2*(1/(1+2.718281828459^(-(a*x))) - 0.5)
y_paper_sigmoid = np.array([x * (1 / (1 + math.exp(-1.702 * x))) for x in xs])
sigmoid_error_paper = (np.square(ys - y_paper_sigmoid)).mean()
y_alt_sigmoid = np.array([x * (1 / (1 + math.exp(-sig_popt[0] * x))) for x in xs])
sigmoid_error_alt = (np.square(ys - y_alt_sigmoid)).mean()
print('Paper tanh error:', tanh_error_paper)
print('Alternative tanh error:', tanh_error_alt)
print('Paper sigmoid error:', sigmoid_error_paper)
print('Alternative sigmoid error:', sigmoid_error_alt)
if print_points == 1:
print(len(xs))
for x, erf in zip(xs, erfs):
print(x, erf)
Resultado:
Tanh fit: a=0.04485
Sigmoid fit: a=1.70099
Paper tanh error: 2.4329173471294176e-08
Alternative tanh error: 2.698034519269613e-08
Paper sigmoid error: 5.6479106346814546e-05
Alternative sigmoid error: 5.704246564663601e-05
Observe primeiro que por paridade de . Precisamos mostrar que por .Φ(x)=12erfc(−x2–√)=12(1+erf(x2–√)) erf erf(x2–√)≈tanh(2π−−√(x+ax3)) a≈0.044715
Para grandes valores de , ambas as funções são delimitadas em . Para pequeno , a respectiva série Taylor lê e Substituindo, obtemos que e Equacionando o coeficiente para , encontramos próximo ao dox [−1,1] x tanh(x)=x−x33+o(x3) erf(x)=2π−−√(x−x33)+o(x3). tanh(2π−−√(x+ax3))=2π−−√(x+(a−23π)x3)+o(x3) erf(x2–√)=2π−−√(x−x36)+o(x3). x3 a≈0.04553992412 0.044715 .
fonte