【Code Generation】Instruction Tuning for Secure Code Generation

Instruction Tuning for Secure Code Generation, ICML’24

构建数据集,提出了SafeCoder方法,用Instruction Tuning来训练LM,使其能生成secure and functional correct的代码

SafeCoder

  1. Standard Instruction Tuning
    D s t d D^{std} Dstd是instruction tuning的数据集,每个样本 ( i , o ) (i, o) (i,o)由一个指令 i i i和对应的输出 o o o组成。标准的instruction tuning是fine-tune模型,让模型在给出 i i i的基础上,生成 o o o,对应的negative log-likelihood loss(负对数似然损失)是:

L std ( i , o ) = − log ⁡ P ( o ∣ i ) = − ∑ t = 1 ∣ o ∣ log ⁡ P ( o t ∣ o < t , i ) L^{\text{std}}(i, o) = - \log P(o \mid i) = - \sum_{t=1}^{|o|} \log P(o_t \mid o_{<t}, i) Lstd(i,o)=logP(oi)=t=1ologP(oto<t,i)

  1. Security Instruction Tuning
    D s e c D^{sec} Dsec由三元祖样本 ( i , o s e c , o v u l ) (i, o^{sec}, o^{vul}) (i,osec,ovul)组成,其中 i i i为指令,它指定了编程任务要的功能需求。 o s e c o^{sec} osec o v u l o^{vul} ovul分别对应包含和不包含vulnerabilities的完成代码,它们只在security上有区别,其他都是一样的。
    security fine-tuning只关注security-related tokens of o s e c o^{sec} osec o v u l o^{vul} ovul,通过计算token-level下 o s e c o^{sec} osec o v u l o^{vul} ovul的区别,可以找到security-related tokens。构造一个mask向量 m s e c m^{sec} msec m s e c m^{sec} msec和o^{sec}长度相同,每个元素都为0或1:当 o s e c o^{sec} osec t t t位置的token o t s e c o_t^{sec} otsec为security-related token时, m t s e c m_t^{sec} mtsec为1,反之为0。同样的,通过 o v u l o^{vul} ovul,可以得到 m v u l m^{vul} mvul
    A masked negetive log-likelihood loss L s e c L^{sec} Lsec

L sec ( i , o s e c , m s e c ) = − ∑ t = 1 ∣ o s e c ∣ m t s e c ⋅ log ⁡ P ( o t s e c ∣ o < t s e c , i ) L^{\text{sec}}(i, o^{sec}, m^{sec}) = - \sum_{t=1}^{|o^{sec}|} m_t^{sec} \cdot \log P(o_t^{sec} \mid o_{<t}^{sec}, i) Lsec(i,osec,msec)=t=1osecmtseclogP(otseco<tsec,i)

A maksed negative log-unlikelihood loss L v u l L^{vul} Lvul

L vul ( i , o v u l , m v u l ) = − ∑ t = 1 ∣ o v u l ∣ m t v u l ⋅ log ⁡ ( 1 − P ( o t v u l ∣ o < t v u l , i ) ) L^{\text{vul}}(i, o^{vul}, m^{vul}) = - \sum_{t=1}^{|o^{vul}|} m_t^{vul} \cdot \log (1 - P(o_t^{vul} \mid o_{<t}^{vul}, i)) Lvul(i,ovul,mvul)=t=1ovulmtvullog(1P(otvulo<tvul,i))

L s e c L^{sec} Lsec L v u l L^{vul} Lvul使用 m s e c m^{sec} msec m v u l m^{vul} mvul来mask仅和security有关的部分,通过最小化 L s e c L^{sec} Lsec L v u l L^{vul} Lvul,能够让LLM输出更安全的code。

  1. 结合Standard Instruction Tuning和Security Tuning
    训练的时候,如果样本来自 D s t d D^{std} Dstd,则用标准 L s t d L^{std} Lstd,如果来自 D s e c D^{sec} Dsec,则用security tuning

Dataset Construction

  1. 用lightweight heuristics, such as keyword matching,选择commits likely to fix vulnerabilities。keywords和considered CWE相关,额外还要求checks the changes within the commit, excluding unsupported file types and commits that edit too many lines and files。规定changes不超过40lines和2个files,这样可以尽量保证changes只和security相关(基于假设:The underlying assumption is that too many changes typically indicate functional edits or refactorings.)
  2. 用CodeQL检测vulnerability,如果前一个version含有vulnerability,后一个version不含,则commit被认为是a vulnerability fix。对于这个commit,before version被认为是 o v u l o^{vul} ovul,post version被认为是 o s e c o^{sec} osec
  3. 基于 ( o s e c , o v u l ) (o^{sec}, o^{vul}) (osec,ovul)query GPT-4生成对应的指令 i i i

