# Miten hermokonekäännös oikeastaan toimii: Kehittäjän opas

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

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

Jos olet seurannut tätä blogia, tiedät, että konekääntäminen on minulle pakkomielle.[Olen kirjoittanut](/blog/autotranslatingmarkdownfiles), [EasyNMT:n käyttö](/blog/backgroundtranslationspt1)Rakennusten taustakäännöspalvelut[, ja jopa](/blog/mostlylucid-nmt-complete-guide)EasyNMT:n parantaminen**Mutta tajusin, etten ole koskaan oikeasti selittänyt

> miten

Hermokonekääntäminen toimii konepellin alla.

HUOMAUTUS: Tämä on osa kokeilujani tekoälyllä / tapa käyttää 1000 dollarin Calude Code Web -pisteitä.

- Olen syöttänyt tälle BUNCH-lehden, ymmärrykseni ja kysymykseni, jotka minun oli tuotettava.
- Se on hauskaa ja täyttää aukon, jota en ole nähnyt missään muualla.
- Korjataan se sitten!
- Tämä viesti vie sinut sanasta "kääntäminen on taikaa" muotoon "kääntäminen on nokkelaa matematiikkaa" selittämällä neurologisen konekäännöksen keskeiset käsitteet selkokielellä (jossa on paljon kaavioita ja C#-koodia konkretisoitavaksi).
- Tämän tehtävän loppuun mennessä ymmärrät:

Mitä keinotekoiset hermoverkot ovat ja miten ne oppivat

[TOC]

## Miten sanoista tulee numeroita (embeddings)

Mitä "huomio" tarkoittaa tekoälyssä (hyökkääjä: kyse ei ole tarkkaavaisuudesta)

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

```

Miten koodaus-dekooderiarkkitehtuuri toimii

## Miksi muuntajat valtasivat maailman

Älä huoli, jos et ole matikkaihminen - pidän tämän mahdollisimman käytännöllisenä ja visuaalisena.

### Sukellataan sisään!

The Core Idea: Kääntäminen numerona Crunching

1. Tässä on ensimmäinen mieltä taivuttava käsite: neurokonekäännös kohtelee käännöstä puhtaasti matemaattisena prosessina.
2. Jos syötät lauseen, järjestelmä muuntaa sen numeroiksi, suorittaa miljoonia matemaattisia operaatioita ja tekee käännöksen.
3. Mutta hetkinen - miten sanat muutetaan numeroiksi?
4. Ja miten matematiikka "ymmärtää" kieltä?

Aloitetaan rakennuspalikoista.

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

Keinotekoiset hermoverkot: Säätiö

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

Ennen kuin voimme ymmärtää neurokonekäännöksiä, meidän on ymmärrettävä keinotekoisia hermoverkkoja.`Math.Tanh`Hienosta nimestä huolimatta he ovat itse asiassa melko yksinkertaisia.

### Mikä on tekoneuroni?

Keinotekoinen neuroni on matemaattinen funktio, joka:

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

Ottaa useita syötteitä

- Kertoo jokaisen syötteen painolla (miten tärkeää se on?)
- Lisää ne kaikki
- Sovelltaa "aktivointitoimintoa" tulosteen tuottamiseksi

### Tässä on visuaalinen kuvaus:

Tehdään tästä konkreettista C#-koodilla:

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

Aktivointitoiminto (tässä tapauksessa**) tekee hermoverkoista kiinnostavia.**Se tuo epälineaarisuutta, jolloin verkko voi oppia monimutkaisia kuvioita.

Ilman sitä, vaikka kuinka monta neuronia kasautuisi yhteen, sinulla olisi vain hieno lineaarinen funktio.

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

Neuroneista verkostoihin**Taikuus tapahtuu, kun tuhannet tai miljoonat hermosolut yhdistetään kerroksittain:**Jokainen kerros "korjaa" syötteen edustavuutta ja poimii yhä abstraktimpia kuvioita.

## Käännettynä:

Varhaiset kerrokset saattavat havaita "tämä on verbi" tai "tämä sana on mennyt ohi aikamuodossa"

### Keskimmäiset kerrokset saattavat havaita "tämä on kysymys" tai "tässä on kyse säästä"

Myöhemmät kerrokset yhdistävät nämä muotoon "käännä tämä kohteliaaksi kysymykseksi huomisen säästä"

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

Miten verkostot oppivat: Koulutusprosessi

### Fiksuinta on, että emme aseta kaikkia painoja manuaalisesti.

Verkko oppii niitä esimerkeistä!**Tätä prosessia kutsutaan nimellä**kaltevuuslaskeuma

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

Jokaisesta väärästä vastauksesta verkko selvittää, mitkä painot olivat eniten vastuussa tästä virheestä, ja muokkaa niitä hieman.`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"
}
```

### Nähtyään miljoonia esimerkkejä painot asettuvat arvoihin, jotka toimivat hyvin.

Tässä on yksinkertaistettu versio 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, ...]"]

```

