NLP(16)--生成式任务

news2025/1/15 6:44:16

前言

仅记录学习过程,有问题欢迎讨论

  输入输出均为不定长序列(seq2seq)

自回归语言模型:

  • x 为 str[start : end ]; y为 [start+1 : end +1] 同时训练多个字,逐字计算交叉熵

encode-decode结构:

  • Encoder将输入转化为向量或矩阵,其中包含了输入中的信息
  • Decoder将Encoder的输出转化为输出

attention机制

  • 输入和输出应该和重点句子强相关,给输入加权(所以维度应该和输入的size一致)
  • 在这里插入图片描述

Teacher forcing

  • 使用真实标签作为下一个输入(自回归语言模型就是使用的teacher forcing)

Transform结构

  • Query来自Decode ,KV来自Encode
  • 在这里插入图片描述

使用Mask Attation 来避免对output做计算时,获取了所有的信息。只使用当前的位置对应的output信息。(自回归模型,先mask,然后在softmax)
在这里插入图片描述

评价指标:

  • BLEU:按照输出的字符计算一系列的数学(惩罚机制,Ngrim)计算来评价相似性

采样:

  • Beam size:
    保留概率最大的n条路径

  • Temperature Sampling
    根据概率分布生成下一个词,通过参数T,T越大,结果越随机,分布更均匀

  • TOP-P/K
    采样先按概率从大到小排序,累加概率不超过P的范围中选
    采样从TOP-K中采样下一个词

代码

使用bert实现自回归训练模型,
添加mask attention 来实现

# coding:utf8

import torch
import torch.nn as nn
import numpy as np
import math
import random
import os
import re

from transformers import BertModel, BertTokenizer

"""
基于pytorch的LSTM语言模型
"""


class LanguageModel(nn.Module):
    def __init__(self, input_dim, vocab_size):
        super(LanguageModel, self).__init__()
        # self.embedding = nn.Embedding(len(vocab), input_dim)
        # self.layer = nn.LSTM(input_dim, input_dim, num_layers=1, batch_first=True)
        self.bert = BertModel.from_pretrained(r"D:\NLP\video\第六周\bert-base-chinese", return_dict=False)
        self.classify = nn.Linear(input_dim, vocab_size)
        # self.dropout = nn.Dropout(0.1)
        self.loss = nn.functional.cross_entropy

    # 当输入真实标签,返回loss值;无真实标签,返回预测值
    def forward(self, x, y=None):
        # x = self.embedding(x)  # output shape:(batch_size, sen_len, input_dim)
        # 使用mask来防止提前预知结果
        if y is not None:
            # 构建一个下三角的mask
            # bert的mask attention 为(batch_size, vocab_size, vocab_size) L*L
            mask = torch.tril(torch.ones(x.shape[0], x.shape[1], x.shape[1]))
            print(mask)
            x, _ = self.bert(x, attention_mask=mask)
            y_pred = self.classify(x)
            return self.loss(y_pred.view(-1, y_pred.shape[-1]), y.view(-1))
        else:
            x = self.bert(x)[0]
            y_pred = self.classify(x)
            return torch.softmax(y_pred, dim=-1)


# 加载字表
def build_vocab(vocab_path):
    vocab = {"<pad>": 0}
    with open(vocab_path, encoding="utf8") as f:
        for index, line in enumerate(f):
            char = line[:-1]  # 去掉结尾换行符
            vocab[char] = index + 1  # 留出0位给pad token
    return vocab


# 加载语料
def load_corpus(path):
    corpus = ""
    with open(path, encoding="utf8") as f:
        for line in f:
            corpus += line.strip()
    return corpus


# 随机生成一个样本
# 从文本中截取随机窗口,前n个字作为输入,最后一个字作为输出
def build_sample(tokenizer, window_size, corpus):
    start = random.randint(0, len(corpus) - 1 - window_size)
    end = start + window_size
    window = corpus[start:end]
    target = corpus[start + 1:end + 1]  # 输入输出错开一位
    # print(window, target)
    # 中文的文本转化为tokenizer的id
    input_ids_x = tokenizer.encode(window, add_special_tokens=False, padding='max_length', truncation=True,
                                   max_length=10)
    input_ids_y = tokenizer.encode(target, add_special_tokens=False, padding='max_length', truncation=True,
                                   max_length=10)
    return input_ids_x, input_ids_y


