跳到正文
>sdcb.ai
2.0 已发布latest v2.0.0 · 2026/10/12100% C#Apache-2.0

HyMT2Sharp

纯 C# 的混元翻译,现在能跑在显卡上了。不依赖 llama.cpp,引用一个 NuGet 包,连模型权重都带上。

安装
dotnet add package Sdcb.HyMT2Sharp
dotnet add package Sdcb.GgufWeights.Hy-MT2-1.8B-2Bit

第二行是 2Bit 模型权重(约 573 MB),也可以直接传 GGUF 文件路径。

15.8k
tok/s prefill · RTX 3080 Ti Vulkan
+4–18%
prefill 对比同机 llama.cpp CUDA
5 / 5
种腾讯官方量化在 CPU 和 GPU 上验证
116
个提交、31 个 PR,从 1.0 到 2.0

翻译竞速

同一句话,四个引擎,按实测速度回放

每条赛道先按 prefill 速度吃掉 83 个 prompt token,再按 decode 速度吐出 60 个 token。速度取自 Ryzen 7 5800X + RTX 3080 Ti 上的 prefill 512 / decode 128 实测,不是在你的浏览器里跑模型。

prompt

SimdPaddleOCR is officially released today (NuGet: Sdcb.SimdPaddleOCR). It is a complete OCR inference engine written entirely in C#. It does not depend on Paddle Inference or ONNX Runtime, and it does not require shipping OpenCV native libraries.

HyMT2SharpVulkan · 3080 Ti—
llama.cppCUDA · 3080 Ti—
HyMT2SharpCPU · 5800X—
llama.cppCPU · 5800X—

prefilldecodeQ4_K_M 起可以和 llama.cpp 正面对比——GPU decode 我们还慢一截。

2Bit

Q2_0C
权重大小
573 MB
NuGet 分片
3
Vulkan pp / tg
15.8k / 299
CPU pp / tg
489 / 47.53

腾讯自有量化格式,llama.cpp 的 CPU 和 GPU 都加载不了,HyMT2Sharp 的 Vulkan 后端是目前唯一的 GPU 路径。 推荐:体积只比 Q4_K_M 的一半多一点,decode 最快。

NuGet
dotnet add package Sdcb.HyMT2Sharp
dotnet add package Sdcb.GgufWeights.Hy-MT2-1.8B-2Bit
Program.cs
using Sdcb.GgufWeights.Hy_MT2_1_8B_2Bit;
using Sdcb.HyMT2Sharp.Backends;
using Sdcb.HyMT2Sharp.Model;

// Metal → Vulkan → CPU
using HunyuanDenseModel model = new(Weights.Model(), backend: BackendFactory.Create());

后端

自动选最快的后端

BackendFactory.Create() 按 Metal → Vulkan → CPU 自动选择;也可以传 "cpu" / "vulkan" / "metal",或设环境变量 HYMT_BACKEND。CPU 内核再按指令集逐级降级。

Vulkan / Metal 的互操作、调度、内存管理全部用 C# 写,仓库语言统计仍是 100% C#。

GPU
  1. Metal
    macOS · Apple Silicon
    M4 虚拟机 ~1,300 / ~70
  2. Vulkan
    Windows · Linux · 需装驱动
    3080 Ti 15.8k / 299
  3. CPU
    都不可用时返回 null
    见下一行
CPU
  1. AVX-512
    Xeon 8559C
    prefill 比 AVX2 快 ~23%
  2. AVX-VNNI
    vpdpbusd
    Q8 内积走 VNNI
  3. AVX2
    Ryzen 7 5800X
    2Bit 489 / 47.5
  4. ARM64 SDOT
    M4 虚拟机
    Q4 prefill 147.7,llama.cpp 84.6
  5. Vector<T>
    兜底
    BLIS 式 GEMM

Intel Arc B580:2Bit 11,039 / 243 tok/s;Q4_K_M 10,620 / 208,同卡 llama.cpp Vulkan 7,345 / 194。AMD RDNA 有默认 tile 调优。

一个值得单独说的修复

966,544 个块里,966,543 个是次正规数

GGUF 量化块里的 d / dmin 缩放因子是 fp16,而真实权重里这些值几乎全是 fp16 的次正规数。旧的 fp16 → fp32 写法中间会产生 fp32 次正规数,每次转换都触发约 150 个周期的微码辅助。

随机字节造的合成权重几乎不会落进次正规区间,所以微基准一直看不出来。改成在整数尾数上计算后结果逐位一致。

decode · Xeon Platinum 8559C

tok/s · 越长越好

修复前修复后
Q6_K+69%
17.7
30.0
Q4_K_M+23%
26.4
32.6
2Bit+22%
52.1
63.5

示例

CLI、Server、WinForms、LINQPad,都默认 2Bit + 自动 GPU

WinForms
WinForms

引擎选"自动",在 3080 Ti 上用 Vulkan:decode 60 个 token 用了 211 ms,约 284 tok/s。

Server
Server

OpenAI 兼容的 /v1/chat/completions,带 SSE 流式和一个聊天页。

LINQPad
LINQPad

包里自带 hello-world、cli、minimal-api 三个脚本,引用后在 Samples 面板里就能看到。

两个坑

写示例时踩到的

流式输出里冒出 �

2Bit 模型更爱把一个多字节字符拆成几个 byte token。第一个 token 单独解码只有半个 UTF-8 序列,于是流里先冒出 �,最后结果却是对的。

token修复前修复后E3 81…ご�…ご (扣住)96…ござ…ござ
Generate
string next = model.Tokenizer
    .DecodeVisible(generated)
    .TrimEnd('\uFFFD');

NVIDIA 上 Vulkan 不还显存

原来的 Dispose 只调 vkDestroyDevice,以为会顺带回收设备名下的资源。NVIDIA 驱动并不会,每次重新加载漏约 4.3 GB。现在 buffer、pipeline、shader module、fence、descriptor pool、command pool 全部单独跟踪、逐个释放。

修复前
ErrorOutOfDeviceMemory
修复后
每根柱子是一次重新加载,虚线 = 3080 Ti 的 12 GB

从 1.0 升级

三个包合成一个

命名空间还是 Sdcb.HyMT2Sharp.Model,new HunyuanDenseModel(path) 和 Forward 的用法没变;不传 backend 时行为与 1.0 一样。

升级
# 1.x
dotnet remove package Sdcb.HyMT2Sharp.Gguf
dotnet remove package Sdcb.HyMT2Sharp.Kernels
dotnet remove package Sdcb.HyMT2Sharp.Model
# 2.0
dotnet add package Sdcb.HyMT2Sharp
  • KvCacheConfig:None / Memory / BlockPolicy(前缀块池)
  • KV cache 改为 bf16,内存减半;prefill 分块
  • Sampler:temperature / top-k / top-p / min-p / 重复惩罚
  • 可从任意可 seek 的 Stream 加载 GGUF

已知限制

还没做好的地方

  • Vulkan decode 比 llama.cpp CUDA 慢 6%~18%,CUDA 的 int8 点积 GEMV 更贴带宽上限。
  • GPU 加载时额外解一份 fp16 权重给 prefill 用,3080 Ti 上一个实例约 4.3 GB 显存。
  • Metal 只在 M4 虚拟机上测过,真机应该更好。
  • HunyuanDenseModel 不是线程安全的,并发请求请排队或各开一个实例。

离线翻译,一个包就够

Apache-2.0 开源,觉得有用欢迎点个 Star。交流可加 QQ 群 495782587(.NET骚操作)。

相关文章