C#与ONNX的简单OCR和净化地物采掘 (中文 (Chinese Simplified))

C#与ONNX的简单OCR和净化地物采掘

Wednesday, 21 January 2026

//

14 minute read

随着I'的建设 清晰RAG 区域包 I'm阅读社交媒体, 人们不断询问同样的事情@. @ @ '你如何从扫描文本中获取功能? @?'}分类错误总是{'}只要使用LLM'...}它有用但非常昂贵的#.SO 就像I'一样 在 OCR 空间深处 我想I'd写一个“'Beginner friend's 'M”的方法,

您有文本的图像@ .}您想要提取文字\ ,} 然后在其中找到有用的结构 * @ MS K2_ names @ MPK3} company\ , place*\ I} 未拨打 LLM=,}将数据传送到云端@ MASK7}或支付每个象征性的款项.}

本条显示: 尽可能简单 输油管: 宇宙魔方 文本提取@, @% 然后 净净额 @(_Via ONNX)}所有确定性全部在C=#.中♪

这里的决定因素是指固定版本@,固定语言数据 @,,在运行时没有适应性学习_.

NuGet 马上就到 - I'm 将此包装为简单 mostlylucid.ocrner 下面的代码是复制@-_paste 准备 @.}


完整管道

flowchart LR
    subgraph OCR["Part 1: OCR"]
        IMG[Image]
        TESS[Tesseract]
        TXT[Raw Text]
    end

    subgraph NER["Part 2: NER"]
        TOK[Tokenize]
        BERT[BERT NER<br/>ONNX]
        ENT[Entities]
    end

    IMG --> TESS
    TESS --> TXT
    TXT --> TOK
    TOK --> BERT
    BERT --> ENT

    style TESS stroke:#f60,stroke-width:3px
    style BERT stroke:#f60,stroke-width:3px
    style ENT stroke:#090,stroke-width:3px

双步,两步 ,两种模式都运行本地端"MS K2" Let'"每个部分.


带有宇宙魔方的 & M1: OCR 部件

宇宙魔方 是标准打开@-}来源于 OCR 引擎\ .}We'}使用 宇宙魔方=.NET-=YTET -伊甸园字幕组=- 翻译:

dotnet add package Tesseract

您也需要经过培训的数据文件@.下载 eng.traineddata矩阵数据 并把它放在 tessdata .\

using Tesseract;

public static string ExtractText(string imagePath)
{
    using var engine = new TesseractEngine("./tessdata", "eng", EngineMode.Default);
    using var img = Pix.LoadFromFile(imagePath);
    using var page = engine.Process(img);

    return page.GetText();
}

呼唤 ExtractText("invoice.png") 并获得一个字符串“.”

重要: TesseractEngine 创建@. @ 在真实应用程序中 <% 1 xB1\bord1\shad1\3cH2F2F4F}创建此软件非常昂贵, 并且重新使用它+. BAR

限制

宇宙魔方运作良好 clean ,高-contrast 标准字体中的文字和:搏斗

  • 立体或装饰字体
  • 低@-}质量扫描或照片
  • 旋转或曲线的文字
  • 复杂背景的文字
  • 带有字幕的动画性GIF
  • 连字符换行@ ( @%inter-\nnational) 可能需要在 NER 前加处理

对于需要处理怪事的生产系统来说 , 3-Tier OCR管道加上Florence-2ONNX,

此教程 @ , @ we'}将假设您有来自其它源的干净图像或文字@ MS K2_ PDF 解析@ MPK3} 抄件 @ I- @ pasteQ, @ secl+.).}

在实际操作中,您通常会想要将 OCR 输出正常化 : @ (trim whitespace@ MS K2 折叠重复的新线 =, 修补明显的连字符@) 然后再将其传递给 NERQ.}


与ONNX的 NER 部件

为何本方法工作

在潜入代码前 Let'}让我们理解我们实际上在做什么 '}如果您是C'°Bre a CQ#_BARBAR_开发者 谁从未碰过 MLQ,}本节是为您准备的

什么是NER ??

