快来与 CodeQwen1.5 结对编程!

本文涉及的产品
交互式建模 PAI-DSW,5000CU*H 3个月
简介: 今天,来自 Qwen1.5 开源家族的新成员,代码专家模型 CodeQwen1.5开源!CodeQwen1.5 基于 Qwen 语言模型初始化,拥有 7B 参数的模型,其拥有 GQA 架构,经过了 ~3T tokens 代码相关的数据进行预训练,共计支持 92 种编程语言、且最长支持 64K 的上下文输入。效果方面,CodeQwen1.5 展现出了优秀的代码生成、长序列建模、代码修改、SQL 能力等,该模型可以大大提高开发人员的工作效率,并在不同的技术环境中简化软件开发工作流程。

简介

代码助手,是一种基于 LLMs 的智能化的编程工具,它可以帮助程序员更高效、更准确的编写代码,使得整个软件开发过程更加流畅和高效。然而流行的代码助手,比如 Github Copilot,依赖于闭源的商业模型,不仅昂贵还会引起如隐私、安全、版权等方面的担忧。幸运的是,开源社区正在致力于打造开放代码模型来实现开放的代码助手。近期涌现出了一批优秀的 Open CodeLLMs,比如 StarCoder2、CodeLlama、DeepSeek-Coder 等,提供了一条新的路径,但仍然值得探索。

image.png

今天,来自 Qwen1.5 开源家族的新成员,代码专家模型 CodeQwen1.5开源!CodeQwen1.5 基于 Qwen 语言模型初始化,拥有 7B 参数的模型,其拥有 GQA 架构,经过了 ~3T tokens 代码相关的数据进行预训练,共计支持 92 种编程语言、且最长支持 64K 的上下文输入。效果方面,CodeQwen1.5 展现出了优秀的代码生成、长序列建模、代码修改、SQL 能力等,该模型可以大大提高开发人员的工作效率,并在不同的技术环境中简化软件开发工作流程。

CodeQwen 是基础的 Coder

代码生成是大语言模型的关键能力之一,期待模型将自然语言指令转换为具有精确的、可执行的代码。仅拥有 70 亿参数的 CodeQwen1.5 在基础代码生成能力上已经超过了更尺寸的模型,进一步缩小了开源代码 LLM 和 GPT-4 之间的编码能力差距。CodeQwen1.5 对 HumanEval 和 MBPP 进行了评估,以提供下面清晰的比较。

Model

Size

HumanEval

0-shot

HumanEval+

0-shot

MBPP

0-shot

MBPP+

0-shot

MBPP

3-shot

Base Model

CodeLlama-Base

7B

33.5

25.6

52.1

41.6

38.6

StarCoder2

7B

35.4

29.9

54.4

45.6

51.0

DeepSeek-Coder-Base

6.7B

47.6

39.6

70.2

56.6

60.6

CodeQwen1.5

7B

51.8

45.7

72.2

60.2

61.8

Chat Model

GPT-3.5-Turbo

-

76.8

70.7

82.5

69.7

70.8

GPT-4-Turbo (Nov 2023)

-

85.4

81.7

83.5

70.7

80.0

DeepSeek-Coder-Instruct

6.7B

78.6

70.1

73.2

63.4

65.4

CodeQwen1.5-Chat

7B

83.5

78.7

77.7

67.2

70.6

除了流行的 Humaneval 与 MBPP 外,在 LiveCodeBench (2023-09-01->2024-04-01)上对 CodeQwen1.5 进行评估,结果展示出了 CodeQwen1.5 具竞争力的效果。但值得注意的是,在预训练语料中包含的 LeetCode 数据可能对该评测有帮助。

image.png

