豆包AI手机背后的VL模型

根据公开报道,豆包AI手机使用的模型是基于UI-TARS在手机上优化的闭源版本,UI-TARS是在阿里的Qwen2 VL上做SFT得来的,目前开源了7b的版本(Qwen2 VL开源了3b-72b的模型)。这里不再多介绍Qwen(Qwen2 VL其实也已经有了UI Operation的功能),主要关注UI-TARS模型在Qwen2 VL上的进一步改进,分数据和训练两部分。

数据

其中最核心的部分在于更精细的数据构造,将每个UI截图从底向上构建了详细的标注信息,从最小的按钮,再到整体布局,甚至状态变换前后的caption标注。

数据类型说明
单个元素的描述(Element Description)单个元素的信息,包括类型(按钮、输入框等,类似前端的组件分类)、视觉描述(颜色、外观等)、位置信息(空间上的上下左右相对信息)、元素功能(例如删除邮件)
UI的详细描述(Dense Caption)一大段详细的文本来描述整个界面
状态转移的描述(State Transition Caption)将一组图像放在一起,用来描述前后的变化以及是否进行了按键等操作
问答(QA)关于该UI界面的问题与回答
标记指示(Set of Mark)在UI中进行一些标记(例如框起来一部份),并基于这些标记构造QA

image-20251218225315177

论文中提到总共构造了50billion token的数据量用于训练7B和72B的模型(Qwen2 VL的预训练就已经使用了1.4 trillion token的数据)

除了这些数据之外,在后面的SFT训练阶段还额外构造了纠错的数据对(错误+纠错),告诉Agent在UI上已经点错了之后,该怎么补救回来,这也是一大亮点(构造这些复杂且深入标注的数据集看上去要花很多钱。。。)

训练

UI-TARS的训练过程可以分为四个步骤:预训练、SFT和DPO

1. 预训练

使用上文所提到的全部数据进行预训练,相当于在Qwen2 VL的基础上拿这些特定的数据继续跑,用ChatGPT估算了一下,50billion token的数据量预训练7B和72B的模型,换算成H200算力大概是

  • 7B:≈ 49.2 – 70.2 H200 GPU-days
  • 72B:≈ 505.6 – 722.2 H200 GPU-days

看着还行,用上128卡的话还是挺快的

2. SFT

这个阶段更为精细,不仅使用了上文数据中高质量的部分,还用了半自动产生的trace数据+纠错数据进一步强化序列操作的能力

Trace

对trace这类序列数据,原生的数据集很稀少,这里用了一种半自动的方式来产生数据+迭代模型。每个迭代都创建一堆任务让模型去跑,再通过人工标注、模型打分等等方式,筛选出优质的trace数据用于下一轮模型的训练,反复用模型自己产生的优质数据进行迭代。

纠错(Reflection Tuning)

纠错数据是将模型的错误trace拿出来重新标记后得到正样本,再用正样本作为SFT的训练数据,正样本的构造方式分为两种:

  • 直接将错误操作改为正确操作,让模型尽量不要犯错

    {T=(instruction,(o1,t1,a1),(o2,t2,a2),,(oτ,tτ,aτ))T+=(instruction,(o1,t1,a1),(o2,t2,a2),,(oτ,tτ,aτ))\left\{ \begin{aligned} \mathcal{T}_{-} &= \bigl( \text{instruction}, (o_1, t_1, a_1), (o_2, t_2, a_2), \ldots, (o_\tau, \textcolor{red}{t_\tau}, \textcolor{red}{a_\tau}) \bigr) \\[6pt] \mathcal{T}_{+} &= \bigl( \text{instruction}, (o_1, t_1, a_1), (o_2, t_2, a_2), \ldots, (o_\tau, \textcolor{green}{t_\tau^{*}}, \textcolor{green}{a_\tau^{*}}) \bigr) \end{aligned} \right.
  • 将错误操作的下一步改为纠错的操作,让模型在犯错之后知道如何改错

{T=(instruction,(o1,t1,a1),(o2,t2,a2),,(oτ,tτ,aτ),(oτ+1,tτ+1,aτ+1))T+=(instruction,(o1,t1,a1),(o2,t2,a2),,(oτ,tτ,aτ),(oτ+1,tτ+1,aτ+1))\left\{ \begin{aligned} \mathcal{T}_{-} &= \bigl( \text{instruction}, (o_1, t_1, a_1), (o_2, t_2, a_2), \ldots, (o_\tau, \textcolor{red}{t_\tau}, \textcolor{red}{a_\tau}), (o_{\tau+1}, t_{\tau+1}, a_{\tau+1}) \bigr) \\[6pt] \mathcal{T}_{+} &= \bigl( \text{instruction}, (o_1, t_1, a_1), (o_2, t_2, a_2), \ldots, (o_\tau, \textcolor{red}{t_\tau}, \textcolor{red}{a_\tau}), (o_{\tau+1}, \textcolor{green}{t_{\tau+1}^{*}}, \textcolor{green}{a_{\tau+1}^{*}}) \bigr) \end{aligned} \right.

3. DPO

在前面的SFT中只是将错误样本改为正样本后进行训练,并没有利用负样本本身的信息,DPO的思想有点像SVM,不仅要把正负样本分开,还要让他们之间的距离尽可能拉大。

LDPO(θ)=Eτ[logσ(βlogπθ(aτsτ)πSFT(aτsτ)βlogπθ(aτsτ)πSFT(aτsτ))]\mathcal{L}_{\text{DPO}}(\theta) = -\mathbb{E}_\tau \Big[ \log \sigma\big( \beta \log \tfrac{\pi_\theta(a'_\tau|s_\tau)}{\pi_{\text{SFT}}(a'_\tau|s_\tau)} - \beta \log \tfrac{\pi_\theta(a_\tau|s_\tau)}{\pi_{\text{SFT}}(a_\tau|s_\tau)} \big) \Big]

DPO构造了上面的损失函数进行训练,log中的比值代表了训练中的模型πθ\pi_\theta相比SFT的模型πSFT\pi_{SFT}的倾向,前者是在正样本上的倾向对比,后者是在负样本的倾向对比,优化目标就是让前者尽量大,后者尽量小,即训练中的模型要比SFT旧模型更倾向于正样本,且远离负样本。这样可以让模型对于正负样本的倾向更为清晰明确

实验部分就不多赘述了,原论文中在perception、grounding等等方面都有很详实的实验,总的来说相比原版Qwen2 VL还是有不小的提升,另外论文中也使用了reasoning等方法进一步提升效果,相对属于比较通用的技巧,这里也不多重复了