循环神经网络模块介绍(Pytorch 12)

到目前为止,我们遇到过两种类型的数据:表格数据和图像数据。对于图像数据,我们设计了专门的卷积神经网络架构(cnn)来为这类特殊的数据结构建模。换句话说,如果我们拥有一张图像,我们 需要有效地利用其像素位置,假若我们对图像中的像素位置进行重排,就会对图像中内容的推断造成极大的困难。

最重要的是,到目前为止我们默认数据都来自于某种分布,并且 所有样本都是独立同分布 的(independently and identically distributed)。然而,大多数的数据并非如此。例如,文章中的单词是按顺序写的,如 果顺序被随机地重排,就很难理解文章原始的意思。同样,视频中的图像帧、对话中的音频信号以及网站上 的浏览行为都是有顺序的。因此,针对此类数据而设计特定模型,可能效果会更好。 另一个问题来自这样一个事实:我们不仅仅可以接收一个序列作为输入,而是还可能期望继续猜测这个序列的后续。例如,一个任务可以是继续预测2, 4, 6, 8, 10, . . .。这在时间序列分析中是相当常见的,可以用来预测 股市的波动、患者的体温曲线或者赛车所需的加速度。同理,我们需要能够处理这些数据的特定模型。

简言之,如果说 卷积神经网络可以有效地处理空间信息,那么本章的循环神经网络(recurrent neural network, RNN)则可以更好地处理序列信息。循环神经网络通过引入状态变量存储过去的信息和当前的输入,从而可 以确定当前的输出。 许多使用循环网络的例子都是基于文本数据的,因此我们将在本章中重点介绍语言模型。在对序列数据进行 更详细的回顾之后,我们将介绍文本预处理的实用技术。然后,我们将讨论语言模型的基本概念,并将此讨论作为循环神经网络设计的灵感。

一 序列模型

处理序列数据需要统计工具和新的深度神经网络架构。

1.1 自回归模型

以 预测股票价格为例。

为了实现这个预测,交易员可以使用回归模型。仅有一个主要问题:输入数据的 数量,输入xt−1, . . . , x1本身因t而异。也就是说,输入数据的数量这个数字将会随着我们遇到的数据量的增加 而增加,因此需要一个近似方法来使这个计算变得容易处理。本章后面的大部分内容将围绕着如何有效估计 P(xt | xt−1, . . . , x1)展开。简单地说,它归结为以下两种策略。

第一种策略,假设在现实情况下相当长的序列 xt−1, . . . , x1可能是不必要的,因此我们只需要满足某个长度 为τ的时间跨度,即使用观测序列xt−1, . . . , xt−τ。当下获得的最直接的好处就是参数的数量总是不变的,至少 在t > τ时如此,这就使我们能够训练一个上面提及的深度网络。这种模型被称为自回归模型(autoregressive models),因为它们是对自己执行回归。

第二种策略,如 下图所示,是保留一些对过去观测的总结ht,并且同时更新预测xˆt和总结ht。这就产生了 基于xˆt = P(xt | ht)估计xt,以及公式ht = g(ht−1, xt−1)更新的模型。由于ht从未被观测到,这类模型也被称 为 隐变量自回归模型(latent autoregressive models)。

这两种情况都有一个显而易见的问题:如何生成训练数据?一个经典方法是使用历史观测来预测下一个未来观测。显然,我们并不指望时间会停滞不前。然而,一个常见的假设是虽然特定值xt可能会改变,但是序列 本身的动力学不会改变。这样的假设是合理的,因为新的动力学一定受新的数据影响,而我们不可能用目前 所掌握的数据来预测新的动力学。统计学家称 不变的动力学为静止的(stationary)。

注意,如果我们处理的是离散的对象(如单词),而不是连续的数字,则上述的考虑仍然有效。唯一的差别是, 对于离散的对象,我们需要使用分类器而不是回归模型来估计P(xt | xt−1, . . . , x1)。