命名实体识别@(NER}) 研究者训练了神经网络,可以阅读文字并突出显示“"”和“有趣的位子”

  • 百分比 -=YTET -伊甸园字幕组=- 翻译:
  • 其他资源 -=YTET -伊甸园字幕组=- 翻译:
  • LOC 业务发生点 “- 位置”“(" 伦敦 ", " 珠穆朗玛峰”
  • MISC -=YTET -伊甸园字幕组=- 翻译:

该模型从上百万个标注的例子中学习了统计模式 . NER 是特性提取@, @ 而不是推理@ . 它在类固醇上的匹配模式 .

为什么是ONX ?

ONNX ( 开放神经网络交换 ) 是 ML 模型的标准格式. 想象一下 冻结的推断值 DLL 对于神经网络来说 :固定重量, 在 @,@ shallors out, 没有训练逻辑,没有随机=:

flowchart LR
    subgraph Training["Training (Python)"]
        PT[PyTorch Model]
        TF[TensorFlow Model]
    end

    subgraph Export["Export Once"]
        ONNX[model.onnx]
    end

    subgraph Runtime["Run Anywhere"]
        CS[C# App]
        CPP[C++ App]
        JS[JavaScript App]
    end

    PT --> ONNX
    TF --> ONNX
    ONNX --> CS
    ONNX --> CPP
    ONNX --> JS

    style ONNX stroke:#f60,stroke-width:4px
    style CS stroke:#090,stroke-width:3px

关键洞察力 : 其他人做了辛勤的工作 “(”在Python“).”中训练模型。

为何不只使用 LLM?

您可以发送文本到 GPT-4, 并询问“ "” 在文本中找到人和公司@".它工作}#! But @:

@ Q 接近@ Q 速度 @MS K2Q 成本/每兆克3Q docs * Q 隐私= Q 一致性= Q#
净当量 @ @ ~50 @% ms@ MS K2} @ I$0 @ @ O @ 本地 @ NSK5# 高中 @ MPK6 @ @
当地LLM API 小型模型可以是片状的 @ 变数 @MS K6
LLM API ”“1-5”“ ”“I$20-50” “MS K4”数据从外部发送的“ ”变量“MSC6”数据。

LLMs非常适合复杂的推理@. 用于比例尺的图案提取}, 一个专门的模型是#40x


管道

这里:'+#我们正在建造的 '+BARBAR

flowchart LR
    subgraph Input
        TEXT[Raw Text]
    end

    subgraph Tokenization["Step 1: Tokenization"]
        TOK[Split into tokens]
        IDS[Convert to IDs]
    end

    subgraph Model["Step 2: ONNX Inference"]
        BERT[BERT Model]
        LOGITS[Logits Output]
    end

    subgraph Output["Step 3: Decode"]
        LABELS[BIO Labels]
        ENT[Entities]
    end

    TEXT --> TOK
    TOK --> IDS
    IDS --> BERT
    BERT --> LOGITS
    LOGITS --> LABELS
    LABELS --> ENT

    style BERT stroke:#f60,stroke-width:4px
    style ENT stroke:#090,stroke-width:3px

每一步都是简单的... .... Let''...


步骤 @1:_ 下载模型

您需要三个文件, 从 Huggging Face@ . @ 手动下载到文件夹“ MS K1 @ e @ . @ g.,” 。 ./models/ner/):

QFile @ Q大小@ QURL#
model.onnx MS K1MB 下载下载
vocab.txt MS K1KB 下载下载
config.json MS K1KB 下载下载

模式是 {\fn黑体\fs22\bord1\shad0\3aHBE\4aH00\fscx67\fscy66\2cHFFFFFF\3cH808080}Birt@-_base @-NER {\fn方正准圆简体\fs12\1cHC9ECC4}翻译: 导出到 ONNX 格式 保护组织.

您的文件夹应该看起来像@ : @

models/
  ner/
    model.onnx      (the neural network)
    vocab.txt       (word → ID mapping)
    config.json     (label definitions)

步骤 @2:工程设置

创建一个新的控制台应用程序并添加 NuGet 软件包@: @% 1

dotnet new console -n NerDemo
cd NerDemo
dotnet add package Microsoft.ML.OnnxRuntime
dotnet add package Microsoft.ML.Tokenizers

两个包裹 :

  • Onnx 运行时 - 运行模型
  • ML . 收缩器 - handles text *% 1 → @ signal transfer

步骤 @3:_ 理解招数