# 建立数据集
# sample_length 输入需要的样本数量。需要多少生成多少
# vocab 词表
# window_size 样本长度
# corpus 语料字符串
def build_dataset(sample_length, tokenizer, window_size, corpus):
    dataset_x = []
    dataset_y = []
    for i in range(sample_length):
        x, y = build_sample(tokenizer, window_size, corpus)
        dataset_x.append(x)
        dataset_y.append(y)
    return torch.LongTensor(dataset_x), torch.LongTensor(dataset_y)


# 建立模型
def build_model(vocab_size, char_dim):
    model = LanguageModel(char_dim, vocab_size)
    return model


# 文本生成测试代码
def generate_sentence(openings, model, tokenizer, window_size):
    # reverse_vocab = dict((y, x) for x, y in vocab.items())
    model.eval()
    with torch.no_grad():
        pred_char = ""
        # 生成文本超过30字终止
        while len(openings) <= 30:
            openings += pred_char
            x = tokenizer.encode(openings, add_special_tokens=False, padding='max_length', truncation=True,
                                 max_length=10)
            x = torch.LongTensor([x])
            if torch.cuda.is_available():
                x = x.cuda()
            # batch_size = 1 最后一个字符的概率
            y = model(x)[0][-1]
            index = sampling_strategy(y)
            # 转化为中文 只有一个字符
            pred_char = tokenizer.decode(index)
    return openings


# 采样方式
def sampling_strategy(prob_distribution):
    if random.random() > 0.1:
        strategy = "greedy"
    else:
        strategy = "sampling"
    if strategy == "greedy":
        return int(torch.argmax(prob_distribution))
    elif strategy == "sampling":
        prob_distribution = prob_distribution.cpu().numpy()
        return np.random.choice(list(range(len(prob_distribution))), p=prob_distribution)


# 计算文本ppl
def calc_perplexity(sentence, model, vocab, window_size):
    prob = 0
    model.eval()
    with torch.no_grad():
        for i in range(1, len(sentence)):
            start = max(0, i - window_size)
            window = sentence[start:i]
            x = [vocab.get(char, vocab["<UNK>"]) for char in window]
            x = torch.LongTensor([x])
            target = sentence[i]
            target_index = vocab.get(target, vocab["<UNK>"])
            if torch.cuda.is_available():
                x = x.cuda()
            pred_prob_distribute = model(x)[0][-1]
            target_prob = pred_prob_distribute[target_index]
            prob += math.log(target_prob, 10)
    return 2 ** (prob * (-1 / len(sentence)))


def train(corpus_path, save_weight=True):
    epoch_num = 15  # 训练轮数
    batch_size = 64  # 每次训练样本个数
    train_sample = 10000  # 每轮训练总共训练的样本总数
    char_dim = 768  # 每个字的维度
    window_size = 10  # 样本文本长度
    # vocab = build_vocab(r"vocab.txt")  # 建立字表
    tokenizer = BertTokenizer.from_pretrained(r"D:\NLP\video\第六周\bert-base-chinese")
    vocab_size = 21128
    corpus = load_corpus(corpus_path)  # 加载语料
    model = build_model(vocab_size, char_dim)  # 建立模型
    if torch.cuda.is_available():
        model = model.cuda()
    optim = torch.optim.Adam(model.parameters(), lr=0.001)  # 建立优化器
    print("文本词表模型加载完毕,开始训练")
    for epoch in range(epoch_num):
        model.train()
        watch_loss = []
        for batch in range(int(train_sample / batch_size)):
            x, y = build_dataset(batch_size, tokenizer, window_size, corpus)  # 构建一组训练样本
            if torch.cuda.is_available():
                x, y = x.cuda(), y.cuda()
            optim.zero_grad()  # 梯度归零
            loss = model(x, y)  # 计算loss
            loss.backward()  # 计算梯度
            optim.step()  # 更新权重
            watch_loss.append(loss.item())
        print("=========\n第%d轮平均loss:%f" % (epoch + 1, np.mean(watch_loss)))
        print(generate_sentence("忽然一阵狂风吹过,他直接", model, tokenizer, window_size))
        print(generate_sentence("天青色等烟雨,而我在", model, tokenizer, window_size))
    if not save_weight:
        return
    else:
        base_name = os.path.basename(corpus_path).replace("txt", "pth")
        model_path = os.path.join("model", base_name)
        torch.save(model.state_dict(), model_path)
        return


