ai学习(2)分词、分词算法、加入注意力机制的Seq2Seq结构模型(编码器、解码器、注意力机制)、日期转换实战代码

news2024/11/24 12:33:56

文章目录

  • 参考书《多模态大模型:算法、应用与微调》
  • 1.分词
  • 2.分词算法
    • 主流的三种分词算法,BPE分词算法(GPT-2、BART、Llama模型)、WordPiece分词算法(BERT模型)、SentencePiece分词算法(ChatGLM、BLOOM、PaLM模型)
  • 3.Seq2Seq结构模型
      • 编码器(Encoder)
      • 解码器(Decoder)
      • 工作流程
  • 4.加入注意力机制的Seq2Seq模型
  • 5.日期转换实战完整代码(加入注意力机制的Seq2Seq结构模型)

参考书《多模态大模型:算法、应用与微调》

1.分词

词元(token)可以理解为最小的语义单元,分词的目的是将输入文本转换为一系列的词元,并且还要保证每个词元拥有相对完整的独立语义。

分词的粒度从细到粗依次是character、subword、word

1.character表示的是单个字符,例如a、b、c、d。

2.word表示的是整个单词,例如water表示水的意思。

3.subword相当于英文中的词根、前缀、后缀等,例如unfortunately中的un、fortun(e)、ly等就是subword,它们都是有含义的。

2.分词算法

分词算法也经历了按词语分、按字分和按子词分三个阶段。

1.按词语分和按字分比较好理解,也有一些工具包可以使用,例如jieba分词。

2.如果是按照子词分,那么词元就可以是偏旁部首,当然对于比较简单的字,一个词元也可以是一个完整的字。
例如,​“江”​“河”​“湖”​“海”这四个字都跟水有关,并且它们都是三点水旁,那么在分词的时候,​“氵”很可能会作为一个词元,​“工”​“可”​“胡”​“每”是另外的词元。
假如“氵”的词元ID为1,​“工”​“可”​“胡”​“每”的词元ID分别是2、3、4、5,那么“江”​“河”​“湖”​“海”的词元序列就可以表示为12、13、14、15。
这样做的好处是,只要字中带有三点水旁,或者词元序列中含有词元ID为1的元素,那么我们就可以认为这个字或者这个词元序列跟水有关。即使是沙漠的“沙”字,是由“氵”和“少”组成的,也可以理解为水很少的地方。

主流的三种分词算法,BPE分词算法(GPT-2、BART、Llama模型)、WordPiece分词算法(BERT模型)、SentencePiece分词算法(ChatGLM、BLOOM、PaLM模型)

1.BPE(Byte Pair Encoding)分词算法是一种用于处理自然语言文本的子词分词技术,它通过统计字符对的频率来迭代地合并最常见的字符对,从而构建词汇表。这种方法能有效处理罕见词汇和新词,减少词汇表的大小,同时保留足够的信息以理解上下文。BPE广泛应用于GPT-2、BART和Llama等模型中,以提高语言生成和理解的能力。

2.WordPiece分词算法是由Google开发的一种子词分词方法,它同样是基于统计的,但与BPE不同的是,WordPiece在构建词汇表时会考虑整个语料库的似然概率,选择能够最大化似然概率的字符对进行合并。BERT模型就使用了WordPiece分词算法,这使得BERT能够有效地处理各种NLP任务,如文本分类、问答和命名实体识别等。

3.SentencePiece是另一种子词分词工具,它不仅支持BPE算法,还支持unigram语言模型。SentencePiece的主要特点是它允许直接从原始句子进行训练,不需要预定义的词汇表,这使得它在处理新词和罕见词时更为灵活。ChatGLM、BLOOM和PaLM等模型采用了SentencePiece分词算法,以增强其对话生成和理解的能力。

3.Seq2Seq结构模型

Seq2Seq(Sequence to Sequence),即序列到序列模型,是一种处理序列数据的模型框架,广泛应用于自然语言处理(NLP)领域中的各种任务,如机器翻译、文本摘要、问答系统等。Seq2Seq模型的核心思想是将一个序列转换为另一个序列,通常包括两个主要部分:编码器(Encoder)和解码器(Decoder)。