在模型处理文本前 , 我们需要将其转换为数字@.}这叫做 符号表示式.

flowchart TD
    subgraph Input
        TEXT["John works at Microsoft"]
    end

    subgraph Tokenize["Tokenization"]
        T1["[CLS]"]
        T2["John"]
        T3["works"]
        T4["at"]
        T5["Microsoft"]
        T6["[SEP]"]
    end

    subgraph IDs["Token IDs"]
        I1["101"]
        I2["1287"]
        I3["2573"]
        I4["1120"]
        I5["7513"]
        I6["102"]
    end

    TEXT --> T1 & T2 & T3 & T4 & T5 & T6
    T1 --> I1
    T2 --> I2
    T3 --> I3
    T4 --> I4
    T5 --> I5
    T6 --> I6

    style T1 stroke:#c00,stroke-width:3px
    style T6 stroke:#c00,stroke-width:3px
    style I2 stroke:#090,stroke-width:3px
    style I5 stroke:#090,stroke-width:3px

关键点 @:

  • [CLS][SEP] 用于标记句号边界的特殊符号
  • 每一个字都变成一个数字 vocab.txt
  • 模型只看到数字 @,}从不见实际文本

正在装入调制器

using Microsoft.ML.Tokenizers;

// Load the vocabulary file
var vocabPath = "./models/ner/vocab.txt";

var options = new BertOptions
{
    LowerCaseBeforeTokenization = false,  // BERT-NER is case-sensitive!
    UnknownToken = "[UNK]",
    ClassificationToken = "[CLS]",
    SeparatorToken = "[SEP]",
    PaddingToken = "[PAD]"
};

using var stream = File.OpenRead(vocabPath);
var tokenizer = BertTokenizer.Create(stream, options);

为什么 LowerCaseBeforeTokenization = false@?@ MSKO} 这个模型是用例数文字来训练的 : @ MS K1 @ @ @ I" @ joñ" @ 和" @john @ MPK5 @ 有不同的含义 : s=-one @ MOK7 @ 可能有一个名字@, @ one ' @ 很可能不是. @ @

重要: 代碼器 必须 使用不同的 vocab,}外壳选项@ ,}{或特殊代号ID 会静悄悄地降低结果=.} 总是使用 vocab.txt 使用模型的船舶 .

缩进文本

var text = "John Smith works at Microsoft in London.";

// Tokenize (splits into subwords)
var encoded = tokenizer.EncodeToTokens(text, out _);

// Get special token IDs
var clsId = 101;  // [CLS] token
var sepId = 102;  // [SEP] token

// Build the full sequence: [CLS] + tokens + [SEP]
var tokenIds = new List<int> { clsId };
tokenIds.AddRange(encoded.Select(t => t.Id));
tokenIds.Add(sepId);

// Also keep the text tokens for later
var tokens = new List<string> { "[CLS]" };
tokens.AddRange(encoded.Select(t => t.Value));
tokens.Add("[SEP]");

在此之后,我们有 :

  • tokenIds: [101, 1287, 3455, 2573, 1120, 7513, 1999, 2414, 119, 102]
  • tokens: ["[CLS]", "John", "Smith", "works", "at", "Microsoft", "in", "London", ".", "[SEP]"]

运行模型

现在,我们把这些数字输入 ONNX 模型@.该模型返回“" @logits @"-}每个位置的每一个可能标签的分数”.

flowchart LR
    subgraph Inputs
        IDS["Token IDs<br/>[101, 1287, 3455, ...]"]
        MASK["Attention Mask<br/>[1, 1, 1, ...]"]
    end

    subgraph Model
        ONNX["BERT NER<br/>model.onnx"]
    end

    subgraph Outputs
        LOG["Logits<br/>[batch, seq_len, 9]"]
    end

    IDS --> ONNX
    MASK --> ONNX
    ONNX --> LOG

    style ONNX stroke:#f60,stroke-width:4px

正在装入模型

using Microsoft.ML.OnnxRuntime;
using Microsoft.ML.OnnxRuntime.Tensors;

// Configure for best performance
var sessionOptions = new SessionOptions
{
    GraphOptimizationLevel = GraphOptimizationLevel.ORT_ENABLE_ALL,
    IntraOpNumThreads = Math.Min(4, Environment.ProcessorCount)
};

