{"id":1438,"date":"2022-09-16T20:48:50","date_gmt":"2022-09-16T20:48:50","guid":{"rendered":"https:\/\/visiorob.com.br\/?p=1438"},"modified":"2022-09-26T20:19:31","modified_gmt":"2022-09-26T20:19:31","slug":"iacar-usando-uma-rede-neural-para-o-controle-da-movimentacao-de-um-robo","status":"publish","type":"post","link":"https:\/\/visiorob.com.br\/index.php\/2022\/09\/16\/iacar-usando-uma-rede-neural-para-o-controle-da-movimentacao-de-um-robo\/","title":{"rendered":"IACar &#8211; Usando uma rede neural para o controle da movimenta\u00e7\u00e3o de um rob\u00f4"},"content":{"rendered":"\n<p>O objetivo aqui \u00e9 apresentar como podemos usar uma rede neural para tomadas de decis\u00e3o. No caso deste artigo a rede neural dever\u00e1 decidir se o rob\u00f4 deve virar para a esquerda, seguir em frente, ou virar para a direita, tendo como input sensores que ir\u00e3o indicar se existe caminho \u00e0 esquerda, a frente, ou \u00e0 direita.<\/p>\n\n\n\n<p>O grupo VisioRob est\u00e1 testando uma ferramenta a <a href=\"https:\/\/unity.com\/pt\/solutions\/automotive-transportation-manufacturing\/robotics\">Unity 3D<\/a> para simula\u00e7\u00e3o e controle de rob\u00f4s. Dessa forma utilizamos essa ferramenta para o desenvolvimento de um simulador onde temos um rob\u00f4 que ir\u00e1 se mover, utilizando uma rede neural para a tomada de decis\u00f5es. A rede neural dever\u00e1 ser treinada em outro ambiente e os seus pesos e bias informados para o simulador. Neste artigo irmos ser\u00e1 demonstrado o simulador e como podemos treinar uma rede neural para o simulador.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p><a href=\"https:\/\/visiorob.com.br\/IACar\/\" target=\"_blank\" rel=\"noreferrer noopener\">Acesse o simulador por este link<\/a><\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Introdu\u00e7\u00e3o sobre redes neurais<\/h2>\n\n\n\n<p>Podemos interpretar uma rede neural como um conjunto de neur\u00f4nios que se ligam de tal forma que podemos treinar esta estrutura para que ela possa tomar algumas decis\u00f5es baseadas em est\u00edmulos que ela recebe. J\u00e1 o neur\u00f4nio, que foi mencionado anteriormente, \u00e9 a unidade b\u00e1sica de uma rede neural. Ele \u00e9 respons\u00e1vel por receber est\u00edmulos e processar esses est\u00edmulos em suas caracter\u00edsticas. A estrutura b\u00e1sica de uma rede neural \u00e9 o que est\u00e1 apresentado na Figura 1.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/visiorob.com.br\/wp-content\/uploads\/2022\/09\/Figura01.png\" alt=\"\" class=\"wp-image-1461\" width=\"475\" height=\"283\"\/><figcaption>Figura 1 &#8211; Estrutura b\u00e1sica de uma rede neural<\/figcaption><\/figure>\n<\/div>\n\n\n<p>Os c\u00edrculos brancos na Figura 1 s\u00e3o os neur\u00f4nios, eles se ligam de forma a constru\u00edrem a rede neural. O funcionamento de um neur\u00f4nio pode ser descrito como:<\/p>\n\n\n\n<div class=\"wp-block-group\"><div class=\"wp-block-group__inner-container is-layout-flow wp-block-group-is-layout-flow\"><span class=\"wp-katex-eq katex-display\" data-display=\"true\">a = f(b_0+\\sum_{i=1}^{n}w_ix_i)<\/span>\n<\/div><\/div>\n\n\n\n<p>A equa\u00e7\u00e3o do neur\u00f4nio indica que o resultado dele, o valor de <span class=\"wp-katex-eq\" data-display=\"false\">a<\/span>, depende da combina\u00e7\u00e3o dos valores que ele recebe como entrada. Os valores de entrada s\u00e3o representados pelo <span class=\"wp-katex-eq\" data-display=\"false\">\\sum_{i=1}^{n}w_ix_i<\/span>, em que <span class=\"wp-katex-eq\" data-display=\"false\">x_i<\/span> representa um conjunto de valores informados pelos neur\u00f4nios ligados a este e <span class=\"wp-katex-eq\" data-display=\"false\">w_i<\/span> representa o quanto cada neur\u00f4nio anterior ir\u00e1 influenciar no resultado deste neur\u00f4nio. Para colaborar com o resultado ainda temos o valor <span class=\"wp-katex-eq\" data-display=\"false\">b_0<\/span>  que representa o bias, que podemos considerar como um desvio m\u00e9dio acrescentado ao desempenho do neur\u00f4nio.<\/p>\n\n\n\n<p>Por fim, o neur\u00f4nio pega o resultado e aplica \u00e0 uma fun\u00e7\u00e3o de ativa\u00e7\u00e3o, a fun\u00e7\u00e3o <span class=\"wp-katex-eq\" data-display=\"false\">f()<\/span>, que \u00e9 respons\u00e1vel por fazer com que o comportamento do neur\u00f4nio seja n\u00e3o linear. Sem essa fun\u00e7\u00e3o de ativa\u00e7\u00e3o o resultado da rede neural seria uma combina\u00e7\u00e3o linear de todos os neur\u00f4nios, o que impediria de que a rede neural trabalhasse de forma n\u00e3o linear. <a href=\"https:\/\/pt.frwiki.wiki\/wiki\/Fonction_d%27activation\" target=\"_blank\" rel=\"noreferrer noopener\">Existem v\u00e1rios modelos de fun\u00e7\u00e3o de ativa\u00e7\u00e3o comumente utilizados em redes neurais<\/a>.<\/p>\n\n\n\n<p>Agora que temos uma ideia de como as redes neurais artificiais s\u00e3o descritas matematicamente, vamos verificar como podemos utilizar uma em um sistema de controle para um rob\u00f4.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Rede neural do simulador do rob\u00f4<\/h2>\n\n\n\n<p>Para o controle do rob\u00f4, o simulador utiliza a rede neural apresentada na Figura 1. Conforme apresentado nela o rob\u00f4 possui tr\u00eas sensores, um para identificar se \u00e9 poss\u00edvel ir para esquerda, um para identificar se \u00e9 poss\u00edvel ir para frente e um para identificar se \u00e9 poss\u00edvel ir para direita. Estes sensores est\u00e3o ligados no que chamamos de camada de entrada ou <em>input layer<\/em>.<\/p>\n\n\n\n<p>O movimento do rob\u00f4 ir\u00e1 depender do resultado da camada de sa\u00edda ou <em>output layer<\/em>. No caso da Figura 1 podemos identificar a camada de sa\u00edda sendo o neur\u00f4nio que est\u00e1 mais a direita. Neste simulador o rob\u00f4 ir\u00e1 virar para a direita se o valor do ultimo neur\u00f4nio for maior do que <span class=\"wp-katex-eq\" data-display=\"false\">+0,5<\/span>; ir\u00e1 virar para a esquerda se o valor do ultimo neur\u00f4nio for menor do que <span class=\"wp-katex-eq\" data-display=\"false\">-0,5<\/span>; e, por fim, ir\u00e1 seguir em frente se o valor do ultimo neur\u00f4nio estiver entre <span class=\"wp-katex-eq\" data-display=\"false\">-0,5<\/span> e <span class=\"wp-katex-eq\" data-display=\"false\">+0,5<\/span>.<\/p>\n\n\n\n<p>Qualquer conjunto de neur\u00f4nios que estejam entre a camada de entrada e a camada de sa\u00edda \u00e9 o que consideramos como as camadas ocultas ou <em>hidden layer<\/em>. Conforme apresentado na Figura 1, a rede neural do simulador apresenta apenas uma \u00fanica camada oculta. Para o problema apresentado ela ser\u00e1 o suficiente. Dependendo do problema pode ser necess\u00e1rio adicionar mais camadas ocultas.<\/p>\n\n\n\n<p>Veja que o neur\u00f4nio da sa\u00edda dever\u00e1 fornecer um valor maior do que <span class=\"wp-katex-eq\" data-display=\"false\">0,5<\/span> at\u00e9 um valor menor do que <span class=\"wp-katex-eq\" data-display=\"false\">-0,5<\/span>. Para facilitar, vamos descrever que os valores da sa\u00edda dever\u00e3o estar entre <span class=\"wp-katex-eq\" data-display=\"false\">-1<\/span> e <span class=\"wp-katex-eq\" data-display=\"false\">+1<\/span>. Dessa forma, podemos utilizar, como fun\u00e7\u00e3o de ativa\u00e7\u00e3o, a fun\u00e7\u00e3o Tangente Hiperb\u00f3lica, que \u00e9 uma fun\u00e7\u00e3o matem\u00e1tica que fornece valores ente <span class=\"wp-katex-eq\" data-display=\"false\">-1<\/span> e <span class=\"wp-katex-eq\" data-display=\"false\">+1<\/span>. A equa\u00e7\u00e3o da Tangente Hiperb\u00f3lica \u00e9 descrita como:<\/p>\n\n\n<span class=\"wp-katex-eq katex-display\" data-display=\"true\">f(x)=tanh(x)=\\frac{e^x-e^{-x}}{e^x+e^{-x}}<\/span>\n\n\n\n<p>Para o simulador, a fun\u00e7\u00e3o de ativa\u00e7\u00e3o Tangente Hiperb\u00f3lica ser\u00e1 utilizada tanto na camada de sa\u00edda como na camada oculta. A camada de entrada n\u00e3o precisa de uma fun\u00e7\u00e3o de ativa\u00e7\u00e3o, j\u00e1 que ela ir\u00e1 trabalhar com os valores recebidos dos sensores.<\/p>\n\n\n\n<p>Agora conhecemos a rede neural do rob\u00f4, mais isso n\u00e3o \u00e9 o suficiente para fazer ele possa tomar decis\u00f5es. Precisamos, agora treinar a rede neural para que ela possa, de certa forma, &#8220;aprender&#8221; como orientar o rob\u00f4. Para realizarmos o treinamento, vamos construir uma rede neural equivalente \u00e0 do rob\u00f4 em um ambiente que possamos treinar ela.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Construindo uma rede neural como a do rob\u00f4 utilizando o TensorFlow<\/h2>\n\n\n\n<p>O <a href=\"https:\/\/www.tensorflow.org\/\" target=\"_blank\" rel=\"noreferrer noopener\">TensorFlow<\/a> \u00e9 uma biblioteca em Python que ajuda a criar e treinar redes neurais artificiais. Tamb\u00e9m recomendo o uso da plataforma <a href=\"https:\/\/colab.research.google.com\/\" target=\"_blank\" rel=\"noreferrer noopener\">Google Colab<\/a> pois ela j\u00e1 vem com diversas bibliotecas instaladas e deixamos o peso computacional para os computadores do Google lidarem com eles.<\/p>\n\n\n\n<p>Como vamos usar Python, vamos come\u00e7ar importando as bibliotecas que vamos utilizar. Podemos fazer isso usando os comandos:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">import tensorflow as tf\nfrom matplotlib import pyplot as plt\nimport numpy as np<\/pre>\n\n\n\n<p>Agora podemos usar o TensorFlow com <strong>tf<\/strong>, gerarmos gr\u00e1ficos com <strong>plt<\/strong> e trabalhar com vetores utilizando <strong>np<\/strong>.<\/p>\n\n\n\n<p>Vamos, agora, criarmos uma rede neural id\u00eantica \u00e0 do simulador utilizando o TensorFlow. Para isso vamos utilizar os comandos:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">model = tf.keras.Sequential([\n    tf.keras.layers.Dense(units=5, activation=\"tanh\",\n                          input_shape=(3,),\n                          name=\"Hidden_Layer\",\n                          ),\n    tf.keras.layers.Dense(units=1, activation=\"tanh\",\n                          name=\"Output_Layer\",\n                          )\n])<\/pre>\n\n\n\n<p>Agora a nossa rede neural est\u00e1 armazenada no objeto <strong>model<\/strong>. O comando <strong>tf.keras.Sequential<\/strong> indica que vamos criar v\u00e1rias camadas uma ligada na outra. O comando <strong>tf.keras.layers.Dense<\/strong> indica que a camada que vamos criar uma camada composta apenas de neur\u00f4nios.<\/p>\n\n\n\n<p>Como usamos <strong>tf.keras.Sequential<\/strong> precisamos indicar as camadas na ordem que elas devem ser criadas. A primeira camada foi criada informando que ela deva ser constru\u00edda usando: <strong>units=5<\/strong>, para indicar que esta camada tem 5 neur\u00f4nio (como apresentado na Figura 1); <strong>activation=&#8221;tanh&#8221;<\/strong>, para indicarmos que estamos usando a fun\u00e7\u00e3o de ativa\u00e7\u00e3o Tangente Hiperb\u00f3lica em todos os neur\u00f4nios desta camada; <strong>input_shape=(3,)<\/strong>, para indicar que teremos 3 (tr\u00eas) valores de entradas (que correspondem aos 3 sensores do rob\u00f4); e <strong>name=&#8221;Hidden_Layer&#8221;<\/strong>, para darmos um nome \u00e0 camada que neste caso identificamos ela como a camada oculta da rede neural (hidden layer).<\/p>\n\n\n\n<p>Para a camada de sa\u00edda, seguimos com o mesmo racioc\u00ednio. Por\u00e9m, no caso usamos: <strong>units=1<\/strong>, j\u00e1 que a camada de sa\u00edda deve conter apenas um \u00fanico neur\u00f4nio; <strong>activation=&#8221;tanh&#8221;<\/strong>, para, novamente, usarmos a fun\u00e7\u00e3o Tangente Hiperb\u00f3lica como fun\u00e7\u00e3o de ativa\u00e7\u00e3o; e <strong>name=&#8221;Output_Layer&#8221;<\/strong>, para darmos um nome a esta camada.<\/p>\n\n\n\n<p>Lembrando que essa rede neural est\u00e1 descrita no objeto model, podemos verificar as caracter\u00edsticas construtivas dela com o comando:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">model.summary()<\/pre>\n\n\n\n<p>Para finalizarmos a constru\u00e7\u00e3o da rede neural, precisamos informar qual t\u00e9cnica ela deve utilizar para aprender. Neste caso, vamos utilizar o m\u00e9todo <strong>compile<\/strong> da nossa rede neural <strong>model<\/strong>:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">model.compile(optimizer='adam', \n              loss='mae')<\/pre>\n\n\n\n<p>Aqui o <strong>optimizer=&#8217;adam&#8217;<\/strong> indica qual t\u00e9cnica a rede neural ir\u00e1 utilizar para otimizar o resultado. O termo <a href=\"https:\/\/www.tensorflow.org\/api_docs\/python\/tf\/keras\/optimizers\/Adam\" target=\"_blank\" rel=\"noreferrer noopener\">adam<\/a> se refere \u00e0 t\u00e9cnica de otimiza\u00e7\u00e3o estoc\u00e1stica de descida de gradiente, em outras palavras, como a rede neural vai alterar os pesos para minimizar o erro na sua sa\u00edda.<\/p>\n\n\n\n<p>Como m\u00e9trica para a avalia\u00e7\u00e3o do erro estamos utilizando <strong>loss= &#8216;mae&#8217;<\/strong>. A m\u00e9trica <a href=\"https:\/\/www.tensorflow.org\/api_docs\/python\/tf\/keras\/losses\/MeanAbsoluteError\" target=\"_blank\" rel=\"noreferrer noopener\">mae<\/a> se refere \u00e0 m\u00e9dia dos erros absolutos, sendo o objetivo chegar no menor erro poss\u00edvel. A equa\u00e7\u00e3o da m\u00e9trica mae \u00e9 descrita como:<\/p>\n\n\n<span class=\"wp-katex-eq katex-display\" data-display=\"true\">loss = \\left | y_{true} - y_{pred} \\right |<\/span>\n\n\n\n<p>Em que:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li><span class=\"wp-katex-eq\" data-display=\"false\">loss<\/span> \u00e9 o valor do erro e o valor a ser minimizado, aproximado de zero;<\/li><li><span class=\"wp-katex-eq\" data-display=\"false\">y_{true}<\/span> \u00e9 o valor real, sendo aquele que deve ser indicado pela rede neural;<\/li><li><span class=\"wp-katex-eq\" data-display=\"false\">y_{pred}<\/span> \u00e9 o valor indicado pela rede neural quando enviamos os dados para ela.<\/li><\/ul>\n\n\n\n<p>Basicamente, estamos falando para a rede neural que, durante o seu treinamento, ela deve testar poss\u00edveis leituras dos sensores e encontrar uma resposta. Esta resposta ser\u00e1 confrontada com a resposta correta. A diferen\u00e7a entre a resposta correta e a resposta obtida pela rede neural \u00e9 o que chamamos de erro. Por fim, o otimizador adam ir\u00e1 trabalhar alterando os pesos (os valores de <span class=\"wp-katex-eq\" data-display=\"false\">w_i<\/span>) de forma que o valor de <span class=\"wp-katex-eq\" data-display=\"false\">loss<\/span> v\u00e1 diminuindo.<\/p>\n\n\n\n<p> Agora que temos uma rede neural semelhante \u00e0 do rob\u00f4, precisamos trein\u00e1-la para que ela seja capaz de controlar o rob\u00f4 de forma adequada. Por\u00e9m, para treinar realizar o treinamento precisamos de um conjunto de dados.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Criando um conjunto de dados para treinar a rede neural<\/h2>\n\n\n\n<p>O rob\u00f4 que iremos treinar possui 3 (tr\u00eas) sensores, eles ser\u00e3o os valores de entrada para a rede neural. Estes sensores ir\u00e3o indicar 1 (um) caso o rob\u00f4 possa ir na dire\u00e7\u00e3o do sensor e 0 (zero) caso o rob\u00f4 n\u00e3o possa ir na dire\u00e7\u00e3o do sensor.<\/p>\n\n\n\n<p>Para cada combina\u00e7\u00e3o de valores para os sensores, devemos informar um valor de sa\u00edda para a rede neural, que ir\u00e3o indicar se o rob\u00f4 ou vira para a direita (valor maior do que <span class=\"wp-katex-eq\" data-display=\"false\">+0,5<\/span> &#8212; vamos utiliza <span class=\"wp-katex-eq\" data-display=\"false\">+1<\/span>), ou vira para a esquerda (valor menor do que <span class=\"wp-katex-eq\" data-display=\"false\">-0,5<\/span> &#8212; vamos utiliza <span class=\"wp-katex-eq\" data-display=\"false\">-1<\/span>), ou se ele deve seguir em frente (vamos utiliza <span class=\"wp-katex-eq\" data-display=\"false\">0<\/span>).<\/p>\n\n\n\n<p>Combinando os valores de entrada da rede neural e de sa\u00edda dela podemos criar a Tabela 1.<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table><tbody><tr><td class=\"has-text-align-center\" data-align=\"center\"><strong>Sensor da Esquerda<\/strong><\/td><td class=\"has-text-align-center\" data-align=\"center\"><strong>Sensor da Frente<\/strong><\/td><td class=\"has-text-align-center\" data-align=\"center\"><strong>Sensor da Direita<\/strong><\/td><td class=\"has-text-align-center\" data-align=\"center\"><strong>Sa\u00edda da Rede Neural<\/strong><\/td><td class=\"has-text-align-center\" data-align=\"center\"><strong>Comportamento do Rob\u00f4<\/strong><\/td><\/tr><tr><td class=\"has-text-align-center\" data-align=\"center\">0<\/td><td class=\"has-text-align-center\" data-align=\"center\">0<\/td><td class=\"has-text-align-center\" data-align=\"center\">0<\/td><td class=\"has-text-align-center\" data-align=\"center\">-1<\/td><td>Se n\u00e3o pode segui nem para direita, nem para frente, nem para esquerda, ent\u00e3o deve girar para a esquerda<\/td><\/tr><tr><td class=\"has-text-align-center\" data-align=\"center\">0<\/td><td class=\"has-text-align-center\" data-align=\"center\">0<\/td><td class=\"has-text-align-center\" data-align=\"center\">1<\/td><td class=\"has-text-align-center\" data-align=\"center\">1<\/td><td>Se s\u00f3 h\u00e1 caminho para direita, ent\u00e3o deve girar para a direita<\/td><\/tr><tr><td class=\"has-text-align-center\" data-align=\"center\">0<\/td><td class=\"has-text-align-center\" data-align=\"center\">1<\/td><td class=\"has-text-align-center\" data-align=\"center\">0<\/td><td class=\"has-text-align-center\" data-align=\"center\">0<\/td><td>Se s\u00f3 h\u00e1 caminho para frente, ent\u00e3o deve seguir em frente<\/td><\/tr><tr><td class=\"has-text-align-center\" data-align=\"center\">0<\/td><td class=\"has-text-align-center\" data-align=\"center\">1<\/td><td class=\"has-text-align-center\" data-align=\"center\">1<\/td><td class=\"has-text-align-center\" data-align=\"center\">0<\/td><td>Se h\u00e1 caminho para frente e para direita, ent\u00e3o deve seguir em frente<\/td><\/tr><tr><td class=\"has-text-align-center\" data-align=\"center\">1<\/td><td class=\"has-text-align-center\" data-align=\"center\">0<\/td><td class=\"has-text-align-center\" data-align=\"center\">0<\/td><td class=\"has-text-align-center\" data-align=\"center\">-1<\/td><td>Se s\u00f3 h\u00e1 caminho para a esquerda, ent\u00e3o deve girar para a esquerda<\/td><\/tr><tr><td class=\"has-text-align-center\" data-align=\"center\">1<\/td><td class=\"has-text-align-center\" data-align=\"center\">0<\/td><td class=\"has-text-align-center\" data-align=\"center\">1<\/td><td class=\"has-text-align-center\" data-align=\"center\">1<\/td><td>Se h\u00e1 caminho para a esquerda e para a direita, ent\u00e3o deve girar para a direita<\/td><\/tr><tr><td class=\"has-text-align-center\" data-align=\"center\">1<\/td><td class=\"has-text-align-center\" data-align=\"center\">1<\/td><td class=\"has-text-align-center\" data-align=\"center\">0<\/td><td class=\"has-text-align-center\" data-align=\"center\">0<\/td><td>Se h\u00e1 caminho para a esquerda e para frente, ent\u00e3o deve seguir em frente<\/td><\/tr><tr><td class=\"has-text-align-center\" data-align=\"center\">1<\/td><td class=\"has-text-align-center\" data-align=\"center\">1<\/td><td class=\"has-text-align-center\" data-align=\"center\">1<\/td><td class=\"has-text-align-center\" data-align=\"center\">0<\/td><td>Se h\u00e1 caminho para esquerda, para frente e para direita, ent\u00e3o deve seguir para frente<\/td><\/tr><\/tbody><\/table><figcaption>Tabela 1 &#8211; Indica\u00e7\u00e3o do comportamento do rob\u00f4 baseado nos valores indicados pelos sensores<\/figcaption><\/figure>\n\n\n\n<p>Repare que os valores apresentados na Tabela 1 listam todas as 8 (oito) combina\u00e7\u00f5es poss\u00edveis de valores informados pelos sensores nas colunas <strong>Sensor da Esquerda<\/strong>, <strong>Sensor da Frente<\/strong> e <strong>Sensor da Direita<\/strong>. J\u00e1 os valores da coluna <strong>Sa\u00edda da Rede Neural<\/strong> foram escolhidos por mim para que o rob\u00f4 tenha os comportamentos apresentados na coluna <strong>Comportamento do Rob\u00f4<\/strong>. Neste caso, \u00e9 poss\u00edvel alterar os valores apresentados na <strong>Sa\u00edda da Rede Neural<\/strong> para alterar o comportamento do rob\u00f4, de acordo com o objetivo que o projetista queira alcan\u00e7ar e tomando os devidos cuidados para que o rob\u00f4 n\u00e3o fa\u00e7a uma a\u00e7\u00e3o indesejada.<\/p>\n\n\n\n<p>Seguindo o modelo de comportamento indicado na Tabela 1, podemos descrever os dados de treinamento como:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">x_train = [[0,0,0],\n[0,0,1],\n[0,1,0],\n[0,1,1],\n[1,0,0],\n[1,0,1],\n[1,1,0],\n[1,1,1]]\n\ny_train = [[-1],\n[1],\n[0],\n[0],\n[-1],\n[1],\n[0],\n[0]]<\/pre>\n\n\n\n<p>Em que <strong>x_train<\/strong> \u00e9 uma lista que representa os conjunto dos poss\u00edveis valores de entrada, o dataset de entrada, e <strong>y_train<\/strong> \u00e9 uma lista que representa o comportamento do rob\u00f4 para cada conjunto de dados de <strong>x_train<\/strong>. <strong>y_train<\/strong> tamb\u00e9m \u00e9 conhecido como dataset de sa\u00edda.<\/p>\n\n\n\n<p>Agora j\u00e1 temos a rede neural e o dataset. O pr\u00f3ximo passo \u00e9 realizar o treinamento da rede neural para que ela possa interpretar os dados da entrada e informar qual \u00e9 a sa\u00edda mais adequada o poss\u00edvel.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Treinando a rede neural com o TensorFlow<\/h2>\n\n\n\n<p>Nesta etapa vamos utilizar o TensorFlow para treinar a rede neural. Podemos definir como treinamento da rede neural a varia\u00e7\u00e3o dos valores dos pesos (ou influ\u00eancia dos neur\u00f4nios) de uma camada na outra e a varia\u00e7\u00e3o do bias de tal forma que a rede neural possa indicar a melhor resposta o poss\u00edvel. No nosso caso estamos utilizando a estrat\u00e9gia <strong>adam<\/strong> e verificando o erro como <strong>mae<\/strong>, como informamos anteriormente.<\/p>\n\n\n\n<p>O treinamento com o TensorFlow pode ser realizado com o comando:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">training = model.fit(x_train, y_train,\n                   batch_size=8,\n                   epochs=1000,\n                   )<\/pre>\n\n\n\n<p>Conforme indicado, estaremos guardando o resultado do treinamento no objeto <strong>training<\/strong>. Para isso iremos pegar o objeto <strong>model<\/strong> que descreve a nossa rede neural e solicitar o m\u00e9todo <strong>fit<\/strong> dele. Como argumentos, estamos indicando <strong>x_train<\/strong> e <strong>y_train<\/strong> sendo os dados de entrada e os dados de sa\u00edda;  <strong>batch_size=8<\/strong>, em que <strong>batch_size<\/strong> \u00e9 a quantidade de dados que vamos jogar na rede neural ao mesmo tempo; <strong>epochs=1000<\/strong>, que quer dizer que vamos repetir o treinamento 1.000 vezes para, ent\u00e3o, avaliarmos o resultado dela.<\/p>\n\n\n\n<p>A fun\u00e7\u00e3o do <strong>batch_size<\/strong> \u00e9 reduzir o tamanho de datasets muito grande para que n\u00e3o sobrecarregue a mem\u00f3ria do computador que ir\u00e1 realizar o treinamento da rede neural. Neste caso, o dataset \u00e9 pequeno, tendo apenas 8 conjunto de dados poss\u00edveis, o que dificilmente ir\u00e1 sobrecarregar o computador que ir\u00e1 realizar o treinamento. Sendo, assim, foi indicado um <strong>batch_size=8<\/strong> que corresponde a usar todo o dataset deste projeto a cada \u00e9poca.<\/p>\n\n\n\n<p>Para acompanharmos o desempenho do treinamento, podemos recorrer a uma an\u00e1lise gr\u00e1fica da evolu\u00e7\u00e3o do erro. Isso pode ser feito pelos comandos:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">error_chart = np.array(training.history['loss'])\nplt.plot(error_chart)\nplt.show()<\/pre>\n\n\n\n<p>Como resultado pelo treinamento das primeiras 1.000 \u00e9pocas, temos o gr\u00e1fico da evolu\u00e7\u00e3o do erro apresentado na Figura 2.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"372\" height=\"248\" src=\"https:\/\/visiorob.com.br\/wp-content\/uploads\/2022\/09\/Figura02.png\" alt=\"\" class=\"wp-image-1487\"\/><figcaption>Figura 2 &#8211; Resultado do treinamento das primeiras 1.000 \u00e9pocas<\/figcaption><\/figure>\n<\/div>\n\n\n<p>Conforme podemos ver na Figura 2, o erro est\u00e1 sempre diminuindo. Isso indica que ainda h\u00e1 espa\u00e7o para melhorar o desempenho da rede neural. Essa melhoria pode ser obtida repetindo o processo de treinamento. Ap\u00f3s treinarmos por mais 1.000 \u00e9pocas temos o resultado apresentado na Figura 3.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"378\" height=\"248\" src=\"https:\/\/visiorob.com.br\/wp-content\/uploads\/2022\/09\/Figura03.png\" alt=\"\" class=\"wp-image-1488\"\/><figcaption>Figura 3 &#8211; Evolu\u00e7\u00e3o do erro ap\u00f3s uma segunda rodada de treinamento de 1.000 \u00e9pocas<\/figcaption><\/figure>\n<\/div>\n\n\n<p>Conforme podemos visualizar na Figura 3, o desempenho do erro est\u00e1 tendendo a chegar em um valor m\u00ednimo. Isso pode ser observado pelo formato da curva apresentada. Podemos continuar o treinamento, mais n\u00e3o haver\u00e1 grandes melhorias no desempenho da rede neural, conforme indicado na Figura 4.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"384\" height=\"248\" src=\"https:\/\/visiorob.com.br\/wp-content\/uploads\/2022\/09\/Figura04.png\" alt=\"\" class=\"wp-image-1489\"\/><figcaption>Figura 4 &#8211; Evolu\u00e7\u00e3o do erro ap\u00f3s a terceira rodada de treinamento de 1.000 \u00e9pocas<\/figcaption><\/figure>\n<\/div>\n\n\n<p>Como podemos visualizar na Figura 4, a melhoria do erro entre a segunda e terceira rodada de treinamento foi muito pequena, tanto que o gr\u00e1fico come\u00e7ou a ressaltar alguns aumentos no valor do erro durante o treinamento. Isso quer dizer que j\u00e1 estamos chegando ao limite do que essa rede neural \u00e9 capaz de nos entregar.<\/p>\n\n\n\n<p>Dessa forma, vamos ficar com os resultados que obtivemos ap\u00f3s a terceira rodada de treinamentos.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Observa\u00e7\u00e3o a respeito da quantidade de treinamentos<\/h2>\n\n\n\n<p>Quando estamos treinando uma rede neural devemos tomar cuidado para n\u00e3o for\u00e7armos muito o treinamento da rede neural e, ao mesmo tempo, tamb\u00e9m n\u00e3o treinarmos pouco ela.<\/p>\n\n\n\n<p>Se treinarmos pouco a rede neural chegaremos a um problema chamado de <em><strong>underfit<\/strong><\/em>, que corresponde ao fato da rede neural n\u00e3o conseguir apresentar resultados satisfat\u00f3rios, obtendo uma grande taxa de erro para quais quer valores usados como entrada.<\/p>\n\n\n\n<p>Por outro lado, se treinarmos muito a rede neural chegamos a um problema chamado de <strong><em>overfit<\/em><\/strong>, que corresponde ao fato da rede neural apresentar um erro extremamente baixo para os dados de treinamento, mas quando apresentamos novos dados para a rede neural ela apresenta uma taxa de erro elevada. Em outras palavras, podemos dizer que a rede neural &#8220;decorou&#8221; os dados de treinamento e s\u00f3 consegue trabalhar com eles.<\/p>\n\n\n\n<p>De maneira geral, quando treinamos uma rede neural esperamos que ela tamb\u00e9m seja capaz de trabalhar com valores distintos aos que foram apresentados a ela durante o treinamento.<\/p>\n\n\n\n<p>No caso espec\u00edfico do controle do rob\u00f4 n\u00e3o existe possibilidade de sinais de entrada diferente dos 8 apresentados na Tabela 1 e, dessa forma, para esta fun\u00e7\u00e3o n\u00e3o haver\u00e1 problemas no comportamento do rob\u00f4 caso cheguemos \u00e0 situa\u00e7\u00e3o de <strong><em>overfit<\/em><\/strong>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Transferindo o aprendizado para o rob\u00f4<\/h2>\n\n\n\n<p>Agora que treinamos uma rede neural que possui as mesmas caracter\u00edsticas do nosso rob\u00f4, temos que transferir esse aprendizado para ele. Isso \u00e9 feito informando o peso de cada liga\u00e7\u00e3o entre os neur\u00f4nios e o bias de cada neur\u00f4nio da rede neural do rob\u00f4.<\/p>\n\n\n\n<p>Podemos obter os pesos e o bias da primeira camada usando os comandos:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">print(model.layers[0].weights)\nprint(model.layers[0].bias.numpy())<\/pre>\n\n\n\n<pre class=\"wp-block-preformatted\">[&lt;tf.Variable 'Hidden_Layer\/kernel:0' shape=(3, 5) dtype=float32, numpy=\narray([[-0.18226664,  0.06532662,  0.21953084,  0.08815249, -0.72672325],\n       [-1.8973173 ,  1.1777258 , -0.6316265 , -2.163294  ,  0.34746122],\n       [ 1.5755405 ,  2.321584  ,  1.2375892 , -3.493037  ,  0.08445551]],\n      dtype=float32)&gt;, &lt;tf.Variable 'Hidden_Layer\/bias:0' shape=(5,) dtype=float32, numpy=\narray([-0.6985663 , -0.32421154,  0.40271592,  0.84894747,  0.11173446],\n      dtype=float32)&gt;]\n[-0.6985663  -0.32421154  0.40271592  0.84894747  0.11173446]<\/pre>\n\n\n\n<p>J\u00e1 os pesos e o bias da segunda camada podem ser obtidos com os comandos:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">print(model.layers[1].weights)\nprint(model.layers[1].bias.numpy())<\/pre>\n\n\n\n<pre class=\"wp-block-preformatted\">[&lt;tf.Variable 'Output_Layer\/kernel:0' shape=(5, 1) dtype=float32, numpy=\narray([[ 1.7698333 ],\n       [ 1.1247258 ],\n       [-0.8695395 ],\n       [-1.1228516 ],\n       [-0.26583275]], dtype=float32)&gt;, &lt;tf.Variable 'Output_Layer\/bias:0' shape=(1,) dtype=float32, numpy=array([-0.08201659], dtype=float32)&gt;]\n[-0.08201659]<\/pre>\n\n\n\n<p>Em cada uma das colunas dos resultados temos os valores dos pesos para a entrada de cada neur\u00f4nio e na ultima linha os bias. Veja que os valores obtidos aqui dependem do treinamento realizado e podem variar entre treinamentos.<\/p>\n\n\n\n<p>De posse dos valores dos pesos e dos bias, no simulador podemos clicar na engrenagem da op\u00e7\u00e3o <strong>Configura\u00e7\u00e3o da IA<\/strong>, apresentada na Figura 5.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"308\" height=\"96\" src=\"https:\/\/visiorob.com.br\/wp-content\/uploads\/2022\/09\/Figura05.png\" alt=\"\" class=\"wp-image-1493\"\/><figcaption>Figura 5 &#8211; Bot\u00e3o para configurar a IA do rob\u00f4 do simulador<\/figcaption><\/figure>\n<\/div>\n\n\n<p>Na configura\u00e7\u00e3o da IA do rob\u00f4 temos os neur\u00f4nios. Ao clicarmos neles, podemos informar os pesos de suas entradas e o seu bias, conforme indicado na Figura 6.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"900\" height=\"563\" src=\"https:\/\/visiorob.com.br\/wp-content\/uploads\/2022\/09\/Figura06.png\" alt=\"\" class=\"wp-image-1494\"\/><figcaption>Figura 6 &#8211; Adicionando os pesos e bias para cada neur\u00f4nio<\/figcaption><\/figure>\n<\/div>\n\n\n<p>Informado todos os pesos e bias de todos os neur\u00f4nio podemos desenhar um trajeto que o rob\u00f4 ir\u00e1 seguir. Depois, basta ligarmos o rob\u00f4 e vermos o desempenho dele. Se quisermos, o simulador permite alterarmos o caminho enquanto o rob\u00f4 se movimenta.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Considera\u00e7\u00f5es finais<\/h2>\n\n\n\n<p>Aqui vimos uma forma de usarmos uma rede neural para controlar o movimento de um rob\u00f4. Ap\u00f3s o treinamento, o simulador permite que informemos os pesos e bias para acompanharmos o resultado e, dessa forma, podemos, tamb\u00e9m, explorar o que cada peso influencia no comportamento do rob\u00f4.<\/p>\n\n\n\n<p>No link <a href=\"https:\/\/colab.research.google.com\/drive\/1je9qH_v-oN0s5S2xLDk5r9o3uS_g3jlQ?usp=sharing\" target=\"_blank\" rel=\"noreferrer noopener\">https:\/\/colab.research.google.com\/drive\/1je9qH_v-oN0s5S2xLDk5r9o3uS_g3jlQ?usp=sharing<\/a> \u00e9 poss\u00edvel encontrar o c\u00f3digo utilizado para treinar uma rede neural igual a do rob\u00f4. E, dessa forma, podemos sugerir outros comportamentos para o rob\u00f4 ao alterarmos os valores de <strong>y_train<\/strong>.<\/p>\n","protected":false},"excerpt":{"rendered":"<div class=\"mh-excerpt\"><p>O objetivo aqui \u00e9 apresentar como podemos usar uma rede neural para tomadas de decis\u00e3o. No caso deste artigo a rede neural dever\u00e1 decidir se <a class=\"mh-excerpt-more\" href=\"https:\/\/visiorob.com.br\/index.php\/2022\/09\/16\/iacar-usando-uma-rede-neural-para-o-controle-da-movimentacao-de-um-robo\/\" title=\"IACar &#8211; Usando uma rede neural para o controle da movimenta\u00e7\u00e3o de um rob\u00f4\">[&#8230;]<\/a><\/p>\n<\/div>","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"om_disable_all_campaigns":false,"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"footnotes":""},"categories":[42,1],"tags":[52,53,54,55],"class_list":["post-1438","post","type-post","status-publish","format-standard","hentry","category-programacao","category-uncategorized","tag-ia","tag-inteligenica-artificial","tag-rede-neural","tag-robo"],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/visiorob.com.br\/index.php\/wp-json\/wp\/v2\/posts\/1438","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/visiorob.com.br\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/visiorob.com.br\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/visiorob.com.br\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/visiorob.com.br\/index.php\/wp-json\/wp\/v2\/comments?post=1438"}],"version-history":[{"count":52,"href":"https:\/\/visiorob.com.br\/index.php\/wp-json\/wp\/v2\/posts\/1438\/revisions"}],"predecessor-version":[{"id":1500,"href":"https:\/\/visiorob.com.br\/index.php\/wp-json\/wp\/v2\/posts\/1438\/revisions\/1500"}],"wp:attachment":[{"href":"https:\/\/visiorob.com.br\/index.php\/wp-json\/wp\/v2\/media?parent=1438"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/visiorob.com.br\/index.php\/wp-json\/wp\/v2\/categories?post=1438"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/visiorob.com.br\/index.php\/wp-json\/wp\/v2\/tags?post=1438"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}