if __name__ == "__main__":
    train("corpus.txt", False)

    # mask = torch.tril(torch.ones(4, 4)).unsqueeze(0).unsqueeze(0)
    # print(mask)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1685973.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

v-cloak 用于在 Vue 实例渲染完成之前隐藏绑定的元素

如果你是后端开发者&#xff08;php&#xff09;&#xff0c;在接触一些vue2开发的后台时&#xff0c;会发现有这段代码&#xff1a; # CDN <script src"https://cdn.jsdelivr.net/npm/vue2/dist/vue.js"></script> # 或 <script src"https://cd…

bclinux基于欧拉(BigCloud Enterprise Linux For Euler)下安装mysql5.7

第一步&#xff1a;下载mysql5.7的rpm安装包 下载地址&#xff1a;https://dev.mysql.com/downloads/mysql/ 第二步&#xff1a;上传mysql安装包到Centos7的下 第三步&#xff1a;检查是否已经安装了mysql或者mariadb&#xff08;centos7默认安装&#xff09;&#xff0c;如已…

《intel开发手册卷3》读书笔记2

IA-32架构的内存管理分为两个部分&#xff1a;分段和分页。分段提供了一种隔离每个进程 或者任务代码、数据和栈模块的机制,保证多个进程或者任务能够在同一个处理器上运 行而不会互相干扰。分页机制实现了传统请求调页的虚拟内存系统&#xff0c;在这种系统中&#xff0c; 程序…

Python 机器学习 基础 之 数据表示与特征工程 【分箱、离散化、线性模型与树 / 交互特征与多项式特征】的简单说明

Python 机器学习 基础 之 数据表示与特征工程 【分箱、离散化、线性模型与树 / 交互特征与多项式特征】的简单说明 目录 Python 机器学习 基础 之 数据表示与特征工程 【分箱、离散化、线性模型与树 / 交互特征与多项式特征】的简单说明 一、简单介绍 二、分箱、离散化、线性…

【加密与解密(第四版)】第十七章笔记

第十八章 反跟踪技术 18.1 由BeginDebugged引发的蝴蝶效应 IsDebuggerPresent()函数读取当前进程PEB中的BeginDebugged标志 CheckRemoteDebuggerPresent() 反调试总结&#xff1a;https://bbs.kanxue.com/thread-225740.htm https://www.freebuf.com/articles/others-articl…

seata介绍及使用

什么是事务的ACID&#xff1f; 几种分布式事务解决方案&#xff1a; AT模式的二阶段提交&#xff1a; TCC模式的二阶段提交&#xff1a; 可靠消息最终一致性方案&#xff1a; SEATA部署&#xff1a; seata-server端下载&#xff1a; 修改seata/conf/file.conf配置文件&#xff…

各种各样的可视化流程图样式,大量案例来袭,设计不愁了。

在设计可视化流程图时&#xff0c;应该注重流程的清晰性和易读性&#xff0c;使用简洁明了的图形和标签&#xff0c;避免过于复杂和混乱的布局&#xff0c;使用户能够直观地理解和跟踪流程的步骤和路径。同时&#xff0c;根据具体的需求和用户群体&#xff0c;可以灵活运用颜色…

小微企业管理系统如何选择等保服务?

小微企业在选择等保&#xff08;信息安全等级保护&#xff09;服务时&#xff0c;应当考虑以下几个关键点以确保既能符合法规要求&#xff0c;又能在成本效益上做出合理决策&#xff1a; 了解等保需求&#xff1a;首先&#xff0c;小微企业需要了解自身的业务性质和信息系统的重…

【软件测试】5.测试用例

目录 1.测试用例 1.1概念 1.2测试的要素 2.测试用例的万能公式 2.1常规思考逆向思维发散性思维 2.2万能公式 2.2.1功能测试 2.2.2界面测试 2.2.3性能测试 2.2.4兼容性测试 2.2.5易用性测试 2.2.6安全测试 2.3弱网测试 1.测试用例 1.1概念 什么是测试用例&#xf…