Large Language Models for Code: Security Hardening and Adversarial Testing, CCS’23

通过security hardening和adversarial testing,实现controlled code generation

Controlled Code Generation: SVEN

不涉及重新训练模型,类似于prefix tuning。在原始的prompt之外,额外一个property c c c c = { s e c , v u l } c = \{sec, vul\} c={sec,vul}。如果 c = s e c c = sec c=sec,则进行security hardening,否则,进行adversarial testing。
1. Inference
其实就是prefix tuning。把SVEN当成独立的模块(其实就是向量),只需要更新训练向量,不涉及LM的训练
2. Training
和SafeCoder类似,对于一个training sample x x x,创建一个长度相同的向量 m m m,如果 x t x_t xt在被改变的区域,则将 m t m_t mt设为1,否则设为0。
有三种diff level:program,line和character。在这三种level里,character肯定最准确,但是如果fix vulnerability只涉及在before version里加上一些代码,那么在 c = v u l c = vul c=vul的时候, m m m中的全部元素皆为0,没办法进行训练。因此,采用了混合策略,当 c = s e c c = sec c=sec时,使用character-level,当 c = v u l c=vul c=vul时,采用line-level。
因此,数据集中的一个样本是三元组 ( x , m , c ) (x, m, c) (x,m,c),c代表property。相对应的有 ¬ c \neg c ¬c

L LM = − ∑ t = 1 ∣ x ∣ m t ⋅ log ⁡ P ( x t ∣ h < t , c ) L_{\text{LM}} = - \sum_{t=1}^{|x|} m_t \cdot \log P(x_t \mid h_{<t}, c) LLM=t=1xmtlogP(xth<t,c)

这个公式用来鼓励SVEN生成含有 c c c属性的样本 x x x

L C T = − ∑ t = 1 ∣ x ∣ m t ⋅ log ⁡ ( P ( x t ∣ h < t , c ) P ( x t ∣ h < t , c ) + P ( x t ∣ h < t , ¬ c ) ) L_{CT} = - \sum_{t=1}^{|x|} m_t \cdot \log \left( \frac{P(x_t | h_{<t}, c)}{P(x_t | h_{<t}, c) + P(x_t | h_{<t}, \neg c)} \right) LCT=t=1xmtlog(P(xth<t,c)+P(xth<t,¬c)P(xth<t,c))

L C T L_{CT} LCT用于对比由不同前缀生成的序列的条件下一个令牌的概率。这个公式用来鼓励生成具有特定属性 c c c的序列,同时避免生成具有相反属性 ¬ c \neg c ¬c的序列。

L K L = ∑ t = 1 ∣ x ∣ ( ¬ m t ) ⋅ KL ( P ( x t ∣ h < t , c ) ∣ P ( x t ∣ h < t ) ) L_{KL} = \sum_{t=1}^{|x|} ( \neg m_t ) \cdot \text{KL}( P(x_t | h_{<t}, c) | P(x_t | h_{<t}) ) LKL=t=1x(¬mt)KL(P(xth<t,c)P(xth<t))

L K L L_{KL} LKL损失来计算 P ( x t ∣ h < t , c ) P(x_t | h_{<t}, c) P(xth<t,c) P ( x ∣ h < t ) P(x | h_{<t}) P(xh<t)之间的距离,鼓励SVEN和原始LM产生的令牌级概率分布之间的相似性。

Overall Loss Function
L = L L M + w C T ⋅ L C T + w K L ⋅ L K L L = L_{LM} + w_{CT} \cdot L_{CT} + w_{KL} \cdot L_{KL} L=LLM+wCTLCT+wKLLKL

对比

SVEN相对于SafeCoder,其实是作用于code completion,额外加了KL Divergence来进行functiona correct的control。但实际上用于code generation的时候,KL的效果反而很差。
下图描述了如何将SVEN用于code generation和SafeCoder进行对比的细节
在这里插入图片描述

思考

在看完ICML’24之后,发现了一个问题,对于Standard Instruction Tuning,对于Code LLMs,用了Code Evol-Instruct这个数据集,对于general LLMs,用了LMSYS-Chat-1M数据集。疑惑的点在于,如果这两个数据集包含代码样本,怎么能够保证这些代码样本的安全性?于是去huggingface上看这两个数据集的情况,发现LMSYS-Chat-1M只涉及conversations,而Code Evol-Instruct则全是和代码相关的数据。后来觉得,可能是因为对于Code Evol-Instruct的Standard Instruction Tuning,并不涉及安全性的考量,只是用到了最普通的unmasked的negative log-likelihood loss进行fine-tune。对于安全性这一点,则是用security相关的数据集进行masked loss训练,所以standard instruction tuning的数据集中是否含有unsecure code并不影响。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值