基于textcnn的MR数据分类

Textcnn模型
上图为TextCnn的网络结构,我们将利用上图的模型进行MR数据集的分析:
首先一般的文本分析主要为以下步骤:

  • 将句子转成词,利用词建立字典
  • 词转成向量(word2vec,Glove,bert,nn.embedding)
  • 句子补0操作变成等长
  • 建立Textcnn模型,训练和测试
    我们所要进行的MR数据集分类也要经历上述步骤,不过有所不同的是MR数据集没有划分好训练集,验证集和测试集,需要我们利用K折交叉验证对数据处理。
    其中:
    ( K折交叉验证用于模型调优,所有的数据都被用来训练,会导致过拟合,K折交叉验证可以缓解过拟合。将数据分为k组,每次从训练集中,抽取出k份中的一份数据作为验证集,剩余数据作为测试集。测试结果采用k组数据的平均值。若训练集较大,则k较小,降低训练成本,若训练集较小,则k较大,增加训练数据。如k=10,则90%的数据被训练;k=20,留一K折交叉验证,是K折交叉验证的一种特例,每次从数据集中抽取一个数据作为测试数据,一般用于数据集很小的情况。)
    将数据集分为训练集,验证集,测试集,并利用word2vec将词转换成向量,然后进行训练,测试。
    下面我将利用代码分析对过程进行解释。

参数设置

class N_config():
    def __init__(self):
        self.embedding_pretrained = None # 是否使用预训练的词向量
        self.n_vocab = 100 # 词表中单词的个数
        self.embed_size = 300 # 词向量的维度
        self.cuda = False # 是否使用gpu
        self.filter_num = 100 # 每种尺寸卷积核的个数
        self.filters = [3,4,5] # 卷积核的尺寸
        self.label_num = 2 # 标签个数
        self.dropout = 0.5 # dropout的概率
        self.batch_size = 50 #最大句子长度
        self.epoch = 200 #训练的轮数
        self.gpu   = 0   #是否使用GPU
        self.learning_rate = 0.0005 #学习率
        self.seed = 1 #随机种子
        self.l2   = 0.004 #l2正则化权重
        self.use_pretrained_embed = True #是否使用预训练
        self.k = 0 #交叉验证的k值

将必要的参数利用class封装在parameter函数中:

  • embedding_pretrained —》》是否使用预训练的词向量
  • n_vocab —》》词表中单词的个数
  • embed_size —》》词向量的维度
  • cuda —》》是否使用gpu
  • filter_num—》》每种尺寸卷积核的个数
  • filters—》》卷积核的尺寸
  • label_num —》》标签个数
  • dropout—》》dropout的概率
  • batch_size—》》最大句子长度
  • epoch—》》训练的轮数
  • gpu —》》是否使用GPU
  • learning_rate —》》学习率
  • seed —》》随机种子
  • l2 —》》l2正则化权重

数据处理

from torch.utils import data
import os
import random
import numpy as np
from gensim.models import KeyedVectors


class MR_Dataset(data.Dataset):
    def __init__(self,state="train",k=0,embedding_type="word2vec"):

        self.path = os.path.abspath('.')
        if "data" not in self.path:
            self.path+="/data"
        # 导入数据及
        pos_samples = open(self.path+"/MR/rt-polarity.pos",errors="ignore").readlines()
        neg_samples = open(self.path+"/MR/rt-polarity.neg",errors="ignore").readlines()
        datas = pos_samples+neg_samples
        #datas = [nltk.word_tokenize(data) for data in datas]
        datas = [data.split() for data in datas]
        max_sample_length = max([len(sample) for sample in datas]) # 求句子最大长度,将所有句子pad成一样的长度
        labels = [1]*len(pos_samples)+[0]*len(neg_samples)
        word2id = {"<pad>":0} # 生成word2id
        for i,data in enumerate(datas):
            for j,word in enumerate(data):
                if word2id.get(word)==None:
                    word2id[word] = len(word2id)
                datas[i][j] = word2id[word]
            datas[i] = datas[i]+[0]*(max_sample_length-len(datas[i]))
        self.n_vocab = len(word2id)
        self.word2id = word2id
        self.get_word2vec()
        c = list(zip(datas,labels)) # 打乱训练集
        random.seed(1)
        random.shuffle(c)
        datas[:],labels[:] = zip(*c)
        if state=="train": # 生成训练集
            self.datas = datas[:int(k * len(datas) / 10)] + datas[int((k + 1) * len(datas) / 10):]
            self.labels = labels[:int(k * len(datas) / 10)] + labels[int((k + 1) * len(labels) / 10):]
            self.datas = np.array(self.datas[0:int(0.9*len(self.datas))])
            self.labels = np.array(self.labels[0:int(0.9*len(self.labels))])
        elif state == "valid": # 生成验证集
            self.datas = datas[:int(k * len(datas) / 10)] + datas[int((k + 1) * len(datas) / 10):]
            self.labels = labels[:int(k * len(datas) / 10)] + labels[int((k + 1) * len(labels) / 10):]
            self.datas = np.array(self.datas[int(0.9 * len(self.datas)):])
            self.labels = np.array(self.labels[int(0.9 * len(self.labels)):])
        elif state == "test": # 生成测试集
            self.datas = np.array(datas[int(k * len(datas) / 10):int((k + 1) * len(datas) / 10)])
            self.labels = np.array(labels[int(k * len(datas) / 10):int((k + 1) * len(datas) / 10)])

    def __getitem__(self, index):
        return self.datas[index], self.labels[index]

    def __len__(self):
        return len(self.datas)


