python/nimport torch/nimport torch.nn as nn/nimport torch.optim as optim/nfrom seqeval.metrics import classification_report, f1_score/nfrom torch.utils.data import DataLoader/nfrom tqdm import tqdm/nfrom copy import deepcopy/nimport warnings/nimport matplotlib.pyplot as plt/nfrom transformers import logging/n/nfrom dataset import LABEL, Data_set, idx2tag, padding/nfrom model.bert_bilstm_crf import BertBilstmCRF # 导入BERT-BiLSTM-CRF模型/n/nlogging.set_verbosity_warning()/n/nwarnings.filterwarnings('ignore', category=DeprecationWarning)/n/ndevice = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')/n/ndef train(model, train_iter, optimizer, loss_fn):/n '''/n 训练函数/n '''/n model.train()/n train_l_sum, c = 0., 0/n for i, (x, y) in enumerate(train_iter):/n x, y = x.to(device), y.to(device)/n y_hat = model(x) # 获取模型预测结果/n loss = loss_fn(y_hat, y) # 计算损失/n optimizer.zero_grad(set_to_none=True)/n loss.backward()/n optimizer.step()/n train_l_sum += loss.item()/n c += 1/n/n if (i + 1) % 15 == 0:/n print(f'step: {i + 1}, cur train loss: {loss.item():.6f}')/n/n return train_l_sum / c/n/ndef evaluate(model, eval_iter, report=False):/n '''/n 评估模型/n '''/n model.eval()/n y_true, y_pred = [], []/n with torch.no_grad():/n for x, y in tqdm(eval_iter):/n masks = (x != 0).numpy()/n x = x.to(device)/n logits = model(x) # 获取模型预测结果/n y_hat = model.decode(logits, masks) # 使用CRF解码获取预测标签/n y = y.numpy()/n for sentence, pred, mask in zip(y, y_hat, masks):/n y_true.append([/n idx2tag[l] for l, m in zip(sentence, mask) if m/n ])/n y_pred.append([/n idx2tag[l] for l, m in zip(pred, mask) if m/n ])/n/n eval_f1 = f1_score(y_pred=y_pred, y_true=y_true)/n if report:/n print('classification report:')/n print(classification_report(y_true=y_true, y_pred=y_pred))/n/n return eval_f1/n/ndef main(args):/n # 加载数据集/n train_set = Data_set('BIOES_data/processed/all/train.txt', args['pretrained_path'])/n dev_set = Data_set('BIOES_data/processed/all/dev.txt', args['pretrained_path'])/n test_set = Data_set('BIOES_data/processed/all/test.txt', args['pretrained_path'])/n train_iter = DataLoader(/n dataset=train_set,/n batch_size=args['batch_size'],/n collate_fn=padding,/n num_workers=4,/n pin_memory=True/n )/n dev_iter = DataLoader(/n dataset=dev_set,/n batch_size=args['batch_size'],/n collate_fn=padding,/n num_workers=4,/n pin_memory=True/n )/n test_iter = DataLoader(/n dataset=test_set,/n batch_size=args['batch_size'],/n collate_fn=padding,/n num_workers=4,/n pin_memory=True/n )/n/n # 加载模型/n model = BertBilstmCRF(/n output_size=args['output_size'],/n hidden_size=args['hidden_size'],/n drop_prob=args['drop_prob'],/n embed_size=args['embed_size'],/n num_layers=args['num_layers'],/n pretrained_path=args['pretrained_path']/n )/n model.to(device)/n loss_fn = nn.CrossEntropyLoss() # 使用交叉熵损失函数/n optimizer = optim.Adam(params=model.parameters(), lr=args['lr'])/n/n best_model, best_f1 = None, 0./n train_losses, eval_f1s = [], []/n for e in range(args['epochs']):/n train_loss = train(model, train_iter, optimizer, loss_fn)/n eval_f1 = evaluate(model, dev_iter)/n train_losses.append(train_loss)/n eval_f1s.append(eval_f1)/n if best_f1 < eval_f1:/n best_f1 = eval_f1/n best_model = deepcopy(model)/n print('Epoch: {}, train_loss: {:.6f} eval_f1: {:.6f}'.format(/n e + 1, train_loss, eval_f1/n ))/n/n evaluate(best_model, test_iter, report=True)/n x_ticks = list(range(1, args['epochs'] + 1, 10))/n plt.figure(figsize=(8, 6))/n plt.subplot(1, 2, 1)/n plt.title('Train Set Loss')/n plt.plot(list(range(args['epochs'])), train_losses)/n plt.xticks(x_ticks)/n plt.xlabel('Epoch')/n plt.ylabel('Loss')/n plt.subplot(1, 2, 2)/n plt.title('Valid Set F1-Score')/n plt.plot(list(range(args['epochs'])), eval_f1s)/n plt.xticks(x_ticks)/n plt.xlabel('Epoch')/n plt.ylabel('f1 score')/n plt.savefig('result/outcome.png')/n plt.show()/n/nif __name__ == '__main__':/n params = {/n 'pretrained_path': 'bert-base-chinese-ws',/n 'lr': 0.001,/n 'batch_size': 64,/n 'epochs': 100,/n 'output_size': len(LABEL),/n 'embed_size': 768,/n 'hidden_size': 256,/n 'num_layers': 2,/n 'drop_prob': 0.5/n }/n print(params)/n main(params)/n/n/n主要修改点:/n/n1. 模型导入: 将 from model.bert_bilstm import BertBilstm 修改为 from model.bert_bilstm_crf import BertBilstmCRF,导入BERT-BiLSTM-CRF模型。/n2. 解码操作: 在 evaluate 函数中,使用 model.decode(logits, masks) 对模型输出进行CRF解码,获取最终预测标签。/n3. 损失函数: 在 main 函数中,loss_fn = nn.CrossEntropyLoss() 使用交叉熵损失函数来计算损失。/n4. BertBilstmCRF 模型: 需要您自己定义 BertBilstmCRF 模型,具体实现参考相关文献和代码。/n/n其他注意事项:/n/n* 确保 dataset 文件夹下的 Data_set 类以及 padding 函数正常工作。/n* 确保 model 文件夹下的 bert_bilstm_crf.py 文件存在,并且包含 BertBilstmCRF 模型的定义。/n* 调整代码中的参数,如 batch_sizeepochs 等,以获得最佳的训练效果。/n/n建议您参考以下资源:/n/n* BERT-BiLSTM-CRF模型的介绍和实现:/n * https://huggingface.co/docs/transformers/tasks/sequence/_labeling/n * https://github.com/allenai/allennlp/blob/master/allennlp/modules/conditional/_random/_field.py/n* BIOES标注方式:/n * https://www.kaggle.com/code/abhishek/bert-for-ner-using-bioes-tagging-scheme/n* CRF解码:/n * https://en.wikipedia.org/wiki/Conditional/_random/_field/n * https://www.youtube.com/watch?v=wN-p_1ZVm2s/n/n完成以上步骤后,您应该能够成功训练BERT-BiLSTM-CRF模型并进行命名实体识别任务。', 'code': 'python/nimport torch/nimport torch.nn as nn/nimport torch.optim as optim/nfrom seqeval.metrics import classification_report, f1_score/nfrom torch.utils.data import DataLoader/nfrom tqdm import tqdm/nfrom copy import deepcopy/nimport warnings/nimport matplotlib.pyplot as plt/nfrom transformers import logging/n/nfrom dataset import LABEL, Data_set, idx2tag, padding/nfrom model.bert_bilstm_crf import BertBilstmCRF # 导入BERT-BiLSTM-CRF模型/n/nlogging.set_verbosity_warning()/n/nwarnings.filterwarnings('ignore', category=DeprecationWarning)/n/ndevice = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')/n/ndef train(model, train_iter, optimizer, loss_fn):/n '''/n 训练函数/n '''/n model.train()/n train_l_sum, c = 0., 0/n for i, (x, y) in enumerate(train_iter):/n x, y = x.to(device), y.to(device)/n y_hat = model(x) # 获取模型预测结果/n loss = loss_fn(y_hat, y) # 计算损失/n optimizer.zero_grad(set_to_none=True)/n loss.backward()/n optimizer.step()/n train_l_sum += loss.item()/n c += 1/n/n if (i + 1) % 15 == 0:/n print(f'step: {i + 1}, cur train loss: {loss.item():.6f}')/n/n return train_l_sum / c/n/ndef evaluate(model, eval_iter, report=False):/n '''/n 评估模型/n '''/n model.eval()/n y_true, y_pred = [], []/n with torch.no_grad():/n for x, y in tqdm(eval_iter):/n masks = (x != 0).numpy()/n x = x.to(device)/n logits = model(x) # 获取模型预测结果/n y_hat = model.decode(logits, masks) # 使用CRF解码获取预测标签/n y = y.numpy()/n for sentence, pred, mask in zip(y, y_hat, masks):/n y_true.append([/n idx2tag[l] for l, m in zip(sentence, mask) if m/n ])/n y_pred.append([/n idx2tag[l] for l, m in zip(pred, mask) if m/n ])/n/n eval_f1 = f1_score(y_pred=y_pred, y_true=y_true)/n if report:/n print('classification report:')/n print(classification_report(y_true=y_true, y_pred=y_pred))/n/n return eval_f1/n/ndef main(args):/n # 加载数据集/n train_set = Data_set('BIOES_data/processed/all/train.txt', args['pretrained_path'])/n dev_set = Data_set('BIOES_data/processed/all/dev.txt', args['pretrained_path'])/n test_set = Data_set('BIOES_data/processed/all/test.txt', args['pretrained_path'])/n train_iter = DataLoader(/n dataset=train_set,/n batch_size=args['batch_size'],/n collate_fn=padding,/n num_workers=4,/n pin_memory=True/n )/n dev_iter = DataLoader(/n dataset=dev_set,/n batch_size=args['batch_size'],/n collate_fn=padding,/n num_workers=4,/n pin_memory=True/n )/n test_iter = DataLoader(/n dataset=test_set,/n batch_size=args['batch_size'],/n collate_fn=padding,/n num_workers=4,/n pin_memory=True/n )/n/n # 加载模型/n model = BertBilstmCRF(/n output_size=args['output_size'],/n hidden_size=args['hidden_size'],/n drop_prob=args['drop_prob'],/n embed_size=args['embed_size'],/n num_layers=args['num_layers'],/n pretrained_path=args['pretrained_path']/n )/n model.to(device)/n loss_fn = nn.CrossEntropyLoss() # 使用交叉熵损失函数/n optimizer = optim.Adam(params=model.parameters(), lr=args['lr'])/n/n best_model, best_f1 = None, 0./n train_losses, eval_f1s = [], []/n for e in range(args['epochs']):/n train_loss = train(model, train_iter, optimizer, loss_fn)/n eval_f1 = evaluate(model, dev_iter)/n train_losses.append(train_loss)/n eval_f1s.append(eval_f1)/n if best_f1 < eval_f1:/n best_f1 = eval_f1/n best_model = deepcopy(model)/n print('Epoch: {}, train_loss: {:.6f} eval_f1: {:.6f}'.format(/n e + 1, train_loss, eval_f1/n ))/n/n evaluate(best_model, test_iter, report=True)/n x_ticks = list(range(1, args['epochs'] + 1, 10))/n plt.figure(figsize=(8, 6))/n plt.subplot(1, 2, 1)/n plt.title('Train Set Loss')/n plt.plot(list(range(args['epochs'])), train_losses)/n plt.xticks(x_ticks)/n plt.xlabel('Epoch')/n plt.ylabel('Loss')/n plt.subplot(1, 2, 2)/n plt.title('Valid Set F1-Score')/n plt.plot(list(range(args['epochs'])), eval_f1s)/n plt.xticks(x_ticks)/n plt.xlabel('Epoch')/n plt.ylabel('f1 score')/n plt.savefig('result/outcome.png')/n plt.show()/n/nif __name__ == '__main__':/n params = {/n 'pretrained_path': 'bert-base-chinese-ws',/n 'lr': 0.001,/n 'batch_size': 64,/n 'epochs': 100,/n 'output_size': len(LABEL),/n 'embed_size': 768,/n 'hidden_size': 256,/n 'num_layers': 2,/n 'drop_prob': 0.5/n }/n print(params)/n main(params)/n/n

BERT-BiLSTM-CRF模型训练代码:基于BIOES标注的命名实体识别

原文地址: https://www.cveoy.top/t/topic/m6N6 著作权归作者所有。请勿转载和采集!

免费AI点我,无需注册和登录