在这里插入图片描述

在这里插入图片描述

编码器(Encoder)

编码器通常是一个循环神经网络(RNN)或其变体(如LSTM或GRU),或者是更现代的Transformer架构。它的任务是读取输入序列(如一句话或一段文本),并将其编码成一个固定大小的内部表示,这个表示通常被称为上下文向量(Context Vector)或编码向量。这个向量旨在捕捉输入序列的主要信息。

解码器(Decoder)

解码器也是一个循环神经网络或Transformer架构,它使用编码器的输出作为初始状态,并逐步生成输出序列。在每个时间步,解码器会生成一个输出单元(如一个词或字符),并将其作为下一个时间步的输入,直到生成一个特殊的结束符号,表示序列结束。

工作流程

  1. 输入处理:输入序列首先被分词(Tokenized)和编码(如转换为词向量)。
  2. 编码阶段:编码器读取输入序列,并生成一个上下文向量。
  3. 解码阶段:解码器使用上下文向量作为初始状态,并逐步生成输出序列,直到生成结束符号。
  4. 输出处理:生成的序列通常需要被解码或转换回可读的文本形式。

4.加入注意力机制的Seq2Seq模型

注意力机制(Attention Mechanism)是Seq2Seq模型的一个重要改进,它允许解码器在生成每个输出元素时“关注”输入序列中的不同部分。这种机制通过计算输入序列中每个部分与当前输出的相关性权重来实现,从而使得模型能够更加关注与当前生成任务最相关的输入部分。

注意力机制的引入显著提高了Seq2Seq模型处理长序列和捕捉复杂依赖关系的能力,尤其是在机器翻译等任务中,它使得模型能够更好地理解输入序列的全局上下文,从而生成更加准确和流畅的输出。
在这里插入图片描述
在这里插入图片描述

5.日期转换实战完整代码(加入注意力机制的Seq2Seq结构模型)

import torch as th
import torch.nn as nn
import torch.optim as optim
import torch.nn.functional as F
from torch.utils.data import Dataset, DataLoader
import numpy as np
import random
import datetime

# Constants
SOS_token = 0
EOS_token = 1
PAD_token = 2
MAX_LENGTH = 11

# EncoderRNN
class EncoderRNN(nn.Module):
    def __init__(self, input_size, hidden_size, dropout_p=0.1):
        super(EncoderRNN, self).__init__()
        self.hidden_size = hidden_size
        self.embedding = nn.Embedding(input_size, hidden_size)
        self.rnn = nn.RNN(hidden_size, hidden_size, batch_first=True)
        self.dropout = nn.Dropout(dropout_p)

    def forward(self, x):
        x = self.embedding(x)
        x = self.dropout(x)
        output, hidden = self.rnn(x)
        return output, hidden

# DecoderRNN
class DecoderRNN(nn.Module):
    def __init__(self, hidden_size, output_size):
        super(DecoderRNN, self).__init__()
        self.embedding = nn.Embedding(output_size, hidden_size)
        self.rnn = nn.RNN(hidden_size, hidden_size, batch_first=True)
        self.out = nn.Linear(hidden_size, output_size)

    def forward(self, encoder_outputs, encoder_hidden, target_tensor=None):
        batch_size = encoder_outputs.size(0)
        decoder_input = th.empty(batch_size, 1, dtype=th.long).fill_(SOS_token)
        decoder_hidden = encoder_hidden
        decoder_outputs = []
        for i in range(MAX_LENGTH):
            decoder_output, decoder_hidden = self.forward_step(decoder_input, decoder_hidden)
            decoder_outputs.append(decoder_output)
            if target_tensor is not None:
                decoder_input = target_tensor[:, i].unsqueeze(1)
            else:
                _, topi = decoder_output.topk(1)
                decoder_input = topi.squeeze(-1).detach()
        decoder_outputs = th.cat(decoder_outputs, dim=1)
        decoder_outputs = F.log_softmax(decoder_outputs, dim=-1)
        return decoder_outputs, decoder_hidden

    def forward_step(self, x, hidden):
        x = self.embedding(x)
        x = F.relu(x)
        x, hidden = self.rnn(x, hidden)
        output = self.out(x)
        return output, hidden

