<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Alexandre</title>
    <description>The latest articles on DEV Community by Alexandre (@z4nder).</description>
    <link>https://dev.to/z4nder</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F525226%2F140b3952-f130-4aad-8949-56608fd7ff4b.png</url>
      <title>DEV Community: Alexandre</title>
      <link>https://dev.to/z4nder</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/z4nder"/>
    <language>en</language>
    <item>
      <title>XOR — Backpropagation na prática em rust</title>
      <dc:creator>Alexandre</dc:creator>
      <pubDate>Mon, 13 Jul 2026 14:32:46 +0000</pubDate>
      <link>https://dev.to/z4nder/xor-backpropagation-na-pratica-em-rust-ofl</link>
      <guid>https://dev.to/z4nder/xor-backpropagation-na-pratica-em-rust-ofl</guid>
      <description>&lt;p&gt;No &lt;a href="https://dev.to/z4nder/backpropagation-treinando-uma-rede-neural-em-rust-4c7g"&gt;post anterior&lt;/a&gt; construímos uma rede MLP completa com forward pass e backpropagation. A rede funcionava. Neste post vamos atacar algo que um único neurônio nunca consegue resolver, o &lt;strong&gt;XOR&lt;/strong&gt;, e entender por que isso exige uma rede com camada oculta.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conteúdo
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;1 Prólogo
&lt;/li&gt;
&lt;li&gt;2 O problema XOR
&lt;/li&gt;
&lt;li&gt;3 Por que um neurônio não resolve
&lt;/li&gt;
&lt;li&gt;4 A estrutura da rede
&lt;/li&gt;
&lt;li&gt;5 Forward pass — avançando pela rede
&lt;/li&gt;
&lt;li&gt;6 Loss — medindo o erro com BCE
&lt;/li&gt;
&lt;li&gt;7 Backpropagation — o gradiente voltando
&lt;/li&gt;
&lt;li&gt;8 Resultados
&lt;/li&gt;
&lt;li&gt;9 Conclusão
&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  1. Prólogo &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;O problema do canhão que escolhemos nos posts anteriores não era o mais adequado para representar o potencial da nossa implementação. Como ele deixava muitos "vazios" entre os exemplos do dataset, dificilmente conseguiríamos chegar ao resultado exato sem adicionar mais complexidade ao modelo.&lt;/p&gt;

&lt;p&gt;Por isso, para colocar nossa implementação de &lt;strong&gt;backpropagation&lt;/strong&gt; em prática e observar um resultado mais concreto e satisfatório, vamos implementar uma solução para o &lt;strong&gt;XOR&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;O &lt;strong&gt;XOR&lt;/strong&gt; é um problema clássico usado para validar implementações de backpropagation. Ele é simples o suficiente para entendermos cada etapa do treinamento manualmente, mas complexo o bastante para exigir uma camada oculta. Historicamente, esse problema ficou famoso por mostrar as limitações dos perceptrons de camada única, contribuindo para o declínio das pesquisas na área após a publicação do livro de Minsky e Papert, em 1969.&lt;/p&gt;




&lt;h3&gt;
  
  
  2. O problema XOR &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;XOR (exclusive OR) retorna 1 quando as entradas são diferentes e 0 quando são iguais:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;A | B | A XOR B
0 | 0 |    0
0 | 1 |    1
1 | 0 |    1
1 | 1 |    0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Plotando os 4 pontos num plano 2D, onde a cor indica a classe, o problema fica visível:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fz4nder%2Frs-xor-neural-network%2Fmain%2Fassets%2Fxor_not_separable.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fz4nder%2Frs-xor-neural-network%2Fmain%2Fassets%2Fxor_not_separable.png" alt="4 pontos do XOR no plano 2D mostrando que nenhuma reta separa as classes" width="700" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Os zeros ficam nas diagonais opostas aos uns. Não existe nenhuma linha reta que separe as duas classes.&lt;/p&gt;

&lt;p&gt;Para contrastar, o AND é &lt;strong&gt;linearmente separável&lt;/strong&gt; onde uma única reta isola o único ponto verdadeiro &lt;code&gt;(1,1)&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fz4nder%2Frs-xor-neural-network%2Fmain%2Fassets%2Fand_separable.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fz4nder%2Frs-xor-neural-network%2Fmain%2Fassets%2Fand_separable.png" alt="4 pontos do AND no plano 2D com reta separando o ponto (1,1) dos demais" width="700" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Linearmente separável&lt;/strong&gt; significa que existe uma reta que divide perfeitamente as classes. XOR não é. AND é.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Matematicamente: não existe nenhum conjunto de &lt;code&gt;pesos&lt;/code&gt; e &lt;code&gt;bias&lt;/code&gt; capaz de representar o XOR usando apenas uma transformação linear.&lt;/p&gt;




&lt;h3&gt;
  
  
  3. Por que um neurônio não resolve &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Um único neurônio calcula &lt;code&gt;y = sigmoid(Wx + b)&lt;/code&gt;, é uma transformação linear seguida de uma função de ativação sempre criando uma reta.&lt;/p&gt;

&lt;p&gt;Com um único neurônio só conseguimos desenhar retas, e retas não resolvem XOR. Com &lt;strong&gt;múltiplos neurônios&lt;/strong&gt; em camadas, cada um aprende uma transformação diferente do espaço, e essa transformações cria as &lt;strong&gt;curvas&lt;/strong&gt; necessárias para separar o que uma reta nunca conseguiria.&lt;/p&gt;

&lt;p&gt;A camada oculta não tenta separar diretamente, ela &lt;strong&gt;aprende uma nova forma de representar os pontos&lt;/strong&gt;, transformando o espaço de entrada em algo onde a separação se torna possível.&lt;/p&gt;

&lt;p&gt;É como dobrar um papel antes de cortar, com papel aberto, o corte não resolve. Dobrado, um único corte separa tudo. A camada oculta faz essa dobra e a camada de saída faz o corte.&lt;/p&gt;




&lt;h3&gt;
  
  
  4. A estrutura da rede &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Para resolver XOR precisamos de uma rede com duas camadas:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;entrada (2)  →  camada oculta (4)  →  saída (1)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;2 entradas&lt;/strong&gt; — os bits A e B&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;4 neurônios ocultos&lt;/strong&gt; — cada um aprende uma "dobra" diferente do espaço. XOR precisa de no mínimo 2, usamos 4 para dar mais folga ao gradiente encontrar uma solução&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;1 saída&lt;/strong&gt; — um único valor entre 0 e 1. Para um par como &lt;code&gt;[0, 1]&lt;/code&gt;, após passar pelas transformações da camada oculta, a rede produz a probabilidade de a saída ser 1. Valores próximos de 0 significam "provavelmente 0", próximos de 1 significam "provavelmente 1"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Em Rust, representamos isso como uma struct com dois conjuntos de pesos e &lt;code&gt;bias&lt;/code&gt;, um por camada:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;Network&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="n"&gt;w1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Matrix&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;   &lt;span class="c1"&gt;// shape: 2×4 — pesos da camada oculta&lt;/span&gt;
    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="n"&gt;b1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Vec&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;f64&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// shape: 4   — bias da camada oculta&lt;/span&gt;
    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="n"&gt;w2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Matrix&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;   &lt;span class="c1"&gt;// shape: 4×1 — pesos da camada de saída&lt;/span&gt;
    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="n"&gt;b2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;f64&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;      &lt;span class="c1"&gt;//             — bias da camada de saída&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;w1&lt;/code&gt; tem shape &lt;code&gt;2×4&lt;/code&gt; porque conecta 2 entradas a 4 neurônios. &lt;code&gt;w2&lt;/code&gt; tem shape &lt;code&gt;4×1&lt;/code&gt; porque combina os 4 neurônios ocultos em 1 saída.&lt;/p&gt;

&lt;p&gt;Os pesos são inicializados aleatoriamente e o treino vai ajustar. Os &lt;code&gt;bias&lt;/code&gt; começam em zero:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;impl&lt;/span&gt; &lt;span class="n"&gt;Network&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;Self&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;rng&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;rand&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;thread_rng&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;Network&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;w1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nn"&gt;Matrix&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.map&lt;/span&gt;&lt;span class="p"&gt;(|&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="n"&gt;rng&lt;/span&gt;&lt;span class="nf"&gt;.gen_range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;1.0&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="mf"&gt;1.0&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="nf"&gt;.collect&lt;/span&gt;&lt;span class="p"&gt;()),&lt;/span&gt;
            &lt;span class="n"&gt;b1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nd"&gt;vec!&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
            &lt;span class="n"&gt;w2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nn"&gt;Matrix&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.map&lt;/span&gt;&lt;span class="p"&gt;(|&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="n"&gt;rng&lt;/span&gt;&lt;span class="nf"&gt;.gen_range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;1.0&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="mf"&gt;1.0&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="nf"&gt;.collect&lt;/span&gt;&lt;span class="p"&gt;()),&lt;/span&gt;
            &lt;span class="n"&gt;b2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  5. Forward pass — avançando pela rede &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Com a estrutura definida, podemos alimentar a rede com o &lt;strong&gt;dataset&lt;/strong&gt;. Ao entrar com um par &lt;code&gt;[A, B]&lt;/code&gt;, ele percorre a rede camada por camada até virar uma previsão.&lt;/p&gt;

&lt;p&gt;O mesmo &lt;code&gt;y = Wx + b&lt;/code&gt; do primeiro neurônio, agora aplicado duas vezes em sequência com &lt;code&gt;x&lt;/code&gt; sendo um vetor e &lt;code&gt;W&lt;/code&gt; uma matriz:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;sigmoid&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;sigmoid&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;B&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt; &lt;span class="n"&gt;W1&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;b1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt; &lt;span class="n"&gt;W2&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;b2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O fluxo completo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[A, B]  →  X @ W1 + b1  →  sigmoid  →  X @ W2 + b2  →  sigmoid  →  saída
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Função de ativação — sigmoid
&lt;/h4&gt;

&lt;p&gt;Sem uma função de ativação entre as camadas, empilhar &lt;code&gt;y = Wx + b&lt;/code&gt; duas vezes ainda resulta numa reta. A ativação é o que quebra essa linearidade.&lt;/p&gt;

&lt;p&gt;Usamos o &lt;strong&gt;sigmoid&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tex"&gt;&lt;code&gt;σ(x) = 1 / (1 + e&lt;span class="p"&gt;^&lt;/span&gt;(-x))
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ela espreme qualquer valor real para o intervalo (0, 1), o que faz sentido para o nosso problema onde a saída final é uma probabilidade.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;sigmoid&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;f64&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;f64&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="mf"&gt;1.0&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;1.0&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.exp&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Outra propriedade que vai ser útil no backprop: a derivada do sigmoid tem forma simples, &lt;code&gt;σ(x) * (1 - σ(x))&lt;/code&gt;, facilitando os gradientes.&lt;/p&gt;

&lt;h4&gt;
  
  
  Implementando o forward
&lt;/h4&gt;

