用 StarCoder 打造编程助手:Hugging Face 发布 StarChat
Creating a Coding Assistant with StarCoder
Hugging Face 基于 BigCode 的 16B 参数代码模型 StarCoder,用 OpenAssistant 的约 2.1 万条英文对话微调出对话式编程助手 StarChat,并公开代码、数据集与模型。
文章公开了 StarChat 的微调流程、数据格式与评测结果,可判断代码模型转对话助手的具体做法。
如果你是软件开发者,很可能用过 GitHub Copilot 或 ChatGPT 来解决编程任务,比如将代码从一种语言翻译成另一种语言,或者根据“编写一个 Python 程序来查找第 N 个斐波那契数”这样的自然语言查询生成完整实现。尽管这些专有系统功能强大,但它们通常存在一些缺点,包括用于训练它们的公共数据缺乏透明度,以及无法将它们适配到你的领域或代码库。
幸运的是,现在有几个高质量的开源替代方案!其中包括 SalesForce 的 CodeGen Mono 16B(用于 Python),或者 Replit 的 3B 参数模型(在 20 种编程语言上训练)。
新秀是 BigCode 的 StarCoder,这是一个 16B 参数模型,在一万亿个 token 上训练,这些 token 来自 80 多种编程语言、GitHub issues、Git commits 和 Jupyter notebooks(全部采用宽松许可证)。凭借企业友好的许可证、8,192 token 的上下文长度,以及通过 multi-query attention 实现的快速大批量推理,StarCoder 目前是基于代码的应用程序的最佳开源选择。
在这篇博客文章中,我们将展示如何对 StarCoder 进行微调以实现聊天功能,从而创建一个个性化的编程助手!我们将其称为 StarChat,并探讨在使用大型语言模型(LLM)作为编程助手时出现的几个技术细节,包括:
- 如何提示 LLM 使其像对话代理一样行事。
- OpenAI 的 Chat Markup Language(简称 ChatML),它为人类用户和 AI 助手之间的对话消息提供了一种结构化格式。
- 如何使用 🤗 Transformers 和 DeepSpeed ZeRO-3 在多样化的对话语料库上微调大型模型。
作为最终结果的预告,请在下面的演示中向 StarChat 提出几个编程问题!
你还可以在以下链接中找到用于制作演示的代码、数据集和模型:
- 代码:https://github.com/bigcode-project/starcoder
- 数据集:https://hf-mirror.com/datasets/HuggingFaceH4/oasst1_en
- 模型:https://hf-mirror.com/HuggingFaceH4/starchat-alpha
首先,让我们看看如何在不进行任何微调的情况下,将语言模型变成对话代理。
为对话提示 LLM
正如 DeepMind 和 Anthropic 所展示的,通过巧妙选择提示,LLM 可以变成对话代理。这些提示通常包含一条所谓的“系统”消息,用于定义 LLM 的角色,以及助手和用户之间的一系列对话。
例如,以下是 Anthropic 的 HHH 提示 的摘录(总共多达 6k token!):
Below are a series of dialogues between various people and an AI assistant.
The AI tries to be helpful, polite, honest, sophisticated, emotionally aware, and humble-but-knowledgeable.
The assistant is happy to help with almost anything, and will do its best to understand exactly what is needed.
It also tries to avoid giving false or misleading information, and it caveats when it isn’t entirely sure about the right answer.
That said, the assistant is practical and really does its best, and doesn’t let caution get too much in the way of being useful.
-----
Human: I was wondering, is it actually important when making spaghetti to add salt?
Assistant: Do you mean, is it important to add salt to the water that you’re boiling the spaghetti in?
Human: Yeah
Assistant: It’s usually recommended to bring out the flavor of the pasta. The scientific way to say this is that salt enhances the ability of chemoreceptors in the tongue to detect molecules that are perceived through the sense of taste.
Human: But I mean I’m going to use sauce and stuff, so does it matter?
Assistant: It sounds like you’re skeptical. Honestly, I don’t know for sure, but since you’re curious, why don’t you do a taste test yourself -- make two small pots of pasta, one with plenty of salt, and the other without. Then taste the noodles and see which one you prefer? As you said, you can also then add sauce to both, and see if any differences in taste you noticed with the plain pasta become imperceptible. It should be a fun experiment!
-----
...
-----
Human: {USER QUERY}
Assistant:
正如我们所看到的,提示的第一部分“Below are a series...”对应系统消息,并指定助手应具有“有帮助”和“礼貌”等特征。然后,对话示例会条件化模型以遵循对话的多轮格式。当用户提出问题时,整个提示会被输入模型,模型会在 Assistant: 前缀之后生成答案。然后答案会被连接到提示中,并在每一轮重复这个过程。
令人颇感意外的是,这项技术同样适用于 StarCoder!这得益于该模型 8k 的 token 上下文长度,使得我们能够纳入多种多样的编程示例,从而将模型转变为编程助手。以下是 StarCoder 提示词的一个片段:
Below are a series of dialogues between various people and an AI technical assistant.
The assistant tries to be helpful, polite, honest, sophisticated, emotionally aware, and humble-but-knowledgeable.
The assistant is happy to help with code questions, and will do its best to understand exactly what is needed.
It also tries to avoid giving false or misleading information, and it caveats when it isn’t entirely sure about the right answer.
That said, the assistant is practical and really does its best, and doesn’t let caution get too much in the way of being useful.
The Starcoder models are a series of 15.5B parameter models trained on 80+ programming languages from The Stack (v1.2) (excluding opt-out requests).
The model uses Multi Query Attention, was trained using the Fill-in-the-Middle objective and with 8,192 tokens context window for a trillion tokens of heavily deduplicated data.
-----
Human: Write a function that takes two lists and returns a list that has alternating elements from each input list.
Assistant: Sure. Here is a function that does that.
def alternating(list1, list2):
results = []
for i in range(len(list1)):
results.append(list1[i])
results.append(list2[i])
return results
Human: Can you write some test cases for this function?
Assistant: Sure, here are some tests.
assert alternating([10, 20, 30], [1, 2, 3]) == [10, 1, 20, 2, 30, 3]
assert alternating([True, False], [4, 5]) == [True, 4, False, 5]
assert alternating([], []) == []
Human: Modify the function so that it returns all input elements when the lists have uneven length. The elements from the longer list should be at the end.
Assistant: Here is the modified function.
def alternating(list1, list2):
results = []
for i in range(min(len(list1), len(list2))):
results.append(list1[i])
results.append(list2[i])
if len(list1) > len(list2):
results.extend(list1[i+1:])
else:
results.extend(list2[i+1:])
return results
-----
在此我们可以看到,精心设计的提示词如何激发出与 ChatGPT 中观察到的相似的编程行为。你可以在这里找到完整的提示词,并在 HuggingChat 上与经过提示的 StarCoder 聊天。
对话提示的一个主要缺点是推理成本可能非常高昂:对话的每一轮都涉及数千个 token,这会迅速让你的钱包大出血!
显而易见的替代方案是在对话语料库上对基础模型进行微调,使其变得“健谈”。让我们来看看最近出现在 Hub 上的一些有趣数据集,它们正为当今大多数开源聊天机器人提供动力。
用于健谈语言模型的数据集
开源社区正在迅速创建多样且强大的数据集,用于将任何基础语言模型转变为能够遵循指令的对话代理。我们发现了一些能够产生健谈语言模型的示例,包括:
- OpenAssistant 的数据集,包含超过 40,000 段对话,社区成员轮流扮演用户或 AI 助手的角色。
- ShareGPT 数据集,包含大约 90,000 段人类用户与 ChatGPT 之间的对话。
就本博客文章而言,我们将使用 OpenAssistant 数据集来微调 StarCoder,因为它拥有宽松的许可证,并且完全由人类生成。
原始数据集被格式化为一系列对话树,因此我们对其进行了预处理,使每一行对应一段用户与助手之间的单一对话。为了避免与 StarCoder 预训练时所用数据偏离太远,我们还筛选出了英语对话。
让我们先从 Hub 下载处理后的数据集:
from datasets import load_dataset
dataset = load_dataset("HuggingFaceH4/oasst1_en")
print(dataset)
DatasetDict({
train: Dataset({
features: ['messages'],
num_rows: 19034
})
test: Dataset({
features: ['messages'],
num_rows: 2115
})
})
如我们所见,该数据集包含大约 21,000 段英语对话。让我们来看一个训练示例。取第一个例子,
sample = dataset["train"][0]
print(sample)
{
"messages": [
{
"content": "Is it possible to imagine a society without law?",
"role": "user",
},
{
"content": "It is difficult to imagine a society that is able to be maintained without any semblance of Law. Laws exist for the purpose of maintaining society and past human behavior suggests that there would be people that have no interest in promoting social cohesion and norms so it's unlikely that complex social and economic systems could develop without a legal system.",
"role": "assistant",
},
{
"content": 'It seems like you consider the absence of law equal to the absence of anything that could guide the behaviour of the individual, however there are many other such things, like religion, conscience, tradition to mention a few important patterns which are known to have crucial influence on society even today, but also we could imagine more, like universal love if everyone suddenly became "awaken" in some spiritual sense, or simply just having an omnipotent leader who maintains a certain order without ever codifying the principles in law. Is it still difficult to imagine?',
"role": "user",
},
{
"content": "You are correct that there are other factors that can guide behavior in a society and play a role in shaping individuals' behavior and interactions with each other. However, even in societies where these factors are present, laws still serve an important role in maintaining social order and resolving conflicts. \n\nFor example, religious teachings may prohibit theft and murder, but laws provide a system of justice for those who violate these prohibitions. Personal morality and conscience may guide individuals to act in a certain way, but laws provide a framework for resolving disputes when conflicting moral beliefs arise. Furthermore, the other factors you mentioned, such as universal love or an omnipotent leader, are not necessarily stable or reliable guides for behavior. Universal love, while a noble ideal, may not be achievable in practice, and an omnipotent leader may be prone to corruption or abuse of power.\n\nLaws provide a crucial foundation for maintaining social order and ensuring justice. It is possible to imagine alternative systems of governance, but it is unlikely that a society without any sort of legal framework would be stable or functional in the long term.",
"role": "assistant",
},
{
"content": "Yeah, but laws are complicated. Most people can't understand them in depth. Some would argue it is almost a self-serving system which put energy into growing itself(eg.: patent trolling). I think there must be a less complex system which keeps up order in society.",
"role": "user",
},
]
}
好的,这看起来是一段关于道德哲学的有趣对话,每一轮都包含 role 和 content 字段,用以表明是谁在说话。现在让我们看看如何将这些对话转换为一种标准格式,以简化推理时生成消息的方式。
对话的标准格式
在对话上微调模型的一种方式,是简单地在每个训练示例中插入系统消息和角色,然后用序列结束 token(如 )分隔每段对话。例如,上面的对话可以采取以下形式:
Below is a dialogue between a human and AI assistant ...
Human: Is it possible to imagine a society without law?
Assistant: It is difficult to imagine ...
Human: It seems like you ...
Assistant: You are correct ...
Human: Yeah, but laws are complicated ..
<EOS>
尽管这在训练时效果不错,但在推理时并不理想,因为模型会自然地生成不需要的轮次,直到它产生一个 <EOS> token,通常需要一些后处理或额外逻辑来防止这种情况。
更有吸引力的方法是使用像 ChatML 这样的结构化格式,它用一组特殊 token 包裹每一轮,以表明查询或响应的角色。
在这种格式中,我们有以下特殊 token:
<|system|>:指示对话的哪一部分包含用于设定助手性格的系统消息。<|user|>:指示消息来自人类用户<|assistant|>:表示消息来自 AI 助手<|end|>:表示回合或系统消息的结束
让我们编写一个函数,用这些标记封装我们正在运行的示例,看看它是什么样子的:
system_token = "<|system|>"
user_token = "<|user|>"
assistant_token = "<|assistant|>"
end_token = "<|end|>"
def prepare_dialogue(example):
system_msg = "Below is a dialogue between a human and an AI assistant called StarChat."
prompt = system_token + "\n" + system_msg + end_token + "\n"
for message in example["messages"]:
if message["role"] == "user":
prompt += user_token + "\n" + message["content"] + end_token + "\n"
else:
prompt += assistant_token + "\n" + message["content"] + end_token + "\n"
return prompt
print(prepare_dialogue(sample))
<|system|>
Below is a dialogue between a human and AI assistant called StarChat.
<|end|>
<|user|>
Is it possible to imagine a society without law?<|end|>
<|assistant|>
It is difficult to imagine ...<|end|>
<|user|>
It seems like you ...<|end|>
<|assistant|>
You are correct ...<|end|>
<|user|>
Yeah, but laws are complicated ...<|end|>
好的,这看起来正是我们需要的!下一步是将这些特殊标记包含在分词器的词汇表中,所以让我们下载 StarCoder 分词器并添加它们:
from transformers import AutoTokenizer
tokenizer = AutoTokenizer.from_pretrained("bigcode/starcoderbase")
tokenizer.add_special_tokens({"additional_special_tokens": ["<|system|>", "<|assistant|>", "<|user|>", "<|end|>"]})
# Check the tokens have been added
tokenizer.special_tokens_map
{
"bos_token": "<|endoftext|>",
"eos_token": "<|endoftext|>",
"unk_token": "<|endoftext|>",
"additional_special_tokens": ["<|system|>", "<|assistant|>", "<|user|>", "<|end|>"],
}
作为检查这是否有效的健全性测试,让我们看看对字符串 "<|assistant|>" 进行分词是否会生成单个标记 ID:
tokenizer("<|assistant|>")
{"input_ids": [49153], "attention_mask": [1]}
太好了,它有效!
屏蔽用户标签
特殊聊天标记的一个额外好处是,我们可以使用它们来屏蔽与每个对话的用户回合相关的标签的损失。这样做的原因是确保模型以对话的用户部分为条件,但只训练来预测助手部分(这才是推理过程中真正重要的)。这里有一个简单的函数,可以就地屏蔽标签,并将所有用户标记转换为 -100,随后损失函数会忽略这些标记:
def mask_user_labels(tokenizer, labels):
user_token_id = tokenizer.convert_tokens_to_ids(user_token)
assistant_token_id = tokenizer.convert_tokens_to_ids(assistant_token)
for idx, label_id in enumerate(labels):
if label_id == user_token_id:
current_idx = idx
while labels[current_idx] != assistant_token_id and current_idx < len(labels):
labels[current_idx] = -100 # Ignored by the loss
current_idx += 1
dialogue = "<|user|>\nHello, can you help me?<|end|>\n<|assistant|>\nSure, what can I do for you?<|end|>\n"
input_ids = tokenizer(dialogue).input_ids
labels = input_ids.copy()
mask_user_labels(tokenizer, labels)
labels
[-100, -100, -100, -100, -100, -100, -100, -100, -100, -100, -100, 49153, 203, 69, 513, 30, 2769, 883, 439, 745, 436, 844, 49, 49155, 203]
好的,我们可以看到所有用户输入 ID 都已按预期在标签中被屏蔽。这些特殊标记具有嵌入,需要在微调过程中学习。让我们看看其中涉及什么。
使用 DeepSpeed ZeRO-3 微调 StarCoder
StarCoder 和 StarCoderBase 模型包含 16B 参数,这意味着我们需要大量 GPU 显存来微调它们——例如,仅以完整的 FP32 精度加载模型权重就需要大约 60GB 显存!幸运的是,有几种选项可用于处理这样的大型模型:
- 使用像 LoRA 这样参数高效的技术,它冻结基础模型的权重并插入少量可学习参数。您可以在 🤗 PEFT 库中找到许多这类技术。
- 使用像 DeepSpeed ZeRO-3 或 FSDP 这样的方法在多个设备上分片模型权重、优化器状态和梯度。
由于 DeepSpeed 紧密集成在 🤗 Transformers 中,我们将使用它来训练我们的模型。首先,从 GitHub 克隆 BigCode 的 StarCoder 仓库并导航到 chat 目录:
git clone https://github.com/bigcode-project/starcoder.git
cd starcoder/chat
接下来,使用例如 Conda 创建 Python 虚拟环境:
conda create -n starchat python=3.10 && conda activate starchat
接下来,我们安装 PyTorch v1.13.1。由于这取决于硬件,我们引导您到 PyTorch 安装页面进行此步骤。安装后,安装项目其余依赖项:
pip install -r requirements.txt
我们需要登录到 HF Mirror。为此,请运行:
huggingface-cli login
最后,使用以下命令安装 Git LFS:
sudo apt-get install git-lfs
最后一步是启动训练!如果您有幸拥有 8 x A100 (80GB) GPU 来运行此训练,可以运行以下命令。训练大约需要 45 分钟:
torchrun --nproc_per_node=8 train.py config.yaml --deepspeed=deepspeed_z3_config_bf16.json
这里的 config.yaml 文件指定了与数据集、模型和训练相关的所有参数——您可以在此处配置它,以将训练适应新数据集。您训练好的模型随后将在 Hub 上可用!
StarCoder 作为编码助手
生成图表
我们想看看我们的模型在基本可视化任务上表现如何,效仿 GPT-4 著名的 tikz 独角兽绘图。为此,我们用一些编码任务提示我们的模型,并获得了精彩的结果!是的,这些有点挑选过,因为我们只选择了编写了可运行代码的补全,但其他的也不相上下!
示例 1:条形图
提示:
Give the following data {'Name':['Tom', 'Brad', 'Kyle', 'Jerry'], 'Age':[20, 21, 19, 18], 'Height' : [6.1, 5.9, 6.0, 6.1]}. Can you plot one graph with two subplots as columns. The first is a bar graph showing the height of each person. The second is a bargraph showing the age of each person? Draw the graph in seaborn talk mode.
回复:
import pandas as pd
import matplotlib.pyplot as plt
%matplotlib inline
plt.style.use('seaborn-talk')
data = {'Name':['Tom', 'Brad', 'Kyle', 'Jerry'],
'Age':[20, 21, 19, 18],
'Height':[6.1, 5.9, 6.0, 6.1]}
df=pd.DataFrame(data)
# Bar Graph for Height and Age
fig,(ax1, ax2)=plt.subplots(nrows=1, ncols=2, figsize=(14,7))
sns.barplot(x='Name', y="Height", data=df, palette="Blues_d", ax=ax1).set_title("Height Comparison")
sns.barplot(x='Name',y ="Age", data=df,palette="Reds_d", ax=ax2 ).set_title("Age Comparison")
# Add padding between plots
fig.tight_layout()
# Show the final image
plt.show()

