从零构建属于自己的GPT系列3:模型训练2(训练函数解读、模型训练函数解读、代码逐行解读)
- 创业
- 2025-07-21 19:18:16

🚩🚩🚩Hugging Face 实战系列 总目录
有任何问题欢迎在下面留言 本篇文章的代码运行界面均在PyCharm中进行 本篇文章配套的代码资源已经上传
从零构建属于自己的GPT系列1:数据预处理 从零构建属于自己的GPT系列2:模型训练1 从零构建属于自己的GPT系列3:模型训练2 从零构建属于自己的GPT系列4:模型训练3
3 数据加载函数 def load_dataset(logger, args): logger.info("loading training dataset") train_path = args.train_path with open(train_path, "rb") as f: train_list = pickle.load(f) train_dataset = CPMDataset(train_list, args.max_len) return train_dataset 日志报告加载训练数据训练数据路径将以二进制形式存储的数据文件使用 pickle 加载到内存中的 train_list 变量中加载CPMDataset包,将train_list从索引转化为torch tensor返回tensor 4 训练函数 def train(model, logger, train_dataset, args): train_dataloader = DataLoader( train_dataset, batch_size=args.batch_size, shuffle=True, num_workers=args.num_workers, collate_fn=collate_fn, drop_last=True ) logger.info("total_steps:{}".format(len(train_dataloader)* args.epochs)) t_total = len(train_dataloader) // args.gradient_accumulation_steps * args.epochs optimizer = transformers.AdamW(model.parameters(), lr=args.lr, eps=args.eps) scheduler = transformers.get_linear_schedule_with_warmup( optimizer, num_warmup_steps=args.warmup_steps, num_training_steps=t_total )# 设置warmup logger.info('start training') train_losses = [] # 记录每个epoch的平均loss for epoch in range(args.epochs): train_loss = train_epoch( model=model, train_dataloader=train_dataloader, optimizer=optimizer, scheduler=scheduler, logger=logger, epoch=epoch, args=args) train_losses.append(round(train_loss, 4)) logger.info("train loss list:{}".format(train_losses)) logger.info('training finished') logger.info("train_losses:{}".format(train_losses)) 训练函数制作Dataloader制作Dataloader制作Dataloader制作Dataloader日志添加信息Dataloader*epochs的数量记录数据长度到t_total变量中指定优化器学习率衰减策略,从transformers包中调用现成的get_linear_schedule_with_warmup方法设置warmup等参数学习率衰减策略日志添加信息开始训练记录所有epoch的训练损失,以求每个epoch的平均loss遍历每个epoch指定一个我们自己写的train_epoch函数1train_epoch函数2train_epoch函数3train_epoch函数4记录损失,只保存4位小数记录日志信息训练损失记录日志信息训练完成最后一句是在日志中保存所有损失吗? 5 迭代训练函数train_epoch def train_epoch(model, train_dataloader, optimizer, scheduler, logger, epoch, args): model.train() device = args.device ignore_index = args.ignore_index epoch_start_time = datetime.now() total_loss = 0 # 记录下整个epoch的loss的总和 epoch_correct_num = 0 # 每个epoch中,预测正确的word的数量 epoch_total_num = 0 # 每个epoch中,预测的word的总数量 for batch_idx, (input_ids, labels) in enumerate(train_dataloader): try: input_ids = input_ids.to(device) labels = labels.to(device) outputs = model.forward(input_ids, labels=labels) logits = outputs.logits loss = outputs.loss loss = loss.mean() batch_correct_num, batch_total_num = calculate_acc(logits, labels, ignore_index=ignore_index) epoch_correct_num += batch_correct_num epoch_total_num += batch_total_num batch_acc = batch_correct_num / batch_total_num total_loss += loss.item() if args.gradient_accumulation_steps > 1: loss = loss / args.gradient_accumulation_steps loss.backward() torch.nn.utils.clip_grad_norm_(model.parameters(), args.max_grad_norm) if (batch_idx + 1) % args.gradient_accumulation_steps == 0: optimizer.step() scheduler.step() optimizer.zero_grad() if (batch_idx + 1) % args.log_step == 0: logger.info( "batch {} of epoch {}, loss {}, batch_acc {}, lr {}".format( batch_idx + 1, epoch + 1, loss.item() * args.gradient_accumulation_steps, batch_acc, scheduler.get_lr())) del input_ids, outputs except RuntimeError as exception: if "out of memory" in str(exception): logger.info("WARNING: ran out of memory") if hasattr(torch.cuda, 'empty_cache'): torch.cuda.empty_cache() else: logger.info(str(exception)) raise exception epoch_mean_loss = total_loss / len(train_dataloader) epoch_mean_acc = epoch_correct_num / epoch_total_num logger.info( "epoch {}: loss {}, predict_acc {}".format(epoch + 1, epoch_mean_loss, epoch_mean_acc)) logger.info('saving model for epoch {}'.format(epoch + 1)) model_path = join(args.save_model_path, 'epoch{}'.format(epoch + 1)) if not os.path.exists(model_path): os.mkdir(model_path) model_to_save = model.module if hasattr(model, 'module') else model model_to_save.save_pretrained(model_path) logger.info('epoch {} finished'.format(epoch + 1)) epoch_finish_time = datetime.now() logger.info('time for one epoch: {}'.format(epoch_finish_time - epoch_start_time)) return epoch_mean_loss train_epoch函数指定训练模式训练设备需要忽略的索引当前epoch开启的具体时间当前epoch的loss总和当前epoch预测词正确的总数量每个epoch需要预测的测的总数量for训练从train_dataloader遍历取数据捕捉异常输入词的索引数据进入训练设备标签数据进入训练设备输入数据经过前向传播得到输出经过softmax后的输出得到损失平均损失通过calculate_acc函数统计该batch的预测token的正确数与总数统计该epoch的预测token的正确数统计该epoch的预测token的总数计算该batch的accuracy获得损失值的标量累加到当前epoch总损失如果当前的梯度累加步数大于1对当前累加的损失对梯度累加步数求平均损失反向传播梯度裁剪:梯度裁剪的目的是控制梯度的大小,防止梯度爆炸的问题。在训练神经网络时,梯度可能会变得非常大,导致优化算法出现数值不稳定的情况。裁剪梯度就是将梯度的整体范数限制在一个特定的阈值之内达到梯度累加的次数后更新参数更新学习率梯度清零梯度累加次数为0时,也就是参数更新时记录日志记录的各个参数占位符占位符对应的各个变量删除两个变量,释放内存捕捉到异常如果异常的信息中的字符串包含内存不足的问题,也就是显卡内存不足将该问题添加到日志信息当显卡内存占用过多时手动释放显卡内存如果不是显卡内存不足记录日志返回异常记录当前epoch的平均loss记录当前epoch的平均accuracy日志记录信息记录的信息为当前epoch索引、损失、准确率日志记录信息,当前保存的模型以及对于的epoch索引保存模型的地址如果地址不存在创建该地址确保得到不是外壳对象保存模型日志记录信息训练完成记录完成时间记录当前epoch训练所花费时间返回epoch平均损失从零构建属于自己的GPT系列1:数据预处理 从零构建属于自己的GPT系列2:模型训练1 从零构建属于自己的GPT系列3:模型训练2 从零构建属于自己的GPT系列4:模型训练3
从零构建属于自己的GPT系列3:模型训练2(训练函数解读、模型训练函数解读、代码逐行解读)由讯客互联创业栏目发布,感谢您对讯客互联的认可,以及对我们原创作品以及文章的青睐,非常欢迎各位朋友分享到个人网站或者朋友圈,但转载请说明文章出处“从零构建属于自己的GPT系列3:模型训练2(训练函数解读、模型训练函数解读、代码逐行解读)”