NLP深度学习 DAY5:Seq2Seq 模型详解

Seq2Seq(Sequence-to-Sequence)模型是一种用于处理输入和输出均为序列任务的深度学习模型。它最初被设计用于机器翻译,但后来广泛应用于其他任务,如文本摘要、对话系统、语音识别、问答系统等。


核心思想

Seq2Seq 模型的目标是将一个序列(如一句话)转换为另一个序列,例如:

  • 输入:英文句子 "Hello, how are you?"

  • 输出:法语句子 "Bonjour, comment ça va ?"


模型结构

Seq2Seq 模型通常由两部分组成:

  1. 编码器(Encoder)

    • 将输入序列(如源语言句子)编码为一个固定长度的上下文向量(Context Vector),用于捕捉输入序列的语义信息。

    • 常用循环神经网络(RNN、LSTM、GRU)或 Transformer 作为编码器。

  2. 解码器(Decoder)

    • 基于编码器生成的上下文向量,逐步生成输出序列(如目标语言句子)。

    • 解码器通常也是一个循环神经网络(或 Transformer),每一步生成一个输出词,直到生成结束符(如 <EOS>)。

首先,来简单介绍下RNN(循环神经网络)结构:

1. RNN 简介

                                                                RNN结构  

RNN中,每个单元接受两个输入,一个是当前时间步输入的信息 X_{t} ,另一个是上一个单元的隐藏层状态 H_{t-1}。为什么这种结构的RNN适合用于做文本等序列型数据的任务,主要是因为隐藏状态的存在使得模型具有记忆性。针对不同的任务,根据输入和输出的数量,通常对RNN结构进行调整。

RNN的常见几种结构

1.1 N to N

该模型处理的一般是输入和输出序列长度相等的任务,如

  • 词性标注
  • 语言模型(Language Modeling)

1.2 1 to N

此类结构的输入长度为1,输出长度为N,一般又可以分为两种:一种是将输入只输入到第一个神经元,另一种将输入输入到所有神经元。

一般用于以下任务:

图像生成文字,一般输入 X 为图片,输出为一段图片描述性的文字;
输入音乐类别,生成对应的音乐
根据小说(新闻情感)类别,生成对应的文字

1.3 N to 1

和1 to N相反,一般常见任务有:

  • 序列分类任务,如给定一段文本或语音序列,归类(情感分类,主题分类等)

2. Seq2Seq 模型

经过上面对几种RNN结构的分析,不难发现RNN结构大多对序列的长度比较局限,对于类似于机器翻译的任务,输入和输出长度并不对等,为N to M的结构,简单的RNN束手无策,因此便有了新的模型,Encoder-Decoder模型,也就是Seq2Seq模型。

模型一般由两部分组成:第一部分是Encoder部分,用于对输入的N长度的序列进行表征;第二部分是Decoder部分,用于将Encoder提取出的表征建立起到输出的M长度序列的映射。

2.1 编码器 Encoder 

 

Encoder部分一般使用了普通RNN的结构。其将一个序列表征为一个定长的上下文向量c,计算方式有多种,如下:

2.2 解码器 Decoder

相对于编码器而言,解码器的结构更多,下面介绍三种:

第一种

这种结构直接Encoder得到的上下文向量作为RNN的初始隐藏状态输入到RNN结构中,后续单元不接受 c 的输入,计算公式如下:

  • 隐藏状态的更新:

                                                      

   

 第二种

第二种将Encoder得到的上下文向量作为每个神经单元的输入,不再是只作为第一个单元的初始隐藏状态。计算公式如下:

第三种

第三种在 c 的处理上和第二种类似,但是区别在于将前一个神经单元的输出作为当前神经单元的输出。计算公式如下:

3. Seq2Seq中的Trick

3.1 Teacher Forcing

主要针对第三种Decoder应用。当某一个单元输出出错时,如果将其输出传递给下一个单元,可能导致错误传递下去。这时候,需要在一定程度上减少这种传递,就采用按一定的比例决定是否对神经单元采用上一个上一个单元的输出作为输入。即:

3.2 Attention 机制(很重要)

提出Attention机制之前,我们先来看下之前的结构有什么问题:

核心问题是当序列过长时,上述的Encoder输出的上下文向量 c 无法记住所有信息,会出现长序列梯度消失的问题。比如句子有100个词,那么c里面可能丢失了前几个词的信息。

Attention 机制是怎样的?

Attention 机制其实是参考了人在翻译文章时候的注意力机制,它会将模型的注意力放在当前翻译的单词上,换句话说,它并不像前面提到的Encoder的结构一样对整个句子用一个表征,它对于每个单词都有一个以单词为中心的表征。Encoder结构如下:

 

3.3 束搜索(Beam Search)

注意:Beam Search只用于测试,不用于训练过程。
当模型训练好后,给其输入一段话,其输出的每个单元的 y 给的是各个词的概率,我们如何根据概率选词且如何判断是否句子终止呢?

采取的方法是在每个时间步,选取当前时间步条件概率最大的k个词,作为该时间步的候选输出序列。如下图,k选择2,第一步p(A|c)和p(C|c)最大;第二步 P(AB|c),P(CE|c)最大;第三步P(ABD|c),P(CED|c)最大。

这样,得到的最终候选序列就是各个时间步的得到的序列的集合,下图种即为6个 {A, C, AB, CE, ABD, CED}。那么最终预测结果就是要从这6个中选出分最高的。 

这时候,可能有小伙伴会发现,那按概率算的话,序列越长的概率肯定越小呀,所以一般最后分数计算会有一个和序列长度有关的惩罚系数,如下: 

其中L为候选序列的长度,α 一般选0.75. 这样一来,序列长的对应的系数更小,而由于取了对数,概率的对数是负数,如此变化后会使得长序列和短序列处于一个可比的情形。 

4. 详细代码对比(RNN VS Seq2Seq)

4.1 基础 RNN 示例(以文本分类为例)

4.1.1 模型结构

  • 输入:一个批次的句子(或序列),已被转化为数字索引表示(如词向量)。
  • RNN:使用 nn.RNN  来提取序列特征。
  • 输出:可以是序列最后一个时间步(或平均池化后的序列向量)接一个线性层,最终输出分类结果。
import torch
import torch.nn as nnclass BasicOnlyRNNModel(nn.Module):def __init__(self, vocab_size, embedding_dim, hidden_dim, output_dim,num_layers=1, bidirectional=False):super(BasicOnlyRNNModel, self).__init__()# 词向量层self.embedding = nn.Embedding(vocab_size, embedding_dim)# 仅使用RNNself.rnn = nn.RNN(input_size=embedding_dim, hidden_size=hidden_dim, num_layers=num_layers,batch_first=True,bidirectional=bidirectional)# 双向时需要 *2self.num_directions = 2 if bidirectional else 1rnn_output_dim = hidden_dim * self.num_directions# 全连接层, 用于将 RNN 的输出映射到分类空间self.fc = nn.Linear(rnn_output_dim, output_dim)def forward(self, text):"""text: [batch_size, seq_len]"""# 嵌入: [batch_size, seq_len] -> [batch_size, seq_len, embedding_dim]embedded = self.embedding(text)# 前向传播 RNN# rnn_out: [batch_size, seq_len, hidden_dim * num_directions]# hidden : [num_layers * num_directions, batch_size, hidden_dim]rnn_out, hidden = self.rnn(embedded)  # 取最后一层的 hidden state# hidden 的形状: [num_layers * num_directions, batch_size, hidden_dim]# 若是单向 RNN,hidden[-1] 即可# 若是双向 RNN,需拼接正向和反向最后时刻if self.num_directions == 1:out = hidden[-1, :, :]  # [batch_size, hidden_dim]else:# 对双向的情况,hidden[-2] 与 hidden[-1] 分别是正向/反向最后时刻out = torch.cat((hidden[-2, :, :], hidden[-1, :, :]), dim=1)# [batch_size, hidden_dim * 2]# 全连接映射至分类空间logits = self.fc(out)  # [batch_size, output_dim]return logits# ================ 以下是训练/推理时的简单示例 ================
if __name__ == "__main__":# 假设我们有一些超参数vocab_size = 10000      # 词典大小embedding_dim = 128     # 词向量维度hidden_dim = 256        # RNN 隐藏层维度output_dim = 2          # 假设做二分类num_layers = 1          # RNN 层数bidirectional = True    # 是否使用双向model = BasicOnlyRNNModel(vocab_size=vocab_size,embedding_dim=embedding_dim,hidden_dim=hidden_dim,output_dim=output_dim,num_layers=num_layers,bidirectional=bidirectional)# 假设当前批次的输入batch_size = 32seq_len = 50batch_text = torch.randint(0, vocab_size, (batch_size, seq_len))  # [batch_size, seq_len]# 前向传播logits = model(batch_text)  # 形状: [32, 2]print(logits.shape)  # 输出: torch.Size([32, 2])
基础 RNN 模型特点
  1. 数据流:输入序列 → 嵌入层 → RNN → 最后一层 hidden state → 全连接层 → 输出。
  2. 应用场景:常用于序列分类/回归(文本分类、情感分析、序列标注等)。
  3. 优点:结构简单,实现快速。
  4. 缺点:对长序列依赖可能不够,若需要输出一个序列(而不是一个标量或一个向量),就需要进一步改造或循环解码。