// Load the model (takes ~2 seconds first time)
var session = new InferenceSession("./models/ner/model.onnx", sessionOptions);

重要: 创建质记器和推文会话, 一次@( @singleton @/Service_)}并重新使用它们 .}唐'}不按文件重新加载-}InferenceSession 创建@ . @ action

准备投入

模型期待#:

  • 输入@ _ids: 我们的代号为 long[]
  • 注意:_mask@ : @ @ I1 @ 真实的牌子@ MS K2 @ * 0} 挂贴
// Pad to a fixed length (BERT requires fixed shapes; powers of 2 are cache-friendly)
int sequenceLength = 64;  // or 128, 256, 512

var inputIds = new long[sequenceLength];
var attentionMask = new long[sequenceLength];

for (int i = 0; i < sequenceLength; i++)
{
    if (i < tokenIds.Count)
    {
        inputIds[i] = tokenIds[i];
        attentionMask[i] = 1;
    }
    else
    {
        inputIds[i] = 0;   // PAD token
        attentionMask[i] = 0;
    }
}

运行中的推断

// Create tensors (shape: [batch_size=1, sequence_length])
var inputIdsTensor = new DenseTensor<long>(inputIds, [1, sequenceLength]);
var attentionMaskTensor = new DenseTensor<long>(attentionMask, [1, sequenceLength]);

// Build inputs
var inputs = new List<NamedOnnxValue>
{
    NamedOnnxValue.CreateFromTensor("input_ids", inputIdsTensor),
    NamedOnnxValue.CreateFromTensor("attention_mask", attentionMaskTensor)
};

// Run the model
using var results = session.Run(inputs);

// Get output logits
var output = results.First(r => r.Name == "logits");
var logits = output.AsTensor<float>();

产出 logits 形状 [1, sequence_length, 9]@ -9_ 每一个象征性位置的可能标签@.}


正在解码输出

模型输出原始分数.}我们需要到:

  1. 为每个标记寻找最高@ - @ scrowring 标签
  2. 将这些标签转换为实际实体

了解 BIO 标记

模型使用 BIO 记号:

flowchart LR
    subgraph Tokens
        T1["John"]
        T2["Smith"]
        T3["works"]
        T4["at"]
        T5["Microsoft"]
    end

    subgraph Labels
        L1["B-PER"]
        L2["I-PER"]
        L3["O"]
        L4["O"]
        L5["B-ORG"]
    end

    T1 --> L1
    T2 --> L2
    T3 --> L3
    T4 --> L4
    T5 --> L5

    style L1 stroke:#090,stroke-width:3px
    style L2 stroke:#090,stroke-width:3px
    style L5 stroke:#00f,stroke-width:3px
  • 马斯克・波德 个人实体的开始
  • 伊姆斯克诺皮尔 @= @Q(@csurvation_) 个人实体
  • OO @=#在任何实体外 @(}不有趣 )
  • 宾斯克罗格 组织开始

这让模型能够处理多@ - @word 实体, 如 @ MS K1_ John Smith% "} 或 @ MPK3_ United Kingdom @ I".}

标签映射

// These are the 9 labels the model was trained on (CoNLL-2003 dataset)
string[] labels =
{
    "O",       // 0: Outside any entity
    "B-PER",   // 1: Beginning of Person
    "I-PER",   // 2: Inside Person
    "B-ORG",   // 3: Beginning of Organization
    "I-ORG",   // 4: Inside Organization
    "B-LOC",   // 5: Beginning of Location
    "I-LOC",   // 6: Inside Location
    "B-MISC",  // 7: Beginning of Miscellaneous
    "I-MISC"   // 8: Inside Miscellaneous
};

注注注注注释注注说明附注注注,注注 注注的注 注 注 注注说明注注附注注 注的注注 注注说注注的附注注说明,注 注,注说明的注说明说明注 注说明注说明 注注 注附注注的注释注 注 注 注注释注说明注释注的说明注,说明注的 注 注说明说明说明 注 注的说明说明,说明说明的附注 注注附注说明注附注的注附注 注 注注释说明注注释的注注释 注注注释注释注,的注, 注注,注释注附注附注注注释说明的说明 注说明 注的注释 注 注附注说明说明注释说明说明附注 注说明的注释注释注释说明 注注释注释 注说明注释注释的说明注释 注注释 注的附注注释注注释,注注释附注注附注注释的 注注脚注注注:_BARBAR_使用标准的“9- label CoNLL schema.%ONOX”出口中包括标签名称。 config.json (id2label 字段@). @% 如果您要交换模型 @ , @ 读取配置而非硬编码的标签 @ MPK2}

