IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 人工智能 -> 2021-08-05 -> 正文阅读

[人工智能]2021-08-05

简单文本情感分类入门

自己最近在B站上看了pytorch入门视频,在此写下自己第一个博客,第一个文本情感分类,写的不是很好,希望大家别喷就行。



一、准备数据集

1.数据集。

我这里选用的是aclImdb数据集,下载链接是:http://ai.stanford.edu/~amaas/data/sentiment/。

2.DataSet类的构建。

这里的 ImDataset继承了torch.DataSet类,重写了父类的__getitem__、 __init__和 len
定义了一个tokenlize(concent)方法,将传进的文本句子进行去除嘈杂符号。ImDataset类的作用是在后续需要使用DataLoader类的时候只需要使用get_data_loader(train=True)方法就即可完成对于dataloader的对象的返回。

代码如下(示例):

"""
完成数据集的准备
"""
from torch.utils.data import Dataset as dataset, DataLoader
import os
import re
import torch

from lib import ws,max_len


def tokenlize(concent):
    """
    对于与传进的数据进行整理,将数据内的嘈杂信息去除。
    :param concent:
    :return:
    """
    concent = re.sub("<.*?>", " ", concent)
    fileters = ['\t', '\\n', '\x96', '\x97', '#', '$', '&', '\(', '\)', '\*', '\+', '\-', '\.', '\=', '\?', '\=', '\.',
                '<', '>', ':']
    concent = re.sub("|".join(fileters), " ", concent)
    concent = re.sub("\'s ", " is ", concent)
    concent = re.sub("\'m ", " am ", concent)
    concent = re.sub("\'re ", " are ", concent)
    concent = re.sub("\'ve ", " have ", concent)
    token = [i.strip().lower() for i in concent.split()]
    return token



class ImDataset(dataset):
    # 完成数据集的准备定义类继承torch.DataSet
    def __init__(self, train=True):
        self.train_data_path = r"E:\dataset\aclImdb\train"
        self.test_data_path = r"E:\dataset\aclImdb\test"
        self.data_path = r""
        if train:
            self.data_path = self.train_data_path
        else:
            self.data_path = self.test_data_path
        # 把所有的文件名放入列表
        temp_data_path = [os.path.join(self.data_path, "pos"), os.path.join(self.data_path, "neg")]
        self.total_file_path = []
        # 将下面所有的文件地址都放入一个列表中
        for path in temp_data_path:
            file_name_list = os.listdir(path)
            file_path_list = [os.path.join(path, i) for i in file_name_list]
            self.total_file_path.extend(file_path_list)

    def __getitem__(self, index):
        file__path = self.total_file_path[index]
        # 这里要返回label和文本
        label_str = file__path.split("\\")[-2]
        label = 0 if label_str == "neg" else 1
        # 获取内容
        concent = open(file__path, 'r',encoding="utf-8").read()
        # 文本处理
        concent = tokenlize(concent)
        return concent, label

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


def collate_fn(batch):
    #  batch是一个列表,其中是一个一个的元组,每个元组是dataset中_getitem__的结果
    # 这里的zip操作是将这个batch种相应的元素打包组合到一起,最后返回一个对象,然后在经过list操作之后可以返回一个列表种包含相应的词语以及标签
    texts, labels = list(zip(*batch))
    content = [ws.transform(i,max_len=max_len) for i in texts]
    content = torch.LongTensor(content)
    labels = torch.LongTensor(labels)
    return content, labels


def get_data_loader(train=True):
    datas = ImDataset(train)
    dataloader = DataLoader(dataset=datas, batch_size=256, shuffle=True, collate_fn=collate_fn)
    return dataloader


if __name__ == "__main__":
    for idx, (input, target) in enumerate(get_data_loader()):
        print(idx)
        print(input)
        print(target)
        break

示例:ImDataSet类完成之后,在之后需要使用的时候只需调用get_data_loader(train=True)方法函数即可返回DataLoader对象。

二、文本序列化

1.文本序列化考虑的因素:

1.1如何将词语和字典之间对应
1.2不同的词语出现的次数不同,是否需要将高频或者低频词与进行过滤,以及词语总数是否进行限制。
1.3的到数字序列之后如何进行转化,
1.4不同句子长度不同,每一个batch的句子如和打造成长度相同的句子。
1.5新词语没有出现在词典中怎么办。

2.解决办法:

构建 Word2Sequence类,分别实现如下的方法:
1.init:python构造方法
2.fit:用于一个句子的统计词频,并分别将其词语和频率记录在self.dict字典种
3.build_vocab:构建词汇字典,构建的过程中解决1.2和1.4的问题。
4.transform:将一个句子转化为数字字典。
5.inverse_transform:将数字序列转化为一个句子
6.len:返回统计的词语的多少,即一个句子的长度。
代码如下(示例):

""""
实现的是构建词典
实现方法将句子转化为数字序列序列转化为句子
"""