&lt;p&gt;O &lt;strong&gt;forward&lt;/strong&gt; é passar o input pelas duas camadas em sequência. Usamos &lt;code&gt;z&lt;/code&gt; para a parte linear (antes do sigmoid) e &lt;code&gt;a&lt;/code&gt; para o resultado após a ativação, essa convenção vai aparecer de novo no backprop:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;forward&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;Matrix&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Vec&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;f64&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Fórmula completa: y = sigmoid(sigmoid(x @ W1 + b1) @ W2 + b2)&lt;/span&gt;

    &lt;span class="c1"&gt;// ── Camada oculta ─────────────────────────────────────────────&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;z1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="nf"&gt;.matmul&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.w1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// z1 = x @ W1  (linear, sem ativação ainda)&lt;/span&gt;

    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;a1_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nd"&gt;vec!&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="py"&gt;.rows&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="py"&gt;.rows&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;a1_data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;sigmoid&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;z1&lt;/span&gt;&lt;span class="nf"&gt;.get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.b1&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt; &lt;span class="c1"&gt;// a1 = sigmoid(z1 + b1)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;a1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Matrix&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="py"&gt;.rows&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;a1_data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// a1 é o espaço transformado&lt;/span&gt;

    &lt;span class="c1"&gt;// ── Camada de saída ───────────────────────────────────────────&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;z2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;a1&lt;/span&gt;&lt;span class="nf"&gt;.matmul&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.w2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// z2 = a1 @ W2  (linear)&lt;/span&gt;

    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="py"&gt;.rows&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.map&lt;/span&gt;&lt;span class="p"&gt;(|&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nf"&gt;sigmoid&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;z2&lt;/span&gt;&lt;span class="nf"&gt;.get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.b2&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="nf"&gt;.collect&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;// a2 = sigmoid(z2 + b2)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;a1&lt;/code&gt; é a saída da camada oculta, os 4 neurônios já transformados pelo sigmoid. É ela que entra na camada de saída, não o input original. O diagrama abaixo mostra o forward do par &lt;code&gt;[A=0, B=1]&lt;/code&gt; com os valores reais em cada nó:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fz4nder%2Frs-xor-neural-network%2Fmain%2Fassets%2Fforward_annotated.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fz4nder%2Frs-xor-neural-network%2Fmain%2Fassets%2Fforward_annotated.png" alt="diagrama da rede com os valores reais em cada nó para o par A=0 B=1 antes do treino" width="800" height="448"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A rede ainda não sabe nada, os pesos são aleatórios e a previsão é ruído. O que vem a seguir é o que transforma esse ruído em conhecimento.&lt;/p&gt;




&lt;h3&gt;
  
  
  6. Loss — medindo o erro com BCE &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;O forward produz uma previsão &lt;code&gt;ŷ&lt;/code&gt;. Para saber o quanto a rede errou, precisamos de uma função que compare &lt;code&gt;ŷ&lt;/code&gt; com o valor esperado &lt;code&gt;y&lt;/code&gt; e retorne um número, quanto maior, pior a previsão. Esse número é a &lt;strong&gt;loss&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Usamos &lt;strong&gt;Binary Cross-Entropy (BCE)&lt;/strong&gt;, que é a loss correta para classificação binária, quando a saída é uma probabilidade entre 0 e 1:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tex"&gt;&lt;code&gt;L = -1/n * Σ [ y * log(ŷ) + (1-y) * log(1-ŷ) ]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A intuição: quando &lt;code&gt;y=1&lt;/code&gt; e &lt;code&gt;ŷ&lt;/code&gt; é próximo de 0, &lt;code&gt;log(ŷ)&lt;/code&gt; vira um número muito negativo e a loss explode. Quando &lt;code&gt;ŷ&lt;/code&gt; é próximo de 1, &lt;code&gt;log(ŷ)&lt;/code&gt; se aproxima de 0 e a loss some. A função pune previsões confiantes e erradas com muito mais força do que o MSE faria.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;bce&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;predictions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;f64&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;targets&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;f64&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;f64&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;predictions&lt;/span&gt;&lt;span class="nf"&gt;.len&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nb"&gt;f64&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;predictions&lt;/span&gt;&lt;span class="nf"&gt;.iter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.zip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;targets&lt;/span&gt;&lt;span class="nf"&gt;.iter&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="nf"&gt;.map&lt;/span&gt;&lt;span class="p"&gt;(|(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;yhat&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;)|&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;yhat&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;yhat&lt;/span&gt;&lt;span class="nf"&gt;.clamp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;1e-7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;1.0&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mf"&gt;1e-7&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// evita log(0)&lt;/span&gt;
        &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;yhat&lt;/span&gt;&lt;span class="nf"&gt;.ln&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;1.0&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;1.0&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;yhat&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.ln&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="py"&gt;.sum&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;f64&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O &lt;code&gt;clamp&lt;/code&gt; evita &lt;code&gt;log(0)&lt;/code&gt; que seria &lt;code&gt;-∞&lt;/code&gt;. Na prática a rede nunca prevê exatamente 0 ou 1, mas é uma proteção necessária.&lt;/p&gt;

&lt;p&gt;Para o backprop precisamos também da derivada da loss em relação a &lt;code&gt;ŷ&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tex"&gt;&lt;code&gt;dL/dŷ = -y/ŷ + (1-y)/(1-ŷ)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;bce_grad&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;predictions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;f64&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;targets&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;f64&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Vec&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;f64&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;predictions&lt;/span&gt;&lt;span class="nf"&gt;.len&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nb"&gt;f64&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;predictions&lt;/span&gt;&lt;span class="nf"&gt;.iter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.zip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;targets&lt;/span&gt;&lt;span class="nf"&gt;.iter&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="nf"&gt;.map&lt;/span&gt;&lt;span class="p"&gt;(|(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;yhat&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;)|&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;yhat&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;yhat&lt;/span&gt;&lt;span class="nf"&gt;.clamp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;1e-7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;1.0&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mf"&gt;1e-7&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;yhat&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;1.0&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;1.0&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;yhat&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="nf"&gt;.collect&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Esse gradiente é o ponto de partida do &lt;strong&gt;backprop&lt;/strong&gt;, o erro medido na saída que vai voltar camada por camada até ajustar cada peso da rede.&lt;/p&gt;




&lt;h3&gt;
  
  
  7. Backpropagation — o gradiente voltando &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Com a loss calculada, precisamos saber quanto cada peso contribuiu para o erro e em qual direção ajustár. Isso é o backprop: aplicar a &lt;strong&gt;chain rule&lt;/strong&gt; de trás pra frente, camada por camada.&lt;/p&gt;

&lt;p&gt;O fluxo inverso ao forward:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dL/dŷ  →  dL/dz2  →  dL/dW2, dL/db2
                  →  dL/da1  →  dL/dz1  →  dL/dW1, dL/db1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;1. Gradiente da loss → &lt;code&gt;dL/dŷ&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Vem direto do &lt;code&gt;bce_grad&lt;/code&gt;, um valor por exemplo do dataset.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Desfazendo o sigmoid da saída → &lt;code&gt;dL/dz2&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;O sigmoid foi a última operação antes de &lt;code&gt;ŷ&lt;/code&gt;. Para voltar por ele usamos sua derivada, &lt;code&gt;σ'(x) = σ(x) * (1 - σ(x))&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="n"&gt;dz2&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dl_dyhat&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;yhat&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;1.0&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;yhat&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;3. Gradientes de W2 e b2&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;z2 = a1 @ W2 + b2&lt;/code&gt;, então:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="c1"&gt;// dW2 = a1ᵀ @ dz2&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="n"&gt;batch&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;dw2&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;a1&lt;/span&gt;&lt;span class="nf"&gt;.get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;dz2&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;db2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;f64&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dz2&lt;/span&gt;&lt;span class="nf"&gt;.iter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.sum&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;4. Propagando para a camada oculta → &lt;code&gt;dL/dz1&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;O gradiente chega em &lt;code&gt;a1&lt;/code&gt; via &lt;code&gt;W2&lt;/code&gt;, depois passa pelo sigmoid da camada oculta:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="n"&gt;batch&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;dl_da1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dz2&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.w2&lt;/span&gt;&lt;span class="nf"&gt;.get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// ← volta por W2&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;a1&lt;/span&gt;&lt;span class="nf"&gt;.get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;dz1&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dl_da1&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;1.0&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;      &lt;span class="c1"&gt;// ← desfaz sigmoid&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;5. Gradientes de W1 e b1&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Mesmo padrão da camada anterior:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;dw1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="nf"&gt;.transpose&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.matmul&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;dz1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// dW1 = Xᵀ @ dz1&lt;/span&gt;
&lt;span class="c1"&gt;// db1[k] = Σ dz1 por coluna&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;6. Update — gradient descent&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Com os gradientes calculados, ajustamos cada peso na direção que reduz a loss:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="c1"&gt;// w = w - lr * dw&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.w1.data&lt;/span&gt;&lt;span class="nf"&gt;.len&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.w1.data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="n"&gt;lr&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;dw1&lt;/span&gt;&lt;span class="py"&gt;.data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.b1&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="n"&gt;lr&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;db1&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.w2.data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="n"&gt;lr&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;dw2&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.b2&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="n"&gt;lr&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;db2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Repetir isso para cada epoch, forward → loss → backward → update, é o treino completo.&lt;/p&gt;

&lt;p&gt;O diagrama abaixo mostra os gradientes voltando pela rede. A espessura de cada aresta representa a magnitude do gradiente naquele peso:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fz4nder%2Frs-xor-neural-network%2Fmain%2Fassets%2Fbackward_annotated.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fz4nder%2Frs-xor-neural-network%2Fmain%2Fassets%2Fbackward_annotated.png" alt="diagrama de backpropagation com arestas de espessura proporcional à magnitude do gradiente" width="800" height="448"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  8. Resultados &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Rodamos o treino por 20.000 epochs com &lt;code&gt;lr = 0.5&lt;/code&gt;. Antes do treino os pesos são aleatórios e as 4 previsões ficam em torno de 0.5. Depois, cada previsão converge exatamente para o valor correto:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fz4nder%2Frs-xor-neural-network%2Fmain%2Fassets%2Fbefore_after.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fz4nder%2Frs-xor-neural-network%2Fmain%2Fassets%2Fbefore_after.png" alt="comparação lado a lado das previsões antes e depois do treino para os 4 casos do XOR" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Dá para ver a rede aprendendo epoch por epoch. No epoch 0 tudo é ruído, no epoch 500 já começa a separar os zeros, no epoch 2000 quase lá, a partir do epoch 5000 os pontos grudam nos targets. A cor indo de roxo para verde segue o progresso:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fz4nder%2Frs-xor-neural-network%2Fmain%2Fassets%2Fevolution.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fz4nder%2Frs-xor-neural-network%2Fmain%2Fassets%2Fevolution.png" alt="grade com 6 painéis mostrando a evolução das previsões nos epochs 0, 500, 2000, 5000, 10000 e 19999" width="800" height="371"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A curva de loss começa em ~0.69 (máximo da BCE com pesos aleatórios) e cai até ~0.0007:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fz4nder%2Frs-xor-neural-network%2Fmain%2Fassets%2Floss.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fz4nder%2Frs-xor-neural-network%2Fmain%2Fassets%2Floss.png" alt="curva de loss BCE ao longo de 20000 epochs caindo de 0.69 para 0.0007" width="799" height="444"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Resultado final:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[0 XOR 0] → 0.0008  classe: 0  esperado: 0  ✓
[0 XOR 1] → 0.9993  classe: 1  esperado: 1  ✓
[1 XOR 0] → 0.9993  classe: 1  esperado: 1  ✓
[1 XOR 1] → 0.0007  classe: 0  esperado: 0  ✓
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;4/4. O backprop está funcionando.&lt;/p&gt;




&lt;h3&gt;
  
  
  9. Conclusão &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Neste post implementamos uma rede neural que resolve o XOR do zero, com forward pass, BCE e backpropagation completo em Rust.&lt;/p&gt;

&lt;p&gt;O que foi aprendido:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Separabilidade linear&lt;/strong&gt; — um único neurônio só desenha retas. XOR precisa de curvas, o que exige uma camada oculta&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sigmoid como ativação&lt;/strong&gt; — transforma qualquer valor real em probabilidade (0,1) e tem derivada simples que facilita o backprop&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;BCE&lt;/strong&gt; — a loss correta para classificação binária, pune previsões confiantes e erradas com muito mais força do que o MSE&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Backpropagation&lt;/strong&gt; — a chain rule aplicada de trás pra frente, desfazendo cada operação do forward para calcular o gradiente de cada peso&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Gradient descent&lt;/strong&gt; — &lt;code&gt;w = w - lr * dw&lt;/code&gt;, repetido epoch por epoch até a loss convergir&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;O que ainda não resolvemos: o dataset XOR tem só 4 pontos e a rede decorou a solução. Para problemas reais, com dados mais distribuidos e distribuições desconhecidas, precisamos de generalização, regularização e validação. Isso fica para frente.&lt;/p&gt;




&lt;h3&gt;
  
  
  Referências
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/z4nder/rs-xor-neural-network" rel="noopener noreferrer"&gt;Código-fonte do projeto&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=GkiITbgu0V0&amp;amp;t=477s" rel="noopener noreferrer"&gt;Neural Network from Scratch — vídeo que inspirou essa série&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Perceptrons_(book)" rel="noopener noreferrer"&gt;Minsky &amp;amp; Papert, Perceptrons (1969)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Cross-entropy" rel="noopener noreferrer"&gt;Binary Cross-Entropy — Wikipedia&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Se este post fizer sentido pra você, o próximo passo natural é representar conceitos como vetores em vez de números, e ver como a semântica emerge da geometria desse espaço.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>rust</category>
      <category>machinelearning</category>
      <category>programming</category>
    </item>
    <item>
      <title>Backpropagation: treinando uma rede neural em Rust</title>
      <dc:creator>Alexandre</dc:creator>
      <pubDate>Thu, 09 Jul 2026 14:24:03 +0000</pubDate>
      <link>https://dev.to/z4nder/backpropagation-treinando-uma-rede-neural-em-rust-4c7g</link>
      <guid>https://dev.to/z4nder/backpropagation-treinando-uma-rede-neural-em-rust-4c7g</guid>
      <description>&lt;p&gt;No &lt;a href="https://dev.to/z4nder/por-que-camadas-lineares-sozinhas-nao-funcionam-e-o-que-a-relu-resolve-5f00"&gt;post anterior&lt;/a&gt; construímos o forward pass completo com duas camadas e ativação podendo já gerar uma previsão, mas os pesos eram aleatórios e nunca mudavam. Neste post fechamos o loop: &lt;strong&gt;loss, backpropagation e gradient descent&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conteúdo
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;1 Prólogo
&lt;/li&gt;
&lt;li&gt;2 A rede prevê mas não aprende
&lt;/li&gt;
&lt;li&gt;3 Medindo o erro com MSE
&lt;/li&gt;
&lt;li&gt;4 O gradiente da saída
&lt;/li&gt;
&lt;li&gt;5 Backpropagation
&lt;/li&gt;
&lt;li&gt;6 Atualizando os pesos
&lt;/li&gt;
&lt;li&gt;7 O loop de treino
&lt;/li&gt;
&lt;li&gt;8 Conclusão
&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  1. Prólogo &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Nos ultimos posts trabalhamos na estrutura para implementar o &lt;strong&gt;Backpropagation&lt;/strong&gt; que eu estava tão animado pois é um dos algoritmos mais famosos nesse ambiente de ML. Conseguimos já compreender como trabalhar com matrizes para termos camadas na rede e o papel da funcao de ativacao nesse processo mas ainda não implementamos o fluxo de treinamento, então vamos nessa, sem medo de ser feliz !&lt;/p&gt;




&lt;h3&gt;
  
  
  2. A rede prevê mas não aprende &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Os pesos &lt;code&gt;W&lt;/code&gt; e &lt;code&gt;b&lt;/code&gt; foram inicializados aleatórios e nunca mudavam com isso a rede gerava uma pervisão mas não aprendia o caminho para melhorar.&lt;/p&gt;

&lt;p&gt;Para aprender essas três coisas precisam acontecer em sequência:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Medir o erro&lt;/strong&gt;: o quanto a previsão se afastou do valor real - MSE&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Calcular os gradientes&lt;/strong&gt;: em qual direção ajustar cada peso para reduzir esse erro - Gradient descent&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Atualizar os pesos&lt;/strong&gt;: aplicar o ajuste em cada camada&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;No nosso contexto de treinamento com multiplas Layers precisamos fazer de uma forma diferente de como fazermos com somente 1 neuronio esses processo.&lt;/p&gt;




&lt;h3&gt;
  
  
  3. Medindo o erro com MSE &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;A fórmula é a mesma que já conhecemos:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;MSE = (1/n) × Σ (previsão - target)²
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A diferença é que &lt;code&gt;previsão&lt;/code&gt; agora é uma &lt;code&gt;Matrix (n×1)&lt;/code&gt;, uma linha por exemplo do batch:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;mse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;predictions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;Matrix&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;targets&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;f64&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;f64&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;targets&lt;/span&gt;&lt;span class="nf"&gt;.len&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nb"&gt;f64&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;f64&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="n"&gt;targets&lt;/span&gt;&lt;span class="nf"&gt;.len&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
        &lt;span class="nf"&gt;.map&lt;/span&gt;&lt;span class="p"&gt;(|&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;diff&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;predictions&lt;/span&gt;&lt;span class="nf"&gt;.get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;targets&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
            &lt;span class="n"&gt;diff&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;diff&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;
        &lt;span class="nf"&gt;.sum&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;sum&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Com os nossos 2 exemplos antes de qualquer treino:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;previsões: [6.66, 5.30]
targets:   [60.0, 80.0]

erro[0] = (6.66  - 60.0)² = 2840.7
erro[1] = (5.30  - 80.0)² = 5580.5

MSE = (2840.7 + 5580.5) / 2 = 4210.6
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Loss alto é esperado e os pesos ainda são aleatórios então o nosso objetivo é fazer esse número cair.&lt;/p&gt;




&lt;h3&gt;
  
  
  4. O gradiente da saída &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;O MSE nos dá 1 número para monitora o treino, mas para &lt;strong&gt;ajustar os pesos&lt;/strong&gt; precisamos de algo mais específico: o quanto cada previsão individualmente precisa mudar, e em qual direção.&lt;/p&gt;

&lt;p&gt;Isso vem da derivada do MSE em relação à &lt;strong&gt;saída da última camada&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;No nosso caso &lt;code&gt;∂MSE/∂z2&lt;/code&gt; com 2 layers a última saída é &lt;code&gt;z2&lt;/code&gt; que é o resultado de &lt;code&gt;a1 @ W2 + b2&lt;/code&gt;, sem aplicar nenhuma ativação. Essa saída bruta &lt;strong&gt;é a previsão final da rede&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A camada de saída não tem &lt;strong&gt;ReLU&lt;/strong&gt; porque a rede precisa poder prever qualquer número: com ReLU ela nunca preveria valores negativos.&lt;/p&gt;

&lt;p&gt;O gradiente dessa saída é&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;∂MSE/∂z2 = (2/n) × (z2 - target)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O resultado é uma &lt;strong&gt;matriz (n×1)&lt;/strong&gt;, um valor por exemplo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;z2      = [ 0.527]     targets = [60.0]
          [-1.011]               [80.0]

∂L/∂z2 = (2/2) × (z2 - targets)
        = [-59.473]
          [-81.011]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Cada valor diz quanto e em qual direção a previsão precisa mudar que é o papel do &lt;strong&gt;gradient descent&lt;/strong&gt;. É o sinal que inicia o &lt;strong&gt;backpropagation&lt;/strong&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;O MSE monitora. O gradiente do MSE guia.&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;mse_grad&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;predictions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;Matrix&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;targets&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;f64&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Matrix&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;targets&lt;/span&gt;&lt;span class="nf"&gt;.len&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nb"&gt;f64&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Vec&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;f64&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="n"&gt;targets&lt;/span&gt;&lt;span class="nf"&gt;.len&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
        &lt;span class="nf"&gt;.map&lt;/span&gt;&lt;span class="p"&gt;(|&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;2.0&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;predictions&lt;/span&gt;&lt;span class="nf"&gt;.get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;targets&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;
        &lt;span class="nf"&gt;.collect&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nn"&gt;Matrix&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;targets&lt;/span&gt;&lt;span class="nf"&gt;.len&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  5. Backpropagation &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Backpropagation &lt;strong&gt;calcula os gradientes&lt;/strong&gt;, quanto cada peso contribuiu para o erro. Quem usa esses gradientes para ajustar os pesos é o &lt;strong&gt;gradient descent&lt;/strong&gt;, que vem depois. São dois papéis separados que acontecem em sequência.&lt;/p&gt;

&lt;p&gt;O forward que é o primeiro treino iniciado com valores aleatorios, precisa guardar os valores intermediários porque o backprop vai percorrer o mesmo caminho ao contrário:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;forward:  guarda →  z1, a1, z2  (previsão com os pesos atuais)
backprop: usa    ←  z2, a1, z1  (percorre de trás pra frente)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O fluxo completo de gradientes por camada:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;∂L/∂z2                        ← gradiente da saída (mse_grad)
∂L/∂W2 = a1.T @ ∂L/∂z2       ← gradiente de W2
∂L/∂b2 = soma(∂L/∂z2)         ← gradiente de b2
∂L/∂a1 = ∂L/∂z2 @ W2.T       ← propaga pela Layer2 (transposta)
∂L/∂z1 = ∂L/∂a1 × relu'(z1)  ← propaga pelo ReLU
∂L/∂W1 = input.T @ ∂L/∂z1    ← gradiente de W1
∂L/∂b1 = soma(∂L/∂z1)         ← gradiente de b1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A transposta aparece em dois lugares e vale explicar o porquê.&lt;/p&gt;

&lt;p&gt;No forward, a multiplicação foi &lt;code&gt;a1 @ W2&lt;/code&gt;: &lt;code&gt;a1&lt;/code&gt; tem formato &lt;code&gt;(n × 4)&lt;/code&gt; e &lt;code&gt;W2&lt;/code&gt; tem formato &lt;code&gt;(4 × 1)&lt;/code&gt;. Para calcular o gradiente de W2, precisamos de uma operação que resulte em &lt;code&gt;(4 × 1)&lt;/code&gt;, o mesmo formato de W2. Fazendo &lt;code&gt;a1.T @ ∂L/∂z2&lt;/code&gt;, ou seja &lt;code&gt;(4 × n) @ (n × 1)&lt;/code&gt;, chegamos exatamente em &lt;code&gt;(4 × 1)&lt;/code&gt;. A transposta é o que acerta os formatos para a multiplicação funcionar na direção inversa.&lt;/p&gt;

&lt;p&gt;O mesmo raciocínio vale para propagar o sinal de volta para a camada 1: no forward foi &lt;code&gt;∂L/∂z2 @ W2&lt;/code&gt;, então no backward é &lt;code&gt;∂L/∂z2 @ W2.T&lt;/code&gt; para os formatos baterem e o sinal chegar em &lt;code&gt;a1&lt;/code&gt; com o formato certo.&lt;/p&gt;

&lt;p&gt;O &lt;code&gt;relu_grad&lt;/code&gt; zera o gradiente onde &lt;code&gt;z1&lt;/code&gt; era negativo, porque o neurônio estava desligado no forward e não contribuiu para o erro:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;backward&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;Matrix&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;z1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;Matrix&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;a1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;Matrix&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;w2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;Matrix&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;grad_z2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;Matrix&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Gradients&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;grad_w2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;a1&lt;/span&gt;&lt;span class="nf"&gt;.transpose&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.matmul&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;grad_z2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;grad_b2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;col_sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;grad_z2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;grad_a1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;grad_z2&lt;/span&gt;&lt;span class="nf"&gt;.matmul&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;w2&lt;/span&gt;&lt;span class="nf"&gt;.transpose&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;grad_z1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;relu_grad&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;grad_a1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;z1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;// zera onde z1 era negativo&lt;/span&gt;

    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;grad_w1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="nf"&gt;.transpose&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.matmul&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;grad_z1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;grad_b1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;col_sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;grad_z1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="n"&gt;Gradients&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;grad_w1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;grad_b1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;grad_w2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;grad_b2&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Neurônio desligado no forward não recebe ajuste no backward.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h3&gt;
  
  
  6. Atualizando os pesos &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Com os gradientes calculados, o update é simples: andar na direção oposta ao gradiente, em todas as camadas, elemento a elemento.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;W = W - lr × ∂L/∂W
b = b - lr × ∂L/∂b
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Layer 2&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="n"&gt;camada2&lt;/span&gt;&lt;span class="py"&gt;.w.rows&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="n"&gt;camada2&lt;/span&gt;&lt;span class="py"&gt;.w.cols&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;grad&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;grads&lt;/span&gt;&lt;span class="py"&gt;.grad_w2&lt;/span&gt;&lt;span class="nf"&gt;.get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;camada2&lt;/span&gt;&lt;span class="py"&gt;.w&lt;/span&gt;&lt;span class="nf"&gt;.set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;camada2&lt;/span&gt;&lt;span class="py"&gt;.w&lt;/span&gt;&lt;span class="nf"&gt;.get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;lr&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;grad&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="n"&gt;camada2&lt;/span&gt;&lt;span class="py"&gt;.b&lt;/span&gt;&lt;span class="nf"&gt;.len&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;camada2&lt;/span&gt;&lt;span class="py"&gt;.b&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="n"&gt;lr&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;grads&lt;/span&gt;&lt;span class="py"&gt;.grad_b2&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Layer 1&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="n"&gt;camada1&lt;/span&gt;&lt;span class="py"&gt;.w.rows&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="n"&gt;camada1&lt;/span&gt;&lt;span class="py"&gt;.w.cols&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;grad&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;grads&lt;/span&gt;&lt;span class="py"&gt;.grad_w1&lt;/span&gt;&lt;span class="nf"&gt;.get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;camada1&lt;/span&gt;&lt;span class="py"&gt;.w&lt;/span&gt;&lt;span class="nf"&gt;.set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;camada1&lt;/span&gt;&lt;span class="py"&gt;.w&lt;/span&gt;&lt;span class="nf"&gt;.get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;lr&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;grad&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="n"&gt;camada1&lt;/span&gt;&lt;span class="py"&gt;.b&lt;/span&gt;&lt;span class="nf"&gt;.len&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;camada1&lt;/span&gt;&lt;span class="py"&gt;.b&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="n"&gt;lr&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;grads&lt;/span&gt;&lt;span class="py"&gt;.grad_b1&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O sinal de menos é o que faz o peso andar na direção que reduz o loss. O &lt;code&gt;lr&lt;/code&gt; (learning rate) controla o tamanho do passo.&lt;/p&gt;




&lt;h3&gt;
  
  
  7. O loop de treino &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;
  &lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fz4nder%2Frs-multilayer-perceptron%2Fmain%2Fassets%2F03%2Fsimple_loop_a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fz4nder%2Frs-multilayer-perceptron%2Fmain%2Fassets%2F03%2Fsimple_loop_a.png" alt="Diagrama do fluxo simples sem treino, mostrando input, forward, previsão e MSE sem atualização dos pesos" width="820"&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;Agora o loop fecha de verdade. Os valores abaixo são da epoch 0, antes de qualquer ajuste:&lt;/p&gt;

&lt;p&gt;
  &lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fz4nder%2Frs-multilayer-perceptron%2Fmain%2Fassets%2F03%2Fcompelte_loop_a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fz4nder%2Frs-multilayer-perceptron%2Fmain%2Fassets%2F03%2Fcompelte_loop_a.png" alt="Diagrama do loop completo de treino com forward, loss, backpropagation e atualização dos pesos" width="300"&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;O loop completo por epoch:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;epoch&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="n"&gt;epochs&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// 1. forward&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;z1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;camada1&lt;/span&gt;&lt;span class="nf"&gt;.forward&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;dataset&lt;/span&gt;&lt;span class="py"&gt;.inputs&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;a1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;relu&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;z1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;z2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;camada2&lt;/span&gt;&lt;span class="nf"&gt;.forward&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;a1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// 2. loss&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;loss&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;mse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;z2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;dataset&lt;/span&gt;&lt;span class="py"&gt;.targets&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// 3. backprop&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;grad_z2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;mse_grad&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;z2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;dataset&lt;/span&gt;&lt;span class="py"&gt;.targets&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;grads&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;backward&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;dataset&lt;/span&gt;&lt;span class="py"&gt;.inputs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;z1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;a1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;camada2&lt;/span&gt;&lt;span class="py"&gt;.w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;grad_z2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// 4. update&lt;/span&gt;
    &lt;span class="c1"&gt;// ... atualiza W2, b2, W1, b1&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Repete por N epochs. A cada iteração os pesos se aproximam dos valores que minimizam o loss.&lt;/p&gt;

&lt;h4&gt;
  
  
  O que o gráfico mostra
&lt;/h4&gt;

&lt;p&gt;
  &lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fz4nder%2Frs-multilayer-perceptron%2Fmain%2Foutput%2F03_loss.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fz4nder%2Frs-multilayer-perceptron%2Fmain%2Foutput%2F03_loss.png" alt="Gráfico da loss ao longo do treino mostrando queda rápida no início e convergência ao longo das epochs" width="900"&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;0–50 epochs:&lt;/strong&gt; queda brusca, os pesos saem do aleatório e encontram uma direção clara. O gradiente é grande porque o erro é enorme, os passos são grandes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;50–300 epochs:&lt;/strong&gt; oscilações, a rede está refinando mas ainda não encontrou um caminho estável. O gradiente varia bastante de epoch para epoch porque os exemplos puxam os pesos em direções ligeiramente diferentes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;300–1000 epochs:&lt;/strong&gt; estabilização, as oscilações somem e o loss converge suavemente. Com mais exemplos o gradiente vira uma média de mais pontos a cada epoch, o que suaviza o sinal e permite uma descida mais consistente.&lt;/p&gt;

&lt;p&gt;
  &lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fz4nder%2Frs-multilayer-perceptron%2Fmain%2Foutput%2F03_errors.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fz4nder%2Frs-multilayer-perceptron%2Fmain%2Foutput%2F03_errors.png" alt="Comparação dos erros antes e depois do treino, mostrando redução significativa após o ajuste dos pesos" width="900"&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;O erro cai de ~54 e ~75 para ~4 e ~4&lt;/p&gt;




&lt;h3&gt;
  
  
  8. Conclusão &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Bbackprop e gradient descent são coisas diferentes que trabalham juntas. Backprop percorre a rede de trás pra frente calculando quanto cada peso contribuiu pro erro. Gradient descent usa esse resultado para dar um passo na direção certa. A separação faz sentido porque o mesmo gradiente poderia ser usado por estratégias de update diferentes.&lt;/p&gt;

&lt;p&gt;Uma limitação que fica clara ao olhar o &lt;code&gt;backward.rs&lt;/code&gt;: cada linha foi calculada à mão para essa arquitetura específica de 2 camadas com ReLU no meio.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="c1"&gt;// essas fórmulas foram derivadas para: input → Layer1 → ReLU → Layer2 → saída&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;grad_w2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;a1&lt;/span&gt;&lt;span class="nf"&gt;.transpose&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.matmul&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;grad_z2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;grad_a1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;grad_z2&lt;/span&gt;&lt;span class="nf"&gt;.matmul&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;w2&lt;/span&gt;&lt;span class="nf"&gt;.transpose&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;grad_z1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;relu_grad&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;grad_a1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;z1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;grad_w1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="nf"&gt;.transpose&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.matmul&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;grad_z1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Se quiséssemos adicionar uma terceira camada, ou trocar o ReLU por uma função de ativação diferente, precisaríamos abrir o &lt;code&gt;backward.rs&lt;/code&gt;, derivar os gradientes para a nova arquitetura e reescrever as fórmulas. A estrutura não é reutilizável.&lt;/p&gt;

&lt;p&gt;O &lt;strong&gt;Micrograd do Karpathy&lt;/strong&gt; resolve isso de outra forma, em vez de calcular as derivadas uma vez para uma arquitetura fixa, cada operação (&lt;code&gt;+&lt;/code&gt;, &lt;code&gt;*&lt;/code&gt;, &lt;code&gt;@&lt;/code&gt;) traz regra de como calcular seu próprio gradiente. No forward, a rede monta um grafo de operações. No backward, percorre esse grafo automaticamente, aplicando cada regra em sequência, independente de quantas camadas ou funções de ativação existam.&lt;/p&gt;

&lt;p&gt;O resultado é o mesmo, os gradientes corretos para cada peso. A diferença é que não é mais preciso escrever &lt;code&gt;backward.rs&lt;/code&gt; na mão para cada arquitetura que se queira testar.&lt;/p&gt;

&lt;p&gt;Resolver isso pode ser o projeto seguinte &lt;strong&gt;autograd&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Referências
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/z4nder/rs-multilayer-perceptron" rel="noopener noreferrer"&gt;Código-fonte do projeto&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=GkiITbgu0V0&amp;amp;t=477s" rel="noopener noreferrer"&gt;Neural Network from Scratch&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/z4nder/por-que-camadas-lineares-sozinhas-nao-funcionam-e-o-que-a-relu-resolve-5f00"&gt;Post anterior — Por que camadas lineares sozinhas não funcionam&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Se este post fizer sentido pra você, o próximo passo é eliminar a necessidade de escrever backprop à mão para cada arquitetura, construindo um sistema de autograd.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>programming</category>
      <category>machinelearning</category>
      <category>rust</category>
    </item>
    <item>
      <title>Por que camadas lineares sozinhas não funcionam e o que a ReLU resolve</title>
      <dc:creator>Alexandre</dc:creator>
      <pubDate>Mon, 06 Jul 2026 17:34:12 +0000</pubDate>
      <link>https://dev.to/z4nder/por-que-camadas-lineares-sozinhas-nao-funcionam-e-o-que-a-relu-resolve-5f00</link>
      <guid>https://dev.to/z4nder/por-que-camadas-lineares-sozinhas-nao-funcionam-e-o-que-a-relu-resolve-5f00</guid>
      <description>&lt;p&gt;No &lt;a href="https://dev.to/z4nder/de-um-neuronio-para-uma-rede-matrizes-camadas-e-o-forward-pass-1ai8"&gt;post anterior&lt;/a&gt; montamos o forward pass com duas camadas lineares em sequência. A rede parece ter mais "profundidade" mas matematicamente ela não tem. Neste post vamos entender por que e o que a função de ativação resolve.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conteúdo
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;1 Prólogo
&lt;/li&gt;
&lt;li&gt;2 O colapso linear
&lt;/li&gt;
&lt;li&gt;3 O que é uma função de ativação
&lt;/li&gt;
&lt;li&gt;4 ReLU no gráfico
&lt;/li&gt;
&lt;li&gt;5 ReLU no código
&lt;/li&gt;
&lt;li&gt;6 Onde a ativação entra — e onde não entra
&lt;/li&gt;
&lt;li&gt;7 Conclusão
&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  1. Prólogo &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Já montamos o &lt;code&gt;forward pass&lt;/code&gt; na nossa layer com duas camadas lineares em sequência&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;z1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;camada1&lt;/span&gt;&lt;span class="nf"&gt;.forward&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;dataset&lt;/span&gt;&lt;span class="py"&gt;.inputs&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// X @ W1 + b1&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;z2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;camada2&lt;/span&gt;&lt;span class="nf"&gt;.forward&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;z1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;             &lt;span class="c1"&gt;// z1 @ W2 + b2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Parece que a rede tem mais "profundidade" agora mas matematicamente estamos apenas empilhando camadas lineares sem ganho real para o aprendizado. As coisas pareciam conceitualmente simples, mas precisamos de um pouco mais de teoria para chegar num resultado melhor. Não se desespere como eu fiz: mesmo que esses conceitos não fiquem totalmente claros de primeira, acredito que consegui chegar numa explicação que melhora bastante a intuição sobre o assunto.&lt;/p&gt;




&lt;h3&gt;
  
  
  2. O colapso linear &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Depois de construir a &lt;code&gt;Layer&lt;/code&gt;, a ideia natural é empilhar várias, uma camada processa a entrada e passa para a próxima, que refina o resultado.&lt;/p&gt;

&lt;p&gt;O problema é que duas camadas lineares em sequência sempre &lt;strong&gt;colapsam numa única camada linear&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Suponha 2 inputs e duas camadas de pesos.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;X = [10.0, 80.0]

W1 = [
 [ 0.5, -0.4]
 [ 0.2, -0.1]
]

b1 = [1.0, 2.0]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Na camada 1 aplicando o &lt;code&gt;forward&lt;/code&gt; chegamos em &lt;code&gt;Z = X @ W1 + b1&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;z1 = 10×0.5  + 80×0.2  + 1 =  22
z2 = 10×(-0.4) + 80×(-0.1) + 2 = -10

Z = [22, -10]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Agora passamos &lt;code&gt;Z&lt;/code&gt; para a camada 2.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;W2 = [
 [0.4, 0.2]
 [0.6, 0.1]
]

b2 = [0.5, 1.0]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Aplicando novamente o &lt;code&gt;forward&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Y = Z @ W2 + b2

y1 = 22×0.4 + (-10)×0.6 + 0.5 = 3.3
y2 = 22×0.2 + (-10)×0.1 + 1.0 = 4.4

Y = [3.3, 4.4]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Apesar de termos usado duas camadas tudo isso ainda é equivalente a uma única transformação linear(Y = X @ W + b)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;X
 ↓
Layer(2,2)
 ↓
Layer(2,2)
 ↓
Y

OU para 1 unico neurônio que é o método `y = x * w + b;`

z = x * w1 + b1;
y = z * w2 + b2;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;É como se o treinamento tivesse aprendido um único conjunto de pesos equivalente ao efeito combinado dos dois.&lt;/p&gt;

&lt;p&gt;Isso acontece porque multiplicações e somas são operações lineares.&lt;/p&gt;

&lt;p&gt;Se colocarmos uma ativação no meio:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;X
 ↓
Linear
 ↓
ReLU
 ↓
Linear
 ↓
Y

OU

z = x*w1 + b1
a = ReLU(z)
y = a*w2 + b2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O ponto principal é que &lt;strong&gt;não existe mais um único &lt;code&gt;w&lt;/code&gt; e &lt;code&gt;b&lt;/code&gt; que reproduzam exatamente esse comportamento para todos os valores de x.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Por isso costumamos dizer:&lt;/p&gt;

&lt;p&gt;Sem ativação, várias camadas são apenas uma regressão linear disfarçada.&lt;br&gt;
Com ativação, a rede passa a representar funções muito mais complexas.&lt;/p&gt;


&lt;h3&gt;
  
  
  3. O que é uma função de ativação &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Uma função de ativação é aplicada &lt;strong&gt;elemento a elemento&lt;/strong&gt; à saída de uma camada antes de passar para a próxima.&lt;/p&gt;

&lt;p&gt;O papel dela é introduzir &lt;strong&gt;não-linearidade&lt;/strong&gt;, um comportamento que nenhuma combinação de pesos e bias consegue reproduzir.&lt;/p&gt;

&lt;p&gt;A mais simples é a &lt;strong&gt;ReLU&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ReLU(x) = max(0, x)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ela zera os negativos e deixa os positivos passarem:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;entrada: [-3.0,  2.0, -0.5,  1.8]
saída:   [ 0.0,  2.0,  0.0,  1.8]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Por que zerar negativos remove a linearidade?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Uma função é linear se &lt;code&gt;f(a + b) = f(a) + f(b)&lt;/code&gt;. Testando com ReLU:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ReLU(-1) + ReLU(1) = 0 + 1 = 1
ReLU(-1 + 1) = ReLU(0) = 0

1 ≠ 0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A propriedade não vale. O "zerar" cria um comportamento assimétrico onde positivos passam, negativos não e isso quebra o que permite o colapso.&lt;/p&gt;

&lt;p&gt;Voltando ao exemplo do tópico anterior e agora com ReLU entre as camadas:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Z = [22, -10]   ← saída da camada 1

ReLU([22, -10]) = [22, 0]   ← o -10 foi zerado

Y = [22, 0] @ W2 + b2

y1 = 22×0.4 + 0×0.6 + 0.5 = 9.3
y2 = 22×0.2 + 0×0.1 + 1.0 = 5.4

Y = [9.3, 5.4]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Sem ReLU o resultado era &lt;code&gt;[3.3, 4.4]&lt;/code&gt;. Com ReLU é &lt;code&gt;[9.3, 5.4]&lt;/code&gt;. O neurônio 2 foi zerado no meio do caminho — e agora &lt;strong&gt;não existe nenhum &lt;code&gt;W&lt;/code&gt; e &lt;code&gt;b&lt;/code&gt; que, numa única camada, produza &lt;code&gt;[9.3, 5.4]&lt;/code&gt; para esse input e ao mesmo tempo se comporte diferente para outros inputs onde o neurônio 2 não seria zerado.&lt;/strong&gt; O comportamento depende do sinal dos valores intermediários, e isso quebra o colapso.&lt;/p&gt;




&lt;h3&gt;
  
  
  4. ReLU no gráfico &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;A forma mais direta de entender o que a ativação faz é olhando o gráfico de duas redes com a mesma arquitetura &lt;code&gt;(1 → 4 → 1)&lt;/code&gt; e os mesmos pesos — a única diferença é a ReLU entre as camadas.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwxzzd8e3v8jb5emje32p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwxzzd8e3v8jb5emje32p.png" alt=" " width="799" height="314"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;À esquerda: &lt;strong&gt;linha reta&lt;/strong&gt;, sempre — independente de quantas layers.&lt;/p&gt;

&lt;p&gt;À direita: segmentos retos com &lt;strong&gt;dobras&lt;/strong&gt;. Cada neurônio oculto contribui com um ponto de dobra onde seu valor pré-ativação cruza zero. Com 4 neurônios ocultos, até 4 dobras possíveis.&lt;/p&gt;

&lt;p&gt;Essas dobras são o que permite à rede aproximar padrões complexos que uma linha reta nunca conseguiria representar.&lt;/p&gt;




&lt;h3&gt;
  
  
  5. ReLU no código &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;A implementação em Rust é trivial:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;relu&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;Matrix&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Matrix&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Vec&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;f64&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="py"&gt;.rows&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;.flat_map&lt;/span&gt;&lt;span class="p"&gt;(|&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="py"&gt;.cols&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;move&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
        &lt;span class="nf"&gt;.map&lt;/span&gt;&lt;span class="p"&gt;(|(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;)|&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="nf"&gt;.get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="nf"&gt;.collect&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="nn"&gt;Matrix&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="py"&gt;.rows&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="py"&gt;.cols&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Recebe uma &lt;code&gt;Matrix&lt;/code&gt;, devolve uma &lt;code&gt;Matrix&lt;/code&gt; do mesmo formato com os negativos zerados. O pipeline fica:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;z1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;camada1&lt;/span&gt;&lt;span class="nf"&gt;.forward&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// X @ W1 + b1&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;a1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;relu&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;z1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;               &lt;span class="c1"&gt;// zera os negativos&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;z2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;camada2&lt;/span&gt;&lt;span class="nf"&gt;.forward&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;a1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;    &lt;span class="c1"&gt;// a1 @ W2 + b2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  6. Onde a ativação entra — e onde não entra &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;A ativação é aplicada &lt;strong&gt;depois&lt;/strong&gt; do forward de cada camada &lt;strong&gt;oculta&lt;/strong&gt;. A camada de saída não leva ativação.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;input
  ↓
Layer 1 → forward → ReLU   ← camadas ocultas levam ativação
  ↓
Layer 2 → forward           ← saída final, sem ativação
  ↓
previsão
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Se zerássemos os negativos na saída, a rede nunca conseguiria prever valores negativos o que seria um problema para qualquer tarefa de regressão.&lt;/p&gt;




&lt;h3&gt;
  
  
  7. Conclusão &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Neste post entendemos por que empilhar camadas lineares não adiciona expressividade e como a ReLU resolve isso com uma operação simples.&lt;/p&gt;

&lt;p&gt;O que foi construído:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A função &lt;code&gt;relu&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Pipeline completo: &lt;code&gt;Layer1 → ReLU → Layer2&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Visualização do colapso linear vs ReLU no gráfico&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No próximo post: &lt;strong&gt;backpropagation&lt;/strong&gt; como medir o erro e fazer a rede aprender de verdade.&lt;/p&gt;




&lt;h3&gt;
  
  
  Referências
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/z4nder/rs-multilayer-perceptron" rel="noopener noreferrer"&gt;Código-fonte do projeto&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=GkiITbgu0V0&amp;amp;t=477s" rel="noopener noreferrer"&gt;Neural Network from Scratch — vídeo que inspirou essa série&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/z4nder/de-um-neuronio-para-uma-rede-matrizes-camadas-e-o-forward-pass-1ai8"&gt;Post anterior — Matrizes, camadas e forward pass&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Se este post fizer sentido pra você, o próximo passo é ensinar a rede a aprender com os próprios erros isso vem no próximo post da série.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>programming</category>
      <category>machinelearning</category>
      <category>rust</category>
    </item>
    <item>
      <title>De um neurônio para uma rede — matrizes, camadas e o forward pass</title>
      <dc:creator>Alexandre</dc:creator>
      <pubDate>Mon, 06 Jul 2026 17:10:01 +0000</pubDate>
      <link>https://dev.to/z4nder/de-um-neuronio-para-uma-rede-matrizes-camadas-e-o-forward-pass-1ai8</link>
      <guid>https://dev.to/z4nder/de-um-neuronio-para-uma-rede-matrizes-camadas-e-o-forward-pass-1ai8</guid>
      <description>&lt;p&gt;Um neurônio com uma entrada só aprende uma reta. Para modelar problemas reais precisamos de mais entradas, mais neurônios e uma forma eficiente de organizar tudo isso. Neste post vamos construir em Rust as peças que tornam uma rede neural possível: matrizes, camadas e o forward pass.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conteúdo
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;1 Prólogo
&lt;/li&gt;
&lt;li&gt;2 O que é uma matriz na prática
&lt;/li&gt;
&lt;li&gt;3 Multiplicação matricial — o que está acontecendo
&lt;/li&gt;
&lt;li&gt;4 O que é uma Layer
&lt;/li&gt;
&lt;li&gt;5 Forward pass
&lt;/li&gt;
&lt;li&gt;6 Conclusão
&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  1. Prólogo &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;No &lt;a href="https://dev.to/z4nder/ia-do-zero-gradient-descent-opimizando-seu-neuronio-em-rust-34cl"&gt;projeto anterior&lt;/a&gt; tínhamos um único neurônio prevendo a distância de uma bala de canhão com um peso, uma entrada e uma saída. Simples, mas inútil para qualquer problema real.&lt;/p&gt;

&lt;p&gt;A distância de uma bala não depende só da energia — depende do vento, do ângulo, do peso do projétil. A rede precisa aprender como cada fator influencia o resultado com um peso diferente. Quando temos múltiplas entradas, múltiplos neurônios e múltiplos exemplos ao mesmo tempo, entram as matrizes.&lt;/p&gt;

&lt;p&gt;Antes a fórmula era &lt;code&gt;distância = w × energia + b&lt;/code&gt; mas com múltiplas entradas (&lt;strong&gt;features&lt;/strong&gt;) o modelo se expande:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;distância = w₁×energia + w₂×vento + w₃×ângulo + b
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Isso pode ser resumido na &lt;strong&gt;notação matricial&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;Y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;X&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt; &lt;span class="n"&gt;W&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O &lt;code&gt;@&lt;/code&gt; é multiplicação matricial. Ele faz exatamente a mesma soma ponderada de antes, mas organizada de forma que funciona para múltiplas features e múltiplos exemplos ao mesmo tempo.&lt;/p&gt;




&lt;h3&gt;
  
  
  2. O que é uma matriz na prática &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Uma matriz é uma tabela de números organizada em linhas e colunas.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;X&lt;/code&gt; representa o dataset de entrada onde &lt;strong&gt;cada linha é um exemplo e cada coluna é uma feature&lt;/strong&gt;. Para 2 exemplos com 3 features, &lt;code&gt;X&lt;/code&gt; tem formato &lt;code&gt;(2×3)&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Matrix&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nd"&gt;vec!&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="mf"&gt;10.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;80.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.30&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;   &lt;span class="c1"&gt;// exemplo 0: energia=10, vento=80, ângulo=0.30&lt;/span&gt;
    &lt;span class="mf"&gt;20.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;60.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.25&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;   &lt;span class="c1"&gt;// exemplo 1: energia=20, vento=60, ângulo=0.25&lt;/span&gt;
&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;W&lt;/code&gt; também vira uma matriz. Com 3 features e 2 neurônios na saída, &lt;code&gt;W&lt;/code&gt; tem formato &lt;code&gt;(3×2)&lt;/code&gt; onde &lt;strong&gt;cada coluna representa um neurônio&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Matrix&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nd"&gt;vec!&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="mf"&gt;0.5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;   &lt;span class="c1"&gt;// pesos da energia  — neurônio 1 e 2&lt;/span&gt;
    &lt;span class="mf"&gt;0.3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;   &lt;span class="c1"&gt;// pesos do vento    — neurônio 1 e 2&lt;/span&gt;
    &lt;span class="mf"&gt;0.2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;   &lt;span class="c1"&gt;// pesos do ângulo   — neurônio 1 e 2&lt;/span&gt;
&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;b&lt;/code&gt; é um &lt;code&gt;Vec&amp;lt;f64&amp;gt;&lt;/code&gt; com &lt;strong&gt;um valor por neurônio&lt;/strong&gt;. Ele não entra na multiplicação de matrizes pois é somado diretamente à saída:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Vec&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;f64&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nd"&gt;vec!&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mf"&gt;0.2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.1&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt; &lt;span class="c1"&gt;// um bias por neurônio&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  3. Multiplicação matricial — o que está acontecendo &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;No projeto anterior usávamos &lt;code&gt;*&lt;/code&gt; para multiplicar um peso por uma entrada. O &lt;code&gt;@&lt;/code&gt; faz a mesma conta para todas as features e todos os exemplos de uma vez.&lt;/p&gt;

&lt;p&gt;Para o exemplo 0 com 1 neurônio:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;X[0] = [10.0, 80.0, 0.3]
W    = [0.5,  0.3,  0.2]

saída[0] = 10.0×0.5 + 80.0×0.3 + 0.3×0.2
         = 5.0 + 24.0 + 0.06
         = 29.06
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A implementação completa fica assim:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;matmul&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;other&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;Matrix&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Matrix&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;assert_eq!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.cols&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;other&lt;/span&gt;&lt;span class="py"&gt;.rows&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;"dimensões incompatíveis: {}×{} · {}×{}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.rows&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.cols&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;other&lt;/span&gt;&lt;span class="py"&gt;.rows&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;other&lt;/span&gt;&lt;span class="py"&gt;.cols&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.rows&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;// linhas de X  (exemplos)&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;other&lt;/span&gt;&lt;span class="py"&gt;.cols&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// colunas de W (neurônios)&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.cols&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;// features — devem bater com linhas de W&lt;/span&gt;

    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Matrix&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;zeros&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;         &lt;span class="c1"&gt;// cada exemplo&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;     &lt;span class="c1"&gt;// cada neurônio&lt;/span&gt;
            &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;sum&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="c1"&gt;// soma ponderada das features&lt;/span&gt;
                &lt;span class="n"&gt;sum&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="nf"&gt;.get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;other&lt;/span&gt;&lt;span class="nf"&gt;.get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="nf"&gt;.set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;result&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O &lt;code&gt;assert_eq!&lt;/code&gt; garante que as dimensões batem antes de rodar. Se &lt;code&gt;X&lt;/code&gt; tem 3 colunas, &lt;code&gt;W&lt;/code&gt; precisa ter 3 linhas pois sem isso o loop produziria resultados errados silenciosamente.&lt;/p&gt;




&lt;h3&gt;
  
  
  4. O que é uma Layer &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Com um único neurônio: 1 peso, 1 bias, 1 saída. Ele só consegue aprender uma relação linear simples.&lt;/p&gt;

&lt;p&gt;Uma &lt;strong&gt;Layer&lt;/strong&gt; é um conjunto de neurônios operando juntos sobre a mesma entrada onde você define quantos neurônios quer e ela cria um &lt;code&gt;W&lt;/code&gt; com uma coluna por neurônio:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;Layer&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Matrix&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Vec&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;f64&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// 3 features de entrada, 4 neurônios na camada&lt;/span&gt;
&lt;span class="nn"&gt;Layer&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Os valores de &lt;code&gt;W&lt;/code&gt; são inicializados &lt;strong&gt;aleatórios&lt;/strong&gt;, não zeros. Se todos os pesos começassem iguais, todos os neurônios aprenderiam exatamente a mesma coisa e a camada inteira seria inútil.&lt;/p&gt;

&lt;p&gt;A escala do aleatório também importa. Pesos muito grandes e os valores explodem ao passar pelas camadas. Muito pequenos e desaparecem. Para isso usamos &lt;strong&gt;Xavier initialization&lt;/strong&gt; — o intervalo é proporcional ao número de entradas:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;scale&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;1.0&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;in_features&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nb"&gt;f64&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.sqrt&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// ≈ 0.577 para 3 features&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;w_data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Vec&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;f64&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="n"&gt;in_features&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;out_features&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;.map&lt;/span&gt;&lt;span class="p"&gt;(|&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="n"&gt;rng&lt;/span&gt;&lt;span class="nf"&gt;.gen_range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;scale&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="n"&gt;scale&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="nf"&gt;.collect&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Gerando pesos dentro de um intervalo controlado, como:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;W (3×4):
 -0.52,  0.18, -0.31,  0.44,
  0.57, -0.12,  0.08, -0.49,
 -0.21,  0.63, -0.55,  0.37
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O &lt;strong&gt;bias começa em zeros&lt;/strong&gt; — ele não tem o mesmo problema de simetria que os pesos.&lt;/p&gt;




&lt;h3&gt;
  
  
  5. Forward pass &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;O &lt;code&gt;forward&lt;/code&gt; é a função da layer que aplica &lt;code&gt;Y = X @ W + b&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Com um único neurônio isso era &lt;code&gt;y = x * w + b&lt;/code&gt;. Com vários neurônios e vários exemplos ao mesmo tempo, a mesma conta vira multiplicação matricial:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;X (1 exemplo, 3 features):
  [10.0, 80.0, 0.3]

W (3 features, 4 neurônios):
  [-0.41,  0.12, -0.29,  0.33]
  [ 0.51, -0.08,  0.05, -0.44]
  [-0.19,  0.55, -0.48,  0.27]

b = [0.0, 0.0, 0.0, 0.0]

y1 = 10×(-0.41) + 80×0.51  + 0.3×(-0.19) + 0  ≈  36.64
y2 = 10×0.12   + 80×(-0.08) + 0.3×0.55   + 0  ≈  -5.04
y3 = 10×(-0.29) + 80×0.05  + 0.3×(-0.48) + 0  ≈   0.96
y4 = 10×0.33   + 80×(-0.44) + 0.3×0.27   + 0  ≈ -31.82

Y = [36.64, -5.04, 0.96, -31.82]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Cada valor de &lt;code&gt;Y&lt;/code&gt; é a saída de um neurônio da camada. A implementação:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;forward&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;Matrix&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Matrix&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;out&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="nf"&gt;.matmul&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.w&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// X @ W&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="py"&gt;.rows&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="py"&gt;.cols&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="nf"&gt;.set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="nf"&gt;.get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.b&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt; &lt;span class="c1"&gt;// + b&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;out&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Chamamos isso de &lt;strong&gt;forward pass&lt;/strong&gt; porque a informação avança pela rede da entrada até a saída. Mais tarde, durante o treinamento, faremos o caminho inverso (&lt;strong&gt;backward pass&lt;/strong&gt;) para ajustar os pesos e reduzir o erro.&lt;/p&gt;




&lt;h3&gt;
  
  
  6. Conclusão &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Neste post saímos de um neurônio com uma entrada e chegamos numa camada com múltiplos neurônios recebendo múltiplas features ao mesmo tempo.&lt;/p&gt;

&lt;p&gt;O que foi construído:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A struct &lt;code&gt;Matrix&lt;/code&gt; com multiplicação matricial e validação de dimensões&lt;/li&gt;
&lt;li&gt;A struct &lt;code&gt;Layer&lt;/code&gt; com &lt;strong&gt;Xavier initialization&lt;/strong&gt; e &lt;code&gt;forward&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;A struct &lt;code&gt;Dataset&lt;/code&gt; com inputs e targets&lt;/li&gt;
&lt;li&gt;O forward pass completo com duas camadas em sequência&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No próximo post: funções de ativação, backpropagation e o loop de treino que faz a rede aprender de verdade.&lt;/p&gt;




&lt;h3&gt;
  
  
  Referências
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/z4nder/rs-multilayer-perceptron" rel="noopener noreferrer"&gt;Código-fonte do projeto&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=GkiITbgu0V0&amp;amp;t=477s" rel="noopener noreferrer"&gt;Neural Network from Scratch — vídeo que inspirou essa série&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/z4nder/ia-do-zero-gradient-descent-otimizando-seu-neuronio-em-rust"&gt;Post anterior — Gradient Descent&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Se este post fizer sentido pra você, o próximo passo é adicionar ativação entre as camadas e ensinar a rede a aprender com os próprios erros e isso vem no próximo post da série.&lt;/p&gt;

</description>
      <category>machinelearning</category>
      <category>rust</category>
      <category>matrix</category>
      <category>ai</category>
    </item>
    <item>
      <title>Gradient Descent — opimizando seu neurônio em rust</title>
      <dc:creator>Alexandre</dc:creator>
      <pubDate>Wed, 01 Jul 2026 16:35:42 +0000</pubDate>
      <link>https://dev.to/z4nder/ia-do-zero-gradient-descent-opimizando-seu-neuronio-em-rust-34cl</link>
      <guid>https://dev.to/z4nder/ia-do-zero-gradient-descent-opimizando-seu-neuronio-em-rust-34cl</guid>
      <description>&lt;h2&gt;
  
  
  IA do zero: Gradient Descent — otimizando seu neurônio em rust
&lt;/h2&gt;

&lt;p&gt;
  &lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fz4nder%2Frs-gradient-descent-neuron%2Fmain%2Fassets%2Fbanner.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fz4nder%2Frs-gradient-descent-neuron%2Fmain%2Fassets%2Fbanner.png" alt="banner do projeto" width="800" height="336"&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;Você já usou o GPT, mas sabe o que existe dentro dele? Neste post vamos ensinar o neurônio a melhorar suas previsões de forma inteligente usando &lt;strong&gt;gradient descent&lt;/strong&gt;, o algoritmo que está por trás de praticamente todo o aprendizado de máquina moderno.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conteúdo
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;1 Prólogo
&lt;/li&gt;
&lt;li&gt;2 O problema com o ±0.01
&lt;/li&gt;
&lt;li&gt;3 Medindo o erro geral — Loss (MSE)
&lt;/li&gt;
&lt;li&gt;4 A parábola — visualizando o loss
&lt;/li&gt;
&lt;li&gt;5 O gradiente — a inclinação como bússola
&lt;/li&gt;
&lt;li&gt;6 Gradient Descent — descendo a parábola
&lt;/li&gt;
&lt;li&gt;7 Implementando o Gradient Descent
&lt;/li&gt;
&lt;li&gt;8 Resultado — ±0.01 vs Gradient Descent
&lt;/li&gt;
&lt;li&gt;9 Conclusão
&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  1. Prólogo &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Retomando o &lt;a href="https://dev.to/z4nder/ia-do-zero-implementar-seu-primeiro-neuronio-em-rust-jc9"&gt;post anterior&lt;/a&gt;, implementamos um neurônio capaz de aprender a prever a distância de um projétil com base na energia do disparo. O treinamento e os resultados foram razoáveis, mas o algoritmo de ajuste utilizado era propositalmente simples para fins educacionais.&lt;/p&gt;

&lt;p&gt;Agora vamos entender e implementar o tão temido &lt;strong&gt;Gradient Descent&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Confesso que, durante meu aprendizado desse tópico, me assustei um pouco com as notações matemáticas, uso de derivadas e gráficos em três dimensões para dar um pequeno passo além do que parecia tão simples no último post. Mas, depois de estudar um pouco mais, acredito que consegui entender um pouco melhor o assunto então vou tentar compartilhar esse entendimento aqui.&lt;/p&gt;




&lt;h3&gt;
  
  
  2. O problema com o ±0.01 &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;O treino anterior ajustava &lt;code&gt;w&lt;/code&gt; e &lt;code&gt;b&lt;/code&gt; com um passo fixo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.weight&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="mf"&gt;0.01&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.bias&lt;/span&gt;   &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="mf"&gt;0.01&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.weight&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mf"&gt;0.01&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.bias&lt;/span&gt;   &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mf"&gt;0.01&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O problema aparece na prática:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;erro = 500  → ajusta 0.01
erro = 0.5  → ajusta 0.01
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Quando o neurônio está muito errado, deveria dar passos grandes e quando está quase certo, passos pequenos para não passar do ponto.&lt;/p&gt;

&lt;p&gt;O que precisamos é de um ajuste &lt;strong&gt;proporcional ao erro&lt;/strong&gt;. É aí que entra o &lt;strong&gt;loss&lt;/strong&gt; e depois o &lt;strong&gt;gradient descent&lt;/strong&gt;.&lt;/p&gt;




&lt;h3&gt;
  
  
  3. Medindo o erro geral — Loss (MSE) &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Já calculamos o erro de um item no dataset de forma simples no post anterior&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;erro = previsto - real
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Mas precisamos entender o quão errado o neurônio está no conjunto inteiro de dados, e não apenas em um exemplo específico. Se ficarmos ajustando as variáveis somente com base no erro de um par do dataset, acabamos prejudicando o resultado nos outros. Precisamos, portanto, de uma forma de calcular o erro médio sobre todo o dataset — isso é o que chamaremos de &lt;strong&gt;&lt;code&gt;loss&lt;/code&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Para isso precisamos da média dos erros&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;loss = (erro1 + erro2 + erro3) / n
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O problema é que erros se cancelam:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ponto A: erro = +30  (previu demais)
ponto B: erro = -30  (previu de menos)

média = 0  ← parece perfeito, mas está errado nos dois casos
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A solução é o &lt;strong&gt;MSE — Mean Squared Error&lt;/strong&gt; (Erro Quadrático Médio):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;loss = (1/n) × Σ (previsto - real)²
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Elevar ao quadrado tem dois efeitos:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Remove o sinal:&lt;/strong&gt; erros positivos e negativos não se cancelam mais&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Penaliza erros grandes:&lt;/strong&gt; um erro de 10 vira 100, um erro de 2 vira 4
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;erro = 2  → contribuição = 4
erro = 10 → contribuição = 100
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Um erro cinco vezes maior gera uma penalização vinte e cinco vezes maior, o loss deve gritar quando o neurônio está muito errado.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;loss&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dataset&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="nb"&gt;f64&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;f64&lt;/span&gt;&lt;span class="p"&gt;)],&lt;/span&gt; &lt;span class="n"&gt;neuron&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;Neuron&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;f64&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dataset&lt;/span&gt;&lt;span class="nf"&gt;.len&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nb"&gt;f64&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;f64&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dataset&lt;/span&gt;
        &lt;span class="nf"&gt;.iter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="nf"&gt;.map&lt;/span&gt;&lt;span class="p"&gt;(|(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;actual&lt;/span&gt;&lt;span class="p"&gt;)|&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;neuron&lt;/span&gt;&lt;span class="nf"&gt;.predict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;actual&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="n"&gt;error&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;
        &lt;span class="nf"&gt;.sum&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;sum&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;MSE&lt;/strong&gt; é a fórmula. &lt;strong&gt;Loss&lt;/strong&gt; é o conceito. A partir daqui vamos usar o termo &lt;strong&gt;loss&lt;/strong&gt; para falar do erro geral do neurônio.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h3&gt;
  
  
  4. A parábola — visualizando o loss &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Agora que temos o loss, podemos calcular o loss para cada valor possível de &lt;code&gt;w&lt;/code&gt; e plotar o resultado. Para isso, fixamos &lt;code&gt;b=18&lt;/code&gt; como estimativa inicial, isolando o efeito de &lt;code&gt;w&lt;/code&gt; no gráfico.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fz4nder%2Frs-gradient-descent-neuron%2Fmain%2Fassets%2F02_parabola.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fz4nder%2Frs-gradient-descent-neuron%2Fmain%2Fassets%2F02_parabola.png" alt="parábola do loss variando w com b fixo em 18, mostrando o mínimo em w=0.92" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Podemos observar que o gráfico tem formato de &lt;strong&gt;parábola&lt;/strong&gt; caindo até um mínimo e sobe novamente, o ponto onde &lt;strong&gt;&lt;code&gt;w=0.92&lt;/code&gt;&lt;/strong&gt; é o valor ideal para &lt;code&gt;b=18&lt;/code&gt;, o &lt;strong&gt;mínimo&lt;/strong&gt; do loss nesse dataset.&lt;/p&gt;

&lt;p&gt;O objetivo do treino é encontrar os valores de &lt;strong&gt;&lt;code&gt;w&lt;/code&gt;&lt;/strong&gt; e &lt;strong&gt;&lt;code&gt;b&lt;/code&gt;&lt;/strong&gt; que reduzem ao máximo o &lt;strong&gt;&lt;code&gt;loss&lt;/code&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Na prática, quando temos dois parâmetros (&lt;code&gt;w&lt;/code&gt; e &lt;code&gt;b&lt;/code&gt;), o loss vira uma &lt;strong&gt;superfície 3D&lt;/strong&gt; — algo parecido com uma tigela. Nosso objetivo continua o mesmo: atingir o ponto mais fundo. O gradient descent faz isso descendo essa superfície simultaneamente nos dois eixos.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fz4nder%2Frs-gradient-descent-neuron%2Fmain%2Fassets%2F02_surface.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fz4nder%2Frs-gradient-descent-neuron%2Fmain%2Fassets%2F02_surface.png" alt="superfície 3D do loss em função de w e b, com destaque no ponto mínimo" width="800" height="620"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  5. O gradiente — a inclinação como bússola &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Você está em algum ponto da parábola e quer chegar no fundo, o &lt;strong&gt;gradiente&lt;/strong&gt; é a inclinação da curva naquele ponto e ele te diz duas coisas:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Direção:&lt;/strong&gt; se a curva está subindo, você vai na direção oposta&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Magnitude:&lt;/strong&gt; curva íngreme (longe do fundo) → passo grande. Quase plana (perto do fundo) → passo pequeno
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;w=0   → inclinação íngreme → passo grande
w=0.8 → inclinação suave  → passo pequeno
w=0.9 → fundo da parábola → gradiente = 0, para
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;É exatamente o que faltava no &lt;code&gt;±0.01&lt;/code&gt;: o passo &lt;strong&gt;proporcional à inclinação&lt;/strong&gt;, não fixo.&lt;/p&gt;

&lt;p&gt;Os gradientes do loss em relação a &lt;code&gt;w&lt;/code&gt; e &lt;code&gt;b&lt;/code&gt; são:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="err"&gt;∂&lt;/span&gt;&lt;span class="n"&gt;loss&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="err"&gt;∂&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;dataset_size&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;Σ&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;erro&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="err"&gt;∂&lt;/span&gt;&lt;span class="n"&gt;loss&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="err"&gt;∂&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;dataset_size&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;Σ&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;erro&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;w&lt;/code&gt;&lt;/strong&gt; multiplica por &lt;code&gt;x&lt;/code&gt; porque &lt;code&gt;w&lt;/code&gt; está ligado a &lt;code&gt;x&lt;/code&gt; na equação do neurônio (&lt;code&gt;y = wx + b&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;b&lt;/code&gt;&lt;/strong&gt; acumula apenas o erro, pois é um deslocamento constante, não depende de &lt;code&gt;x&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Não precisa se assustar com essas fórmulas, pois não vamos derivá-las agora.&lt;/p&gt;

&lt;p&gt;Por enquanto, basta entender que elas medem a inclinação do erro em relação a &lt;code&gt;w&lt;/code&gt; e &lt;code&gt;b&lt;/code&gt;, indicando para qual direção devemos mover os parâmetros e o quão forte deve ser essa atualização.&lt;/p&gt;

&lt;p&gt;Na implementação, veremos que calcular os gradientes é bem mais simples do que a notação matemática sugere.&lt;/p&gt;




&lt;h3&gt;
  
  
  6. Gradient Descent — descendo a parábola &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Agora que entendemos que precisamos alterar &lt;code&gt;w&lt;/code&gt; e &lt;code&gt;b&lt;/code&gt; em direção ao mínimo podemos aplicar essa fórmula&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;erro&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;previsto&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;real&lt;/span&gt;
&lt;span class="n"&gt;dataset_size&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dataset&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;

&lt;span class="err"&gt;∂&lt;/span&gt;&lt;span class="n"&gt;L&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="err"&gt;∂&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;dataset_size&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;Σ&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;erro&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="err"&gt;∂&lt;/span&gt;&lt;span class="n"&gt;L&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="err"&gt;∂&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;dataset_size&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;Σ&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;erro&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;Gradient&lt;/span&gt; &lt;span class="n"&gt;Descent&lt;/span&gt;
&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;lr&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="err"&gt;∂&lt;/span&gt;&lt;span class="n"&gt;loss&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="err"&gt;∂&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;
&lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;lr&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="err"&gt;∂&lt;/span&gt;&lt;span class="n"&gt;loss&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="err"&gt;∂&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Assim nasce o &lt;strong&gt;Gradient Descent&lt;/strong&gt;, para aplicar vamos primeiro definir um valor de &lt;strong&gt;&lt;code&gt;lr&lt;/code&gt;&lt;/strong&gt;=0.0001, que é o tamanho do passo que vamos dar.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;lr muito grande → passa do fundo, fica oscilando
lr muito pequeno → chega lá, mas demora muito
lr ideal → desce suave até o mínimo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Para aplicar vamos definir alguns valores iniciais&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;w&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;10.0&lt;/span&gt;
&lt;span class="n"&gt;b&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;10.0&lt;/span&gt;
&lt;span class="n"&gt;lr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.0001&lt;/span&gt;
&lt;span class="n"&gt;dataset_size&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Também vamos definir um dataset&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(1,  60)
(2,  80)
(10, 60)
(4,  70)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Com &lt;code&gt;w=10, b=10&lt;/code&gt; o neurônio calcula &lt;code&gt;previsto = 10x + 10&lt;/code&gt;. Agora acumulamos &lt;code&gt;Σ(erro)&lt;/code&gt; e &lt;code&gt;Σ(erro * x)&lt;/code&gt; ponto a ponto:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;posição&lt;/th&gt;
&lt;th&gt;x&lt;/th&gt;
&lt;th&gt;real&lt;/th&gt;
&lt;th&gt;previsto&lt;/th&gt;
&lt;th&gt;erro = previsto - real&lt;/th&gt;
&lt;th&gt;erro × x&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;60&lt;/td&gt;
&lt;td&gt;20&lt;/td&gt;
&lt;td&gt;-40&lt;/td&gt;
&lt;td&gt;-40&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;80&lt;/td&gt;
&lt;td&gt;30&lt;/td&gt;
&lt;td&gt;-50&lt;/td&gt;
&lt;td&gt;-100&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;60&lt;/td&gt;
&lt;td&gt;110&lt;/td&gt;
&lt;td&gt;50&lt;/td&gt;
&lt;td&gt;500&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;70&lt;/td&gt;
&lt;td&gt;50&lt;/td&gt;
&lt;td&gt;-20&lt;/td&gt;
&lt;td&gt;-80&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Calculando os somatórios &lt;code&gt;Σ(erro)&lt;/code&gt; e &lt;code&gt;Σ(erro * x)&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Σ(erro * x) = -40 + -100 + 500 + -80 = 280
Σ(erro)     = -40 +  -50 +  50 + -20 = -60
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Calculando as derivadas &lt;code&gt;∂L/∂w&lt;/code&gt; e &lt;code&gt;∂L/∂b&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;∂L/∂w = (2 / 4) * 280 = 140
∂L/∂b = (2 / 4) * -60 = -30
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Calculando &lt;strong&gt;Gradient Descent&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;weight&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;10.0&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mf"&gt;0.0001&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;140&lt;/span&gt;    &lt;span class="err"&gt;→&lt;/span&gt; &lt;span class="mf"&gt;9.986&lt;/span&gt;
&lt;span class="n"&gt;bias&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;10.0&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mf"&gt;0.0001&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="err"&gt;→&lt;/span&gt; &lt;span class="mf"&gt;10.003&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Chegamos em um ajuste de &lt;code&gt;w=10&lt;/code&gt; para &lt;code&gt;w=9.986&lt;/code&gt; e &lt;code&gt;b=10&lt;/code&gt; para &lt;code&gt;b=10.003&lt;/code&gt;. Com &lt;code&gt;∂L/∂w = +140&lt;/code&gt; o gradiente é positivo, então diminuímos &lt;code&gt;w&lt;/code&gt;, o neurônio estava prevendo demais em &lt;code&gt;x=10&lt;/code&gt;. Com &lt;code&gt;∂L/∂b = -30&lt;/code&gt; o gradiente é negativo, então aumentamos &lt;code&gt;b&lt;/code&gt;, a maioria dos pontos estava sendo subestimada.&lt;/p&gt;

&lt;h3&gt;
  
  
  7. Implementando o Gradient Descent &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Agora que calculamos manualmente os valores chegou a parte mais fácil que é implementar nosso algoritmo.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Inicializa &lt;code&gt;Σ(erro * x)&lt;/code&gt; e &lt;code&gt;Σ(erro)&lt;/code&gt;&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;error_x_sum&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;// Σ(erro * x)&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;error_sum&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;// Σ(erro)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2. Acumula os erros do dataset&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Para cada ponto calculamos o erro e acumulamos os dois somatórios.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;actual&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;dataset&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="nf"&gt;.predict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;actual&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="n"&gt;error_x_sum&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;error_sum&lt;/span&gt;   &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;3. Calcula as derivadas &lt;code&gt;∂L/∂w&lt;/code&gt; e &lt;code&gt;∂L/∂b&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Transformamos os somatórios nos gradientes finais dividindo pelo tamanho do dataset.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;grad_w&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;2.0&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;dataset_size&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;error_x_sum&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;// ∂L/∂w&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;grad_b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;2.0&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;dataset_size&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;error_sum&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;     &lt;span class="c1"&gt;// ∂L/∂b&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;4. Aplica o Gradient Descent&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Andamos na direção oposta ao gradiente (por isso o &lt;code&gt;-&lt;/code&gt;), com passo controlado pelo &lt;strong&gt;&lt;code&gt;lr&lt;/code&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;grad_w&lt;/code&gt; positivo → diminuímos &lt;code&gt;w&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;grad_w&lt;/code&gt; negativo → aumentamos &lt;code&gt;w&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;grad_w&lt;/code&gt; próximo de zero → estamos perto do mínimo
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.weight&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="n"&gt;lr&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;grad_w&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.bias&lt;/span&gt;   &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="n"&gt;lr&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;grad_b&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;5. Implementação completa&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;train&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dataset&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="nb"&gt;f64&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;f64&lt;/span&gt;&lt;span class="p"&gt;)],&lt;/span&gt; &lt;span class="n"&gt;lr&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;f64&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;epochs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;usize&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;dataset_size&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dataset&lt;/span&gt;&lt;span class="nf"&gt;.len&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nb"&gt;f64&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_epoch&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="n"&gt;epochs&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;error_x_sum&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;error_sum&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;actual&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;dataset&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="nf"&gt;.predict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;actual&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="n"&gt;error_x_sum&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="n"&gt;error_sum&lt;/span&gt;   &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;grad_w&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;2.0&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;dataset_size&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;error_x_sum&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;grad_b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;2.0&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;dataset_size&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;error_sum&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.weight&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="n"&gt;lr&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;grad_w&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.bias&lt;/span&gt;   &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="n"&gt;lr&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;grad_b&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  8. Resultado — ±0.01 vs Gradient Descent &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Rodamos os dois algoritmos com as mesmas condições iniciais:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;±0.01&lt;/th&gt;
&lt;th&gt;Gradient Descent&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Epochs&lt;/td&gt;
&lt;td&gt;1000&lt;/td&gt;
&lt;td&gt;1000&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Passo&lt;/td&gt;
&lt;td&gt;fixo &lt;code&gt;0.01&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;proporcional ao gradiente&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Learning rate&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0.0003&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;W inicial&lt;/td&gt;
&lt;td&gt;5.0&lt;/td&gt;
&lt;td&gt;5.0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;B inicial&lt;/td&gt;
&lt;td&gt;5.0&lt;/td&gt;
&lt;td&gt;5.0&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Com isso obtivemos os seguintes resultados&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fz4nder%2Frs-gradient-descent-neuron%2Fmain%2Fassets%2F02_comparison.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fz4nder%2Frs-gradient-descent-neuron%2Fmain%2Fassets%2F02_comparison.png" alt="comparação dos ajustes de ±0.01 e gradient descent sobre o dataset" width="799" height="314"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;O que o gradient descent faz é encontrar a &lt;strong&gt;melhor reta possível&lt;/strong&gt; dentro dessa limitação e o &lt;strong&gt;loss&lt;/strong&gt; mostra isso claramente caindo de &lt;code&gt;77&lt;/code&gt; no &lt;code&gt;±0.01&lt;/code&gt; para &lt;code&gt;37&lt;/code&gt;. No gráfico abaixo podemos observar isso&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fz4nder%2Frs-gradient-descent-neuron%2Fmain%2Fassets%2F02_loss_comparison.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fz4nder%2Frs-gradient-descent-neuron%2Fmain%2Fassets%2F02_loss_comparison.png" alt="curva de loss ao longo das epochs comparando ±0.01 e gradient descent em escala log" width="800" height="462"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Outro ponto que vale destacar é a forma como o gradient descent realiza os ajustes de &lt;code&gt;w&lt;/code&gt; e &lt;code&gt;b&lt;/code&gt;, cada ponto é uma epoch. Com &lt;code&gt;±0.01&lt;/code&gt; dá passos iguais o tempo todo, mesmo perto do fundo continua com a mesma força, já o gradient descent desacelera conforme se aproxima e para quando o gradiente chega a zero. No gráfico abaixo podemos observar isso&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fz4nder%2Frs-gradient-descent-neuron%2Fmain%2Fassets%2F02_path.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fz4nder%2Frs-gradient-descent-neuron%2Fmain%2Fassets%2F02_path.png" alt="caminho de cada algoritmo na parábola epoch a epoch, mostrando passos fixos vs proporcionais" width="799" height="314"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ainda assim a linha não tocou perfeitamente todos os pontos, para isso seriam necessários mais parâmetros e mais neurônios, ou seja, uma rede neural. Isso vem nas próximas fases.&lt;/p&gt;




&lt;h3&gt;
  
  
  9. Conclusão &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Neste post saímos de um ajuste cego e implementamos &lt;strong&gt;gradient descent&lt;/strong&gt;, o algoritmo base do aprendizado de máquina moderno.&lt;/p&gt;

&lt;p&gt;O que foi aprendido:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;O &lt;strong&gt;loss&lt;/strong&gt; (MSE) transforma os erros individuais num único número que representa o desempenho geral do neurônio&lt;/li&gt;
&lt;li&gt;O &lt;strong&gt;gradiente&lt;/strong&gt; é a inclinação do loss em relação a cada parâmetro e ele diz a direção e o tamanho do passo&lt;/li&gt;
&lt;li&gt;O gradient descent desce a superfície de loss simultaneamente em &lt;code&gt;w&lt;/code&gt; e &lt;code&gt;b&lt;/code&gt; até encontrar o mínimo&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;O que ainda não resolvemos: com um único neurônio e uma função linear, o melhor que conseguimos é uma reta e dados que não seguem uma reta linear não podem ser modelados assim, independente de quantas &lt;strong&gt;epochs&lt;/strong&gt; ou de qual algoritmo de treino.&lt;/p&gt;

&lt;p&gt;No próximo post: &lt;strong&gt;redes neurais&lt;/strong&gt;, múltiplos neurônios em camadas que juntos conseguem aprender padrões não-lineares.&lt;/p&gt;




&lt;h3&gt;
  
  
  Referências
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/z4nder/rs-gradient-descent-neuron" rel="noopener noreferrer"&gt;Código-fonte do projeto&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=GkiITbgu0V0&amp;amp;t=477s" rel="noopener noreferrer"&gt;Neural Network from Scratch — vídeo que inspirou essa série&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Gradient_descent" rel="noopener noreferrer"&gt;Gradient Descent — Wikipedia&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Se este post fizer sentido pra você, o próximo passo natural é adicionar mais neurônios e introduzir funções de ativação é aí que o aprendizado começa a capturar padrões que uma reta simples não consegue descrever.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>programming</category>
      <category>machinelearning</category>
      <category>rust</category>
    </item>
    <item>
      <title>Implementar seu primeiro neurônio em Rust</title>
      <dc:creator>Alexandre</dc:creator>
      <pubDate>Tue, 30 Jun 2026 22:26:20 +0000</pubDate>
      <link>https://dev.to/z4nder/ia-do-zero-implementar-seu-primeiro-neuronio-em-rust-jc9</link>
      <guid>https://dev.to/z4nder/ia-do-zero-implementar-seu-primeiro-neuronio-em-rust-jc9</guid>
      <description>&lt;p&gt;Você já usou o GPT, mas sabe o que existe dentro dele? Neste post vamos construir em Rust o &lt;strong&gt;bloco mais fundamental de qualquer rede neural&lt;/strong&gt;, um único neurônio e entender na prática como &lt;strong&gt;previsão, erro e treino&lt;/strong&gt; funcionam.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conteúdo
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;1 Prólogo
&lt;/li&gt;
&lt;li&gt;2 O problema
&lt;/li&gt;
&lt;li&gt;3 O que é um dataset
&lt;/li&gt;
&lt;li&gt;4 A fórmula: y = mx + b
&lt;/li&gt;
&lt;li&gt;5 Implementando o neurônio
&lt;/li&gt;
&lt;li&gt;6 Calculando o erro
&lt;/li&gt;
&lt;li&gt;7 Desenvolvendo o training loop
&lt;/li&gt;
&lt;li&gt;8 As limitações desse método
&lt;/li&gt;
&lt;li&gt;9 Conclusão
&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  1. Prólogo &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Tenho usado muita IA ultimamente para escrever código, construir produtos e acompanhar tudo o que está acontecendo na área. Um ponto com o qual sempre concordo é a importância de &lt;strong&gt;estudar os fundamentos&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Em algum momento usamos jQuery, depois React, Vue, Svelte, Next, Nuxt, Xupt, Xep e plinbols. Por trás de todas elas, existem conceitos e &lt;strong&gt;princípios que permanecem&lt;/strong&gt; e é nisso que acredito que vale a pena investir tempo tentando compreender.&lt;/p&gt;

&lt;p&gt;Imagine um cenário em que algum conhecido não técnico te pergunta como funciona essa tal de IA e você não faz ideia do que responder. Talvez isso nem fizesse tanta diferença, porque provavelmente ele também não entenderia todos os detalhes, mas eu prefiro não correr o risco de &lt;strong&gt;passar essa vergonha&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Então resolvi voltar um pouco ao começo: estudar alguns conceitos fundamentais, implementá-los, tomar notas e transformar essas anotações em uma &lt;strong&gt;série de posts&lt;/strong&gt; para compartilhar essa jornada de aprendizado.&lt;/p&gt;

&lt;p&gt;Este primeiro post é sobre implementar e treinar um neurônio artificial capaz de aprender uma relação entre uma entrada X e uma saída Y.&lt;/p&gt;




&lt;h3&gt;
  
  
  2. O problema &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Imagine um canhão que cada vez que ele dispara, você controla a energia do disparo e queremos saber até onde a bala vai chegar.&lt;/p&gt;

&lt;p&gt;A pergunta é: dado um &lt;strong&gt;valor de energia&lt;/strong&gt; que nunca usamos antes, conseguimos prever a &lt;strong&gt;distância&lt;/strong&gt;?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;energia → [ neurônio ] → distância prevista
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;É isso que o neurônio vai aprender — &lt;strong&gt;não a partir de uma fórmula&lt;/strong&gt;, mas a partir dos dados que coletamos.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ftcc56vvgrzl1eh9s25r7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ftcc56vvgrzl1eh9s25r7.png" alt="canhão e dataset" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  3. O que é um dataset &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Alguém foi lá e atirou o canhão 9 vezes e a cada disparo, anotou dois números: a &lt;strong&gt;energia usada&lt;/strong&gt; e a &lt;strong&gt;distância&lt;/strong&gt; que a bala percorreu.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;dataset&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Vec&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;f64&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;f64&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nd"&gt;vec!&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;10.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;28.0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;  &lt;span class="c1"&gt;// energia 10 → bala caiu a 28&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;20.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;38.0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;  &lt;span class="c1"&gt;// energia 20 → bala caiu a 38&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;30.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;47.0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;40.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;56.0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;50.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;64.0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;60.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;74.0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;70.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;82.0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;80.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;91.0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;90.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;100.0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="c1"&gt;// energia 90 → bala caiu a 100&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Cada par é &lt;code&gt;(energia, distância)&lt;/code&gt; e este é o nosso &lt;strong&gt;dataset&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;É com esses dados que o neurônio vai aprender, ele &lt;strong&gt;nunca vê a fórmula por trás&lt;/strong&gt;, &lt;strong&gt;somente os pares&lt;/strong&gt;. É como tentar descobrir a receita de um prato apenas provando ele &lt;strong&gt;várias vezes&lt;/strong&gt;.&lt;/p&gt;




&lt;h3&gt;
  
  
  4. A fórmula: y = mx + b &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Olhando os dados dá pra perceber: conforme a energia aumenta, a distância aumenta proporcionalmente então podemos descrever esse caso como a equação de uma reta.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;y = mx + b&lt;/code&gt; descreve uma linha reta. Dado qualquer &lt;code&gt;x&lt;/code&gt;, ela devolve um &lt;code&gt;y&lt;/code&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;m&lt;/code&gt; controla a &lt;strong&gt;inclinação&lt;/strong&gt; — a cada 1 unidade que &lt;code&gt;x&lt;/code&gt; avança, &lt;code&gt;y&lt;/code&gt; sobe &lt;code&gt;m&lt;/code&gt; unidades&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;b&lt;/code&gt; controla onde a reta &lt;strong&gt;começa&lt;/strong&gt; — onde ela cruza o eixo Y quando &lt;code&gt;x = 0&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fc6uou4qnob9qx8ykz70q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fc6uou4qnob9qx8ykz70q.png" alt="efeito do bias" width="700" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwyhq4fftxi3s9hxqek8m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwyhq4fftxi3s9hxqek8m.png" alt="efeito do weight" width="700" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Neste primeiro exemplo, vamos modelar o neurônio como uma &lt;strong&gt;transformação linear simples&lt;/strong&gt;. Em Machine Learning (ML), &lt;code&gt;m&lt;/code&gt; e &lt;code&gt;b&lt;/code&gt; ganham nomes diferentes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;m&lt;/code&gt; → &lt;code&gt;weight&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;b&lt;/code&gt; → &lt;code&gt;bias&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Na prática, neurônios em redes mais complexas têm uma função de ativação que introduz curvas e permite aprender padrões não-lineares. Sem ela, combinar vários neurônios ainda resulta numa reta. Mas isso é assunto das fases seguintes — por agora trabalhamos com o neurônio mais simples possível.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h3&gt;
  
  
  5. Implementando o neurônio &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Um neurônio artificial, neste contexto, é &lt;strong&gt;essa equação aplicada a um problema real&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Para o nosso problema, a tradução fica assim:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mx&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;distância&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;weight&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;energia&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;bias&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ou seja, &lt;code&gt;x&lt;/code&gt; vira &lt;code&gt;energia&lt;/code&gt;, &lt;code&gt;y&lt;/code&gt; vira &lt;code&gt;distância&lt;/code&gt;, &lt;code&gt;m&lt;/code&gt; vira &lt;code&gt;weight&lt;/code&gt; e &lt;code&gt;b&lt;/code&gt; vira &lt;code&gt;bias&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;Neuron&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="n"&gt;weight&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;f64&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="n"&gt;bias&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;f64&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;impl&lt;/span&gt; &lt;span class="n"&gt;Neuron&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;predict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;f64&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;f64&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.weight&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.bias&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;neuron&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Neuron&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;weight&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;bias&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A função &lt;code&gt;predict&lt;/code&gt; é literalmente &lt;code&gt;y = mx + b&lt;/code&gt;, com &lt;code&gt;weight&lt;/code&gt; e &lt;code&gt;bias&lt;/code&gt; definidos como zero, pois nosso neurônio ainda não sabe nada.&lt;/p&gt;




&lt;h3&gt;
  
  
  6. Calculando o erro &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Agora que temos nosso neurônio com a função &lt;code&gt;predict&lt;/code&gt; implementada, além dos parâmetros &lt;code&gt;weight&lt;/code&gt; e &lt;code&gt;bias&lt;/code&gt;, precisamos medir o quão boa foi a nossa previsão.&lt;/p&gt;

&lt;p&gt;O erro é calculado comparando o &lt;strong&gt;valor previsto&lt;/strong&gt; pelo neurônio com o &lt;strong&gt;valor real&lt;/strong&gt; definido no dataset.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mx&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;
&lt;span class="n"&gt;distância&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;weight&lt;/span&gt; &lt;span class="err"&gt;×&lt;/span&gt; &lt;span class="n"&gt;energia&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;bias&lt;/span&gt;

&lt;span class="n"&gt;erro&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;previsão&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;valor_real&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;predicted&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;neuron&lt;/span&gt;&lt;span class="nf"&gt;.predict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;energy&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;predicted&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;actual&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Visualmente, o estado inicial é esse:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0ahy3my0wpmz4avz6dev.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0ahy3my0wpmz4avz6dev.png" alt="gráfico mostrando a previsão inicial do neurônio, os pontos reais do dataset e as linhas de erro entre eles" width="700" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Linha roxa&lt;/strong&gt; — previsão do neurônio, colada no zero&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bolinhas verdes&lt;/strong&gt; — os valores reais do dataset&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Linhas laranjas&lt;/strong&gt; — o tamanho do erro em cada ponto&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;O objetivo é ajustar &lt;code&gt;weight&lt;/code&gt; e &lt;code&gt;bias&lt;/code&gt; até a linha azul passar por cima das bolinhas e, quando as linhas laranjas sumirem, o neurônio aprendeu.&lt;/p&gt;




&lt;h3&gt;
  
  
  7. Desenvolvendo o training loop &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Agora que conseguimos calcular o erro, precisamos fazer o neurônio melhorar suas previsões.&lt;/p&gt;

&lt;p&gt;O training loop consiste em repetir o mesmo processo várias vezes. Cada passagem completa pelo dataset é chamada de uma &lt;code&gt;epoch&lt;/code&gt;. A cada &lt;code&gt;epoch&lt;/code&gt;, vamos ajustando &lt;code&gt;weight&lt;/code&gt; e &lt;code&gt;bias&lt;/code&gt; com o objetivo de aproximar a reta dos valores observados.&lt;/p&gt;

&lt;p&gt;Para este primeiro exemplo, vamos utilizar uma estratégia &lt;strong&gt;bastante simples e totalmente didática&lt;/strong&gt;, sem ainda entrar em gradient descent ou cálculo de derivadas:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Inicializamos weight e bias com valores (0, 0);&lt;/li&gt;
&lt;li&gt;Para cada par do dataset, por exemplo (10, 28), calculamos o erro da previsão;&lt;/li&gt;
&lt;li&gt;Se o erro for maior que 0, significa que estamos prevendo um valor maior do que o esperado, então reduzimos weight e bias em 0.01;&lt;/li&gt;
&lt;li&gt;Se o erro for menor que 0, significa que estamos prevendo um valor menor do que o esperado, então aumentamos weight e bias em 0.01;&lt;/li&gt;
&lt;li&gt;Repetimos esse processo durante 1000 epochs, tentando calibrar os valores de weight e bias.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;epoch&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="n"&gt;epochs&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;energy&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;actual&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;dataset&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;predicted&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="nf"&gt;.predict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;energy&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;predicted&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;actual&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.weight&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="mf"&gt;0.01&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.bias&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="mf"&gt;0.01&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.weight&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mf"&gt;0.01&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.bias&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mf"&gt;0.01&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Essa regra de ajuste foi escolhida porque é fácil de visualizar: quando o neurônio erra para cima, empurramos os parâmetros para baixo; quando erra para baixo, empurramos para cima. Ela melhora o modelo, mas &lt;strong&gt;ainda não é o procedimento mais adequado para treino&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Depois de 1000 epochs:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhibuynze0talsudcmd6b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhibuynze0talsudcmd6b.png" alt="Depois do treino" width="700" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A reta se ajustou. O neurônio aprendeu alguma coisa.&lt;/p&gt;




&lt;h3&gt;
  
  
  8. As limitações desse método &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;A reta se ajustou, mas não perfeitamente: ela acerta nos pontos do meio e erra mais nas pontas.&lt;/p&gt;

&lt;p&gt;O motivo é que esse algoritmo ajusta sempre pelo mesmo passo fixo (&lt;code&gt;0.01&lt;/code&gt;), sem considerar o &lt;strong&gt;tamanho do erro&lt;/strong&gt;, só o sinal. Além disso, ele não usa a inclinação de uma função de perda para decidir a direção e a intensidade ideais do ajuste, então em algum momento começa a oscilar, ultrapassa o valor certo, corrige demais pro outro lado e ultrapassa de novo. &lt;strong&gt;Mais epochs não resolve&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;O que resolve é o &lt;strong&gt;gradient descent&lt;/strong&gt;, outra forma de tentar reduzir o erro que veremos em um próximo post.&lt;/p&gt;




&lt;h3&gt;
  
  
  9. Conclusão &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Neste post saímos do zero e implementamos um neurônio funcional em Rust.&lt;/p&gt;

&lt;p&gt;O que foi aprendido:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Um neurônio artificial é &lt;code&gt;y = mx + b&lt;/code&gt; — a equação de uma reta&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;weight&lt;/code&gt; e &lt;code&gt;bias&lt;/code&gt; são os parâmetros e são ajustados pelo treino&lt;/li&gt;
&lt;li&gt;O dataset é o gabarito e o neurônio aprende olhando exemplos, sem ver a fórmula&lt;/li&gt;
&lt;li&gt;O erro mede o quanto o neurônio está errando em cada ponto&lt;/li&gt;
&lt;li&gt;O training loop usa o erro para ajustar os parâmetros a cada &lt;code&gt;epoch&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Na prática, o que construímos aqui foi um &lt;strong&gt;modelo linear simples treinado com uma regra manual de ajuste&lt;/strong&gt; e isso já é suficiente para entender a intuição central de previsão, erro e correção, mesmo antes de entrar em outros algoritmos.&lt;/p&gt;

&lt;p&gt;O que ainda não resolvemos é que o ajuste pelo sinal do erro é &lt;strong&gt;simples demais&lt;/strong&gt;, não considera o tamanho do erro com precisão e pode causar oscilação.&lt;/p&gt;

&lt;p&gt;No próximo post: &lt;strong&gt;gradient descent&lt;/strong&gt;, o algoritmo que visa melhorar isso e é uma forte base de todo o aprendizado de máquina moderno.&lt;/p&gt;




&lt;h3&gt;
  
  
  Referências
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/z4nder/rs-linear-neuron" rel="noopener noreferrer"&gt;Código-fonte do projeto&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=GkiITbgu0V0&amp;amp;t=477s" rel="noopener noreferrer"&gt;Neural Network from Scratch — vídeo que inspirou essa série&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Artificial_neuron" rel="noopener noreferrer"&gt;Artificial neuron — Wikipedia&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Se este post fizer sentido pra você, o próximo passo natural é implementar uma função de perda e depois partir para &lt;strong&gt;gradient descent&lt;/strong&gt;, que é onde o treino começa a ficar mais próximo do que se usa de verdade em Machine Learning.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>rust</category>
      <category>machinelearning</category>
      <category>programming</category>
    </item>
    <item>
      <title>Programar é uma arte</title>
      <dc:creator>Alexandre</dc:creator>
      <pubDate>Tue, 23 Sep 2025 11:59:06 +0000</pubDate>
      <link>https://dev.to/z4nder/programar-e-uma-arte-3gi9</link>
      <guid>https://dev.to/z4nder/programar-e-uma-arte-3gi9</guid>
      <description>&lt;p&gt;Assim como desenhar, &lt;strong&gt;programar é traduzir o mundo em outra linguagem&lt;/strong&gt;.&lt;br&gt;&lt;br&gt;
Bons programadores, como bons artistas, não enxergam melhor, mas sabem &lt;strong&gt;organizar, escolher e representar melhor&lt;/strong&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Índice
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;1. Introdução&lt;/li&gt;
&lt;li&gt;2. Fundamentos&lt;/li&gt;
&lt;li&gt;3. Fundamentos da arte&lt;/li&gt;
&lt;li&gt;
4. Fundamentos da programação

&lt;ul&gt;
&lt;li&gt;4.1. Lógica computacional&lt;/li&gt;
&lt;li&gt;4.2. Estruturas de dados e algoritmos&lt;/li&gt;
&lt;li&gt;4.3. Ferramental (Tooling)&lt;/li&gt;
&lt;li&gt;4.4. Debugging e engenharia reversa&lt;/li&gt;
&lt;li&gt;4.5. Abstração&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;6. Conclusão&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  1. Introdução &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;No início dos meus estudos em programação, sempre caminhei em paralelo com o estudo de desenho. Durante essa jornada, não pude deixar de traçar paralelos entre as duas áreas. O estudo do desenho sempre me pareceu ter um caminho claro: focar nos chamados &lt;strong&gt;fundamentos&lt;/strong&gt; e praticar. Já na programação, sempre busquei identificar esses fundamentos, mas a definição nunca foi tão evidente.&lt;br&gt;&lt;br&gt;
Neste texto, pretendo explorar o que considero serem os &lt;strong&gt;fundamentos da programação&lt;/strong&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  2. Fundamentos &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;O que me encanta na ideia de fundamentos é que eles são tópicos inesgotáveis. Você pode &lt;strong&gt;estudá-los por toda a vida&lt;/strong&gt;, e ainda assim haverá sempre mais a aprender. É como anatomia no desenho: você pode aprofundar infinitamente, desde o estudo dos ossos até a simplificação de formas para criar estilos exagerados ou minimalistas. Mas, para que o resultado seja intencional e convincente, precisa estar bem fundamentado.  &lt;/p&gt;

&lt;p&gt;Da mesma forma, um bom desenho ou um bom programa depende da aplicação equilibrada de vários fundamentos ao mesmo tempo. Dominar apenas um não garante um bom resultado final. Os fundamentos não são uma lista que se esgota, mas pontos de &lt;strong&gt;prática constante&lt;/strong&gt; — como um boxeador que treina o mesmo soco todos os dias até que se torne instintivo.  &lt;/p&gt;
&lt;h2&gt;
  
  
  3. Fundamentos da arte &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Como este é um artigo focado em &lt;strong&gt;programação&lt;/strong&gt;, muitos podem não ter tido contato com os &lt;strong&gt;fundamentos da arte&lt;/strong&gt;. Então farei uma breve explicação para seguirmos:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Linhas:&lt;/strong&gt; o elemento mais básico para definir contorno, forma e dar sensação de movimento.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Formas:&lt;/strong&gt; blocos de construção de qualquer objeto, representados por figuras geométricas básicas como círculos, quadrados e triângulos. Simplificar a realidade em formas ajuda a construir o desenho de maneira mais precisa.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Perspectiva:&lt;/strong&gt; permite criar a ilusão de profundidade e tridimensionalidade em uma superfície plana.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Anatomia:&lt;/strong&gt; essencial para desenhar pessoas e animais de maneira realista e proporcional. É o estudo da estrutura corporal, músculos e ossos.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Composição:&lt;/strong&gt; refere-se à organização visual dos elementos dentro do espaço. Envolve a disposição, o equilíbrio e a distribuição de objetos, cores e linhas para criar uma obra harmoniosa.
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;
  
  
  4. Fundamentos da programação &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;
&lt;h2&gt;
  
  
  4.1. Lógica computacional&lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Capacidade de &lt;strong&gt;entender uma necessidade&lt;/strong&gt; e transformá-la em um programa. Observe como um desenhista enxerga formas simples (círculos, quadrados) em uma figura complexa.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://blenderartists.org/t/planes-of-the-head-from-andrew-loomis-method/1412699" rel="noopener noreferrer"&gt;LINK&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Floj8fmbhrwqe6va7pr72.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Floj8fmbhrwqe6va7pr72.png" alt="Etapas de um desenho" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;O programador deve ter a habilidade de enxergar processos complexos e representa-los de forma simplificada. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Exemplo:&lt;/strong&gt; imagine um programador conversando com um cliente sobre um novo projeto. O cliente descreve um fluxo de contratação totalmente manual, que envolve diversos setores, diferentes níveis de permissão, etapas de aprovação, envio de e-mails e muitos outros detalhes.&lt;br&gt;&lt;br&gt;
O papel do programador é &lt;strong&gt;extrair, simplificar e organizar esses fluxos&lt;/strong&gt;, transformando a descrição em um modelo compreensível. Só assim será possível apresentar ao cliente &lt;strong&gt;quais funcionalidades serão desenvolvidas&lt;/strong&gt; e &lt;strong&gt;como elas vão funcionar&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft0b8mc7mjbx2r53uxfj7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft0b8mc7mjbx2r53uxfj7.png" alt="Diagrama do projeto" width="800" height="280"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  4.2. Estruturas de dados e algoritmos &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;São formas de organizar e processar informações. Assim como um artista usa a &lt;strong&gt;composição&lt;/strong&gt; para distribuir elementos em uma cena, o programador utiliza estruturas para dar ordem e eficiência aos dados.&lt;/p&gt;

&lt;p&gt;Observe essas 2 artes&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://www.artstation.com/artwork/nEYBNe" rel="noopener noreferrer"&gt;https://www.artstation.com/artwork/nEYBNe&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.artstation.com/artwork/OmomKg" rel="noopener noreferrer"&gt;https://www.artstation.com/artwork/OmomKg&lt;/a&gt;
&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsfava7a1zzoxvlpcwfto.png" alt="Comparando 2 artes" width="800" height="340"&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Na primeira arte, não há técnicas de composição evidentes; já na segunda, o olhar do observador é conduzido intencionalmente pelos elementos, seguindo o caminho que o artista planejou.&lt;/p&gt;

&lt;p&gt;Da mesma forma, um programador deve saber &lt;strong&gt;escolher as estruturas de dados e algoritmos adequados&lt;/strong&gt; para guiar o fluxo das informações. Usar um &lt;strong&gt;array&lt;/strong&gt; para armazenar uma lista telefônica pode até funcionar, mas não será a decisão mais eficiente — nesse caso, uma estrutura de &lt;strong&gt;mapa&lt;/strong&gt; permitiria buscas muito mais rápidas e organizadas.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Lista telefônica usando Vec&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;lista_telefonica&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nd"&gt;vec!&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Peter"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"1111-1111"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Carlos"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"2222-2222"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Jordan"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"3333-3333"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="c1"&gt;// Procurar telefone do Jordan em um Vec (O(n))&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;telefone&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;None&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nome&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;numero&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;lista_telefonica&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;nome&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"Jordan"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;telefone&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;Some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;numero&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nd"&gt;println!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Telefone do Jordan (Vec): {:?}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;telefone&lt;/span&gt;&lt;span class="nf"&gt;.unwrap&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

&lt;span class="c1"&gt;// Lista telefônica usando HashMap&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;lista_telefonica_map&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;HashMap&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;lista_telefonica_map&lt;/span&gt;&lt;span class="nf"&gt;.insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Peter"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"1111-1111"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;lista_telefonica_map&lt;/span&gt;&lt;span class="nf"&gt;.insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Carlos"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"2222-2222"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;lista_telefonica_map&lt;/span&gt;&lt;span class="nf"&gt;.insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Jordan"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"3333-3333"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Procurar telefone do Jordan em HashMap (O(1))&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nf"&gt;Some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;numero&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;lista_telefonica_map&lt;/span&gt;&lt;span class="nf"&gt;.get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Jordan"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;println!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Telefone do Jordan (HashMap): {}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;numero&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Dominar essas estruturas — e os algoritmos que as acompanham — é essencial para compor sistemas complexos. Cada estrutura tem pontos fortes e fracos, e saber quando aplicar cada uma delas é o que diferencia soluções simples de ótimas composições.&lt;/p&gt;

&lt;h2&gt;
  
  
  4.3. Ferramental (Tooling) &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Assim como um artista que utiliza uma &lt;strong&gt;mesa digitalizadora&lt;/strong&gt; consegue desenhar mais rápido, com maior precisão e explorar possibilidades criativas que seriam muito mais trabalhosas no papel, o programador também pode acelerar e ampliar sua capacidade ao dominar suas ferramentas.&lt;/p&gt;

&lt;p&gt;O uso de &lt;strong&gt;LLMs&lt;/strong&gt; para gerar código ou documentação, &lt;strong&gt;scripts de automação&lt;/strong&gt; para eliminar tarefas repetitivas, &lt;strong&gt;Docker&lt;/strong&gt; para garantir ambientes consistentes e até sistemas como o &lt;strong&gt;Nix&lt;/strong&gt; para reproduzir setups complexos traz não apenas mais velocidade, mas também &lt;strong&gt;conforto e segurança&lt;/strong&gt; no dia a dia de desenvolvimento.&lt;/p&gt;

&lt;p&gt;Aprender e dominar essas ferramentas é tão importante quanto aprender uma linguagem de programação: são elas que permitem transformar esforço bruto em eficiência, garantindo que o desenvolvedor trabalhe com mais fluidez e tenha liberdade para explorar soluções mais sofisticadas.&lt;/p&gt;

&lt;h2&gt;
  
  
  4.4. Debugging e engenharia reversa &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Um bom desenvolvedor deve ser capaz de &lt;strong&gt;“executar mentalmente” o código&lt;/strong&gt;, acompanhando cada fluxo de decisão (&lt;code&gt;if&lt;/code&gt;, &lt;code&gt;switch&lt;/code&gt;) e cada loop (&lt;code&gt;for&lt;/code&gt;, &lt;code&gt;while&lt;/code&gt;) como se estivesse rodando o programa na cabeça.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;calcular_frete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;valor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;f64&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;destino&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;f64&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;valor&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// Frete grátis para pedidos acima de 500&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;valor&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mf"&gt;500.0&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// Destino prioritário tem taxa fixa&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;destino&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"capital"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mf"&gt;20.0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// Valor padrão&lt;/span&gt;
    &lt;span class="mf"&gt;50.0&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Você não deve precisar perder tempo executando esse código com todas as suas possibilidades para debugar, enquanto escreve já deve ser capaz de executar as possibilidades de entrada e saída para a função. &lt;/p&gt;

&lt;p&gt;O verdadeiro desafio surge quando algo dá errado: muitas vezes o erro aparece apenas como uma mensagem no console ou um comportamento inesperado na tela do cliente, enquanto &lt;strong&gt;a causa real&lt;/strong&gt; está escondida em camadas mais profundas.&lt;/p&gt;

&lt;p&gt;Depurar significa seguir esse rastro, &lt;strong&gt;passo a passo&lt;/strong&gt;, de cima para baixo, até chegar à raiz do problema. É como um artista que olha para um desenho “estranho” e percebe que a falha não está na pintura final, mas em uma proporção incorreta do esboço inicial. Ter essa habilidade de engenharia reversa, de reconstruir o caminho do erro até sua origem, é o que transforma um desenvolvedor comum em um solucionador de problemas eficiente.&lt;/p&gt;

&lt;h2&gt;
  
  
  4.5. Abstração &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Abstração é o &lt;strong&gt;ato de simplificar&lt;/strong&gt;: olhar para um problema complexo e destacar apenas os pontos essenciais.&lt;br&gt;&lt;br&gt;
Um pintor não precisa desenhar cada fio de cabelo, &lt;strong&gt;apenas sugerir&lt;/strong&gt; volume e textura. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.artstation.com/artwork/kqq0d" rel="noopener noreferrer"&gt;Observe essa pintura&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fur4yz3eh9bxdzroskc13.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fur4yz3eh9bxdzroskc13.png" alt="Pintura compelta" width="800" height="380"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Note que o artista não precisou pintar cada detalhe da cena, alguns elementos da pintura são somente pinceladas; ele &lt;strong&gt;concentrou-se no ponto de interesse&lt;/strong&gt; e deixou de lado elementos desnecessários. Ainda assim conseguimos identificar claramente uma criatura em um pasto de animais com montanhas ao fundo. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F70i72xw8stbofq03bfec.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F70i72xw8stbofq03bfec.png" alt="Pintura particionada" width="783" height="643"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Em programação, as &lt;strong&gt;abstrações&lt;/strong&gt; existem para organizar o caos. Ao criar uma função como sendEmail, o que realmente importa é a intenção: “enviar um e-mail”. Se será por API, SMTP ou outro provedor é apenas um &lt;strong&gt;detalhe de implementação&lt;/strong&gt;, que deve ser abstraído para poder mudar sem impactar o restante do sistema. Esse isolamento torna o código mais limpo, reutilizável e fácil de manter.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusão &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Estudar fundamentos não significa que você dominará tudo, mas sim que terá a &lt;strong&gt;base sólida para evoluir&lt;/strong&gt;. Conhecer os fundamentos permite aplicá-los de forma consciente, adaptá-los e até quebrar regras quando necessário, da mesma forma que um artista usa formas circulares para transmitir suavidade, mas pode inverter a lógica para transmitir algo inesperado.  &lt;/p&gt;

&lt;p&gt;O essencial é entender que fundamentos não se esgotam: quanto mais você pratica, mais naturais se tornam, e mais liberdade você ganha para &lt;strong&gt;criar, inovar e resolver problemas&lt;/strong&gt; de maneira original.  &lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>beginners</category>
      <category>discuss</category>
    </item>
    <item>
      <title>Rust Threads safety: Uma comparação com C.</title>
      <dc:creator>Alexandre</dc:creator>
      <pubDate>Mon, 18 Nov 2024 22:54:10 +0000</pubDate>
      <link>https://dev.to/z4nder/rust-threads-safety-uma-comparacao-com-c-1a8h</link>
      <guid>https://dev.to/z4nder/rust-threads-safety-uma-comparacao-com-c-1a8h</guid>
      <description>&lt;p&gt;Nesta &lt;strong&gt;POC&lt;/strong&gt; (Proof of Concept), exploraremos como a linguagem &lt;strong&gt;Rust&lt;/strong&gt; trata as &lt;strong&gt;race conditions&lt;/strong&gt;, comparando-a com &lt;strong&gt;C&lt;/strong&gt;, uma linguagem amplamente usada, mas com menos garantias de segurança para concorrência.&lt;/p&gt;

&lt;h2&gt;
  
  
  Rust Threads safety: Uma Comparação com C
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://doc.rust-lang.org/nomicon/races.html" rel="noopener noreferrer"&gt;Threads Safety: Data Races de C ao Rust&lt;/a&gt;&lt;/strong&gt;  &lt;/p&gt;

&lt;h2&gt;
  
  
  Índice
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
1. Introdução
&lt;/li&gt;
&lt;li&gt;
2. Threads
&lt;/li&gt;
&lt;li&gt;
3. Implementação em C

&lt;ul&gt;
&lt;li&gt;
3.1. Código sem Proteção Contra Race Conditions
&lt;/li&gt;
&lt;li&gt;
3.2. Corrigindo com Mutex
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

4. Implementação em Rust

&lt;ul&gt;
&lt;li&gt;
4.1. Problema com Race Conditions
&lt;/li&gt;
&lt;li&gt;
4.2. Resolução com Mutex e Arc
&lt;/li&gt;
&lt;li&gt;
4.3. Mutex vs. RwLock
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

5. Conclusão
&lt;/li&gt;

&lt;li&gt;

6. Referências
&lt;/li&gt;

&lt;/ul&gt;




&lt;h3&gt;
  
  
  1. Introdução &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Em computação, &lt;strong&gt;threads&lt;/strong&gt; são usadas para dividir tarefas de software em subtarefas que podem ser executadas concorrentemente. Ao usar &lt;strong&gt;threads&lt;/strong&gt;, ganhamos tempo de processamento e aproveitamos melhor os recursos da máquina, mas essa concorrência traz desafios, como &lt;strong&gt;race conditions&lt;/strong&gt; que podem gerar inconsistências graves nos dados.&lt;/p&gt;




&lt;h3&gt;
  
  
  2. Threads &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Threads&lt;/strong&gt; são unidades de execução que permitem processar tarefas simultaneamente. Podemos pensar em threads como fluxos independentes de execução dentro de um programa, ilustrados na imagem abaixo:  &lt;/p&gt;

&lt;h1&gt;
  &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2uoyr3ps4icgof9t8xc0.png" width="800" height="914"&gt;
&lt;/h1&gt;

&lt;p&gt;Embora as threads tragam vantagens de desempenho, elas introduzem riscos, especialmente ao acessar recursos compartilhados.&lt;/p&gt;

&lt;p&gt;Além disso, threads podem ser usadas para implementar paralelismo, onde múltiplas tarefas são executadas simultaneamente em diferentes núcleos de CPU. Isso permite que o programa aproveite melhor o hardware disponível, acelerando a execução de tarefas independentes.&lt;/p&gt;




&lt;h3&gt;
  
  
  3. Implementação em C &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Vamos criar um sistema simples em &lt;strong&gt;C&lt;/strong&gt;:  &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Um saldo inicial de 1000.
&lt;/li&gt;
&lt;li&gt;Um conjunto de transações que podem ser créditos ou débitos.
&lt;/li&gt;
&lt;li&gt;Processamento paralelo dessas transações usando threads.&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  3.1. Código sem Proteção Contra Race Conditions &lt;a&gt;&lt;/a&gt;
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;saldo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 

&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;creditar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;valor&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;tmp_saldo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;saldo&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="n"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Delay simulado&lt;/span&gt;

    &lt;span class="n"&gt;saldo&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;tmp_saldo&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;valor&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;debitar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;valor&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;temp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;saldo&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="n"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Delay simulado&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;temp&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;valor&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;saldo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;temp&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;valor&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nf"&gt;processar_transacao&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;valor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;valor&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;creditar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;valor&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;debitar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;abs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;valor&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;transactions&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;150&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;150&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;num_transactions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;transactions&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;transactions&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

    &lt;span class="n"&gt;pthread_t&lt;/span&gt; &lt;span class="n"&gt;threads&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;num_transactions&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;num_transactions&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;pthread_create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;threads&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;processar_transacao&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;transactions&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt; &lt;span class="c1"&gt;// Cria uma thread para cada transação&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;num_transactions&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;pthread_join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;threads&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Aguarda todas as threads terminarem&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Saldo final da conta: %d&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;saldo&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ao optarmos por um ambiente com &lt;strong&gt;processamento multithreading&lt;/strong&gt; pode acontecer o que chamamos de &lt;strong&gt;race conditions&lt;/strong&gt;, no momento em que 2 threads acessam e modificam um mesmo valor temos uma condição de corrida. Esse problema acontece pois não é garantido uma sincronização do valor acessado em cada thread devido à concorrência entre as chamadas. &lt;/p&gt;

&lt;p&gt;Ao executar várias vezes esse código, o saldo final varia, pois threads acessam e alteram &lt;code&gt;saldo&lt;/code&gt; simultaneamente.&lt;/p&gt;

&lt;h1&gt;
  &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fts89527lobltsjkcv3cf.png" width="800" height="638"&gt;
&lt;/h1&gt;




&lt;h4&gt;
  
  
  3.2. Corrigindo com Mutex &lt;a&gt;&lt;/a&gt;
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;saldo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
&lt;span class="n"&gt;pthread_mutex_t&lt;/span&gt; &lt;span class="n"&gt;saldo_mutex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Mutex para proteger o saldo&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;creditar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;valor&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
    &lt;span class="n"&gt;pthread_mutex_lock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;saldo_mutex&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Bloqueia o mutex&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;tmp_saldo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;saldo&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="n"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Delay simulado&lt;/span&gt;

    &lt;span class="n"&gt;saldo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tmp_saldo&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;valor&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="n"&gt;pthread_mutex_unlock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;saldo_mutex&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Libera o mutex&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;debitar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;valor&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;pthread_mutex_lock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;saldo_mutex&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Bloqueia o mutex&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;tmp_saldo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;saldo&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="n"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Delay simulado&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tmp_saldo&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;valor&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;saldo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tmp_saldo&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;valor&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;pthread_mutex_unlock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;saldo_mutex&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;// Libera o mutex&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Mutex é um primitivo de sincronização que garante que apenas um thread tenha acesso a um recurso compartilhado por vez. O acrônimo &lt;strong&gt;mutex&lt;/strong&gt; vem do termo em inglês &lt;em&gt;mutual exclusion&lt;/em&gt;, que significa "exclusão mútua". &lt;/p&gt;

&lt;p&gt;Quando uma thread adquire um &lt;strong&gt;mutex&lt;/strong&gt;, qualquer outra thread que tente adquirir o mesmo &lt;strong&gt;mutex&lt;/strong&gt; é suspenso até que a primeira thread libere o &lt;strong&gt;mutex&lt;/strong&gt;. Isso evita que dois ou mais processos(threads) tenham acesso simultâneo ao recurso compartilhado. &lt;/p&gt;

&lt;h1&gt;
  &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffzmz96x1bzhu3id7l7ft.png" width="800" height="789"&gt;
&lt;/h1&gt;

&lt;h3&gt;
  
  
  4. Implementação em Rust &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Rust’s rich type system and ownership model guarantee memory-safety and thread-safety — enabling you to eliminate many classes of bugs at compile-time.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pensar em Rust como uma linguagem ausente de &lt;strong&gt;data race&lt;/strong&gt; não é produtivo, mas podemos entender como as &lt;strong&gt;structs&lt;/strong&gt; e seu compilador contribuem trazendo recursos ótimos para segurança de memória e thread. &lt;/p&gt;

&lt;p&gt;Rust trata &lt;strong&gt;race conditions&lt;/strong&gt; com garantias em tempo de compilação, utilizando recursos como &lt;strong&gt;ownership&lt;/strong&gt;, &lt;strong&gt;borrowing&lt;/strong&gt; e estruturas seguras para concorrência:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Arc&lt;/strong&gt;: Compartilhamento seguro de dados imutáveis.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mutex&lt;/strong&gt; e &lt;strong&gt;RwLock&lt;/strong&gt;: Controle de acesso para dados mutáveis.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  4.1. Problema com Race Conditions &lt;a&gt;&lt;/a&gt;
&lt;/h4&gt;

&lt;p&gt;Sem o uso das structs Arc e Mutex&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;saldo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// saldo mutável, mas sem proteção&lt;/span&gt;

    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;handle1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;thread&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;spawn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;move&lt;/span&gt; &lt;span class="p"&gt;||&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;saldo&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;// erro: `saldo` é movido para esta thread sem proteção&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;handle2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;thread&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;spawn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;move&lt;/span&gt; &lt;span class="p"&gt;||&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;saldo&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;// erro: `saldo` é movido para esta thread sem proteção&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="n"&gt;handle1&lt;/span&gt;&lt;span class="nf"&gt;.join&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.unwrap&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;handle2&lt;/span&gt;&lt;span class="nf"&gt;.join&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.unwrap&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Rust não permite o acesso direto a um dado &lt;strong&gt;mutável&lt;/strong&gt; (saldo) a partir de várias &lt;strong&gt;threads&lt;/strong&gt; sem proteção.&lt;br&gt;
O compilador vai gerar um erro porque saldo está sendo movido para várias threads (&lt;em&gt;handle1&lt;/em&gt; e &lt;em&gt;handle2&lt;/em&gt;) sem um mecanismo seguro.&lt;br&gt;
Mensagem de erro que será exibida é:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;error[E0382]: use of moved value: &lt;span class="sb"&gt;`&lt;/span&gt;saldo&lt;span class="sb"&gt;`&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  4.2. Resolução com Mutex e Arc &lt;a&gt;&lt;/a&gt;
&lt;/h4&gt;

&lt;p&gt;Usando &lt;code&gt;Mutex&lt;/code&gt; e &lt;code&gt;Arc&lt;/code&gt; conseguimos compilar e executar nosso código, com os problemas de &lt;strong&gt;race condition&lt;/strong&gt; tratados.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;ContaBancaria&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;saldo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;i32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;impl&lt;/span&gt; &lt;span class="n"&gt;ContaBancaria&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;creditar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;valor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;i32&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;tmp_saldo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.saldo&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nn"&gt;thread&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;time&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;Duration&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;from_secs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
        &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.saldo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tmp_saldo&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;valor&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;debitar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;valor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;i32&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;tmp_saldo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.saldo&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="nn"&gt;thread&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;time&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;Duration&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;from_secs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;tmp_saldo&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;valor&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.saldo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tmp_saldo&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;valor&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;consultar_saldo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;i32&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.saldo&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;conta&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Arc&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Mutex&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ContaBancaria&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;saldo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt; &lt;span class="p"&gt;}));&lt;/span&gt;  &lt;span class="c1"&gt;// Cria a conta com Arc&lt;/span&gt;

    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;handles&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nd"&gt;vec!&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;transactions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;150&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;150&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;transaction&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;transactions&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;conta&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Arc&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;clone&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;conta&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;handle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;thread&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;spawn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;move&lt;/span&gt; &lt;span class="p"&gt;||&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;random_sleep_time&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;rand&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;thread_rng&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.gen_range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="nn"&gt;thread&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;time&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;Duration&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;from_secs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;random_sleep_time&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;transaction&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;conta&lt;/span&gt;&lt;span class="nf"&gt;.lock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.unwrap&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.creditar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;transaction&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;conta&lt;/span&gt;&lt;span class="nf"&gt;.lock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.unwrap&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.debitar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;transaction&lt;/span&gt;&lt;span class="nf"&gt;.abs&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;

        &lt;span class="n"&gt;handles&lt;/span&gt;&lt;span class="nf"&gt;.push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;


    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;handle&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;handles&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;handle&lt;/span&gt;&lt;span class="nf"&gt;.join&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.unwrap&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// Espera todas as threads terminarem&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;saldo_final&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;conta&lt;/span&gt;&lt;span class="nf"&gt;.lock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.unwrap&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.consultar_saldo&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nd"&gt;println!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Saldo final da conta: {}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;saldo_final&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  4.3. Mutex vs. RwLock &lt;a&gt;&lt;/a&gt;
&lt;/h4&gt;

&lt;p&gt;Mutex e RwLock são usados para tratar &lt;strong&gt;race conditions&lt;/strong&gt;, cada um com vantagens específicas:&lt;/p&gt;

&lt;p&gt;Mutex: Garante acesso exclusivo de um recurso para uma thread, bloqueando o acesso das outras até seja liberado. É simples e eficaz, mas mesmo leituras bloqueiam o recurso, tornando-o &lt;strong&gt;menos eficiente em cenários com muitas leituras&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;RwLock: Permite múltiplas leituras simultâneas com .read() e restringe a escrita exclusiva com .write(). É &lt;strong&gt;Ideal para cenários com predominância de leituras&lt;/strong&gt;, pois melhora o desempenho ao permitir paralelismo nas operações de leitura.&lt;/p&gt;




&lt;h3&gt;
  
  
  5. Conclusão &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;A comparação entre C e Rust destaca abordagens diferentes para resolver &lt;strong&gt;race conditions&lt;/strong&gt;. Enquanto C exige atenção para evitar erros de condições de corrida, Rust reduz esses riscos em tempo de compilação, por meio de ferramentas como Mutex, RwLock e Arc além do modelo de ownership. Isso não apenas torna o código mais seguro, mas também &lt;strong&gt;reduz a carga mental do programador&lt;/strong&gt; evitando bugs silenciosos.&lt;/p&gt;

&lt;p&gt;Em resumo, Rust se posiciona como uma excelente escolha para o desenvolvimento de sistemas &lt;strong&gt;concorrentes&lt;/strong&gt;, oferecendo segurança e confiabilidade.&lt;/p&gt;




&lt;h3&gt;
  
  
  6. Referências &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Repo com os códigos: &lt;a href="https://github.com/z4nder/rust-data-races" rel="noopener noreferrer"&gt;https://github.com/z4nder/rust-data-races&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Race_condition" rel="noopener noreferrer"&gt;https://en.wikipedia.org/wiki/Race_condition&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.bughunt.com.br/o-que-sao-vulnerabilidades-race-condition/" rel="noopener noreferrer"&gt;https://blog.bughunt.com.br/o-que-sao-vulnerabilidades-race-condition/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://medium.com/cwi-software/spring-boot-race-condition-e-ambiente-multi-thread-263b21e0042e" rel="noopener noreferrer"&gt;https://medium.com/cwi-software/spring-boot-race-condition-e-ambiente-multi-thread-263b21e0042e&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://learn.microsoft.com/en-us/troubleshoot/developer/visualstudio/visual-basic/language-compilers/race-conditions-deadlocks" rel="noopener noreferrer"&gt;https://learn.microsoft.com/en-us/troubleshoot/developer/visualstudio/visual-basic/language-compilers/race-conditions-deadlocks&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.reddit.com/r/rust/comments/18faxjg/understanding_threadsafety_vs_race_conditions/?rdt=52263" rel="noopener noreferrer"&gt;https://www.reddit.com/r/rust/comments/18faxjg/understanding_threadsafety_vs_race_conditions/?rdt=52263&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://doc.rust-lang.org/nomicon/races.html" rel="noopener noreferrer"&gt;https://doc.rust-lang.org/nomicon/races.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://news.ycombinator.com/item?id=23599598" rel="noopener noreferrer"&gt;https://news.ycombinator.com/item?id=23599598&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>c</category>
      <category>rust</category>
      <category>safety</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Schemas em SQL: Indexes e B+ trees</title>
      <dc:creator>Alexandre</dc:creator>
      <pubDate>Thu, 19 Oct 2023 18:21:27 +0000</pubDate>
      <link>https://dev.to/z4nder/schemas-em-sql-indexes-e-b-trees-20ng</link>
      <guid>https://dev.to/z4nder/schemas-em-sql-indexes-e-b-trees-20ng</guid>
      <description>&lt;p&gt;Indexes e B+ trees qual será a relação dessa engraçada estrutura de dados com nossos queridos indexes do banco?&lt;/p&gt;

&lt;h2&gt;
  
  
  Conteúdo
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;1 Prólogo
&lt;/li&gt;
&lt;li&gt;2 O que são indexes
&lt;/li&gt;
&lt;li&gt;3 B Tree e B+ Tree
&lt;/li&gt;
&lt;li&gt;4 Vamos observar na prática
&lt;/li&gt;
&lt;li&gt;5 Conclusão
&lt;/li&gt;
&lt;li&gt;6 Referências
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  1 Prólogo &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;O que são &lt;strong&gt;indexes&lt;/strong&gt; e como eles são usados para &lt;strong&gt;optimizar buscas&lt;/strong&gt;? quantas vezes já não adicionamos indexes em colunas de tabelas com milhares de registros e magicamente as queries caíram de alguns segundos para milissegundos, nunca foi magica e sim &lt;strong&gt;Computer Science&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. O que são indexes &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Index são uma estrutura separada da estrutura dos registros tabela, sendo feita uma &lt;strong&gt;cópia de uma parte&lt;/strong&gt; dos seus dados, que servem como um ponteiro para acessar um registro específico.&lt;/p&gt;

&lt;p&gt;Quando pensamos em criar &lt;em&gt;index&lt;/em&gt; existe um conceito que podemos seguir &lt;strong&gt;"As many as you need, As few as you can get away with"&lt;/strong&gt;, em outras palavras, você deve criar índices suficientes para &lt;strong&gt;acelerar as consultas&lt;/strong&gt; e melhorar o desempenho, mas não deve criar muitos índices desnecessários, pois isso pode &lt;em&gt;aumentar o espaço de armazenamento&lt;/em&gt; e a sobrecarga inserções no banco de dados, já que sempre que um registro for inserido vão ser criados também os &lt;code&gt;indexes&lt;/code&gt; existentes.&lt;/p&gt;

&lt;p&gt;Então como sei quais index criar? Para criar seus indexes é preciso olhar para &lt;strong&gt;queries que pretende executar&lt;/strong&gt;, para montar um bom &lt;code&gt;schema&lt;/code&gt; olhamos para os dados que vamos armazenar, já para bons &lt;code&gt;indexes&lt;/code&gt; olhamos para as &lt;code&gt;queries&lt;/code&gt; estamos executando ou pretendemos executar. &lt;/p&gt;

&lt;h3&gt;
  
  
  3. B Tree e B+ Tree &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Como foi dito os indexes são partes dos seus dados armazenados em uma estrutura diferente, essa estrutura é a &lt;code&gt;B+Tree&lt;/code&gt;, antes de entendermos ela precisamos compreender a &lt;code&gt;B Tree&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;B Tree é uma estrutura não lineares diferentes de um &lt;code&gt;Array&lt;/code&gt;, que somente podemos ir para frente e para trás com as árvores podemos navegar para níveis e subníveis dentro dela.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbo4g68okyoe0elfrms1a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbo4g68okyoe0elfrms1a.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A &lt;code&gt;B Tree&lt;/code&gt; diferente a &lt;code&gt;Binary Tree&lt;/code&gt; permite que armazenemos mais de um valor por nó, como na imagem de exemplo onde o primeiro nó tem 2 valores &lt;code&gt;20&lt;/code&gt; e o &lt;code&gt;40&lt;/code&gt; permitindo que tenhamos um bloco de valores em cada nó que recebem o nome de página. &lt;/p&gt;

&lt;p&gt;B+tree é a estrutura de dados que está por trás das &lt;strong&gt;buscas optimizadas&lt;/strong&gt; que o banco faz, é uma estrutura derivada das &lt;code&gt;BTrees&lt;/code&gt;, mas com uma forma diferente de armazenar suas chaves de uma maneira que o processamento sequencial e aleatório de chaves fossem eficientes, sendo bastante usadas em &lt;code&gt;bancos de dados&lt;/code&gt; como MYSQL e &lt;code&gt;sistemas de arquivo&lt;/code&gt; como FTP. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fow409mzr5socc0ywnpiq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fow409mzr5socc0ywnpiq.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A principal diferença de estrutura das duas é que a &lt;code&gt;B+&lt;/code&gt; os dados são armazenados apenas nas folhas(Nós finais, que não tem filhos), e seus nós internos &lt;strong&gt;armazenam ponteiros&lt;/strong&gt; para os filhos e suas folhas são uma &lt;code&gt;linked list&lt;/code&gt; facilitando assim uma busca sequencial de valores se adequando bem melhor para o contexto de bancos de dados, já a &lt;code&gt;B Tree&lt;/code&gt; é mais versátil permitindo um uso em uma variedade maior de contextos.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Prática &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Vamos observar como uma query usa index para encontrar os dados e como seria essa mesma busca se não usássemos os index.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SELECT * FROM users;  
EXPLAIN SELECT * FROM users WHERE name='Virux';
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0ecmo4pq42mzl9kmcdv3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0ecmo4pq42mzl9kmcdv3.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Como o SQL fez para encontrar um &lt;code&gt;user&lt;/code&gt; baseado no nosso &lt;code&gt;where&lt;/code&gt; ? &lt;/p&gt;

&lt;p&gt;Sem um índice, o MySQL vai ler toda a tabela do início ao fim encontrando os valores desejados, conseguimos comprovar isso observando valor &lt;code&gt;all&lt;/code&gt; no campo &lt;code&gt;type&lt;/code&gt; que o &lt;code&gt;EXPLAIN&lt;/code&gt; nos retorna, ou seja, quanto maior a tabela mais lenta a busca, como &lt;code&gt;Virux&lt;/code&gt; é o registro 9 ele precisou ler 8 registros até encontrar o desejado.&lt;/p&gt;

&lt;p&gt;Executando isso o SQL vai criar um index para esse campo&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;INDEX&lt;/span&gt; &lt;span class="n"&gt;idx_name&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Agora se a coluna &lt;code&gt;name&lt;/code&gt; tiver um index executando a mesma busca será feita de uma forma mais optimizada, buscando na estrutura da &lt;code&gt;B+Tree&lt;/code&gt; que o mysql montou com os seus dados, conseguimos identificar isso com o valor &lt;code&gt;ref&lt;/code&gt; no campo &lt;code&gt;type&lt;/code&gt; que o &lt;code&gt;EXAPLAIN&lt;/code&gt; nos retorna.&lt;/p&gt;

&lt;p&gt;Podemos encontrar esse registro com somente &lt;strong&gt;3 etapas&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft2299zfnubhexm3fojj0.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft2299zfnubhexm3fojj0.gif" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Conclusão &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Com isso podemos concluir que buscar usando &lt;strong&gt;index são bem mais optimizadas&lt;/strong&gt;, pois são feitas em uma estrutura de dados separada da sua tabela chamada &lt;code&gt;B+Tree&lt;/code&gt;, mas precisamos criar nossos index com cuidado pensando nas queries que pretendemos executar, pois eles afetam diretamente a desempenho das inserções além de aumentar o espaço de armazenamento. &lt;/p&gt;

&lt;h3&gt;
  
  
  6. Referências &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/B%2B_tree" rel="noopener noreferrer"&gt;B+Tree Wiki&lt;/a&gt; &lt;br&gt;
&lt;a href="https://www.cs.usfca.edu/~galles/visualization/BTree.html" rel="noopener noreferrer"&gt;B+Tree Vizualize&lt;/a&gt; &lt;br&gt;
&lt;a href="https://dev.mysql.com/doc/refman/8.0/en/mysql-indexes.html" rel="noopener noreferrer"&gt;Doc do mysql sobre index&lt;/a&gt;&lt;/p&gt;

</description>
      <category>mysql</category>
      <category>database</category>
      <category>sql</category>
      <category>algorithms</category>
    </item>
    <item>
      <title>Garanta a Eficiência: Escolhendo entre tipos String no SQL</title>
      <dc:creator>Alexandre</dc:creator>
      <pubDate>Tue, 29 Aug 2023 12:27:27 +0000</pubDate>
      <link>https://dev.to/z4nder/garanta-a-eficiencia-escolhendo-entre-tipos-string-no-sql-115m</link>
      <guid>https://dev.to/z4nder/garanta-a-eficiencia-escolhendo-entre-tipos-string-no-sql-115m</guid>
      <description>&lt;p&gt;Garanta a eficiência, nova série fazendo mais sucesso que The Walking Dead, venha aprender como salvar seus strings no seu banco sql.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conteúdo
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;1 Prólogo
&lt;/li&gt;
&lt;li&gt;2 CHAR
&lt;/li&gt;
&lt;li&gt;3 VARCHAR
&lt;/li&gt;
&lt;li&gt;4 CHARSET e COLLATE
&lt;/li&gt;
&lt;li&gt;5 Conclusão
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  1. Prólogo &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Dando continuidade à nossa série, já abordamos os valores numéricos agora, chegou a hora de nos aprofundarmos nas strings. Neste artigo, exploraremos as diferenças entre os tipos &lt;code&gt;VARCHAR&lt;/code&gt; e &lt;code&gt;CHAR&lt;/code&gt;, além de fornecer uma compreensão detalhada sobre os conceitos de &lt;code&gt;CHARSET&lt;/code&gt; e &lt;code&gt;COLLATE&lt;/code&gt;, os quais você certamente já encontrou em seus bancos de dados, mas talvez ainda não tenha uma ideia clara de suas finalidades.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. CHAR &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;O tipo de dado CHAR no MySQL é usado para armazenar strings de comprimento fixo.&lt;/p&gt;

&lt;p&gt;Se o valor de uma string CHAR tiver um comprimento menor do que o comprimento especificado, os espaços em branco serão adicionados automaticamente ao final da string para preencher o espaço restante. Esses espaços em branco serão incluídos.&lt;/p&gt;

&lt;p&gt;O tipo de dado CHAR é usado principalmente quando você precisa armazenar strings de comprimento fixo ou quando há um requisito específico para o tamanho da string. As comparações e pesquisas em colunas CHAR são mais rápidas do que em colunas VARCHAR porque não há necessidade de levar em consideração o tamanho variável.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. VARCHAR &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;O tipo de dado VARCHAR armazena strings de comprimento variável, o que significa que o tamanho ocupado no armazenamento depende do comprimento real da string. Por exemplo, se você definir uma coluna VARCHAR(255) e inserir uma string de apenas 10 caracteres, ela ocupará apenas a quantidade de espaço necessária para armazenar esses 10 caracteres.&lt;/p&gt;

&lt;p&gt;O tipo de dado VARCHAR pode ser mais eficiente em termos de armazenamento em comparação com o tipo de dado CHAR se a maioria das strings armazenadas tiver comprimentos variáveis. Isso ocorre porque o espaço alocado para armazenar a string é proporcional ao comprimento real da string e não ao comprimento máximo especificado.&lt;/p&gt;

&lt;p&gt;O tipo de dado VARCHAR &lt;strong&gt;requer espaço adicional de armazenamento para registrar o comprimento real da string&lt;/strong&gt;. Esse espaço extra varia de 1 a 2 bytes, dependendo do tamanho máximo especificado para a coluna VARCHAR.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. CHARSET e COLLATE &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;strings&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;fixed100&lt;/span&gt; &lt;span class="nb"&gt;CHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="c1"&gt;-- 100 bytes "Aaron     ..."&lt;/span&gt;
    &lt;span class="n"&gt;var100&lt;/span&gt; &lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;-- 5 bytes + 1 Byte "Aaron"&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;SHOW&lt;/span&gt; &lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;strings&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="nv"&gt;`strings`&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nv"&gt;`fixed100`&lt;/span&gt; &lt;span class="nb"&gt;char&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;DEFAULT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nv"&gt;`var100`&lt;/span&gt; &lt;span class="nb"&gt;varchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;DEFAULT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;ENGINE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;InnoDB&lt;/span&gt; &lt;span class="k"&gt;DEFAULT&lt;/span&gt; &lt;span class="n"&gt;CHARSET&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;utf8mb4&lt;/span&gt; &lt;span class="k"&gt;COLLATE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;utf8mb4_0900_ai_ci&lt;/span&gt;

&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;information_schema&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CHARACTER_SETS&lt;/span&gt; &lt;span class="k"&gt;ORDER&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="k"&gt;CHARACTER_SET_NAME&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1p9o2e6xfvf30wzn8nnn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1p9o2e6xfvf30wzn8nnn.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  CHARSET (utf8mb4)
&lt;/h4&gt;

&lt;p&gt;O CHARSET &lt;strong&gt;&lt;code&gt;utf8mb4&lt;/code&gt;&lt;/strong&gt; é uma configuração no MySQL que define o conjunto de caracteres utilizado para armazenar dados em colunas de texto. Nesse caso, o &lt;strong&gt;&lt;code&gt;utf8mb4&lt;/code&gt;&lt;/strong&gt; refere-se a um conjunto de caracteres multibyte que suporta a codificação UTF-8.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;utf8&lt;/code&gt;&lt;/strong&gt;: Refere-se ao conjunto de caracteres UTF-8, que é um padrão universalmente aceito para representação de caracteres em várias línguas e scripts. O UTF-8 é capaz de representar uma ampla gama de caracteres e é amplamente utilizado em sistemas modernos.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;mb4&lt;/code&gt;&lt;/strong&gt;: É uma abreviação de "multibyte 4", indicando que o conjunto de caracteres suporta até 4 bytes por caractere. Isso permite a representação de caracteres que requerem mais de 2 bytes, como emojis e caracteres especiais de diferentes idiomas.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  COLLATE (utf8mb4_0900_ai_ci)
&lt;/h4&gt;

&lt;p&gt;A cláusula COLLATE é usada para definir a ordem de classificação de caracteres em operações de comparação e classificação de texto. No caso específico do COLLATE &lt;strong&gt;&lt;code&gt;utf8mb4_0900_ai_ci&lt;/code&gt;&lt;/strong&gt;, é uma sequência de configuração que define a ordem de classificação. Essas definições são as seguintes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;utf8mb4&lt;/code&gt;&lt;/strong&gt;: É um conjunto de caracteres que suporta a codificação UTF-8 de caracteres multibyte. O UTF-8 é um padrão universalmente aceito para representação de caracteres e suporta uma ampla gama de caracteres de diferentes idiomas.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;0900&lt;/code&gt;&lt;/strong&gt;: É um indicador da versão do algorítimo usado. Neste caso, &lt;strong&gt;&lt;code&gt;0900&lt;/code&gt;&lt;/strong&gt; refere-se à versão do Unicode Collation Algorithm (ou UCA). As versões mais recentes do MySQL podem introduzir atualizações e melhorias nos conjuntos de caracteres existentes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;ai&lt;/code&gt;&lt;/strong&gt;: É uma abreviação de "Accent Insensitive" (insensível a acentos). Isso significa que as comparações de caracteres são realizadas sem levar em consideração os acentos. Por exemplo, as letras "á" e "a" seriam consideradas iguais.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;ci&lt;/code&gt;&lt;/strong&gt;: É uma abreviação de "Case Insensitive" (insensível a maiúsculas e minúsculas). Isso significa que as comparações de caracteres são realizadas sem levar em consideração a diferença entre letras maiúsculas e minúsculas. Por exemplo, as letras "A" e "a" seriam consideradas iguais.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  5. Conclusão &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Neste artigo, exploramos a diferença entre os tipos de string &lt;code&gt;VARCHAR&lt;/code&gt; e &lt;code&gt;CHAR&lt;/code&gt; no MySQL. Aprendemos que o &lt;code&gt;CHAR&lt;/code&gt; é ideal para tamanhos fixos, enquanto o &lt;code&gt;VARCHAR&lt;/code&gt; é mais adequado para tamanhos variáveis. Além disso, compreendemos o papel do &lt;code&gt;CHARSET&lt;/code&gt; e &lt;code&gt;COLLATE&lt;/code&gt;, permitindo personalizar a ordenação de texto.&lt;/p&gt;

&lt;p&gt;Com esse conhecimento, podemos tomar decisões mais acertadas ao projetar nossas tabelas no MySQL, garantindo a eficiência e o desempenho ideais para nossas aplicações. A escolha inteligente dos tipos de string e configurações de charset/collate é crucial para um banco de dados otimizado e bem-sucedido.&lt;/p&gt;

</description>
      <category>sql</category>
      <category>mysql</category>
      <category>beginners</category>
      <category>database</category>
    </item>
    <item>
      <title>Garanta a Eficiência: Escolhendo entre tipos decimais no SQL</title>
      <dc:creator>Alexandre</dc:creator>
      <pubDate>Wed, 12 Jul 2023 00:30:56 +0000</pubDate>
      <link>https://dev.to/z4nder/garanta-a-eficiencia-escolhendo-entre-tipos-decimais-no-sql-17de</link>
      <guid>https://dev.to/z4nder/garanta-a-eficiencia-escolhendo-entre-tipos-decimais-no-sql-17de</guid>
      <description>&lt;p&gt;Decimais, existem tantos e qual devo escolher ? Saiba que essa decisão é de total importância para não perder dinheiro em seu software.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conteúdo
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Prólogo&lt;/li&gt;
&lt;li&gt;Tipos decimais SQL&lt;/li&gt;
&lt;li&gt;O que é essa precisão ?&lt;/li&gt;
&lt;li&gt;Então quando eu não ira querer precisão&lt;/li&gt;
&lt;li&gt;Vamos observar na prática&lt;/li&gt;
&lt;li&gt;Conclusão&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  1. Prólogo &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Sempre tive dúvidas sobre a razão pela qual existem tantos tipos de dados &lt;code&gt;decimais&lt;/code&gt; no SQL e quando é apropriado utilizá-los, especialmente ao lidar com valores monetários, onde a consistência dos cálculos e a precisão são fundamentais para &lt;strong&gt;evitar perdas financeiras&lt;/strong&gt;. Muitos desses tipos de dados são desconhecidos ou subutilizados no cotidiano de um desenvolvedor web. No entanto, estar ciente dos seus casos de uso diferenças é uma vantagem significativa para quando precisar usar você conseguir identificar.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Tipos decimais SQL&lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Existem diversos tipos de dados decimais disponíveis no SQL, cada um com seu próprio propósito e comportamento. Vamos explorar alguns dos tipos mais comuns:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;DECIMAL/NUMERIC&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;O tipo &lt;code&gt;DECIMAL&lt;/code&gt; possui um alias (apelido) chamado &lt;code&gt;NUMERIC&lt;/code&gt;, ou seja ambos têm o mesmo comportamento. Esse tipo é especialmente adequado para lidar com valores precisos, como dinheiro, onde é crucial manter a exatidão das informações.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;FLOAT&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;O tipo &lt;code&gt;FLOAT&lt;/code&gt; é recomendado para valores aproximados, como estatísticas, por serem eficientes em termos de espaço de armazenamento e desempenho, ocupando um total de 4 bytes de espaço de armazenamento.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;DOUBLE&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;O campo &lt;code&gt;DOUBLE&lt;/code&gt; também é apropriado para valores aproximados, mas oferece um range de valores maior em comparação ao &lt;code&gt;FLOAT&lt;/code&gt;. Para acomodar essa flexibilidade, ele requer 8 bytes de espaço de armazenamento. &lt;/p&gt;

&lt;h3&gt;
  
  
  3. O que é essa precisão ?&lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Essa precisão é você saber que se um cliente comprar 2 produtos que custam R$ 20,30 ele vai pagar R$ 20,60 e não R$ 20,59999931231232321. &lt;/p&gt;

&lt;h3&gt;
  
  
  4. Então quando eu não ira querer precisão ?&lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Embora o &lt;code&gt;float&lt;/code&gt; possa introduzir variações nos cálculos, há casos de uso em que eles são vantajosos na prática. Aqui estão dois exemplos:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Cálculos científicos e simulações: Em muitas áreas da ciência e da engenharia, os cálculos envolvem números que não exigem uma precisão extrema. Nesses casos, o uso de &lt;code&gt;float&lt;/code&gt; pode ser adequado, pois oferece uma representação aproximada dos valores com eficiência de espaço e desempenho. Por exemplo, em simulações físicas, como modelos de sistemas climáticos ou mecânicos, a precisão aproximada fornecida pelos números de ponto flutuante é suficiente e pode acelerar significativamente os cálculos.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Processamento gráfico: Em aplicações de computação gráfica, como jogos ou renderização de imagens, o uso de &lt;code&gt;float&lt;/code&gt; é comum para representar coordenadas 3D, cores e transformações. A natureza aproximada dos números de ponto flutuante não é perceptível para a maioria dos usuários, e a velocidade de processamento é fundamental nesses casos.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  5. Vamos observar na prática&lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Criaremos uma tabela para testes chamada decimals&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;decimals&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="nb"&gt;INT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;d1&lt;/span&gt; &lt;span class="nb"&gt;DECIMAL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="n"&gt;d2&lt;/span&gt; &lt;span class="nb"&gt;FLOAT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;-- 4 bytes&lt;/span&gt;
  &lt;span class="n"&gt;d3&lt;/span&gt; &lt;span class="nb"&gt;DOUBLE&lt;/span&gt; &lt;span class="c1"&gt;-- 8 bytes&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;decimals&lt;/span&gt;
&lt;span class="k"&gt;VALUES&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;40&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;40&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;40&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;00&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;00&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;00&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="k"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;d1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="k"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;d2&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="k"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;d3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;decimals&lt;/span&gt; &lt;span class="k"&gt;GROUP&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ao executar o SELECT vamos ter o seguinte resultado&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;sum(d1)&lt;/th&gt;
&lt;th&gt;sum(d2)&lt;/th&gt;
&lt;th&gt;sum(d3)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;20.40&lt;/td&gt;
&lt;td&gt;20.400001525878906&lt;/td&gt;
&lt;td&gt;20.400000000000006&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Nesse exemplo, criamos uma tabela chamada "decimals" com três colunas: "d1" do tipo DECIMAL(10, 2), "d2" do tipo FLOAT e "d3" do tipo DOUBLE. Em seguida, inserimos duas linhas de dados nessa tabela.&lt;/p&gt;

&lt;p&gt;Ao realizar a soma dos valores de cada coluna usando a cláusula GROUP BY, podemos observar as diferenças resultantes. A coluna "d1", que utiliza o tipo DECIMAL com precisão fixa de duas casas decimais, apresenta um resultado preciso de 20.40.&lt;/p&gt;

&lt;p&gt;No entanto, as colunas "d2" (FLOAT) e "d3" (DOUBLE) demonstram as variações típicas dos números de ponto flutuante. Embora os valores somados sejam teoricamente iguais a 20.40, devido à representação aproximada desses tipos, ocorrem pequenas variações nos resultados. Essas variações podem ocorrer devido a erros de arredondamento ou limitações na precisão dos bits usados para representar os números.&lt;/p&gt;

&lt;p&gt;Essas diferenças podem parecer insignificantes, mas em casos que exigem precisão exata, como manipulação de valores monetários, elas podem levar a perdas ou erros nos cálculos financeiros.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. Conclusão &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Exploramos os diferentes tipos de dados decimais no &lt;code&gt;SQL&lt;/code&gt; e destacamos a importância de escolher o tipo correto com base nas necessidades específicas. Ao lidar com valores monetários e cálculos que exigem precisão absoluta, é recomendado utilizar tipos decimais de precisão fixa, como &lt;code&gt;DECIMAL&lt;/code&gt; ou &lt;code&gt;NUMERIC&lt;/code&gt;. Esses tipos garantem resultados consistentes e evitam perdas de valor.&lt;/p&gt;

&lt;p&gt;Embora os números de ponto flutuante (float) possam ser vantajosos em determinados cenários, e*&lt;em&gt;les podem introduzir variações nos cálculos&lt;/em&gt;* devido à natureza aproximada da representação. É essencial avaliar o contexto e a precisão necessária para evitar problemas de arredondamento.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Garanta a Eficiência: Escolhendo Sabiamente o Tipo de Dado Integer no MySQL</title>
      <dc:creator>Alexandre</dc:creator>
      <pubDate>Tue, 04 Jul 2023 18:16:05 +0000</pubDate>
      <link>https://dev.to/z4nder/garanta-a-eficiencia-escolhendo-sabiamente-o-tipo-de-dado-integer-no-mysql-16pc</link>
      <guid>https://dev.to/z4nder/garanta-a-eficiencia-escolhendo-sabiamente-o-tipo-de-dado-integer-no-mysql-16pc</guid>
      <description>&lt;p&gt;Já pensou no motivo de um banco de dados ter tantos tipos de valores inteiros? SMALLINT? BIGINT? É de comer?&lt;/p&gt;

&lt;h2&gt;
  
  
  Conteúdo
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Prólogo&lt;/li&gt;
&lt;li&gt;Escolhendo tipos em modelos de dados&lt;/li&gt;
&lt;li&gt;Tomando uma decisão consciente&lt;/li&gt;
&lt;li&gt;O que posso fazer um Byte ?&lt;/li&gt;
&lt;li&gt;Agora vamos colocar em prática&lt;/li&gt;
&lt;li&gt;Considerações finais&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  1. Prólogo&lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Nessa vida de desenvolvedor de software, aprendi a valorizar os fundamentos das tecnologias com as quais trabalho. Neste artigo, vamos explorar todos os tipos &lt;strong&gt;INTEGER&lt;/strong&gt; existentes, quais suas características e como podemos usar isso para tomar decisões mais assertivas ao modelar um esquema com &lt;strong&gt;MySQL&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Escolhendo tipos em modelos de dados&lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Um princípio fundamental para modelar dados é avaliar se os tipos escolhidos são os melhores para os valores que serão recebidos. Nesse artigo vamos tentar entender quais tipos de inteiros existem e quais suas diferenças para podermos tomar essa melhor decisão no momento de criar nossas tabelas.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Tomando uma decisão consciente&lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Para conseguirmos tomar a decisão mais consciente precisamos saber quais o &lt;strong&gt;tipos de inteiro&lt;/strong&gt; existentes e qual o espaço ocupado em &lt;strong&gt;Bytes&lt;/strong&gt; por cada tipo, pois independente de você inserir o número inteiro 1 em um registro ele ocupa um espaço diferente de acordo com o tipo de dado do schema.&lt;/p&gt;

&lt;p&gt;Por exemplo, o tipo &lt;strong&gt;TINYINT&lt;/strong&gt; ocupa &lt;code&gt;1 byte&lt;/code&gt;, enquanto o tipo &lt;strong&gt;BIGINT&lt;/strong&gt; ocupa &lt;code&gt;8 bytes&lt;/code&gt;. Portanto, mesmo que você insira o número inteiro 1 em um registro, ele ocupará um espaço diferente dependendo do tipo de dado especificado no esquema (schema).&lt;/p&gt;

&lt;p&gt;Podemos considerar que cada tipo de inteiros nos permitem armazenar um certo range de valores e cada range reserva uma quantidade de Bytes.&lt;/p&gt;

&lt;p&gt;Vamos observar todos os tipos e seus custos de Bytes:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Storage (Bytes)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;TINYINT&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SMALLINT&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MEDIUMINT&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;INT&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  4. O que posso fazer um Byte ?&lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F749bb223ohee865q06k9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F749bb223ohee865q06k9.png" alt="Ilustração de uma linha com 8 bits"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Com 1 Byte podemos usar 8 Bits, ou seja com o &lt;strong&gt;TINYINT&lt;/strong&gt; podemos armazenar números no seguinte range:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="mi"&gt;00000000&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="mi"&gt;11111111&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;255&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;E caso precisarmos ter um sinal ? Nesse caso vamos precisas separar um bit para isso reduzindo nosso range assim:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="mi"&gt;1111111&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;128&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;negative&lt;/span&gt; &lt;span class="nx"&gt;bit&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="mi"&gt;1111111&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;127&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;positive&lt;/span&gt; &lt;span class="nx"&gt;bit&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Com isso temos a seguinte tabela:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Storage (Bytes)&lt;/th&gt;
&lt;th&gt;Min Signed&lt;/th&gt;
&lt;th&gt;Max Signed&lt;/th&gt;
&lt;th&gt;Min Unsigned&lt;/th&gt;
&lt;th&gt;Max Unsigned&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;TINYINT&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;-128&lt;/td&gt;
&lt;td&gt;127&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;255&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SMALLINT&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;-32768&lt;/td&gt;
&lt;td&gt;32767&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;65535&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MEDIUMINT&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;-8388608&lt;/td&gt;
&lt;td&gt;8388607&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;16777215&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;INT&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;-2147483648&lt;/td&gt;
&lt;td&gt;2147483647&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;4294967295&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;BIGINT&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;-2^63&lt;/td&gt;
&lt;td&gt;2^63-1&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;2^64-1&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  5. Agora vamos colocar em prática&lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="nv"&gt;`books`&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nv"&gt;`id`&lt;/span&gt; &lt;span class="nb"&gt;bigint&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt; &lt;span class="n"&gt;AUTO_INCREMENT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nv"&gt;`title`&lt;/span&gt; &lt;span class="nb"&gt;varchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nv"&gt;`num_pages`&lt;/span&gt; &lt;span class="nb"&gt;SMALLINT&lt;/span&gt; &lt;span class="nb"&gt;UNSIGNED&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
     &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nesse trecho de SQL, tomamos a decisão de escolher o tipo de inteiro mais adequado com base no contexto do nosso caso de uso. Ao analisar a coluna &lt;code&gt;num_pages&lt;/code&gt;, que representa o total de páginas de um livro, optamos por utilizar o tipo &lt;strong&gt;SMALLINT&lt;/strong&gt;. Essa escolha foi feita levando em consideração os seguintes fatores:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Valor máximo adequado:&lt;/strong&gt; O tipo &lt;strong&gt;TINYINT&lt;/strong&gt; possui um valor &lt;code&gt;máximo de 255&lt;/code&gt;, o qual poderia ser facilmente ultrapassado por livros com um número significativo de páginas. No entanto, o tipo &lt;strong&gt;SMALLINT&lt;/strong&gt; oferece um tamanho maior, permitindo um valor máximo de 65535. Essa faixa é mais adequada para a representação do número de páginas de um livro na vida real a não ser que você esteja lendo Game of Thrones, ai já seria preciso de um BIGINIT.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Modificador UNSIGNED:&lt;/strong&gt; Utilizamos o modificador &lt;code&gt;UNSIGNED&lt;/code&gt; para indicar que não há necessidade de armazenar valores negativos para o número de páginas de um livro. Isso nos permite aproveitar um limite positivo maior dentro do mesmo tipo de dado, já que não precisamos reservar espaço para o sinal.&lt;/p&gt;

&lt;p&gt;Portanto, ao escolher o tipo &lt;code&gt;SMALLINT UNSIGNED&lt;/code&gt; para a coluna &lt;code&gt;num_pages&lt;/code&gt;, levamos em consideração o valor máximo adequado, a economia de espaço e a exclusão da possibilidade de valores negativos, garantindo uma representação eficiente e precisa do número de páginas dos livros em nosso sistema.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Considerações finais&lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Após compreendermos as diferenças entre os tipos de inteiro, percebi o quanto é importante escolher o tipo de dado adequado para cada situação. Refletindo sobre minha própria experiência, lembro-me das vezes em que utilizei o tipo &lt;strong&gt;INTEGER&lt;/strong&gt; desnecessariamente. Após aprofundar-me nesse assunto e compartilhar essas informações, acredito que não vou mais cometer esse erro. Espero que este artigo tenha sido esclarecedor para vocês também, auxiliando na escolha consciente do tipo de inteiro mais adequado para cada contexto.&lt;/p&gt;




&lt;p&gt;&lt;a href="https://discord.gg/JspQr3GPve" rel="noopener noreferrer"&gt;Venha fazer parte&lt;/a&gt; de um ambiente de aprendizado.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb8burs8kanqnoiag1ywf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb8burs8kanqnoiag1ywf.png" alt="Banner da Hive Community"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