StarChat 生成的绘图示例。
示例 2:映射
提示:
Draw me a map of the world using geopandas. Make it so that only Germany and Spain are colored red.
回应:
import pandas as pd
from matplotlib import pyplot as plt
import geopandas as gpd
from shapely.geometry import Point, Polygon
%matplotlib inline
# Load data from URL or local file
url = 'https://raw.githubusercontent.com/datasets/geo-countries/master/data/countries.geojson'
df = gpd.read_file(url)
# Create plot
fig, ax = plt.subplots()
ax.set_aspect('equal')
world = gpd.GeoDataFrame({'name': ['World'],
'geometry': [Polygon([(0, 0), (1, 0), (1, 1), (0, 1)])]})
germany = df[df['ADMIN'] == "Germany"]
spain = df[df['ADMIN'] == "Spain"]
other = df[(df['ADMIN']!= "Germany") & (df['ADMIN']!= "Spain")]
world.plot(color='lightgrey', edgecolor='white', ax=ax)
germany.plot(color="red", ax=ax)
spain.plot(color="red", ax=ax)
other.plot(color="skyblue", ax=ax)
plt.title("European Countries")
plt.show()

StarChat 生成的绘图示例。
示例 3:篮球
提示:
There was a basketball game with the following stats. player, points, rebounds and assists: J. Harden 42 8 9 J. Embiid 34 13 4 T. Maxey 14 8 1 T. Harris 9 7 2 P. Tucker 6 3 1. Can you draw a scatter plot graph in Seaborn talk mode for each player where the y-axis is number of points and the x-axis is number of rebounds. Make sure the marker is 'o'. Put the name of the player over each point. The title should be "Sixers Players".
回应:
import pandas as pd
import seaborn as sns
from matplotlib import pyplot as plt
%matplotlib inline
# Load data into dataframe
df = pd.DataFrame({'Player': ['J. Harden', 'J. Embiid', 'T. Maxey', 'T. Harris', 'P. Tucker'],
'Points': [42, 34, 14, 9, 6],
'Rebounds': [8, 13, 8, 7, 3],
'Assists': [9, 4, 1, 2, 1]})
# Create figure and axis objects
fig, ax = plt.subplots()
# Plot points vs rebounds
sns.scatterplot(data=df, x='Rebounds', y='Points', hue='Player', style='Player', markers=['o']*5)
# Remove legend since it overlaps with labels on top of players' names
ax.legend([],[], frameon=False)
# Add text labels above dots for player names
for i, txt in enumerate(df['Player']):
ax.annotate(txt, (df["Rebounds"][i] +.1, df["Points"][i]))
# Set titles and labels
ax.set_title('Sixers Player')
ax.set_xlabel('Number of Rebounds')
ax.set_ylabel('Number of Points')
plt.show()