1.2 马尔可夫模型

回想一下,在自回归模型的近似法中,我们使用xt−1, . . . , xt−τ 而不是xt−1, . . . , x1来估计xt。只要这种是近似精确的,我们就说序列满足马尔可夫条件(Markov condition)。

当假设xt仅是离散值时,这样的模型特别棒,因为在这种情况下,使用动态规划可以沿着马尔可夫链精确地 计算结果

利用这一事实,我们只需要考虑过去观察中的一个非常短的历史:P(xt+1 | xt, xt−1) = P(xt+1 | xt)。隐马尔 可夫模型中的动态规划超出了本节的范围,而动态规划这些计算工具已经在控制算法和强化学习算法广泛使用。

1.3 模型训练

在了解了上述统计工具后,让我们在实践中尝试一下!首先,我们生成一些数据:使用 正弦函数和一些可加 性噪声来生成序列数据,时间步为1, 2, . . . , 1000。

%matplotlib inline
import torch
from torch import nn
from d2l import torch as d2l

T = 1000
time = torch.arange(1, T + 1, dtype=torch.float32)
x = torch.sin(0.01 * time) + torch.normal(0, 0.2, (T,))
d2l.plot(time, [x], 'time', 'x', xlim=[1, 1000], figsize=(6, 3))

接下来,我们将这个序列转换为 模型的特征-标签(feature‐label)对。基于嵌入维度τ,我们将数据映射为 数据对yt = xt 和xt = [xt−τ , . . . , xt−1]。这比我们提供的数据样本少了τ个,因为我们没有足够的历史记录来 描述前τ个数据样本。一个简单的解决办法是:如果拥有足够长的序列就丢弃这几项;另一个方法是用零填 充序列。在这里,我们 仅使用前600个“特征-标签”对 进行 训练

tau = 4
features = torch.zeros((T - tau, tau))
for i in range(tau):
    features[:, i] = x[i: T - tau + i]
labels = x[tau:].reshape((-1, 1))
batch_size, n_train = 16, 600
train_iter = d2l.load_array((features[:n_train], labels[:n_train]),
                           batch_size, is_train=True)

def init_weights(m):
    if type(m) == nn.Linear:
        nn.init.xavier_uniform_(m.weight)
        
def get_net():
    net = nn.Sequential(nn.Linear(4, 10), 
                        nn.ReLU(),
                        nn.Linear(10, 1))
    net.apply(init_weights)
    return net

loss = nn.MSELoss(reduction='none')

def train(net, train_iter, loss, epochs, lr):
    trainer = torch.optim.Adam(net.parameters(), lr)
    for epoch in range(epochs):
        for X, y in train_iter:
            trainer.zero_grad()
            l = loss(net(X), y)
            l.sum().backward()
            trainer.step()
        print(f'epoch:{epoch + 1}, loss:{d2l.evaluate_loss(net, train_iter, loss): f}')
        
net = get_net()
train(net, train_iter, loss, 5, 0.01)

1.4 执行预测

onestep_preds = net(features)
d2l.plot([time, time[tau:]], 
         [x.detach().numpy(), onestep_preds.detach().numpy()], 'time',
         'x', legend=['data', '1-step preds'], 
         xlim = [1, 1000], figsize=(6, 3))

正如我们所料,单步预测效果不错。即使这些预测的时间步超过了600 + 4(n_train + tau),其结果看起来 仍然是可信的。然而有一个小问题:如果数据观察序列的时间步只到604,我们需要一步一步地向前迈进

通常,对于直到xt的观测序列,其在时间步t + k处的预测输出xˆt+k 称为k步预测(k‐step‐ahead‐prediction)。 由于我们的观察已经到了x604,它的k步预测是xˆ604+k。换句话说,我们必须使用我们自己的预测(而不是原 始数据)来进行多步预测。

