神经机器如何翻译实际有效@: 开发者 @'s 指南
一. 导言导言 导言 导言 导言
如果你一直关注这个博客 @,}你知道 I'}你对机器翻译有点着迷 使用简易NMT, 建筑背景翻译服务,和偶数 A. 改进《简易农用条约》@ ._But I realized I'}但我知道我从未真正解释过 如何 神经机能翻译工作 在hood.下
请注意::}这是我在AI &/’的实验的一部分, 这是用来花费“$1000”Calude Code Web credits “.” I''ve fed this BUNCH of pages, 我的理解是‘,’
@' @%s six 修正@! @ this post will take you 从#"}翻譯為魔術 " 轉成"} 翻譯是聰明的數學 *"}
@,_您能理解吗? :}
- 什么是人工神经网络以及它们是如何学习的
- 单词如何成为数字 @ ( @ embeddings@ MS K1 @ *
- “(spoiler :”的意思是什么?
- 编码器% - @ decoder 结构如何工作
- 为什么变压器占据了世界
请不要担心,如果你不是一位数学家 -I'将保持这个尽可能的实用性和视觉性
核心 Idea @ :}翻译为数字拼接
这里“ ' @ ” 这是第一个 mind@ MS K1 @ abending disciple @ : @ 神经机器翻译将翻译作为纯数学过程处理@ I. @ 您在句子中喂, @ 系统将其转换为数字@,}执行数以百万计的数学操作=,# 并发布一个译文+.{
graph LR
A[Source Sentence] --> B[Convert to Numbers]
B --> C[Neural Network Processing]
C --> D[Convert to Words]
D --> E[Translated Sentence]
但等待“-” 您如何将单词转换为数字“ ?” 和数学“ I"” 理解 “ MS K3” 语言“ MSSK4” 是如何从建筑块开始的?
人造神经网络
在理解神经机器翻译之前 , 我们需要了解人工神经网络吗?. 尽管他们有花哨的名字
什么是人工中风? ?吗?
人造神经元是一个数学函数,该函数:
- 需要多个投入
- 将每个输入乘以重量 * (}\ \ 此输入何等重要 \ MASK1\
- 全部加起来
- 应用“ "” 激活函数@" 来生成输出
这里的' 是一个视觉表示@:
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
让我们来做这个混凝土 用一些 C#}代码=: *
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);
}
}
在此情况下, 激活函数@ ( @% 1 Math.Tanh“)”是让神经网络有趣的东西。“. ”它引入了非“MS K2”的线性“MSC3 允许网络学习复杂的模式。”没有“. ”,不管你堆在一起有多少个神经元 ”“MSSK6 ” 你和' 都有一个花哨的线性的功能 ‘. ’
从中向网络
当你把这些千千万万个神经元连接在一起时 魔法就会发生
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
“"refinees" 输入的表示@ , 在翻译中提取越来越抽象的模式”.
- 早期层可能检测到 @ " @ 这是动词@ MS K1} 或" @ 这个单词是过去时态@ MPK3}
- 中层可能检测到 @"}这是个问题"}或@"}这跟天气有关
- 稍后的层将这些结合到“"”中,
培训过程
我们用手动设置了所有这些重量 . 网络从示例中学习它们
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
此进程被称为 梯度下位“.”针对每个错误的回答“,”网络计算出“"” 哪个重量对这个错误负最大责任,
这里'在 CMS K1}中有一个简化版本
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);
}
}
}
}
真正的神经网络使用更先进的算法 反正对映 有效计算如何调整整个网络的权重\ ,}但原则是相同的{:学习错误_.
将语言转换为数学
现在我们遇到了我们的第一个主要挑战 : 我们如何将单词输入神经网络?? 我们需要把文本转换成数字吗?
单-}热编码的问题
最天真的方法是 @"one@-_hot编码 @MS K2}#-}为每个单词指定一个独有的编号@:{
// Don't do this!
var wordToNumber = new Dictionary<string, int>
{
{"cat", 1},
{"dog", 2},
{"king", 3},
{"queen", 4},
{"man", 5},
{"woman", 6}
};
网络可以告诉 @"cat{"}和@"dog"}都比 @MS K7cata}"}和Z"queen}MSSK10}数字(1}和2}')更相似
解决方案=:字嵌入
我们代表每个单词 矢量 类似单词会得到相似的矢量@:
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"
}
嵌入式学习如何?
通过对神经网络进行简单的任务训练来学习嵌入内容, 教它如何使用“".”的字眼。 这个想法是:类似情况下出现的词应该有相似的含义。
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, ...]"]
在培训了数十亿个句子后, “,” 类似情况下出现的单词最终会以相似的嵌入方式出现。“.” “"” “Cat"” 和“MS K4” 两个字都出现在 "“pet” “",” 附近。 @"‘feed’",’ “Z"’cute}",’ 所以它们的嵌入关系就紧密地连接起来
注意 : 游戏变换器
在翻译“"”时,
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
请注意注意,请注意 是一个让网络在生成每个输出单词时对输入的不同部分 < . } @ " goint "\ { \ > 提供一个机制,
如何关注工作
将注意力视为问@: @"}翻译此字元{,}我该注意的源词是#?"}
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)
- 根据这些概率创建源词的加权平均值
可视化关注
当翻译“"”时, 欧洲经济区协议于8月签署,
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
当生成 " @Abkommen@MSKMK1 @(}协议),时,
自 己 -Attention: 照顾自己
使用现代变压器 自我- @ 注意在同一句中,“:”等词相互呼应,以建立更好的代表机构。 “.”
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
在“"”中,鱼群在河岸附近游荡。 “"” 银行“MSC3”这个词强烈地关注到“MS K4” river ",” 和“" water",” 帮助网络理解它的意思是“MSG10 riversbank"” 不是“MSQ12”金融机构“MSHK13”
编码器@ - @ Decoder 结构
现在,我们可以把这一切放在一起了 !+Neural机器翻译使用 编码器@- @decoder 结构@: @%
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
Encoder: 理解源代码
编码器@' @%s 的任务是阅读源句并构建丰富的表达式+:}
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;
}
}
在编码@, @ 之后, 每个源字都有包含 :}的表示式
- 它的意思是“( ”来自嵌入中的 “) ”
- 它在句子中的位置 @ ( 来自位置编码@ MS K1 {
- 它与其它词“(”的关系。
生成翻译的解码器@: @
解码器一次生成一个词的翻译@: @
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"
a 培训翻译模式
训练翻译模式需要三样东西,
- 并行权利“:百万对两语文的判刑
- 损失职能@: @" @wrong@"}我们的预测是什麽? ?#
- 优化调整权重以减少损失
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
一个状态的-@of @-#The_-}艺术模型=:
- 培训数据-=YTET -伊甸园字幕组=- 翻译:
- 培训时间@ : @ @ I1-4 @ 星期在高端@ MS K2 @ end GPUs
- 模型大小@: @ 100M to @MS K2B+参数@(重量}#)
将它统合起来:}一个完整的示例
让'通过翻译 "追踪猫坐在垫子上到法语=:
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 --> SA[Self-Attention]
E2 --> SA
E3 --> SA
E4 --> SA
E5 --> SA
E6 --> SA
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
步进- - Step process :
步骤“1:”和编码“MS K1”
var theEmbedding = encoder.GetEmbedding("The");
// [0.2, -0.1, 0.3, 0.05, ..., 0.1] (300 dimensions)
步骤“2:”和“Encode”
var catEmbedding = encoder.GetEmbedding("cat");
// [0.5, 0.3, -0.2, 0.4, ..., 0.15] (300 dimensions)
步骤 @3: @ self @ - @ 注意
// "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
“4:解码器”开始于
var decoderState = decoder.InitialState();
步骤“5:” 生成 “"” LeQ"
// 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";
步骤 @6:_ 生成@"}\ CHat_ "
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"
为什么变换者赢
在 ChatGPT!)}的变压器架构@( @% the \ "_T"}由于 @:#而成为主导。
- 平行化与老旧的重复式模型不同 所有单词都可以同时处理
- Long- 山脉依附性@:# 注意可以连接任何两个单词@,}无论距离有多远
- 缩缩@:#更多数据@+}更大的模型=%=#更好的结果 ~(#*达到一个点=){
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
经常网络按顺序处理 @( @slow@ !),}而变压器则同时处理所有单词 #(_spast!).#
在 C#:中使用NMT
现在,你明白它是如何工作的了 , @在这里 @'}您如何在“.QNET application”中实际使用它?
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; }
}
用法@: @%
// 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
});
}
}
共同挑战和解决方案
1. 处理长文本
NMT 模型有输入长度限制@( @ 通常为 @ 512-1024 @ massigns @ MPK2 @ 解答@ MS K3_ browding\ !}
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);
}
2. 保存格式
标记@ , @ HTML @ MS K1} 和其他标记可能会混淆 NMT 模型@ MPK2
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.批处理提高效率
一次翻译一个句子是缓慢的 @. 批发@!#
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;
}
性能特点
了解计算成本有助于设计更好的解决方案
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
GPU=):
- 小型模型 (100%M params@): @ @50-100_ms
- 中模式 (500%M params@): @ @200-500_ms
- 大型模型 @(1B+ paramsMS K2 1-3秒
CPU 相对于 GPU:GPU是 NMT 更快的 @ 2-10x
批次处理“: 能够实现“ 100+ 句子” 吗? / 第二批量
结论结论
神经机器翻译可能看起来像魔术, 但是它实际上是一个优雅的组合 一些聪明的想法:}
- 内嵌: 代表文字作为矢量表达含义
- 神经网络“:”学习数百万个例子的模式。
- 请注意注意,请注意关注投入的相关部分
- 编码器 @ -_ decoder@: 隔代的单独理解
- 变换器: 平行处理一切
令人惊讶的是,现代NMT系统对于语法(grammar) ,(语法)有明确的规则,
若您与NMT合作制作, @(#as I do for this blog_),}理解这些原则会帮助您@:}
- 除调问题@:_#为什么模型翻译@"Bank"}作为“"Banque"}(}金融=)}而不是「"_里韦•"}{(河 )?}?
- 优化业绩:我是否应该批量申请?使用光束搜索@?
- 处理边缘案件@:# 我如何保存代码块 翻译为标记@? @
- 设定的预期期望“:”为什么它能处理“100,000-”字文档“MS K3”吗?
球场仍在快速演进中 . 模型越变越大 MS K1 速度越快 , 和年年越好 但核心概念 @- 嵌入, 注意@, encoder-decoder {- 仍然具有基本意义_.}
现在,当你在你的博客文章“,”上点击“"” Translate@"时,
继续阅读
如果您想下潜更深 :
- 你们需要的注意力 - 原始变压器纸
- 闪光变形器 精彩的直观解释
- 联合学习对齐和翻译的神经机器翻译 注意机制文件
- 我在《容易NMT》上的文章 实际实施细节