class Word2Sequence:
    # 特殊字符对于不认识的词语进行填充
    # 对于不够vector长度的也进行填充
    UNK_TAG = "UNK"
    PAD_TAG = "PAD"

    UNK = 0
    PAD = 1

    # 定义构造方法
    def __init__(self):
        self.dict = {
            self.UNK_TAG: self.UNK,
            self.PAD: self.PAD
        }
        self.count = {}  # 统计词频

    def fit(self, sentence):
        """"
        把每一个句子放到dict中
        sentence: [word1,word2.....]
        """
        for word in sentence:
            # 词语没有的时候放0有的时候+1
            self.count[word] = self.count.get(word, 0) + 1

    def build_vocab(self, min=5, max=None, max_featuers=None):
        """
        生成词典
        :param min:最小出现的次数
        :param max:最大出现的次数
        :param max_featuers:一共保留多少个词语
        :return:
        """
        # 删除count种小于min的word
        self.count = {word: value for word, value in self.count.items() if value > min}
        # 市删除count大于max的词语
        if max is not None:
            self.count = {word: value for word, value in self.count.items() if value <= max}
        # 限制保留的词语数
        if max_featuers is not None:
            # 进行排序去除多余的部分
            # 使用sorted函数排序当reverse=True的时候是升序
            temp = sorted(self.count.items(), key=lambda x: x[-1], reverse=True)[:max_featuers]
            self.count = temp

        for word in self.count:
            self.dict[word] = len(self.dict)

        # 得到反转的字典
        self.inverse_dict = dict(zip(self.dict.values(), self.dict.keys()))

    def transform(self, sentence, max_len=None):
        """
        把句子转化为序列
        :param sentence:【word1,word2....】
        :param max_len: 对句子进行填充和裁剪
        :return: 数字序列
        """
        if max_len is not None:
            # 如果当前的句子没有达到vector的要求呢么就必须填充
            if max_len > len(sentence):
                sentence = sentence + [self.PAD_TAG] * (max_len - len(sentence))
            # 如果太长的话就要裁剪
            if max_len < len(sentence):
                sentence = sentence[:max_len]
        return [self.dict.get(word, self.UNK) for word in sentence]

    def inverse_transform(self, indices):
        """
        把序列转化为一个句子
        :param indices:数字序列
        :return:句子
        """
        return [self.inverse_dict.get(num) for num in indices]

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

三、文本句子序列化。

1.将本读取到的文本序列对象存储在本地磁盘,之后在需要的时候就可以直接使用。

from word_sequence import Word2Sequence
import pickle
import os
from DataSet import tokenlize
from tqdm import tqdm

if __name__ == "__main__":
    ws = Word2Sequence()
    path = r"E:\dataset\aclImdb\train"
    temp_data_path = [os.path.join(path, "pos"), os.path.join(path, "neg")]
    for data_path in temp_data_path:
        file_paths = [os.path.join(data_path, file_name) for file_name in os.listdir(data_path)]
        for file_path in tqdm(file_paths):
            sencente = tokenlize(open(file_path,encoding="utf-8").read())
            ws.fit(sencente)
    ws.build_vocab(min=10,max_featuers=10000)
    pickle.dump(ws, open("E:\Python code\情感分类\model\ws.pkl", "wb"))

这里使用tqdm模块的作用是显示序列化的进度

三、模型、训练以及总结。

1.模型的构建:

直接构建模型类然后继承torch.nn.Moudel类,重写父类构造方法,重写向前计算的方法,即可。
目前还没有学习RNN神经网络所以这里在使用embedding,之后直接使用的全连接层代替RNN来,所以训练的效果肯定不够好。
直接上代码:

class MyModel(nn.Module):
    def __init__(self):
        super(MyModel, self).__init__()
        self.embedding = nn.Embedding(len(ws), 100)
        self.fc = nn.Linear(max_len * 100, 2)

    def forward(self, input):
        """

        :param input: [batch_size,max_len]
        :return: [batch_size,max_len,100]
        """
        x = self.embedding(input)
        x = x.view([-1, max_len * 100])
        out = self.fc(x)
        return F.log_softmax(out,dim=-1)

2.模型的训练:

我这里是直接定义了一个方法进行训练,当然在训练之前肯定要实例化一个自己的模型对象,以及一个优化器类对象。最后只实验了一下代码能不能跑。


import torch.nn as nn
import torch.nn.functional as F
from lib import ws, max_len
from torch.optim import Adam
from DataSet import get_data_loader
model = MyModel()
optimizer = Adam(model.parameters(), 0.001)


def train(epoch):
    for idx, (input, target) in enumerate(get_data_loader()):
        optimizer.zero_grad()
        output = model(input)
        loss = F.nll_loss(output, target)
        loss.backward()
        optimizer.step()
        print(loss.item())


if __name__ == '__main__':
    for i in range(1):
        train(i)

2.总结:

这是我第一次使用pytorch来写自己的第一个文本情感分类模型,也是我第一次写博客(不喜欢希望别喷就行),当然训练出效果不是很理想(因为没有使用RNN来实现),在次记录我的学习经历,希望自己可以越来越强(向大佬膜拜)。

  人工智能 最新文章
2022吴恩达机器学习课程——第二课(神经网
第十五章 规则学习
FixMatch: Simplifying Semi-Supervised Le
数据挖掘Java——Kmeans算法的实现
大脑皮层的分割方法
【翻译】GPT-3是如何工作的
论文笔记:TEACHTEXT: CrossModal Generaliz
python从零学(六)
详解Python 3.x 导入(import)
【答读者问27】backtrader不支持最新版本的
上一篇文章      下一篇文章      查看所有文章
加:2021-08-06 09:37:50  更:2021-08-06 09:44:22 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/4 18:10:54-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码