二、Seq2Seq 示例(以机器翻译为例)

对于Seq2Seq模型,一般包含 Encoder(编码器)Decoder(解码器)两个主要部分(可选地加入Attention机制)。下文示例使用 LSTM 结构,演示最基础的编码器-解码器形式(不带注意力机制)。带注意力的情况会多一步 Attention 计算。

1. Encoder(编码器)

import torch
import torch.nn as nnclass Encoder(nn.Module):def __init__(self, vocab_size, embedding_dim, hidden_dim, num_layers=1):super(Encoder, self).__init__()self.hidden_dim = hidden_dimself.num_layers = num_layersself.embedding = nn.Embedding(vocab_size, embedding_dim)self.lstm = nn.LSTM(embedding_dim, hidden_dim, num_layers, batch_first=True)def forward(self, src):"""src: [batch_size, src_len]"""embedded = self.embedding(src)  # [batch_size, src_len, embedding_dim]outputs, (hidden, cell) = self.lstm(embedded)# outputs: [batch_size, src_len, hidden_dim]# hidden: [num_layers, batch_size, hidden_dim]# cell:   [num_layers, batch_size, hidden_dim]return hidden, cell

2. Decoder(解码器)

class Decoder(nn.Module):def __init__(self, vocab_size, embedding_dim, hidden_dim, num_layers=1):super(Decoder, self).__init__()self.hidden_dim = hidden_dimself.num_layers = num_layersself.embedding = nn.Embedding(vocab_size, embedding_dim)self.lstm = nn.LSTM(embedding_dim, hidden_dim, num_layers, batch_first=True)self.fc_out = nn.Linear(hidden_dim, vocab_size)  # 输出到词表大小def forward(self, tgt, hidden, cell):"""tgt: [batch_size] 当前时间步解码器输入(可以是一个词或一批词)hidden, cell: 编码器传过来的(或者上一时间步传下来的)隐状态"""# 解码器一般一次输入一个token,也可以批量处理多个# 这里假设 tgt 形状是 [batch_size],先unsqueeze到[batch_size, 1]tgt = tgt.unsqueeze(1)  # [batch_size, 1]embedded = self.embedding(tgt)  # [batch_size, 1, embedding_dim]output, (hidden, cell) = self.lstm(embedded, (hidden, cell))# output: [batch_size, 1, hidden_dim]prediction = self.fc_out(output.squeeze(1))  # [batch_size, vocab_size]return prediction, hidden, cell

