NLP从零开始------16.文本中阶处理之序列到序列模型(1)

1. 序列到序列模型简介

        序列到序列( sequence to sequence, seq2seq) 是指输入和输出各为一个序列(如一句话) 的任务。本节将输入序列称作源序列,输出序列称作目标序列。序列到序列有非常多的重要应用, 其中最有名的是机器翻译( machine translation), 机器翻译模型的输入是待翻译语言(源语言) 的文本,输出则是翻译后的语言(目标语言) 的文本。

        此外, 序列到序列的应用还有: 改写( paraphrase), 即将输入文本保留原意, 用意思相近的词进行重写; 风格迁移( style transfer), 即转换输入文本的风格(如口语转书面语、负面评价改为正面评价、现代文改为文言文等); 文本摘要( summarization), 即将较长的文本总结为简短精练的短文本; 问答( question answering), 即为用户输入的问题提供回答;对话( dialog),即对用户的输入进行回应。这些都是自然语言处理中非常重要的任务。另外,还有许多任务,尽管它们并非典型的序列到序列任务,但也可以使用序列到序列的方法解决,例如后面章节将要提到的命名实体识别任务,即识别输入句子中的人名、地名等实体,既可以使用后面章节将要介绍的序列标注方法来解决,也可以使用序列到序列方法解决,举例如下:

        源序列: 小红在上海旅游。

        目标序列:[小红|人名]在[上海|地名]旅游。

        类似地,后续章节将要介绍的成分句法分析( constituency parsing)、语义角色标注( semantic role labeling, SRL)、共指消解( coreference resolution) 等任务也都可以使用序列到序列的方法解决。值得一提的是,虽然前面提到的这些任务可以利用序列到序列的方式解决,但是许多情况下效果不如其最常用的方式(如利用序列标注方法解决命名实体识别)。
        对于像机器翻译这一类经典的序列到序列任务,采用基于神经网络的方法具有非常大的优势。在早期的相关研究被提出后不久,基于神经网络序列到序列的机器翻译模型效果就迅速提升并超过了更为传统的统计机器翻译模型,成为主流的机器翻译方案。因此,本节主要介绍基于神经网络的序列到序列方法,包括模型、学习和解码。随后介绍序列到序列模型中常用的指针网络与拷贝机制。最后介绍序列到序列任务的一些延伸和扩展。

2. 基于神经网络的序列到序列模型

        序列到序列模型与上个章节介绍的语言模型十分类似,都需要在已有文字序列的基础上预测下一个词的概率分布。其区别是,语言模型只需建模一个序列, 而序列到序列模型需要建模两个序列,因此需要包含两个模块:一个编码器用于处理源序列,一个解码器用于生成目标序列。本小节将依次介绍基于循环神经网络、注意力机制以及 Transformer的序列到序列模型。

2.1 循环神经网络

        如下图所示, 基于循环神经网络(包括长短期记忆等变体)的序列到序列模型与前几个章节介绍的循环神经网络非常相似,但是按输入不同分成了编码器、解码器两部分, 其中编码器依次接收源序列的词,但不计算任何输出。编码器最后一步的隐状态成为解码器的初始隐状态,这个隐状态向量有时称作上下文向量( context vector),它编码了整个源序列的信息。解码器在第一步接收特殊符号“< sos>”作为目标序列的起始符, 并预测第一个词的概率分布,从中解码出第一个词(解码方法将在下面讨论);随后将第一个词作为下一步的输入, 继续解码第二个词,以此类推, 直到最后解码出终止符“< oos>”,意味着目标序列已解码完毕。这种方式即前面所介绍的自回归过程。

        下面介绍基于循环神经网络的编码器和解码器的代码实现。首先是作为编码器的循环神经网络。

