深度学习与自然语言处理第五次作业——段落分析模型

深度学习与自然语言处理第五次作业——段落分析模型

基于Seq2seq模型来实现文本生成的模型,输入可以为一段已知的金庸小说段落,来生成新的段落并做分析。


文章目录

  • 深度学习与自然语言处理第五次作业——段落分析模型
  • 一、实验原理
    • 1、Seq2seq模型简介
    • 2、LTSM模型介绍
  • 二、解题流程
    • 1、读取训练语料
    • 2、训练模型
    • 3、读取测试语料
    • 4、结果输出
  • 三、实验结果与分析
    • 1、实验结果
    • 2、实验总结
  • 代码
    • 1、语料预处理
    • 2、主函数


一、实验原理

1、Seq2seq模型简介

Seq2seq是sequence to sequence的缩写。Seq2seq 是深度学习中最强大的概念之一,从翻译开始,后来发展到问答系统,音频转录等。seq2seq 是一个 Encoder–Decoder 结构的网络,它的输入是一个序列,输出也是一个序列, Encoder 中将一个可变长度的信号序列变为固定长度的向量表达,Decoder 将这个固定长度的向量变成可变长度的目标的信号序列。
图5
在Seq2Seq结构中,编码器Encoder把所有的输入序列都编码成一个统一的语义向量Context,然后再由解码器Decoder解码。在解码器Decoder解码的过程中,不断地将前一个时刻的输出作为后一个时刻的输入,循环解码,直到输出停止符为止。

2、LTSM模型介绍

LSTM(Long Short Term Memory ) 长短期记忆神经网络。在RNN的基础上加入了遗忘机制,选择性的保留或遗忘前期的某些数据,且不再采用乘法而是加法以避免梯度爆炸的问题。


二、解题流程

1、读取训练语料

根据题目要求,我选择读取《笑傲江湖》的内容,并对其中的内容进行预处理,保留其中的标点符号并去除掉无关字符。

2、训练模型

训练模型的步骤如下所示:
使用jieba分词对输入的语料进行分词,并使用Word2Vec模型对输入的语料进行词嵌入,最后再利用pytorch框架进行LSTM神经网络训练。

3、读取测试语料

与读取训练语料相似,对测试语料进行读取,并进行一定的预处理。

4、结果输出

对结果进行输出。


三、实验结果与分析

1、实验结果