上述的评估主要围绕 Python 能力,但 CodeQwen1.5 不仅仅是 Python 专家,还是一个多编程语言专家。在 MultiPL-E 的 8 种主流语言(Python、C++、Java、PHP、TypeScript、C#、Bash,JavaScript)上对 CodeQwen1.5 进行全面评估。这些结果证明了 CodeQwen1.5 强大的编程能力。

image.png

CodeQwen 是长序列 Coder

长序列能力对于代码模型来说至关重要,是理解仓库级别代码、成为 Code Agent 的核心能力。而当前的代码模型对于长度的支持仍然非常有限,阻碍了其实际应用的潜力。CodeQwen1.5 希望进一步推进开源代码模型在长序列建模上的进展,收集并构造了仓库级别的长序列代码数据进行预训练,通过精细的数据配比和组织方式,使其最终可以最长支持 64K 的输入长度。

评估一:选择了不在 CodeQwen1.5 训练数据、最新产生的高质量 github 仓库 (来自 2024-3-28 的 Github Trending 仓库),来观测其长序列建模的有效性。下图可以发现在序列不断增长的情况下, CodeQwen1.5 的 PPL 仍然可以保持下降的趋势。

企业微信截图_17133447569950.png

评估二:一个名为 Needle in the Code 的合成任务, 其效仿文本领域流行的长序列评测。在一个较长的代码库(CodeQwen选择了 Megatron,向其对开源 LLMs 的贡献致敬)的不同位置中插入非常简单的一个自定义函数,测试模型能否在代码库最后重复这个函数。下图可以发现,CodeQwen 能够在 64k 长度范围内仍然可以很好的完成这个任务。

image.png

无论是评估一还是评估二,都是初步的、基础的评估方式,仅仅是一个起点而非全部。但是,对于 Chat 模型,希望用更实际的任务来评估其长序列能力。

评估三:SWE Bench 的目的是解决真实软件开发中的问题,给定一个代码仓库和 issue,期待 LLMs/Agents 能够给出相应的 commit patch 来解决这个 issue。SWE Bench 对 Code LLMs 的长序列能力提出了更高的要求,不仅需要理解代码仓库,还要生成可通过单测的代码。

image.png

目前 SWEBench 竞技场上的玩家都依赖闭源模型, CodeQwen1.5 首次入局,尽管仅有 0.89 的分数但仍强于 ChatGPT3.5,这展示了开源代码模型与专有模型的竞争力尽管尚处于初期,但具有潜力。

CodeQwen 是优秀的代码修改者

一个好的代码助手不仅可以根据指令生成代码,还能够针对已有代码或者新的需求进行修改或错误修复。为此评估了 CodeQwen1.5 在代码修改方面的能力。首先在关注 CodeEditorBench,涉及到 Debug、Translate、Switch、Polish 等四个方面的代码修改能力,结果表明 CodeQwen1.5 在 7B 规模上达到了比较好的效果。

image.png

CodeQwen 是出色的 SQL 专家

CodeQwen1.5 可以作为一个智能的 SQL 专家,弥合了非编程专业人士与高效数据交互之间的差距。它通过自然语言使无编程专业知识的用户能够查询数据库,从而缓解了与SQL相关的陡峭学习曲线。在两个流行的文本到SQL基准测试Spider和Bird上评估了CodeQwen1.5-Chat的性能。实验结果显示,CodeQwen1.5在接近GPT-4的位置排名第二(结果来自DIN-SQL,一种 SOTA 的提示方法)。这一出色的表现得益于在预训练和微调阶段均广泛利用了合成数据。合成数据具有可扩展性、可验证性和多样性的特点,在增强CodeQwen1.5的SQL能力方面已被证明是一项具有吸引力的未来研究领域。

image.png

模型体验

模型测试效果很不错:

image.png

体验链接:

https://modelscope.cn/studios/qwen/CodeQwen1.5-7b-Chat-demo

模型链接和下载

CodeQwen模型系列现已在ModelScope社区开源,包括:

CodeQwen1.5-7B-Chat:

https://modelscope.cn/models/qwen/CodeQwen1.5-7B-Chat

CodeQwen1.5-7B-Chat-GGUF:

https://modelscope.cn/models/qwen/CodeQwen1.5-7B-Chat-GGUF

CodeQwen1.5-7B:

https://modelscope.cn/models/qwen/CodeQwen1.5-7B

CodeQwen1.5-7B-Chat-AWQ:

https://modelscope.cn/models/qwen/CodeQwen1.5-7B-Chat-AWQ

社区支持通过git或者SDK直接下载模型的repo:

from modelscope import snapshot_download
model_dir = snapshot_download("qwen/CodeQwen1.5-7B-Chat")

模型推理

环境配置和安装:

  1. python 3.10及以上版本
  2. pytorch推荐2.0及以上版本
  3. 建议使用CUDA 11.8及以上

本文在魔搭社区免费提供的GPU免费算力上体验:

image.png

模型推理

from modelscope import AutoModelForCausalLM, AutoTokenizer
device = "cuda" # the device to load the model onto
model = AutoModelForCausalLM.from_pretrained(
    "qwen/CodeQwen1.5-7B-Chat",
    torch_dtype="auto",
    device_map="auto"
)
tokenizer = AutoTokenizer.from_pretrained("qwen/CodeQwen1.5-7B-Chat")
prompt = "Write a quicksort algorithm in python."
messages = [
    {"role": "system", "content": "You are a helpful assistant."},
    {"role": "user", "content": prompt}
]
text = tokenizer.apply_chat_template(
    messages,
    tokenize=False,
    add_generation_prompt=True
)
model_inputs = tokenizer([text], return_tensors="pt").to(device)
generated_ids = model.generate(
    model_inputs.input_ids,
    max_new_tokens=512
)
generated_ids = [
    output_ids[len(input_ids):] for input_ids, output_ids in zip(model_inputs.input_ids, generated_ids)
]
response = tokenizer.batch_decode(generated_ids, skip_special_tokens=True)[0]
print(response)

显存占用:

image.png

可见,GQA的架构,对于显存占有有一定的优化效果。

模型微调和微调后推理

我们使用swift来对模型进行微调, swift是魔搭社区官方提供的LLM&AIGC模型微调推理框架.

微调代码开源地址:

https://github.com/modelscope/swift

我们使用leetcode-python-en数据集进行微调. 任务是: 解python程序题

环境准备:

git clone https://github.com/modelscope/swift.git
cd swift
pip install .[llm]

微调脚本: LoRA

# https://github.com/modelscope/swift/blob/main/examples/pytorch/llm/scripts/codeqwen1half_7b_chat/lora/sft.sh
# Experimental environment: A100
# 25GB GPU memory
CUDA_VISIBLE_DEVICES=0 \
swift sft \
    --model_type codeqwen1half-7b-chat \
    --model_revision master \
    --sft_type lora \
    --tuner_backend peft \
    --dtype AUTO \
    --output_dir output \
    --ddp_backend nccl \
    --dataset leetcode-python-en \
    --train_dataset_sample -1 \
    --num_train_epochs 3 \
    --max_length 2048 \
    --check_dataset_strategy warning \
    --lora_rank 8 \
    --lora_alpha 32 \
    --lora_dropout_p 0.05 \
    --lora_target_modules DEFAULT \
    --gradient_checkpointing true \
    --batch_size 1 \
    --weight_decay 0.1 \
    --learning_rate 1e-4 \
    --gradient_accumulation_steps 16 \
    --max_grad_norm 0.5 \
    --warmup_ratio 0.03 \
    --eval_steps 100 \
    --save_steps 100 \
    --save_total_limit 2 \
    --logging_steps 10 \

训练过程也支持本地数据集,需要指定如下参数:

--custom_train_dataset_path xxx.jsonl \
--custom_val_dataset_path yyy.jsonl \

自定义数据集的格式可以参考:

https://github.com/modelscope/swift/blob/main/docs/source/LLM/%E8%87%AA%E5%AE%9A%E4%B9%89%E4%B8%8E%E6%8B%93%E5%B1%95.md#%E6%B3%A8%E5%86%8C%E6%95%B0%E6%8D%AE%E9%9B%86%E7%9A%84%E6%96%B9%E5%BC%8F

微调后推理脚本: (这里的ckpt_dir需要修改为训练生成的checkpoint文件夹)

# Experimental environment: 3090
CUDA_VISIBLE_DEVICES=0 \
swift infer \
    --ckpt_dir "output/codeqwen1half-7b-chat/vx-xxx/checkpoint-xxx" \
    --load_dataset_config true \
    --max_new_tokens 2048 \
    --temperature 0.1 \
    --top_p 0.7 \
    --repetition_penalty 1. \
    --do_sample true \
    --merge_lora false \

微调的可视化结果

训练loss:

image.png


训练后生成样例:

[PROMPT]<|im_start|>system
You are a helpful assistant.<|im_end|>
<|im_start|>user
Given an `m x n` integer matrix `matrix`, if an element is `0`, set its entire row and column to `0`'s.
You must do it [in place](https://en.wikipedia.org/wiki/In-place_algorithm).
**Example 1:**
**Input:** matrix = \[\[1,1,1\],\[1,0,1\],\[1,1,1\]\]
**Output:** \[\[1,0,1\],\[0,0,0\],\[1,0,1\]\]
**Example 2:**
**Input:** matrix = \[\[0,1,2,0\],\[3,4,5,2\],\[1,3,1,5\]\]
**Output:** \[\[0,0,0,0\],\[0,4,5,0\],\[0,3,1,0\]\]
**Constraints:**
*   `m == matrix.length`
*   `n == matrix[0].length`
*   `1 <= m, n <= 200`
*   `-231 <= matrix[i][j] <= 231 - 1`
**Follow up:**
*   A straightforward solution using `O(mn)` space is probably a bad idea.
*   A simple improvement uses `O(m + n)` space, but still not the best solution.
*   Could you devise a constant space solution?
<|im_end|>
<|im_start|>assistant
[OUTPUT]```python
def setZeroes(matrix):
    m, n = len(matrix), len(matrix[0])
    rows, cols = set(), set()
    for i in range(m):
        for j in range(n):
            if matrix[i][j] == 0:
                rows.add(i)
                cols.add(j)
    for i in rows:
        for j in range(n):
            matrix[i][j] = 0
    for j in cols:
        for i in range(m):
            matrix[i][j] = 0
```
The algorithm first iterates through the matrix to find the rows and columns that need to be set to 0. It uses two sets, `rows` and `cols`, to store the indices of the rows and columns that need to be set to 0.
After finding the rows and columns, the algorithm iterates through the rows and sets all the elements in that row to 0. Then, it iterates through the columns and sets all the elements in that column to 0.
This algorithm has a time complexity of O(m * n) and a space complexity of O(m + n), which is the best possible for this problem.<|im_end|>
[LABELS]```python
def setZeroes(matrix):
    rows = len(matrix)
    cols = len(matrix[0])
    firstRow, firstCol = False, False
    for i in range(rows):
        for j in range(cols):
            if matrix[i][j] == 0:
                if i == 0: firstRow = True
                if j == 0: firstCol = True
                matrix[i][0] = 0
                matrix[0][j] = 0
    for i in range(1, rows):
        for j in range(1, cols):
            if matrix[i][0] == 0 or matrix[0][j] == 0:
                matrix[i][j] = 0
    if firstRow:
        for j in range(cols):
            matrix[0][j] = 0
    if firstCol:
        for i in range(rows):
            matrix[i][0] = 0
```
1. Iterate over the matrix, marking the first element of the row and column for every 0 encountered.
2. Set a flag if the first row or the first column has a 0.
3. Iterate over the matrix, ignoring the first row and first column. Set the element to 0 if the corresponding first row or column is marked.
4. Finally, set the first row and column to 0 if their flags are set.
--------------------------------------------------
[PROMPT]<|im_start|>system
You are a helpful assistant.<|im_end|>
<|im_start|>user
Given an array `nums` of size `n`, return _the majority element_.
The majority element is the element that appears more than `⌊n / 2⌋` times. You may assume that the majority element always exists in the array.
**Example 1:**
**Input:** nums = \[3,2,3\]
**Output:** 3
**Example 2:**
**Input:** nums = \[2,2,1,1,1,2,2\]
**Output:** 2
**Constraints:**
*   `n == nums.length`
*   `1 <= n <= 5 * 104`
*   `-109 <= nums[i] <= 109`
**Follow-up:** Could you solve the problem in linear time and in `O(1)` space?
<|im_end|>
<|im_start|>assistant
[OUTPUT]```python
def majorityElement(nums):
    count = 0
    candidate = None
    for num in nums:
        if count == 0:
            candidate = num
        count += (1 if num == candidate else -1)
    return candidate
```
The algorithm uses a modified version of the Boyer-Moore Voting Algorithm. It initializes a counter `count` to 0 and a candidate variable to store the potential majority element. Then, it iterates through the input array `nums`. If the counter is 0, it updates the candidate to the current element. If the current element is equal to the candidate, it increments the counter; otherwise, it decrements the counter. After the iteration, the candidate variable will hold the majority element.
This algorithm has a linear time complexity of O(n) and constant space complexity of O(1), making it efficient for the follow-up question.<|im_end|>
[LABELS]```python
def majority_element(nums):
    count = 0
    candidate = None
    for num in nums:
        if count == 0:
            candidate = num
        count += (num == candidate) - (num != candidate)
    return candidate
```
The algorithm used here is called the Boyer-Moore Majority Vote algorithm. It works by initializing a candidate element and a count. Then, we iterate through the given array. If the count is 0, we set the candidate to the current element in the array. Then we update the count by adding 1 if the current element is equal to the candidate, or subtracting 1 otherwise. At the end of the iteration, the candidate will have the majority element.
The algorithm works because if there is a majority element, it will always appear more than the sum of all other elements, so the count will not be 0 at the end.

资源消耗

image.png

结论

CodeQwen1.5-7B 及 CodeQwen1.5-7B-Chat,一个开放的、多面体的 Code LLM,希望这个模型能在 Code 助手、Code Agent 等方面为社区贡献。未来通义千问团队仍然会积极投入代码智能建设,实现真正的 AI 程序员。

https://modelscope.cn/studios/qwen/CodeQwen1.5-7b-Chat-demo/

相关文章
|
4月前
|
安全 Java Android开发
程序世界的奇幻旅程:从码农梦想家到JAVA开发实践者
程序世界的奇幻旅程:从码农梦想家到JAVA开发实践者
26 0
|
5月前
|
开发者
第十一期乘风伯乐活动开启,快来推荐你身边热爱分享的技术达人吧
乘风伯乐奖,面向阿里云开发者社区已入驻乘风者计划的博主(技术/星级/专家),邀请用户入驻乘风者计划即可获得乘风者定制周边等实物奖励。本期面向阿里云开发者社区寻找100位乘风伯乐,邀请人数月度TOP 1 获奖者(大于108人)可获得cherry樱桃MX3.0S键盘及伯乐之星证书!
1679 172
第十一期乘风伯乐活动开启,快来推荐你身边热爱分享的技术达人吧
|
7月前
|
监控 架构师 安全
速读《技术人修炼之道》-看到最后定有收获
最近一段时间读完了《技术人修炼之道》,书中内容涵盖了作者多年实践和思想的结晶,整体读来有许多观点深有同感,也学习到了一些新的理念,在这里感谢黄哲铿老师。本文主要结合我自身十几年的IT行业经验,以及创业多年的感受,从书中提炼了一些个人觉得非常有价值并且好落地的点进行分享。
|
开发者
【开发者7日学】求职达人训练营上线啦~快来打卡赢好礼
阿里云培训中心联合开发者社区推出求职达人训练营7天学习活动,由阿里师兄们围绕行业介绍、职业选择、职场经验等内容进行分享,帮助大学生快速了解真实职场环境、提升实用求职技巧、培养必备职业素养等。
【开发者7日学】求职达人训练营上线啦~快来打卡赢好礼
乘风者计划的体会
体会了计划后,颇有感触,更加了解计算机的历史,更加明白了科技对于国家的发展有多大的影响,更坚定了我对计算机的魅力加深,在未来的学习希望能提高自我学习的能力,促进自身发展,为社会做出自己的贡献,我国科技实力和创新能力的全面提升,为经济发展、民生改善和国家安全提供了重要支撑,为推进科技自立自强、建设科技强国开辟了广阔空间,我们比历史上任何时期都更有能力、更有底气实现高水平科技自立自强,对于计划的实现表示感谢,感谢能有这个机会让自己去追求梦想,感谢阿里云这个平台,为我们大学生提供更多的帮助,更能为我们增加信心去大放异彩和展现自己,我也会把握这次机遇,更加努力的学习,报答祖国
|
云计算 Docker 容器
关于阿里云的使用感触
关于最近使用阿里云的一些感触和分享
|
架构师 测试技术 程序员
全攻略!!!告诉学弟学妹怎么入行游戏行业
有粉丝问我想要做游戏,怎么才能进入游戏行业呐?忆当年,已过十余载,当年大学毕业的时候有学姐进入珠海西山居做测试,当时觉得很高端,好想进去,可惜没有如意,当时觉得很遗憾,不过两年后我还是进入了游戏行业,只是为了弥补遗憾,为了不让和我有同样想法的同学有遗憾,今天聊一下具体入行攻略。
217 0
全攻略!!!告诉学弟学妹怎么入行游戏行业
|
弹性计算 NoSQL Java
|
运维 搜索推荐 大数据
阿里云冬季实战营第五期体验感悟
阿里云冬季实战营第五期大数据相关操作体验感悟
|
机器学习/深度学习 Cloud Native 前端开发
阿里技术人和开发者朋友们的私藏书单
在快速变化、充满不确定的时代大背景下,拥抱变化成为常态。该如何应对、如何破局? 通过读书持续学习、持续精进,可能是其中成本最低、最高效的一种方式。
阿里技术人和开发者朋友们的私藏书单