CodingTour
ARTS #222 | WAM 与 LMDeploy

家里多了一个可爱的小物件,萌萌的垃圾桶~

Algorithm

本周选择的算法题是:Smallest String With A Given Numeric Value

class Solution:
    def getSmallestString(self, n: int, k: int) -> str:
        result = []
        while n > 0:
            n -= 1
            d = min(k - n, 26)
            result.append(chr(ord('a') + d - 1))
            k -= d
        return ''.join(result[::-1])

Review

Watermark Anything

在 WAM 发布的第一时间学习了他们的论文,但有些疑问一直没有弄清楚,所以也没有表达过相关看法,简单聊聊。

Meta 提出的模型,它是基于分割的 extractor,这是和市面上大多数水印算法最大的区别。

在抗攻击能力上,支持:

  • 几何变换(恒等变换、调整大小、裁剪、旋转、水平翻转、透视变换)
  • 数值调整(JPEG 压缩、高斯模糊、中值滤波、亮度、对比度、饱和度、色相)
  • 以及几何变换带来的水印像素位置的变化

还有极具特色的多水印解码,这种场景发生在多个带水印图片组合在一起的时候(现实中最容易出现的情况),不像其他的解码方法,WAM 能解码出每一条水印。

同时利用了 GPU,在速度上可能有优势。

限制是模型对每条水印中能够嵌入的信息量上限为 32 位,单条肯定是不够用的,按监管的要求,至少要有四部分:

  • 素材 ID
  • 素材所有者
  • 入库时间
  • 用户 ID,方便追溯

所以难免需要写入多条,或者用类似短链接的方式做关联。

它虽然是个水印模型,但它不是为了解决水印问题而生的,更像是引入了 SAM 的感觉,就有点像是没有解决水印领域的核心问题,待验证。

Tip

统计当前目录下每个子目录的文件数量:

du -a | cut -d/ -f2 | sort | uniq -c | sort -nr

Share

本地运行 LMDeploy

最近入坑 LMDeploy,为了更好的观察 LMDeploy 的行为,在本地以 debug 的形式运行,踩了一些坑。。。

一份可在 vscode 中运行的配置:

{
    "name": "Python Debugger: Serve",
    "type": "debugpy",
    "request": "launch",
    "cwd": "${workspaceFolder}/lmdeploy",
    "module": "lmdeploy.cli.entrypoint",
    "console": "integratedTerminal",
    "args": [
        "serve",
        "api_server",
        "/path/to/model",
        "--backend", "turbomind",
        "--server-port", "23333",
    ]
},

需要在 entrypoint 里增加 main 入口:

关于找不到 _turbomind 的问题

turbomind 是 LMDeploy 自研实现的推理引擎,是一个用 C++ 编写的高性能推理库,核心功能:

  1. 高效的 Transformer 推理实现,基于 NVIDIA FasterTransformer
  2. 支持张量并行(Tensor Parallel)
  3. KV Cache 管理
  4. batch 优化
  5. 支持动态形状
  6. 性能优化:
    1. CUDA kernel 优化
    2. 内存管理优化
    3. 计算流水线优化
  7. 支持 AWQ、W4A16 等量化格式

引用位置: ~/lmdeploy/turbomind/turbomind.py

一开始想绕过编译,直接用预编译好的 _turbomind,LMDeploy 也通过另外一个仓库提供了各种版本:

https://github.com/zhyncs/lmdeploy-build

能链接到了,但在运行过程中会各种报错,找不到 yaml-cpp 等等。。。

通过 ldd 指令检查 so 文件确实没有,其实和 yaml-cpp 无关:

尝试自己编译 _turbomind,各种依赖缺失:

分析 CMakeLists,能不依赖就不依赖,比如这些依赖只在 BUILD_MULTI_GPU 开启时才需要(默认开启),那么我们就可以直接关闭该配置:

感觉快成功了:

安装 pybind,解决 binding 问题后,终于可以了:

构建指令:

# 创建 bld 和进行本地编译
mkdir bld && cd bld && bash ../generate.sh && ninja -j$(nproc)

# 从 bld 中切到 lmdeploy 子目录并设置软链接
cd ../lmdeploy && ln -s ../bld/lib .

_turbomind 架构分析:

_turbomind (C++ 层)
    |
    +-- CUDA Kernels (底层计算)
    |
    +-- Memory Manager (内存管理)
    |
    +-- Pipeline Scheduler (调度器)
    |
Python 绑定层
    |
    +-- lmdeploy.turbomind (Python API)

从实现上看,turbomind 是连接 Python 层 LMDeploy 和底层 CUDA 计算的中间件,负责高效地执行实际的模型推理计算,这就是为什么编译和正确加载 _turbomind 对于使用 turbomind 后端至关重要,否则会退化为 PyTorchEngine。