Come la traduzione automatica neurale funziona effettivamente: Guida di uno sviluppatore (Italiano (Italian))

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

Sunday, 09 November 2025

//

23 minute read

Introduzione

Se hai seguito questo blog, sai che sono un po' ossessionato dalla traduzione automatica.Ho scritto di, utilizzando EasyNMTservizi di traduzione di background edilizio, e anchemigliorare 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

Come le parole diventano numeri (imbottiture)

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

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.

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

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.TanhNonostante il nome elegante, in realta' sono molto semplici al loro interno.

Che cos'è un neurone artificiale?

Un neurone artificiale è una funzione matematica che:

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#:

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.

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"

// 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 chiamadiscesa gradiente

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));
    }
}
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

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#:

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.

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 matematicaOra 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

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

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?

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 giocoEcco un'intuizione critica: quando si traduce "Il gatto seduto sul tappetino" in francese, parole di origine diverse contano per parole di destinazione diverse:

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.

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)

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à

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 moderniauto-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."
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

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 unencoder-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)

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

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:

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

Il processo completo di traduzione:

// "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

var decoderState = decoder.InitialState();

Formazione di un modello di traduzione richiede tre cose:

// 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

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

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
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

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)

// 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:

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"

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

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"

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 vintoL'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 comuni1.
  2. Gestione dei testi lunghiI modelli NMT hanno limiti di lunghezza di ingresso (tipicamente 512-1024 token).
  3. **Soluzione: chunking!**2.
  4. Conservazione della formattazioneMarkdown, 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 prestazioneCapire i costi computazionali aiuta l'architetto a trovare soluzioni migliori:
  • **Prestazioni tipiche (per frase sulla GPU):**Modelli di piccole dimensioni
  • (100M parami): 50-100mModelli medi
  • (500M params): 200-500msModelli 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: Può raggiungere più di 100 frasi / secondo con il batching
  • ConclusioneLa traduzione automatica neurale potrebbe sembrare magica, ma in realtà è una combinazione elegante di diverse idee intelligenti:
  • Incorporazioni: Rappresentare le parole come vettori che catturano il significato
  • Reti neurali: Impara modelli da milioni di esempi
Finding related posts...
logo

© 2026 Scott Galloway — Unlicense — All content and source code on this site is free to use, copy, modify, and sell.