实验结果如下所示:
输入内容
令狐冲向盈盈瞧去,见她低了头沉思,心想:“她为保全自己名声,要取我性命,那又是甚么难事了?”说道:“你要杀我,自己动手便是,又何必劳师动众?”缓缓拔出长剑,倒转剑柄,递了过去。盈盈接过长剑,微微侧头,凝视着他,令狐冲哈哈一笑,将胸膛挺了挺。盈盈道:“你死在临头,还笑甚么?”令狐冲道:“正因为死在临头,所以要笑。”
  盈盈提起长剑,手臂一缩,作势便欲刺落,突然转过身去,用力一挥,将剑掷了出去。长剑在黑暗中闪出一道寒光,当的一声,落在远处地下。
  盈盈顿足道:“都是你不好,教江湖上这许多人都笑话于我。倒似我一辈子……一辈子没人要了,千方百计的要跟你相好。你……你有甚么了不起?累得我此后再也没脸见人。”令狐冲又哈哈一笑。盈盈怒道:“你还要笑我?还要笑我?”忽然哇的一声哭了出来。她这么一哭,令狐冲心下登感歉然,柔情一起,蓦然间恍然大悟:“她在江湖上位望甚尊,这许多豪杰汉子都对她十分敬畏,自必向来十分骄傲,又是女孩儿家,天生的腼腆,忽然间人人都说她喜欢了我,也真难免令她不快。她叫老头子他们如此传言,未必真要杀我,只不过是为了辟谣。她既这么说,自是谁也不会疑心我跟她在一起了。”柔声道:“果然是我不好,累得损及姑娘清名。在下这就告辞。”盈盈伸袖拭了拭眼泪,道:“你到哪里去?”令狐冲道:“信步所至,到哪里都好。”盈盈道:“你答允过要保护我的,怎地自行去了?”令狐冲微笑道:“在下不知天高地厚,说这些话,可教姑娘笑话了。姑娘武功如此高强,又怎需人保护?便有一百个令狐冲,也及不上姑娘。”说着转身便走。盈盈急道:“你不能走。”令狐冲道:“为甚么?”盈盈道:“祖千秋他们已传了话出去,数日之间,江湖上便无人不知,那时人人都要杀你,这般步步荆棘,别说你身受重伤,就是完好无恙,也难逃杀身之祸。”
  令狐冲淡然一笑,道:“令狐冲死在姑娘的言语之下,那也不错啊。”走过去拾起长剑插入剑鞘,自忖无力走上斜坡,便顺着山涧走去。
  盈盈眼见他越走越远,追了上来,叫道:“喂,你别走!”令狐冲道:“令狐冲跟姑娘在一起,只有累你,还是独自去了的好。”盈盈道:“你……你……”咬着嘴唇,心头烦乱之极,见他始终不肯停步,又奔近几步,说道:“令狐冲,你是要迫我亲口说了出来,这才快意,是不是?”令狐冲奇道:“甚么啊?我可不懂了。”盈盈又咬了咬口唇,说道:“我叫祖千秋他们传言,是要你……要你永远在我身边,不离开我一步。”说了这句话后,身子发颤,站立不稳。令狐冲大是惊奇,道:“你……你要我陪伴?”盈盈道:“不错!祖千秋他们把话传出之后,你只有陪在我身边,才能保全性命。没想到你这不顾死活的小子,竟一点不怕,那不是……那不是反而害了你么?”
  输出内容
  挨过妻子蜀锦无相无作全无不忍他恩重蜀锦治愈坐失神光无可奈何无可奈何不忍容让我定容让治愈不忍他恩重我定他恩重苦楚容让苦楚坐失神光苦楚这具我定两次仍然两次无可奈何仍然苦楚蜀锦神光我定竟会蜀锦全无当众这具练剑坐失坐失两次伤势苦楚无可奈何伤势伤势练剑容让激得神光我定他恩重数着全无我定坐失容让仍然坐失苦楚坐失我定竟会仍然他恩重这具当众激得当众神光无可奈何他恩重无可奈何蜀锦竟会苦楚蜀锦全无仍然伤势激得苦楚数着无可奈何坐失仍然无可奈何治愈不忍无可奈何全无不忍仍然仍然蜀锦坐失全无他恩重他恩重蜀锦数着当众容让仍然我定蜀锦仍然当众当众无可奈何伤势练剑伤势仍然这具容让仍然苦楚两次无可奈何竟会当众竟会这具坐失全无他恩重坐失治愈苦楚蜀锦竟会容让容让全无这具全无容让激得数着激得练剑我定治愈数着竟会治愈伤势我定坐失练剑我定这具当众当众竟会全无他恩重竟会数着我定激得练剑容让数着激得治愈数着治愈数着数着治愈练剑他恩重全无两次他恩重练剑无可奈何他恩重神光容让坐失当众他恩重苦楚这具全无两次仍然我定仍然仍然神光仍然练剑蜀锦全无当众仍然我定当众我定他恩重练剑苦楚蜀锦两次仍然不忍容让仍然坐失这具苦楚两次无可奈何容让伤势全无蜀锦治愈容让练剑数着伤势练剑这具治愈无可奈何两次仍然苦楚仍然他恩重仍然治愈当众坐失我定他恩重苦楚竟会激得练剑坐失蜀锦伤势全无这具他恩重我定两次容让我定我定激得他恩重数着两次坐失我定数着全无他恩重治愈容让我定竟会蜀锦两次容让不忍这具全无容让无可奈何练剑我定全无坐失治愈竟会这具激得容让仍然他恩重练剑这具仍然神光竟会这具数着仍然两次伤势伤势数着这具激得两次激得全无容让坐失不忍他恩重激得当众伤势我定治愈治愈竟会苦楚苦楚全无苦楚治愈仍然伤势练剑无可奈何我定治愈神光伤势治愈竟会治愈竟会容让不忍仍然我定练剑竟会仍然当众伤势仍然苦楚坐失他恩重容让坐失全无当众无可奈何伤势神光练剑仍然容让竟会苦楚这具神光这具坐失仍然数着数着练剑治愈全无不忍激得不忍当众两次数着两次当众无可奈何两次伤势伤势仍然他恩重容让激得无可奈何他恩重激得苦楚不忍练剑苦楚不忍他恩重他恩重仍然激得我定他恩重伤势这具他恩重容让无可奈何两次治愈不忍两次当众神光数着神光竟会无可奈何坐失容让两次我定当众两次仍然容让苦楚数着我定坐失坐失伤势两次激得全无数着当众两次伤势我定神光治愈治愈不忍这具当众治愈数着坐失这具仍然不忍数着无可奈何他恩重竟会练剑伤势不忍伤势他恩重神光两次数着容让苦楚伤势竟会当众数着我定他恩重数着两次当众练剑两次竟会这具容让他恩重不忍苦楚竟会激得我定他恩重激得仍然数着数着两次坐失我定竟会当众练剑无可奈何苦楚神光神光苦楚我定我定竟会伤势无可奈何这具两次神光激得苦楚容让仍然数着当众蜀锦激得不忍这具蜀锦竟会激得无可奈何苦楚两次竟会无可奈何练剑无可奈何坐失我定竟会全无全无不忍激得神光竟会竟会竟会治愈数着激得两次两次神光这具我定激得练剑这具激得数着蜀锦治愈这具两次伤势仍然苦楚全无当众神光蜀锦无可奈何竟会全无无可奈何我定这具激得两次伤势蜀锦他恩重竟会治愈我定治愈两次我定激得当众无可奈何无可奈何仍然容让练剑治愈伤势神光竟会数着治愈全无苦楚竟会全无数着苦楚苦楚蜀锦他恩重他恩重不忍无可奈何当众这具不忍治愈数着神光全无竟会练剑我定竟会激得容让伤势这具坐失蜀锦不忍容让当众练剑他恩重不忍练剑两次仍然伤势数着坐失他恩重伤势我定竟会他恩重竟会全无无可奈何这具练剑两次无可奈何当众治愈仍然数着全无全无我定无可奈何全无激得我定数着激得蜀锦这具无可奈何竟会坐失仍然数着容让这具练剑竟会苦楚坐失当众竟会竟会无可奈何不忍无可奈何激得苦楚无可奈何神光蜀锦伤势两次无可奈何治愈数着神光当众这具苦楚苦楚两次他恩重全无激得仍然伤势练剑神光仍然神光我定当众伤势蜀锦练剑练剑这具苦楚坐失无可奈何两次容让治愈不忍这具这具全无他恩重激得容让坐失神光无可奈何我定练剑容让这具这具当众数着容让这具坐失练剑无可奈何神光苦楚数着伤势伤势我定竟会当众竟会他恩重无可奈何不忍这具他恩重数着无可奈何苦楚不忍不忍激得苦楚治愈无可奈何伤势治愈当众神光治愈苦楚他恩重治愈我定这具他恩重竟会坐失练剑数着蜀锦仍然激得竟会这具两次苦楚我定竟会两次两次苦楚仍然治愈我定数着他恩重练剑容让他恩重苦楚坐失全无当众容让坐失治愈苦楚这具容让仍然仍然不忍苦楚仍然治愈全无无可奈何不忍他恩重蜀锦坐失全无他恩重数着他恩重仍然不忍容让容让仍然数着无可奈何全无无可奈何当众我定坐失治愈坐失这具当众他恩重苦楚竟会苦楚不忍激得治愈治愈竟会仍然他恩重不忍数着两次练剑无可奈何坐失练剑数着数着坐失他恩重全无两次不忍竟会练剑苦楚治愈无可奈何我定当众我定我定我定两次苦楚竟会数着蜀锦两次仍然全无他恩重不忍无可奈何伤势不忍神光神光不忍我定蜀锦坐失蜀锦当众神光伤势伤势治愈我定无可奈何蜀锦苦楚竟会蜀锦全无坐失当众神光练剑这具两次数着治愈当众坐失数着神光神光无可奈何神光坐失无可奈何坐失他恩重神光容让仍然不忍坐失治愈竟会他恩重两次蜀锦无可奈何当众这具无可奈何当众练剑神光苦楚两次我定竟会坐失这具练剑仍然治愈坐失苦楚坐失全无坐失治愈这具无可奈何这具全无无可奈何容让两次蜀锦不忍无可奈何蜀锦他恩重练剑不忍全无全无不忍伤势神光容让伤势无可奈何竟会激得他恩重全无练剑全无治愈练剑我定坐失全无他恩重两次蜀锦两次坐失无可奈何坐失数着当众蜀锦两次仍然激得他恩重神光坐失容让神光治愈他恩重容让激得治愈伤势容让伤势这具坐失竟会坐失练剑不忍容让神光蜀锦我定全无伤势他恩重当众练剑容让这具