multistep_preds = torch.zeros(T)
multistep_preds[: n_train + tau] = x[: n_train + tau]
for i in range(n_train + tau, T):
    multistep_preds[i] = net(multistep_preds[i - tau: i].reshape((1, -1)))

d2l.plot([time, time[tau:], time[n_train + tau:]],
         [x.detach().numpy(), onestep_preds.detach().numpy(),
          multistep_preds[n_train + tau:].detach().numpy()], 'time',
         'x', legend=['data', '1-step preds', 'multistep preds'], 
         xlim=[1, 1000], figsize=(6, 3))

如上面的例子所示,绿线的预测显然并不理想。经过几个预测步骤之后,预测的结果很快就会衰减到一个常数。为什么这个算法效果这么差呢?事实是由于错误的累积:假设在步骤1之后,我们积累了一些错误ϵ1 = ¯ϵ。 于是,步骤2的输入被扰动了ϵ1,结果积累的误差是依照次序的ϵ2 = ¯ϵ + cϵ1,其中c为某个常数,后面的预测 误差依此类推。因此误差可能会相当快地偏离真实的观测结果。例如,未来24小时的天气预报往往相当准确, 但超过这一点,精度就会迅速下降

基于k = 1, 4, 16, 64,通过对整个序列预测的计算,让我们更仔细地看一下k步预测的困难。

## 步长使用64做预测
max_steps = 64
features = torch.zeros((T - tau - max_steps + 1, tau + max_steps))
for i in range(tau):
    features[:, i] = x[i: i + T - tau - max_steps + 1]

for i in range(tau, tau + max_steps):
    features[:, i] = net(features[:, i - tau: i]).reshape(-1)

steps = (1, 4, 16, 64)
d2l.plot([time[tau + i - 1: T - max_steps + i] for i in steps],
         [features[:, (tau + i - 1)].detach().numpy() for i in steps], 'time', 'x',
         legend=[f'{i}-step preds' for i in steps], xlim=[5, 1000], 
         figsize=(6, 3))

以上例子清楚地说明了当我们试图预测更远的未来时,预测的质量是如何变化的。虽然“4步预测”看起来仍然不错,但超过这个跨度的任何预测几乎都是无用的

小结:

  • 内插法(在现有观测值之间进行估计)和 外推法(对超出已知观测范围进行预测)在实践的难度上差别很大。因此,对于所拥有的序列数据,在训练时始终要尊重其时间顺序,即最好不要基于未来的数据进 行训练
  • 序列模型的估计需要专门的统计工具,两种较流行的选择是 自回归模型和隐变量自回归模型
  • 对于时间是向前推进的因果模型,正向估计通常比反向估计更容易。
  • 对于直到时间步t的观测序列,其在时间步t + k的预测输出是“k步预测”。随着我们对预测时间k值的 增加,会造成误差的快速累积和预测质量的极速下降。

二 文本预处理

对于 序列数据处理 问题,这样的数据存在许多种形式,文本是最常见例子之一。例如,一篇文章可以被简单地看作一串单词序列,甚至是一串字符序列。我们将解析文本的常见预处理步骤。这些步骤通常包括:

  1. 文本作为字符串加载到内存中。
  2. 将字符串拆分为词元(如单词和字符)。
  3. 建立一个词表,将拆分的词元映射到数字索引。
  4. 将文本转换为数字索引序列,方便模型操作

2.1 读取数据集

首先,我们从H.G.Well的 时光机器 中加载文本。这是一个相当小的语料库,只有 30000多个单词,但足够我 们小试牛刀,而现实中的文档集合可能会包含数十亿个单词。下面的函数将数据集读取到由多条文本行组成 的列表中,其中每条文本行都是一个字符串。为简单起见,我们在这里忽略了标点符号和字母大写

import collections
import re
from d2l import torch as d2l

#@save
d2l.DATA_HUB['time_machine'] = (d2l.DATA_URL + 'timemachine.txt',
                                '090b5e7e70c295757f55df93cb0a180b9691891a')

