# Come la traduzione automatica neurale funziona effettivamente: Guida di uno sviluppatore

<datetime class="hidden">2025-11-09T14:30</datetime>

<!--category-- Neural Machine Translation, Machine Learning, AI, EasyNMT, Deep Learning, AI-Article -->
## Introduzione

Se hai seguito questo blog, sai che sono un po' ossessionato dalla traduzione automatica.[Ho scritto di](/blog/autotranslatingmarkdownfiles), [utilizzando EasyNMT](/blog/backgroundtranslationspt1)servizi di traduzione di background edilizio[, e anche](/blog/mostlylucid-nmt-complete-guide)migliorare EasyNMT**Ma ho capito che non l'ho mai spiegato.

> come

la traduzione automatica neurale funziona sotto il cofano.

NOTA: Questo fa parte dei miei esperimenti con AI / un modo per spendere $1000 Codice Calude crediti Web.

- Ho dato a questo un sacco di documenti, la mia comprensione, le domande che ho dovuto generare questo articolo.
- E' divertente e riempie un vuoto che non ho visto riempito da nessun'altra parte.
- Quindi risolviamola!
- Questo post vi porterà da "traduzione è magia" a "traduzione è matematica intelligente" spiegando i concetti chiave dietro la traduzione automatica neurale in inglese semplice (con un sacco di diagrammi e qualche codice C# per renderlo concreto).
- Entro la fine di questo post, capirete:

Che cosa sono le reti neurali artificiali e come imparano

[TOC]

## Come le parole diventano numeri (imbottiture)

Che cosa significa "attenzione" nell'IA (spoiler: non si tratta di prestare attenzione)

```mermaid
graph LR
    A[Source Sentence] --> B[Convert to Numbers]
    B --> C[Neural Network Processing]
    C --> D[Convert to Words]
    D --> E[Translated Sentence]

```

Come funziona l'architettura encoder-decoder

## Perché i trasformatori hanno conquistato il mondo

Non preoccuparti se non sei un matematico, lo terro' il piu' pratico e visivo possibile.

### Immergiamoci!

L'idea principale: Traduzione come numero Crunching

1. Ecco il primo concetto di piegamento mentale: la traduzione automatica neurale tratta la traduzione come un processo puramente matematico.
2. Si alimenta in una frase, il sistema lo converte in numeri, esegue milioni di operazioni matematiche, e salta fuori una traduzione.
3. Ma aspetta - come si convertono le parole in numeri?
4. E come fa la matematica a "capire" il linguaggio?

Iniziamo con i mattoni.

```mermaid
graph LR
    I1[Input 1] -->|weight: 0.8| N[Neuron]
    I2[Input 2] -->|weight: -0.3| N
    I3[Input 3] -->|weight: 0.5| N
    N --> O[Output]

    style N stroke-width:4px
```

Reti neurali artificiali: La Fondazione

```csharp
public class Neuron
{
    private double[] weights;
    private double bias;

    public double Activate(double[] inputs)
    {
        // Step 1: Multiply each input by its weight and sum them
        double sum = bias;
        for (int i = 0; i < inputs.Length; i++)
        {
            sum += inputs[i] * weights[i];
        }

        // Step 2: Apply activation function (tanh keeps values between -1 and 1)
        return Math.Tanh(sum);
    }
}
```

Prima di capire la traduzione automatica neurale, abbiamo bisogno di capire le reti neurali artificiali.`Math.Tanh`Nonostante il nome elegante, in realta' sono molto semplici al loro interno.

### Che cos'è un neurone artificiale?

Un neurone artificiale è una funzione matematica che:

```mermaid
graph LR
    subgraph Input Layer
        I1[Input 1]
        I2[Input 2]
        I3[Input 3]
    end

    subgraph Hidden Layer 1
        H1[Neuron 1]
        H2[Neuron 2]
        H3[Neuron 3]
        H4[Neuron 4]
    end

    subgraph Hidden Layer 2
        H5[Neuron 5]
        H6[Neuron 6]
        H7[Neuron 7]
    end

    subgraph Output Layer
        O1[Output 1]
        O2[Output 2]
    end

    I1 --> H1 & H2 & H3 & H4
    I2 --> H1 & H2 & H3 & H4
    I3 --> H1 & H2 & H3 & H4

    H1 --> H5 & H6 & H7
    H2 --> H5 & H6 & H7
    H3 --> H5 & H6 & H7
    H4 --> H5 & H6 & H7

    H5 --> O1 & O2
    H6 --> O1 & O2
    H7 --> O1 & O2
```

Richiede più ingressi

- Moltiplichi ogni input di un peso (quanto è importante questo input?)
- Li aggiunge tutti.
- Applica una "funzione di attivazione" per produrre un output

### Ecco una rappresentazione visiva:

Facciamolo concreto con un codice C#:

```mermaid
graph TD
    A[Start with Random Weights] --> B[Feed in Training Example]
    B --> C[Network Makes Prediction]
    C --> D{Is Prediction Correct?}
    D -->|No| E[Calculate Error]
    E --> F[Adjust Weights Slightly]
    F --> B
    D -->|Yes| G[Try Next Example]
    G --> B

    style E stroke-width:2px
    style F stroke-width:2px
```

La funzione di attivazione (in questo caso**) è ciò che rende interessanti le reti neurali.**Introduce la non linearità, permettendo alla rete di apprendere modelli complessi.

Senza di esso, non importa quanti neuroni avete impilato insieme, avreste solo una funzione lineare elegante.

```csharp
public class SimpleNeuralNetwork
{
    private double learningRate = 0.01;
    private Neuron[] neurons;

    public void Train(TrainingExample[] examples, int epochs)
    {
        for (int epoch = 0; epoch < epochs; epoch++)
        {
            foreach (var example in examples)
            {
                // Forward pass: make a prediction
                double prediction = Predict(example.Input);

                // Calculate error
                double error = example.ExpectedOutput - prediction;

                // Backward pass: adjust weights
                // (simplified - real networks use backpropagation)
                AdjustWeights(error * learningRate);
            }
        }
    }
}
```

Da neuroni a reti**La magia accade quando si collegano migliaia o milioni di questi neuroni insieme in strati:**Ogni livello "raffina" la rappresentazione dell'input, estraendo modelli sempre più astratti.

## In traduzione:

I livelli iniziali potrebbero rilevare "questo è un verbo" o "questa parola è al passato"

### Gli strati medi potrebbero rilevare "questa è una domanda" o "questo è circa il tempo"

I livelli successivi combinano questi in "tradurre questo come una domanda educata sul tempo di domani"

```csharp
// Don't do this!
var wordToNumber = new Dictionary<string, int>
{
    {"cat", 1},
    {"dog", 2},
    {"king", 3},
    {"queen", 4},
    {"man", 5},
    {"woman", 6}
};
```

Come le reti imparano: il processo di formazione

### Ecco la parte intelligente: non selezioniamo manualmente tutti quei pesi.

La rete li impara dagli esempi!**Questo processo si chiama**discesa gradiente

```csharp
public class WordEmbedding
{
    // Each word is represented by a vector of floats
    private Dictionary<string, float[]> embeddings;

    public float[] GetEmbedding(string word)
    {
        return embeddings[word]; // e.g., [0.2, -0.5, 0.8, 0.1, ...]
    }

    // Calculate similarity between two words
    public double Similarity(string word1, string word2)
    {
        var vec1 = GetEmbedding(word1);
        var vec2 = GetEmbedding(word2);

        // Cosine similarity: how "aligned" are the vectors?
        return CosineSimilarity(vec1, vec2);
    }

    private double CosineSimilarity(float[] a, float[] b)
    {
        double dot = 0, magA = 0, magB = 0;
        for (int i = 0; i < a.Length; i++)
        {
            dot += a[i] * b[i];
            magA += a[i] * a[i];
            magB += b[i] * b[i];
        }
        return dot / (Math.Sqrt(magA) * Math.Sqrt(magB));
    }
}
```



```mermaid
graph TD
    subgraph "2D Projection of 300D Space"
        King[King<br/>0.8, 0.6]
        Queen[Queen<br/>0.75, 0.55]
        Man[Man<br/>0.3, 0.2]
        Woman[Woman<br/>0.25, 0.15]
        Dog[Dog<br/>-0.6, 0.4]
        Cat[Cat<br/>-0.65, 0.38]
    end

    King -.similar.-> Queen
    Man -.similar.-> Woman
    Dog -.similar.-> Cat
    King -.same vector.-> Man
    Queen -.same vector.-> Woman
```

Per ogni risposta sbagliata, la rete capisce "quali pesi sono stati più responsabili di questo errore?" e li modifica un po '.`king - man + woman ≈ queen`

```csharp
public float[] AnalogicalReasoning(string a, string b, string c)
{
    // king - man + woman = ?
    var vecA = GetEmbedding(a); // king
    var vecB = GetEmbedding(b); // man
    var vecC = GetEmbedding(c); // woman

    var result = new float[vecA.Length];
    for (int i = 0; i < vecA.Length; i++)
    {
        result[i] = vecA[i] - vecB[i] + vecC[i];
    }

    // Find the word closest to this vector
    return FindClosestWord(result); // Should return "queen"
}
```

### Dopo aver visto milioni di esempi, i pesi si stabiliscono in valori che funzionano bene.

Ecco una versione semplificata in C#:

```mermaid
graph LR
    A["The cat sat on the mat"] --> B[Train Neural Network]
    B --> C["cat → [0.1, 0.5, -0.3, ...]"]
    B --> D["sat → [0.2, -0.1, 0.4, ...]"]
    B --> E["mat → [0.15, 0.45, -0.25, ...]"]

```

Le reti neurali reali usano un algoritmo più sofisticato chiamato

## retropropagazione

che calcola in modo efficiente come regolare i pesi in tutta la rete, ma il principio è lo stesso: imparare dagli errori.

```mermaid
graph TD
    subgraph English
        E1[The]
        E2[cat]
        E3[sat]
        E4[on]
        E5[the]
        E6[mat]
    end

    subgraph French
        F1[Le]
        F2[chat]
        F3[s'est assis]
        F4[sur]
        F5[le]
        F6[tapis]
    end

    E2 -. focus 90% .-> F2
    E3 -. focus 70% .-> F3
    E4 -. focus 80% .-> F4
    E6 -. focus 85% .-> F6
    E1 -. focus 30% .-> F1
```

**Abbinamenti di parole: Trasformare il linguaggio in matematica**Ora abbiamo affrontato la nostra prima grande sfida: come inserire le parole in una rete neurale?

### Dobbiamo convertire il testo in numeri.

Il problema con la codifica One-Hot

```csharp
public class AttentionMechanism
{
    // Calculate attention weights for each source word
    public double[] CalculateAttention(
        float[] currentTargetState,     // Where we are in translation
        float[][] sourceWordStates)     // All source words
    {
        int sourceLength = sourceWordStates.Length;
        double[] scores = new double[sourceLength];

        // Step 1: Calculate relevance scores
        for (int i = 0; i < sourceLength; i++)
        {
            scores[i] = DotProduct(currentTargetState, sourceWordStates[i]);
        }

        // Step 2: Convert to probabilities (softmax)
        return Softmax(scores);
    }

    public float[] ApplyAttention(
        double[] attentionWeights,
        float[][] sourceWordStates)
    {
        // Create weighted average of source words
        int dim = sourceWordStates[0].Length;
        float[] result = new float[dim];

        for (int i = 0; i < sourceWordStates.Length; i++)
        {
            for (int j = 0; j < dim; j++)
            {
                result[j] += (float)(attentionWeights[i] * sourceWordStates[i][j]);
            }
        }

        return result;
    }

    private double[] Softmax(double[] scores)
    {
        double[] result = new double[scores.Length];
        double sum = 0;

        for (int i = 0; i < scores.Length; i++)
        {
            result[i] = Math.Exp(scores[i]);
            sum += result[i];
        }

        for (int i = 0; i < scores.Length; i++)
        {
            result[i] /= sum;
        }

        return result;
    }

    private double DotProduct(float[] a, float[] b)
    {
        double sum = 0;
        for (int i = 0; i < a.Length; i++)
        {
            sum += a[i] * b[i];
        }
        return sum;
    }
}
```

L'approccio ingenuo è "una codifica hot" - assegna ad ogni parola un numero unico:

1. Ma questo ha un problema enorme: i numeri sono arbitrari.
2. La rete non può dire che "gatto" e "cane" sono più simili di "gatto" e "regina."
3. I numeri 1 e 2 non significano niente.
4. La soluzione: Inserimento di parole

### Invece, rappresentiamo ogni parola come un

vettore

```mermaid
graph TD
    subgraph "English (Source)"
        E1[The]
        E2[agreement]
        E3[on]
        E4[the]
        E5[European]
        E6[Economic]
        E7[Area]
    end

    subgraph "German (Target)"
        G1[Das]
        G2[Abkommen]
        G3[über]
        G4[den]
        G5[Europäischen]
    end

    E1 -->|0.8| G1
    E2 -->|0.9| G2
    E3 -->|0.6| G3
    E4 -->|0.3| G3
    E5 -->|0.85| G5
    E6 -->|0.7| G5

```

di numeri, tipicamente dimensioni 300-1000.

### Parole simili ottengono vettori simili:

Ecco cosa rende magico l'incorporamento: catturano relazioni semantiche:**Il famoso esempio:**Come vengono imparati gli Embeddings?

```mermaid
graph LR
    subgraph "Self-Attention for 'bank'"
        B[bank]
        R[river]
        W[water]
        F[fish]
    end

    B -.high attention.-> R
    B -.high attention.-> W
    B -.medium attention.-> F

```

Le inserzioni vengono imparate addestrando una rete neurale su un semplice compito: "predire le parole circostanti."

## L'idea è che le parole che appaiono in contesti simili dovrebbero avere significati simili.

Dopo l'addestramento su miliardi di frasi, le parole che appaiono in contesti simili finiscono con inserzioni simili. "Cat" e "cane" appaiono entrambi vicino a "pet," "feed," " cute," così le loro inserzioni finiscono insieme.**Attenzione: Il cambio di gioco**Ecco un'intuizione critica: quando si traduce "Il gatto seduto sul tappetino" in francese, parole di origine diverse contano per parole di destinazione diverse:

```mermaid
graph LR
    subgraph Encoder
        E1[Word Embeddings] --> E2[Self-Attention Layer 1]
        E2 --> E3[Self-Attention Layer 2]
        E3 --> E4[Self-Attention Layer N]
        E4 --> E5[Contextual Representations]
    end

    subgraph Decoder
        D1[Previous Translations] --> D2[Self-Attention]
        D2 --> D3[Cross-Attention to Encoder]
        D3 --> D4[Feed Forward]
        D4 --> D5[Next Word Prediction]
    end

    E5 -.provides context.-> D3

```

### Attenzione

è un meccanismo che permette alla rete di "focus" su diverse parti dell'ingresso quando genera ogni parola in uscita.

```csharp
public class TransformerEncoder
{
    private WordEmbedding wordEmbedding;
    private SelfAttentionLayer[] layers;

    public float[][] Encode(string[] sourceWords)
    {
        // Step 1: Convert words to embeddings
        float[][] embeddings = sourceWords
            .Select(w => wordEmbedding.GetEmbedding(w))
            .ToArray();

        // Step 2: Add positional encoding (so network knows word order)
        float[][] withPositions = AddPositionalEncoding(embeddings);

        // Step 3: Apply multiple self-attention layers
        float[][] representations = withPositions;
        foreach (var layer in layers)
        {
            representations = layer.Forward(representations);
        }

        return representations; // Contextual representations for each word
    }

    private float[][] AddPositionalEncoding(float[][] embeddings)
    {
        // Add position-specific patterns so network knows word order
        // (transformers don't naturally understand sequence order)
        int sequenceLength = embeddings.Length;
        int embeddingDim = embeddings[0].Length;

        for (int pos = 0; pos < sequenceLength; pos++)
        {
            for (int i = 0; i < embeddingDim; i++)
            {
                double angle = pos / Math.Pow(10000, (2.0 * i) / embeddingDim);
                // Use sine for even dimensions, cosine for odd
                embeddings[pos][i] += (float)(i % 2 == 0 ? Math.Sin(angle) : Math.Cos(angle));
            }
        }

        return embeddings;
    }
}
```

Come funziona l'attenzione

- Pensate all'attenzione come alla domanda: "Per tradurre questa parola, a quale parola di origine devo prestare attenzione?"
- Il meccanismo di attenzione:
- Confronta lo stato di destinazione corrente con ogni parola sorgente

### Calcola un "punteggio di pertinenza" per ogni parola sorgente

Converte i punteggi in probabilità (si sommano a 1)

```csharp
public class TransformerDecoder
{
    private WordEmbedding targetEmbedding;
    private SelfAttentionLayer[] selfAttentionLayers;
    private CrossAttentionLayer[] crossAttentionLayers;
    private FeedForwardLayer[] feedForwardLayers;

    public string[] Decode(float[][] encodedSource, int maxLength)
    {
        List<string> translation = new List<string>();
        translation.Add("<START>"); // Special token to begin

        while (translation.Count < maxLength)
        {
            // Get next word
            string nextWord = GenerateNextWord(encodedSource, translation.ToArray());

            if (nextWord == "<END>") break; // Stop token

            translation.Add(nextWord);
        }

        return translation.Skip(1).ToArray(); // Remove <START> token
    }

    private string GenerateNextWord(float[][] encodedSource, string[] partialTranslation)
    {
        // Step 1: Embed the partial translation
        float[][] targetEmbeddings = partialTranslation
            .Select(w => targetEmbedding.GetEmbedding(w))
            .ToArray();

        // Step 2: Self-attention on target words
        float[][] selfAttended = ApplySelfAttention(targetEmbeddings);

        // Step 3: Cross-attention to source (this is where translation happens!)
        float[][] crossAttended = ApplyCrossAttention(selfAttended, encodedSource);

        // Step 4: Feed forward
        float[] finalState = ApplyFeedForward(crossAttended[^1]); // Last position

        // Step 5: Predict next word
        return PredictWord(finalState);
    }

    private string PredictWord(float[] state)
    {
        // Convert state to probability distribution over all possible words
        Dictionary<string, double> wordProbabilities = CalculateWordProbabilities(state);

        // Return most likely word (or sample from distribution)
        return wordProbabilities.OrderByDescending(kv => kv.Value).First().Key;
    }
}
```

Crea una media ponderata delle parole sorgente sulla base di queste probabilità

```mermaid
sequenceDiagram
    participant Input as Source Sentence
    participant Encoder
    participant Decoder
    participant Output as Translation

    Input->>Encoder: "The cat sat"
    Encoder->>Encoder: Build representations
    Encoder->>Decoder: Encoded states

    Decoder->>Decoder: Generate [START]
    Decoder->>Output: Emit START token

    Decoder->>Decoder: Attend to "The" → Generate "Le"
    Decoder->>Output: "Le"

    Decoder->>Decoder: Attend to "cat" → Generate "chat"
    Decoder->>Output: "chat"

    Decoder->>Decoder: Attend to "sat" → Generate "s'est assis"
    Decoder->>Output: "s'est assis"

    Decoder->>Decoder: Generate [END]
    Output->>Output: "Le chat s'est assis"
```

## Visualizzazione dell'attenzione

Nel tradurre "L'accordo sullo Spazio economico europeo è stato firmato nell'agosto 1992" al tedesco, l'attenzione appare così:

1. **Quando si genera "Abkommen" (accordo), la rete presta attenzione al 90% a "accordo," al 5% a "the" e al 5% distribuito tra l'altro.**Self-Attenzione: Attenersi a se stessi
2. **Uso di trasformatori moderni**auto-attenzione
3. **: le parole nella stessa frase si occupano l'un l'altro per costruire rappresentazioni migliori.**In "Il pesce nuotava vicino alla riva del fiume," la parola "banca" assiste fortemente a "fiume," "pesce" e "acqua," aiutando la rete a capire che significa "fiume" non "istituzione finanziaria."

```csharp
public class TranslationTrainer
{
    private TransformerEncoder encoder;
    private TransformerDecoder decoder;
    private double learningRate = 0.0001;

    public void Train(ParallelCorpus corpus, int epochs)
    {
        foreach (var epoch in Enumerable.Range(0, epochs))
        {
            double totalLoss = 0;
            int batchCount = 0;

            foreach (var batch in corpus.GetBatches(batchSize: 32))
            {
                // Forward pass
                var predictions = new List<string[]>();
                var losses = new List<double>();

                foreach (var pair in batch)
                {
                    // Encode source
                    var encoded = encoder.Encode(pair.Source);

                    // Try to decode target
                    var predicted = decoder.Decode(encoded, pair.Target.Length);

                    // Calculate loss (how different is prediction from target?)
                    double loss = CalculateLoss(predicted, pair.Target);
                    losses.Add(loss);
                }

                // Backward pass: adjust weights
                double avgLoss = losses.Average();
                UpdateWeights(avgLoss);

                totalLoss += avgLoss;
                batchCount++;
            }

            Console.WriteLine($"Epoch {epoch}: Average Loss = {totalLoss / batchCount}");
        }
    }

    private double CalculateLoss(string[] predicted, string[] target)
    {
        // Cross-entropy loss: how far off were our word predictions?
        double loss = 0;

        for (int i = 0; i < Math.Min(predicted.Length, target.Length); i++)
        {
            if (predicted[i] != target[i])
            {
                loss += 1.0; // Simplified - real loss is more nuanced
            }
        }

        return loss / target.Length;
    }

    private void UpdateWeights(double loss)
    {
        // Backpropagation: adjust all weights in encoder and decoder
        // to reduce the loss (simplified here)
        // Real implementation uses automatic differentiation
    }
}
```

L'architettura encoder-decoder

```mermaid
graph TD
    A[10M Sentence Pairs] --> B[Initial Random Weights]
    B --> C[Epoch 1: Loss = 5.2]
    C --> D[Epoch 2: Loss = 3.8]
    D --> E[Epoch 3: Loss = 2.1]
    E --> F[Epoch 10: Loss = 0.8]
    F --> G[Epoch 20: Loss = 0.3]
    G --> H[Trained Model!]

    style A stroke-width:2px
    style H stroke-width:4px
```

Ora possiamo mettere tutto insieme!

- **Neural traduzione automatica utilizza un**encoder-decoder
- **architettura:**Il codificatore: Comprendere la sorgente
- **Il compito del codificatore è quello di leggere la frase sorgente e costruire ricche rappresentazioni:**Dopo la codifica, ogni parola sorgente ha una rappresentazione che cattura:

## Il suo significato (dall'incorporamento)

La sua posizione nella frase (da codifica posizionale)

```mermaid
graph TD
    subgraph "1. Encoding"
        A1[The] --> E1[emb: 0.2, -0.1, ...]
        A2[cat] --> E2[emb: 0.5, 0.3, ...]
        A3[sat] --> E3[emb: -0.1, 0.4, ...]
        A4[on] --> E4[emb: 0.1, -0.2, ...]
        A5[the] --> E5[emb: 0.2, -0.1, ...]
        A6[mat] --> E6[emb: 0.4, 0.2, ...]
    end

    subgraph "2. Self-Attention in Encoder"
        E1 & E2 & E3 & E4 & E5 & E6 --> SA[Self-Attention]
        SA --> C1[ctx: 0.3, 0.1, ...]
        SA --> C2[ctx: 0.6, 0.4, ...]
        SA --> C3[ctx: -0.2, 0.5, ...]
    end

    subgraph "3. Decoding"
        D1[START] --> G1[Le]
        C2 -.attend.-> G1

        G1 --> G2[chat]
        C2 -.attend.-> G2

        G2 --> G3[s'est assis]
        C3 -.attend.-> G3
    end


```

### Il suo rapporto con altre parole (da auto-attenzione)

**Il Decoder: Generare la Traduzione**

```csharp
var theEmbedding = encoder.GetEmbedding("The");
// [0.2, -0.1, 0.3, 0.05, ..., 0.1] (300 dimensions)
```

**Il decoder genera la traduzione una parola alla volta:**

```csharp
var catEmbedding = encoder.GetEmbedding("cat");
// [0.5, 0.3, -0.2, 0.4, ..., 0.15] (300 dimensions)
```

**Il processo completo di traduzione:**

```csharp
// "cat" attends to other words
var catAttention = attention.CalculateAttention(catEmbedding, allWordEmbeddings);
// [0.1, 0.3, 0.2, 0.05, 0.1, 0.25]
// High attention to "sat" (0.3) and "mat" (0.25)

var catContextual = attention.ApplyAttention(catAttention, allWordEmbeddings);
// Weighted average incorporating context
```

**Formazione di un modello di traduzione<START>**

```csharp
var decoderState = decoder.InitialState();
```

**Formazione di un modello di traduzione richiede tre cose:**

```csharp
// Attend to source
var sourceAttention = crossAttention.Calculate(decoderState, encodedSource);
// [0.8, 0.05, 0.05, 0.02, 0.05, 0.03]
// Strong focus on "The" (0.8)

var nextWordProbs = decoder.PredictNextWord(decoderState, sourceAttention);
// {"Le": 0.85, "La": 0.08, "Les": 0.04, ...}

var firstWord = "Le";
```

**Corpo parallelo**

```csharp
decoderState = decoder.UpdateState(decoderState, "Le");

var sourceAttention = crossAttention.Calculate(decoderState, encodedSource);
// [0.05, 0.9, 0.02, 0.01, 0.01, 0.01]
// Strong focus on "cat" (0.9)

var nextWordProbs = decoder.PredictNextWord(decoderState, sourceAttention);
// {"chat": 0.92, "chien": 0.03, ...}

var secondWord = "chat";
```

**: Milioni di coppie di frasi in entrambe le lingue<END>**

```
Final translation: "Le chat s'est assis sur le tapis"
```

## Funzione perdita

: Quanto era "sbagliato" la nostra previsione?

1. **Ottimizzazione**: Regolare i pesi per ridurre la perdita
2. **La formazione richiede enormi quantità di dati e di calcolo:**Per un modello all'avanguardia:
3. **Dati relativi alla formazione**: 10-100 milioni di coppie di frasi

```mermaid
graph LR
    subgraph "Old: Recurrent Neural Networks"
        R1[Word 1] --> R2[Word 2]
        R2 --> R3[Word 3]
        R3 --> R4[Word 4]
    end

    subgraph "New: Transformers"
        T1[Word 1] -.attend.-> T2[Word 2]
        T1 -.attend.-> T3[Word 3]
        T1 -.attend.-> T4[Word 4]
        T2 -.attend.-> T3
        T2 -.attend.-> T4
        T3 -.attend.-> T4
    end


```

Tempo di formazione

## : 1-4 settimane su GPU di fascia alta

Dimensione del modello

```csharp
public class TranslationService
{
    private readonly HttpClient _httpClient;
    private readonly string _nmtServiceUrl;

    public TranslationService(HttpClient httpClient, IConfiguration config)
    {
        _httpClient = httpClient;
        _nmtServiceUrl = config["NMT:ServiceUrl"];
    }

    public async Task<TranslationResult> TranslateAsync(
        string text,
        string sourceLang,
        string targetLang)
    {
        var request = new TranslationRequest
        {
            Text = new[] { text },
            SourceLang = sourceLang,
            TargetLang = targetLang
        };

        var response = await _httpClient.PostAsJsonAsync(
            $"{_nmtServiceUrl}/translate",
            request);

        response.EnsureSuccessStatusCode();

        var result = await response.Content
            .ReadFromJsonAsync<TranslationResponse>();

        return new TranslationResult
        {
            Original = text,
            Translated = result.Translated[0],
            SourceLanguage = sourceLang,
            TargetLanguage = targetLang,
            TranslationTime = result.TranslationTime
        };
    }
}

public class TranslationRequest
{
    [JsonPropertyName("text")]
    public string[] Text { get; set; }

    [JsonPropertyName("source_lang")]
    public string SourceLang { get; set; }

    [JsonPropertyName("target_lang")]
    public string TargetLang { get; set; }
}

public class TranslationResponse
{
    [JsonPropertyName("translated")]
    public string[] Translated { get; set; }

    [JsonPropertyName("translation_time")]
    public double TranslationTime { get; set; }
}
```

: parametri da 100M a 1B+ (peso)

```csharp
// In your controller or service
public class BlogPostController : ControllerBase
{
    private readonly TranslationService _translator;

    public async Task<IActionResult> TranslatePost(int postId, string targetLang)
    {
        var post = await _blogService.GetPostAsync(postId);

        var translatedTitle = await _translator.TranslateAsync(
            post.Title,
            "en",
            targetLang);

        var translatedContent = await _translator.TranslateAsync(
            post.Content,
            "en",
            targetLang);

        return Ok(new
        {
            Title = translatedTitle.Translated,
            Content = translatedContent.Translated,
            OriginalLanguage = "en",
            TargetLanguage = targetLang
        });
    }
}
```

## Mettere tutto insieme: un esempio completo

### Tracciamo attraverso la traduzione "Il gatto seduto sul tappeto" in francese:

Processo passo-passo:

```csharp
public async Task<string> TranslateLongText(string longText, string targetLang)
{
    const int maxChunkSize = 500; // characters

    // Split on paragraph boundaries
    var paragraphs = longText.Split(new[] { "\n\n", "\r\n\r\n" },
        StringSplitOptions.RemoveEmptyEntries);

    var translatedParagraphs = new List<string>();

    foreach (var paragraph in paragraphs)
    {
        if (paragraph.Length <= maxChunkSize)
        {
            var result = await _translator.TranslateAsync(paragraph, "en", targetLang);
            translatedParagraphs.Add(result.Translated);
        }
        else
        {
            // Split long paragraph into sentences
            var sentences = SplitIntoSentences(paragraph);
            var translatedSentences = new List<string>();

            foreach (var sentence in sentences)
            {
                var result = await _translator.TranslateAsync(sentence, "en", targetLang);
                translatedSentences.Add(result.Translated);
            }

            translatedParagraphs.Add(string.Join(" ", translatedSentences));
        }
    }

    return string.Join("\n\n", translatedParagraphs);
}
```

### Passo 1: Codifica "The"

Passo 2: Codifica "gatto"

```csharp
public async Task<string> TranslateMarkdown(string markdown, string targetLang)
{
    // Extract text from markdown while preserving structure
    var doc = Markdig.Markdown.Parse(markdown);
    var textSegments = new List<(string text, int position)>();

    // Walk the AST and extract translatable text
    foreach (var node in doc.Descendants())
    {
        if (node is LiteralInline literal)
        {
            var text = literal.Content.ToString();
            if (!string.IsNullOrWhiteSpace(text) && !IsImagePath(text))
            {
                textSegments.Add((text, literal.Span.Start));
            }
        }
    }

    // Translate all segments
    var translations = await Task.WhenAll(
        textSegments.Select(async seg => new
        {
            seg.position,
            translated = (await _translator.TranslateAsync(seg.text, "en", targetLang)).Translated
        }));

    // Reconstruct markdown with translations
    var result = markdown;
    foreach (var translation in translations.OrderByDescending(t => t.position))
    {
        result = result.Remove(translation.position, textSegments
            .First(s => s.position == translation.position).text.Length)
            .Insert(translation.position, translation.translated);
    }

    return result;
}
```

### Fase 3: Self-Attention

Passo 4: Decoder inizia con

```csharp
public async Task<Dictionary<string, string>> TranslateBatch(
    IEnumerable<string> texts,
    string targetLang)
{
    const int batchSize = 32;
    var results = new Dictionary<string, string>();

    foreach (var batch in texts.Chunk(batchSize))
    {
        var request = new TranslationRequest
        {
            Text = batch.ToArray(),
            SourceLang = "en",
            TargetLang = targetLang
        };

        var response = await _httpClient.PostAsJsonAsync(
            $"{_nmtServiceUrl}/translate",
            request);

        var result = await response.Content
            .ReadFromJsonAsync<TranslationResponse>();

        for (int i = 0; i < batch.Length; i++)
        {
            results[batch[i]] = result.Translated[i];
        }
    }

    return results;
}
```

## Passo 5: Generare "Le"

Passo 6: Generare "chat"

```mermaid
graph TD
    A[Translation Request] --> B{Model Size}
    B -->|Small 100M params| C[Fast: 50-100ms]
    B -->|Medium 500M params| D[Medium: 200-500ms]
    B -->|Large 1B+ params| E[Slow: 1-3 seconds]

    A --> F{Hardware}
    F -->|CPU| G[Slow: 2-5x slower]
    F -->|GPU| H[Fast: Baseline]
    F -->|TPU/Special AI chips| I[Very Fast: 2-3x faster]

    style C stroke-width:2px
    style E stroke-width:2px
```

Passo 7: Continuare fino

- **Perché i trasformatori hanno vinto**L'architettura del trasformatore (la "T" in ChatGPT!) divenne dominante perché:
- **Parallelizzazione**: A differenza dei vecchi modelli ricorrenti, tutte le parole possono essere elaborate simultaneamente
- **Dipendenze a lungo raggio**: Attenzione può collegare qualsiasi due parole, non importa quanto distanti

**Scalabilità**: Più dati + modello più grande = migliori risultati (fino ad un punto)

**Le reti ricorrenti processano in sequenza (slow!), mentre i trasformatori processano tutte le parole contemporaneamente (veloce!).**Usare NMT in C#: Un esempio pratico

## Ora che capisci come funziona, ecco come lo useresti effettivamente in un'applicazione .NET:

Uso:

1. **Sfide e soluzioni comuni**1.
2. **Gestione dei testi lunghi**I modelli NMT hanno limiti di lunghezza di ingresso (tipicamente 512-1024 token).
3. **Soluzione: chunking!**2.
4. **Conservazione della formattazione**Markdown, HTML e altri markup possono confondere i modelli NMT:
5. **3.**Elaborazione di lotti per l'efficienza

Tradurre una frase alla volta è lento.

Batch them!

- **Caratteristiche di prestazione**Capire i costi computazionali aiuta l'architetto a trovare soluzioni migliori:
- **Prestazioni tipiche (per frase sulla GPU):**Modelli di piccole dimensioni
- **(100M parami): 50-100m**Modelli medi
- **(500M params): 200-500ms**Modelli di grandi dimensioni

(1B+ parami): 1-3 secondi

Now when you hit "translate" on your blog posts, you'll know exactly what's happening under the hood! 🚀

## CPU vs GPU

: GPU è 2-10x più veloce per NMT

- [Elaborazione del lotto](https://arxiv.org/abs/1706.03762): Può raggiungere più di 100 frasi / secondo con il batching
- [Conclusione](https://jalammar.github.io/illustrated-transformer/)La traduzione automatica neurale potrebbe sembrare magica, ma in realtà è una combinazione elegante di diverse idee intelligenti:
- [Incorporazioni](https://arxiv.org/abs/1409.0473): Rappresentare le parole come vettori che catturano il significato
- [Reti neurali](/blog/category/EasyNMT): Impara modelli da milioni di esempi