比赛地址:医疗诊疗对话意图识别

V1:

方案:BERT
预训练模型:bert-base-chinese

分数:0.8043

 Val P: 0.7621,  Val R: 76.7676%,  Val F1: 0.7619,  Val Acc: 81.5204%

V2:
分数:0.8158
排名:长期赛:193(本次)/1561

方案:BERT+CNN
预训练模型:bert-base-chinese

训练结果:
Val P: 0.758,  Val R: 76.6730%,  Val F1: 0.7595,  Val Acc: 81.7135%

后期优化思路:

1、使用行业模型微调

2、尝试bert+bilstm+crf

3、词嵌入时单独增加角色信息编码

4、多模型融合

运行脚本:
python run_bert.py

源码下载:

比赛地址:医疗诊疗对话意图识别挑战赛BERT/BERT+CNN资源-CSDN文库

模型:配置bert

import torch
import torch.nn as nn
# from pytorch_pretrained_bert import BertModel, BertTokenizer
from transformers import BertModel, BertTokenizer, BertConfig
from transformers import AutoModel, AutoTokenizer, AutoConfig
import os



class Config(object):

    """配置参数"""
    def __init__(self, dataset, local=False):
        self.local = local
        self.date='20241106'
        self.model_name = 'bert_'+self.date
        self.train_path = dataset + '/data/train.txt'                                # 训练集
        self.dev_path = dataset + '/data/dev.txt'                                    # 验证集
        self.test_path = dataset + '/data/test.txt'                                  # 测试集
        self.class_list = [x.strip() for x in open(
            dataset + '/data/class.txt').readlines()]                                # 类别名单
        self.save_path = dataset + '/saved_dict/'+self.model_name+'.ckpt'        # 模型训练结果
        self.save_path_best = dataset + '/saved_dict/'+self.model_name+'.ckpt'        # 模型训练结果
        self.save_path_test_org = dataset + '/data_old/test.json'         # 测试源文件
        self.save_path_test = dataset + '/saved_dict/test'+self.date+'.json'        # 测试结果
        self.device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')   # 设备

        self.require_improvement = 1000                                 # 若超过1000batch效果还没提升,则提前结束训练
        self.num_classes = len(self.class_list)                         # 类别数
        self.batch_size = 128                                           # mini-batch大小
        self.pad_size = 256                                              # 每句话处理成的长度(短填长切)
        self.learning_rate = 5e-5                                       # 学习率
        self.dropout = 0.3
        if local and local == True:
            self.bert_path = 'E:/models/bert-base-chinese'
            self.num_epochs = 1  # epoch数
        else:
            self.bert_path = '/data/nfs/baozhi/models/google-bert_bert-base-chinese'
            self.num_epochs = 10  # epoch数
        self.tokenizer = BertTokenizer.from_pretrained(self.bert_path)
        self.transformer_config = BertConfig.from_pretrained(self.bert_path)
        # self.tokenizer = AutoTokenizer.from_pretrained(self.bert_path)
        # self.transformer_config = AutoConfig.from_pretrained(self.bert_path)
        self.hidden_size = 768


class Model(nn.Module):

    def __init__(self, config: Config):
        super(Model, self).__init__()
        self.bert = BertModel.from_pretrained(config.bert_path)
        for param in self.bert.parameters():
            param.requires_grad = True
        self.dropout = nn.Dropout(config.dropout)
        # self.fc = nn.Linear(config.hidden_size, config.num_classes)
        self.linear = nn.Linear(config.hidden_size, config.num_classes)


    # def forward(self, token_ids, attention_masks, token_type_ids):
    #     bert_outputs = self.bert(
    #         input_ids=token_ids,
    #         attention_mask=attention_masks,
    #         token_type_ids=token_type_ids,
    #     )
    #     seq_out = bert_outputs[1]
    #     seq_out = self.dropout(seq_out)
    #     seq_out = self.linear(seq_out)
    #     return seq_out

    def forward(self, x):
        context = x[0]  # 输入的句子
        mask = x[2]  # 对padding部分进行mask,和句子一个size,padding部分用0表示,如:[1, 1, 1, 1, 0, 0]
        bert_outputs = self.bert(context, attention_mask=mask)
        seq_out = bert_outputs[1]
        seq_out = self.dropout(seq_out)
        seq_out = self.linear(seq_out)
        return seq_out