python">import torch
import torch.nn as nnclass RNNEncoder(nn.Module):def __init__(self, vocab_size, hidden_size):super(RNNEncoder, self).__init__()# 隐层大小self.hidden_size = hidden_size# 词表大小self.vocab_size = vocab_size# 词嵌入层self.embedding = nn.Embedding(self.vocab_size,\self.hidden_size)self.gru = nn.GRU(self.hidden_size, self.hidden_size,\batch_first=True)def forward(self, inputs):# inputs: batch * seq_len# 注意门控循环单元使用batch_first=True,因此输入需要至少batch为1features = self.embedding(inputs)output, hidden = self.gru(features)return output, hidden

         接下来是作为解码器的另一个循环神经网络的代码实现。

python">class RNNDecoder(nn.Module):def __init__(self, vocab_size, hidden_size):super(RNNDecoder, self).__init__()self.hidden_size = hidden_sizeself.vocab_size = vocab_size# 序列到序列任务并不限制编码器和解码器输入同一种语言,# 因此解码器也需要定义一个嵌入层self.embedding = nn.Embedding(self.vocab_size, self.hidden_size)self.gru = nn.GRU(self.hidden_size, self.hidden_size,\batch_first=True)# 用于将输出的隐状态映射为词表上的分布self.linear = nn.Linear(self.hidden_size, self.vocab_size)# 解码整个序列def forward(self, encoder_outputs, encoder_hidden, target_tensor=None):batch_size = encoder_outputs.size(0)# 从<sos>开始解码decoder_input = torch.empty(batch_size, 1,\dtype=torch.long).fill_(SOS_token)decoder_hidden = encoder_hiddendecoder_outputs = []# 如果目标序列确定,最大解码步数确定;# 如果目标序列不确定,解码到最大长度if target_tensor is not None:seq_length = target_tensor.size(1)else:seq_length = MAX_LENGTH# 进行seq_length次解码for i in range(seq_length):# 每次输入一个词和一个隐状态decoder_output, decoder_hidden = self.forward_step(\decoder_input, decoder_hidden)decoder_outputs.append(decoder_output)if target_tensor is not None:# teacher forcing: 使用真实目标序列作为下一步的输入decoder_input = target_tensor[:, i].unsqueeze(1)else:# 从当前步的输出概率分布中选取概率最大的预测结果# 作为下一步的输入_, topi = decoder_output.topk(1)# 使用detach从当前计算图中分离,避免回传梯度decoder_input = topi.squeeze(-1).detach()decoder_outputs = torch.cat(decoder_outputs, dim=1)decoder_outputs = F.log_softmax(decoder_outputs, dim=-1)# 为了与AttnRNNDecoder接口保持统一,最后输出Nonereturn decoder_outputs, decoder_hidden, None# 解码一步def forward_step(self, input, hidden):output = self.embedding(input)output = F.relu(output)output, hidden = self.gru(output, hidden)output = self.out(output)return output, hidden

        

2.2 注意力机制

        在序列到序列循环神经网络上加入注意力机制的方式同样与上一章节介绍的方式非常相似,区别在于,注意力机制在这里仅用于解码时建模从目标序列到源序列的依赖关系。具体而言,在解码的每一步,将解码器输出的隐状态特征作为查询,将编码器计算的源序列中每个元素的隐状态特征作为键和值,从而计算注意力输出向量; 这个输出向量会与解码器当前步骤的隐状态特征一起用于预测目标序列的下一个元素。
        序列到序列中的注意力机制使得解码器能够直接“看到”源序列,而不再仅依赖循环神经网络的隐状态传递源序列的信息。此外,注意力机制提供了一种类似于人类处理此类任务时的序列到序列机制。人类在进行像翻译这样的序列到序列任务时,常常会边看源句边进行翻译,而不是一次性读完源句之后记住它再翻译, 而注意力机制模仿了这个过程。最后,注意力机制为序列到序列模型提供了一些可解释性: 通过观察注意力分布,可以知道解码器生成每个词时在注意源句中的哪些词,这可以看作源句和目标句之间的一种“软性”对齐。
        下面介绍基于注意力机制的循环神经网络解码器的代码实现。我们使用一个注意力层来计算注意力权重,其输入为解码器的输入和隐状态。这里使用 Bahdanau注意力( Bahdanau attention) , 这是序列到序列模型中应用最广泛的注意力机制,特别是对于机器翻译任务。该注意力机制使用一个对齐模型( alignment model) 来计算编码器和解码器隐状态之间的注意力分数,具体来讲就是一个前馈神经网络。相比于点乘注意力, Bahdanau注意力利用了非线性变换。