2、实验总结

本次实验由于实验设备的限制,实验只训练了10轮,即epoch=10,因此实验结果不够好看,重复内容很多,但是还是可以看出一些相关性,比如原文讲的是令狐冲与任盈盈的关系,出现了“相好”“陪伴”等词,因此输出有“妻子”一词;’此时令狐冲受伤了,因此出现了“伤势”一词;任盈盈救了令狐冲,因此出现了“恩情”一词。
在未来如果有机会,我还应该对模型进行调参,并通过再多次数的训练。本次实验是本课程最后一次大作业,虽然以前接触过相关LSTM神经网络相关内容,但是仍对其具体应用不甚了解。

本次运用的是Seq2seq,这个模型时利用LSTM的En-Decoder来搭建的,以往也可以用RNN、GRN一类的模型来实现。因此,LSTM与Seq2seq的关系就像原料与产品的关系,这个产品可以使用这个原料也可以使用别的原料来制作;与此同时这个原料可以用来制作这个产品也可以用于别的产品。

本学期经过大作业的训练,自己已经掌握了一些自然语言处理的方法,但这些方法还比较简单,针对更加复杂的自然语言处理的问题,还需要以后继续深入地学习。

代码

1、语料预处理

import re
def read_data():
    with open('../深度学习与自然语言处理/novel/天龙八部.txt', "r", encoding='gb18030') as f:
        file_read = f.readlines()
        all_text = ""
        for line in file_read:
            line = re.sub('\s','', line)
            line = re.sub('!','。', line)
            line = re.sub('?','。', line)# 保留句号
            line = re.sub('[\u0000-\u3001]', '', line)
            line = re.sub('[\u3003-\u4DFF]', '', line)
            line = re.sub('[\u9FA6-\uFFFF]', '', line)
            all_text += line
        f.close()
    return all_text