梳理 JavaScript 中空数组调用 every方法返回true 带来惊讶的问题

前言 人生总是在意外之中. 情况大概是这样的. 前两天版本上线以后, 无意中发现了一个bug, 虽然不是很大, 为了不让用户使用时感觉到问题. 还是对着一个小小的bug进行了修复, 并重新在上线一次, 虽然问题不大, 但带来的时间成本还是存在的. 以及上线后用户体验并不是很好. 问题…

ArrayList与LinkedList

内存 内存缓存 预先将数据写到容器等数据存储单元中&#xff0c;就是软件内存缓存。 内存缓存淘汰机制 FIFO&#xff08;First in ,First Out&#xff09;&#xff08;先进先出&#xff09; LFU (Least Frequently Used) (频繁的最后淘汰) LRU(Least Recently Used) &#…

Lumines推出RGBL彩色混合LED

Luminus Devices倾心打造了一款崭新的4合1 RGBL&#xff08;红绿蓝绿石灰&#xff09;LED系列&#xff0c;专为舞台与建筑照明领域量身打造&#xff0c;满足对高显色指数&#xff08;CRI&#xff09;与高输出颜色混合的苛刻需求。这一创新之举&#xff0c;无疑是照明技术的一次…

K8S认证|CKA题库+答案| 7. 调度 pod 到指定节点

7、调度 pod 到指定节点 您必须在以下Clusterd/Node上完成此考题&#xff1a; Cluster Master node Worker node hk8s master …

DFA 算法

为什么要学习这个算法 前一段时间遇到了瓶颈&#xff0c;因为词库太多了导致会有一些速度过慢&#xff0c;而且一个正则表达式已经放不下了&#xff0c;需要进行拆分正则才可以。 正好我以前看过有关 dfa 的介绍&#xff0c;但是并没有深入的进行研究&#xff0c;所以就趁着周…

ubuntu22.04下 easyconnect+输入法安装

先使用对应ubuntu版本的easyconnect安装 sudo dpkg -i EasyConnect_x64_7_6_7_3.deb 下载压缩包servicePack&#xff0c;并解压缩 cd 下载路径/servicePack sudo cp * /usr/share/sangfor/EasyConnect/ 打开easyConnect /usr/share/sangfor/EasyConnect/EasyConnect 此处…

docker 安装 SonarQube

文章目录 docker 安装 SonarQube一、修改句柄二、创建挂载文件夹三、拉取镜像四、修改 PG 库4.1、创建用户4.2、创建库 五、启动和挂载六、访问七、安装插件 docker 安装 SonarQube 版本&#xff1a;8.9 对 JDK 8 最大支持为 8.9 版本 一、修改句柄 #修改文件句柄数量&#…

投骰子——(随机游戏的控制)

精华点在于&#xff1a;利用封装&#xff0c;函数之间的良好调用&#xff0c;从而清晰明了的解决问题。 #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> # include<stdlib.h> # include<time.h> # include"math.h" # define ARR_LEN 10 # d…

YoloV9改进策略:注意力改进|HCANet全局与局部的注意力模块CAFM|二次创新|即插即用

摘要 本文是在CAFM的基础上做了一些修改&#xff0c;算是二次创新吧&#xff01;修改后的模块对比原来的模型有了很大的提升。我用改进后的模型来改进YoloV9&#xff0c;精度得到了大幅度的提升&#xff0c;即插即用&#xff0c;简单易懂。为了方便大家写论文&#xff0c;我现…

十年磨一剑“2024成都电子信息展会”推动电子产业全球发展

2024成都电子展&#xff0c;招商工作已接近尾声&#xff0c;这场盛大的展会不仅是电子信息行业的一次盛会&#xff0c;更是中国西部电子信息产业发展的重要里程碑。自2013年起&#xff0c;中国&#xff08;西部&#xff09;电子信息博览会便选择成都作为其永久的举办地&#xf…

pod容器基础概念

一 Pod基础概念&#xff1a; ①Pod是kubernetes中最小的资源管理组件&#xff0c;Pod也是最小化运行容器化应用的资源对象。一个 Pod代表着集群中运行的一个进程。 ②kubernetes中其他大多数组件都是围绕着Pod来进行支撑和扩展Pod功能的&#xff0c; 例如&#xff0c;用于管…