def read_time_machine():   #@save
    with open(d2l.download('time_machine'), 'r') as f:
        lines = f.readlines()
    return [re.sub('[^A-Za-z]+', ' ', line).strip().lower() for line in lines]

lines = read_time_machine()
print(f'文本总行数:{len(lines)}')
print(lines[0])
print(lines[10])

2.2 词元化

下面的tokenize函数将文本行列表(lines)作为输入,列表中的每个元素是一个文本序列(如一条文本行)。 每个文本序列又被拆分成一个词元列表,词元(token)是文本的基本单位。最后,返回一个由词元列表组成 的列表,其中的每个词元都是一个字符串(string)。

def tokenize(lines, token='word'):   #@save
    if token == 'word':
        return [line.split() for line in lines]
    elif token == 'char':
        return [list(line) for line in lines]
    else:
        print('error: 未知词元类型:' + token)
    
tokens = tokenize(lines)
for i in range(11):
    print(tokens[i])

2.3 词表

词元的类型是字符串,而模型需要的输入是数字,因此这种类型不方便模型使用。现在,让我们构建一个字典,通常也叫做词表(vocabulary),用来将字符串类型的词元映射到从0开始的数字索引中。我们先将训练 集中的所有文档合并在一起,对它们的唯一词元进行统计,得到的统计结果称之为语料(corpus)。然后根 据每个唯一词元的出现频率,为其分配一个数字索引。很少出现的词元通常被移除,这可以降低复杂性。另 外,语料库中不存在或已删除的任何词元都将映射到一个特定的未知词元“”。我们可以选择增加一个 列表,用于保存那些被保留的词元,例如:填充词元(“”);序列开始词元(“”);序列结束词元 (“”)。

class Vocab:   #@save
    def __init__(self, tokens=None, min_freq=0, reserved_tokens=None):
        if tokens is None:
            tokens = []
        if reserved_tokens is None:
            reserved_tokens = []
        counter = count_corpus(tokens)
        self._token_freqs = sorted(counter.items(), key=lambda x: x[1], reverse=True)
        self.idx_to_token = ['<unk>'] + reserved_tokens
        self.token_to_idx = {token: idx for idx, token in enumerate(self.idx_to_token)}
        for token, freq in self._token_freqs:
            if freq < min_freq:
                break
            if token not in self.token_to_idx:
                self.idx_to_token.append(token)
                self.token_to_idx[token] = len(self.idx_to_token) - 1
                
    def __len__(self):
        return len(self.idx_to_token)
    
    def __getitem__(self, tokens):
        if not isinstance(tokens, (list, tuple)):
            return self.token_to_idx.get(tokens, self.unk)
        return [self.__getitem__(token) for token in tokens]
    
    @property
    def unk(self):
        return 0
    
    @property
    def token_freqs(self):
        return self._token_freqs
    
def count_corpus(tokens):  #@save
    if len(tokens) == 0 or isinstance(tokens[0], list):
        tokens = [token for line in tokens for token in line]
    return collections.Counter(tokens)

vocab = Vocab(tokens)
print(list(vocab.token_to_idx.items())[:10])

for i in [0, 10]:
    print('文本:', tokens[i])
    print('索引:', vocab[tokens[i]])

2.4 整合所有功能

在使用上述函数时,我们 将所有功能打包到 load_corpus_time_machine 函数中,该函数返回corpus(词元索 引列表)和vocab(时光机器语料库的词表)。我们在这里所做的改变是:

  1. 为了简化后面章节中的训练,我们使用字符(而不是单词)实现文本词元化
  2. 时光机器数据集中的每个文本行不一定是一个句子或一个段落,还可能是一个单词,因此返回 的corpus仅处理为单个列表,而不是使用多词元列表构成的一个列表。
def load_corpus_time_machine(max_tokens=-1):    #@save
    lines = read_time_machine()
    tokens = tokenize(lines, 'char')
    vocab = Vocab(tokens)
    corpus = [vocab[token] for line in tokens for token in line]
    if max_tokens > 0:
        corpus = corpus[:max_tokens]
    return corpus, vocab

corpus, vocab = load_corpus_time_machine()
len(corpus), len(vocab)   # (170580, 28)

小结:

  • 文本是序列数据 的一种最常见的形式之一。
  • 为了对文本进行预处理,我们 通常将文本拆分为词元,构建词表 将词元字符串映射为数字 索引,并 将文本数据转换为词元 索引以供模型操作。

三 语言模型和数据集

在给定这样的文本序列时,语言模型(language model)的目标是 估计序列的联合概率

为了训练语言模型,我们需要计算单词的概率,以及给定前面几个单词后出现某个单词的条件概率。这些概 率本质上就是语言模型的参数。

这里,我们假设训练数据集是一个大型的文本语料库。比如,维基百科的所有条目、古登堡计划101,或者 所有发布在网络上的文本。训练数据集中词的概率可以根据给定词的相对词频来计算。

一种常见的策略是执行某种形式的 拉普拉斯平滑(Laplace smoothing),具体方法是在所有计数中添加一个 小常量。

3.1 自然语言统计

我们看看在真实数据上如果进行自然语言统计。根据 8.2节中介绍的时光机器数据集构建词表,并打印前10个 最常用的(频率最高的)单词。

import random
import torch
from d2l import torch as d2l

tokens = d2l.tokenize(d2l.read_time_machine())
# 因为每个文本行不一定是一个句子或一个段落,因此我们把所有文本行拼接到一起
corpus = [token for line in tokens for token in line]
vocab = d2l.Vocab(corpus)
vocab.token_freqs[:10]

正如我们所看到的,最流行的词看起来很无聊,这些词通常被称为 停用词(stop words),因此可以被过滤掉。 尽管如此,它们本身仍然是有意义的,我们仍然会在模型中使用它们。

freqs = [freq for token, freq in vocab.token_freqs]
d2l.plot(freqs, xlabel='token: x', ylabel='frequency: n(x)',
         xscale='log', yscale='log')

bigram_tokens = [pair for pair in zip(corpus[:-1], corpus[1:])]
bigram_vocab = d2l.Vocab(bigram_tokens)
bigram_vocab.token_freqs[:10]

trigram_tokens = [triple for triple in zip(corpus[:-2], corpus[1:-1], corpus[2:])]
trigram_vocab = d2l.Vocab(trigram_tokens)
trigram_vocab.token_freqs[:10]

bigram_freqs = [freq for token, freq in bigram_vocab.token_freqs]
trigram_freqs = [freq for token, freq in trigram_vocab.token_freqs]
d2l.plot([freqs, bigram_freqs, trigram_freqs], xlabel='token: x',
         ylabel='frequency: n(x)', xscale='log', yscale='log',
         legend=['unigram', 'bigram', 'trigram'])

小结:

  • 语言模型 是自然语言处理的关键。
  • n元语法 通过截断相关性,为处理长序列提供了一种实用的模型。
  • 长序列存在一个问题:它们很少出现或者从不出现
  • 齐普夫定律 支配着单词的分布,这个分布不仅适用于一元语法,还适用于其他n元语法。
  • 通过 拉普拉斯平滑法 可以有效地处理 结构丰富而频率不足的低频词词组
  • 读取长序列的主要方式是 随机采样和顺序分区。在迭代过程中,后者可以保证来自两个相邻的小批量中的子序列在原始序列上也是相邻的

四 循环神经网络

我们介绍了n元语法模型,其中单词xt在时间步t的条件概率仅取决于前面n − 1个单词。对于时 间步t − (n − 1)之前的单词,如果我们想将其可能产生的影响合并到xt上,需要增加n,然而 模型参数的数量也会随之呈指数增长,因为词表V需要存储|V|n个数字,因此与其将P(xt | xt−1, . . . , xt−n+1)模型化,不如使用 隐变量模型

