• pytorch 文本多分类


    https://github.com/jiangqy/LSTM-Classification-pytorch 基础上进行的修改

    一、需求:短信文本分类

    1.1 原始数据

    以英语语言为主,人工打标签,分为四类:0,1,2,3。
    文本长度:最长为300个单词。
    已经经过预处理:去掉所有其它字符,只保留了字母,以空格作为分隔符。

    df = pd.read_csv('./data/labeled.csv')
    df=df[['clean_review','cat_id']]
    df.sample(10)
    

    二、构造训练样本

    1. 特征和标签

    import torch
    from torch.utils.data.dataset import Dataset
    import numpy as np
    import pandas as pd
    
    class Dictionary(object):
        def __init__(self):
            self.word2idx = {}
            self.idx2word = []
    
        def add_word(self, word):
            if word not in self.word2idx:
                self.idx2word.append(word)
                self.word2idx[word] = len(self.idx2word) - 1
            return self.word2idx[word]
    
        def __len__(self):
            return len(self.idx2word)
    
    class Corpus(object):
    
        def __init__(self,sen_len):
            self.dictionary = Dictionary()
            self.dictionary.add_word("UNK") # 要指定样本长度,不够的补0,默认0对应的单词为"UNK"
            self.texts,self.labels = self.tokenize(sen_len)
    
        def tokenize(self,sen_len):
            """
            得到字典,完成文本从单词到数字的转换
            :param sen_len: 文本长度
            :return:
            """
            df = pd.read_csv("./data/clean_review.csv")
            token_text = []
            tokens = 0
            labels = []
            for item in df.iterrows():
                line = item[1]["clean_review"] # 该行中,clean_review字段对应的值
                labels.append(int(item[1]["cat_id"])) # 该行中,cat_id字段对应的值,即这个样本的标签
                words = line.split(" ") 
    
                tokens += len(words)
                for word in words:
                    word = word.strip()
                    if word:
                        self.dictionary.add_word(word)
    
                txt = torch.LongTensor(np.zeros(sen_len, dtype=np.int64)) # 构造长度为sen_len的tensor
                for index,word in enumerate(words[:sen_len]):
                    word = word.strip()
                    if word:
                        txt[index] = self.dictionary.word2idx[word]
                token_text.append(txt)
    
            return token_text,labels
    

    2. 自定义Dataset

    class LSTMDataset(Dataset):
    
        def __init__(self,sen_len, corpus):
            corpus = corpus
            self.token_text = corpus.texts
            self.labels = corpus.labels
            self.sen_len = sen_len
    
        def __getitem__(self, index):
            """
            根据索引获取对应的特征和标签
            :param index:
            :return:
            """
            text = self.token_text[index]
            label = torch.LongTensor([self.labels[index]])
            return text, label
    
        def __len__(self):
            return len(self.labels)
    
    

    三、LSTM模型

    import torch.nn as nn
    import torch.nn.functional as F
    import torch
    from torch.autograd import Variable
    
    
    class LSTMClassifier(nn.Module):
        """
        LSTM模型
        """
        def __init__(self, embedding_dim, hidden_dim, vocab_size, label_size, batch_size, use_gpu):
            super(LSTMClassifier, self).__init__()
            self.hidden_dim = hidden_dim
            self.batch_size = batch_size
            self.use_gpu = use_gpu
    
            self.word_embeddings = nn.Embedding(vocab_size, embedding_dim) # 生成的嵌入矩阵
            self.lstm = nn.LSTM(embedding_dim, hidden_dim,num_layers=1) #
            self.hidden2label = nn.Linear(hidden_dim, label_size) # 四分类 label_size=4
            self.hidden = self.init_hidden()
    
        def init_hidden(self):
            if self.use_gpu:
                h0 = Variable(torch.zeros(1, self.batch_size, self.hidden_dim).cuda())
                c0 = Variable(torch.zeros(1, self.batch_size, self.hidden_dim).cuda())
            else:
                h0 = Variable(torch.zeros(1, self.batch_size, self.hidden_dim))
                c0 = Variable(torch.zeros(1, self.batch_size, self.hidden_dim))
            return (h0, c0)
    
        def forward(self, sentence):
            embeds = self.word_embeddings(sentence)
            x = embeds.view(len(sentence), self.batch_size, -1)
            lstm_out, self.hidden = self.lstm(x, self.hidden)
            y = self.hidden2label(lstm_out[-1])
            y = F.softmax(y,dim=1)
    
            return y
    
    # 得到最终的train_loader,训练过程就是对其进行遍历
    corpus = Corpus(DATA_DIR,sentence_len)
    train_set = LSTMDataset(sentence_len, corpus)
    train_loader = DataLoader(train_set,
                              batch_size=batch_size,
                              shuffle=True,
                              num_workers=4
                             )
    

    四、损失函数和优化器

    optimizer = optim.SGD(model.parameters(), lr=learning_rate)
    loss_function = nn.CrossEntropyLoss()
    

    输出层经过softmax之后,可以使用CrossEntropyLoss作为损失函数。

    五、开始训练

    for epoch in range(epochs):
        optimizer = adjust_learning_rate(optimizer, epoch)
    
        ## training epoch
        total_acc = 0.0
        total_loss = 0.0
        total = 0.0
        for iter, traindata in enumerate(train_loader):
            train_inputs, train_labels = traindata
            train_labels = torch.squeeze(train_labels)
    
            if use_gpu:
                train_inputs, train_labels = Variable(train_inputs.cuda()), train_labels.cuda()
            else:
                train_inputs = Variable(train_inputs)
    
            model.zero_grad()
            model.batch_size = len(train_labels)
            model.hidden = model.init_hidden()
            output = model(train_inputs.t())
    
            loss = loss_function(output, Variable(train_labels))
            loss.backward()
            optimizer.step()
    
            # calc training acc
            _, predicted = torch.max(output.data, 1)
            total_acc += (predicted == train_labels).sum()
            total += len(train_labels)
            total_loss += loss.item()
    
        train_loss_.append(total_loss / total)
        train_acc_.append(total_acc / total)
        ## testing epoch
        total_acc = 0.0
        total_loss = 0.0
        total = 0.0
        for iter, testdata in enumerate(test_loader):
            test_inputs, test_labels = testdata
            test_labels = torch.squeeze(test_labels)
    
            if use_gpu:
                test_inputs, test_labels = Variable(test_inputs.cuda()), test_labels.cuda()
            else:
                test_inputs = Variable(test_inputs)
    
            model.batch_size = len(test_labels)
            model.hidden = model.init_hidden()
            output = model(test_inputs.t())
    
            loss = loss_function(output, Variable(test_labels))
    
            # calc testing acc
            _, predicted = torch.max(output.data, 1)
            total_acc += (predicted == test_labels).sum()
            total += len(test_labels)
            total_loss += loss.item()
        test_loss_.append(total_loss / total)
        test_acc_.append(total_acc / total)
    
        print('[Epoch: %3d/%3d] Training Loss: %.3f, Testing Loss: %.3f, Training Acc: %.3f, Testing Acc: %.3f'
              % (epoch, epochs, train_loss_[epoch], test_loss_[epoch], train_acc_[epoch], test_acc_[epoch]))
    

    六、模型保存

    traced_model = torch.jit.script(model)
    traced_model.save("lstm.pt")
    

    如果生成的模型提供给java调用,而不是python直接调用,使用pytorch提供的torch.jit.script方法
    教程如下:https://liuzhian.github.io/2021/04/08/初识TorchScript/

  • 相关阅读:
    获取request错误信息
    request error: Connection aborted.', error(113, 'No route to host')
    python yield
    mysql 2003: Can't connect to MySQL server on '127.0.0.1:3306' (99)
    top查看特定pid
    Producer-consumer problem in Python
    ubuntu16.04 安装opencv3.3
    ubuntu 安装MySQLdb
    ElasticSearch mapping
    ubuntu 安装qq方案
  • 原文地址:https://www.cnblogs.com/leimu/p/15789279.html
Copyright © 2020-2023  润新知