从 Android 到 Flutter 再到 Rust:我在阿里园区踩过的深度学习框架坑

创新Tech
2025-12-13 20:10
阅读 463

上周五晚上十点,我盯着 Terminal 里一行行飘过的 loss 值,突然想起去年双11前夜——那时我还是个纯正的 Android 开发,每天和 Gradle 打架、被 ProGuard 折磨、在 Kotlin 协程里迷失自我。如今转战 Flutter 两年多,写起 Dart 来比写 Java 还顺手,Vim 的 .vimrc 都快能当简历用了。

但谁能想到,一个 UI 工程师,居然有一天要亲手训模型?

起因说来有点社死:我们组接了个「智能图片裁剪」的需求,产品经理甩过来一句:“能不能像淘宝详情页那样,自动识别主体,把商品抠出来?” 我当场就懵了——这特么不是 CV(计算机视觉)的事吗?咋找上我这个写 ContainerRow 的?

可现实是骨感的。团队里没专职算法工程师,老板一句“你之前搞过 TensorFlow Lite 吗?”,我就被迫营业了。更扎心的是,隔壁网易的朋友刚跳槽去某大模型初创公司,晒着 50k 的 offer —— 看来不学点硬核东西,真要在杭州卷不动了。

于是,抱着“反正闲着也是刷 LeetCode”的心态,我一头扎进了深度学习框架的深水区。这篇文章就是我这三个月摸爬滚打后的一些开发心得,也顺便聊聊几本救我狗命的书籍


别信“开箱即用”,那都是骗小白的

一开始我天真地以为,现在 AI 框架都这么成熟了,找个现成模型微调一下不就完了?结果第一天就翻车。

我先是试了 TensorFlow(毕竟 Android 时代就认识它)。安装、pip install、导入,一切顺利。直到我试图加载一个自定义数据集——等等,怎么又要写 tf.data.Dataset,又要配 tf.config.experimental.set_memory_growth?当年在 Android 上处理 OOM 就够头疼了,现在还得在 GPU 上防爆显存?

# 当时写的 TF 数据管道,现在看简直屎山
def load_dataset():
    paths = tf.data.Dataset.list_files("data/*.jpg")
    images = paths.map(load_and_preprocess_image)
    labels = paths.map(extract_label)
    return tf.data.Dataset.zip((images, labels)).batch(32)

跑起来倒是快,但调试?别想了。TF 的 eager mode 虽然比 graph mode 友好,但一旦出错,报错信息动辄上百行,什么 InvalidArgumentError: Expected image (JPEG, PNG, or GIF), got unknown format —— 明明我文件后缀是 .jpg 啊!后来才发现有几张图其实是 WebP 格式,藏得比产品经理的需求变更还深。

更惨的是部署。我们 App 是 Flutter 的,得用 TensorFlow Lite。转换模型时又遇到算子不支持的问题,折腾一周才搞定。上线后测试同学反馈:“iOS 上裁剪偏移了 10 像素。” 我:???原来 TFLite 在不同平台浮点精度还有差异!

那一刻我真的想砸电脑。


PyTorch:真香,但别高兴太早

被 TF 折磨得不行,我转投 PyTorch 怀抱。毕竟 GitHub 上 90% 的新论文代码都是 PyTorch 写的,社区活跃,文档也清晰。

果然,上手快多了。数据加载用 torch.utils.data.Dataset,几行代码搞定;模型定义继承 nn.Module,逻辑清晰;训练循环更是自由得飞起:

model = MyModel()
optimizer = torch.optim.Adam(model.parameters(), lr=1e-4)
for epoch in range(10):
    for images, labels in dataloader:
        outputs = model(images)
        loss = criterion(outputs, labels)
        loss.backward()
        optimizer.step()
        optimizer.zero_grad()  # 别忘了这行!我第一次漏了,loss 直接 NaN

调试体验也爽到飞起——直接 print tensor,断点随便打,Vim + IPython 组合拳打得很舒服。关键是,PyTorch Mobile 虽然不如 TFLite 成熟,但导出 ONNX 再转其他格式的路子很稳。

但问题来了:性能

我们的图片裁剪模型需要实时响应(用户上传即出结果),PyTorch 原生推理在手机上慢得像蜗牛。就算用了 TorchScript 优化,还是比 TFLite 慢 30%。而且 iOS 上集成还得搞一堆 C++ binding,Flutter 插件写得我头秃。

更别说内存占用——测试机 iPhone 12 直接杀后台,运维小哥在群里 @ 我:“你们这模块内存飙到 800MB,再这样明天就下线。”

行吧,框架再香,扛不住业务压力也是白搭。


那么,Rust + tch-rs?别闹了兄弟

说到这儿,必须提一嘴我最近迷上的 Rust。作为 Vim 党,我对性能和可控性有执念。看到有人用 tch-rs(PyTorch 的 Rust binding)写推理引擎,我两眼放光:“这不就是我的归宿?”