4.1 无隐状态的神经网络

让我们来看一看只有 单隐藏层的多层感知机。设隐藏层的激活函数为ϕ,给定一个小批量样本X ∈ R n×d,其 中批量大小为n,输入维度为d,则隐藏层的输出H ∈ R n×h通过下式计算。

         H = \varnothing (XW_{xh} + b_h)

4.2 有隐状态的循环神经网络

有了隐状态后,情况就完全不同了。假设我们在时间步t有小批量输入Xt ∈ R n×d。换言之,对于n个序列样本 的小批量,Xt的每一行对应于来自该序列的时间步t处的一个样本。接下来,用Ht ∈ R n×h 表示时间步t的隐 藏变量。与多层感知机不同的是,我们在这里保存了前一个时间步的隐藏变量Ht−1,并引入了一个新的权重 参数Whh ∈ R h×h,来描述如何在当前时间步中使用前一个时间步的隐藏变量。具体地说,当前时间步隐藏 变量由当前时间步的输入与前一个时间步的隐藏变量一起计算得出。

        H_t = \varnothing (X_tW_{xh} + H_{t-1}W_{hh}+ b_h)

比无隐状态相比多添加了一项H_{t-1}W_{hh},从而实例化了。从相邻时间步的隐藏变量Ht和 Ht−1之 间的关系可知,这些变量 捕获并保留了序列直到其当前时间步的历史信息,就如当前时间步下神经网络的状 态或记忆,因此这样的隐藏变量被称为隐状态(hidden state)。由于在当前时间步中,隐状态使用的定义与 前一个时间步中使用的定义相同,因此的计算是循环的(recurrent)。于是基于循环计算的隐状态神 经网络被命名为 循环神经网络(recurrent neural network)。在循环神经网络中执行计算的层称为循环层(recurrent layer)。

import torch
from d2l import torch as d2l

X, W_xh = torch.normal(0, 1, (3, 1)), torch.normal(0, 1, (1, 4))
H, W_hh = torch.normal(0, 1, (3, 4)), torch.normal(0, 1, (4, 4))
torch.matmul(X, W_xh) + torch.matmul(H, W_hh)
# tensor([[ 1.2156,  0.6346, -2.1131, -1.5739],
#         [-1.5890, -0.7256,  1.1961, -0.7566],
#         [-1.9251, -1.0113,  0.1320,  1.8175]])

torch.matmul(torch.cat((X, H), 1), torch.cat((W_xh, W_hh), 0))
# tensor([[-3.8297, -2.1686,  1.9846,  6.5896],
#         [ 3.0873,  4.4307, -1.2372, -2.8524],
#         [ 2.6609,  0.1703, -0.0343, -3.5691]])

小结:

  • 对隐状态使用 循环计算的神经网络称为 循环神经网络(RNN)。
  • 循环神经网络的隐状态 可以捕获直到当前时间步序列 的历史信息。
  • 循环神经网络模型的参数数量不会随着时间步的增加而增加
  • 我们可以使用循环神经网络创建 字符级语言模型
  • 我们可以使用 困惑度 来评价 语言模型的质量。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

专业渗透测试 Phpsploit-Framework(PSF)框架软件小白入门教程(三)

本系列课程&#xff0c;将重点讲解Phpsploit-Framework框架软件的基础使用&#xff01; 本文章仅提供学习&#xff0c;切勿将其用于不法手段&#xff01; 继续接上一篇文章内容&#xff0c;讲述如何进行Phpsploit-Framework软件的基础使用和二次开发。 当我们点击 submit 提…

【JavaEE 初阶(一)】初识线程