将数据处理的MR_Dataset封装在data函数中:
首先导入相应的库, 进行初始化:

  1. 首先判断在当前路径是否含有data文件如果没有就添加,然后导入数据将MR数据集中的积极和消极的词语分别导入,并进行组合
  2. 然后将数据中的每一句子的单词分离,由于数据集分为积极和消极两个部分,可以分别利用0,1代表消极和积极构成标签,利用句子的最大长度将所有的数据填充成相同大小,并把每一次映射到词向量里
  3. 由于数据集中的数据是按照积极和消极数据排序,现在要将数据打乱,由于要保证每一个数据集和标签对应,所以必须将数据集和标签打包并转换成列表并且随机打乱。
  4. 然后利用k折交叉验证,这里将数据分为10份。将第从开始到第k份的数据集和k+1到结尾的数据和标签取出,并且将其中90%的数据作为训练集,其余10%作为验证集。将第k份数据作为测试集。
  5. 后利用类中的函数可以方便获取信息如由输入的索引返回数据和标签,和返回词的长度
    接上:
    def get_word2vec(self):
        '''
        生成word2vec词向量
        :return: 根据词表生成的词向量
        '''
        if  not os.path.exists(self.path+"/word2vec_embedding_mr.npy"): # 如果已经保存了词向量,就直接读取
            print ("Reading word2vec Embedding...")
            wvmodel = KeyedVectors.load_word2vec_format("D:/python/GoogleNews-vectors-negative300.bin.gz",binary=True)
            tmp = []
            for word, index in self.word2id.items():
                try:
                    tmp.append(wvmodel.get_vector(word))
                except:
                    pass
            mean = np.mean(np.array(tmp))
            std = np.std(np.array(tmp))
            print (mean,std)
            vocab_size = self.n_vocab
            embed_size = 300
            embedding_weights = np.random.normal(mean,std,[vocab_size,embed_size]) # 正太分布初始化方法
            for word, index in self.word2id.items():
                try:
                    embedding_weights[index, :] = wvmodel.get_vector(word)
                except:
                    pass
            np.save(self.path+"/word2vec_embedding_mr.npy", embedding_weights) # 保存生成的词向量
        else:
            embedding_weights = np.load(self.path+"/word2vec_embedding_mr.npy") # 载入生成的词向量
        self.weight = embedding_weights

我们已经构成了词典,接下来就是将每一个词转换成Word2vec的词向量:

  1. 先判断当前路径中是否已经含有了词向量如果含有直接导入,如果没有将已经训练好的word2vec词向量导入。
  2. 利用数据集中的数据对应求得词向量,加入列表求取方差和标准差利用其和词向量大小和,嵌入大小随机生成权重
  3. 将每个词向量在word2vec中的词张量保存
  4. 如果在路径已经含有就将其直接导入。

模型构建

我们basicmodel和TextCnnmodel封装到basic,model两个python函数:

class BasicModule(nn.Module):
    def __init__(self):
        super(BasicModule, self).__init__()
        self.model_name = str(type(self))

    def load(self, path):
        self.load_state_dict(torch.load(path))

    def save(self, path):
        torch.save(self.state_dict(), path)

    def forward(self):
        pass


if __name__ == '__main__':
    print('Running the BasicModule.py...')
    model = BasicModule()

BasicModel():

  • 继承torch.nn.model模块
  • 可以将数据导入和保存
