模型选择
本小组的项目课题是针对2021级项目实训实施方案中的开题方向“面向法律文书的文本生成系统”,而在小组的项目计划中,课题实现则主要集中在案情分析和智能法条推荐方面,进而辅助法律文书的文本生成。
经过测试,例如清华技术成果转化的ChatGLM无法实现具体的法条推荐功能,而openAI的GPT大模型,由于国内外的差异,反而不符合国人的法律需求。
故本项目实现的法律文本分析系统由ChatGLM-6B LoRA 16-bit指令微调得到。数据集包括现有的法律问答数据集、结合法条的实际司法实践中的案例所构建的高质量法律文本问答系统,目前已将大语言模型确定,此后还需要结合模型的问答输出结果将模型python接口与后端相连接。
模型微调过程
已完成
没有使用特定的依赖,只需要根据ChatGLM官方给出的requirements准备环境(命令行) GitHub - THUDM/ChatGLM-6B: ChatGLM-6B: An Open Bilingual Dialogue Language Model | 开源双语对话语言模型
显存方面,本人选用的的ChatGLM-6B是FP16精度的,运行代码需要不少于14G的显存;后续要进行进一步的LoRA微调的话,显存硬件条件的要求更高。
(注:由于配置足够完成FP16精度的ChatGLM-6B进行部署,故未尝试量化模型减少部署开支)
5.20
微调过程发现在该模型下训练92K对话数据集需要满足单卡显存 >= 15G,存在显存不足情况即
若采用LoRA微调ChatGLM-6B(FP16)时报错torch.OutOfMemoryError:CUDA out of Memory.
5.27
若训练代码采用并行算法训练模型,完成对ChatGLM LoRA FP16的指令微调可以加快训练速度
python train.py \
--title $EXP_NAME \
--train_path $TRAINING_DATA_PATH \
--save_dir $LORA_CHECKPOINT_SAVE_PATH
CUDA_VISIBLE_DEIVCES=0
模型微调:
- ChatGLM 6B 模型下载
- 样本准备与数据预处理
- 模型训练与参数调整
- 模型测试
模型数据集准备
已完成
本次微调的数据集样本准备如下:
- 带有法律条文依据的情景问答
- 律所真实案情分析(中文数据)
- 详见主页 https://github.com/liuhuanyong/CrimeKgAssitant
5.20
加入法律知识问题的解释性回答,占比20%,真实情景对话下调至80%
5.22
调整数据集结构,添加新采集的ChatGPT单轮情景对话数据集,主要为结合具体法条的案情分析问答,与法律知识解释占比为1:1:3
模型训练细节
已完成
模型参数设置及调整:
- 直接在train.py运行文档设置和调整模型训练参数,确定模型训练配置,包括lora微调
def train():
parser = ArgumentParser()
parser.add_argument("--train_path", type=str, default= ", help="Path of the trainset")
parser.add_argument("--model_checkpoint", type=str, default="/model", help="Path, url or short name of the model")
parser.add_argument("--peft_path", type=str, default=None, help="Model type (gpt or gpt2)")
parser.add_argument("--save_dir", type=str,default= './Fine_Tuning_Results')
parser.add_argument("--title", type=str,default= ' ')
parser.add_argument("--train_batch_size", type=int, default=2, help="Batch size for training")
parser.add_argument("--n_epochs", type=int, default=1, help="Number of training epochs")
parser.add_argument("--lr1", type=float, default=5e-6, help="model1 learning rate")
parser.add_argument("--lora_rank", type=int, default=8, help="lora_rank")
parser.add_argument("--lora_alpha", type=int, default=16, help="lora_alpha")
parser.add_argument("--lora_dropout", type=float, default=0.1, help="lora_dropout")
parser.add_argument("--local_rank", type=int, default=-1, help="Local rank for distributed training (-1: not distributed)")
parser.add_argument("--device", type=str, default="cuda" if torch.cuda.is_available() else "cpu", help="Device (cuda or cpu)")
parser.add_argument("--gradient_accumulation_steps", type=int, default=2, help="Accumulate gradients on several steps")
parser.add_argument("--max_norm", type=float, default=1.0, help="Clipping gradient norm")
parser.add_argument("--eval_before_start", action='store_true', help="If true start with a first evaluation before training")
parser.add_argument("--log_path", type=str, default="log/", help="Log path")
args = parser.parse_args()
args.log_path = os.path.join(args.log_path,args.title)
def train_step(engine, batch):
model.train()
batch = tuple(input_tensor.to(args.device) for input_tensor in batch)
input_ids,lm_labels = batch
loss = model(input_ids=input_ids,labels=lm_labels).loss
loss = (loss / args.gradient_accumulation_steps)
loss.backward()
torch.nn.utils.clip_grad_norm_(model.parameters(), args.max_norm)
if engine.state.iteration % args.gradient_accumulation_steps == 0:
optimizer1.step()
optimizer1.zero_grad()
if engine.state.iteration % 500 == 0:
logger.info("Epoch [%d], Iter [%d] Loss: %.4f" % (engine.state.epoch, engine.state.iteration, loss.item()))
return loss.item()
trainer = Engine(train_step)
p_scheduler1 = PiecewiseLinear(optimizer1, "lr", [(0, args.lr1), ((args.n_epochs) * len(train_loader)-5000, 0.0)])
5.20
调整训练数据集,添加法律知识回答数据,更新参数结构(除去问题的answer还包括reference)
模型训练策略采用可靠的自监督方式,对于ChatGLM自身训练以及结合ChatGPT情景对话数据集训练均可适用,通过文本段+问题的方式让网络自己回答所生成的问题,保证回答的准确性,并且确保涵盖了法律知识的问题回答。
- 模型训练框架图:
其中情景对话训练包括question、answer和reference,使用的训练样例与网络生成的回答数据:
question:张三激怒想要轻生的李四,间接造成李四不堪精神压力、坠楼身亡,请问张三的行为是否触犯刑法?
answer:如果李四因被张三施压想要轻生,间接造成其不堪精神压力、坠楼身亡的行为,可能触犯中国刑法。
reference:根据刑法的规定,自杀是指故意非法剥夺自己的生命力。需要注意的是,自杀不是自诉案件,如果想为张三对李四的行为辩护,需要聘请专业的律师为其提供法律咨询和辩护。如果需要帮助,建议及时咨询当地律师或相关部门。
法律知识问题的解释性回答:
question:如果遭遇校园霸凌,肇事者需要承担什么法律责任?
answer:遭遇霸凌是一种严重的社会问题,肇事者需要承担法律责任来保护受害人的权益。
根据中国《民法通则》和《刑法》的规定,肇事者需要承担相应的法律责任。
reference:《民法通则》规定,侵犯他人合法权益,给他人造成财产损失或者人身伤害的,应当承担民事责任。如果肇事者的行为导致受害人死亡或者严重残疾的,应当承担刑事责任。
《刑法》规定,侵犯他人合法权益,给他人造成财产损失或者人身伤害的,应当承担刑事责任。如果肇事者的行为导致受害人死亡或者严重残疾的,可能需要被判处长期有期徒刑或者无期徒刑。
如果遭受霸凌,并肇事者因此造成了受害人的伤害,肇事者可能需要承担相应的法律责任。具体的法律责任和处罚措施需要根据具体情况来确定。若需要帮助,建议及时咨询当地律师或相关部门。
目前的数据集包括现有的法律问答数据集和 基于法条和真实案例指导以及法律解释 的self-Instruct构建的高质量法律文本问答
6.23
更改数据集生成错误数据,固定修改外的组件完成模型微调,更新参数后重新运行样例 “A公司的总经理在签订大单合同时,由于其严重不负责任,被诈骗,导致公司损失重大” 生成法条正确,给出第二条建议
模型测试结果
正在调整模型输出
模型参数设置及调整:
- 在demo.py中设置模型运行参数,添加多个devices分担模型运行开销,加快生成速度
parser = ArgumentParser()
parser.add_argument('--model_path', type=str, default = "model")
parser.add_argument('--model_checkpoint', type=str, default ='model_checkpoint')
parser.add_argument('--peft_path', type=str, default = 'peft_model/lora.p')
parser.add_argument('--lora_use', type=bool, default = True)
parser.add_argument('--adapter_use', type=bool, default = False)
parser.add_argument('--gpu_id', type=str, default = "0")
parser.add_argument("--seed", type=int, default=3407)
args = parser.parse_args()
# set_seed(args)
##os.environ["CUDA_VISIBLE_DEVICES"] = args.gpu_id #问题所在 2024.4.3
os.environ["CUDA_VISIBLE_DEVICES"] = "3"
#os.environ["CUDA_VISIBLE_DEVICES"] = "0,1,2,3"
def read_json(path):
with open(path, "r") as f:
return json.load(f)
if args.lora_use:
model_class = ChatGLMForConditionalGeneration
model = model_class.from_pretrained(args.model_path, device_map = device_map).half()
model.config.use_cache = True # silence the warnings. Please re-enable for inference!
logger.info("Setup PEFT")
peft_config = LoraConfig(
task_type=TaskType.CAUSAL_LM,
inference_mode=False,
r=8,
lora_alpha=16,
lora_dropout=0.1,
target_modules=['query_key_value'],
)
model = get_peft_model(model, peft_config)
后端与模型连接输出格式
model.eval()
print("#model")
print("Human:")
history=[]
while True:
query = input()
print("#anwser")
if 'new chat' in query:
history=[]
else:
response, history = model.chat(tokenizer, query, history=history, max_length=500)
print(response)
print("#end")
测试预训练模型结果如图:
法律知识问题的解释性回答:
基于法律依据的情景问答:
5.25
测试回顾结果后发现,“在某家IT公司中,软件工程师张三因为长期收到主管领导的欺压,在被迫离职之前报复性地删除了公司的所有备份数据、并破坏了服务器设施,请问张三需要承担什么样的法律责任?”这一案例的法律情景对话中,出现了案情分析不够准确的问题,
analysis:对于案例文本分析中的“报复”和“欺压”等关键词的理解错误,系统误以为是故意杀人相关的犯罪案例,造成了案情分析的不准确。
solution:增加训练相似的真实法律案例,结合律师与真实客户的对话回复弥补对关键词的分析和生成错误。主要针对不同的数据集并行训练,而对于同一名录如刑法下的罪名,例如涉嫌构成故意杀人罪和故意毁坏财物罪,调整参数微调模型作不同分支判断。
5.28
注:目前重点着眼于模型的测试结果对比,通过与北大法律网站等优秀的传统法律帮扶网站相进行比较和补充,主要在法条推荐和生成方面调参和输出格式。同时开始结合固定模板生成法律文书(以及与前后端的输出接口匹配问题)