微博文本分类任务

2023-05-16

数据

借用了这位兄弟的数据,4类文本分类问题:https://blog.csdn.net/qq_28626909/article/details/80382029
在这里插入图片描述

代码参考

预处理工具torchtext学习参考了nlpuserdendi_hust二位兄弟:https://blog.csdn.net/nlpuser/article/details/88067167 https://blog.csdn.net/dendi_hust/article/details/101221922

模型代码学习了dendi_hust兄弟的博客:https://blog.csdn.net/dendi_hust/article/details/94435919
源博客中只有模型部分的代码,所以找了份数据跑下,将整个流程补充完整,顺便加了些代码的注释方便理解。数据集很小,在没用预训练词向量下一定是欠拟合的,结果仅供参考。

预处理

首先,将文件拼成一个DataFrame
在这里插入图片描述
后续处理用torchtext包进行
torchtext官方教程:https://torchtext.readthedocs.io/en/latest/index.html

Field 格式定义

重要的参数:

  1. sequential:是否是可序列化数据(类似于字符串数据),默认值是 True
  2. user_vocab:是否使用 Vocab 对象,如果取 False,则该字段必须是数值类型;默认值是True
  3. tokenize:是一个 function 类型的对象(如 string.cutjieba.cut 等),用于对字符串进行分词;
  4. batch_first:如果该属性的值取 True,则该字段返回的 Tensor 对象的第一维度是 batch 的大小;默认值是False
  5. fix_length:该字段是否是定长,如果取 None 则按同 batch 该字段的最大长度进行pad;
  6. stop_words:停用词,List,在tokenize步会剔除;

重要函数:
build_vocab:为该Field创建Vocab

CONTENT = Field(sequential=True, tokenize=jieba.cut, batch_first=True, fix_length=200, stop_words=stopwords)
LABEL = Field(sequential=False, use_vocab=False)
Dataset 构建数据集

重要参数:

  1. examplesExample对象列表;
  2. fields:格式是List(tuple(str, Field)),其中 strField 对象的描述;

重要函数:

  1. split():此方法用于划分数据集,将数据集划分为train、test、valid数据集;
  2. split_ratio:此参数为 floatlist 类型,当参数为float类型时(参数取值要在[0, 1]),表示数据集中多少比例的数据划分到train(训练)数据集里,剩余的划分到valid(验证)数据集里;如果该参数是list类型(如[0.7, 0.2, 0.1]),表示traintestvalid数据集的比例;该参数默认值是 0.7
# get_dataset构造并返回Dataset所需的examples和fields
def get_dataset(csv_data, text_field, label_field, test=False):
    # id数据对训练在训练过程中没用,使用None指定其对应的field
    fields = [("id", None), # we won't be needing the id, so we pass in None as the field
                 ("content", text_field), ("label", label_field)]       
    examples = []

    if test:
        # 如果为测试集,则不加载label
        for text in tqdm(csv_data['content']):
            examples.append(Example.fromlist([None, text, None], fields))
    else:
        for text, label in tqdm(zip(csv_data['content'], csv_data['label'])):
            examples.append(Example.fromlist([None, text, label], fields))
    return examples, fields

train_examples, train_fields = get_dataset(train_df, CONTENT, LABEL)
test_examples, test_fields = get_dataset(test_df, CONTENT, None, test=True)

# 构建Dataset数据集
train_dataset = Dataset(train_examples, train_fields)
test_dataset = Dataset(test_examples, test_fields)
Iterator 构建迭代器

根据batch_size 生成 DatasetIteratior。常用的有 IteratorBucketIterator 。其中 BucketIteratorIterator 的子类,与 Iterator 相比,BucketIterator 会把相同或相近长度的数据(按 sort_key)属性进行排序,这样可以最小化 pad

重要参数:

  1. dataset:需要生成Iterator的数据集;
  2. batch_size:每个 batch的大小;
  3. sort_key:用来为每个 Example 进行排序的字段,默认是None
  4. shuffle:每次 epoch 是否进行 shuffle