Todelliset hermoverkot käyttävät kehittyneempää algoritmia nimeltä

## backpropagation

siinä lasketaan tehokkaasti, miten painoja voi säätää koko verkossa, mutta periaate on sama: opi virheistä.

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

**Word Updatings: Kielen muuttaminen matematiikaksi**Nyt kohtaamme ensimmäisen suuren haasteemme: miten syötämme sanoja hermoverkkoon?

### Teksti on muunnettava numeroiksi.

Yksikuukautisen koodauksen ongelma

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

Naiivi lähestymistapa on "yksikuuma koodaus" - anna jokaiselle sanalle yksilöllinen luku:

1. Tällä on kuitenkin valtava ongelma: luvut ovat mielivaltaisia.
2. Verkko ei osaa sanoa, että "kissa" ja "koira" ovat enemmän samanlaisia kuin "kissa" ja "kuningatar".
3. Numerot 1 ja 2 eivät merkitse mitään.
4. Ratkaisu: Sanat syventyvät

### Sen sijaan edustamme jokaista sanaa

vektori

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

```

numeroiden määrä, tyypillisesti 300–1000 ulottuvuuksia.

### Samanlaiset sanat saavat samanlaisia vektoreita:

Tämä tekee upotuksista maagisia - ne vangitsevat semanttiset suhteet:**Kuuluisa esimerkki:**Miten uppoutumista opitaan?

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

```

Upotukset opitaan kouluttamalla hermoverkkoa yksinkertaiseen tehtävään: "ennakoi ympäröivät sanat".

## Ajatuksena on, että samanlaisissa yhteyksissä esiintyvillä sanoilla pitäisi olla samanlainen merkitys.

Kun on harjoiteltu miljardeja lauseita, vastaavissa yhteyksissä esiintyvät sanat päätyvät samanlaisiin upotuksiin. "Cat" ja "dog" näkyvät molemmat lähellä "pet", "feed", "söpö", joten niiden upotukset päätyvät lähelle toisiaan.**Huomio: Pelin vaihtaja**Kriittinen oivallus: kääntäessään "Katti istui matolla" ranskaksi eri lähdesanoilla on merkitystä eri kohdesanoille:

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

```

### Huomio

on mekanismi, jonka avulla verkko "keskittää" syötteen eri osiin, kun se tuottaa jokaisen ulostulosanan.

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

Miten huomio toimii

- Ajattele huomiota kysyessäsi: "Kääntääksesi tämän sanan, mihin lähdesanoihin minun pitäisi kiinnittää huomiota?"
- Huomiomekanismi:
- Vertaa nykyistä kohdetilaa jokaiseen lähdesanaan

### Laskee kunkin lähdesanan "relevanssipisteet"

Muuntaa pisteet todennäköisyyksiksi (joiden summa on 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;
    }
}
```

Luo näihin todennäköisyyksiin perustuvan lähdesanojen painotetun keskiarvon

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

## Huomion visualisointi

Kääntäessään "Euroopan talousaluetta koskeva sopimus allekirjoitettiin elokuussa 1992" saksaksi huomio näyttää seuraavanlaiselta:

1. **Kun verkko tuottaa "Abkommen" (sopimus), se kiinnittää 90 prosenttia huomiota "sopimukseen", 5 prosenttia "sopimukseen" ja 5 prosenttia muun muassa jaettuna.**Itsekeskeisyys: Itsensä huomioiminen
2. **Modernit muuntajat käyttävät**itsekeskeisyys
3. **: sanat samassa lauseessa huolehtivat toisistaan rakentaakseen parempia kuvauksia.**"Kalat uivat lähellä joen rantaa" -sanassa sana "pankki" tarkoittaa voimakkaasti "jokea", "kalaa" ja "vettä", mikä auttaa verkostoa ymmärtämään, että se tarkoittaa "jokipankkia" eikä "rahoituslaitosta".

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

Enkooderi-dekooderiarkkitehtuuri

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

Nyt voimme koota kaiken yhteen!