3. Seq2Seq 整合 

class Seq2Seq(nn.Module):def __init__(self, encoder, decoder, device):super(Seq2Seq, self).__init__()self.encoder = encoderself.decoder = decoderself.device = devicedef forward(self, src, tgt, teacher_forcing_ratio=0.5):"""src: [batch_size, src_len]tgt: [batch_size, tgt_len] 训练时通常会有“开始标志 <sos>”和“结束标志 <eos>”。teacher_forcing_ratio: float,表示在训练时使用老师强制的概率"""batch_size = src.shape[0]tgt_len = tgt.shape[1]vocab_size = self.decoder.fc_out.out_features# 用于存储解码器每个时间步的输出词分布outputs = torch.zeros(batch_size, tgt_len, vocab_size).to(self.device)# 1. 编码器对源序列进行编码,获取初始 hidden, cellhidden, cell = self.encoder(src)# 2. 解码器的第一个输入通常是 <sos>input_t = tgt[:, 0]  # 取第0个词(即<sos>)for t in range(1, tgt_len):# 2.1 将当前时间步的 token 喂给 Decoderoutput, hidden, cell = self.decoder(input_t, hidden, cell)# output 形状: [batch_size, vocab_size]# 2.2 存储outputs[:, t, :] = output# 2.3 决定下一时间步输入:是用模型自己的预测还是用老师的标签(teacher forcing)teacher_force = torch.rand(1).item() < teacher_forcing_ratiotop1 = output.argmax(1)  # [batch_size], 最大值所对应的词索引input_t = tgt[:, t] if teacher_force else top1return outputs
Seq2Seq 模型特点
  1. 整体结构:输入序列先经过 Encoder 编码,将序列信息“压缩”到 hidden, cell(或 h_n, c_n),再在解码阶段通过 Decoder 逐步解码出目标序列。
  2. 输出:是一个序列而非一个标量/向量,通过循环或一步步地喂入上一步的输出(或真实标签)来生成。
  3. 扩展:在解码阶段可加入 Attention(Luong/Bahdanau 等),或者进一步用 Transformer 替代 RNN,形成更强大的序列到序列生成模型。
  4. 应用场景:机器翻译、文本摘要、对话系统、序列到序列的生成任务(如代码自动生成、语音到文本等)。

三、RNN VS Seq2Seq(回答问题:为什么要有编码器?直接把词向量拼在一起,然后用 RNN 1 to N 不行吗?)

在序列到序列(Seq2Seq)任务中(如机器翻译、文本摘要等),直接使用RNN后通过全连接层输出(1 to N)看似简单,但存在以下关键问题,而编码器-解码器(Encoder-Decoder)结构通过分步编码和解码的方式有效解决了这些挑战:

在序列到序列(Seq2Seq)任务中(如机器翻译、文本摘要等),直接使用词嵌入后通过全连接层(“M个神经元”)输出看似简单,但存在以下关键问题,而编码器-解码器(Encoder-Decoder)结构通过分步编码和解码的方式有效解决了这些挑战:


1. 序列的时序依赖性

自然语言中的单词顺序至关重要。例如:

  • 句子1猫追老鼠

  • 句子2老鼠追猫
    两个句子包含相同的词,但含义完全相反。

  • 简单词嵌入+全连接的缺陷
    若直接将所有词嵌入拼接成一个向量(如[猫, 追, 老鼠] → 一个长向量),模型会丢失词序信息,无法区分两个句子的差异。

  • 编码器-解码器的优势
    通过LSTM或Transformer按顺序处理输入词,编码器能够保留词序信息,并在隐藏状态中传递时序依赖关系。


2. 输入和输出的变长问题