python">import torch.nn.functional as Fclass BahdanauAttention(nn.Module):def __init__(self, hidden_size):super(BahdanauAttention, 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):# query: batch * 1 * hidden_size# keys: batch * seq_length * hidden_size# 这一步用到了广播(broadcast)机制scores = self.Va(torch.tanh(self.Wa(query) + self.Ua(keys)))scores = scores.squeeze(2).unsqueeze(1)weights = F.softmax(scores, dim=-1)context = torch.bmm(weights, keys)return context, weightsclass AttnRNNDecoder(nn.Module):def __init__(self, vocab_size, hidden_size):super(AttnRNNDecoder, self).__init__()self.hidden_size = hidden_sizeself.vocab_size = vocab_sizeself.embedding = nn.Embedding(self.vocab_size, self.hidden_size)self.attention = BahdanauAttention(hidden_size)# 输入来自解码器输入和上下文向量,因此输入大小为2 * hidden_sizeself.gru = nn.GRU(2 * self.hidden_size, self.hidden_size,\batch_first=True)# 用于将注意力的结果映射为词表上的分布self.out = nn.Linear(self.hidden_size, self.vocab_size)# 解码整个序列def forward(self, encoder_outputs, encoder_hidden, target_tensor=None):batch_size = encoder_outputs.size(0)# 从<sos>开始解码decoder_input = torch.empty(batch_size, 1, dtype=\torch.long).fill_(SOS_token)decoder_hidden = encoder_hiddendecoder_outputs = []attentions = []# 如果目标序列确定,最大解码步数确定;# 如果目标序列不确定,解码到最大长度if target_tensor is not None:seq_length = target_tensor.size(1)else:seq_length = MAX_LENGTH# 进行seq_length次解码for i in range(seq_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:# teacher forcing: 使用真实目标序列作为下一步的输入decoder_input = target_tensor[:, i].unsqueeze(1)else:# 从当前步的输出概率分布中选取概率最大的预测结果# 作为下一步的输入_, topi = decoder_output.topk(1)# 使用detach从当前计算图中分离,避免回传梯度decoder_input = topi.squeeze(-1).detach()decoder_outputs = torch.cat(decoder_outputs, dim=1)decoder_outputs = F.log_softmax(decoder_outputs, dim=-1)attentions = torch.cat(attentions, dim=1)# 与RNNDecoder接口保持统一,最后输出注意力权重return decoder_outputs, decoder_hidden, attentions# 解码一步def forward_step(self, input, hidden, encoder_outputs):embeded =  self.embedding(input)# 输出的隐状态为1 * batch * hidden_size,# 注意力的输入需要batch * 1 * hidden_sizequery = hidden.permute(1, 0, 2)context, attn_weights = self.attention(query, encoder_outputs)input_gru = torch.cat((embeded, context), dim=2)# 输入的隐状态需要1 * batch * hidden_sizeoutput, hidden = self.gru(input_gru, hidden)output = self.out(output)return output, hidden, attn_weights

