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

server/2024/10/19 23:39:48/

文章目录

  • 参考书《多模态大模型:算法、应用与微调》
  • 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_sizeself.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_hiddendecoder_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_hiddendef 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_hiddendecoder_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, attentionsdef 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_tokenself.word2index["<EOS>"] = EOS_tokenself.word2index["<PAD>"] = PAD_tokenself.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])@propertydef num_word(self):return len(self.vocab)# Training
n_epochs = 100
batch_size = 32
hidden_size = 128
learning_rate = 0.001dataset = 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 = 0for 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 sizex = th.tensor(np.array([x]))  # Convert input to a batch of size 1encoder_outputs, encoder_hidden = encoder(x)# Correctly initialize the decoder input for a batch size of 1decoder_input = th.ones(x.shape[0], 1).long().fill_(SOS_token)  # [batch_size, 1]decoder_hidden = encoder_hiddendecoder_outputs = []# Generate output step-by-stepfor _ 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 wordsdecoded_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.ppmy.cn/server/113579.html

相关文章

tabBar设置底部菜单选项以及iconfont图标

tabBartabBar属性:设置底部 tab 的表现 ​ ​ ​ ​ 首先在pages.json页面写一个tabBar对象,里面放入list对象数组,里面至少要有2个、最多5个 tab, 如果只有一个tab的话,H5(浏览器)依然可以显示底部有一个导航栏,如果没有,需要重启后才有,小程序则报错,只有2个以上才可以…

【网络】HTTP协议

目录 一、知识星球 1.URL 2.urlencode和urldecode 二、HTTP的请求与响应 1.HTTP协议格式 2.HTTP的方法 3.HTTP状态码 4.HTTP性质 在我们之前写过的服务端和客户端&#xff0c;两者进行通信时&#xff0c;理论上来讲&#xff0c;我们只需要拿着服务端的ip地址和端口号…

C#/.NET/.NET Core推荐学习路线文档文章

前言 专门为C#/.NET/.NET Core推荐学习路线&文档&文章提供的一个Issues&#xff0c;各位小伙伴可以把自己觉得不错的学习路线、文档、文章相关地址分享出来&#x1f91e;。 https://github.com/YSGStudyHards/DotNetGuide/issues/10 &#x1f3f7;️C#/.NET/.NET Cor…

单点登录:cas单点登录实现原理浅析

cas单点登录实现原理浅析 一晃几个月没写博客了&#xff0c;今年多灾多难的一年。 安能摧眉折腰事权贵&#xff0c;使我不得开心颜&#xff01; 财富是对认知的补偿&#xff0c;不是对勤奋的嘉奖。勤奋只能解决温饱&#xff0c;要挣到钱就得预知风口&#xff0c;或者有独到见解…

Python利用pyecharts实现数据可视化

小编会持续更新知识笔记&#xff0c;如果感兴趣可以三连支持。闲来无事&#xff0c;水文一篇&#xff0c;不过上手实践一下倒还是挺好玩的&#xff0c;这一块知识说不定以后真可以尝试拿来做数据库的报表显示。 有梦别怕苦&#xff0c;想赢别喊累。 目录 前言 JSON数据格式的…

【python计算机视觉编程——7.图像搜索】

python计算机视觉编程——7.图像搜索 7.图像搜索7.1 基于内容的图像检索&#xff08;CBIR&#xff09;从文本挖掘中获取灵感——矢量空间模型&#xff08;BOW表示模型&#xff09;7.2 视觉单词**思想****特征提取**&#xff1a; 创建词汇7.3 图像索引7.3.1 建立数据库7.3.2 添加…

iOS18 beta版本怎么回退至iOS17正式版本?

截止目前&#xff0c;苹果最近的iOS18的beta测试版本已经发了8版了&#xff0c;有许多朋友们都已升级提前尝鲜了&#xff0c;升级体验后许多果粉朋友们觉得有许多功能还是不够稳定&#xff0c;有些许bug&#xff0c;就想要降级&#xff0c;回退到iOS17的正式版&#xff0c;但又…

CSDN文章无水印转成PDF

文章目录 一、打开检查二、点击进入控制台三、在控制台中输入代码 一、打开检查 f11或者右键打开检查 二、点击进入控制台 三、在控制台中输入代码 (function(){ use strict;var articleBox $("div.article_content");articleBox.removeAttr("style&quo…