Я пытаюсь реализовать обратный распространяющийся автоматический кодер (обучение с градиентным спуском) и хотел убедиться, что я правильно рассчитываю градиент. Этот учебник предлагает вычислять производную каждого параметра по одному: grad_i(theta) = (J(theta_i+epsilon) - J(theta_i-epsilon)) / (2*epsilon)
. Я написал пример кода в Matlab, чтобы сделать это, но без особой удачи - различия между градиентом, вычисленным по производной, и градиентом, найденным численно, имеют тенденцию быть большими (>> 4 значащих числа). *
Если кто-то может предложить какие-либо предложения, я был бы очень признателен за помощь (либо в моем расчете градиента, либо в том, как я выполняю проверку). Поскольку я значительно упростил код, чтобы сделать его более читабельным, я не включил смещения и больше не связываю матрицы весов.
Сначала я инициализирую переменные:
numHidden = 200;
numVisible = 784;
low = -4*sqrt(6./(numHidden + numVisible));
high = 4*sqrt(6./(numHidden + numVisible));
encoder = low + (high-low)*rand(numVisible, numHidden);
decoder = low + (high-low)*rand(numHidden, numVisible);
Далее, учитывая некоторое входное изображение x
, выполните прямое распространение:
a = sigmoid(x*encoder);
z = sigmoid(a*decoder); % (reconstruction of x)
Используемая мной функция потерь - стандартная & Sigma; (0,5 * (z - x) ^ 2)):
% first calculate the error by finding the derivative of sum(0.5*(z-x).^2),
% which is (f(h)-x)*f'(h), where z = f(h), h = a*decoder, and
% f = sigmoid(x). However, since the derivative of the sigmoid is
% sigmoid*(1 - sigmoid), we get:
error_0 = (z - x).*z.*(1-z);
% The gradient \Delta w_{ji} = error_j*a_i
gDecoder = error_0'*a;
% not important, but included for completeness
% do back-propagation one layer down
error_1 = (error_0*encoder).*a.*(1-a);
gEncoder = error_1'*x;
И, наконец, проверьте правильность градиента (в этом случае просто сделайте это для декодера):
epsilon = 10e-5;
check = gDecoder(:); % the values we obtained above
for i = 1:size(decoder(:), 1)
% calculate J+
theta = decoder(:); % unroll
theta(i) = theta(i) + epsilon;
decoderp = reshape(theta, size(decoder)); % re-roll
a = sigmoid(x*encoder);
z = sigmoid(a*decoderp);
Jp = sum(0.5*(z - x).^2);
% calculate J-
theta = decoder(:);
theta(i) = theta(i) - epsilon;
decoderp = reshape(theta, size(decoder));
a = sigmoid(x*encoder);
z = sigmoid(a*decoderp);
Jm = sum(0.5*(z - x).^2);
grad_i = (Jp - Jm) / (2*epsilon);
diff = abs(grad_i - check(i));
fprintf('%d: %f <=> %f: %f\n', i, grad_i, check(i), diff);
end
Запуск этого набора данных MNIST (для первой записи) дает такие результаты, как:
2: 0.093885 <=> 0.028398: 0.065487
3: 0.066285 <=> 0.031096: 0.035189
5: 0.053074 <=> 0.019839: 0.033235
6: 0.108249 <=> 0.042407: 0.065843
7: 0.091576 <=> 0.009014: 0.082562