def content_deal(content):  # 语料预处理,进行断句,去除一些广告和无意义内容
    ad = ['本书来自www.cr173.com免费txt小说下载站\n更多更新免费电子书请关注www.cr173.com', '----〖新语丝电子文库(www.xys.org)〗', '新语丝电子文库',
          '\u3000', '\n', '。', '?', '!', ',', ';', ':', '、', '《', '》', '“', '”', '‘', '’', '[', ']', '....', '......',
          '『', '』', '(', ')', '…', '「', '」', '\ue41b', '<', '>', '+', '\x1a', '\ue42b']
    for a in ad:
        content = content.replace(a, '')
    return content

2、主函数

import torch
import torch.nn as nn
import os
import re
import jieba
from tqdm import trange
from gensim.models import Word2Vec
import numpy as np
class Net(nn.Module):
    def __init__(self, onehot_num):
        super(Net, self).__init__()
        onehot_size = onehot_num
        embedding_size = 256
        n_layer = 2
        self.lstm = nn.LSTM(embedding_size, embedding_size, n_layer, batch_first=True)# 编码
        self.encode = torch.nn.Sequential(nn.Linear(onehot_size, embedding_size),nn.Dropout(0.5),nn.ReLU())# 解码
        self.decode = torch.nn.Sequential(nn.Linear(embedding_size, onehot_size),nn.Dropout(0.5),nn.Sigmoid())

    def forward(self, x):# 入
        em = self.encode(x).unsqueeze(dim=1)# 出
        out, (h, c) = self.lstm(em)
        res = 2*(self.decode(out[:,0,:])-0.5)
        return res

def read_data():
    with open('笑傲江湖.txt', "r", encoding='gb18030') as f:
        file_read = f.readlines()
        all_text = ""
        for line in file_read:
            line = re.sub('\s','', line)
            line = re.sub('!','。', line)
            line = re.sub('?','。', line)# 保留句号
            line = re.sub('[\u0000-\u3001]', '', line)
            line = re.sub('[\u3003-\u4DFF]', '', line)
            line = re.sub('[\u9FA6-\uFFFF]', '', line)
            all_text += line
        f.close()
    return all_text

def content_deal(content):  # 语料预处理,进行断句,去除一些广告和无意义内容
    ad = ['本书来自www.cr173.com免费txt小说下载站\n更多更新免费电子书请关注www.cr173.com', '----〖新语丝电子文库(www.xys.org)〗', '新语丝电子文库',
          '\u3000', '\n', '。', '?', '!', ',', ';', ':', '、', '《', '》', '“', '”', '‘', '’', '[', ']', '....', '......',
          '『', '』', '(', ')', '…', '「', '」', '\ue41b', '<', '>', '+', '\x1a', '\ue42b']
    for a in ad:
        content = content.replace(a, '')
    return content