寻找最佳标签

每个标牌的“,” 我们选择最高登录分的标签 “:”

var predictions = new List<(string Token, string Label, float Confidence)>();

int numLabels = 9;

for (int i = 0; i < tokens.Count; i++)
{
    // Skip special tokens
    if (tokens[i] is "[CLS]" or "[SEP]" or "[PAD]")
        continue;

    // Find highest scoring label
    float maxScore = float.MinValue;
    int maxIndex = 0;

    for (int j = 0; j < numLabels; j++)
    {
        float score = logits[0, i, j];
        if (score > maxScore)
        {
            maxScore = score;
            maxIndex = j;
        }
    }

    // Convert logit to probability (softmax)
    float confidence = Softmax(logits, i, numLabels, maxIndex);

    predictions.Add((tokens[i], labels[maxIndex], confidence));
}

缩略 Softmax 函数将原始分数转换为概率@(0-1):

static float Softmax(Tensor<float> logits, int position, int numLabels, int targetIndex)
{
    // Find max for numerical stability
    float maxLogit = float.MinValue;
    for (int j = 0; j < numLabels; j++)
        maxLogit = Math.Max(maxLogit, logits[0, position, j]);

    // Compute softmax
    float sumExp = 0f;
    for (int j = 0; j < numLabels; j++)
        sumExp += MathF.Exp(logits[0, position, j] - maxLogit);

    return MathF.Exp(logits[0, position, targetIndex] - maxLogit) / sumExp;
}

关于信任的说明微软分数是 相对数@ ,_ 尚未校准概率@ MS K1} 它们='\ 有用于排序和阈值@ I,, 但 dono{ ' t treat 0.92 使用它们过滤低端的-信任预测 , 不是作为地面真相=.}


采掘实体

现在,我们有了 - -token预测... .......

最初的, WordPiece 合并助手@.这些控件 ## 子词和标点间距正确@ : @

static void AppendWordPiece(StringBuilder sb, string token)
{
    if (string.IsNullOrEmpty(token)) return;

    // WordPiece continuation: "##soft" → append without space
    if (token.StartsWith("##", StringComparison.Ordinal))
    {
        sb.Append(token.AsSpan(2));
        return;
    }

    // No leading space if first token or if punctuation
    if (sb.Length > 0 && !IsPunctuationToken(token))
        sb.Append(' ');

    sb.Append(token);
}

static bool IsPunctuationToken(string token) =>
    token.Length == 1 && char.IsPunctuation(token[0]);

static string MergeWordPieces(IEnumerable<string> tokens)
{
    var sb = new StringBuilder();
    foreach (var t in tokens)
        AppendWordPiece(sb, t);
    return sb.ToString();
}

现在实体 提取.}实体信任就是 最小象征性信任度 在横跨“-”和“保守”、“,”、“因此,一个微弱的标牌是‘'’ 以平均%:’来隐藏吗?

public sealed class Entity
{
    public required string Text { get; init; }
    public required string Type { get; init; }  // PER, ORG, LOC, MISC
    public required float Confidence { get; init; }
}

static List<Entity> ExtractEntities(
    IReadOnlyList<(string Token, string Label, float Confidence)> predictions)
{
    var entities = new List<Entity>();

    string? currentType = null;
    var currentTokens = new List<string>();
    float currentConfidence = 1.0f;

    void Flush()
    {
        if (currentType == null || currentTokens.Count == 0) return;

        entities.Add(new Entity
        {
            Type = currentType,
            Text = MergeWordPieces(currentTokens),
            Confidence = currentConfidence
        });

        currentType = null;
        currentTokens.Clear();
        currentConfidence = 1.0f;
    }

    foreach (var (token, label, conf) in predictions)
    {
        // Continue current entity if model says I-<same type>
        if (currentType != null && label == $"I-{currentType}")
        {
            currentTokens.Add(token);  // keep ## form, merge handles it
            currentConfidence = Math.Min(currentConfidence, conf);
            continue;
        }

        // New entity begins
        if (label.StartsWith("B-", StringComparison.Ordinal))
        {
            Flush();
            currentType = label[2..];
            currentTokens.Add(token);
            currentConfidence = conf;
            continue;
        }

        // Anything else (O, or I- without matching current type) ends the entity
        Flush();
    }

    Flush();
    return entities;
}