# Attention
class Attention(nn.Module):
    def __init__(self, hidden_size):
        super(Attention, self).__init__()
        self.Wa = nn.Linear(hidden_size, hidden_size)
        self.Ua = nn.Linear(hidden_size, hidden_size)
        self.Va = nn.Linear(hidden_size, 1)

    def forward(self, query, keys):
        scores = self.Va(th.tanh(self.Wa(query) + self.Ua(keys)))
        scores = scores.squeeze(2).unsqueeze(1)
        weights = F.softmax(scores, dim=-1)
        context = th.bmm(weights, keys)
        return context, weights

# AttentionDecoderRNN
class AttentionDecoderRNN(nn.Module):
    def __init__(self, hidden_size, output_size, dropout_p=0.1):
        super(AttentionDecoderRNN, self).__init__()
        self.embedding = nn.Embedding(output_size, hidden_size)
        self.attention = Attention(hidden_size)
        self.rnn = nn.RNN(2 * hidden_size, hidden_size, batch_first=True)
        self.out = nn.Linear(hidden_size, output_size)
        self.dropout = nn.Dropout(dropout_p)

    def forward(self, encoder_outputs, encoder_hidden, target_tensor=None):
        batch_size = encoder_outputs.size(0)
        decoder_input = th.empty(batch_size, 1, dtype=th.long).fill_(SOS_token)
        decoder_hidden = encoder_hidden
        decoder_outputs = []
        attentions = []
        for i in range(MAX_LENGTH):
            decoder_output, decoder_hidden, attn_weights = self.forward_step(decoder_input, decoder_hidden, encoder_outputs)
            decoder_outputs.append(decoder_output)
            attentions.append(attn_weights)
            if target_tensor is not None:
                decoder_input = target_tensor[:, i].unsqueeze(1)
            else:
                _, topi = decoder_output.topk(1)
                decoder_input = topi.squeeze(-1).detach()
        decoder_outputs = th.cat(decoder_outputs, dim=1)
        decoder_outputs = F.log_softmax(decoder_outputs, dim=-1)
        attentions = th.cat(attentions, dim=1)
        return decoder_outputs, decoder_hidden, attentions

    def forward_step(self, input, hidden, encoder_outputs):
        embedded = self.dropout(self.embedding(input))
        query = hidden.permute(1, 0, 2)
        context, attn_weights = self.attention(query, encoder_outputs)
        input_rnn = th.cat((embedded, context), dim=2)
        output, hidden = self.rnn(input_rnn, hidden)
        output = self.out(output)
        return output, hidden, attn_weights

# DateDataset
class DateDataset(Dataset):
    def __init__(self, n):
        self.date_cn = []
        self.date_en = []
        for _ in range(n):
            year = random.randint(1950, 2050)
            month = random.randint(1, 12)
            day = random.randint(1, 28)
            date = datetime.date(year, month, day)
            self.date_cn.append(date.strftime("%y-%m-%d"))
            self.date_en.append(date.strftime("%d/%b/%Y"))
        self.vocab = set([str(i) for i in range(0, 10)] + ["-", "/"] + [i.split("/")[1] for i in self.date_en])
        self.word2index = {v: i for i, v in enumerate(sorted(list(self.vocab)), start=2)}
        self.word2index["<SOS>"] = SOS_token
        self.word2index["<EOS>"] = EOS_token
        self.word2index["<PAD>"] = PAD_token
        self.vocab.add("<SOS>")
        self.vocab.add("<EOS>")
        self.vocab.add("<PAD>")
        self.index2word = {i: v for v, i in self.word2index.items()}
        self.input, self.target = [], []
        for cn, en in zip(self.date_cn, self.date_en):
            self.input.append([self.word2index[v] for v in cn])
            self.target.append(
                [self.word2index["<SOS>"], ] +
                [self.word2index[v] for v in en[:3]] +
                [self.word2index[en[3:6]]] +
                [self.word2index[v] for v in en[6:]] +
                [self.word2index["<EOS>"], ]
            )
        self.input, self.target = np.array(self.input), np.array(self.target)

    def __len__(self):
        return len(self.input)

    def __getitem__(self, index):
        return self.input[index], self.target[index], len(self.target[index])

    @property
    def num_word(self):
        return len(self.vocab)

# Training
n_epochs = 100
batch_size = 32
hidden_size = 128
learning_rate = 0.001

dataset = DateDataset(1000)  # Example size
dataloader = DataLoader(dataset, batch_size=batch_size, shuffle=True, drop_last=True)
encoder = EncoderRNN(dataset.num_word, hidden_size)
decoder = AttentionDecoderRNN(hidden_size, dataset.num_word)
encoder_optimizer = optim.Adam(encoder.parameters(), lr=learning_rate)
decoder_optimizer = optim.Adam(decoder.parameters(), lr=learning_rate)
criterion = nn.NLLLoss()

for i in range(n_epochs + 1):
    total_loss = 0
    for input_tensor, target_tensor, target_length in dataloader:
        encoder_optimizer.zero_grad()
        decoder_optimizer.zero_grad()
        encoder_outputs, encoder_hidden = encoder(input_tensor)
        decoder_outputs, _, _ = decoder(encoder_outputs, encoder_hidden, target_tensor)
        loss = criterion(
            decoder_outputs.view(-1, decoder_outputs.size(-1)),
            target_tensor.view(-1).long()
        )
        loss.backward()
        encoder_optimizer.step()
        decoder_optimizer.step()
        total_loss += loss.item()
    total_loss /= len(dataloader)
    if i % 10 == 0:
        print(f"epoch: {i}, loss: {total_loss}")

# Evaluation
def evaluate(encoder, decoder, x):
    encoder.eval()
    decoder.eval()
    
    # Ensure input is in tensor form and matches batch size
    x = th.tensor(np.array([x]))  # Convert input to a batch of size 1
    encoder_outputs, encoder_hidden = encoder(x)
    
    # Correctly initialize the decoder input for a batch size of 1
    decoder_input = th.ones(x.shape[0], 1).long().fill_(SOS_token)  # [batch_size, 1]
    
    decoder_hidden = encoder_hidden
    decoder_outputs = []
    
    # Generate output step-by-step
    for _ in range(MAX_LENGTH):
        decoder_output, decoder_hidden, _ = decoder.forward_step(decoder_input, decoder_hidden, encoder_outputs)
        decoder_outputs.append(decoder_output)
        
        # Use the model's own output as the next input
        _, topi = decoder_output.topk(1)
        decoder_input = topi.squeeze(-1).detach()
    
    decoder_outputs = th.cat(decoder_outputs, dim=1)
    _, topi = decoder_outputs.topk(1)
    
    # Decode the output words
    decoded_ids = topi.squeeze()
    decoded_words = []
    for idx in decoded_ids:
        decoded_words.append(dataset.index2word[idx.item()])
    
    return ''.join(decoded_words)



for i in range(5):
    predict = evaluate(encoder, decoder, dataset[i][0])
    print(f"input: {dataset.date_cn[i]}, target: {dataset.date_en[i]}, predict: {predict}")

输出结果
epoch: 0, loss: 1.974310448092799
epoch: 10, loss: 0.010178287904108725
epoch: 20, loss: 0.002612524500657474
epoch: 30, loss: 0.001208579239074982
epoch: 40, loss: 0.0007198411941287979
epoch: 50, loss: 0.0022603232458594347
epoch: 60, loss: 0.00045849111460660014
epoch: 70, loss: 0.0002735930226457816
epoch: 80, loss: 0.00019530811668148324
epoch: 90, loss: 0.00014774623512846206
epoch: 100, loss: 0.00011550318477900638
input: 85-08-18, target: 18/Aug/1985, predict: 18/Aug/1985
input: 23-04-25, target: 25/Apr/2023, predict: 25/Apr/2023
input: 19-07-27, target: 27/Jul/2019, predict: 27/Jul/2019
input: 97-06-11, target: 11/Jun/1997, predict: 11/Jun/1997
input: 66-06-16, target: 16/Jun/1966, predict: 16/Jun/1966

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

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

相关文章

Linux常见指令、ls、pwd、cd、touch、mkdir、rmdir、rm等的介绍