class TextCNN(BasicModule):

    def __init__(self, config):
        super(TextCNN, self).__init__()
        if config.embedding_pretrained is not None:
            self.embedding = nn.Embedding.from_pretrained(config.embedding_pretrained, freeze=False)
        else:
            self.embedding = nn.Embedding(config.n_vocab, config.embed_size)
        if config.cuda:
            self.convs = [nn.Conv1d(config.embed_size, config.filter_num, filter_size).cuda()
                          for filter_size in config.filters]
        else:
            self.convs = [nn.Conv1d(config.embed_size, config.filter_num, filter_size)
                          for filter_size in config.filters]
        self.dropout = nn.Dropout(config.dropout)
        self.fc = nn.Linear(config.filter_num * len(config.filters), config.label_num)

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

    def forward(self, x):
        out = self.embedding(x)
        out = out.transpose(1, 2).contiguous()
        out = torch.cat([self.conv_and_pool(out, conv) for conv in self.convs], 1)
        out = self.dropout(out)
        out = self.fc(out)
        return out

通过BasicModel的导入TextCnnmodel()

  • 首先进行初始化:先判断是否进行预训练,和GPU对数据进行嵌入层和卷积处理,设置dropout函数和线性全连接层将卷积的结果分类。
  • 由池化层将定义激活函数和最大池化
  • 定义forward模块,对输入的权重嵌入,并将其第二维和第三维转置,将数据先卷积再最大池化,将所有得到的数据cat集合在一起,经Dropout后经线性全连接层进行分类
    注:其中涉及的所有函数中的参数均参考 N_config中的设定

验证工具

由于我们要进行交叉验证,对数据要进行不断处理,所以当数据的loss一直不变时停止训练;我将EarlyStopping封装到tool函数中:

class EarlyStopping:
    """Early stops the training if validation loss doesn't improve after a given patience."""
    def __init__(self, patience=7, verbose=False, delta=0,cv_index = 0)
        self.patience = patience
        self.verbose = verbose
        self.counter = 0
        self.best_score = None
        self.early_stop = False
        self.val_loss_min = np.Inf
        self.delta = delta
        self.cv_index = cv_index

    def __call__(self, val_loss, model):

        score = -val_loss

        if self.best_score is None:
            self.best_score = score
            self.save_checkpoint(val_loss, model)
        elif score < self.best_score + self.delta:
            self.counter += 1
            print('EarlyStopping counter: %d out of %d'%(self.counter,self.patience))
            if self.counter >= self.patience:
                self.early_stop = True
        else:
            self.best_score = score
            self.save_checkpoint(val_loss, model)
            self.counter = 0

    def save_checkpoint(self, val_loss, model):
        '''Saves model when validation loss decrease.'''
        if self.verbose:
            print('Validation loss decreased (%.5f --> %.5f).  Saving model ...'%(self.val_loss_min,val_loss))
        torch.save(model.state_dict(), './checkpoints/checkpoint%d.pt'%self.cv_index)
        self.val_loss_min = val_loss
  • patience (int):改进了上次验证丢失后的等待时间。默认值:7
  • verbose (bool):如果为True,则打印每个验证丢失改进的消息。默认值:False
  • delta(浮动):监测数量的最小变化,以合格为改进。默认值:0
    这里我们将Loss取负数使其越小越好,首先由其best_score默认值为None,由判断可将sore的值赋给其,并将其进行保存,后再经过调用判断sore是否小于self.best_score + self.delta,如果小于使count加1,当count的值大于等于patience (这里我们设置为10),将停止训练设置为Ture;否则将sore再次赋给best_score,保存并将count归零。

主函数

前面我介绍了封装的函数,现在介绍主函数对该项目目的实现:

from parameter import N_config
from data_process import MR_Dataset
from  model_buiding import TextCNN
import torch
import torch.optim as optim
import torch.nn as nn
from tool import EarlyStopping
import numpy as np
import torch.autograd as autograd

导入相关库:
将N_config,MR_Datase,TextCnn和EarlyStoppingt从parameter,data_process,model_buiding,tool函数中导入
定义相关函数

config = N_config()


def get_parameter():
    print("参数准备完毕!")
    print()

将参数初始化