注:: WordPiece 完全由 MergeWordPieces不需要特殊控制流 .


完整示例

这里“ ' @ ” 是您可以复制和运行的最小工作示例@ MS K1\ {

using System.Text;
using Microsoft.ML.OnnxRuntime;
using Microsoft.ML.OnnxRuntime.Tensors;
using Microsoft.ML.Tokenizers;

// === Configuration ===
var modelPath = "./models/ner/model.onnx";
var vocabPath = "./models/ner/vocab.txt";

// === Load tokenizer ===
var bertOptions = new BertOptions
{
    LowerCaseBeforeTokenization = false,
    UnknownToken = "[UNK]",
    ClassificationToken = "[CLS]",
    SeparatorToken = "[SEP]"
};

using var vocabStream = File.OpenRead(vocabPath);
var tokenizer = BertTokenizer.Create(vocabStream, bertOptions);

// === Load model ===
var sessionOptions = new SessionOptions
{
    GraphOptimizationLevel = GraphOptimizationLevel.ORT_ENABLE_ALL
};
using var session = new InferenceSession(modelPath, sessionOptions);

// === Process text ===
var text = "John Smith, CEO of Microsoft, announced the acquisition in London yesterday.";

// Tokenize
var encoded = tokenizer.EncodeToTokens(text, out _);

// Build sequence with special tokens
var tokens = new List<string> { "[CLS]" };
tokens.AddRange(encoded.Select(t => t.Value));
tokens.Add("[SEP]");

var rawIds = new List<int> { 101 };  // [CLS]
rawIds.AddRange(encoded.Select(t => t.Id));
rawIds.Add(102);  // [SEP]

// Pad to fixed length
int seqLen = 64;
var inputIds = new long[seqLen];
var attentionMask = new long[seqLen];

for (int i = 0; i < seqLen; i++)
{
    inputIds[i] = i < rawIds.Count ? rawIds[i] : 0;
    attentionMask[i] = i < rawIds.Count ? 1 : 0;
}

// === Run inference ===
var inputs = new List<NamedOnnxValue>
{
    NamedOnnxValue.CreateFromTensor("input_ids",
        new DenseTensor<long>(inputIds, [1, seqLen])),
    NamedOnnxValue.CreateFromTensor("attention_mask",
        new DenseTensor<long>(attentionMask, [1, seqLen]))
};

using var results = session.Run(inputs);
var logits = results.First().AsTensor<float>();

// === Decode predictions ===
string[] labels = ["O", "B-PER", "I-PER", "B-ORG", "I-ORG", "B-LOC", "I-LOC", "B-MISC", "I-MISC"];

// WordPiece merge helper
static string MergeWordPieces(List<string> tokens)
{
    var sb = new StringBuilder();
    foreach (var t in tokens)
    {
        if (t.StartsWith("##", StringComparison.Ordinal))
            sb.Append(t.AsSpan(2));
        else if (sb.Length > 0 && t.Length > 0 && !char.IsPunctuation(t[0]))
            sb.Append(' ').Append(t);
        else
            sb.Append(t);
    }
    return sb.ToString();
}

Console.WriteLine($"Input: {text}\n");
Console.WriteLine("Entities found:");

string? currentType = null;
var currentTokens = new List<string>();

for (int i = 1; i < tokens.Count - 1; i++)  // Skip [CLS] and [SEP]
{
    var token = tokens[i];

    // Find best label
    int bestIdx = 0;
    float bestScore = float.MinValue;
    for (int j = 0; j < 9; j++)
    {
        if (logits[0, i, j] > bestScore)
        {
            bestScore = logits[0, i, j];
            bestIdx = j;
        }
    }

    var label = labels[bestIdx];

    // Continue current entity if model says I-<same type>
    if (currentType != null && label == $"I-{currentType}")
    {
        currentTokens.Add(token);
        continue;
    }

    // New entity begins
    if (label.StartsWith("B-"))
    {
        if (currentType != null)
            Console.WriteLine($"  [{currentType}] {MergeWordPieces(currentTokens)}");

        currentType = label[2..];
        currentTokens = [token];
        continue;
    }

    // Anything else ends the current entity
    if (currentType != null)
        Console.WriteLine($"  [{currentType}] {MergeWordPieces(currentTokens)}");
    currentType = null;
    currentTokens.Clear();
}