- **Neural konekäännös käyttää**enkooderi-dekooderi
- **arkkitehtuuri:**Koodaaja: Lähteen ymmärtäminen
- **Kooderin tehtävänä on lukea lähdelause ja rakentaa rikkaita kuvauksia:**Koodauksen jälkeen jokaisella lähdesanalla on esitys, joka kuvaa:

## Sen merkitys (siirtymästä)

Sen asema lauseessa (sijaintikoodauksesta)

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


```

### Sen suhde muihin sanoihin (itsetietoisuudesta)

**Dekooderi: Luo käännös**

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

**Dekooderi tuottaa käännöksen sana kerrallaan:**

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

**Täydellinen käännösprosessi:**

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

**Kääntämismallin koulutus<START>**

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

**Käännösmallin kouluttaminen vaatii kolme asiaa:**

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

**Rinnakkainen corpus**

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

**: Miljoonat lauseparit molemmilla kielillä<END>**

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

## Hävikkitoiminto

Kuinka "väärä" ennusteemme oli?

1. **Optimointi**: Painojen säätäminen tappion vähentämiseksi
2. **Koulutus vaatii valtavasti dataa ja laskentaa:**Huippuluokan malliksi:
3. **Koulutustiedot**10-100 miljoonaa lauseparia

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


```

Koulutusaika

## : 1–4 viikkoa huippuluokan GPU:illa

Mallin koko

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

: 100 m–1B+-parametrit (painot)

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

## Kaiken yhdistäminen: täydellinen esimerkki

### Jäljitetään kääntämällä "Kissa istui matolla" ranskaksi:

Askel kerrallaan -prosessi:

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

### Vaihe 1: Koodaa "The"

Vaihe 2: Koodaa "kissa"

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

### Vaihe 3: Itsekeskeisyys

Vaihe 4: Dekooderi alkaa

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

## Vaihe 5: Luo "Le"

Vaihe 6: Luo "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
```

Vaihe 7: Jatka kunnes

- **Miksi muuntajat voittivat**Muuntajan arkkitehtuurista (CatGPT:n T) tuli hallitseva, koska:
- **Rinnakkaistaminen**: Toisin kuin vanhemmat toistuvat mallit, kaikki sanat voidaan käsitellä samanaikaisesti
- **Pitkän kantaman riippuvuudet**: Huomio voi yhdistää mitä tahansa kahta sanaa riippumatta siitä, kuinka kaukana toisistaan

**Kallistuvuus**: Lisää dataa + isompi malli = parempia tuloksia (jopa piste)

**Verkkojen uusiminen tapahtuu peräkkäin (hidas!), ja muuntajat käsittelevät kaikki sanat kerralla (nopeasti!).**NMT:n käyttö C#: käytännön esimerkki

## Nyt kun ymmärrät, miten se toimii, voit itse asiassa käyttää sitä .net-sovelluksessa:

Käyttö:

1. **Yhteiset haasteet ja ratkaisut**1 Täysosuma
2. **Pitkien tekstien käsittely**NMT-malleilla on sisääntulon pituusrajat (tyypillisesti 512-1024 rahaketta).
3. **Ratkaisu: pilkkominen!**2.
4. **Muotoilun säilyttäminen**Markdown, HTML ja muut markit voivat hämmentää NMT-malleja:
5. **3.**Erän käsittely tehokkuuden vuoksi

Lause kerrallaan kääntäminen on hidasta.

Napatkaa heidät!

- **Suorituskykyä koskevat ominaisuudet**Laskennallisten kustannusten ymmärtäminen auttaa arkkitehtiä löytämään parempia ratkaisuja:
- **Tyypillinen suoritus (GPU:n lausetta kohti):**Pienet mallit
- **(100 m:n paramit): 50-100 m**Keskikokoiset mallit
- **(500 m:n paramit): 200–500 m**Suuret mallit

(1B+ paramit): 1-3 sekuntia

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

## Suoritin vs. GPU

: GPU on NMT:lle 2-10x nopeampi

- [Erän käsittely](https://arxiv.org/abs/1706.03762): Voi saavuttaa 100+ lausetta/sekunti eräajolla
- [Päätelmät](https://jalammar.github.io/illustrated-transformer/)Hermokonekääntäminen voi vaikuttaa taikuudelta, mutta se on itse asiassa elegantti yhdistelmä useita nokkelia ideoita:
- [Liitännät](https://arxiv.org/abs/1409.0473): Edusta sanoja vektoreina, jotka vangitsevat merkityksen
- [Meriliikenneverkot](/blog/category/EasyNMT): Opettele mallit miljoonista esimerkeistä