重要函数:

  1. splits():为数据集生成Iterator
  2. datasetsTuple 类型的 DatasetTuple的第一个元素应该是train数据集的Dataset
  3. batch_sizesTuple类型,和datasets中的Dataset一一对应,表示各个数据集生成batch的大小;
# 同时对训练集和验证集进行迭代器的构建
train_iter, val_iter = BucketIterator.splits(
        (train_dataset, test_dataset), # 构建数据集所需的数据集
        batch_sizes=(8, 8),
        device=-1, # 如果使用gpu,此处将-1更换为GPU的编号
        sort_key=lambda x: len(x.content), # the BucketIterator needs to be told what function it should use to group the data.
        sort_within_batch=False,
        repeat=False # we pass repeat=False because we want to wrap this Iterator layer.
)
Vocab 构建词典

重要参数:

  1. countercollections.Counter 类型的对象,用于保存数据(如:单词)的频率;
  2. vectors:预训练的词向量,可以是torch.vocab.Vectors类型,也可以是其他类型;
  3. min_freq: 最低频率限制,如果某个词频率比min_freq低,则不记录到词典;
CONTENT.build_vocab(train_dataset)

看一下构建的词典

e = list(train_iter)[0]
e.content
tensor([[  317,    89,   569,  ...,     1,     1,     1],
        [15317,   673, 24260,  ...,     1,     1,     1],
        [  157, 18588,  2441,  ...,     1,     1,     1],
        ...,
        [10065, 15698,   120,  ...,     1,     1,     1],
        [ 2691,  7237,  8676,  ...,     1,     1,     1],
        [  390,  1667,   125,  ...,     1,     1,     1]])
e.content.shape
torch.Size([8, 50])

跑模型 BILSTM+ATTENTION

搭双向LSTM和最后的全连接层,

    def build_model(self):
        # 初始化词向量
        self.char_embeddings = nn.Embedding(self.char_size, self.char_embedding_size)
        # 词向量参与更新
        self.char_embeddings.weight.requires_grad = True
        # attention layer
        self.attention_layer = nn.Sequential(
            nn.Linear(self.hidden_dims, self.hidden_dims),
            nn.ReLU(inplace=True)
        )
        # self.attention_weights = self.attention_weights.view(self.hidden_dims, 1)

        # 双层lstm
        self.lstm_net = nn.LSTM(self.char_embedding_size, self.hidden_dims,
                                num_layers=self.rnn_layers, dropout=self.keep_dropout,
                                bidirectional=True)
        # FC层
        self.fc_out = nn.Sequential(
            # nn.Dropout(self.keep_dropout),
            # nn.Linear(self.hidden_dims, self.hidden_dims),
            # nn.ReLU(inplace=True),
            # nn.Dropout(self.keep_dropout),
            nn.Linear(self.hidden_dims, self.num_classes),
        )

attention部分
在这里插入图片描述
attention的理解参考:https://distill.pub/2016/augmented-rnns/
简化了attention层,减少全连接层、Relu层,减少参数量

def attention_net(self, lstm_out, lstm_hidden):
    '''

    :param lstm_out:    [batch_size, len_seq, n_hidden * 2]
    :param lstm_hidden: [batch_size, num_layers * num_directions, n_hidden]
    :return: [batch_size, n_hidden]
    '''
    # chunk的方法做的是对张量进行分块,返回一个张量列表。但如果指定轴的元素个数被chunks除不尽,最后一块的元素个数会少。
    lstm_tmp_out = torch.chunk(lstm_out, 2, -1)
    
    # h [batch_size, time_step, hidden_dims] 
    # 将双向LSTM的激活值相加
    h = lstm_tmp_out[0] + lstm_tmp_out[1]
    
    # 将最后一层隐藏层两个方向权重加起来
    # [batch_size, num_layers * num_directions, n_hidden]
    lstm_hidden = torch.sum(lstm_hidden, dim=1)
    
    # [batch_size, 1, n_hidden]  在下标1的位置增加1维
    lstm_hidden = lstm_hidden.unsqueeze(1)
    
    # atten_score [batch_size, 1, time_step]  attention score层
    atten_score = torch.bmm(lstm_hidden, h.transpose(1, 2))
    
    # atten_weight [batch_size, 1, time_step] softmax归一化(attention distribution层)
    atten_weight = F.softmax(atten_score, dim=-1)
    
    # [batch_size, 1, n_hidden] 加权输出值
    context = torch.bmm(atten_weight, h)
    result = context.squeeze(1)
    return result

