Aplicação de Algoritmos Genéticos em Redes Neurais

 

Computador, DNA e cérebro conectado a uma rede neural

Aqui no DidáticaTech você já aprendeu tanto sobre Algoritmos Genéticos como sobre Redes Neurais.

Agora chegou o momento de unir esses conhecimentos: é possível aplicar o conceito de Algoritmos Genéticos nas Redes Neurais; basta lembrar que uma rede neural é um sistema que tem uma arquitetura – o que pode ser visto como uma função.

Há uma entrada; passamos pela função; e há uma saída.

Se estivermos lidando com um problema de classificação, como reconhecer dígitos escritos à mão, por exemplo, a entrada será um conjunto de valores numéricos, que representa a densidade de cada um dos pixels.

Se passamos essa entrada para essa grande função, – que é uma rede neural – a rede vai nos dar uma saída, que será a classe. Essa função gigante, que é feita a partir da arquitetura de uma rede neural, é calibrada por meio dos pesos e dos bias da rede.

Afinal, cada uma das entradas vai passar por uma conta onde serão multiplicados cada um dos valores – cada um dos pixels. No caso do nosso exemplo, cada um dos valores será multiplicado por pesos específicos, somados no final a um bias; depois, passará por uma função de ativação; após isso, será transmitido para uma próxima camada de neurônios – que consistem em pesos e bias – que multiplicarão os neurônios anteriores.

Em resumo, temos um conjunto muito grande de pesos e bias que, por terem valores bem específicos, ao entrar determinado valor – uma amostra – tem a saída desejada: entramos com o número 0 e a resposta é a classe 0, entramos com o dígito 3 e a resposta é a classe 3.

Uma rede bem calibrada, então, é nada mais do que uma função que dá exatamente aquela resposta que esperávamos a partir de uma entrada.

No fim das contas, quando fazemos um treinamento de uma rede neural – todo o processo de escolher um algoritmo de gradiente descendente para fazer as iterações até que a nossa função de custo vai sendo reduzida – não podemos esquecer que estamos procurando quais são os pesos e bias com o melhor ajuste, de maneira que tenhamos o melhor resultado possível (a saída desejada) a partir de uma entrada.

Pódio com três colocados - melhores indivíduos de uma população genéticaAgora, vamos pensar no conceito de Algoritmos Genéticos. Podemos simplesmente enxergar todos os pesos e bias da rede como sendo genes – ou elementos e características – de um grande vetor que é o que representa o total de conjuntos (elementos) dessa rede neural.

Queremos encontrar qual o melhor indivíduo, qual o melhor conjunto de elementos possível, para calibrar de forma que tenhamos o melhor resultado da nossa função no fim das contas.

Podemos estabelecer uma fitness function que seja a própria função de custo que será minimizada, por exemplo. Ou ainda, podemos usar o score final. Se tivermos um resultado positivo – acertamos a classe–; temos um score específico.

Nesse caso, podemos usar simplesmente o valor final do score como sendo um parâmetro para calibrar a nossa fitness function, já que queremos maximizar esse score, por exemplo. O fato é: vamos escolher uma fitness function e vamos escolher nossos indivíduos – que são os pesos e bias da rede.

Se estamos trabalhando com uma rede neural que possui uma quantidade total de 10 mil parâmetros, ou seja, 10 mil pesos e bias ao todo, podemos encará-la como sendo um grande vetor com 10 mil elementos/genes que são os pesos e bias. A partir daí, vamos estabelecer o seguinte processo:

  1. Partimos da população inicial de vários desses indivíduos em que cada um tem 10 mil elementos variando, por exemplo, entre 0 e 1;
  2. Podemos estabelecer inicialmente um sorteio randômico;
  3. Avaliamos o fitness score de todos esses indivíduos;
  4. Ficamos com os melhores e aplicamos crossover e mutação;
  5. Novamente, vemos quais são os melhores fitness score;

Esse processo pode ser repetido quantas vezes for necessário. Assim, iterativamente, vamos trabalhando em cima dos indivíduos até que, ao final, cheguemos a um indivíduo que possua uma combinação de pesos e bias tal que o nosso score final seja um score desejado: um score alto, de acordo com os critérios que estabelecemos.

Esse conceito é muito simples. Como é possível perceber, estamos “ignorando” o processo do gradiente descendente. Se, por acaso, alguém não gosta do gradiente descendente ou não se sente confortável com a matemática por trás dele (todo aquele rebuscamento matemático que é feito para fazer cada update do gradiente descendente estocástico e todos os algoritmos de gradiente descendente envolvidos), a boa notícia é que, trabalhando com algoritmos genéticos, não utilizaremos o gradiente descendente!

Essa é uma forma alternativa de estimarmos os pesos e bias de uma rede neural que tem um princípio de compreensão muito mais simples e intuitiva. Ou seja, trabalhando com algoritmos genéticos, podemos ainda assim trabalhar otimizando uma rede neural.

Podemos criar um conjunto de pesos e bias inicial, a partir do total de parâmetros que a rede possui, não importando qual é a arquitetura da rede neural.

O fato é que, independentemente da arquitetura, uma rede será calibrada a partir de pesos e bias. Dessa forma, criamos um vetor – que é um indivíduo, uma quantidade total de elementos – e, a partir disso, começamos nosso processo iterativo até que se chegue no indivíduo que tenha um ajuste fino satisfatório.

Prós e contras da utilização dos Algoritmos Genéticos

Corredor dando largada - conceito de chegar em um resultado rápidoÉ evidente, entretanto, que essa técnica possui tanto vantagens quanto desvantagens.