在Seq2Seq任务中,输入和输出的长度通常是动态变化的。例如:

  • 输入:英文句子 "Hello world"(2个词)

  • 输出:中文翻译 "你好世界"(3个词)

  • 简单词嵌入+全连接的缺陷
    全连接层需要固定维度的输入和输出,无法处理变长序列。

  • 编码器-解码器的优势

    • 编码器可处理任意长度的输入序列,将其压缩为固定长度的上下文向量(hiddencell)。

    • 解码器基于上下文向量逐步生成变长的输出序列(逐词生成,直到预测到<eos>)。


3. 长距离依赖建模

语言中常存在跨越多个单词的依赖关系。例如:

  • 句子The cat, which was hungry and had been wandering the streets for days, finally found some food.
    主句的主语cat与谓语found相隔很远。

  • 简单词嵌入+全连接的缺陷
    全连接层难以捕捉长距离依赖(尤其是当句子较长时)。

  • 编码器-解码器的优势

    • LSTM通过门控机制(遗忘门、输入门)逐步更新cell状态,传递长期信息。

    • Transformer通过自注意力机制(Self-Attention)直接建模词与词之间的全局依赖。


4. 信息压缩与语义表示

编码器的核心作用是将输入序列编码为一个全局语义表示(上下文向量)。

  • 简单词嵌入+全连接的缺陷
    直接将所有词嵌入拼接为一个向量,缺乏对整体语义的抽象(相当于“词袋模型”)。

  • 编码器-解码器的优势

    • 编码器通过循环或注意力机制逐步融合上下文信息,生成紧凑的语义表示。

    • 解码器基于此表示逐步展开生成目标序列,确保输出与输入语义一致。


5. 模型效率与参数共享

  • 简单词嵌入+全连接的缺陷
    若输入长度为N,输出长度为M,全连接层的参数量为 (N×embedding_dim) × M,随序列长度增长迅速膨胀,导致计算成本高且易过拟合。

  • 编码器-解码器的优势

    • LSTM或Transformer通过参数共享(同一层处理所有时间步),参数量仅与隐藏层维度相关,与序列长度无关。

    • 例如,LSTM的参数量为 4×(embedding_dim + hidden_dim)×hidden_dim,与输入长度N无关。


6. 实际案例对比

假设用两种模型处理机器翻译任务:

方案1:简单全连接
  • 输入:将源句子所有词嵌入拼接为一个向量(如N=5embedding_dim=256 → 输入维度1280)。

  • 输出:直接映射到目标语言的词表(如vocab_size=10000),参数量为 1280×10000 = 12.8M

  • 问题

    • 无法处理长度变化的输入输出。

    • 无法建模词序和长距离依赖。

    • 参数量大且难以训练。

方案2:编码器-解码器(LSTM)
  • 编码器:LSTM逐步处理源序列,输出上下文向量(如hidden_dim=256)。

  • 解码器:LSTM基于上下文向量逐词生成目标序列。

  • 参数量:编码器和解码器的LSTM参数量均为 4×(256+256)×256 ≈ 1M,总计约2M

  • 优势

    • 处理变长序列。

    • 建模词序和长距离依赖。

    • 参数量小且高效。


总结

编码器-解码器结构通过分步编码和解码,解决了以下核心问题:

  1. 时序依赖性:保留词序信息。

  2. 变长序列处理:动态生成输出。

  3. 长距离依赖建模:通过LSTM或注意力机制捕捉全局关系。

  4. 语义压缩与传递:生成紧凑的上下文表示。

  5. 模型效率:参数共享降低计算成本。

直接使用词嵌入+全连接的方案虽然在理论上可行,但无法满足实际任务的需求。编码器-解码器及其改进模型(如Transformer)已成为序列建模的主流方法,广泛应用于机器翻译、对话系统、文本生成等任务。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

数据结构 队列

目录 前言 一&#xff0c;队列的基本知识 二&#xff0c;用数组实现队列 三&#xff0c;用链表实现队列 总结 前言 接下来我们将学习队列的知识&#xff0c;这会让我们了解队列的基本概念和基本的功能 一&#xff0c;队列的基本知识 (Queue) 我们先来研究队列的ADT&#xff0c…

