导读:本期聚焦于小伙伴创作的《C#如何读取PyTorch的.pt或.pth模型文件?TorchSharp加载模型完整步骤详解》,敬请观看详情。把训练好的PyTorch模型放到C#工程里做推理,最直接的办法是用TorchSharp加载.pt或.pth文件。实际项目中常遇到版本不匹配、权重读不出、设备映射错误等问题。TorchSharp通过LibTorch底层绑定,支持用torch.jit.load读取脚本化模型,也能用state_dict方式还原普通训练权重。关键在于模型导出阶段要用trace或script固化计算图,并在C#侧正确设置CPU或CUDA设备。下文结合代码示例说明从文件读取、参数恢复到前向推理的完整链路,并对比两种加载方式的适用场景与避坑要点。

在C#环境中运行PyTorch模型,核心思路是利用TorchSharp这套.NET绑定库调用LibTorch原生能力。TorchSharp提供了与Python端近似的API,能够直接读取由PyTorch导出的序列化文件,并在内存中重建模型结构与参数。对于已经用Python训练完成的.pt或.pth文件,只要导出方式正确,C#侧并不需要重复编写网络定义。

C#如何读取PyTorch的.pt或.pth模型文件?TorchSharp加载模型完整步骤详解

一、PyTorch模型导出前的准备

在Python端保存模型时,常见做法有两种。一种是仅保存状态字典,即model.state_dict(),这种方式只保留权重,不保留网络结构;另一种是通过torch.jit.script或torch.jit.trace生成脚本化模型,将结构与参数一起固化到文件中。如果希望在C#中直接用TorchSharp读取并推理,推荐采用脚本化方式,因为C#侧无需重新声明网络层。

下面给出Python导出脚本化模型的示例。使用trace需要构造一个符合输入形状的示例张量,而script则直接分析代码路径。对于包含控制流的模型,script更稳妥。导出后得到的.pt文件可以在C#工程中直接加载。

import torch
import torch.nn as nn

class DemoNet(nn.Module):
    def __init__(self):
        super().__init__()
        self.fc = nn.Linear(10, 2)
    def forward(self, x):
        return self.fc(x)

net = DemoNet()
net.eval()
dummy = torch.randn(1, 10)
# 使用trace导出
traced = torch.jit.trace(net, dummy)
traced.save("demo_traced.pt")
# 或使用script导出
scripted = torch.jit.script(net)
scripted.save("demo_scripted.pt")

二、TorchSharp加载.pt文件的基础方式

TorchSharp中对应的加载方法是TorchSharp.Tensorflow?不对,应使用torch.jit.load。该方法位于TorchSharp命名空间下,返回的是一个可调用模块。加载时需注意文件路径使用绝对或相对可访问地址,且LibTorch运行时版本应与导出时PyTorch使用的LibTorch大版本兼容,否则会报序列化格式错误。

以下代码展示在C#控制台程序中读取脚本化模型,并在CPU上执行前向计算。注意输入张量的形状与Python端trace时的dummy保持一致,数据类型通常为float32。

using TorchSharp;
using static TorchSharp.torch;

class Program
{
    static void Main()
    {
        // 加载脚本化模型
        using var module = torch.jit.load("demo_scripted.pt");
        // 构造输入张量,形状[1,10]
        var input = torch.randn(1, 10);
        // 前向推理
        var output = module.forward(input);
        Console.WriteLine(output);
    }
}

如果模型导出时包含CUDA设备信息,而C#运行环境只有CPU,可在加载后调用module.to(device)进行设备迁移。TorchSharp通过torch.device方法声明目标设备,避免运行时报设备不匹配异常。

三、仅加载state_dict的权重恢复方案

当.pth文件只含state_dict时,C#侧必须先用C#重新定义相同结构的网络类,再读取权重字典逐项赋值。这种方式适合对模型结构有完全控制权的团队,但维护成本较高,一旦网络定义和Python端不一致就会加载失败。

下面示例展示如何定义线性网络并加载权重。TorchSharp的load方法可读取pth文件为字典对象,再通过module.load_state_dict映射。注意键名必须与Python端打印的state_dict键完全一致。

using TorchSharp;
using static TorchSharp.torch;
using TorchSharp.Modules;

class DemoNet : nn.Module<Tensor, Tensor>
{
    private Linear fc;
    public DemoNet() : base("DemoNet")
    {
        fc = Linear(10, 2);
        RegisterComponents();
    }
    public override Tensor forward(Tensor x)
    {
        return fc.forward(x);
    }
}

class Loader
{
    static void Run()
    {
        var net = new DemoNet();
        var state = torch.load("demo_weights.pth");
        net.load_state_dict(state);
        var inp = torch.randn(1, 10);
        var outp = net.forward(inp);
        Console.WriteLine(outp);
    }
}

四、两种加载方式对比与避坑

脚本化加载优势在于结构内嵌、C#代码量少、跨语言一致性高;缺点是动态控制流复杂的模型可能trace不准。state_dict方式灵活、文件小,但要求双端网络定义同步,且容易因层名微调而失败。实际部署中,若模型来自第三方,优先协商提供scripted.pt。

常见错误包括:LibTorch版本不匹配导致无法读取、输入形状错误引发维度异常、未调用eval模式使Dropout等层干扰推理。建议在C#加载后立即用固定随机种子验证输出是否与Python端一致,从而确认加载链路正确。

加载方式文件内容C#侧要求适用场景
jit.load结构与权重无需定义网络快速部署、跨语言
load+state_dict仅权重重定义网络自研模型精细控制

五、设备与性能注意事项

在Windows或Linux服务器上运行TorchSharp,需安装对应LibTorch本地库。NuGet包TorchSharp默认带CPU版,若需CUDA应额外引用TorchSharp-cuda包。加载大模型时,建议显式指定device以减少默认设备探测开销。

推理批量处理时,可构造批维度输入并利用TorchSharp的no_grad上下文关闭梯度,降低内存占用。以下代码演示批量推理的基本写法。

using TorchSharp;
using static TorchSharp.torch;

void BatchInfer(string modelPath)
{
    using var m = torch.jit.load(modelPath);
    m.eval();
    using (var noGrad = torch.no_grad())
    {
        var batch = torch.randn(32, 10);
        var res = m.forward(batch);
        Console.WriteLine(res.shape);
    }
}

通过上述步骤,C#程序即可稳定读取PyTorch的.pt或.pth文件并完成推理任务。选择导出与加载方案时,应综合团队语言栈、模型复杂度和部署环境来决定。

TorchSharpPyTorch模型加载C#深度学习修改时间:2026-08-02 18:24:35

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。