Solucionando problemas de implementação de rede neural

7

Estive no curso de Standford / Coursera Machine Learning ; e está indo muito bem. Estou realmente mais interessado na compreensão do tópico do que em obter a nota do curso e, como tal, estou tentando escrever todo o código em uma linguagem de programação em que sou mais fluente (algo que eu possa facilmente descobrir). raízes de).

A maneira como aprendo melhor é através da solução de problemas, por isso implementei uma rede neural e ela não funciona. Parece que tenho a mesma probabilidade de cada classe, independentemente do exemplo de teste (por exemplo, 0,45 da classe 0, 0,55 da classe 1, independentemente dos valores de entrada). Estranhamente, esse não é o caso se eu remover todas as camadas ocultas.

Aqui está uma breve descrição do que faço;

Set all Theta's (weights) to a small random number

for each training example

set activation 0 on layer 0 as 1 (bias)
set layer 1 activations = inputs

forward propagate;
 Z(j+1) = Theta(j) x activation(j)  [matrix operations]
 activation(j+1) = Sigmoid function (Z(j+1)) [element wise sigmoid]

Set Hx = final layer activations

Set bias of each layer (activation 0,0) = 1

[back propagate]
calculate delta;
delta(last layer) = activation(last layer) - Y  [Y is the expected answer from training set]

delta(j) = transpose(Theta(j)) x delta(j+1) .* (activation(j) .*(Ones - activation(j))

[where ones is a matrix of 1's in every cell; and .* is the element wise multiplication]
[Don't calculate delta(0) since there ins't one for input layer]


DeltaCap(j) = DeltaCap(j) + delta(j+1) x transpose(activation(j))

Next [End for]

Calculate D;

D(j) = 1/#Training * DeltaCap(j) (for j = 0)

D(j) = 1/#Training * DeltaCap(j) + Lambda/#Training * Theta(j) (for j = 0)


[calculate cost function]

J(theta) = -1/#training * Y*Log(Hx) + (1-Y)*log(1-Hx) + lambda/ (2 * #training) * theta^2

Recalculate Theta

Theta = Theta - alpha * D

Provavelmente não é muita coisa para continuar. Se alguém puder me dizer se há alguma falha importante no meu código que seria fantástica, caso contrário, alguma idéia geral de onde eu poderia estar errado / como depurar algo assim também seria ótimo.

EDITAR:

Aqui está uma imagem rápida da rede (incluindo um caso de teste de entradas e respostas) (após 1 milhão de iterações de descida de gradiente);

insira a descrição da imagem aqui

O conjunto de dados que usei são duas pontuações nos exames como x e o sucesso / fracasso de ingressar em uma universidade como y. Claramente, duas pontuações de 0 significariam falha na entrada na universidade, no entanto, a rede sugere 56% de chance de obtê-la com 0 como entrada.

Edite # 2;

Eu executei um algoritmo de verificação de gradiente com o seguinte tipo de resultados;

Cálculo numérico: -0.0074962585205895493 Valor da propagação: 0.62021047431540277

Cálculo numérico: 0.0032635827218463476 Valor da propagação: -0.39564819922432665

etc. Claramente, há algo errado aqui; Eu vou trabalhar com isso.

FraserOfSmeg
fonte
11
Como você inicializa os pesos? Você já tentou verificar os gradientes produzidos pelo algoritmo backprop (isso envolve executar a rede feed-forward muitas vezes, com uma pequena variação em cada peso e medir a diferença na saída)?
Neil Slater
@ NeilSlater Inicializo os pesos da seguinte forma: rnd () × 2 × e -e [basicamente escolhe um pequeno número entre -e ee onde e é apenas um valor próximo de zero]. Ainda não fiz a verificação de gradiente, ainda não estou 100% claro sobre esse processo. Eu traço J (teta) e J (teta) 1-J (teta) 0 [J atual (teta) - último].
FraserOfSmeg
Até onde eu vejo, não há grande falha no seu código. No entanto, muitas pequenas coisas podem dar errado. Sugiro que primeiro tente implementar o código usando os códigos de esqueleto fornecidos, por exemplo, ex4.m, etc. Em particular, o uso de sigmoidGradient.m pode ajudá-lo a verificar se o cálculo do gradiente está correto.
Yuqian

Respostas:

1

Suas entradas são dimensionadas ? Não fazer isso pode fazer com que os pesos explodam imediatamente.

É prática comum pré-processar sua entrada para estar entre -1 e 1 ou pelo menos nesse intervalo. Caso contrário, você corre o risco de seus gradientes explodirem ou desaparecerem (cobertos aqui ).

jamesmf
fonte
Obrigado pela entrada (trocadilho intencional), mas como as duas entradas possuem pontuações em 100, os dois recursos têm a mesma escala, portanto o dimensionamento do recurso não é necessário (pelo menos é o que eu entendo?). No entanto, pensei nisso também e tentei com cada valor escalado entre 0 e 1 (pontuação / 100), mas os mesmos problemas surgiram.
FraserOfSmeg
Você já olhou as ativações de cada camada para algumas iterações?
jamesmf