2.3 Transformer

        Transformer模型同样也可以用于序列到序列任务。编码器与上一章介绍的 Transformer结构几乎相同,仅有两方面区别。一方面,由于不需要像语言模型那样每一步只能看到前置序列,而是需要看到完整的句子, 因此掩码多头自注意力模块中去除了注意力掩码。另一方面,由于编码器不需要输出,因此去掉了顶层的线性分类器。
        解码器同样与上一章介绍的 Transformer结构几乎相同,但在掩码多头自注意力模块之后增加了一个交叉多头注意力模块,以便在解码时引入编码器所计算的源序列的信息。交叉注意力模块的设计与上面介绍的循环神经网络上的注意力机制是类似的。具体而言,交叉注意力模块使用解码器中自注意力模块的输出计算查询,使用编码器顶端的输出计算键和值,不使用任何注意力掩码, 其他部分与自注意力模块一样。

        基于 Transformer的序列到序列模型通常也使用自回归的方式进行解码, 但 Transformer不同位置之间的并行性,使得非自回归方式的解码成为可能。非自回归解码器的结构与自回归解码器类似,但解码时需要先预测目标句的长度,将该长度对应个数的特殊符号作为输入,此外自注意力模块不需要掩码,所有位置的计算并行执行。有关具体细节这里不再展开。

        接下来我们复用上一章的代码,实现基于 Transformer的编码器和解码器。