模型+配置:bert+cnn

import torch
import torch.nn as nn
import torch.nn.functional as F
from transformers import BertModel, BertTokenizer, BertConfig


class Config(object):

    """配置参数"""

    def __init__(self, dataset, local=False):
        self.local = local
        self.date = '20241106'
        self.model_name = 'bert_' + self.date
        self.train_path = dataset + '/data/train.txt'  # 训练集
        self.dev_path = dataset + '/data/dev.txt'  # 验证集
        self.test_path = dataset + '/data/test.txt'  # 测试集
        self.class_list = [x.strip() for x in open(
            dataset + '/data/class.txt').readlines()]  # 类别名单
        self.save_path = dataset + '/saved_dict/' + self.model_name + '.ckpt'  # 模型训练结果
        self.save_path_best = dataset + '/saved_dict/' + self.model_name + '.ckpt'  # 模型训练结果
        self.save_path_test_org = dataset + '/data_old/test.json'  # 测试源文件
        self.save_path_test = dataset + '/saved_dict/test' + self.date + '.json'  # 测试结果
        self.device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')  # 设备

        self.require_improvement = 1000  # 若超过1000batch效果还没提升,则提前结束训练
        self.num_classes = len(self.class_list)  # 类别数
        self.learning_rate = 5e-5  # 学习率
        self.dropout = 0.1
        if local and local == True:
            self.bert_path = 'E:/models/bert-base-chinese'
            self.num_epochs = 1  # epoch数
            self.pad_size = 32  # 每句话处理成的长度(短填长切)
            self.batch_size = 16  # mini-batch大小
        else:
            self.bert_path = '/data/nfs/baozhi/models/google-bert_bert-base-chinese'
            self.num_epochs = 10  # epoch数
            self.pad_size = 256  # 每句话处理成的长度(短填长切)
            self.batch_size = 128  # mini-batch大小
        self.tokenizer = BertTokenizer.from_pretrained(self.bert_path)
        self.transformer_config = BertConfig.from_pretrained(self.bert_path)
        # self.tokenizer = AutoTokenizer.from_pretrained(self.bert_path)
        # self.transformer_config = AutoConfig.from_pretrained(self.bert_path)
        self.hidden_size = 768

        self.filter_sizes = [2, 3, 4]                                   # 卷积核尺寸
        self.num_filters = 256                                          # 卷积核数量(channels数)



class Model(nn.Module):

    def __init__(self, config):
        super(Model, self).__init__()
        self.bert = BertModel.from_pretrained(config.bert_path)
        for param in self.bert.parameters():
            param.requires_grad = True
        self.convs = nn.ModuleList(
            [nn.Conv2d(1, config.num_filters, (k, config.hidden_size)) for k in config.filter_sizes])
        self.dropout = nn.Dropout(config.dropout)

        self.fc_cnn = nn.Linear(config.num_filters * len(config.filter_sizes), config.num_classes)

    def conv_and_pool(self, x, conv):
        x = F.relu(conv(x)).squeeze(3)
        x = F.max_pool1d(x, x.size(2)).squeeze(2)
        return x

    def forward(self, x):
        context = x[0]  # 输入的句子
        mask = x[2]  # 对padding部分进行mask,和句子一个size,padding部分用0表示,如:[1, 1, 1, 1, 0, 0]
        outputs = self.bert(context, attention_mask=mask)
        bert_output = outputs.last_hidden_state  # (batch_size, seq_len, 768)
        bert_output = bert_output.unsqueeze(1)  # (batch_size, 1, seq_len, 768)

        conv_outputs = [conv(bert_output).squeeze(3) for conv in self.convs]  # [(batch_size, num_filters, seq_len - fs + 1)]
        pooled_outputs = [nn.functional.max_pool1d(co, co.size(2)).squeeze(2) for co in conv_outputs]  # [(batch_size, num_filters)]
        concatenated = torch.cat(pooled_outputs, 1)  # (batch_size, num_filters * len(filter_sizes))
        concatenated = self.dropout(concatenated)
        logits = self.fc_cnn(concatenated)
        return logits

更多推荐