0


基于pytorch使用LSTM进行虎年春联生成

先看看我摘录的一些结果吧

七字春联,开头两个字分别为 虎年、虎气、春节

虎年啸虎春虎虎
虎气伏虎牛龙龙

虎年虎虎展啸风
春节啸春虎风虎

虎年虎啸啸千啸
春节萝啸气风春

虎年啸浩一讯欢
春节回旧鹤绣舞

虎年啸一着有处
春节回一福舞福

虎年啸月翼业来
春节回旧精绣福

我语文水平不太行,乍一眼看感觉还是满高级的。

训练数据 春联.csv

0
龙腾虎啸
腊尽春回
高崖伏虎啸
茅庐卧龙飞
虎啸风声远
龙腾海浪高
龙引千江水
虎越万重山
密林藏伏虎
萝峰染晴云
山月流古雪
风虎浴清泉
事事都如意
虎虎有生气
云中熊虎将
天上凤凰儿
百尺飞泉鸣震谷
一声长啸势惊天
丙部琳琅春馥郁
寅宾璀灿日光华
长白虎啸林中日
江南猿啼岭上风
赤县奔腾如虎跃
神州崛起似龙飞
丑旧寅新宏图展
牛归虎跃春意浓
丑去寅来千里锦
牛奔虎啸九州春
丑去寅来人益健
牛奔虎跃春愈新
春风浩荡神州绿
虎气升腾岳麓雄
春风着意随人愿
虎气生威壮国魂
春光春色源春意
虎将虎年扬虎威
春节乍闻春有喜
虎年乐见虎生风
春雷巨响山河动
月夜旋风草木飞
春晓寅回人起舞
岁祯虎啸物昭苏
电闪金光夸五色
雷鸣巨吼动千山
憨厚忠诚牛品德
高昂奋勇虎精神
虎步奔腾开胜景
春风浩荡展鸿图
虎踞龙盘今胜昔
花得鸟语旧更新
虎踞龙盘今胜昔
莺歌燕舞呈吉祥
虎年赢得春风意
喜讯唤来燕子情
虎气顿生年属虎
春风常驻户迎春
虎气频催翻旧景
春风浩荡著新篇
虎添双翼前程远
国展宏图事业新
虎啸大山山献宝
龙腾祖国国扬威
虎啸密林凤万壑
鹤眠苍松月千岩
虎啸青山千里锦
风拂绿柳万家春
虎啸一声山海动
龙腾三界吉祥来
虎跃龙腾生紫气
风调雨顺兆丰年
虎跃龙腾兴骏业
莺歌燕舞羡鹏程
虎跃神州千业旺
春临盛世万民欢
花事才逢花好日
虎年更有虎威风
黄牛虽去精神在
猛虎初来气象新
江山秀丽春增色
事业辉煌虎更威
江山一统腾龙日
岁月三春入虎年
皆称飞虎一身胆
不负英雄千古名
金牛昂首高歌去
玉虎迎春敛福来
金牛辞岁寒风尽
白虎迎春喜气来
金牛辞岁千仓满
玉虎迎春百业兴
金牛奋蹄奔大道
乳虎添翼舞新春
金牛奋蹄开锦绣
乳虎添翼会风云
金牛送旧千家乐
玉虎迎新万户欢
龙腾虎跃人间景
鸟语花香天地春
绿野春深禾涌碧
神州虎啸青山来
门庭虎踞平安岁
柳浪莺歌锦绣春
门浴春风梅吐艳
户生虎气鸟争鸣
年逢寅虎群情奋
岁别丑牛大地春
牛肥马壮丰收岁
虎跃龙腾大有年
牛肥马壮家家富
虎跃龙腾处处春
牛奋千程荣盛世
虎驮五福贺新春
牛奋四蹄开锦绣
虎添双翼会风云
牛耕绿野千仓满
虎啸青山万木荣
牛耕沃野扬长去
虎啸群山大步来
千载难逢新世纪
万民谱写虎春秋
乾元启运三阳泰
斗丙回寅万户春
人逢盛世精神壮
虎跃奇峰气势雄
人间喜庆康平世
虎岁承欢幸福春
人民气魄如龙虎
祖国江山似画图
人入虎年鼓虎劲
门添春色发春辉
人添志气虎添翼
雪舞丰年燕舞春
人效黄牛心自贵
岁朝寅虎劲更高
山明水秀风光丽
虎跃龙腾日月新
生气联吟欣虎虎
留春伴读奋年年
四海龙腾抒壮志
千山虎啸振雄风
四海三江春气息
千家万户虎精神
四海笙歌迎虎岁
九州英杰跃鹏程
唯大英雄能伏虎
是真俊杰敢擒龙
啸一声惊天动地
睁双眼照耀乾坤
新年捷报虎添翼
大路朝阳马奋蹄
兴伟业仍须牛劲
展宏图更壮虎威
一代英豪生虎气
三春杨柳动莺歌
英雄气概如龙虎
祖国江山似画图
英雄时代英雄业
龙虎精神龙虎年
莺歌燕舞新春日
虎跃龙腾大治年
迎春节莺歌遍地
兴中华虎劲冲天
云喷笔花腾虎豹
雨翻墨浪走蛟龙
宅后青山金虎踞
门前绿水玉龙盘
致富脱贫添虎翼
开山治水展鹏程
丙穴鱼生人间改岁
寅方斗指天下皆春
春风浩荡花香鸟语
岁月峥嵘虎跃龙腾
虎跃龙腾九州焕彩
风调雨顺五谷丰登
牛奔福地普天献瑞
虎卧华堂满院生辉
势如破竹人欢马叫
安若泰山虎踞龙盘
紫气东来江山如画
红旗招展龙虎扬威
祖国富强神龙活虎
人民幸福舞燕飞莺
白虎替青牛招财进宝
黄莺鸣翠柳辞旧迎新
虎跃龙腾创人间奇迹
莺歌燕舞描大地春光
虎跃龙腾有天皆丽日
花香鸟语无地不春风
花团锦簇江山添异彩
虎啸龙吟华夏壮神威
金牛辞旧携凯歌而去
乳虎迎春带捷报新来
瑞雪兆丰年年年大吉
丑牛接寅虎虎虎生威
岁月逢春山河添锦绣
人民思治龙虎振精神
效虎豪吟放怀歌富岁
闻鸡起舞挥笔颂春光
祖国腾飞大鹏振羽翼
宏图再展乳虎显神通
庆虎岁把酒高吟虎跃曲
祝丰年扶犁又唱丰收谣
迎虎年敢逐改革拦路虎
送牛岁勇当奉献老黄牛
迎新春处处呈文明气象
入虎岁人人当改革先锋
虎跃龙腾碧海黄山妆玉宇
莺歌燕舞春风旭日蔚神州
虎跃龙腾华夏人民多俊杰
莺歌燕舞阳春山水尽朝晖
牛耕广野丑年犁出文明路
虎跃深山寅岁图开舜尧天
岁步寅年喜庆团圆同把酒
珠还合浦欢歌一统共迎春
喜庆牛年两制先迎香港还
欢歌兔岁亿民再赞澳门归
栽竹栽松竹隐凤凰松隐鹤
培山培水山藏虎豹水藏龙
丑岁建奇功香港回归昌国运
寅年兴大业宏图展现壮情怀
虎年喜虎劲攻关夺隘皆如虎
春节焕春光绣水描山总是春
牛年虽过去牛劲更增多奉献
虎岁喜临门虎威大振有精神
寅时入虎年十亿人民振虎劲
佳节描春色九州大地荡春潮
忆旧岁牛劲冲霄汉神鞭一指神州巨变
看今朝虎威壮中华众志成城经济腾飞