python">import torch
import torch.nn as nn
import torch.nn.functional as F
import numpy as np
import sys
sys.path.append('./code')
from transformer import *class TransformerEncoder(nn.Module):def __init__(self, vocab_size, max_len, hidden_size, num_heads,\dropout, intermediate_size):super().__init__()self.embedding_layer = EmbeddingLayer(vocab_size, max_len,\hidden_size)# 直接使用TransformerLayer作为编码层,简单起见只使用一层self.layer = TransformerLayer(hidden_size, num_heads,\dropout, intermediate_size)# 与TransformerLM不同,编码器不需要线性层用于输出def forward(self, input_ids):# 这里实现的forward()函数一次只能处理一句话,# 如果想要支持批次运算,需要根据输入序列的长度返回隐状态assert input_ids.ndim == 2 and input_ids.size(0) == 1seq_len = input_ids.size(1)assert seq_len <= self.embedding_layer.max_len# 1 * seq_lenpos_ids = torch.unsqueeze(torch.arange(seq_len), dim=0)attention_mask = torch.ones((1, seq_len), dtype=torch.int32)input_states = self.embedding_layer(input_ids, pos_ids)hidden_states = self.layer(input_states, attention_mask)return hidden_states, attention_mask
python">class MultiHeadCrossAttention(MultiHeadSelfAttention):def forward(self, tgt, tgt_mask, src, src_mask):"""tgt: query, batch_size * tgt_seq_len * hidden_sizetgt_mask: batch_size * tgt_seq_lensrc: keys/values, batch_size * src_seq_len * hidden_sizesrc_mask: batch_size * src_seq_len"""# (batch_size * num_heads) * seq_len * (hidden_size / num_heads)queries = self.transpose_qkv(self.W_q(tgt))keys = self.transpose_qkv(self.W_k(src))values = self.transpose_qkv(self.W_v(src))# 这一步与自注意力不同,计算交叉掩码# batch_size * tgt_seq_len * src_seq_lenattention_mask = tgt_mask.unsqueeze(2) * src_mask.unsqueeze(1)# 重复张量的元素,用以支持多个注意力头的运算# (batch_size * num_heads) * tgt_seq_len * src_seq_lenattention_mask = torch.repeat_interleave(attention_mask,\repeats=self.num_heads, dim=0)# (batch_size * num_heads) * tgt_seq_len * \# (hidden_size / num_heads)output = self.attention(queries, keys, values, attention_mask)# batch * tgt_seq_len * hidden_sizeoutput_concat = self.transpose_output(output)return self.W_o(output_concat)# TransformerDecoderLayer比TransformerLayer多了交叉多头注意力
class TransformerDecoderLayer(nn.Module):def __init__(self, hidden_size, num_heads, dropout,\intermediate_size):super().__init__()self.self_attention = MultiHeadSelfAttention(hidden_size,\num_heads, dropout)self.add_norm1 = AddNorm(hidden_size, dropout)self.enc_attention = MultiHeadCrossAttention(hidden_size,\num_heads, dropout)self.add_norm2 = AddNorm(hidden_size, dropout)self.fnn = PositionWiseFNN(hidden_size, intermediate_size)self.add_norm3 = AddNorm(hidden_size, dropout)def forward(self, src_states, src_mask, tgt_states, tgt_mask):# 掩码多头自注意力tgt = self.add_norm1(tgt_states, self.self_attention(\tgt_states, tgt_states, tgt_states, tgt_mask))# 交叉多头自注意力tgt = self.add_norm2(tgt, self.enc_attention(tgt,\tgt_mask, src_states, src_mask))# 前馈神经网络return self.add_norm3(tgt, self.fnn(tgt))class TransformerDecoder(nn.Module):def __init__(self, vocab_size, max_len, hidden_size, num_heads,\dropout, intermediate_size):super().__init__()self.embedding_layer = EmbeddingLayer(vocab_size, max_len,\hidden_size)# 简单起见只使用一层self.layer = TransformerDecoderLayer(hidden_size, num_heads,\dropout, intermediate_size)# 解码器与TransformerLM一样,需要输出层self.output_layer = nn.Linear(hidden_size, vocab_size)def forward(self, src_states, src_mask, tgt_tensor=None):# 确保一次只输入一句话,形状为1 * seq_len * hidden_sizeassert src_states.ndim == 3 and src_states.size(0) == 1if tgt_tensor is not None:# 确保一次只输入一句话,形状为1 * seq_lenassert tgt_tensor.ndim == 2 and tgt_tensor.size(0) == 1seq_len = tgt_tensor.size(1)assert seq_len <= self.embedding_layer.max_lenelse:seq_len = self.embedding_layer.max_lendecoder_input = torch.empty(1, 1, dtype=torch.long).\fill_(SOS_token)decoder_outputs = []for i in range(seq_len):decoder_output = self.forward_step(decoder_input,\src_mask, src_states)decoder_outputs.append(decoder_output)if tgt_tensor is not None:# teacher forcing: 使用真实目标序列作为下一步的输入decoder_input = torch.cat((decoder_input,\tgt_tensor[:, i:i+1]), 1)else:# 从当前步的输出概率分布中选取概率最大的预测结果# 作为下一步的输入_, topi = decoder_output.topk(1)# 使用detach从当前计算图中分离,避免回传梯度decoder_input = torch.cat((decoder_input,\topi.squeeze(-1).detach()), 1)decoder_outputs = torch.cat(decoder_outputs, dim=1)decoder_outputs = F.log_softmax(decoder_outputs, dim=-1)# 与RNNDecoder接口保持统一return decoder_outputs, None, None# 解码一步,与RNNDecoder接口略有不同,RNNDecoder一次输入# 一个隐状态和一个词,输出一个分布、一个隐状态# TransformerDecoder不需要输入隐状态,# 输入整个目标端历史输入序列,输出一个分布,不输出隐状态def forward_step(self, tgt_inputs, src_mask, src_states):seq_len = tgt_inputs.size(1)# 1 * seq_lenpos_ids = torch.unsqueeze(torch.arange(seq_len), dim=0)tgt_mask = torch.ones((1, seq_len), dtype=torch.int32)tgt_states = self.embedding_layer(tgt_inputs, pos_ids)hidden_states = self.layer(src_states, src_mask, tgt_states,\tgt_mask)output = self.output_layer(hidden_states[:, -1:, :])return output

http://www.ppmy.cn/news/1519171.html

相关文章

Mysql性能优化之自适应索引

自适应索引 是什么 自适应哈希索引是 InnoDB 存储引擎为了提高特定类型查询性能而自动构建的一种内存中的哈希索引结构。它可以根据查询模式和数据访问频率自动调整&#xff0c;以优化数据库的性能。 与BTree的区别 与传统的 B-tree 索引不同&#xff0c;哈希索引使用哈希函…

wordpress安装完访问时提示“不安全”

当WordPress安装完访问时浏览器提示“不安全”&#xff0c;可能的原因和解决方法如下&#xff1a; 未启用SSL证书&#xff1a; 如果你的网站没有启用SSL证书&#xff0c;浏览器会将其标记为不安全。可以通过安装SSL证书来解决这个问题。 安装并启用Really Simple SSL插件也是…

[001-07-001].Redis中的BigKey使用分析

1、常见面试题&#xff1a; 1.阿里的广告平台&#xff0c;海量数据里面查询某一固定前缀的key2.小红书&#xff0c;如何在生产限制keys*/flushdb/flushall等危险命令以防止误删除误使用3.美团&#xff0c;MEMORU USAGE命令你使用过吗4.Bikey问题&#xff0c;多大算big&#xf…

数据结构:单向链表

目录 结构体 创建链表 插入链表 头插法 尾插法 遍历打印 更新链表指定节点 查找链表指定节点 删除链表指定节点 销毁链表 找到元素中间位置 找到链表倒数第k个节点 链表元素倒置 链表元素排序 冒泡排序 选择排序 链表 1.空间可以不连续&#xff0c;访问元素不…

日常积累史2

2024.08.27 1.每行固定只显示2个元素-css 方案1&#xff1a; .container1 {display: grid;grid-template-columns: repeat(2, 1fr); /* 设置两列&#xff0c;每列宽度相等 */ } .item1 {background: #0b9f00; }方案2&#xff1a; .container2 {display: flex;flex-wrap: wrap…

split对大文件(tar/tar.gz)文件进行分片及合并

文章目录 1、tar文件指定大小分片2、合并分片文件并解压 1、tar文件指定大小分片 split -b 4000M -d -a 3 cm-11.tar.gz cm-11.tar.gz.使用split命令&#xff0c;-b 4000M 表示设置每个分割包的大小&#xff0c;单位还是可以k -d "参数指定生成的分割包后缀为数字的形式 …

Django REST Framework(十九)权限

Django REST framework (DRF) 的权限认证涉及以下几个方面&#xff1a;全局权限配置、局部权限配置、自定义权限类、以及自定义认证类。以下是关于这些方面的详细说明&#xff1a; 1. 全局权限配置 在 Django 项目的配置文件 settings.py 中&#xff0c;可以全局配置 DRF 的权…

B+树的原理及实现

B树的原理及实现 一、引言 B树是一种基于B树的树形数据结构&#xff0c;它在数据库和文件系统的索引中有着广泛的应用。与B树相比&#xff0c;B树的所有数据记录都存储在叶节点上&#xff0c;并且增加了顺序访问的能力&#xff0c;这使得B树在处理大量数据时更加高效。 二、…

Python 爬虫爬取京东商品信息

Python 爬虫爬取京东商品信息 下面我将逐一解释每一部分的代码 导入库 from selenium import webdriver from selenium.webdriver.edge.service import Service from selenium.webdriver.edge.options import Options import time import random import csv from selenium.co…

学习大数据DAY43 Sqoop 安装,配置环境和使用

目录 sqoop 安装 配置 mysql sqoop 安装 sqoop 指令集 sqoop 使用 sqoop 创建 hive 表 sqoop 全量导入表 sqoop 增量导入表 sqoop 全量导出表 sqoop 分区表导入表 sqoop 分区表导出表 上机练习 sqoop 安装 配置 mysql create database test DEFAULT CHARACTER S…

农产品智慧物流系统论文

摘 要 互联网发展至今&#xff0c;无论是其理论还是技术都已经成熟&#xff0c;而且它广泛参与在社会中的方方面面。它让信息都可以通过网络传播&#xff0c;搭配信息管理工具可以很好地为人们提供服务。针对信息管理混乱&#xff0c;出错率高&#xff0c;信息安全性差&#x…

python 实现一个简单的网页爬虫程序

最近在学习python&#xff0c;以下为网页爬虫代码&#xff0c;供参考 1、爬取指定网页的标题和所有的连接 2、并将这些信息保存到一个文件中。 前置&#xff1a;因使用到网页相关的功能&#xff0c;故需导入requests、BeautifulSoup 库来完成 #导入网页相关的库 import requ…

干货分享|分享一款高效的软件卸载神器 Geek Uninstaller

问题&#xff1a;卸载软件时&#xff0c;时常会留下残留文件和注册表。当遇到流氓软件&#xff0c;还常常卸载失败。 1.软件介绍 特点&#xff1a;高效快速&#xff0c;小巧便携。100% 免费 2.下载方法 官方下载网站&#xff1a;Geek Uninstaller - the best FREE uninstaller …

中锂天源锂电池:为卡车驻车空调提供高效、安全、持久的能源解决方案

随着我国运输行业的飞速发展&#xff0c;卡车司机对驾驶环境和行车舒适度的要求越来越高。在炎炎夏日或寒冷冬季&#xff0c;驻车空调已成为卡车司机的必需品。然而&#xff0c;传统驻车空调供电方式存在诸多问题&#xff0c;如电力不足、续航时间短等。为解决这一痛点&#xf…

Unet改进17:添加ShuffleAttention||减少冗余计算和同时存储访问

本文内容:在不同位置添加ShuffleAttention注意力机制 目录 论文简介 1.步骤一 2.步骤二 3.步骤三 4.步骤四 论文简介 注意机制使神经网络能够准确地关注输入的所有相关元素,已成为提高深度神经网络性能的重要组成部分。在计算机视觉研究中广泛应用的注意机制主要有空间注…

ElasticSearch7.12.1详细安装

部署ElasticSearch docker安装 因为我们还需要部署kibana容器&#xff0c;因此需要让es和kibana容器互联。这里先创建一个网络 创建网络 docker network create es-net 查看网络列表 docker network ls 获取镜像包 docker pull elasticsearch:7.12.1 运行 docker run -d \ -…

【扩散模型(七)】IP-Adapter 与 IP-Adapter Plus 的具体区别是什么?

系列文章目录 【扩散模型&#xff08;二&#xff09;】IP-Adapter 从条件分支的视角&#xff0c;快速理解相关的可控生成研究【扩散模型&#xff08;三&#xff09;】IP-Adapter 源码详解1-训练输入 介绍了训练代码中的 image prompt 的输入部分&#xff0c;即 img projection…

EXO:模型最终验证的地方;infer_tensor;step;MLXDynamicShardInferenceEngine

目录 EXO:模型最终验证的地方 EXO:infer_tensor EXO:step MXNet的 mx.array 类型是什么 NDArray优化了什么 1. 异步计算和内存优化 2. 高效的数学和线性代数运算 3. 稀疏数据支持 4. 自动化求导 举例说明 EXO:模型最终验证的地方 EXO:infer_tensor 这段代码定…

MariaDB 和 MySQL 版本关联

MariaDB 和 MySQL 是两个常用的关系型数据库管理系统&#xff08;RDBMS&#xff09;&#xff0c;它们在很多方面非常相似&#xff0c;因为 MariaDB 是 MySQL 的一个分支。MariaDB 和 MySQL 之间的版本关联可以通过以下几个方面来理解&#xff1a; 1. 历史背景 MySQL: MySQL 是…

数学建模强化宝典(1)级比检验

前言 级比检验是灰色预测中一个重要的步骤&#xff0c;主要用于判断原始数据是否满足准指数规律&#xff0c;从而确定数据是否适合进行灰色预测分析。 一、级比检验的定义 级比检验是通过计算原始数据与其前一期数据的比值&#xff08;即级比&#xff09;&#xff0c;并对级比进…