def get_data():
    torch.manual_seed(config.seed)
    if torch.cuda.is_available():
        torch.cuda.set_device(config.gpu)
    training_set = MR_Dataset(state="train", k=config.k)
    config.n_vocab = training_set.n_vocab
    training_iter = torch.utils.data.DataLoader(dataset=training_set,
                                                batch_size=config.batch_size,
                                                shuffle=True,
                                                num_workers=2)
    if config.use_pretrained_embed:
        config.embedding_pretrained = torch.from_numpy(training_set.weight).float()
    else:
        pass
    valid_set = MR_Dataset(state="valid", k=config.k)
    valid_iter = torch.utils.data.DataLoader(dataset=valid_set,
                                             batch_size=config.batch_size,
                                             shuffle=False,
                                             num_workers=2)
    test_set = MR_Dataset(state="test", k=config.k)
    test_iter = torch.utils.data.DataLoader(dataset=test_set,
                                            batch_size=config.batch_size,
                                            shuffle=False,
                                            num_workers=2)
    print("数据准备完毕!")
    print()
    return training_iter, valid_iter, test_iter,valid_set,test_set

get_data():

  • 首先对参数进行随机初始化
  • 判断是否使用GPU对训练数据集,验证数据集,测试数据集获取并返回
  • 并将其转换成张量形式
def get_model(pa):
    model = TextCNN(pa)
    if config.cuda and torch.cuda.is_available():
        model.cuda()
        config.embedding_pretrained.cuda()
    print('模型构建完毕!')
    print()
    return model


def get_loss_and_opitm():
    criterion = nn.CrossEntropyLoss()
    optimizer = optim.Adam(model.parameters(), lr=config.learning_rate)
    print('损失函数和优化器构建完毕!')
    print()
    return criterion, optimizer

将模型和损失函数以及优化器设置

def get_test_result(data_iter,data_set):
    model.eval()
    data_loss = 0
    true_sample_num = 0
    for data, label in data_iter:
        if config.cuda and torch.cuda.is_available():
            data = data.cuda()
            label = label.cuda()
        else:
            data = torch.autograd.Variable(data).long()
        out = model(data)
        loss = criterion(out, autograd.Variable(label.long()))
        data_loss += loss.data.item()
        true_sample_num += np.sum((torch.argmax(out, 1) == label).cpu().numpy()) #(0,0.5)
    acc = true_sample_num / data_set.__len__()
    return data_loss,acc
   

将数据集传入,将数据集中的数据和标签遍历出,通过判断是否需要GPU将数据转换成张量,计算数据中正确的个数,最后利用正确的个数除以数据的总长度获得正确率。
进行训练

acc = 0
    for i in range(0, 10):  # 10-cv
        print("现在进行第{}fold的运算".format(i+1))
        early_stopping = EarlyStopping(patience=10, verbose=True, cv_index=i)
        print("-----获取数据集--------------")
        training_iter,valid_iter,test_iter,valid_set,test_set = get_data()
        print('------构建模型---------------')
        model = get_model(config)
        if config.cuda and torch.cuda.is_available():
            model.cuda()
            config.embedding_pretrained.cuda()
        print('------构建损失函数和优化器---------')
        criterion ,optimizer = get_loss_and_opitm()
        count = 0
        loss_sum = 0
      

通过对10折的交叉验证,将工具EarlyStopping的patience设置为10,进行数据集的构建,和模型构建和优化器的使用

 print("-----现在开始训练--------")
        for epoch in range(config.epoch):
            # 开始训练
            model.train()
            for data, label in training_iter:
                if config.cuda and torch.cuda.is_available():
                    data = data.cuda()
                    label = label.cuda()
                else:
                    data = torch.autograd.Variable(data).long()
                label = torch.autograd.Variable(label).squeeze()
                out = model(data)
                l2_loss = config.l2 * torch.sum(torch.pow(list(model.parameters())[1], 2))
                loss = criterion(out, autograd.Variable(label.long())) + l2_loss
                loss_sum += loss.data.item()
                count += 1
                if count % 100 == 0:
                    print("epoch", epoch, end='  ')
                    print("The loss is: %.5f" % (loss_sum / 100))
                    loss_sum = 0
                    count = 0
                optimizer.zero_grad()
                loss.backward()
                optimizer.step()
                # save the model in every epoch
            # 一轮训练结束,在验证集测试
            valid_loss, valid_acc = get_test_result(valid_iter, valid_set)
            early_stopping(valid_loss, model)
            print("The valid acc is: %.5f" % valid_acc)
            if early_stopping.early_stop:
                print("Early stopping")
                break
        # 1 fold训练结果
        model.load_state_dict(torch.load('./checkpoints/checkpoint%d.pt' % i))
        test_loss, test_acc = get_test_result(test_iter, test_set)
        print("The test acc is: %.5f" % test_acc)
        acc += test_acc / 10
    # 输出10-fold的平均acc
    print("The test acc is: %.5f" % acc)