结果……光是配 CUDA 环境就花了三天。cargo build 时依赖冲突报错看得我怀疑人生。最后跑通了一个 MNIST 示例,成就感满满。但一测性能——比 PyTorch 原生还慢!因为 tch-rs 底层还是调的 libtorch,中间多了一层 FFI 开销。

而且,生态太弱。没有 DataLoader,没有预训练模型仓库,连个像样的图像预处理库都得自己撸。我花了一周写了个 JPEG 解码器,结果发现 image crate 已经有现成的了……浪费生命啊!

不过话说回来,Rust 写推理服务端倒是挺香。我们现在有个边缘计算节点,用 Actix + tch-rs 跑模型,稳定又省内存。但移动端?算了,等 Maturin 或者 WASM 技术再成熟点再说吧。


最终方案:ONNX + 自研轻量 Runtime

折腾一圈下来,我悟了:别在一棵树上吊死

现在的方案是:

  1. 训练用 PyTorch(开发效率高,调试爽)
  2. 导出 ONNX(跨平台中间表示)
  3. 移动端用自研轻量 Runtime 加载 ONNX

为什么不用 ONNX Runtime 官方版?因为太大了!光 so 文件就 20MB+,App 包体积直接爆炸。我们砍掉了所有非必要算子,只保留 CNN 和 Resize 相关的,最终 runtime 控制在 3MB 以内。

关键代码其实就这几行(伪代码):

// Flutter 插件调用 Rust Runtime(通过 FFI)
fn run_inference(image_bytes: &[u8]) -> Vec<f32> {
    let model = load_onnx_model("crop.onnx");
    let input = preprocess(image_bytes); // resize + normalize
    let output = model.run(&[input]);
    postprocess(output) // 转回裁剪坐标
}

配合 Dart 的 ffi 包,性能杠杠的。iOS 和 Android 表现一致,再也不用担心平台差异了。


框架对比:血泪总结表

为了让大家少走弯路,我把几个主流框架在我们场景下的表现整理成表:

维度 TensorFlow PyTorch ONNX (自研 Runtime) tch-rs (Rust)
训练开发体验 ⭐⭐☆(Graph 模式反人类) ⭐⭐⭐⭐⭐(Pythonic,调试友好) ❌(不支持训练) ⭐⭐(Rust 学习曲线陡)
移动端部署难度 ⭐⭐⭐(TFLite 成熟但配置繁琐) ⭐⭐(TorchScript + iOS 集成复杂) ⭐⭐⭐⭐(一次导出,多端运行) ⭐(生态不全,需大量胶水代码)
推理性能(手机) ⭐⭐⭐⭐ ⭐⭐⭐ ⭐⭐⭐⭐ ⭐⭐(当前版本)
包体积增量 ~5MB (TFLite) ~8MB (LibTorch) ~3MB(精简后) ~6MB
社区/文档 ⭐⭐⭐⭐ ⭐⭐⭐⭐⭐ ⭐⭐⭐

注:评分基于 移动端图像任务 场景,仅供参考


书单推荐:别只看教程,读点硬核的

光靠博客和 YouTube 是不够的。这几个月我啃了几本书,真心推荐:

  1. 《Deep Learning with PyTorch》
    不是那种“7 天入门”的快餐书,而是由 PyTorch 官方团队写的实战指南。从张量操作到分布式训练,讲得透彻。我就是在第 8 章学会用 torch.jit.trace 导出模型的。

  2. 《Hands-On Machine Learning》(中文名《机器学习实战》)
    虽然偏理论,但第 14 章讲 TensorFlow Serving 和移动端部署的部分救了我命。作者 Aurélien Géron 真的是神人。

  3. 《Programming Rust》
    如果你也想用 Rust 玩 AI,这本书比官方 Book 更贴近工程实践。特别是 unsafe 和 FFI 章节,写插件时天天翻。


写在最后:UI 工程师也能玩转 AI?

回到开头的问题:一个写 Flutter 的,有必要搞深度学习吗?

我的答案是:看你想走到哪

如果你只想做个页面仔,那确实不用。但如果你想在杭州这种卷王之都拿高薪(阿里 P7 起步,网易 S4+),或者想进 AIGC 初创公司,全栈能力已经不够了,得是 “AI+端”复合型人才

现在我们组已经形成固定流程:我负责模型选型、训练脚本、移动端集成;后端同学用 Rust 写推理服务;测试用 Python 写自动化评估 pipeline。大家各司其职,但都懂一点对方的领域——这才是真正的高效协作。

至于那些曾经让我想砸电脑的报错?现在看都是勋章。上周产品又提了个新需求:“能不能识别人物姿态,自动加滤镜?” 我笑了笑,打开 Vim,新建了个 pose_estimation.py……

毕竟,程序员的浪漫,就是把不可能变成 git commit -m "feat: add AI magic"


P.S. 如果你在杭州,也在搞 Flutter + AI,欢迎约咖啡(或龙井茶)。咱们可以一起吐槽产品经理,顺便交流下如何用 Rust 写个更快的图像预处理库。

评论 0

最热最新
暂无评论
匿名用户Lv.1
0
影响力
0
文章
0
粉丝