Redes Neurais – C# – Hopfield

Continuando o artigo anterior de Redes Neurais para C#, vamos agora entrar no glorioso mundo das redes neurais de Hopfield, esta que é muito provavelmente o tipo mais simples de implementação para ANN. Em uma definição resumida do formato em questão, direi que trata-se de uma rede que contem uma única camada, completamente conectada e auto associativa, onde, por auto associativa quero dizer que uma vez que um padrão seja identificado, o mesmo será retornado.

Oh Yeah, bring it on!

Diminuindo o ritmo no blá-blá-blá, que tal um exemplo funcional de com o que a tal da rede neural se parece? Para facilitar o entendimento eu vou simplificar o exemplo ao máximo, logo não me culpe se você em seguida sentir que é o novo gênio da AI e resolver criar seu próprio andróid-escravo-lavador de carros.

Abaixo, um diagrama simples dos relacionamentos de uma rede contendo quatro neurônios:

Imagem 1 - Rede Neural básica

Imagem 1 – Rede Neural básica

Na rede neural representada pela Imagem 1, vê-se claramente que todos os neurônios estão interligados uns aos outros. Para facilitar o entendimento, podemos representar esta visão na matriz abaixo. Note que os pontos de intersecção ocorrem em todos os pontos exceto de forma recursiva¹. Isto será explicado com maiores detalhes mais a frente.

Neurônio N1 N2 N3 N4
N1 x x x
N2 x x x
N3 x x x
N4 x x x

Weight Matrix

Antes de ser crucificado pelo que estou prestes a fazer, para fins de entendimento mais claro do conteúdo, vou deliberadamente traduzir este termo técnico para algo mais fácil de assimilar. De agora em diante, eu declaro que em meus tópicos, weight matrix se chamará matriz de pesagem. Pronto!

Ok, mas você pode (e deveria) se perguntar: WTF matriz de pesagem?!

Imagine por um instante o que estamos tentando realizar aqui: Através da criação de redes neurais artificiais, estamos a grosso modo tentando de alguma forma replicar o que acontece naturalmente em um animal com capacidade de aprendizado, logo, como acontece na natureza nossas redes neurais artificiais nascem burras e precisam passar por um processo para que organizem um dado conjnto de dados e informações de forma coesa, formando então uma estrutura que contém conhecimento.

Existem algumas formas de se ministrar este aprendizado das quais posso citar três (geralmente consideradas como apenas duas) e, desta vez não me atreverei a traduzir nomes:

  • Supervised learning:  Por este método, o processo de aprendizagem e calibragem do algoritmo é acompanhado por um processo externo, seja um sistema ou um humano;
  • Unsupervised learning:  O sistema descobre a melhor solução por meio de estatísticas, sem intervenção externa;
  • Reinforcement Learning: Um processo que mistura ambos os modelos acima e, por este motivo, não é considerado como um processo independente em algumas literaturas.

A matriz de pesagem é o mecanismo pelo qual as redes neurais que trabalharemos serão ajustadas. Abaixo o exemplo mais comum de uma matriz de pesagem para uma rede Hopfield de quatro neurônios que identifica o padrão 0101 e 1010, note porém que estou passando a solução do problema antes de descrever o problema em si. Mais adiante veremos como esta matriz foi formada:

Neurônio N1 N2 N3 N4
N1 0 -1 1 -1
N2 -1 0 -1 1
N3 1 -1 0 -1
N4 -1 1 -1 0

Você só está tendo contato com estes dados agora pois acredito ser mais fácil de explicar os próximos passos com uma representação visual do que buscamos com toda a parafernália que será explicada / montada.

Matematica.Apply();

Um dos principais pontos que utilizaremos em Hopfield é a manipulação de vetores, como a idéia aqui é passar a parte prática, não vou me ater à explicações da parte matemática da operação, porém, é muito fácil encontrar referências on-line sobre o assunto².

Para explicar a montagem da matriz de pesagem, vamos iniciar com uma matriz vazia, como a seguinte:

Neurônio N1 N2 N3 N4
N1 0 0 0 0
N2 0 0 0 0
N3 0 0 0 0
N4 0 0 0 0

Para começar, vamos fornecer o valor 0101 para a matriz acima de forma a respeitar as já mencionadas regras básicas da estrutura¹. Esta matriz derivada é chamada de matriz de contribuição.

No calculo desta matriz, existem algumas necessidades que devem ser supridas, sendo:

  • Cálculo dos valores bipolares do input (no caso, baseado em 0101). Calcular os valores bipolares significa que representaremos os valores binários por meio de -1 e 1 e não por 0 e 1; A função que representa este requisito é:
  • bipolar
    A função que realiza a conversão dos valores para bipolar é a seguinte:Podemos representá-la em C# da seguinte forma:

    (2 * valor) - 1;

    Já para conversão inversa, de bipolar para binário:E em C#:

    (valor + 1) / 2.0;
  • Como segundo passo, nós vamos transpor e multiplicar os valores bipolares de 0101 por eles mesmos;
  • Como terceiro e último passo nós precisamos zerar todas as ocorrências onde os neurônios eventualmente poderia se comunicar consigo mesmo¹;

Para realizarmos o processamento utilizando os valores bipolares utilizamos a função Signum:

Onde:

b são os limites inferiores e superiores;
v é o valor de ativação da unidade.

0101, põe na conta do Papa!

Ok, agora com as devidas explicações e notações em mãos, vamos para a execução dos três passos descritos acima:

  1. Converter para bipolar: A conversão de cada um dos dígitos de nosso input 0,1,0 e 1 para um valor bipolar, resulta em –1,1, -1 e 1. Esta nova sequência numérica é a nossa base para construção da matriz de contribuição, logo, neste ponto possuímos uma matriz com quatro linhas e uma coluna, que pode ser representada em C# da seguinte forma:
    
     /// Matriz com quatro linhas e uma coluna
     double[] matrizLinha = new double[] { -1, 1, -1, 1 };
  2. Multiplicação das matrizes:

    1. Agora que possuímos uma matriz com os valores de entrada já convertidos para bipolar, podemos dar o segundo passo que é onde invertemos a matriz existente, neste ponto a matriz se tornará algo equivalente à:
      ///
      
       /// Matriz com uma linha e quatro colunas
       double[,] matrizColuna = new double[1, 4] { { -1, 1, -1, 1} };
       

      Note que basicamente o que fizemos foi reorganizar a estrutura da matriz de forma a transformar colunas em linhas (o oposto também é valido);

    2. O passo anterior nos forneceu uma nova matriz, a qual, utilizaremos para realizar uma multiplicação entre a matriz descrita no Item 1 e a nova, descrita no Item 2.1. Se você, apesar de ter sido direcionado, ainda não como realizar multiplicação de matrizes, ainda há tempo, clique aqui.O Resultado desta multiplicação será a estrutura abaixo:
       /// Matriz correspondente a multiplicação das matrizes anteriores
       double[,] matriz = {
       { 1, -1, 1, -1 }, /// Primeira coluna
       {-1,1,-1,1},     /// Segunda coluna
       {1,-1,1,-1},     /// Terceira coluna
       {-1,1,-1,1}      /// Quarta coluna
       };
  3. Limpar as referências recursivas: Agora que possuímos o produto da multiplicação das matrizes de contribuição, devemos remover os valores que denotem recursividade. Para isto, o procedimento não poderia ser mais simples, bastando definir o valor 0 a todas as posições da matriz onde o valor do índice da coluna é igual ao da linha ou seja [x,x] = 0.
    /// Para uma matriz de 4 posições
    for (int i = 0; i < 4; i++) {
    matriz[i, i] = 0;
    }

Neste ponto possuímos uma matriz com a seguinte representação em memória:


 /// Matriz correspondente a multiplicação das matrizes anteriores
  double[,] matriz = {
 { 0, -1, 1, -1 }, /// Primeira coluna
 {-1,0,-1,1},     /// Segunda coluna
 {1,-1,0,-1},     /// Terceira coluna
 {-1,1,-1,0}      /// Quarta coluna
 };

Esta matriz sim tem uma utilidade para o algoritmo como um todo. Ela agora poderá ser adicionada à matriz de pesagem. Se nós esperamos que esta rede neural reconheça o padrão 0101 então esta será a matriz de pesagem. Na verdade, por meio desta exata mesma matriz de pesagem também é possível reconhecer o padrão 1010, que é considerado o oposto do padrão inicial. Quando trabalhando com padrões binários, uma mesma matriz de pesagem é compartilhada para padrões inversos.

Porém, se esperamos ser capazes de reconhecer outros padrões de input (como, por exemplo 0110 ou 1001), então precisamos calcular a matriz de contribuição para ambos os inputs e compilar seus resultados em uma matriz de pesagem.

No próximo post, uma aplicação de reconhecimento de padrões utilizando o que vimos hoje.

Mais info

¹As premissas básicas das redes Hopfield são as seguintes: e , onde somos impedidos de recorrência e guiados a uma simetria de pesos.

²Operações matemáticas com vetores.

Referências

3 comentários

  1. Ótimo post pra quem tá começando na área… Muito mais fácil de digerir do que algumas das literaturas (não que eu queira construir meu próprio “andróid-escravo-lavador de carros”, hehe).

    Curtir

  2. O conceito é o mesmo para reconhecer um texto?
    Exemplo, criar uma rede neural que saiba que:
    Spider man 4 é igual a Spider 4 man e diferente de spider man 3?

    Curtir

    • Então Roberto, para a sua questão uma lógica tradicional resolveria, visto que não existe um desvio entre o input e o resultado esperado. Não é necessário ‘treinar’ o algoritimo para realizar qualquer tipo de inferência ou evolução. O que, por outro lado, seria interessante utilizar AI / RN (Probabilidade), seria para o caso de onde o usuário ao inputar “Spider Man 4”, na realidade queria dizer, “Spider Man 3″… o algoritimo poderia trabalhar com variaveis que vao desde dados sobre o usuário (idade, filmes que já assistiu, etc), até os itens mais randomicos (local de onde está realizando a busca, horário, etc)… isto tudo deve fazer parte do seu estudo da solução… caso seja este seu caso, de uma olhada em redes bayesianas: http://en.wikipedia.org/wiki/Bayesian_network

      Bons estudos!

      Curtir

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s

%d blogueiros gostam disto: