NLP(17)--大模型发展(1)

news2024/12/22 20:03:26

前言

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

大模型的演化:

ElMO : 类似双向lstm 结果和词向量拼接 预训练鼻祖

GPT :使用了Transformer 模型 开始使用Token (发现预训练的作用)

Bert:认为双向比单向好 MLM(双向) 优于 LTR

Ernie-baidu:中文强于bert mask训练改为词组而非token

GPT2:继续使用Transformer 使用单向 more data

UNILM:使用Transformer + Mask attention 所以双向和单向都可以训

Transformer-XL & XLNet: 循环机制(利用attention|)解决bert输入长度限制(max_len = 512)

Roberta: bert变体 ,more data/去掉NSP/长样本/动态改变Mask位置 效果更好

Span bert:去掉NSP 随机mask连续token SBO

ALBert: 试图解决bert模型过大的问题(因式分解 vh = vE + E*h) 想办法减少参数( 跨层参数共享)

T5:Text-to-Text Transfer Transformer:Seq2Seq理论解决一切NLP问题

GPT3:参数量1750亿 目标:像人一样学习

总结

使用类bert形式训练 还是需要一个线性层配合任务改变 使用还是不便
更加理想的方式,使用文本来描述任务答案,训练方式统一(text-text),推理方式统一(无需解码结果 index-result)

Instruct GPT:

SFT训练 从续写到回答 输入的x 为问题 x+y为答案
在这里插入图片描述

RW训练(判断答案好坏的模型):强化学习 一个问题对应多个答案,由人工排序打分 y(w)=更好的答案 y(L) =差的 (类似于loss)

RL训练 在SFT上发展,但期望和SFT训练后结果分布相差不大 目标是使得RW model最大

In context learning:

训练内容直接在对话中产生,学习后输出内容(模型权重没变)
Z-s o-s f-s (zero/one/few shot) 问题中是否包含样例(和prompt)

提示工程:

  1. 提示词(prompt) 提示词是模型在训练过程中学习到的,模型在训练过程中会学习到一些通用的模式,这些模式可以作为提示词来指导模型的训练。
  2. 复杂任务可以拆解为多个步骤一步一训练,训练完成后再组合起来

代码

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

标题/内容任务,也是自回归模型,
对于输入输出长度不一致的问题,可以仔细看看怎么实现的,mask怎么实现的(采用mask使得x,y相互不可见)

# coding:utf8
import json

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

from torch.utils.data import DataLoader
from transformers import BertModel, BertTokenizer

"""
基于pytorch的LSTM语言模型
使用SFT训练 Q&A
"""


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 = torch.nn.CrossEntropyLoss(ignore_index=-1)

    # 当输入真实标签,返回loss值;无真实标签,返回预测值
    def forward(self, x, y=None, mask=None):
        # x = self.embedding(x)  # output shape:(batch_size, sen_len, input_dim)
        # 使用mask来防止提前预知结果
        if y is not None:
            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)
            y_pred = self.classify(x)
            return torch.softmax(y_pred, dim=-1)


# 加载语料
def load_corpus(path):
    title_list = []
    content_list = []
    with open(path, encoding="utf8") as f:
        for i, line in enumerate(f):
            line = json.loads(line)
            title_list.append(line["title"])
            content_list.append(line["content"])
    return [title_list, content_list]


# 建立数据集
# sample_length 输入需要的样本数量。需要多少生成多少
# vocab 词表
# window_size 样本长度
# corpus 语料字符串
def build_dataset(sample_length, tokenizer, corpus, max_len, valid_flag=False):
    # dataset_x = []
    # dataset_y = []
    # dataset_mask = []
    dataset = []
    for i in range(sample_length):
        dataiter = build_sample(tokenizer, corpus, max_len, valid_flag)
        # dataset_x.append(x)
        # dataset_y.append(y)
        # dataset_mask.append(mask)
        dataset.append(dataiter)
    return DataLoader(dataset, batch_size=32, shuffle=True, num_workers=0)


# 构建一个的mask
def create_mask(question_size, answer_size):
    len_s1 = question_size + 2  # cls + sep
    len_s2 = answer_size + 1  # sep
    # 创建掩码张量
    mask = torch.ones(len_s1 + len_s2, len_s1 + len_s2)
    # 遍历s1的每个token
    for i in range(len_s1):
        # s1的当前token不能看到s2的任何token
        mask[i, len_s1:] = 0
        # 遍历s2的每个token
    for i in range(len_s2):
        # s2的当前token不能看到后面的s2 token
        mask[len_s1 + i, len_s1 + i + 1:] = 0
    return mask


def pad_mask(tensor, target_shape):
    # 获取输入张量和目标形状的长宽
    height, width = tensor.shape
    target_height, target_width = target_shape
    # 创建一个全零张量,形状为目标形状
    result = torch.zeros(target_shape, dtype=tensor.dtype, device=tensor.device)
    # 计算需要填充或截断的区域
    h_start = 0
    w_start = 0
    h_end = min(height, target_height)
    w_end = min(width, target_width)
    # 将原始张量对应的部分填充到全零张量中
    result[h_start:h_end, w_start:w_end] = tensor[:h_end - h_start, :w_end - w_start]
    return result


def build_sample(tokenizer, corpus, max_len, valid_flag=False):
    x_list, y_list = corpus
    # 随机获取一组样本:
    random_index = random.randint(0, len(x_list) - 1)
    x = x_list[random_index]
    if valid_flag:
        print(x)
    y = y_list[random_index]
    # 中文的文本转化为tokenizer的id 不添加【CLS】
    input_ids_x = tokenizer.encode(x, add_special_tokens=False)
    input_ids_y = tokenizer.encode(y, add_special_tokens=False)
    pad_x = [tokenizer.cls_token_id] + input_ids_x + [tokenizer.sep_token_id] + input_ids_y
    pad_y = len(input_ids_x) * [-1] + [tokenizer.sep_token_id] + input_ids_y
    # 自己对长度做处理  padding 到 max_len
    pad_x = pad_x[:max_len] + [0] * (max_len - len(pad_x))
    pad_y = pad_y[:max_len] + [0] * (max_len - len(pad_y))

    # 构建一个的mask矩阵,让prompt内可以交互,answer中上下文之间没有交互
    mask = create_mask(len(input_ids_x), len(input_ids_y))
    mask = pad_mask(mask, (max_len, max_len))
    return [torch.LongTensor(pad_x), torch.LongTensor(pad_y), mask]


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


# 采样方式
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)


def evaluate(openings, model, tokenizer, corpus):
    model.eval()
    # 转化为input_id
    openings = tokenizer.encode(openings)
    # 控制生成的字数
    with torch.no_grad():
        while len(openings) <= 50:
            x = torch.LongTensor([openings])
            if torch.cuda.is_available():
                x = x.cuda()
            # 因为有了mask 所以输入就是输出,看最后一个字的预测
            y_pred = model(x)[0][-1]
            index = sampling_strategy(y_pred)
            openings.append(index)
    return tokenizer.decode(openings)



def train(corpus_path, save_weight=True):
    epoch_num = 15  # 训练轮数
    batch_size = 32  # 每次训练样本个数
    train_sample = 1000  # 每轮训练总共训练的样本总数
    char_dim = 768  # 每个字的维度
    tokenizer = BertTokenizer.from_pretrained(r"D:\NLP\video\第六周\bert-base-chinese")
    vocab_size = 21128
    max_len = 50
    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)  # 建立优化器
    # data
    dataset = build_dataset(train_sample, tokenizer, corpus, max_len)
    print("文本词表模型加载完毕,开始训练")
    for epoch in range(epoch_num):
        model.train()
        watch_loss = []
        for x, y, mask in dataset:  # 构建一组训练样本
            if torch.cuda.is_available():
                x, y, mask = x.cuda(), y.cuda(), mask.cuda()
            optim.zero_grad()  # 梯度归零
            loss = model(x, y, mask)  # 计算loss
            loss.backward()  # 计算梯度
            optim.step()  # 更新权重
            watch_loss.append(loss.item())
        print("=========\n第%d轮平均loss:%f" % (epoch + 1, np.mean(watch_loss)))
        result1 = evaluate("阿根廷歹徒抢服装尺码不对拿回店里换", model, tokenizer, corpus)
        print(result1)

    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("sample_data.json", False)

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


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

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