滑动窗口设置为2,即两个字符预测下一个字符,滑动预测5个字符。
但是还是存在较大问题,因为我是直接将所有的对联都拼接起来然后滑动选取训练数据和标签,而不是每句滑动选取,这样就导致会串,但是懒得切了,就这样吧。

完整代码

# coding: utf-8import torch
import torch.nn as nn
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.preprocessing import OneHotEncoder
import torch.nn.functional as F

classlstm_model(nn.Module):def__init__(self, vocab, hidden_size, num_layers, dropout=0.5):super(lstm_model, self).__init__()
        self.vocab = vocab  # 字符数据集# 索引,字符
        self.int_char ={i: char for i, char inenumerate(vocab)}
        self.char_int ={char: i for i, char in self.int_char.items()}# 对字符进行one-hot encoding
        self.encoder = OneHotEncoder(sparse=True).fit(vocab.reshape(-1,1))

        self.hidden_size = hidden_size
        self.num_layers = num_layers

        # lstm层
        self.lstm = nn.LSTM(len(vocab), hidden_size, num_layers, batch_first=True, dropout=dropout)# 全连接层
        self.linear = nn.Linear(hidden_size,len(vocab))defforward(self, sequence, hs=None):
        out, hs = self.lstm(sequence, hs)# lstm的输出格式(batch_size, sequence_length, hidden_size)
        output = self.linear(out[:,-1])# linear的输出格式,(batch_size * sequence_length, vocab_size)return output, hs

    defonehot_encode(self, data):return self.encoder.transform(data)defonehot_decode(self, data):return self.encoder.inverse_transform(data)deflabel_encode(self, data):return np.array([self.char_int[ch]for ch in data])deflabel_decode(self, data):return np.array([self.int_char[ch]for ch in data])defget_batches(data, batch_size, seq_len):'''
    :param data: 源数据,输入格式(num_samples, num_features)
    :param batch_size: batch的大小
    :param seq_len: 序列的长度(精度)
    :return: (batch_size, seq_len, num_features)
    '''
    num_features = data.shape[1]
    num_chars = batch_size * seq_len  # 一个batch_size的长度

    num_batches =int(np.floor(data.shape[0]/ num_chars))# 计算出有多少个batches

    need_chars = num_batches * num_chars  # 计算出需要的总字符量

    targets = np.vstack((data[1:].A, data[0].A))# 可能版本问题,取成numpy比较好reshape

    inputs = data[:need_chars].A.astype("int")# 从原始数据data中截取所需的字符数量need_words

    train_data = np.zeros((inputs.shape[0]- seq_len, seq_len, num_features))
    train_label = np.zeros((inputs.shape[0]- seq_len, num_features))for i inrange(0, inputs.shape[0]- seq_len,1):
        train_data[i]= inputs[i:i+seq_len]
        train_label[i]= inputs[i+seq_len-1]for i inrange(0, inputs.shape[0]- seq_len,  batch_size):if i + batch_size > inputs.shape[0]- seq_len:break
        x = train_data[i:i+batch_size]
        y = train_label[i:i+batch_size]yield x, y