Uma das vantagens dos algoritmos genéticos aplicados à rede neurais é que para problemas bastante simples, em que a solução possa ser rapidamente encontrada, pode ser que os algoritmos genéticos cheguem no resultado mais rápido do que quando utilizada a técnica de gradiente descendente.

Afinal, o gradiente descendente tem a limitação de que cada passo é sempre dado devagar; são dados passos curtos de cada vez. Por isso o learning rate costuma ser pequeno. Como cada iteração, nesse caso, é feita apenas com um lote, não com o total dos dados de treinamento, esses passos não podem ser muito longos.

Caso contrário, poderia ser que, ao darmos um passo muito grande em uma direção errada, fossemos parar em um caminho que não fosse o desejado.

Dessa forma, é muito importante dar um passo de cada vez. Assim garantimos um treinamento mais estável. Além disso, com um problema rápido de ser resolvido, é possível que a utilização do gradiente descendente torne a resolução mais lenta.

Com os algoritmos genéticos, por outro lado, é possível que na primeira seleção natural já cheguemos a um indivíduo com o score muito alto. Ou seja, a possível rapidez dos algoritmos genéticos é uma vantagem.

Problemas mais complexos (possuem muitos parâmetros), no entanto, podem ficar computacionalmente muito custosos com os algoritmos genéticos. Problemas de deep learning que possuem uma quantidade grande de dados para fazer o treinamento e uma quantidade grande de parâmetros são exemplos disso.

Se temos um conjunto de dados de treinamento que é de milhões de amostras, para saber o fitness score de um indivíduo apenas (um conjunto de pesos e bias), temos que testar qual é o fitness score em relação a todos os dados de treino; temos que passar todo o conjunto de dados e treinos para esse modelo fazer uma previsão de todas as classes e, a partir disso, estabelecer o fitness score.

Porém, fazer isso para cada um dos milhões de indivíduos da população seria muito custoso: teríamos de passar todos os dados de treino para todos os indivíduos da população e fazer isso muitas vezes, porque vamos ter que iterar para muitas gerações – já que estaríamos trabalhando com milhares, milhões ou até bilhões de parâmetros, como alguns casos mais recentes de deep learning.

Retirada de uma pequena amostra de um frasco maior

Como haveria muitos parâmetros, isso iria requerer muitas variações – muitas combinações de crossover e de mutação – ainda mais se pensarmos em um ajuste fino de cada um deles; muitas gerações teriam de ser feitas e cada uma delas teria que avaliar cada um dos indivíduos, passando por todos os dados de treinamento.

Em casos como esse, o gradiente descendente, trabalhando com o conceito de batch size (uma amostra pequena, um pedaço pequeno de lotes de treinamentos), conseguiria agilizar bastante a procura do mínimo da função de custo.

Afinal, o gradiente descendente não depende de todos os dados de treinamento para fazer cada uma das validações.

Esse é um dos motivos pelos quais os algoritmos genéticos, hoje, não são a técnica mais usada na prática do deep learning; o gradiente descendente é a técnica dominante.

O que o futuro aguarda?

Entretanto, as pesquisas na área têm avançado; é possível que, em um futuro próximo, os algoritmos genéticos voltem à tona como uma boa alternativa para problemas, até mesmo, de deep learning.

Além disso, poderia se fazer uma combinação de algoritmos genéticos e gradiente descendente para se explorar o melhor dos dois mundos. Estão sendo ainda, cada vez mais, usadas técnicas diferentes.

Diferentes espécies de pássarosNesse âmbito, há uma técnica interessante, lançada pela Opening Eye, que usa uma fitness function – o fitness score. Essa técnica não simplesmente estabelece um objetivo de ter uma classe correta de um problema de classificação – ou ter um valor de regressão no qual se quer chegar – mas dá uma fitness score que premia a variabilidade.

Dessa forma, sempre que uma característica nova foi gerada, em relação ao resultado final, há uma recompensa.

Nesse caso, o algoritmo genético estaria sempre perseguindo coisas novas. Ao se fazer bastante exploração, é possível, depois, salvar os melhores fitness score.

Isso ajuda a não estagnar em pontos de máximo ou mínimo locais, o que é um dos desafios do deep learning hoje: problemas muito complexos possuem uma função no hiperespaço que não conseguimos enxergar; não conseguimos ver quais são os pontos de máximo ou de mínimo; não sabemos exatamente se o algoritmo de gradiente descendente está caminhando ou está estagnando num mínimo local ao invés de procurar o mínimo global da função total.

A utilização dos algoritmos genéticos seria capaz de solucionar o problema da estagnação; eles podem ajudar no porque eles trazem uma variabilidade – uma mutação –, pois se sempre é premiada a questão da variabilidade, pode ser que se explore bastante o ambiente.

E, como dito anteriormente, essa característica dos algoritmos genéticos aliada ao gradiente descendente pode gerar estados muito satisfatórios.

Continue estudando!

Por esse ser um interessante campo de pesquisa em ascensão, é válido começarmos a trabalhar com algoritmos genéticos e outros tópicos de machine learning. Para isso, preparamos um curso no qual você poderá se aprofundar nesses assuntos:

Aqui você aprende sobre bibliotecas, funções, problemas simples e complexos, dentre diversas outras coisas. Depois, estenderemos isso para as redes neurais e vamos aplicar na prática a calibrarção de pesos e bias de uma rede neural. Poderemos ver esse conceito de algoritmos genéticos sendo aplicado em diferentes esferas.

Além disso, temos outras diversas opções, tanto pagas quanto gratuitas, para você prosseguir com seu aprendizado. Clique aqui e confira!

Leia também: