Πώς λειτουργεί πραγματικά η Νευρική Μετάφραση Μηχανής: Οδηγός ενός προγραμματιστή (ελληνικά (Greek))

Πώς λειτουργεί πραγματικά η Νευρική Μετάφραση Μηχανής: Οδηγός ενός προγραμματιστή

Sunday, 09 November 2025

//

22 minute read

Εισαγωγή

Αν παρακολουθείς αυτό το blog, ξέρεις ότι έχω εμμονή με τη μετάφραση μηχανών.Έχω γράψει για, χρήση του EasyNMTυπηρεσίες μετάφρασης ιστορικού κτιρίου, και ακόμηβελτίωση του EasyNMT**Αλλά συνειδητοποίησα ότι ποτέ δεν έχω πραγματικά εξηγήσει

Πώς

νευρική μετάφραση μηχανών λειτουργεί κάτω από την κουκούλα.

ΣΗΜΕΙΩΣΗ: Αυτό είναι μέρος των πειραμάτων μου με AI / ένας τρόπος για να περάσετε $ 1000 Calude Code Web πιστώσεις.

  • Έχω ταΐσει αυτό ένα σωρό χαρτιά, καταλαβαίνω, ερωτήσεις που έπρεπε να δημιουργήσω αυτό το άρθρο.
  • Έχει πλάκα και γεμίζει ένα κενό που δεν έχω δει να γεμίζει πουθενά αλλού.
  • Οπότε ας το διορθώσουμε αυτό!
  • Αυτή η δημοσίευση θα σας μεταφέρει από "η μετάφραση είναι μαγεία" σε "η μετάφραση είναι έξυπνη μαθηματικά" εξηγώντας τις βασικές έννοιες πίσω από τη νευρική μετάφραση μηχανών σε απλά αγγλικά (με πολλά διαγράμματα και κάποιο κώδικα C# για να το κάνει σκυρόδεμα).
  • Μέχρι το τέλος αυτής της ανάρτησης, θα καταλάβετε:

Τι είναι τα τεχνητά νευρωνικά δίκτυα και πώς μαθαίνουν

Πώς οι λέξεις γίνονται αριθμοί (εμπρόσθιες)

Τι σημαίνει "προσοχή" στην AI (που παρερμηνεύει: δεν έχει να κάνει με το να δίνεις προσοχή)

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

Πώς λειτουργεί η αρχιτεκτονική κωδικοποιητή-αποκωδικοποιητή

Γιατί οι μετασχηματιστές κατέλαβαν τον κόσμο

Μην ανησυχείς αν δεν είσαι άνθρωπος των μαθηματικών, θα το κρατήσω όσο πιο πρακτικό και οπτικό γίνεται.

Ας βουτήξουμε μέσα!

The Core Idea: Μετάφραση ως αριθμός Crunching

  1. Εδώ είναι το πρώτο μυαλό-δαμασμό έννοια: η νευρική μετάφραση μηχανών αντιμετωπίζει τη μετάφραση ως μια καθαρά μαθηματική διαδικασία.
  2. Τροφοδοτείς σε μια πρόταση, το σύστημα την μετατρέπει σε αριθμούς, εκτελεί εκατομμύρια μαθηματικές λειτουργίες, και βγάζει μια μετάφραση.
  3. Αλλά περιμένετε - πώς μετατρέπετε τις λέξεις σε αριθμούς;
  4. Και πώς τα μαθηματικά "καταλαβαίνουν" γλώσσα;

Ας ξεκινήσουμε με τα δομικά στοιχεία.

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

Τεχνητά Νευρωνικά Δίκτυα: Το Ίδρυμα

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

Πριν μπορέσουμε να κατανοήσουμε τη νευρική μετάφραση μηχανών, πρέπει να κατανοήσουμε τα τεχνητά νευρωνικά δίκτυα.Math.TanhΠαρά το φανταχτερό όνομα, είναι πολύ απλά στον πυρήνα τους.

Τι είναι ένας τεχνητός νεύρος;

Ένας τεχνητός νευρώνας είναι μια μαθηματική λειτουργία που:

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

Παίρνει πολλαπλές εισόδους

  • Πολλαπλασιάζεται κάθε είσοδος κατά βάρος (πόσο σημαντική είναι αυτή η είσοδος;)
  • Τα βάζει όλα επάνω.
  • Εφαρμόζει μια "λειτουργία ενεργοποίησης" για την παραγωγή μιας εξόδου

Εδώ είναι μια οπτική αναπαράσταση:

Ας κάνουμε αυτό το τσιμέντο με έναν κωδικό 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

Η λειτουργία ενεργοποίησης (σε αυτή την περίπτωση**) είναι αυτό που κάνει τα νευρικά δίκτυα ενδιαφέροντα.**Εισάγει μη γραμμικότητα, επιτρέποντας στο δίκτυο να μάθει περίπλοκα μοτίβα.

Χωρίς αυτό, δεν έχει σημασία πόσοι νευρώνες μαζευτήκατε μαζί, απλά θα είχατε μια φανταχτερή γραμμική λειτουργία.

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

Από τους Νευρούς στα Δίκτυα**Η μαγεία συμβαίνει όταν συνδέετε χιλιάδες ή εκατομμύρια από αυτούς τους νευρώνες μαζί σε στρώματα:**Κάθε στρώμα "αποσυνθέτει" την αναπαράσταση της εισόδου, εξάγοντας όλο και πιο αφηρημένα μοτίβα.

Στη μετάφραση:

Τα πρώτα στρώματα μπορεί να ανιχνεύσουν "αυτό είναι ένα ρήμα" ή "αυτή η λέξη είναι παρελθοντική"

Μεσαία στρώματα μπορεί να ανιχνεύσουν "αυτό είναι μια ερώτηση" ή "αυτό είναι για τον καιρό"

Αργότερα τα στρώματα τα συνδυάζουν σε "μεταφράστε αυτό ως μια ευγενική ερώτηση σχετικά με τον αυριανό καιρό"

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

Πώς Μαθαίνουν τα Δίκτυα: Η Διαδικασία Εκπαίδευσης

Εδώ είναι το έξυπνο μέρος: δεν ρυθμίζουμε χειροκίνητα όλα αυτά τα βάρη.

Το δίκτυο τα μαθαίνει από παραδείγματα!Αυτή η διαδικασία ονομάζεταικάθοδος κλίσης

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

Για κάθε λάθος απάντηση, το δίκτυο υπολογίζει "ποια βάρη ήταν πιο υπεύθυνα για αυτό το λάθος;" και τα ανατριχιάζει λίγο.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"
}

Αφού είδαμε εκατομμύρια παραδείγματα, τα βάρη τοποθετούνται σε αξίες που λειτουργούν καλά.

Εδώ είναι μια απλοποιημένη έκδοση στο 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, ...]"]

Πραγματικά νευρικά δίκτυα χρησιμοποιούν έναν πιο εξελιγμένο αλγόριθμο που ονομάζεται

backpropagation

που υπολογίζει αποτελεσματικά πώς να ρυθμίσετε τα βάρη σε ολόκληρο το δίκτυο, αλλά η αρχή είναι η ίδια: να μάθετε από τα λάθη.

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

Ενσωμάτωση λέξεων: Μετατρέποντας τη γλώσσα σε μαθηματικάΤώρα χτυπάμε την πρώτη μας μεγάλη πρόκληση: πώς τροφοδοτούμε τις λέξεις σε ένα νευρωνικό δίκτυο;

Πρέπει να μετατρέψουμε το κείμενο σε αριθμούς.

Το πρόβλημα με την ενιαία κωδικοποίηση

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

Η αφελής προσέγγιση είναι "ένα-καυτό κωδικοποίηση" - αποδίδουν κάθε λέξη ένα μοναδικό αριθμό:

  1. Αλλά αυτό έχει ένα τεράστιο πρόβλημα: οι αριθμοί είναι αυθαίρετοι.
  2. Το δίκτυο δεν μπορεί να πει ότι "γάτα" και "σκύλος" είναι πιο παρόμοια από "γάτα" και "queen."
  3. Οι αριθμοί 1 και 2 δεν σημαίνουν τίποτα.
  4. Η Λύση: Ενσωμάτωση λέξεων

Αντ' αυτού, εκπροσωπούμε κάθε λέξη ως ένα

διάνυσμα

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

των αριθμών, συνήθως 300-1000 διαστάσεις.

Παρόμοιες λέξεις παίρνουν παρόμοια διανυσματικά σημεία:

Εδώ είναι τι κάνει την ενσωμάτωση μαγικό - αιχμαλωτίζουν σημασιολογικές σχέσεις:**Το διάσημο παράδειγμα:**Πώς Μαθαίνουν οι Ενδυμασίες;

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

Οι προσθήκες μαθαίνονται με την εκπαίδευση ενός νευρικού δικτύου σε ένα απλό έργο: "προβλέψτε τις λέξεις που περιβάλλουν."

Η ιδέα είναι ότι οι λέξεις που εμφανίζονται σε παρόμοια πλαίσια θα πρέπει να έχουν παρόμοιες έννοιες.

Μετά την εκπαίδευση σε δισεκατομμύρια προτάσεις, οι λέξεις που εμφανίζονται σε παρόμοια πλαίσια καταλήγουν με παρόμοιες καταχωρήσεις. "Cat" και "σκύλος" εμφανίζονται και οι δύο κοντά στο "pet," "feed," "χαριτωμένος," έτσι ώστε οι ενδυμασίες τους καταλήγουν κοντά μαζί.Προσοχή: Ο Changer ΠαιχνιδιούΕδώ είναι μια κριτική διορατικότητα: κατά τη μετάφραση "Η γάτα κάθισε στο χαλί" στα γαλλικά, διαφορετικές λέξεις πηγή ύλη για διαφορετικές λέξεις στόχο:

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

Προσοχή!

είναι ένας μηχανισμός που επιτρέπει στο δίκτυο να "εστιάζει" σε διαφορετικά μέρη της εισόδου όταν παράγει κάθε λέξη εξόδου.

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

Πώς Λειτουργεί η Προσοχή

  • Σκέψου την προσοχή σαν να ρωτάς: "Για να μεταφράσεις αυτή τη λέξη, σε ποιες πηγές πρέπει να δίνω προσοχή;"
  • Ο μηχανισμός προσοχής:
  • Συγκρίνει την τρέχουσα κατάσταση στόχου με κάθε λέξη πηγής

Υπολογίζει μια "βαθμίδα αναφοράς" για κάθε λέξη πηγής

Μετατρέπει τις βαθμολογίες σε πιθανότητες (αθροίζουν στο 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;
    }
}

Δημιουργεί ένα σταθμισμένο μέσο όρο των λέξεων πηγής βάσει αυτών των πιθανοτήτων

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"

Οραματισμός Προσοχής

Κατά τη μετάφραση "Η συμφωνία για τον Ευρωπαϊκό Οικονομικό Χώρο υπεγράφη τον Αύγουστο του 1992" στα γερμανικά, η προσοχή μοιάζει κάπως έτσι:

  1. **Κατά τη δημιουργία του "Abkommen" (συμφωνία), το δίκτυο δίνει 90% προσοχή στη "συμφωνία," 5% στο "the" και 5% κατανέμεται μεταξύ άλλων.**Αυτοπροσοχή: Να Προσέχετε τον Εαυτό Σας
  2. Σύγχρονη χρήση μετασχηματιστώναυτοπροσοχή
  3. **: οι λέξεις στην ίδια πρόταση φροντίζουν ο ένας τον άλλον για την κατασκευή καλύτερων αναπαραστάσεων.**Στο "Το ψάρι κολύμπησε κοντά στην όχθη του ποταμού," η λέξη "τράπεζα" παρακολουθεί έντονα το "ρίβερ," το "ψάρι" και το "νερό," βοηθώντας το δίκτυο να καταλάβει ότι σημαίνει "ριβερμπάνκ" όχι "χρηματοπιστωτικό ίδρυμα."
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
    }
}

Η αρχιτεκτονική κωδικοποιητή-αποκωδικοποιητή

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

Τώρα μπορούμε να τα συναρμολογήσουμε όλα!

  • Neural μετάφραση μηχανή χρησιμοποιεί ένακωδικοποιητής-αποκωδικοποιητής
  • **αρχιτεκτονική:**Ο Κωδικοποιητής: Κατανόηση της Πηγής
  • **Η δουλειά του κωδικοποιητή είναι να διαβάζει την αρχική πρόταση και να φτιάχνει πλούσιες αναπαραστάσεις:**Μετά την κωδικοποίηση, κάθε λέξη πηγή έχει μια αναπαράσταση που συλλαμβάνει:

Η σημασία του (από την ενσωμάτωση)

Η θέση του στην πρόταση (από την κωδικοποίηση θέσης)

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


Η σχέση του με άλλα λόγια (από την αυτοπροσοχή)

Ο Αποκωδικοποιητής: Δημιουργία της Μετάφρασης

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

Ο αποκωδικοποιητής παράγει τη μετάφραση μία λέξη τη φορά:

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

Η πλήρης διαδικασία μετάφρασης:

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

Εκπαίδευσις ενός Μεταφραστικού Υποδείγματος

var decoderState = decoder.InitialState();

Η εκπαίδευση ενός μεταφραστικού μοντέλου απαιτεί τρία πράγματα:

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

Παράλληλο σώμα

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

: Εκατομμύρια ζεύγη προτάσεων και στις δύο γλώσσες

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