最终结果:非常菜

Epoch: 1  | time in 0 minutes, 47 seconds
	Loss: 1.2363(train)	|	Acc: 49.8%(train)
	Loss: 1.0654(valid)	|	Acc: 70.5%(valid)
Epoch: 2  | time in 0 minutes, 49 seconds
	Loss: 0.9987(train)	|	Acc: 74.4%(train)
	Loss: 0.9925(valid)	|	Acc: 74.0%(valid)
Epoch: 3  | time in 0 minutes, 48 seconds
	Loss: 0.8978(train)	|	Acc: 84.4%(train)
	Loss: 0.9435(valid)	|	Acc: 80.0%(valid)
Epoch: 4  | time in 0 minutes, 48 seconds
	Loss: 0.8553(train)	|	Acc: 88.3%(train)
	Loss: 0.9059(valid)	|	Acc: 84.5%(valid)
Epoch: 5  | time in 0 minutes, 47 seconds
	Loss: 0.8406(train)	|	Acc: 89.9%(train)
	Loss: 0.9185(valid)	|	Acc: 83.0%(valid)

完整代码见:https://github.com/DiegoSong/nlp_on_RM/blob/master/text_cat/BiLSTM_attention.ipynb

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

微博文本分类任务 的相关文章

  • 在数组中进行图形绘制

    include lt stdio h gt define k 2 43 1 define 2 define s 0 static unsigned short stop 61 s k k k k k k k s k k k k k k k
  • socket函数

    转自 xff1a http blog csdn net guoping16 article details 6584382 1 基本套接字函数 xff08 1 xff09 socket函数原型 socket 建立一个socket文件描述符
  • 进程与线程

    第一章 xff1a 计算机系统漫游 进程 xff1a 进程是操作系统对一个正在运行的程序的一种抽象 xff0c 一个系统可以同时运行多个进程 xff0c 看上去是CPU并发的执行多个程序 xff0c 实际上是通过进程切换来实现的 xff0c
  • GDI GDI+ 的区别

    转载自 xff1a http www cnblogs com lidabo p 3701252 html GDI 43 是GDI的下一个版本 xff0c 它进行了很好的改进 xff0c 并且易用性更好 GDI的一个好处就是你不必知道任何关于
  • GDI GDI+ 的区别

    转载自 xff1a http www cnblogs com lidabo p 3701252 html GDI 43 是GDI的下一个版本 xff0c 它进行了很好的改进 xff0c 并且易用性更好 GDI的一个好处就是你不必知道任何关于
  • 使用的DockPanel的心得

    使用这个控件的时候后一定要先Show this DockPlan1 才能使用DockTo this DockPlan1 DockStyle Bottom 固定位置 xff0c 否则会抛出异常
  • C#使用双缓冲解决绘图闪屏的问题

    最近在工作需要使用C 绘制图形 xff0c 看了一下绘制的函数觉得很简单就开始着手工作了 xff0c 但是在实际应用的时候发现鼠标进行绘制的时候会闪屏 xff0c 原因是图元重绘的时间不一致 xff0c 百度一下有很多更详细的 xff0c
  • 关于捕获键盘信息的processDialogkey方法

    转载自 xff1a http blog csdn net lucifinil s article details 6318189 在一些控件里的keydown方法 xff0c 没有办法捕获所有的按键消息 比如自己写一个窗体控件库 xff0c
  • C#泛型委托

    因为项目原因最近要使用C 进行编程 xff0c 于是每天现学现卖一点一点的进行开发 之前很长的时间一直使用C和C 43 43 进行编程 xff0c 于是转到C 一开始开始不是特别适应的 xff0c 特别是C 这门语言没有了指针 xff0c
  • 基于windows的Ubuntu双系统安装

    Data 2016 12 19 Author cjh Theme Ubuntu dual system installation 前期准备 1 Ubuntu相关版本镜像ios 2 UltraISO 用于制作U盘启动盘 3 EasyBCD 2
  • 汇编文件.S和.s的区别

    c C 原始程序 xff1b 预处理 编译 汇编 C C 43 43 原始程序 xff1b 预处理 编译 汇编 ccC 43 43 原始程序 xff1b 预处理 编译 汇编 cxx C 43 43 原始程序 xff1b 预处理 编译 汇编
  • 串口网口数据帧解析(支持连包、断传、错误数据过滤)

    本文转载自 xff1a https blog csdn net hwb 1988 article details 45872379 嵌入式系统中 xff0c 关于数据接受部分确实思考了很多 xff0c 下面总结下个人经验 关于串口传输 xf
  • Use of $Super$ $  and$Sub$ $to patch symbol definitions

    在无法修改现有符号的情况下 xff0c 可以使用特殊模式 现有符号无法修改 xff0c 例如 xff0c 如果它位于外部库或ROM代码中 在这种情况下 xff0c 您可以使用 Super 和 Sub 模式来修补现有符号 修补函数foo xf
  • RT-Thread内核移植

    记录代码移植过程 xff0c 成功一步记录一步 第一步 xff1a 建立裸机程序 使用STM32CubeMx建立一个裸机程序 生成MDK5工程 第二步 xff1a 参考0 bare metal完成board c board h文件 在Dri
  • C#委托和事件框架封装简写 delegate、event、Action、EventHandler

    曾经 Net大佬只有一个Delegete 委托 xff0c 别人想用委托的时候 xff0c 必须得用delegate关键字来定义一个委托 xff0c 就像这样 span class token comment 定义一个无返回值的 xff0c
  • CentOS 7 firewalld使用简介

    学习apache安装的时候需要打开80端口 xff0c 由于centos 7版本以后默认使用firewalld后 xff0c 网上关于iptables的设置方法已经不管用了 xff0c 想着反正iptable也不会用 xff0c 索性直接搬
  • 通过VNC访问docker容器的图形界面

    https hub docker com r dorowu ubuntu desktop lxde vnc https github com fcwu docker ubuntu vnc desktop docker ubuntu vnc
  • 阿里云产品图标

    2022年最新 最全的阿里云产品图标 xff0c 矢量图哦 xff0c 留下你的邮箱 xff0c 我发给你 2022年最新阿里云产品图标 有200多个图标 随时可以拿来用 为了可以审批通过 我在这里多写点字 我平时都是用这些图标 用来做设计
  • 论文引用:参考文献GB/T 7714、APA、MLA的自动生成

    一 谷歌学术 1 谷歌学术镜像 xff1a 谷歌学术镜像 Google学术搜索导航 64 思谋学术 xff0c 随意点进去一个链接 2 搜索需要的论文 xff0c 点击下方引用小标志 3 根据自己需要的引用标准 xff0c 选择复制 注 x
  • 人工智能与安全论坛:智能与安全的融合与对抗

    前几天随公司参加了互联网安全大会 xff08 ISC xff0c Internet Security Conference xff09 xff0c 虽然只参加了半天的会议 xff0c 感觉收获不 更重要的是偶遇师兄 xff0c 人生无处不相

随机推荐