❣博主主页: 33的博客❣ ▶️文章专栏分类:JavaEE◀️ &#x1f69a;我的代码仓库: 33的代码仓库&#x1f69a; &#x1faf5;&#x1faf5;&#x1faf5;关注我带你了解更多线程知识 目录 1.前言2.进程3.线程4.线程和进程的区别5.Thread创建线程5.1继承Thread创建线程5.2实现R…

非平衡数据处理-SMOTE Tomek算法(互联网最全)

作者Toby&#xff0c;来源公众号&#xff1a;Python风控模型&#xff0c;非平衡数据处理-SMOTE Tomek算法 之前Toby老师讲了非平衡数据处理相关知识&#xff0c;具体内容和链接如下。 imbalanced data机器学习非平衡数据处理 Python非平衡数据处理_SMOTE-ENN 方法 非平衡数…

【SSM进阶学习系列丨分页篇】PageHelper 分页插件导入集成实践

文章目录 一、说明什么是分页PageHelper介绍 二、导入依赖三、集成Spring框架中四、编写Service五、编写Controller六、编写queryAllByPage页面展示数据 一、说明 什么是分页 ​ 针对分页&#xff0c;使用的是PageHelper分页插件&#xff0c;版本使用的是5.1.8 。 ​ 参考文档…

虚拟机网络实现桥接模式

虚拟机网络实现桥接模式 虚拟化软件&#xff1a;VMware 17 Linux&#xff1a;rocky8_9 主机&#xff1a;Win10 文章目录 虚拟机网络实现桥接模式1. 桥接模式介绍2. 查看Win本机的网络信息&#xff08;以笔记本电脑以WiFi联网为例&#x…

【Canvas与艺术】录王昌龄出塞诗“秦时明月汉时关”

【成图】 【代码】 <!DOCTYPE html> <html lang"utf-8"> <meta http-equiv"Content-Type" content"text/html; charsetutf-8"/> <head><title>使用HTML5/Canvas绘制秦时明月汉时关</title><style type&q…

【论文阅读】Sparse is Enough in Scaling Transformers

Sparse is Enough in Scaling Transformers 论文地址摘要1 介绍2 相关工作模型压缩。模型修剪模型蒸馏。稀疏注意力。张量分解。稀疏前馈。 3 Sparse is Enough3.1 稀疏前馈层3.2 稀疏 QKV 层3.3 稀疏损失层。 4 长序列的稀疏性4.1 长序列架构4.2 内存效率的可逆性4.3 泛化的循…

# 从浅入深 学习 SpringCloud 微服务架构(七)Hystrix(4)

从浅入深 学习 SpringCloud 微服务架构&#xff08;七&#xff09;Hystrix&#xff08;4&#xff09; 一、hystrix&#xff1a;使用 turbine 聚合所有的 hytrix 的监控数据测试。创建父工程 spring_cloud_hystrix_demo&#xff0c;导入相关依赖坐标。并在父工程 spring_cloud_…

C++校招八股

c类的访问权限与继承方式 公有成员在任何地方都可以被访问&#xff0c;包括类的外部和派生类。受保护成员在类的内部和派生类中可以被访问&#xff0c;但在类的外部不可访问。 私有成员只能在类的内部访问&#xff0c;包括类的成员函数和友元函数&#xff0c;不允许在类的外部…

MySQL45讲(一)(45)

如果使用的是unsigned int 做的主键&#xff0c;如果你用完了&#xff0c;在insert直接就是报冲突的错误 碰到这种情况&#xff0c;只能进行修改字段的属性了&#xff0c;把他换成big unsigned 了&#xff0c;所以建表对字段定义的时候就需要判断好&#xff0c;是否会超过 对于…

我的创作纪念日—128天的坚持|分享|成长

☘️博主介绍☘️&#xff1a; ✨又是一天没白过&#xff0c;我是奈斯&#xff0c;DBA一名✨ ✌✌️擅长Oracle、MySQL、SQLserver、阿里云AnalyticDB for MySQL(分布式数据仓库)、Linux&#xff0c;也在扩展大数据方向的知识面✌✌️ ❣️❣️❣️大佬们都喜欢静静的看文章&am…