Λειτουργία απώλειας

Πόσο "λάθος" ήταν η πρόβλεψή μας;

  1. Βελτιστοποίηση: Ρυθμίστε τα βάρη για να μειώσετε την απώλεια
  2. **Η εκπαίδευση παίρνει τεράστιες ποσότητες δεδομένων και υπολογισμού:**Για υπερσύγχρονο μοντέλο:
  3. Δεδομένα κατάρτισης: 100-100 εκατομμύρια ζεύγη προτάσεων
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


Χρόνος κατάρτισης

: 1-4 εβδομάδες σε υψηλής ποιότητας GPUs

Μέγεθος υποδείγματος

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

: 100M έως 1B+ παράμετροι (βάρη)

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

Συνδυάζοντας τα πάντα: Ένα Πλήρες Παράδειγμα

Ας εντοπίσουμε μέσω της μετάφρασης "Η γάτα κάθισε στο χαλάκι" στα γαλλικά:

Διαδικασία βήμα προς βήμα:

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

Βήμα 1: Κωδικοποίηση "The"

Βήμα 2: Κωδικοποίηση "γάτα"

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

Βήμα 3: Αυτοπροσοχή

Βήμα 4: Ο αποκωδικοποιητής ξεκινά με

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

Βήμα 5: Δημιουργία "Le"

Βήμα 6: Δημιουργία "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

Βήμα 7: Συνεχίστε μέχρι

  • Γιατί Κέρδισαν οι ΜετασχηματιστέςΗ αρχιτεκτονική του μετασχηματιστή (το "T" στο ChatGPT!) έγινε κυρίαρχη επειδή:
  • Παραλληλοποίηση: Σε αντίθεση με παλαιότερα επαναλαμβανόμενα μοντέλα, όλες οι λέξεις μπορούν να επεξεργαστούν ταυτόχρονα
  • Εξαρτήσεις μεγάλης εμβέλειαςΗ προσοχή μπορεί να συνδέσει δύο λέξεις, όσο μακριά κι αν είναι.

Ευκαμψία: Περισσότερα στοιχεία + μεγαλύτερο μοντέλο = καλύτερα αποτελέσματα (μέχρι ένα σημείο)

**Τα επαναλαμβανόμενα δίκτυα επεξεργάζονται διαδοχικά (αργή!), ενώ οι μετασχηματιστές επεξεργάζονται όλες τις λέξεις ταυτόχρονα (γρήγορα!).**Χρήση NMT σε C#: Ένα Πρακτικό Παράδειγμα

Τώρα που καταλαβαίνετε πώς λειτουργεί, εδώ είναι πώς θα το χρησιμοποιήσετε πραγματικά σε μια εφαρμογή .NET:

Χρήση:

  1. Κοινές Προκλήσεις και Λύσεις1.
  2. Χειρισμός μακρών κειμένωνΤα μοντέλα NMT έχουν όρια μήκους εισόδου (συνήθως 512-1024 μάρκες).
  3. **Λύση: πνιγμός!**2.
  4. Διατήρηση της μορφοποίησηςMarkdown, HTML, και άλλα markup μπορούν να μπερδέψουν τα μοντέλα NMT:
  5. **3.**Επεξεργασία παρτίδας για απόδοση

Η μετάφραση μιας πρότασης τη φορά είναι αργή.

Μαζευτείτε!

  • Χαρακτηριστικά επιδόσεωνΚατανόηση του υπολογιστικού κόστους σας βοηθά αρχιτέκτονας καλύτερες λύσεις:
  • **Τυπικές επιδόσεις (ανά πρόταση για GPU):**Μικρά μοντέλα
  • (100M params): 50-100msΜεσαία μοντέλα
  • (500M params): 200-500msΜεγάλα μοντέλα

(1B+ params): 1-3 δευτερόλεπτα

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 γρηγορότερα για NMT

  • Επεξεργασία παρτίδας: Μπορεί να επιτύχει 100+ προτάσεις/δεύτερο με παρτίδα
  • ΣυμπέρασμαΗ μετάφραση Neural machine μπορεί να μοιάζει με μαγεία, αλλά στην πραγματικότητα είναι ένας κομψός συνδυασμός από διάφορες έξυπνες ιδέες:
  • Ενσωμάτωση: Αντιπροσωπεύουν τις λέξεις ως φορείς που αιχμαλωτίζουν το νόημα
  • Νευρωνικά δίκτυα: Μάθετε πρότυπα από εκατομμύρια παραδείγματα
Finding related posts...
logo

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