Estoy tratando de tren de una sola capa de un autoencoder utilizando minFunc, y mientras que la función de costo parece disminuir, cuando está activado, el DerivativeCheck falla. El código que estoy usando es como cierre del libro de texto los valores de lo posible, aunque extremadamente simplificado.
La función de pérdida que estoy usando es el cuadrado del error de:
$ J(W; x) = \frac{1}{2}||a^{l} - x||^2 $
con $a^{l}$ igual a $\sigma(W^{T}x)$ donde $\sigma$ es la función sigmoidea. El gradiente por lo tanto debe ser:
$ \delta = (a^{l} - x)*a^{l}(1 - a^{l}) $
$ \nabla_{W} = \delta(a^{l-1})^T $
Tenga en cuenta, que para simplificar las cosas, me he dejado el sesgo por completo. Mientras que esto va a provocar un mal funcionamiento, no debe afectar el gradiente de verificación, ya que estoy buscando solo el peso de la matriz. Además, he atado el codificador y el decodificador de matrices, por lo que efectivamente hay una sola matriz de pesos.
El código que estoy usando para la función de pérdida es (edit: he vectorizados el lazo que tenía y limpiar el código un poco):
% loss function passed to minFunc
function [ loss, grad ] = calcLoss(theta, X, nHidden)
[nInstances, nVars] = size(X);
% we get the variables a single vector, so need to roll it into a weight matrix
W = reshape(theta(1:nVars*nHidden), nVars, nHidden);
Wp = W; % tied weight matrix
% encode each example (nInstances)
hidden = sigmoid(X*W);
% decode each sample (nInstances)
output = sigmoid(hidden*Wp);
% loss function: sum(-0.5.*(x - output).^2)
% derivative of loss: -(x - output)*f'(o)
% if f is sigmoid, then f'(o) = output.*(1-output)
diff = X - output;
error = -diff .* output .* (1 - output);
dW = hidden*error';
loss = 0.5*sum(diff(:).^2, 2) ./ nInstances;
% need to unroll gradient matrix back into a single vector
grad = dW(:) ./ nInstances;
end
A continuación está el código que uso para ejecutar el optimizador (por una sola vez, como el tiempo de ejecución es bastante larga con todas las muestras de formación):
examples = 5000;
fprintf('loading data..\n');
images = readMNIST('train-images-idx3-ubyte', examples) / 255.0;
data = images(:, :, 1:examples);
% each row is a different training sample
X = reshape(data, examples, 784);
% initialize weight matrix with random values
% W: (R^{784} -> R^{10}), W': (R^{10} -> R^{784})
numHidden = 10; % NOTE: this is extremely small to speed up DerivativeCheck
numVisible = 784;
low = -4*sqrt(6./(numHidden + numVisible));
high = 4*sqrt(6./(numHidden + numVisible));
W = low + (high-low)*rand(numVisible, numHidden);
% run optimization
options = {};
options.Display = 'iter';
options.GradObj = 'on';
options.MaxIter = 10;
mfopts.MaxFunEvals = ceil(options.MaxIter * 2.5);
options.DerivativeCheck = 'on';
options.Method = 'lbfgs';
[ x, f, exitFlag, output] = minFunc(@calcLoss, W(:), options, X, numHidden);
Los resultados que obtengo con el DerivitiveCheck en son generalmente de menos de 0, pero mayor que 0.1. He tratado de código similar utilizando lote de gradiente de la pendiente, y obtener resultados ligeramente mejores (algunos son < 0.0001, pero ciertamente no todos).
No estoy seguro de si cometí un error con mi matemáticas o código. Cualquier ayuda sería muy apreciada!
actualización
He descubierto un pequeño error en mi código (que no aparece en el código de abajo) causando excepcionalmente mal rendimiento. Por desgracia, todavía estoy recibiendo cada vez menos-de-buenos resultados. Por ejemplo, la comparación entre los dos gradientes:
calculate check
0.0379 0.0383
0.0413 0.0409
0.0339 0.0342
0.0281 0.0282
0.0322 0.0320
con diferencias de hasta 0.04, lo que estoy suponiendo que sigue fallando.