关于投机采样speculative decoding我就不特别详细解释了
我在这里简单描述一下
小模型生成了接下来的n个标记,然后在大模型上进行n个并行推理,具体为:Prompt,Prompt + ST1,Prompt + ST1 + ST2 … Prompt + ST1 + ST2 … + STn。
(ST = 推测标记)
需要了解整个详细背景的,请看我原来的文章
OpenAI,Claude,Gemini御三家线上推理的杀手锏(Speculative Decoding)
这玩意本来大家都在用,因为省算力,同时降延迟。
但是OpenAI真的是一个非常产品化的公司,这点毋庸置疑,它居然把这么后台的东西都能做到前台feature来...
这个东西叫Predicted Outputs
其实投机采样的本质就是大模型给你checking小模型你decoding的对不,我们都知道decoding在现在的Transformer的体系里面,它就没个并行,因为是自回归的机制,别说Vllm,这块要是还不理解,建议理解一下Kv-cache的加速机理。
对同等遗传序列由于小模型Parameter少,层少,深度潜,那前向肯定比大模型快,这毋庸置疑。
但是有没有我连小模型都懒得用,直接上去checking
你别说,还真有可能,就是你把你认为高度重复的部分告诉我,那我把这个记住,你只要在prompt里标注出来它是被prediction的,那我就对这段不用复杂的自回归了,直接并行,咔一下就出结果了
也就是上来就来下面这样
Prompt,Prompt + ST1,Prompt + ST1 + ST2 … Prompt + ST1 + ST2 … + STn。
对用户的好处,那自然不必说,因为模型分为input和output token,你把本来应该output,token by token推理的output,给转成input了,input就可以prefill也就是玩kv-cache,也就可以被并行计算,那你说快不快,这也就节省了推理延迟,同时理论上,是省钱的,因为input token便宜,output贵。
其实道理就这么简单。
比如以下这段代码,你也不想改啥,你就想把username的部分,改成email
/// <summary>
/// Represents a user with a first name, last name, and username.
/// </summary>
public class User
{
/// <summary>
/// Gets or sets the user's first name.
/// </summary>
public string FirstName { get; set; }
/// <summary>
/// Gets or sets the user's last name.
/// </summary>
public string LastName { get; set; }
/// <summary>
/// Gets or sets the user's username.
/// </summary>
public string Username { get; set; }
}
那就直接把这个包进prediction里
import OpenAI from "openai";
const code = `
/// <summary>
/// Represents a user with a first name, last name, and username.
/// </summary>
public class User
{
/// <summary>
/// Gets or sets the user's first name.
/// </summary>
public string FirstName { get; set; }
/// <summary>
/// Gets or sets the user's last name.
/// </summary>
public string LastName { get; set; }
/// <summary>
/// Gets or sets the user's username.
/// </summary>
public string Username { get; set; }
}
`;
const openai = new OpenAI();
const completion = await openai.chat.completions.create({
model: "gpt-4o",
messages: [
{
role: "user",
content: "Replace the Username property with an Email property. Respond only with code, and with no markdown formatting."
},
{
role: "user",
content: code
}
],
prediction: {
type: "content",
content: code
}
});
// Inspect returned data
console.log(completion);
然后llm拿到了直接上来就投机采样checking了,关于这部分被包进来的内容,那自然是比推理快的。
费用和时间的对比:
对比还是挺明显的,返回结果从5.2s降到了3.3s,快省1半了,那是相当的快了,但是这个省钱并没有,反而比原来贵了0.1555 cents到0.2675 cents,贵了小一半。那不对呀,本来应该output变input我便宜了才对啊
OpenAI的人的解释是
如果预测是100%准确的,那么你不会看到费用差异。当模型与你的推测有差异时,我们会进行额外采样以“发现”新的标记,这就是我们为什么按完成时间费率对被拒绝的标记收费的原因。(果然是黑店)
不过确实是快,到是真的,这东西用好了,再加上其他的一些降低延迟的方法,例如端输出微调,并行回答,并行化投机采样的串行任务全都加上的话,那么你的LLM任务确实能达到非常好的优化,这本来是一门很科学的方法论,我们以后有时间再讲。
还是挺感慨和欣赏OpenAI做产品的力度和先进度的,所以随手写了一个小短文。很少有人能想到把这么后台的玩意变到前台来使用,还能赚钱