Transformer复现——《深度学习框架PyTorch:入门与实践》11章的书本案例

本次复现较为顺利,没有什么bug。

训练Train  

训练了两次,下图右侧生成的效果明显好于上次构建的Tensorflow模型。不知为何train和生成是同时进行?

亲测训练实验:

main函数:

1,批量修改cuda改成cpu

2epoch改成1

3,在main函数下面添加语句train()

4,执行main.py函数

打开visdom server出现问题,解决方法如下:
小白安装Visdom简明教程_zealwx的博客-CSDN博客

其中,修改的server.py没找到,于是修改了run_server.py。

Statics作者百度网盘分享链接也失效了。于是没有执行statics替换那步。不过直接解决了visdom无法打开的问题

Generate生成

# coding:utf8
import sys, os
import torch as t
from torch.utils.data import DataLoader
from data import get_data
from model import PoetryModel
from torch import nn
from utils import Visualizer
import tqdm
from torchnet import meter
import ipdb


class Config(object):
    data_path = 'data'         # 诗歌的文本文件存放路径
    pickle_path = 'data/tang.npz'    # 预处理好的二进制文件
    lr = 1e-3
    weight_decay = 1e-4
    use_gpu = False
    epoch = 50
    env = 'poetry1'             # visdom env
    batch_size = 128
    maxlen = 125                # 超过这个长度之后的字被丢弃,小于这个长度的在前面补空格
    max_gen_len = 200           # 生成诗歌最长长度
    model_path = 'checkpoints/tang_5.pth'           # 预训练模型路径
    start_words = '美丽与智慧的月儿'     # 诗歌开始
    model_prefix = 'checkpoints/tang'  # 模型保存路径
    plot_every = 5             # 每20个batch 可视化一次
    debug_file = '/tmp/debugp/'

opt = Config()

def gen(**kwargs):
    """
    给定几个词,根据这几个词接着生成一首完成的诗词
    例如,start_words为'海内存知己',可以生成
    海内存知己,天涯尚未安。
    故人归旧国,新月到新安。
    海气生边岛,江声入夜滩。
    明朝不可问,应与故人看。
    """

    for k, v in kwargs.items():
        setattr(opt, k, v)

    device = t.device('cpu') if opt.use_gpu else t.device('cpu')
    data, word2ix, ix2word = get_data(opt)
    model = PoetryModel(len(word2ix))
    model.load_state_dict(t.load(opt.model_path))
    model.to(device)
    model.eval()

    src = [word2ix[word] for word in opt.start_words]
    res = src = [word2ix['<START>']] + src
    max_len = 100

    for _ in range(max_len):
        src = t.tensor(res).to(device)[:, None]
        src_mask = generate_square_subsequent_mask(src.shape[0])
        src_pad_mask = src == len(word2ix) - 1
        src_pad_mask = src_pad_mask.permute(1, 0).contiguous()
        memory, logits = model(src, src_mask.cpu(), src_pad_mask.cpu())
        next_word = logits[-1, 0].argmax().item()
        if next_word == word2ix['<EOP>']:
            break
        res.append(next_word)
    res = [ix2word[_] for _ in res[1:]]
    print(''.join(res))

def gen_acrostic(**kwargs):
    """
    生成藏头诗
    start_words为'深度学习'
    生成:
	深山高不极,望望极悠悠。
	度日登楼望,看云上砌秋。
	学吟多野寺,吟想到江楼。
	习静多时选,忘机尽处求。
    """
    for k, v in kwargs.items():
        setattr(opt, k, v)

    device = t.device('cpu') if opt.use_gpu else t.device('cpu')

    data, word2ix, ix2word = get_data(opt)
    model = PoetryModel(len(word2ix))
    model.load_state_dict(t.load(opt.model_path))
    model.to(device)

    model.eval()

    start_word_len = len(opt.start_words)
    index = 0  # 用来指示已经生成了多少句藏头诗
    src_base = [word2ix[word] for word in opt.start_words]
    res = [word2ix['<START>']] + [src_base[index]]
    index += 1
    max_len = 100

    for _ in range(max_len):
        src = t.tensor(res).to(device)[:, None]
        src_mask = generate_square_subsequent_mask(src.shape[0])
        src_pad_mask = src == len(word2ix) - 1
        src_pad_mask = src_pad_mask.permute(1, 0).contiguous()
        memory, logits = model(src, src_mask.cpu(), src_pad_mask.cpu())

        next_word = logits[-1, 0].argmax().item()
        # 如果遇到句号感叹号等,把藏头的词作为下一个句的输入
        if next_word in {word2ix[u'。'],word2ix[u'!'],word2ix['<START>']}:
            # 如果生成的诗歌已经包含全部藏头的词,则结束
            if index == start_word_len:
                res.append(next_word)
                break
            # 把藏头的词作为输入,预测下一个词
            res.append(next_word)
            res.append(src_base[index])
            index += 1
        else:
            res.append(next_word)

    res = [ix2word[_] for _ in res[1:]]
    print(''.join(res))