H3C MSTP 实验

H3C MSTP 实验 实验拓扑 ​​ 实验需求 所有交换机上创建 Vlan10&#xff0c;Vlan20&#xff0c;Vlan30 和 Vlan40所有交换机之间的端口配置为 Trunk&#xff0c;并放行相关 VLAN按照图示分区域配置 MSTP&#xff0c;并配置主备根网桥 实验步骤 VLAN基础配置&#xff08;…

RateLimiter 限流 —— 通过切面对单个用户进行限流和黑名单处理

关于登录的安全性管理有较多的手段&#xff0c;包括&#xff1b;设备信息、IP信息、绑定的信息、验证码登各类方式。不过在一些网页版的登录中&#xff0c;如果有人想办法把你的验证码给我&#xff0c;我就可以登录你的账户&#xff0c;查看你的数据。对于一些不法分子通过让你…

windows 驱动开发-DMA技术(二)

前面描述了DMA技术中适配器相关的部分以及DMA的分类&#xff0c;接下来看一下系统具体在支持两种DMA时候的操作的细微差别。 此处解释一下Scatter/Gather&#xff0c;这个也翻译为散点/收集&#xff0c;是指指示设备能够读取或写入内存中的任何区域&#xff0c;而不仅仅是特定…

构建智能化商旅服务:酒店中台云服务架构设计与实践

随着商旅行业的不断发展和智能化趋势的兴起&#xff0c;酒店中台云服务成为了提升服务质量和效率的关键。本文将探讨酒店商旅中台云服务的架构设计与实现&#xff0c;介绍其关键特点和最佳实践&#xff0c;助力商旅行业迈向智能化未来。 1. **需求分析与场景设计&#xff1a;*…

【阿里云服务器】ubuntu 22.04.1安装docker以及部署java环境

我的服务器配置是2GB CPU 2GB 内存 Ubuntu22.04 目录 一、阿里云 ubuntu 22.04.1安装docker 二、docker基础命令 三、Windows电脑访问云服务器 四、安装java环境 安装OpenJDK 8&#xff08;可以根据需要安装其他版本的JDK&#xff09; 安装java的依赖管理工具maven 一、…

基于yolov2深度学习网络模型的鱼眼镜头中人员检测算法matlab仿真

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 5.算法完整程序工程 1.算法运行效果图预览 2.算法运行软件版本 matlab2022a 3.部分核心程序 load yolov2.mat% 加载训练好的目标检测器 img_size [448,448]; imgPath test/; % 图像…

LeetCode 15 —— 三数之和

阅读目录 1. 题目2. 解题思路3. 代码实现 1. 题目 2. 解题思路 首先我们对数组进行从小到大排序&#xff0c;然后遍历数组 [ 0 , n u m s . s i z e ( ) − 3 ] [0,nums.size()-3] [0,nums.size()−3] 作为三元组中的 a a a&#xff0c;由于三元组的索引互不相同&#xff0c…

文件与IO基础常识知识

在这里&#xff0c;只介绍理论知识&#xff0c;不介绍代码。 目录 1.IO 1.1.字面概念 1.2.输入输出模型 2.文件 2.1.文件目录 2.2.文件路径 2.3.文件分类 1.IO 为了我们接下来学习的文件IO&#xff0c;所以我们先来认识什么是IO。 1.1.字面概念 &#xff08;1&#x…

【知识加油站】——机电产品数字孪生机理模型构建

明确一种多领域、多层次、参数化、一致性的机电一体化装备数字孪生机理模型构建准则&#xff01; 关键词英文简称&#xff1a; 数字孪生&#xff1a;DT物联网&#xff1a;IoT网络物理系统&#xff1a;CPS高级架构&#xff1a;HLA统一建模语言&#xff1a;UML数控机床&#xf…