Git 版本控制:基础介绍与常用操作

目录 Git 的基本概念 Git 安装与配置 Git 常用命令与操作 1. 初始化本地仓库 2. 版本控制工作流程 3. 分支管理 4. 解决冲突 5. 回退和撤销 6. 查看提交日志 前言 在软件开发过程中&#xff0c;开发者常常需要在现有程序的基础上进行修改和扩展。但如果不加以管理&am…

Java 大视界 -- Java 大数据在量子通信安全中的应用探索(69)

&#x1f496;亲爱的朋友们&#xff0c;热烈欢迎来到 青云交的博客&#xff01;能与诸位在此相逢&#xff0c;我倍感荣幸。在这飞速更迭的时代&#xff0c;我们都渴望一方心灵净土&#xff0c;而 我的博客 正是这样温暖的所在。这里为你呈上趣味与实用兼具的知识&#xff0c;也…

国产碳化硅(SiC)MOSFET模块在电镀电源中全面取代进口IGBT模块

国产碳化硅&#xff08;SiC&#xff09;MOSFET模块在电镀电源中全面取代进口IGBT模块&#xff0c;倾佳电子杨茜分析以下几方面的技术、经济和政策优势&#xff1a; 倾佳电子杨茜致力于推动SiC碳化硅模块在电力电子应用中全面取代IGBT模块&#xff0c;助力电力电子行业自主可控…

linux用户管理

创建用户&#xff1a;useradd &#xff08;创建用户命令的详细使用&#xff1a;如何创建用户-CSDN博客&#xff09; &#xff08;如何创建具有重复uid的用户&#xff1a;如何创建具有重复uid的用户-CSDN博客&#xff09; 删除用户&#xff1a;userdel &#xff08;删除用户命…

【C++动态规划 离散化】1626. 无矛盾的最佳球队|2027

本文涉及知识点 C动态规划 离散化 LeetCode1626. 无矛盾的最佳球队 假设你是球队的经理。对于即将到来的锦标赛&#xff0c;你想组合一支总体得分最高的球队。球队的得分是球队中所有球员的分数 总和 。 然而&#xff0c;球队中的矛盾会限制球员的发挥&#xff0c;所以必须选…

【安全测试】测开方向学习遇到的问题记录

【问题一】springboot如何访问静态资源文件 springboot启动根路径位置 F:\untitled05\demo4\src\main\resources\static 例如图片位置存放在F:\untitled05\demo4\src\main\resources\static即可 配置文件配置 spring.web.resources.static-locationsfile:/F:/untitled05/de…

Github 2025-01-25Rust开源项目日报Top10

根据Github Trendings的统计,今日(2025-01-25统计)共有10个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量Rust项目10Python项目1Vue项目1JavaScript项目1Deno: 现代JavaScript和TypeScript运行时 创建周期:2118 天开发语言:Rust, JavaScript协议类型…

详细解释java当中的所有知识点(前言及数据类型及变量)(第一部分)

会将java当中的所有的知识点以及相关的题目进行分享&#xff0c;这是其中的第一部分&#xff0c;用红色字体标注出重点&#xff0c;以及加粗的方式进行提醒 目录 一、Java语言概述 1.Java语言简介 2.语言优势 二、main方法 1.Java程序结构组成 2.运行Java程序 3.注释 4.…

HarmonyOS应用开发快速入门

本节内容将帮助开发者学习如何构建一个全新的HarmonyOS应用&#xff0c;学习使用DevEco Studio创建新项目、使用预览器预览页面、了解基础组件如Image、Text等。 文章目录 一、介绍二、创建一个新项目三、页面结构总览四、自定义文本视图五、创建Image组件 一、介绍 根据本教程…

ICSE‘25 LLM Assistance for Memory Safety

