如果你是一个软件开发者,你可能已经使用过 ChatGPT 或 GitHub 的 Copilot 去解决一些写代码过程中遇到的问题,比如将代码从一种语言翻译到另一种语言,或者通过自然语言,诸如“写一个计算斐波那契数列第 N 个元素的 Python 程序”,来自动生成代码。尽管这些专有系统功能强大,但它们仍然有很多不足,比如对训练所使用的公共数据透明度的缺失、没有能力去让它们适配自己的使用领域或代码库。
幸运的是,现在我们有了很多高质量开源替代品!包括 SalesForce 为 Python 语言开发的 CodeGen Mono 16B,以及 Replit 开发的、在 20 种编程语言上训练过的 一个 3B 参数量的模型。
而最近新出现的一个选择则是 BigCode 开发的 StarCoder,这是一个在一万亿的 token、80 多种编程语言上训练过的 16B 参数量的模型。训练数据多来自 GitHub 上的 issues、使用 Git 提交的代码、Jupyter Notebook 等等 (相关使用都已经过许可)。得益于对企业友好的许可证、长度为 8192 的 token、借助 multi-query attention 的快速大批量推理,StarCoder 可以说是当前对代码相关的应用最合适的开源选择。
本文将介绍如何对 StarCoder 进行微调,进而创建一个可以聊天的个人编程助手。这个编程助手我们将称之为 StarChat。借助 StarChat 的开发过程,我们将探索以下几个使用大语言模型 (LLM) 创建编程助手时可能遇到的几个技术细节:
最后,为了尝试一下效果,我们还会问 StarChat 几个编程方面的问题 (参考下面的演示)。
体验地址: http://huggingfaceh4-starchat-playground.hf.space
你也可以查看生成上面演示所使用的代码、数据集和模型:
接下来第一步,我们先来看看怎样把语言模型转化为一个对话代理。这里我们不是用任何微调。
DeepMind 和 Anthropic 的相关研究指出,大语言模型 (LLM) 可以通过选取合适的文本提示 (prompt) 来转化为对话代理。这些文本提示通常包含一种所谓的“系统”信息来定义 LLM 的角色,以及一系列人机对话的示例。
比如这里,就是 Anthropic’s HHH prompt 这一文本提示的一些节选 (总计 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:
As we can see, the first part of the prompt “Below are a series…” corresponds to the system message and specifies that the assistant should have characteristics like “helpfulness” and “politeness”. The dialogue examples then condition the model to follow the multi-turn format of a conversation. When a user asks a question, the whole prompt is fed to the model and it generates an answer after the Assistant:
prefix. The answer is then concatenated to the prompt and the process repeated at every turn.
Somewhat surprisingly, this technique also works for StarCoder! This is enabled by the model’s 8k token context length, which allows one to include a wide variety of programming examples and covert the model into a coding assistant. Here’s an excerpt of the StarCoder prompt:
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 被输入进去,这会非常消耗推理资源!
所以,一个显而易见的改进措施就是使用一个对话的语料库去微调这个大语言模型,使得它会聊天。接下来我们就看看几个有趣的数据集,这几个数据集最近登陆了 HuggingFace Hub,当前很多开源的聊天机器人都是基于它们训练的。
如今的开源社区正在加快创建多样和高性能的数据集,以便将各种基础的语言模型转换为能遵照指示来对话的对话代理模型。这里我们找了一些示例数据集,可以用于生产对话语言模型:
在本文中,我们将使用 OpenAssistant 来微调 StarCoder,主要是出于许可证的原因,而且它是完全由人工生成的。
由于原始的数据集是以对话树的格式收集起来的,我们预处理了数据,确保每行单独对应一段用户和 AI 模型的对话。为防止模型演化得距离原始预训练数据太远,我们也过滤掉了非英语文本。
首先我们下载这个已经处理过的数据集:
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
})
})
可以看到,数据集包含大约 21000 段英文对话。我们先来看看这些训练数据,拿第一条数据看看:
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 exists for the purpose of maintaining society and past human behavior suggests that there would 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 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 (如 <EOS>) 分隔开。举例而言,上面的对话可以转换成这个形式:
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|>
: 表示说话内容的结尾,或系统信息的结尾。下面我们写一个函数,把我们的实例数据用这些特殊的 token 包装起来:
system_token = "<|assistant|>"
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|>
以上就是包装好后的数据!下一步,我们还需要把这些特殊的 token 加入到分词器 (tokenizer) 的词汇表中。我们这里下载 StarCoder 的分词器,然后加入这些特殊 token:
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|>” 输入到分词器中是否会输出单独一个 token 的 ID:
tokenizer("<|assistant|>")
{"input_ids": [49153], "attention_mask": [1]}
很好!有效!
使用特殊 token 还有一个好处,就是我们可以把来自用户话语部分的损失函数值给掩盖掉。因为我们的模型是基于用户的话语而只被训练去预测 AI 助手说话的部分 (模型推理时只需要根据用户的话回答用户)。下面就是一个简单的函数,用于掩盖掉用户部分的标签,并把所有的用户部分的 token 转为 -100 (接下来 -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 全都被掩盖掉了。这些特殊的 token 在微调阶段将会学习到自己特定的嵌入 (embedding)。接下来我们看看如何微调。
StarCoder 和 StarCoderBase 模型的参数量达到了 160 亿,如果我们把模型以 FP32 的精度载入到 GPU 中,将需要大约 60 GB 的 vRAM。然而幸运的是,我们有其它方法去应对这种规模的大模型:
我们将使用 DeepSpeed 来训练我们的模型,因为它已经被整合进了 ? Transformers。首先,我们先从 GitHub 下载 StarCoder 的代码仓库,进入 chat
文件夹:
git clone http://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,注意这一步和硬件有关,请参考官方安装页面)。之后安装本项目的相关依赖项:
pip install -r requirements.txt
同时,我们还需要登录上 Hugging Face。执行以下指令:
huggingface-cli login
最后,安装 Git LFS:
sudo apt-get install git-lfs
接下来我们就可以训练了!如果你有幸拥有 8 个 A100 (80 GB 显存),你可以通过下下面的命令去开始训练。训练会花费大约 45 分钟:
torchrun --nproc_per_node=8 train.py config.yaml --deepspeed=deepspeed_z3_config_bf16.json
这里的 config.yaml
指定了关于数据集、模型、训练的所有参数。你可以在 这里 重新配置它,以适应新的训练数据集。稍后,训练好的模型将会出现在 Hub 上。
仿照著名的 让 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()
例 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 = 'http://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()
例 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()
评估编程助手 (或更广泛地讲,聊天机器人) 其实是一个比较棘手的任务,因为面向用户的评测标准通常难以被传统自然语言处理的基准上体现出来。比如,我们使用基础的和微调过的 StarCoderBase 模型在 EleutherAI 的 language model evaluation harness 做如下测试:
测试结果在下表中统计了出来。我们可以看出微调过的模型多少有了点提升,但这并不能反映出对话相关的能力。
Model | ARC | HellaSwag | MMLU | TruthfulQA |
---|---|---|---|---|
StarCoderBase | 0.30 | 0.46 | 0.33 | 0.40 |
StarChat (alpha) | 0.33 | 0.49 | 0.34 | 0.44 |
那除了使用这种在基准测试集上的指标,我们还可以怎么做评测呢?最近,两种主流的评测方法被提了出来:
为了简单起见,我们使用 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 实际上生成了比我们要求更多的数据。当前,这个数据集包含了 115 条文本提示 (prompt),而且主要是使用 Python。四分之三的文本提示是要求提供代码的,剩下四分之一是索要针对有 bug 代码的反馈的。
在我们的实验中,我们要求 OpenAI 的模型去评估得到的回答,对它们进行 1 到 8 分的打分,使用的是略加修改的 Vicuna code prompt 数据。这里,使用我们这个数据集微调过的 StarCoder 在 95.6% 的情况下得分都高于原始的基础模型。我们还发现了一个有趣的瑕疵现象: ChatGPT 喜欢打处于中位的安全分,而 GPT-4 更敢于去给极端分数,如 1 分和 8 分。
以下示例就展示了大语言模型 (LLM) 是如何去给一个问答的质量打分的:
文本提示 (prompt):
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"
GPT4 给出的评价:
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 的回复,似乎 ChatGPT 忽视了助手 1 并未完成任务这个事实。ChapGPT 说第二个回答更好,然而却给助手 2 打了相对较低的分数。
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 数据集。读者还可以参考对应的 model card 来更详细地了解模型在事实性和偏向性方面的问题。
基于我们上述的各种实验,我们很惊讶地发现,像 StarCoder 这样的代码生成模型,可以通过在诸如 OpenAssistant 的数据集上微调,被转化为一个对话机器人。一种可能的解释是,因为 StarCoder 已经在代码和 GitHub 的 issue 上训练过了,而后者提供了丰富的自然语言信息。我们期待看到社区引领 StarCoder 走向新的方向,甚至激发下一个开源对话问答助手的热潮 ?。
我们感谢 Nicolas Patry 和 Olivier Dehaene,他们在部署 StarCoder 到 Inference API,以及实现 blazing fast text generation 方面提供了很多帮助。我们也感谢 Omar Sanseviero 在数据收集方面给出的指导,以及他为改进演示示例提出的宝贵建议。最后,我们也感谢 Abubakar Abid 和 Gradio 团队提供的完美开发体验,以及为制作出色演示示例所分享的专业知识。
如有需要,请按照如下方式引用本篇文章。
@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 = {Hugging Face Blog},
year = {2023},
note = {http://huggingface.co/blog/starchat-alpha},
}
原文链接: http://huggingface.co/blog/starchat-alpha
作者: Lewis Tunstall, Nathan Lambert, Nazneen Rajani, Edward Beeching, Teven Le Scao, Sheon Han, Philipp Schmid, Leandro von Werra, Sasha Rush
译者: hugging-hoi2022
审校/排版: zhongdongy (阿东)
官网简单的响应式横幅组件被映射到一个媒体容器,该容器包含不同拐点的多个图像。横幅始终显示拐点的最佳图像。简单的响应式横幅组件允许您上传针对宽屏、台式机、平板电脑和智能手机以及店面支持的每种语言进行了优化的图像。您指定一个URL来链接图像。当客户单击图像时,他们将被重定向到您店面中的页面。下图显示了在桌面拐点处呈现的简单响应式横幅组件:下图显示了在移动拐点中呈现的相同的简单响应式横幅组件:DefiningtheContentsofaSimpleResponsiveBannerComponent此过程描述了如何定义简单响应式横幅组件的内容。在ComponentEditor里,切换到Content面板: 在media区域上传对应的图片: 下图是SAPSpartacusbanner运行时的一个例子:
历史本人也是从2013年接触iOS开发的,哪个时候iOS和Android很火爆,只要懂一点iOS或者Android基础就随便找工作。因为火爆所以各种培训机构,各种没有学过编程的都去学习iOS和Android。从2017年左右就感觉iOS和Android没有那么火了。隐约记得从2017年开始一个iOS开发职位可以收到很多简历。我也是从2018年跳槽后至今也没有跳槽了。也不知道现在iOS是什么一个情况。现状从2019年下半年,由于公司iOS业务量不是很多,App主要是政府人员在使用所以Android的需求多一些。所以就开始写后台了。当时老大只是说有时间可以帮后台写一些简单的接口。这样就一发不可收拾了。最牛逼的时候既要写接口,还要写App,哈哈~~。到现在90%的时间都在写接口,10%的时间修改一些App的需求。不知不觉我就转Java后台开发了。但是有时间还是会看一些iOS方面的技术文章,偶尔也在写一些iOS的技术文章。去年也自学了Flutter写了一个Flutter的App。标签还记得之前我给自己贴的一个标签是iOS开发者,但是目前我撕了之前所有的标签,我认为自己就是一个程序员。不要给自己
RequestMappingHandlerAdapter含有大量的web基础组件协助完成一整个请求的调度、处理RequestMappingHandlerAdapter 适配@RequestMapping注解标注的Handler(HandlerMethod类型)Spring3.1新增的一个适配器类,用于数据绑定、数据转换、数据校验、内容协商 因为有了它的存在,使得开发者几乎可以忘掉原生的ServletAPI Spring5.0在把Servlet容器从必选项变成可选项后,即使切换了web容器(比如换成jetty),也能做到在使用层面上对开发者无感知 @since3.1实现了InitializingBean接口和BeanFactoryAwarepublicclassRequestMappingHandlerAdapterextendsAbstractHandlerMethodAdapterimplementsBeanFactoryAware,InitializingBean{ //唯一构造方法:默认注册一些消息转换器。开启@EnableWebMvc后此默认行为会被set方法覆盖 publ
最近看到QQ音乐的歌词每次滑动后都可以滚回到中间位置。觉得甚是神奇,打开开发者模式显示布局,发现歌词部分不是采用android控件的写的,应该是前端写的。于是,我想,能不能用recyclerView实现这个自动回滚到中间位置呢。功夫不负有心人,查找了一些资料之后,终于搞定了。下面由我细细讲来。目标点击某个条目,在经过4s无任何操作之后,该条目滚动到中间位置显示。点击后,用户在滑动,等用户不操作后再开始延时。用户多次点击,记最后一次点击位置。分析首先先考虑,滚动到指定位置是如何操作的?//滚动到指定位置 recyclerView.scrollToPosition(position); //平滑滚动到指定位置 recyclerView.smoothScrollToPosition(position);复制有没有滚动到制定像素位置呢?//scrollBy(x,y)这个方法是自己去控制移动的距离,单位是像素,所以在使用scrollBy(x,y)需要自己去计算移动的高度或宽度。 recyclerView.scrollBy(x,y)复制可是,问题是滚动到中间位置啊?这个怎么办呢?这样子行不行呢?m
今天的两道题目全都围绕链表,第一个是困难级别的、要合并多个排序的链表;第二题是中等难度,需要两两交换链表中的节点,昨天没能用递归法写出代码,今天就尝试用递归实现了下,测试效果不咋地,但递归法跑通了!题目一第23题:合并K个排序链表:合并k个排序链表,返回合并后的排序链表。请分析和描述算法的复杂度。示例:输入: [ 1->4->5, 1->3->4, 2->6 ] 输出:1->1->2->3->4->4->5->6复制思路刚看到这题面,联想昨天刚写了合并两个排序链表的题目,最先想到的就是基于能够实现合并两个的方法mergeTwoLists(l1,l2),先取列表中前两条链表合并,再将结果分别与第三、四等一直到最后一条链表合并,最终结果即所求。但按这个思路写完代码提交后,测评结果是“超出时间限制”。如果想简化处理,我们从结果来看,其实就是把所有可能的数以链表的形式输出。那么思路就来了:我们把列表中所有链表中出现的节点数字存起来,排序后用这些数字重新生成一条链表,就达到题目要求了。代码#Definitionforsing
为了抗击新冠肺炎病毒疫情,腾讯云AI即日起免费为战疫开发者提供人脸识别、文字识别、语音识别、语音合成、机器翻译、腾讯智能对话平台TBP等服务,直至疫情结束。所有为政府部门、医疗机构等开发疫情服务,以及提供远程办公、教学等服务的开发者和服务商,都可以免费或以一定优惠额度享受服务。经典案例微应急、交通疫情小程序使用了腾讯云慧眼、文字识别OCR、实名认证等功能,助力疫情管控。企业微信使用了腾讯云人脸打卡功能,帮助企业统计员工远程到岗情况。鹤山政府使用了腾讯云慧眼、文字识别OCR等功能,方便疫情线索收集。VIPKID使用了腾讯云通用印刷体识别功能,快速识别营销文档是否符合规范。政务民生全国多地已经开始小区封闭式管理,在管控人员/车辆进出时,通过人脸识别,可以判断是否为小区住户、是否在规定时间进出小区;通过车牌号识别,可以统一管理小区车辆,记录车辆停放位置、时长,以及是否为疫区车辆。当前自我保护的最好方法就是不出门、不出门、不出门!线上政务服务的需求量会增多,例如人脸验证、身份证识别、驾驶证识别等等。接入政务联络机器人。以一个拥有2000人的小区来说,如果依靠人工的话需要20个调查员,6个小时才
MonteCarlo算法画π#encoding=utf8 importmatplotlib.pyplotasplt importrandom defget_random_point(N): x0=[] y0=[] x1=[] y1=[] forindexinrange(1,N): x=random.random() y=random.random() ifx*x+y*y<1: x0.append(x) y0.append(y) else: x1.append(x) y1.append(y) return(x0,y0,x1,y1) defplot_pi(): forNin[100,1000,10000,100000]: (x0,y0,x1,y1)=get_random_point(N) plt.figure(N,figsize=(7,7)) plt.plot(x0,y0,'b.',x1,y1,'r.') plt.title('N={}'.format(N)) plt.show() if__name__==&quo
上一节中我们定义了一个响应式表单,其中表单数据是在定义的时候就初始化好的,但是很多时候数据需要异步获取,比如 打开一个编辑页面,需要请求HTTP拿到数据。根据数据修改表单中字段的值,最终体现在页面上。 我们改造上一节的例子,成为异步获取数据。 我们先创建service文件,写一个loadUser方法,模拟HTTP请求import{Injectable}from'@angular/core'; import{of}from'rxjs'; import{delay}from'rxjs/operators'; ///api/users/1 exportinterfaceUser{ id:number; firstName:string; lastName:string; about:string; } constfakeData={ id:0, firstName:'Cory', lastName:'Rylan', about:'WebDeveloper' }; @
在2018年还剩下42天的时候,在阴晴不定的市场行情再次让众人扼腕叹息的时候,作为EOS社区的深度参与者,我们希望以一种特别的方式,与EOS社区成员一起迎接新一年的到来。这是一系列文章,包含了基础的EOS的概念和必备的操作方法,我称之为:EOS42章经。邀请你来一起同行。每天一个小概念,走过42天,一起过新年。天气越冷,越要坚定。今天开篇,多说一点。为什么计划做EOS42章经系列?EOS系统相对复杂,账号模型,权限设计,资源模型,投票、治理模型各个方面,往往乱花渐欲迷人眼;EOS的变化日新月异,往往令新人想要学,却又不知道从何学起。对于无技术背景的同学而言,想要一窥EOS的全貌,却容易陷入茫茫信息洪流之中。而且每天关于EOS的新闻和文章层出不穷,往往让想要了解的同学,无所适从。想要系统学习EOS的基础知识,往往需要借助于媒体的只言片语,或者各类社区之中的小范围交流。EOS42章经系列文章,期望通过基础概念的打磨,帮助EOS初学者也能够理解解基础的概念,想要理解EOS的方方面面,其实并不需要先学会编程才行。希望借此机会,能够跟各位EOS关注者一起,一个一个概念去梳理清楚,降低EOS的认知
大家经常说:无工具不管理、无数据难决策。所以企业的人力资源管理,我们首先要考虑在目前大数据背景下如何开展人力资源数据的整理与分析。当前,移动互联网、社交应用、大数据等技术浪潮凶猛来袭,正在加速驱动着企业人力资源管理的信息化进程。那么,到底如何有效迎接这一浪潮,如何以价值为导向,整理、分析,并发掘出关键信息加以分析利用,从而提升人力资源管理效益,是每一位管理者面临的问题。如何通过建立人力资源数据库,完成全面的数据化分析,实现用数据说话,真正推动企业人力资源管理转型升级,支撑企业战略发展。人力资源管理也需要快速摆脱事务管理、主管评价、感性决策的现状,逐步步入到数据化、网络化的科学管理时代。一、人力资源大数据的关键要素对于大数据在人力资源管理中的应用,最关键的不是数据绝对化的大与多,而是信息的丰富性与连续性。有的企业可能认为企业人员没有那么多,人力资源数据不足以“大”,因此觉得企业的人力资源数据分析没有价值,可以不用做数据分析,实则不然。人力资源的大数据分析主要有三个关键要素:第一,要全体不要抽样,也就是不再像以前调查采用抽样的模式,而是要全体数据,即全部员工的数据,越全越好;第二,要相关不
已不推荐本方法,多渠道打包请看【Android】Walle多渠道打包&Tinker热修复。现状多渠道打包,相信很同学都知道。在AndroidStudio中只要经过配置,就能打出对应市场的渠道包。打过包的同学可能都会有这样的感受:散热器疯狂地转、打包速度那叫一个慢。这时候除了无奈,还是无奈~~场景(讲一个我现实中遇到的情况) 今天APP要发布,已经是晚上八点多。这时候功能已经测得差不多了,老大说可以打包了。美好的时光即将到来,打完包就可以回家了,这个点还能回家撸几把。想到这里就有点小激动 一共要打7个包,每个包大概2~3分钟。开始打包,于是电脑疯狂转了十几分钟。完毕,坐等发布。这时候发现一个文案错误,要我改一下。这不是要了亲命,我刚打完的包。一个文案错误,又要浪费我十几分钟等打包。这种情况多来个几次,晚上不用回家了都。 有一次,我一晚上打了六次包,一次十五分钟来算,光打包的时间就花了一个多小时,这能忍?作为一个高(lan)效(duo)的程序员,怎么能把宝贵的休息时间花在等待上。解决方案在介绍之前,要感谢我的同事阮阮同学,这个解决方案是阮阮同学教我的。 这里我来介绍一个更加快速的打
所谓广义线性模型,顾名思义就是一般狭义线性模型的推广,那我们先看看我们一般的狭义线性模型,这在第十讲也说过可以参看http://www.ppvke.com/Blog/archives/30010,我们经常说的线性回归是OLS线性模型.这种模型的拟合方法是将实际观测值与理论预测值的误差平方和使之最小化,从而推导出线性模型的参数,即最小二乘法.而广义线性模型是通过极大似然估计法来估计参数的,所谓极大似然估计,就是将观测值所发生的概率连乘起来,得到似然函数,然后求似然函数的极大值,来推导出线性模型的参数,其中原理就是,既然一次实验某个结果发生了,那么我们可以认为,这个结果在这次实验中发生的概率是比较大的,那么,这次结果发生的概率是与模型的参数有关的,只要求出最大概率相应的参数自然就确定了,这里假设每个观测之间的相互独立的,才能用连乘的方法将每个观测的概率密度连乘起来。其实在OLS回归中,我们也可以用极大似然估计发方法来估计参数,我们可以发现其结果和最小二乘法的结果是相同的.而在广义模型中我们使用极大似然估计方法.另外,一般的OLS线性模型是有前提假设的,这在前面的章节中有讲到,参见http:
老常时间没写了,这次是真碰到心动的东西了,赶快给大家奉献上来。 (先上图!) (Cloud9IDE,云端IDE,简单一点就是运行在浏览器中的IDE,你不需要安装任何东西, 只要打开任何一个浏览器,甚至包括手机、平板电脑的浏览器,然后你的网速不是很慢, 你就可以在你的开发世界里享受了。) 我也是刚刚接触这个开发环境,这里不做详细介绍,只是简单的说几点,具体的细节留给 大家自己去探索(https://c9.io/)。 1.她是基于Web的,她是在线的,这意味着你在不同地点、不同设备、不同系统上体验 到的开发环境几乎是一模一样的。我觉得这一点很重要,有时你上班时很有精神,可是回 到家后,可能仅仅是因为自己电脑上编辑器某些设置的不合意,你就立马没心情再看代码 了,又去捣鼓你的编辑器了。 2.她是一款IDE,她不仅仅包含编辑器,她还包含有各种语言的编译运行环境。这一点对 于像我这种初学者很重要,我可以随时了解、学习各种语言,写一些简单的小程序。 举一 个极端的例子,假使你在网吧里玩游戏玩累了,你想写一点程序,这时你可以立马打开c9.io ,你
一、摄动法 在各种量子力学书中所介绍的微扰论,其数学原理就是数学中的摄动法。还有黄昆固体物理书297页就是用摄动法解玻尔兹曼方程。 摄动法非常好的介绍:非线性微分方程的近似解析求解——摄动法-知乎(zhihu.com) 这里作者提到使用摄动法需要对方程无量纲化,这是因为“小参数”是相对的小。而无量纲化的取法是猜出来的。 另外,这个作者写的有限差分法也很好:微分方程数值求解——有限差分法-知乎(zhihu.com) 二、我关于摄动法的问题 问题:但是我很奇怪的是,为什么黄昆固体物理书、量子力学书中使用微扰论都没有提到无量纲化?为什么黄昆固体物理书以及一些论文(比如sipe00年论文)直接就将分布函数按电场阶数展开,并没有无量纲化?比如黄昆书中: 我网上查了一些资料,都是说使用摄动法必须无量纲化,但是我不知道为什么必须无量纲化? 我数学不好,想了很久想不出来,算了,就相信那些资料说的必须无量纲化吧。 单位换算和无量纲化的方法 单位换算和无量纲化的方法可以参考:量纲转换神器-知乎(zhihu.com)中介绍的:Permeability(µ-Magneticpermeability,Ma
1.【UnicodeEncodeError:'ascii'codeccan'tencodecharactersinposition0-1:ordinalnotinrange】 原因 字符串在Python内部的表示是unicode编码,因此,在做编码转换时,通常需要以unicode作为中间编码,即先将其他编码的字符串解码(decode)成unicode,再从unicode编码(encode)成另一种编码。 Decode的作用是将其他编码的字符串转换成unicode编码,如str1.decode('gb2312'),表示将gb2312编码的字符串str1转换成unicode编码。 Encode的作用是将unicode编码转换成其他编码的字符串,如str2.encode('gb2312'),表示将unicode编码的字符串str2转换成gb2312编码。 因此,转码的时候一定要先搞明白,字符串str是什么编码,然后decode成unicode,然后再encode成其他编码,代码中字符串的默认编码与代码文件本身的编码一致。 python在安装时,默认的编码是ascii,当程序中出现非as
vertlet积分常用于质点牛顿动力学仿真,像分子动力学仿真,原理数值分析和博客都比较详细了,下面的MassPt这个类有 mS-位置,mV-速度,mF-力这几个牛顿运动方程中的质点的几个物理状态,测试时仿真的高中小球平抛运动5秒中,每0.1秒 一个仿真步,初始是在0高度,根据h=0.5*g*t^2,g取9.8,则可见s在t=5时mS.y=-122.5 y | * ---->x * * * 下面算例在控制台下打印每个仿真步的位置,没有做多余的可视化。 #include<iostream> #include"vec3d.h" usingnamespaceosg; classMassPt { public: MassPt() {
8086计算机组织 文章目录 8086计算机组织一.微机的一般构成1.CPU2.主存储器3.输入输出设备4.系统总线 二.Intel8086/8088CPU的功能结构三.Intel8086/8088CPU的寄存器以及功能1.通用寄存器(1)数据寄存器组成功能 (2)指针寄存器组成功能 (3)变址寄存器组成功能 2.段寄存器3.指令指针组成功能 4.标志寄存器组成功能 (1)进位标志位(2)奇偶标志位PF(3)辅助进位标志位AF(4)零值标志位(5)符号标志位(6)溢出标志位(7)单步标志位(TraceFlag,TF)(8)中断允许标志位(IF)(9)方向标志位(DF) 四.存储器的组织结构1.存储器的组成2.存储器的段结构(1)存储器段结构特点(2)逻辑地址和物理地址及其对应关系 五.堆栈及其操作方法1.堆栈的构造2.设置堆栈 一.微机的一般构成 运算器、控制器(中央处理器)、存储器、I/O设备 1.CPU 包括:运算器和控制器 功能: 2.主存储器 功能:存放程序和数据的部件。 存储器容量:存储单元的多少;对于每一个存储单元的访问都需要通过:地址 ti
第二次结对作业 这个作业属于哪个课程 https://edu.cnblogs.com/campus/fzzcxy/SE/ 江李悦 211706178 冯志成 211706170 这个作业要求在哪里 https://edu.cnblogs.com/campus/fzzcxy/SE/homework/10417 这个作业的目标 将调查问卷的结果进行可视化处理和原型设计 作业正文 如下文 其他参考文献 无 一.简单自我介绍 大家好!我是计科二班的江李悦,我的结队队友是同班的冯志成同学,此次结队作业由我们两个共同完成,如果有什么地方大家觉得不严谨或者可以完善的地方,欢迎大家提出来,也希望大家可以多多支持。 二.数据可视化 为了让用户可以更加直观的了解疫情期间网课的教学效果,对问卷数据进行可视化。 电脑端体验: https://free.modao.cc/app/2a6fc7d8db347cdc9ac16afc4ed001dee8cbcd2d?simulator_type=device&sticky 移动端体验: 1.大家更喜欢线上还是线下学习?
很久没有写了呢。 这次,我想向悦悦真诚的道歉。 六一做错了好多好多事。 我的错误之一,在于浪费,明明有和悦悦说了不浪费的(上一次我们出去我已经有一次这样的行为了),但是为了一时高兴,有在悦悦明明告诫我的前提下浪费了。 错误之二,在于并没有给悦悦一个很好的休息体验,我答应了悦悦只一次的,但是却因为自己那本就不太重要的过度欲望,让悦悦和我第二次了,让悦悦很累,身体有很多不适感。同时,也没有给我的悦悦一个很好的吃饭体验,下次六一不会了,当然,烧烤一定是加入黑名单了。 错误之三,在于之前总是挑悦悦的刺,虽然六一是用开玩笑的语气和你说的,但是,如果我总是这样,我的悦悦也会不开心的。 错误之四,过度的仅仅让悦悦单方面偏爱我,在无论是性(或者是情感、身体上的关怀)六一都有点太放纵而不节制了。 但悦悦,六一会慢慢的改正,我难以意识到或改的不好的地方也请悦悦监督六一,在六一答应你要做到的事情上,悦悦不要委屈自己好不好?我们可以商量,你不愿意的,你不能接受的,悦悦可以稍微严肃的告诉六一,让六一清楚的意识到六一的行为将会或者可能会对你造成伤害,或让你有不开心的情绪。 不过呢,六一觉得也有很棒的地方嘛,拍了那