liangwq / Chatglm_lora_multi-gpu

chatglm多gpu用deepspeed和
404 stars 61 forks source link

模型是否存在信息泄露 #39

Closed 980202006 closed 11 months ago

980202006 commented 1 year ago

我在你的代码基础上,将标点的attention_mask置为0,即不mask。但训练时,发现模型很快就收敛了,且会读到未来的token,即使是无意义的。 step: 0 如下示例: 为了得到完整的句子,我构造了这样的示例,进行forward。输出结果第一个字符最大概率为"会增加"这个token。另外训练时,loss很快收敛到了0.01左右。(一个epoch) Instruction: 根据主题生成中文歌词,每一句歌词用中文逗号隔开 Input:这首歌的歌词的主题是爱情和乌梅子酱。生成的歌词为: 会增加会增加会增加会增加会增加会增加会增加会增加会增加,会议上会议上会议上会议上会议上会议上会议上会议上会议上,保证了保证了保证了保证了保证了保证了保证了保证了,多是多是多是多是多是多是,完全没有完全没有完全没有完全没有完全没有完全没有完全没有完全没有完全没有完全没有完全没有完全没有完全没有,升值升值升值升值升值升值升值升值升值,茵茵茵茵茵茵茵茵茵,句话句话句话句话句话句话句话句话,西路西路西路西路西路西路,其中一个其中一个其中一个其中一个其中一个其中一个其中一个其中一个其中一个其中一个其中一个其中一个其中一个,发脾气发脾气发脾气发脾气发脾气发脾气,关税关税关税关税关税关税关税关税关税关税关税关税关税,就好像就好像就好像就好像就好像就好像就好像就好像就好像,口袋口袋口袋口袋口袋口袋口袋口袋口袋,辽宁省辽宁省辽宁省辽宁省辽宁省辽宁省辽宁省辽宁省,大佬大佬大佬大佬大佬大佬,重要的是重要的是重要的是重要的是重要的是重要的是重要的是重要的是重要的是重要的是重要的是重要的是重要的是,沪指沪指沪指沪指沪指沪指,一口气一口气一口气一口气一口气一口气一口气一口气一口气一口气一口气一口气一口气。

mask相关代码:

    def encode_input(self, prompt_str, bs=1):
        input_ids = []
        position_ids = []
        prompt_str = prompt_str.replace(',',',')
        prompt_str = prompt_str.replace(':',':')
        prompt = self.tokenizer.encode(prompt_str.split('每句字数:')[0]+ '生成的歌词为:')
        # sent_word_counts = eval(f"[{prompt_str.split('每句字数:')[-1][:-1].replace('\nAnswer: 生成的歌词为:',;)}]")
        counts = prompt_str.split('每句字数:')[-1][:-1].replace('。生成的歌词为','')
        sent_word_counts = eval(f"[{counts}]")
        completion = self.make_output_mask(sent_word_counts)
        _max_length = len(completion) + len(prompt)
        attention_mask = torch.ones((bs, _max_length, _max_length), device=self.device)
        attention_mask.tril_()
        # 需要根据字数构造completion
        # 修复??问题,可能是逗号没有编码对
        completion = [6 if i == 0 else i for i in completion ]
        context_length = prompt.index(130004)
        attention_mask[0, :, :context_length] = 1

        to_pad = _max_length - len(prompt) - len(completion)

        inp = prompt + completion + [self.tokenizer.pad_token_id] * to_pad
        input_ids.append(inp)
        # convert to tensor
        input_ids = torch.tensor(input_ids, device=self.device).long()
        pun_pos = [i for i, x in enumerate(inp) if x == 6]
        pun_pos += [i for i, x in enumerate(inp) if x == 63823]  # 句号
        # 将逗号位置的attention设置为可见
        attention_mask[0, :, pun_pos] = 1

        position_ids.append(torch.stack([torch.arange(0, _max_length, device=self.device),
                                    torch.concat([torch.zeros(context_length - 1, device=self.device),
                                                torch.arange(0, _max_length - context_length + 1,
                                                            device=self.device)])]).long())
        position_ids = torch.stack(position_ids)
        attention_mask.unsqueeze_(1)
        return {
            'input_ids': input_ids,
            # 'attention_mask': 1 - attention_mask,  # 翻转mask
            'attention_mask':(attention_mask<0.5).bool(),  # 翻转mask
            'position_ids': position_ids
        }
980202006 commented 1 year ago

我尝试了去掉lora,修改未来的token,结果不变;加上lora修改未来token,结果会改变。

liangwq commented 1 year ago

我尝试了去掉lora,修改未来的token,结果不变;加上lora修改未来token,结果会改变。

你大概有多少数据量,数据量分布是怎么样的 lora训练效果在小数量集合上,实验验证是没ptuning-2好 chatglm 6B本身网络已经比较强了,你把私域的数据做迁移数据设计和任务设计挺重要的