def train(**kwargs):
    for k, v in kwargs.items():
        setattr(opt, k, v)

    device = t.device('cpu') if opt.use_gpu else t.device('cpu')
    vis = Visualizer(env = opt.env)

    # 获取数据
    data, word2ix, ix2word = get_data(opt)
    data = t.from_numpy(data)
    dataloader = DataLoader(data, batch_size=opt.batch_size, shuffle=True, num_workers=1)

    # 模型定义
    model = PoetryModel(len(word2ix))
    optimizer = t.optim.Adam(model.parameters(), lr=0.0001, betas=(0.9, 0.98), eps=1e-9)
    criterion = nn.CrossEntropyLoss(ignore_index=len(word2ix)-1)
    if opt.model_path:
        model.load_state_dict(t.load(opt.model_path))
    model.to(device)

    loss_meter = meter.AverageValueMeter()
    for epoch in range(opt.epoch):
        loss_meter.reset()
        for ii, data_ in tqdm.tqdm(enumerate(dataloader)):
            # 训练
            data_ = data_.long().transpose(1, 0).contiguous()
            data_ = data_.to(device)
            optimizer.zero_grad()
            input_, target = data_[:-1, :], data_[1:, :]
            src_mask = generate_square_subsequent_mask(input_.shape[0])
            src_pad_mask = input_ == len(word2ix) - 1
            src_pad_mask = src_pad_mask.permute(1,0).contiguous()
            
            memory, logit = model(input_, src_mask.to(device), src_pad_mask.to(device))

            mask = target != word2ix['</s>']
            target = target[mask] # 去掉前缀的空格
            logit = logit.flatten(0, 1)[mask.view(-1)]

            loss = criterion(logit, target)
            loss.backward()
            optimizer.step()

            loss_meter.add(loss.item())
        
            # 可视化
            if (1 + ii) % opt.plot_every == 0:
                if os.path.exists(opt.debug_file):
                        ipdb.set_trace()

                vis.plot('loss', loss_meter.value()[0])

                # 诗歌原文
                poetrys = [[ix2word[_word] for _word in data_[:, _iii].tolist()]
                            for _iii in range(data_.shape[1])][:16]
                vis.text('</br>'.join([''.join(poetry) for poetry in poetrys]), win=u'origin_poem')

                gen_poetries = []
                # 分别以这几个字作为诗歌的第一个字,生成8首诗
                for word in list(u'美丽和智慧的月儿'):
                    gen_poetry = ''.join(generate(model, word, word2ix, ix2word))
                    gen_poetries.append(gen_poetry)

                # gen_poetries = generate(model, u'春江花月夜凉如水', ix2word, word2ix)

                vis.text('</br>'.join([''.join(poetry) for poetry in gen_poetries]), win=u'gen_poem')

        if (epoch+1) % opt.plot_every == 0:
            t.save(model.state_dict(), '%s_%s.pth' % (opt.model_prefix, epoch+1))

@t.no_grad()
def generate(model, start_words, word2ix, ix2word, max_len=100):
    model.eval()
    device = t.device('cpu') if opt.use_gpu else t.device('cpu')

    src = [word2ix[word] for word in start_words]
    res = src = [word2ix['<START>']] + src 

    for _ in range(max_len):
        src = t.tensor(res).to(device)[:, None]
        src_mask = generate_square_subsequent_mask(src.shape[0])
        src_pad_mask = src == len(word2ix)-1
        src_pad_mask = src_pad_mask.permute(1,0).contiguous()
        memory,logits = model(src, src_mask.cpu(), src_pad_mask.cpu())
        
        next_word =  logits[-1,0].argmax().item()
        if next_word == word2ix['<EOP>']:
            break
        res.append(next_word)
        
        if next_word == word2ix['<EOP>']:
            break
    res = [ix2word[_] for _ in res]
    model.train()
    return res


def generate_square_subsequent_mask(sz):
    mask = (t.triu(t.ones(sz, sz)) == 1).transpose(0, 1) # 生成下三角矩阵(下三角全为True,其余位False)
    mask = mask.float().masked_fill(mask == 0, float('-inf')).masked_fill(mask == 1, float(0.0))
    return mask

 
if __name__ == '__main__':
    import fire
    fire.Fire()
    #train(batch_size=128,pickle_path='tang.npz',lr=1e-3,epoch=2)
    #train()
    gen_acrostic()

利用.pth文件,进行文本生成

main源代码进行如下更改:

1 model_path = 'checkpoints/tang_5.pth'           # 预训练模型路径

    start_words = '美丽与智慧的月儿'     # 诗歌开始

2,在if __name__==’__main__’:下面加入测试字段:

gen()

3,将gen()函数换成gen_acrostic(),则可生产藏头诗

美人歌舞罢,独自对花时。今日花前去,明朝叶上垂。

丽句传歌处,清吟对酒时。山僧同宿寺,野客共归期。野寺僧来远,江楼客到迟。相思不相见,应喜白云知。

和风吹雨过江城,万里云山一望平。不见江南人不见,空闻塞上戍楼声。

智者不可见,愚者不可论。愚人不识面,智者不识门。

慧星现,现在四方同。若在诸天幷五日,不然一法定无踪,不是一般通。

的的无消息,啾啾空夜啼。不知人事少,何处更相携。

月落星稀夜未央,月明灯暗满衣裳。

儿童不识汉家翁,一种青山万岁中。

结论:

1,利用模型.pth可以生成两种情形或格式的文本。(说不定也可以生成歌词。)

2,预训练模型.pth训练的次数越多(5~50分析),模型倾向越好。

3,每次同等情况下,生成的结果一致,可重复性高。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值