相关文章

ARP基本原理

相关概念 ARP报文 ARP报文分为ARP请求报文和ARP应答报文&#xff0c;报文格式如图1所示。 图1 ARP报文格式 Ethernet Address of destination&#xff08;0–31&#xff09;和Ethernet Address of destination&#xff08;32–47&#xff09;分别表示Ethernet Address of dest…

Linux中解决普通用户使用不了sudo问题

目录 sudo的使用场景sudo使用不了的原因解决方法 sudo的使用场景 之前我们介绍了文件的权限问题 如果一个普通用户想去执行一个它命令之外的权限&#xff0c;只能使用sudo 比如普通用户使用yum去安装软件&#xff0c;需要sudo yum xxxx sudo使用不了的原因 这里我们用普通用户…

浏览器的下载行为基本原理

浏览器解析 在使用浏览器访问某些资源时&#xff0c;有些资源是直接下载有些资源是直接打开。例如前端的html&#xff0c;xml&#xff0c;css&#xff0c;图片等资源都是直接打开&#xff0c;而txt&#xff0c;excel等文件是直接下载。那么如何控制访问一个资源时是下载文件还…

C# run Node.js

C# run nodejs Inter-Process Communication&#xff0c;IPC Process类 启动Node.js进程&#xff0c;通过标准输入输出与其进行通信。 // n.js// 监听来自标准输入的消息 process.stdin.on(data, function (data) {// 收到消息后&#xff0c;在控制台输出并回复消息console.l…

MyBatisPlus标准分页功能制作,以及设置分页拦截器,selectPage(new Page<>(current,size),null)

目录 1、设置分页拦截器 2、创建数据库及表 3、pom.xml 4、添加MP的相关配置信息 application.yml 5、根据数据库表创建实体类 User 6、创建 UserDao 接口 7、编写引导类 8、编写测试类 9、Run的运行结果 1、设置分页拦截器 package com.example.config; import com.baomidou.m…

从零开始傅里叶变换

从零开始傅里叶变换 1 Overview2 傅里叶级数2.1 基向量2.2 三角函数系表示 f ( t ) f(t) f(t)2.2.1 三角函数系的正交性2.2.2 三角函数系的系数 2.3 复指数函数系表示 f ( t ) f(t) f(t)2.3.1 复指数函数系的系数2.3.2 复指数函数系的正交性 2.4 傅里叶级数总结 3 傅里叶变换…

基于轻量级神经网络GhostNet开发构建CIFAR100数据集场景下的图像识别分析系统,对比不同分辨路尺度下模型的性能情况

Cifar100数据集是一个经典的图像分类数据集&#xff0c;常用于计算机视觉领域的研究和算法测试。以下是关于Cifar100数据集的详细介绍&#xff1a; 数据集构成&#xff1a;Cifar100数据集包含60000张训练图像和10000张测试图像。其中&#xff0c;训练图像分为100个类别&#x…

肯尼亚大坝决堤反思:强化大坝安全监测的必要性

一、背景介绍 近日&#xff0c;肯尼亚发生了一起严重的大坝决堤事件。当地时间4月29日&#xff0c;肯尼亚内罗毕以北的一座大坝决堤&#xff0c;冲毁房屋和车辆。当地官员称&#xff0c;事故遇难人数已升至71人。这起事件再次提醒我们&#xff0c;大坝安全无小事&#xff0c;监…

SpringMVC源码解读[1] -Spring MVC 环境搭建

源码地址: https://github.com/chen-jiacheng/springmvc-quickstart 一、使用 IDEA 创建 Spring MVC 项目 直接创建项目即可 默认项目结构: springmvc-quickstart ├── pom.xml └── src├── main│ ├── java│ │ └── com│ │ └── chenjiache…

微软开发者大会:编程进入自然语言时代、“AI员工”闪亮登场

当地时间周二&#xff0c;美国科技公司微软召开年度Build开发者大会。在CEO纳德拉的带领下&#xff0c;微软各个产品团队再一次展现出惊人的执行力&#xff0c;在发布会上又拿出了接近50个新产品或功能更新。 整场发布会持续了接近两个小时&#xff0c;在这里挑选了一些投资者…

深度学习之基于YoloV5入侵检测系统

欢迎大家点赞、收藏、关注、评论啦 &#xff0c;由于篇幅有限&#xff0c;只展示了部分核心代码。 文章目录 一项目简介 二、功能三、系统四. 总结 一项目简介 一、项目背景 随着信息技术的飞速发展&#xff0c;网络安全问题日益凸显。入侵检测系统&#xff08;IDS&#xff0…

[图解]产品经理创新模式01物流变成信息流

1 00:00:01,570 --> 00:00:04,120 有了现状的业务序列图 2 00:00:04,960 --> 00:00:08,490 我们就来改进我们的业务序列图了 3 00:00:08,580 --> 00:00:11,010 把我们要做的系统放进去&#xff0c;改进它 4 00:00:13,470 --> 00:00:15,260 怎么改进&#xff1f;…

第五节 Starter 的加载全貌

tips&#xff1a;下载源码&#xff0c;再结合本章内容&#xff0c;学习整个加载过程。 上一章&#xff0c;我们理解了 spring.factories 的触发时机&#xff0c;但放在 SpringBoot 的整个加载过程来讲&#xff0c;只能算部分。 而这一章&#xff0c;将从 SpringBoot 的加载全貌…

Day 60 84.柱状图中最大的矩形

柱状图中最大的矩形 给定 n 个非负整数&#xff0c;用来表示柱状图中各个柱子的高度。每个柱子彼此相邻&#xff0c;且宽度为 1 。 求在该柱状图中&#xff0c;能够勾勒出来的矩形的最大面积。 1 < heights.length <10^50 < heights[i] < 10^4 ​ 这道题很明显&…

x264码率控制基础

x264码率控制模型 x264码率控制也是基于率失真模型即,D为失真,R为码率,为拉格朗日因子,当取值较大时,倾向于低码率高失真的情况;当取值较小时,倾向于高码率低失真的情况。由拉格朗日乘数法知, 参考[1], x264采用的是高码率下码率和失真之间的关系

数据结构和算法|排序算法系列(一)|选择排序

首先需要你对排序算法的评价维度和一个理想排序算法应该是什么样的有一个基本的认知&#xff1a; 《Hello算法之排序算法》 主要内容来自&#xff1a;Hello算法11.2 选择排序 选择排序是明显的基于比较的排序。下文开始阐述选择排序的整个算法流程 算法流程 选择排序应该已…

x264 码率控制原理:x264_ratecontrol_start 函数

x264_ratecontrol_start 函数 函数原理 函数功能:编码一帧之前,为当前帧选择一个量化 QP,属于帧级别码率控制;这对于控制视频质量和文件大小至关重要。通过调整QP,编码器可以在保持视频质量的同时,尽可能减小输出文件的大小。函数参数:x264_t *h: 编码器上下文结构体指…

贴片 RS8752XK 封装SOP-8 250MHz,2通道高速运放

传感器信号放大&#xff1a;在传感器应用中&#xff0c;RS8752XK可以用于放大微弱的传感信号&#xff0c;如压力、温度、光强等传感器的信号。 数据采集系统&#xff1a;在数据采集设备中&#xff0c;RS8752XK可以用于放大和调理模拟信号&#xff0c;以供模数转换器&#xff0…

abs(-2147483648) == 2147483648?

从数学意义上&#xff0c;这是对的。但是&#xff0c;就怕但是。 #include int main() {long long v;v abs(-2147483648);printf("%lld\n", v);return 0; } 输出: -2147483648 我们从source code中一一解开. /* Return the absolute value of I. */ int abs (…