deftrain(model, data, batch_size, seq_len, epochs, lr=0.01, valid=None):
    device ='cuda'if torch.cuda.is_available()else'cpu'

    model = model.to(device)
    optimizer = torch.optim.Adam(model.parameters(), lr=lr)
    criterion = nn.CrossEntropyLoss()if valid isnotNone:
        data = model.onehot_encode(data.reshape(-1,1))
        valid = model.onehot_encode(valid.reshape(-1,1))else:
        data = model.onehot_encode(data.reshape(-1,1))

    train_loss =[]
    val_loss =[]for epoch inrange(epochs):
        model.train()
        hs =None# hs等于hidden_size隐藏层节点
        train_ls =0.0
        val_ls =0.0for x, y in get_batches(data, batch_size, seq_len):
            optimizer.zero_grad()
            x = torch.tensor(x).float().to(device)
            out, hs = model(x, hs)
            hs =([h.data for h in hs])
            y = y.reshape(-1,len(model.vocab))
            y = model.onehot_decode(y)
            y = model.label_encode(y.squeeze())
            y = torch.from_numpy(y).long().to(device)

            loss = criterion(out, y.squeeze())
            loss.backward()
            optimizer.step()
            train_ls += loss.item()if valid isnotNone:
            model.eval()
            hs =Nonewith torch.no_grad():for x, y in get_batches(valid, batch_size, seq_len):
                    x = torch.tensor(x).float().to(device)# x为一组测试数据,包含batch_size * seq_len个字
                    out, hs = model(x, hs)# out.shape输出为tensor[batch_size * seq_len, vocab_size]
                    hs =([h.data for h in hs])# 更新参数

                    y = y.reshape(-1,len(model.vocab))# y.shape为(128,100,43),因此需要转成两维,每行就代表一个字了,43为字典大小
                    y = model.onehot_decode(y)# y标签即为测试数据各个字的下一个字,进行one_hot解码,即变为字符# 但是此时y 是[[..],[..]]形式
                    y = model.label_encode(y.squeeze())# 因此需要去掉一维才能成功解码# 此时y为[12...]成为一维的数组,每个代表自己字典里对应字符的字典序
                    y = torch.from_numpy(y).long().to(device)# 这里y和y.squeeze()出来的东西一样,可能这里没啥用,不太懂
                    loss = criterion(out, y.squeeze())# 计算损失值
                    val_ls += loss.item()

            val_loss.append(np.mean(val_ls))
        train_loss.append(np.mean(train_ls))print("val_loss", val_ls)print("train_loss:", train_ls)

    plt.plot(train_loss, label="train_loss")
    plt.plot(val_loss, label="val loss")
    plt.title("loop vs epoch")
    plt.legend()
    plt.show()

    model_name ="lstm_model.net"withopen(model_name,'wb')as f:# 训练完了保存模型
        torch.save(model.state_dict(), f)defpredict(vocab_size, model, char, top_k=None, hidden_size=None):
    device ='cuda'if torch.cuda.is_available()else'cpu'
    model.to(device)
    model.eval()# 固定参数with torch.no_grad():
        char = np.array([char])# 输入一个字符,预测下一个字是什么,先转成numpy
        char = char.reshape(-1,1)# 变成二维才符合编码规范
        char_encoding = model.onehot_encode(char).A  # 对char进行编码,取成numpy比较方便reshape
        char_encoding = char_encoding.reshape(1,-1, vocab_size)# 转成模型输入格式 

        char_tensor = torch.tensor(char_encoding, dtype=torch.float32)# 转成tensor
        char_tensor = char_tensor.to(device)

        out, hidden_size = model(char_tensor, hidden_size)# 放入模型进行预测,out为结果

        probs = F.softmax(out, dim=1).squeeze()# 计算预测值,即所有字符的概率print(probs.shape)if top_k isNone:# 选择概率最大的top_k个
            indices = np.arange(vocab_size)else:
            probs, indices = probs.topk(top_k)
            indices = indices.cpu().numpy()
        probs = probs.cpu().numpy()

        char_index = np.random.choice(indices, p=probs/probs.sum())# 随机选择一个字符索引作为预测值
        char = model.int_char[char_index]# 通过索引找出预测字符return char, hidden_size