不知道从什么时候开始&#xff0c;各大技术社区&#xff0c;技术群聊流行着 “用Rust重写!” &#xff0c;放一张图(笑死… 这不, 随着大模型技术的流行&#xff0c;大家都在探索如何让大模型自动完成仓库级别(全程序)的代码重构&#xff0c;代码变换&#xff08;Refactor&…

Java实现.env文件读取敏感数据

文章目录 1.common-env-starter模块1.目录结构2.DotenvEnvironmentPostProcessor.java 在${xxx}解析之前执行&#xff0c;提前读取配置3.EnvProperties.java 这里的path只是为了代码提示4.EnvAutoConfiguration.java Env模块自动配置类5.spring.factories 自动配置和注册Enviro…

基于Python的人工智能患者风险评估预测模型构建与应用研究(下)

3.3 模型选择与训练 3.3.1 常见预测模型介绍 在构建患者风险评估模型时,选择合适的预测模型至关重要。不同的模型具有各自的优缺点和适用场景,需要根据医疗数据的特点、风险评估的目标以及计算资源等因素进行综合考虑。以下详细介绍几种常见的预测模型。 逻辑回归(Logisti…

零基础Vue入门4——Vue3基础核心

本节重点&#xff1a; vue3最佳实践 ref reactive computed watch、watchEffect 讲解重点之后下面会带大家开发一个页面&#xff08;表单表格&#xff09;&#xff0c;之后会有一个TodoList的小练习&#xff0c;文末附有小练习的代码参考。跟着练习一定带你可以上手开发vu…

一文掌握ADB的安装及使用

文章目录 一、什么是ADB&#xff1f;二、 安装ADB2.1 下载ADB2.2 配置环境变量 三、连接Android设备四、 常用ADB命令五、ADB高级功能5.1 屏幕截图和录制5.2 模拟按键输入5.3 文件管理5.4 系统设置管理5.5 系统操作指令5.6 日志操作指令5.7 APK操作指令5.8 设备重启和恢复 六、…

使用Edu邮箱申请一年免费的.me域名

所需材料&#xff1a;公立Edu教育邮箱一枚&#xff08;P.S&#xff1a;该服务不支持所有的Edu教育邮箱&#xff0c;仅支持比较知名的院校&#xff09; 说到域名&#xff0c;.me这个后缀可谓是个性十足&#xff0c;适合个人网站、博客等。.me是黑山的国家顶级域名&#xff08;c…

7.抽象工厂(Abstract Factory)

抽象工厂与工厂方法极其类似&#xff0c;都是绕开new的&#xff0c;但是有些许不同。 动机 在软件系统中&#xff0c;经常面临着“一系列相互依赖的对象”的创建工作&#xff1b;同时&#xff0c;由于需求的变化&#xff0c;往往存在更多系列对象的创建工作。 假设案例 假设…

Visual Studio使用GitHub Copilot提高.NET开发工作效率

GitHub Copilot介绍 GitHub Copilot 是一款 AI 编码助手&#xff0c;可帮助你更快、更省力地编写代码&#xff0c;从而将更多精力集中在问题解决和协作上。 GitHub Copilot Free包含哪些功能&#xff1f; 每月 2000 代码补全&#xff0c;帮助开发者快速完成代码编写。 每月 …

[JavaWeb]搜索表单区域

一.注意事项 设置外边距:margin:(参数可省去部分)上 下 左 右 二.源代码 <!DOCTYPE html> <html lang"zh-CN"> <head> <meta charset"UTF-8"> <title>Tlias智能学习辅助系统</title> <style> /* 导航栏样…

NLP自然语言处理通识

目录 ELMO 一、ELMo的核心设计理念 1. 静态词向量的局限性 2. 动态上下文嵌入的核心思想 3. 层次化特征提取 二、ELMo的模型结构与技术逻辑 1. 双向语言模型&#xff08;BiLM&#xff09; 2. 多层LSTM的层次化表示 三、ELMo的运行过程 1. 预训练阶段 2. 下游任务微调 四、ELMo的…