// Output last entity
if (currentType != null)
    Console.WriteLine($"  [{currentType}] {MergeWordPieces(currentTokens)}");

产出=:

Input: John Smith, CEO of Microsoft, announced the acquisition in London yesterday.

Entities found:
  [PER] John Smith
  [ORG] Microsoft
  [LOC] London

理解 WordPiece 子词

BERT 用途 WordPiece 符号化, 将未知的单词分割成子字. ## 前缀意指 @ "_ 继续前一个单词@ MS K1\

flowchart LR
    subgraph Original
        W1["Elasticsearch"]
    end

    subgraph Tokenized
        T1["Elastic"]
        T2["##search"]
    end

    subgraph Merged
        M1["Elasticsearch"]
    end

    W1 --> T1 & T2
    T1 --> M1
    T2 --> M1

    style T2 stroke:#c00,stroke-width:3px

缩略 MergeWordPieces 帮助手处理此@ : @ ## 添加了没有空格的自定义符@, production "Elasticsearch" 代替 "Elastic search".


绩效提示

1.批次多文本

如果您有很多文本, 请在批量中处理@ , @ title: group

// Instead of: 1 text × 1 inference = 50ms
// Do: 16 texts × 1 inference = 100ms (6ms per text)

int batchSize = 16;
var batchInputIds = new long[batchSize, seqLen];
// ... fill batch ...
var tensor = new DenseTensor<long>(batchInputIds, [batchSize, seqLen]);

2. 使用聪明的下巴

使用最小的桶子 适合: *

int[] buckets = [32, 64, 128, 256, 512];
int targetLength = buckets.FirstOrDefault(b => b >= tokenIds.Count);
if (targetLength == 0) targetLength = 512;

在实际操作中 ,ONNX NER足够快可以运行 摄食期间的内线@, 不只是批量工作@. 您可以在文件到达时提取实体, 而不是排队等待 #.#

-=YTET -伊甸园字幕组=- 翻译:

对于高排气量 ,使用直接ML *(Windows})或CUDA:

dotnet add package Microsoft.ML.OnnxRuntime.DirectML  # Windows GPU
# or
dotnet add package Microsoft.ML.OnnxRuntime.Gpu       # NVIDIA CUDA
var options = new SessionOptions();
options.AppendExecutionProvider_DML();  // Use GPU

何时使用此 vs LLM

|使用ONNX NER|使用LLMMS K2GPT-4/Claude}| |--------------|------------------------| -=YTET -伊甸园字幕组=- 翻译: |+标准实体 @(+People_,+Ongs=,#places@)+#|#海关实体类型 @MS K6} 当您需要解释时 | | 确定性管道 MS K1 探索分析 | 功能提取@| 解释 @/ 合成 @MSC3

两种方法都能解决 不同问题.NER抽取结构;LMs 解释意涵的原因吗?.


大图片

此图案@ - @%含有冷冻模型的确定性抽取,随后可选合成@-_ 比例远胜于将原始文字推入LLM, 希望它能表现好一点#.}

NER 不是你做的“"”或“I,”或 “输入更精密的管道”

同一方法也适用于其他地物提取任务@:嵌入,分类 @,asume_. train 一旦“(or”使用预先训练的), 将出口到 ONNX, 跑遍各地 @,确定性MSQK8}

何处适合此 OCR +NER输油管是一块建筑块_.。 对于完整图象 <-how professional depactive > ,dexter},和检索>-se 减少的RAGLucidRAG文件“. ” 您在此提取的实体成为节点“ ; ” 文件变成边缘“ IMS K2 ” , LLM只看到它需要什么“ MSSK3 ”


资源资源资源 资源和资源资源资源

圖書館&模擬:

相关条款:

Finding related posts...
logo

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