dandelionsllm / pandallm

Panda项目是于2023年5月启动的开源海外中文大语言模型项目,致力于大模型时代探索整个技术栈,旨在推动中文自然语言处理领域的创新和合作。
Apache License 2.0
1.07k stars 91 forks source link

请问如何在COIG数据集上继续训练 #23

Closed scarydemon2 closed 1 year ago

scarydemon2 commented 1 year ago

作者你好,最近我在训练我们的BLOOMZ模型,数据使用的是BELLE公开的一部分和我们自己的一部分数据。训练完发现模型在instruction following的能力不是特别好。 你们提到训练完之后,再在COIG数据集上训练instruction following的能力会有提升。因此我们做了一些实验。发现似乎继续微调的话模型整体的能力都有很明显的下降。 请问你们在使用COIG数据做训练是如何实现的?有什么特殊的技巧吗?超参数如何设置的?

SparkJiao commented 1 year ago

首先,提升instruction following是指相对于在普通语料上用Causal LM的方式预训练得到的模型有提升,不太清楚你提到的BELLE的数据是指通用语料还是instruction tuning的语料,如果是后者,COIG可能确实不会让性能继续提升。 同理,如果你们已经用了Alpaca的语料,从chat或者instruction following的角度来说应该都不会比COIG差。所以我觉得可能是模型本身效果就不够好,可以尝试换一个基座模型(有同学反馈说Boolmz作为基座模型的效果比较差,可以试试LLaMA) 另外超参数可以在 config 这里找到,这是instruction tuning阶段的,预训练阶段的学习率小了很多。

lucasjinreal commented 1 year ago

@SparkJiao 借楼问一下,我看有一些实现在instruction微调的时候,把输入mask掉,有些会把输入加到训练里面,请问一下正常情况下,这么处理输入input_ids 和 labels 可以吗?

elif "instruction" in data_point.keys() and "input" in data_point.keys():
            prefix = "Human:"
            inp = data_point["input"]
            instruction = data_point["instruction"]
            output = data_point["output"]
            inp = inp.strip()
            instruction = instruction.strip()
            output = output.strip()

            if inp is not None and inp != "":
                # does order matters?
                instruction += inp
            if len(instruction) > 0:
                prefix = prefix + instruction + "\n"
            prefix += "Assistant:"
            sentence_ids = tokenizer.encode(
                prefix, add_special_tokens=False
            )  # do not add bos_token_id
            tgt_ids = tokenizer.encode(output, add_special_tokens=False)
            # label = [IGNORE_INDEX] * len(sentence_ids) + tgt_ids
            input_ids += sentence_ids + tgt_ids
            # labels += label
            input_ids += [tokenizer.eos_token_id]
            # labels += [tokenizer.eos_token_id]
            # labels = 

        input_ids = input_ids[: max_seq_length - 1]
        # train on inputs
        labels = input_ids.copy()

        labels = labels[: max_seq_length - 1]
        if not any(x > -100 for x in labels):
            labels[18:24] = input_ids[
                18:24
            ]  # labels can not have all values being -100. 18 and 24 are just random numbers

        # print(f'-----test sample:\n{tokenizer.decode(input_ids, skip_special_tokens=True)}\n------end')
        attention_mask = [1] * len(input_ids)
        tokenized_full_prompt = {
            "input_ids": input_ids,
            "attention_mask": attention_mask,
            "labels": labels,
        }
SparkJiao commented 1 year ago

@SparkJiao 借楼问一下,我看有一些实现在instruction微调的时候,把输入mask掉,有些会把输入加到训练里面,请问一下正常情况下,这么处理输入input_ids 和 labels 可以吗?

elif "instruction" in data_point.keys() and "input" in data_point.keys():
            prefix = "Human:"
            inp = data_point["input"]
            instruction = data_point["instruction"]
            output = data_point["output"]
            inp = inp.strip()
            instruction = instruction.strip()
            output = output.strip()

            if inp is not None and inp != "":
                # does order matters?
                instruction += inp
            if len(instruction) > 0:
                prefix = prefix + instruction + "\n"
            prefix += "Assistant:"
            sentence_ids = tokenizer.encode(
                prefix, add_special_tokens=False
            )  # do not add bos_token_id
            tgt_ids = tokenizer.encode(output, add_special_tokens=False)
            # label = [IGNORE_INDEX] * len(sentence_ids) + tgt_ids
            input_ids += sentence_ids + tgt_ids
            # labels += label
            input_ids += [tokenizer.eos_token_id]
            # labels += [tokenizer.eos_token_id]
            # labels = 

        input_ids = input_ids[: max_seq_length - 1]
        # train on inputs
        labels = input_ids.copy()

        labels = labels[: max_seq_length - 1]
        if not any(x > -100 for x in labels):
            labels[18:24] = input_ids[
                18:24
            ]  # labels can not have all values being -100. 18 and 24 are just random numbers

        # print(f'-----test sample:\n{tokenizer.decode(input_ids, skip_special_tokens=True)}\n------end')
        attention_mask = [1] * len(input_ids)
        tokenized_full_prompt = {
            "input_ids": input_ids,
            "attention_mask": attention_mask,
            "labels": labels,
        }

没太仔细看你的代码 大体上应该是没问题的 instruction tuning阶段对instruction部分不计算loss是为了把这个当成conditional generation去做 如果你是普通的文本 并不建议对输入只计算部分损失 没有这样做的理由

lucasjinreal commented 1 year ago

@SparkJiao 好的,感谢。pandallm里面也是 没有mask inputs吗?

SparkJiao commented 1 year ago

@lucasjinreal 有的。可以参考data collator部分,我们有对instruction和input部分做mask

lucasjinreal commented 1 year ago

但是我看有些地方 会打开输入的 loss计算,在训练sft的时候,这是处于什么考量呢,哪种方式更优啊

SparkJiao commented 1 year ago

请说一下哪里打开了?

SparkJiao commented 1 year ago

不好意思不太清楚别的方案里这样做的考虑 建议去问他们