文章目录 前言一、ls二、pwd三、cd四、touch五、 mkdir六、rmdir七、rm总结 前言 Linux常见指令、ls、pwd、cd、touch、mkdir、rmdir、rm等的介绍 一、ls 列出该目录下的所有子目录与文件。对于文件&#xff0c;将列出文件名以及其他信息 -a 列出目录下的所有文件&#xff0c;…

蓝鹏测控更换新滑台供应商,实现数据平稳性显著提升

近日&#xff0c;蓝鹏测控技术有限公司宣布了一项重要的供应链优化举措——成功更换了其核心设备——滑台的供应商。这一变革不仅优化了公司的生产流程&#xff0c;还显著提升了产品的数据平稳性&#xff0c;达到了惊人的5%提升&#xff0c;标志着蓝鹏测控在提升产品质量与性能…

代码随想录算法训练营第五十三天 | 110.字符串接龙 ,105.有向图的完全可达性 ,106.岛屿的周长

目录 110.字符串接龙 思路 方法一&#xff1a; 广搜 105.有向图的完全可达性 思路 1.确认递归函数&#xff0c;参数 2.确认终止条件 3.处理目前搜索节点出发的路径 方法一&#xff1a;广搜 106.岛屿的周长 思路 解法一&#xff1a; 解法二&#xff1a; 方法一 …

Python | Leetcode Python题解之第398题随机数索引

题目&#xff1a; 题解&#xff1a; class Solution:def __init__(self, nums: List[int]):self.nums numsdef pick(self, target: int) -> int:ans cnt 0for i, num in enumerate(self.nums):if num target:cnt 1 # 第 cnt 次遇到 targetif randrange(cnt) 0:ans …

15 三数之和

解题思路&#xff1a; \qquad 要找到所有和为0的三元组&#xff0c;使用暴力去解的话时间复杂度为 O ( N 3 ) O(N^3) O(N3)&#xff0c;但是这样会超时。若三数之和为0&#xff0c;那么只要知道其中的两个&#xff0c;就可以知道第三个数的值。进而可以想到用map这样的数据结…

Patch 35586779: WLS PATCH SET UPDATE 10.3.6.0.231017

以上补丁请自行去oracle官网下载&#xff0c;需要技术支持的请联系&#xff1a;https://item.taobao.com/item.htm?spm2013.1.w4023-17257245948.4.19611db9bzrKBx&id608692494369

C语言 | Leetcode C语言题解之第397题整数替换

题目&#xff1a; 题解&#xff1a; //第一种动态规划:超时 // class Solution { // public: // int integerReplacement(int n) { // vector<int>dp(n1,0); // dp[1]0; // for(int i2;i<n;i){ // if(i%20){ // …

Ubuntu查看系统用户信息

0 Preface/Foreword 1 查看方式 1.1 查看系统用户 getent passwd getent: Get entries for Name Service Switch Libraries. 该命令会列出系统上所有用户的详细信息&#xff0c;包括用户名、密码、用户ID&#xff08;UID&#xff09;、组ID&#xff08;GID&#xff09;、用户描…

Python用MarkovRNN马尔可夫递归神经网络建模序列数据t-SNE可视化研究

原文链接&#xff1a;https://tecdat.cn/?p37634 本文聚焦于利用马尔可夫递归神经网络&#xff08;MarkovRNN&#xff09;结合树库展开建模工作。MarkovRNN 通过整合马尔可夫特性与离散随机变量来深入探索递归神经网络中的随机转换机制&#xff0c;旨在高效处理具有复杂潜在信…

轻量级模型解读——GhostNet系列

GhostNet由华为诺亚方舟实验室于2019年11月底提出&#xff0c;投稿于cvpr2020&#xff0c;后面2022年&#xff0c;2024年相继提出更新版本GhostNetv2和GhostNetv3。 它们参数量、复杂度及ImageNet的top1结果对比情况如下&#xff1a; 文章目录 1、GhostNetv11.1 Ghost Module1…

如何阅读李冬梅老师《数据结构》

根据《如何阅读一本书》第五章&#xff1a;主动阅读的基础&#xff1a;阅读者要提出的4个基本问题&#xff1f; 以第2章&#xff0c;线性表为例&#xff1a; &#xff08;1&#xff09;本章主要在谈些什么&#xff1f;例如第二章简介&#xff0c;读完这一章可以自己试着写个简…