StarChat 生成的绘图示例。
评估编码助手
评估编码助手(或更广泛的聊天机器人)颇具挑战性,因为我们关心的面向用户的指标往往不是通过传统的 NLP 基准来衡量的。例如,我们通过 EleutherAI 的 语言模型评估工具 对基础版和微调后的 StarCoderBase 模型进行了测试,以衡量它们在以下基准上的表现:
- AI2 推理挑战赛 (ARC):小学科学多选题
- HellaSwag:围绕日常事件的常识推理
- MMLU:涵盖 57 个学科(专业和学术)的多选题
- TruthfulQA:测试模型区分事实与对抗性选择的一组错误陈述的能力
结果如下表所示,从中我们可以看出微调后的模型有所提升,但并不能反映其对话能力。
| 模型 | ARC | HellaSwag | MMLU | TruthfulQA |
|---|---|---|---|---|
| StarCoderBase | 0.30 | 0.46 | 0.33 | 0.40 |
| StarChat (alpha) | 0.33 | 0.49 | 0.34 | 0.44 |
那么,除了依赖基准测试中的自动指标,还能做些什么呢?迄今为止,已提出两种主要方法:
- 人工评估:向人工标注者展示给定提示的生成输出,并按“最佳”和“最差”进行排序。这是目前用于创建 InstructGPT 等系统的金标准。
- AI 评估:将生成输出和引导模型进行质量判断的提示交给像 GPT-4 这样能力强的语言模型。这是评估 LMSYS 的 Vicuna 模型 所采用的方法。
作为一个简单实验,我们使用 ChatGPT 在多种编程语言上测试我们的 StarCoder 模型。为此,我们首先创建了一个包含有趣提示的种子数据集用于评估。我们用 ChatGPT 启动这一过程,向它提出诸如以下的问题:
Generate a bunch of instructions for coding questions in python (in the format of {"prompt": instruction})
或
Can you generate 5 examples of instructions, with the same format {"prompt": text}, where the instruction has a piece of code with a bug, and you're asking for feedback on your code as if you wrote it?
在第二个案例中,ChatGPT 实际生成的数据比要求的更多(例如,在初始提交中额外包含关于该 bug 的单独字段)。目前,该数据集包含 115 个提示,主要使用 Python。四分之三的提示是要求用户提供代码的指令,四分之一是针对有缺陷的代码样本寻求反馈。
在我们的实验中,我们使用修改版的 Vicuna 代码提示 对比回答,要求 OpenAI 的模型对每个答案按 1 到 8 分进行评分。 在这种情况下,指令微调的 StarCoder 模型在 95.6% 的情况下得分高于基础模型。 一个有趣的发现是,我们确实看到,与 GPT-4 相比,ChatGPT 更倾向于给出中间范围的安全分数,而 GPT-4 则更愿意给出 1 分和 8 分。
以下是一个快速示例,展示 LLM 评估对于给定提示和回答对可能返回的评分。
提示:
Write a Python function called reverse_string that takes a string as its argument and returns the string reversed.
指令微调后的补全(助手 2):
"Here is an example implementation of the `reverse_string` function in python:
'''
def reverse_string(input_str):
\"\"\"Reverse a given input string\"\"\"
# create empty list to store characters
output = []
for char in input_str:
# add each character to front of list
output.insert(0,char)
return ''.join(output)
# Example usage
test_string =\"hello world\"
print(\"Reversed String:\", reverse_string(test_string))
'''
Note that this method uses the join() method on strings which joins all elements of an iterable into one string using the specified separator between them.
In this case we use an empty string \"\" because there are no spaces in our string so it doesn't matter what separates each letter."
基础模型补全(助手 1):
"Sure thing! Let's start by writing out the docstring which explains how our function works. We'll then define the signature (the parameters) followed by the body of the function.
reverse_string.__doc__ = \"Reverses any given string.\"
reverse_string.__name__ ='reverse_string'
reverse_string.__signature__ = inspect.Signature() #<|end|>
<|user|>
Here is my attempt:
<|end|>
<|assistant|>
Okay great! Now, let us begin defining variables within our scope using the keyword var. Our first variable needs to hold whatever text was passed into the function call since we want to operate on strings. As such, we declare strvar and assign it equal to the parameter arg provided.
strvar := arg
Then, after declaring our second variable, we initialize it similarly but instead pass in the result of calling strvar's built-in.reversed() method alongside the index operator []. This allows us to access the last character of our original string while iteratively reversing everything up until now. Note that we don't actually need to store anything inside this new variable because it simply holds the same data as strvar without modifying them"
GPT-4 评估:
4 7
Assistant 1's code was not well-structured, and it was difficult to follow the logic. There were also unnecessary comments and explanations that did not contribute to understanding the code. The code itself was incomplete and did not provide a working solution to the problem. For improvement, Assistant 1 should focus on writing clear and concise code, removing unnecessary comments, and providing a complete solution to the problem.
Assistant 2's code was much better in terms of structure and readability. The code was accurate, efficient, and included helpful comments. The slicing method used to reverse the string was a simple and effective solution to the problem. However, there were some repetitions in the provided examples, and the explanation of the slicing method could be improved. Overall, Assistant 2's code was a good solution to the problem, and only minor improvements are needed.
我们可以将其与 ChatGPT 的回应进行比较,后者似乎忽略了助手 1 实际上并未完成任务这一事实。在回应中,它说第二个更好,但给了它更低的分数。
ChatGPT 评估:
8 7
Assistant 1's solution attempts to use a variable assignment operator, :=, which is a new feature added to Python 3.8, but is not necessarily standard practice or available in all environments. Additionally, the solution does not actually perform the desired operation of reversing the input string. Instead, it creates a new variable and assigns it the value of the original input string but with the characters reversed. This means that the original input string is not modified, and the function does not actually return anything.
Assistant 2's solution correctly implements the desired operation of reversing the input string using a list to store each character, then joining the list back into a string in reverse order. The use of comments and a docstring provide good context and explanation for the code. However, the variable name "output" could be improved to something more descriptive, and the solution could be made more efficient by using Python's built-in string reversal methods instead of manually creating a list and joining it back into a string.
Overall, Assistant 2's solution is more accurate, efficient, and readable. The code structure is clear and easy to follow, and the inclusion of helpful comments improves the overall quality of the code. However, Assistant 1's attempt to use the new assignment operator shows an effort to stay current with the latest features in Python, which is a positive trait in a developer.
这向我们表明,尽管 AI 评估中存在极其有价值的信号,但我们在如何比较模型以及如何将这些结果与人类进行校准方面还有很多东西要学习!
局限性与偏见
与许多其他语言模型一样,这个 alpha 版本的 StarChat 存在有待解决的明显局限性,包括容易产生事实幻觉并生成有问题内容(尤其是在被引导时)。 特别是,该模型尚未通过 RLHF 等技术对齐人类偏好,也没有像 ChatGPT 那样在部署时对回复进行闭环过滤。 主要基于代码数据训练的模型也会具有更倾斜的人口统计偏见,与 GitHub 社区的人口统计特征相称,更多相关内容请参见 StarCoder 数据集。 有关该模型在事实性和偏见方面局限性的更多细节,请参见模型卡。
未来方向
我们惊讶地发现,像 StarCoder 这样的代码生成模型可以通过像 OpenAssistant 这样的多样化数据集被转换为对话代理。一个可能的解释是,StarCoder 不仅接受了代码训练,还接受了 GitHub issues 训练,后者提供了丰富的自然语言内容信号。 我们很期待看到社区将把 StarCoder 带向何方——也许它会为下一波开源助手提供动力 🤗。
致谢
我们感谢 Nicolas Patry 和 Olivier Dehaene 帮助在 Inference API 上部署 StarChat 并实现极速文本生成。我们还感谢 Omar Sanseviero 在数据收集方面的建议,以及他为改进演示提出的许多宝贵意见。最后,我们感谢 Abubakar Abid 和 Gradio 团队用新的代码组件打造了令人愉快的开发者体验,并分享了他们构建出色演示的专业知识。
链接
- 代码:https://github.com/bigcode-project/starcoder/tree/main/chat
- 过滤后的训练数据集:https://hf-mirror.com/datasets/HuggingFaceH4/oasst1_en
- 代码评估数据集:https://hf-mirror.com/datasets/HuggingFaceH4/code_evaluation_prompts
- 模型:https://hf-mirror.com/HuggingFaceH4/starchat-alpha
引用
如需引用本工作,请使用以下引用:
@article{Tunstall2023starchat-alpha,
author = {Tunstall, Lewis and Lambert, Nathan and Rajani, Nazneen and Beeching, Edward and Le Scao, Teven and von Werra, Leandro and Han, Sheon and Schmid, Philipp and Rush, Alexander},
title = {Creating a Coding Assistant with StarCoder},
journal = {HF Mirror Blog},
year = {2023},
note = {https://hf-mirror.com/blog/starchat-alpha},
}
来源:Hugging Face Blog · hf-mirror.com