正试训练

  • 通过循环进行200轮的训练
  • model.train()进入训练模式,和下文中测试中的 get_test_result():中model.eval()进入测试模式有所不同,因为在训练的过程要根据一定的概率Dropout一部分数据,而在测试中不需要,这相当于集成化的学习,如果在测试中使用model.train()会使结果差很多。
  • 随后判断是否使用GPU,如果使用就将其转换到GPU中,如果不就将其转换成torch中long的形式,label也将其转换Torch类型
  • 然后,将数据传入模型进行L2正则计算总的损失每一百个输出一次,通过手动调零,反向传播求导和优化循环训练
    验证
  • 将验证集导入get_test_result,early_stopping.early_stop,由其进行判断当达到patience值后停止验证
    测试
    通过导入先前保存的数据,将测试集传入,获得正确率
    输出10折的平均正确率

结果

我的运行截图如下:
在这里插入图片描述
运行过程大概是这样,因为我使用的CPU训练很慢,就只截取前一部分。

总结

  • 这是我对前一段时间学习的总结笔记
  • 主要利用MR数据集(利用K折交叉验证),通过Word2vec进行词向量的转换实现MR数据集的分类
  • 这里使用的CPU会使训练的时间很长,可以使用GPU改进
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: bcc-csm2-mr 数据处理是指对bcc-csm2-mr全球气候模型生成的数据进行处理和分析的过程。bcc-csm2-mr是由中国气象科学研究院(北京)开发的一个耦合全球气候模型,能够模拟地球气候系统的运行情况。 在数据处理过程中,首先需要对模型生成的原始数据进行清洗和预处理。这包括检查数据的完整性、有效性和一致性,去除无效或错误的数据,填补缺失值,并进行数据格式转换和标准化。清洗和预处理后,数据才能被用于后续的分析和应用。 接下来,可以对处理后的数据进行多种分析方法的应用。例如,可以使用统计学方法来计算和求取数据的统计特征,例如平均值、方差、相关系数等。还可以利用时间序列分析方法来研究数据的变化趋势和周期性。此外,还可以进行空间分析,以探索地区之间的差异和相关性。 在数据处理过程中,还可以利用可视化技术将结果呈现出来,使得数据更加直观和易于理解。例如,可以使用地图、图表等方式展示数据的分布和变化,帮助研究人员更好地理解数据的内在规律和趋势。 最后,数据处理的结果可以为气候科学研究、气候变化预测和决策支持等领域提供重要信息和依据。例如,可以用于评估气候变化对人类社会和生态环境的影响,研究气候变化的机理和驱动因素,以及制定应对气候变化的政策和措施。 总之,bcc-csm2-mr 数据处理是一个复杂而关键的过程,通过对模型生成的数据进行清洗、预处理、分析和可视化,为气候科学研究和应用提供重要基础和支持。 ### 回答2: bcc-csm2-mr 是一种用于数据处理的模型。 数据处理是指将原始数据进行清洗、分析和转换,以便提取有用的信息和知识的过程。对于 bcc-csm2-mr 模型而言,它主要用于处理气候数据。 首先,该模型会对原始气候观测数据进行质量控制,删除有错误和缺失的数据,并进行填补处理,以确保数据的准确性和完整性。接下来,模型会对数据进行重采样,将原始观测数据转换为更适合模型输入的格式和时间分辨率。同时,还会进行空间插值,将数据在不同地点之间进行插值,以填补空白区域。 然后,模型会对数据进行预处理,包括数据去噪、滤波和降维等操作。这些操作旨在减少数据的噪声和冗余,提高数据的可用性和可解释性。接着,模型会进行统计分析和建模,利用各种算法和技术来寻找数据中的模式和趋势,以便对气候系统进行建模和预测。 最后,模型会对处理后的数据进行后处理和可视化,将结果以图表、图像和报告的形式展示出来,以便人们更好地理解和利用这些数据。同时,模型还支持数据的存储和共享,以便其他研究人员或机构能够使用这些数据进行不同的研究和应用。 总之,bcc-csm2-mr 是一个用于处理气候数据的模型,它通过一系列的数据清洗、分析、转换和建模等操作,从原始数据中提取有用的信息和知识,为气候研究和预测提供支持。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值