Estou treinando uma rede neural (detalhes não importantes) em que os dados de destino são um vetor de ângulos (entre 0 e 2 * pi). Estou procurando conselhos sobre como codificar esses dados. Aqui está o que estou tentando atualmente (com sucesso limitado):
1) Codificação 1-de-C: divido os ângulos possíveis configurados em mais ou menos 1000 ângulos discretos e, em seguida, indico um ângulo específico colocando 1 no índice relevante. O problema disso é que a rede simplesmente aprende a emitir todos os 0s (já que isso é quase exatamente correto).
2) Escalonamento simples: escalonei o intervalo de saída da rede ([0,1]) para [0,2 * pi]. O problema aqui é que os ângulos têm naturalmente uma topologia circular (ou seja, 0,0001 e 2 * pi estão realmente próximos um do outro). Com esse tipo de codificação, essas informações são perdidas.
Todas as sugestões serão apreciadas!
fonte
Respostas:
Introdução
Acho essa pergunta realmente interessante, suponho que alguém tenha publicado um trabalho sobre ela, mas é meu dia de folga, então não quero ir atrás de referências.
Portanto, poderíamos considerá-lo como uma representação / codificação da saída, o que faço nesta resposta. Eu continuo pensando que existe uma maneira melhor, onde você pode simplesmente usar uma função de perda ligeiramente diferente. (Talvez soma das diferenças ao quadrado, usando o módulo de subtração 2 ).π
Mas em diante com a resposta real.
Método
Proponho que um ângulo seja representado como um par de valores, seu seno e seu cosseno.θ
Portanto, a função de codificação é: e a função de decodificação é: Para o arctan2 sendo as tangentes inversas, preservando a direção em todos os quadrantes)θ ↦ ( sin( θ ) , cos( θ ) )
( y1, y2) ↦ arctan2 ( y1, y2)
Em teoria, você poderia trabalhar de forma equivalente diretamente com os ângulos se sua ferramenta usar suporte
atan2
como uma função de camada (recebendo exatamente 2 entradas e produzindo 1 saída). O TensorFlow faz isso agora e oferece suporte à descida gradiente , embora não seja destinado a esse uso. Eu investiguei usandoout = atan2(sigmoid(ylogit), sigmoid(xlogit))
uma função de perdamin((pred - out)^2, (pred - out - 2pi)^2)
. Descobri que ele treinava muito pior do que usarouts = tanh(ylogit), outc = tanh(xlogit))
com uma função de perda0.5((sin(pred) - outs)^2 + (cos(pred) - outc)^2
. Que eu acho que pode ser atribuído ao gradiente ser descontínuo poratan2
Meu teste aqui o executa como uma função de pré-processamento
Para avaliar isso, defini uma tarefa:
Eu implementei uma função gerar essas imagens aleatoriamente, com linhas em ângulos aleatórios (NB: as versões anteriores deste post usavam inclinações aleatórias, em vez de ângulos aleatórios. Agradecemos a @Ari Herman por apontar isso. Agora está corrigido). Eu construí várias redes neurais para avaliar o desempenho da tarefa. Os detalhes completos da implementação estão neste caderno Jupyter . O código está todo em Julia e eu uso a biblioteca de rede neural Mocha .
Para comparação, apresento-o contra os métodos alternativos de escala para 0,1. e colocar em 500 escaninhos e usar softmax com etiqueta macia. Não estou particularmente feliz com o último e sinto que preciso ajustá-lo. É por isso que, diferentemente dos outros, eu apenas o testo por 1.000 iterações, contra os outros dois que foram executados por 1.000 e por 10.000
Configuração Experimental
As imagens eram pixels, com a linha voltada para o centro e indo para a borda. Não havia ruído, etc. na imagem, apenas uma linha "preta", sobre fundo branco.101 × 101
Para cada trilha, 1.000 treinamentos e 1.000 imagens de teste foram geradas aleatoriamente.
A rede de avaliação tinha uma única camada oculta de largura 500. Neurônios sigmóides foram usados na camada oculta.
Foi treinado por Decocção de Gradiente Estocástico, com uma taxa de aprendizado fixa de 0,01 e um momento fixo de 0,9.
Não houve regularização ou abandono. Nem houve qualquer tipo de convolução, etc. Uma rede simples, que espero sugira que esses resultados generalizem
É muito fácil ajustar esses parâmetros no código de teste , e eu encorajo as pessoas a fazer isso. (e procure por erros no teste).
Resultados
Meus resultados são os seguintes:
Onde me refiro ao erro, esse é o valor absoluto da diferença entre o ângulo de saída da rede neural e o ângulo real. Portanto, o erro médio (por exemplo) é a média dos 1.000 casos de teste dessa diferença, etc. Não tenho certeza de que não devo escalá-lo novamente, cometendo um erro de dizer igual para um erro de ). π7 π4 π4
Apresento também a precisão em vários níveis de granularidade. A precisão é a parte dos casos de teste que foi corrigida. Isso
accuracy_to_point01
significa que foi contado como correto se a saída estivesse dentro de 0,01 do ângulo real. Nenhuma das representações obteve resultados perfeitos, mas isso não surpreende, dado o funcionamento da matemática de ponto flutuante.Se você der uma olhada no histórico deste post, verá que os resultados têm um pouco de ruído para eles, um pouco diferente a cada vez que o executo. Mas a ordem geral e a escala de valores permanecem as mesmas; permitindo assim tirar algumas conclusões.
Discussão
Binning com softmax tem um desempenho de longe o pior, pois eu disse que não tenho certeza de que não estraguei nada na implementação. Porém, ele apresenta um desempenho ligeiramente acima da taxa de estimativa. se apenas estivéssemos supondo que estaríamos recebendo um erro médio deπ
A codificação sin / cos tem um desempenho significativamente melhor que a codificação em escala 0-1. A melhoria é na medida em que, em 1.000 iterações de treinamento, o sin / cos está apresentando um desempenho três vezes melhor na maioria das métricas do que o dimensionamento em 10.000 iterações.
Eu acho que, em parte, isso está relacionado à melhoria da generalização, pois ambos estavam obtendo um erro quadrático médio bastante semelhante no conjunto de treinamento, pelo menos uma vez que 10.000 iterações foram executadas.
Certamente, existe um limite superior para o melhor desempenho possível nessa tarefa, já que o ângulo pode ser mais ou menos qualquer número real, mas nem todos esses anjos produzem linhas diferentes na resolução de pixels. Portanto, como, por exemplo, os ângulos 45.0 e 45.0000001 estão vinculados à mesma imagem nessa resolução, nenhum método jamais obterá os dois perfeitamente corretos.101 × 101
Também parece provável que, em uma escala absoluta, para ir além desse desempenho, seja necessária uma rede neural melhor. Em vez do muito simples descrito acima na configuração experimental.
Conclusão.
Parece que a representação sin / cos é de longe a melhor das representações que investiguei aqui. Isso faz sentido, pois tem um valor suave à medida que você se move ao redor do círculo. Também gosto que o inverso possa ser feito com o arctan2 , que é elegante.
Acredito que a tarefa apresentada seja suficiente em sua capacidade de apresentar um desafio razoável para a rede. Embora eu ache que realmente esteja apenas aprendendo a fazer o ajuste de curva para , talvez seja muito fácil. E talvez pior ainda, esteja favorecendo a representação emparelhada. Eu não acho que seja, mas está ficando tarde aqui, então talvez eu tenha perdido algo que eu convido você novamente a examinar meu código . Sugira melhorias ou tarefas alternativas.f( x ) = y1y2x
fonte
tan(angle)
tão bem, dado que tan não está definido para todos os ângulos (por exemplo, ). Vou executá-lo novamente com ângulos gerados aleatoriamente e editar as postagens.Aqui está outra implementação do Python comparando a codificação proposta por Lyndon White a uma abordagem em bin. O código abaixo produziu a seguinte saída:
Como você pode ver, enquanto a abordagem binned executa admiravelmente nesta tarefa de brinquedo, a codificação desempenho melhor em todas as configurações de treinamento, às vezes por uma margem considerável. Eu suspeito que a tarefa específica se tornou mais complexo, os benefícios da utilização Lyndon Branco 's representação se tornaria mais pronunciada.( sin ( θ ) , cos ( θ ) )( pecado( θ ) , cos( θ ) ) (sin(θ),cos(θ))
fonte
Aqui está minha versão em Python do seu experimento. Mantive muitos detalhes da sua implementação iguais, em particular utilizo o mesmo tamanho de imagem, tamanhos de camada de rede, taxa de aprendizado, momento e métricas de sucesso.
Cada rede testada possui uma camada oculta (tamanho = 500) com neurônios logísticos. Os neurônios de saída são lineares ou softmax, conforme observado. Usei 1.000 imagens de treinamento e 1.000 imagens de teste que foram geradas de forma independente e aleatória (para que haja repetições). O treinamento consistiu em 50 iterações no conjunto de treinamento.
Consegui obter uma precisão muito boa usando binning e codificação "gaussiana" (um nome que eu criei; semelhante ao binning, exceto que o vetor de saída de destino tem o formato exp (-pi * ([1,2,3, ... , 500] - idx) ** 2) em que idx é o índice correspondente ao ângulo correto). O código está abaixo; Aqui estão meus resultados:
Erro de teste para codificação (cos, sin):
1.000 imagens de treinamento, 1.000 imagens de teste, 50 iterações, saída linear
Média: 0,0911558142071
Mediana: 0.0429723541743
Mínimo: 2.77769843793e-06
Máximo: 6.2608513539
Precisão de 0,1: 85,2%
Precisão em 0,01: 11,6%
Precisão em 0.001: 1.0%
Erro de teste para codificação [-1,1]:
1.000 imagens de treinamento, 1.000 imagens de teste, 50 iterações, saída linear
Média: 0.234181700523
Mediana: 0.17460197307
Mínimo: 0.000473665840258
Máximo: 6.00637777237
Precisão em 0.1: 29.9%
Precisão em 0,01: 3,3%
Precisão de 0,001: 0,1%
Erro de teste para codificação 1-de-500:
1.000 imagens de treinamento, 1.000 imagens de teste, 50 iterações, saída softmax
Média: 0,0298767021922
Mediana: 0.00388858079174
Mínimo: 4.08712407829e-06
Máximo: 6.2784479965
Precisão de 0,1: 99,6%
Precisão em 0,01: 88,9%
Precisão de 0,001: 13,5%
Erro de teste para codificação gaussiana:
1.000 imagens de treinamento, 1.000 imagens de teste, 50 iterações, saída softmax
Não consigo descobrir por que nossos resultados parecem estar em contradição um com o outro, mas parece valer uma investigação mais aprofundada.
fonte
Outra maneira de codificar o ângulo é como um conjunto de dois valores:
Isso teria o mesmo problema que o arctan2, pois o gradiente é indefinido em theta = 0. Não tenho tempo para treinar uma rede e comparar com outras codificações, mas neste artigo a técnica parecia razoavelmente bem-sucedida.
fonte