liangwq commented 1 year ago

我在你的代码基础上,将标点的attention_mask置为0,即不mask。但训练时,发现模型很快就收敛了,且会读到未来的token,即使是无意义的。 step: 0 如下示例: 为了得到完整的句子,我构造了这样的示例,进行forward。输出结果第一个字符最大概率为"会增加"这个token。另外训练时,loss很快收敛到了0.01左右。(一个epoch) Instruction: 根据主题生成中文歌词,每一句歌词用中文逗号隔开 Input:这首歌的歌词的主题是爱情和乌梅子酱。生成的歌词为: 会增加会增加会增加会增加会增加会增加会增加会增加会增加,会议上会议上会议上会议上会议上会议上会议上会议上会议上,保证了保证了保证了保证了保证了保证了保证了保证了,多是多是多是多是多是多是,完全没有完全没有完全没有完全没有完全没有完全没有完全没有完全没有完全没有完全没有完全没有完全没有完全没有,升值升值升值升值升值升值升值升值升值,茵茵茵茵茵茵茵茵茵,句话句话句话句话句话句话句话句话,西路西路西路西路西路西路,其中一个其中一个其中一个其中一个其中一个其中一个其中一个其中一个其中一个其中一个其中一个其中一个其中一个,发脾气发脾气发脾气发脾气发脾气发脾气,关税关税关税关税关税关税关税关税关税关税关税关税关税,就好像就好像就好像就好像就好像就好像就好像就好像就好像,口袋口袋口袋口袋口袋口袋口袋口袋口袋,辽宁省辽宁省辽宁省辽宁省辽宁省辽宁省辽宁省辽宁省,大佬大佬大佬大佬大佬大佬,重要的是重要的是重要的是重要的是重要的是重要的是重要的是重要的是重要的是重要的是重要的是重要的是重要的是,沪指沪指沪指沪指沪指沪指,一口气一口气一口气一口气一口气一口气一口气一口气一口气一口气一口气一口气一口气。

mask相关代码:

    def encode_input(self, prompt_str, bs=1):
        input_ids = []
        position_ids = []
        prompt_str = prompt_str.replace(',',',')
        prompt_str = prompt_str.replace(':',':')
        prompt = self.tokenizer.encode(prompt_str.split('每句字数:')[0]+ '生成的歌词为:')
        # sent_word_counts = eval(f"[{prompt_str.split('每句字数:')[-1][:-1].replace('\nAnswer: 生成的歌词为:',;)}]")
        counts = prompt_str.split('每句字数:')[-1][:-1].replace('。生成的歌词为','')
        sent_word_counts = eval(f"[{counts}]")
        completion = self.make_output_mask(sent_word_counts)
        _max_length = len(completion) + len(prompt)
        attention_mask = torch.ones((bs, _max_length, _max_length), device=self.device)
        attention_mask.tril_()
        # 需要根据字数构造completion
        # 修复??问题,可能是逗号没有编码对
        completion = [6 if i == 0 else i for i in completion ]
        context_length = prompt.index(130004)
        attention_mask[0, :, :context_length] = 1

        to_pad = _max_length - len(prompt) - len(completion)

        inp = prompt + completion + [self.tokenizer.pad_token_id] * to_pad
        input_ids.append(inp)
        # convert to tensor
        input_ids = torch.tensor(input_ids, device=self.device).long()
        pun_pos = [i for i, x in enumerate(inp) if x == 6]
        pun_pos += [i for i, x in enumerate(inp) if x == 63823]  # 句号
        # 将逗号位置的attention设置为可见
        attention_mask[0, :, pun_pos] = 1

        position_ids.append(torch.stack([torch.arange(0, _max_length, device=self.device),
                                    torch.concat([torch.zeros(context_length - 1, device=self.device),
                                                torch.arange(0, _max_length - context_length + 1,
                                                            device=self.device)])]).long())
        position_ids = torch.stack(position_ids)
        attention_mask.unsqueeze_(1)
        return {
            'input_ids': input_ids,
            # 'attention_mask': 1 - attention_mask,  # 翻转mask
            'attention_mask':(attention_mask<0.5).bool(),  # 翻转mask
            'position_ids': position_ids
        }

我个人的建议是,如果你的数据量不大 你完全可以用local knowledge base的方法来实现 不需要做finetu呢,甚至用few shot方式也可以 训练lora其实还是需要一定数据,数据分布还是有要求的 特别是像chatglm这种模型,参数不多,表达力很强,网络参数应该都是调教过的,你这个时候控制不好,改它少量参数是容易崩的

980202006 commented 1 year ago

谢谢,训练数据是11w个文本对,训练完第一轮,模型就基本上记住了所有的样本。