def train():
    embed_size = 1024
    epochs = 25
    end_num = 10

    print("读取数据开始")
    all_text = read_data()
    text_terms = list()
    for text_line in all_text.split('。'):
        seg_list = list(jieba.cut(text_line, cut_all=False))  # 使用精确模式
        if len(seg_list) < 5:
            continue
        seg_list.append("END")
        text_terms.append(seg_list)
    print("读取数据结束")
    # 获得word2vec模型
    print("开始计算向量")
    if not os.path.exists('model.model'):
        print("开始构建模型")
        model = Word2Vec(sentences=text_terms,sg=0, vector_size=embed_size, min_count=1, window=10, epochs=10)
        print("模型构建完成")
        model.save('model.model')
    print("模型已保存")
    print("开始训练")
    sequences = text_terms
    vec_model = Word2Vec.load('model.model')
    model = Net(embed_size).cuda()
    optimizer = torch.optim.AdamW(params=model.parameters(), lr=0.0001)
    for epoch_id in range(epochs):
        for idx in trange(0, len(sequences) // end_num - 1):
            seq = []
            for k in range(end_num):
                seq += sequences[idx + k]
            target = []
            for k in range(end_num):
                target += sequences[idx + end_num + k]
            input_seq = torch.zeros(len(seq), embed_size)
            for k in range(len(seq)):
                input_seq[k] = torch.tensor(vec_model.wv[seq[k]])
                target_seq = torch.zeros(len(target), embed_size)
            for k in range(len(target)):
                target_seq[k] = torch.tensor(vec_model.wv[target[k]])
            all_seq = torch.cat((input_seq, target_seq), dim=0)
            optimizer.zero_grad()
            out_res = model(all_seq[:-1].cuda())
            f1 = ((out_res[-target_seq.shape[0]:] ** 2).sum(dim=1)) ** 0.5
            f2 = ((target_seq.cuda() ** 2).sum(dim=1)) ** 0.5
            loss = (1 - (out_res[-target_seq.shape[0]:] * target_seq.cuda()).sum(dim=1) / f1 / f2).mean()
            loss.backward()
            optimizer.step()
            if idx % 50 == 0:
                print("loss: ", loss.item(), " in epoch ", epoch_id, " res: ",out_res[-target_seq.shape[0]:].max(dim=1).indices, target_seq.max(dim=1).indices)
        state = {"models": model.state_dict()}
        torch.save(state, "model/" + str(epoch_id) + ".pth")

def read_test_data():
    name = 'test.txt'
    with open(name, "r", encoding='utf-8') as f:
        file_read = f.readlines()
        all_text = ""
        for line in file_read:
            line = re.sub('\s', '', line)
            line = re.sub('!', '。', line)
            line = re.sub('?', '。', line)
            line = re.sub(',', '。', line)# 保留句号
            line = re.sub('[\u0000-\u3001]', '', line)
            line = re.sub('[\u3003-\u4DFF]', '', line)
            line = re.sub('[\u9FA6-\uFFFF]', '', line)
            all_text += line
    return all_text

def test():
    embed_size = 1024
    print("start read test data")
    text = read_test_data()
    text_terms = list()
    test_len = 0
    for text_line in text.split('。'):
        seg_list = list(jieba.cut(text_line,cut_all=False))  # 使用精确模式
        if len(seg_list) < 5:
            continue
        seg_list.append("END")
        test_len = test_len + len(seg_list)
        text_terms.append(seg_list)
    print("end read data")

    checkpoint = torch.load("model/" + str(9) + ".pth")

    model = Net(embed_size).eval().cuda()
    model.load_state_dict(checkpoint["models"])
    vec_model = Word2Vec.load('model.model')

    seqs = []
    for sequence in text_terms:
        seqs += sequence

    input_seq = torch.zeros(len(seqs), embed_size).cuda()
    result = ""
    with torch.no_grad():
        for k in range(len(seqs)):
            input_seq[k] = torch.tensor(vec_model.wv[seqs[k]])
        end_num = 0
        length = 0
        while end_num < 10 and length < test_len:
            print("length: ", length)
            out_res = model(input_seq.cuda())[-2:-1]
            key_value = vec_model.wv.most_similar(positive=np.array(out_res.cpu()), topn=20)
            key = key_value[np.random.randint(20)][0]
            if key == "END":
                result += "。"
                end_num += 1
            else:
                result += key
            length += 1
            input_seq = torch.cat((input_seq, out_res), dim=0)
    print(result)

if __name__ == "__main__":
    # train()
    test()


你可能感兴趣的:(深度学习,自然语言处理,人工智能)