defsample(vocab_size, seq_len, model, length,sentence, top_k=None):
    hidden_size =None
    new_sentence =[char for char in sentence]for i inrange(length):

        next_char, hidden_size = predict(vocab_size, model, new_sentence[-seq_len:], top_k=top_k, hidden_size=hidden_size)

        new_sentence.append(next_char)return"".join(new_sentence)defmain():
    hidden_size =512
    num_layers =4
    batch_size =128
    seq_len =2
    epochs =30
    lr =0.0001

    f = pd.read_csv("春联.csv")
    f = f["0"]
    text =list(f)
    text =".".join(text).replace(".","")
    vocab = np.array(sorted(set(text)))# 建立字典
    vocab_size =len(vocab)print("vocab_size", vocab_size)

    val_len =int(np.floor(0.2*len(text)))# 划分训练测试集
    trainset = np.array(list(text[:-val_len]))
    validset = np.array(list(text[-val_len:]))

    model = lstm_model(vocab, hidden_size, num_layers)# 模型实例化
    train(model, trainset, batch_size, seq_len, epochs, lr=lr, valid=validset)# 训练模型
    model.load_state_dict(torch.load("lstm_model.net"))# 调用保存的模型
    new_text1 = sample(vocab_size, seq_len, model,5,"虎年", top_k=7)# 预测模型,生成100个字符,预测时选择概率最大的前5个
    new_text2 = sample(vocab_size, seq_len, model,5,"春节", top_k=7)# 预测模型,生成100个字符,预测时选择概率最大的前5个print(new_text1)# 输出预测文本print(new_text2)if __name__ =="__main__":
    main()

本文转载自: https://blog.csdn.net/qq_52785473/article/details/122759050
版权归原作者 Icy Hunter 所有, 如有侵权,请联系我们删除。

“基于pytorch使用LSTM进行虎年春联生成”的评论:

还没有评论