基于STM32设计的18650锂电池电量(电压/电流)检测系统——采用电阻分压法、均值滤波及ADC测量—文末工程资料下载

基于STM32设计的锂电池电量&#xff08;电压/电流&#xff09;检测 前言&#xff1a;使用STM32F103C8T6的ADC&#xff0c;和电阻分压法及均值滤波来测量18650锂电池的电压&#xff0c;并在OLED显示屏上显示电池电压值&#xff0c;求出电池电压值即求出电池的电流值和电量值。本…

数据库系统概论笔记(持续更新)

一、概念 1、数据 数据库中存储的基本对象。 2、数据库 定义&#xff1a;长期存储在计算机内、有组织、可共享的大量数据的集合。 3、数据库管理系统 定义&#xff1a;是位于用户与操作系统之间的一层数据管理软件。 主要功能&#xff1a; 1&#xff09; 数据定义功能 …

C++ | Leetcode C++题解之第395题至少有K个重复字符的最长子串

题目&#xff1a; 题解&#xff1a; class Solution { public:int longestSubstring(string s, int k) {int ret 0;int n s.length();for (int t 1; t < 26; t) {int l 0, r 0;vector<int> cnt(26, 0);int tot 0;int less 0;while (r < n) {cnt[s[r] - a];…

QStackedWidget类的使用

本文介绍QStackedWidget类的使用。 StackedWidget控件在Qt应用程序开发过程中用的还是比较多的&#xff0c;配合按钮可以实现多个页面之间相互切换&#xff0c;方便了应用程序的开发&#xff0c;本文简要介绍QStackedWidget类实际使用过程中的常用方法&#xff0c;并给出一个简…

Matlab -- meshgrid和peaks的用法

最近在看到关于三维路径规划方面中&#xff0c;提到使用了样条插值的方法&#xff0c;其中提到了meshgrid和peaks。也查阅了相关资料&#xff0c;现将查阅的资料整理如下。 1 meshgrid函数 该函数是网格采样点的函数。 主要使用的函数为[X,Y]meshgrid(xgv,ygv); meshgrid函数…

华为OD机试真题 - 矩阵匹配 - 深度优先搜索DFS(Python/JS/C/C++ 2024 D卷 200分)

华为OD机试 2024E卷题库疯狂收录中&#xff0c;刷题点这里 专栏导读 本专栏收录于《华为OD机试真题&#xff08;Python/JS/C/C&#xff09;》。 刷的越多&#xff0c;抽中的概率越大&#xff0c;私信哪吒&#xff0c;备注华为OD&#xff0c;加入华为OD刷题交流群&#xff0c;…

华为OD机试 - 跳房子I(Java 2024 E卷 100分)

华为OD机试 2024E卷题库疯狂收录中&#xff0c;刷题点这里 专栏导读 本专栏收录于《华为OD机试&#xff08;JAVA&#xff09;真题&#xff08;E卷D卷A卷B卷C卷&#xff09;》。 刷的越多&#xff0c;抽中的概率越大&#xff0c;私信哪吒&#xff0c;备注华为OD&#xff0c;加…

高效驱动之选 ——KP85211ASGA 半桥栅极驱动器 内置互锁死区

KP85211A是一款 225V 耐压&#xff0c;具有 1A 拉电流和 1.5A 灌电流能力的半桥栅极驱动器&#xff0c;专用于驱动功率MOSFET或IGBT。采用高压器件工艺技术&#xff0c;具有良好的电流输出及出色的抗瞬态干扰能力。可保证开关节点 VS 瞬态 -7V 情况下系统正常工作。可支持开关节…

SpringBoot自定义启动器(自定义Starter)

一、如何理解 SpringBoot 的 starter 机制 Spring Boot 的 Starter 机制是其简化开发流程的关键特性之一。通过提供 预配置的依赖项 和 自动配置 支持&#xff0c;这一机制极大地简化了项目的依赖管理和配置工作&#xff0c;使得开发者可以更快地搭建应用程序框架&#xff0c;…