序列模型的使用示例

序列模型的使用示例

  • 1 RNN原理
    • 1.1 序列模型的输入输出
    • 1.2 循环神经网络(RNN)
    • 1.3 RNN的公式表示
    • 2 数据的尺寸
  • 3 PyTorch中查看RNN的参数
  • 4 PyTorch中实现RNN
    • (1)RNN实例化
    • (2)forward函数
    • (3)多层RNN的参数尺寸
  • 5 实战

1 RNN原理

1.1 序列模型的输入输出

假如你想要建立一个序列模型,它的输入语句是这样的: “Harry Potter and Herminoe Granger invented a new spell.”,(句中的人名都是出自于 J.K.Rowling 笔下的系列小说 Harry Potter)。假如你想要建立一个能够自动识别句中人名的序列模型,那么这就是一个命名实体识别问题。命名实体识别系统可以用来查找不同类型的文本中的人名、公司名、时间、地点、国家名和货币名等等。

将输入的句子定义为x,上述的输入语句中共有9个单词,可以对输入进行编号,用 x < t > x^{<t>} x<t> 来索引句子中第t个单词的位置。假如这个序列模型有一个输出序列,使得输入的每个单词都对应一个输出值,这个值为1表示对应的输入单词是人名的一部分,为0表示不是人名的一部分,同时用 y < t > y^{<t>} y<t> 对输出进行编号,如下图所示:
在这里插入图片描述

同时我们用 T x T_x Tx 来表示输入序列的长度,这个例子中输入是9个单词,所以 T x = 9 T_x= 9 Tx=9 ,同样,可用 T y T_y Ty 来表示输出序列的长度。输出序列的长度可以和输入序列的相同,也可以不同。

之前我们在DNN中用 x ( i ) x^{(i)} x(i) 表示第i个训练样本,这里我们可以用 x ( i ) < t > x^{(i)<t>} x(i)<t> 来表示第i个样本的第t个元素, T x ( i ) T{x}^{(i)} Tx(i) 代表第i个训练样本的输入序列长度。同样的,用 y ( i ) < t > y^{(i)<t>} y(i)<t> 来表示第i个样本的第t个元素对应的输出值, T y ( i ) T{y}^{(i)} Ty(i) 代表第i个训练样本的输出序列长度。

我们该怎样表示序列中的一个单词呢,比如Harry这个单词,对应的索引 x ( 1 ) x^{(1)} x(1) 是什么?自然语言处理(Natural Language Process,简称NLP)中,想要表示一个句子里的单词,第一件事是做一张词表,有时也称为词典,我们这里用10000个单词的词典举例。
在这里插入图片描述

当词典构建好之后,遍历数据集,给数据集中的每一个单词匹配一个one-hot编码,即用一个10000维的向量表示,例如单词a出现在词典中的第一个位置,那么当输入a时,就生成一个10000维的向量,该向量的第一个元素是1,其他都是0。

因此,给定上述输入语句,可以生成如下的向量:
在这里插入图片描述

图中其实就是One-hot向量,因为向量中只有一个位置是1,其余都是0。

如果遇到不在词典中的单词,那么就创建一个叫做 Unknow Word 的伪单词,用<UNK>作为标记,来表示不在词表中的单词。

这里我们用的词典只有一万个单词,正常商业应用的词典,词汇量3万至5万比较常见,10万的也有,某些大型互联网公司用的词典,其单词数量甚至超过百万。

1.2 循环神经网络(RNN)

这节我们来谈一谈怎样建立模型,来实现从X到Y的映射。

我们先尝试一下标准神经网络。前面的例子,“Harry Potter and Herminoe Granger invented a new spell.”有9个单词,因此需要把这9个单词一次性输入网络,如图所示:
在这里插入图片描述

为了方便输入,可以将单词索引成一个整数,但使用标准神经网络有以下两个问题:

  1. 上述例子是9个单词,所以输入单元是9个,但如果另一条句子有10个单词,那么这张网络将不再适用。
  2. 这种网络并不共享从文本的不同位置上学到的特征。具体来说,经过训练后的神经网络,当Harry出现在位置 x < 1 > x^{<1>} x<1> 时,会将其判定为人名的一部分,那么如果Harry 出现在其他位置,比如 x < 8 > x^{<8>} x<8> 时,很有可能因为位置不同,权重参数不同,神经网络不会将其认为是人名的组成部分。

为了解决上述问题,这里引入循环神经网络的概念。

还是“Harry Potter and Herminoe Granger invented a new spell.”这句话,如果从左往右逐个读取单词,当读到第一个单词Harry时,将其对应的One-hot向量 x < 1 > x^{<1>} x<1> 输入到神经网络,输出 y ^ < 1 > \hat{y} ^{<1>} y^<1>,并判断其是否为人名的一部分,用下面的图表示:

在这里插入图片描述

这里只有两层神经网络,一个隐藏层(图中的小圆圈可以认为是神经元),一个输出层。设隐藏层的激活值为 a < 1 > a^{<1>} a<1> ,输入第一个单词的过程称为时间步1。

接着读取第二个单词,将 x < 2 > x^{<2>} x<2> 输入神经网络, x < 2 > x^{<2>} x<2> 乘以权重之后,并不是马上激活,而是要先加上来自时间步1的激活值 a < 1 > a^{<1>} a<1>,然后再将相加后的结果激活,获得激活值 a < 2 > a^{<2>} a<2> ,最后计算输出层,获得预测值 y ^ < 2 > \hat{y} ^{<2>} y^<2>。(这样说不太准确,但这样说方便理解,后面会详细讲解)

依此类推,在计算激活值的时候,加入上一时步的激活值,直至整条语句读取结束,这就是循环神经网络,结构如下:
在这里插入图片描述

为了使各个部分结构一致,在零时刻,需要构造一个激活值 a < 0 > a^{<0>} a<0> ,这通常是个零向量,加上激活值 a < 0 > a^{<0>} a<0> 后的结构如下图所示:
在这里插入图片描述

在某些文献中,你看到的循环神经网络有可能是下面这种形式:
在这里插入图片描述

在每一个时间步中,输入 x < t > x ^{<t>} x<t> 输出 y < t > y ^{<t>} y<t> ,用一个带箭头的圆圈,表示把激活值重新输入网络,圆圈上面加上一个方块,表示激活值输回网络会延迟一个时间步。

循环神经网络每个时间步的参数也是一致的,也就是说,第一次输入时的网络和第二次、第三次、第t次输入时,网络的参数完全一致。

因为只有一个隐藏层,因此我们设隐藏层的权重参数为Wax,各个时步的Wax相同。我们设水平联系的权重参数为Waa,在计算本时步激活值的时候,把上一层的激活值乘以Waa,然后再加到本时步,各个时步的Waa相同。本时步的激活值算出来之后,需要计算输出值,这时需要乘以一个输出权重Wya,再将结果激活作为输出值。Wax、Waa、Wya这些参数,第一个下标表示用来计算什么,第二个下标表示这个参数该乘什么。

将以上参数标在图片中,则是下面这个结果:
在这里插入图片描述

标在简化循环图中,则是下面的结果:
在这里插入图片描述

1.3 RNN的公式表示

如果把上面的过程用公式表达,则如下所示:
a < 1 > = g ( W a a a < 0 > + W a x x < 1 > + b a ) y < 1 > = g ( W y a a < 1 > + b y ) \begin{array}{l} a^{<1>}=g\left(W_{a a} a^{<0>}+W_{a x} x^{<1>}+b_{a}\right) \\ y^{<1>}=g\left(W_{y a} a^{<1>}+b_{y}\right) \end{array} a<1>=g(Waaa<0>+Waxx<1>+ba)y<1>=g(Wyaa<1>+by)

这里面g表示激活函数,一般情况下,隐藏层使用tanh作为激活函数,有时也用Relu,输出层看网络要解决的问题,如果是二分类问题,就用sigmoid,如果是k分类问题,就用softmax。如果想区分隐藏层和输出层的激活函数,那么可以对g标号,如下所示:
a < t > = g 1 ( W a a a < t − 1 > + W a x x < t > + b a ) y < t > = g 2 ( W y a a < t > + b y ) \begin{array}{l} a^{<t>}=g_1\left(W_{a a} a^{<t-1>}+W_{a x} x^{<t>}+b_{a}\right) \\ y^{<t>}=g_2\left(W_{y a} a^{<t>}+b_{y}\right) \end{array} a<t>=g1(Waaa<t1>+Waxx<t>+ba)y<t>=g2(Wyaa<t>+by)

其中,计算激活值的公式可以简化表示如下:
a ⟨ t ⟩ = g 1 ( W a [ a ⟨ t − 1 ⟩ , x ⟨ t ⟩ ] T + b a ) a^{\langle t\rangle}=g_{1}\left(W_{a}\left[a^{\langle t-1\rangle}, x^{\langle t\rangle}\right]^{T}+b_{a}\right) at=g1(Wa[at1,xt]T+ba)
这里 W a = [ W a a , W a x ] W_{a}=\left[W_{a a}, W_{a \mathrm{x}}\right] Wa=[Waa,Wax]

假设单词库里有一万个单词,那么 x < t > x^{<t>} x<t> 的维度为(10000, 1),若隐藏层有100个神经元,那么 a < t > a^{<t>} a<t> 的维度为(100, 1), [ a < t − 1 > , x < t > ] T \left[a^{<t-1>}, x^{<t>}\right]^{T} [a<t1>,x<t>]T 的维度为(10100, 1)。Waa的维度就是(100,100),Wax的维度就是(100,10000),把这两个矩阵整合之后,Wa就是(100,10100)。

同样对于输出层的公式,也可以使用更简单的方式重写: y < t > = g 2 ( W y a < t > + b y ) y^{<t>}=g_{2}\left(W_{y} a^{<t>}+b_{y}\right) y<t>=g2(Wya<t>+by)
现在 W y W_y Wy b y b_y by W a W_a Wa b a b_a ba,下标表示的是分别会输出什么类型的量。

使用上述记法,当我们建立更复杂模型时就能够简化我们要用到的符号。

如果将循环神经网络的结果画得更工整一点,将是下面的图形:
在这里插入图片描述
这种结构的循环神经网络有一个缺点,就是在计算t时步时,仅仅使用了t时步以前的计算结果,没有使用t时步之后的结果。比如,现在有两个句子,“Teddy Roosevelt was a great President.”(中文意思是 西奥多罗斯福是一位伟大的总统,因为他的小名也叫泰迪,因此也经常被称为“Teddy Roosevel”),“Teddy bears are on sale!”(正在销售泰迪熊),如果使用相同的循环神经网络从左往右扫描句子,那么获得的第一个单词都是Teddy,因为是第一个,都没有从上一层传过来的激活值,那么会获得相同的输出,前者Teddy是人名,后者是熊,因此两者的输出,必有一个有错。
针对这个问题,可以使用双向循环神经网络。不过本文的重点是RNN的原理和过程,以及在PyTorch中的数据处理,目的是了解这一类模型的调用的和数据处理方式,讲原理只是为了后面讲接口时能更直观。

2 数据的尺寸

这里先说明一下,本节的资料来源和上节不一样,因此符号定义和上面的有所不同,了解原理即可。

RNN每次输入一个单词,那么 x t x_t xt 就是该单词对应的One-hot向量,尺寸为[vector_length][1,vector_length],向量长度也是特征长度,因此也可以用[feature len]或者[1, feature len]来表示。

使用PyTorch的并行技术,给模型喂数据的时候,每次都喂一个batch。假设每个batch由5个句子各出一个单词组成,则batch_size=5,那么就相当于有5条生产线(这5条生产线共享参数),每次喂数据的时候,都是给这5条生产线各喂一个单词,所以 x t x_t xt 的尺寸为[batch_size, vector_length]

如果觉得每次输入一个单词太慢,那么可以一次输入, 假如每条句子都是8个单词,那么x的尺寸是[8, 5, feature len],如果每次输入的单词个数是seq len,那么x的尺寸是[batch_size, seq len, feature len]seq len表示句子长度。

为了便于探讨RNN中参数的尺寸,下面我们不对输出层加激活函数,假设第t时步的计算过程如下图所示:
在这里插入图片描述

这里 W x h W_{xh} Wxh W h h W_{hh} Whh W h y W_{hy} Why ,第一个下标表示这个参数该乘什么,第二个下标表示这个参数用来计算什么,和前面介绍原理时刚好相反。

上图中 x t x_t xt 是每个时步输入的数据,它的尺寸是[batch_size, feature len],假设隐藏层的神经元个数为hidden length,那么隐藏层的输出 h t h_t ht 的尺寸就是[batch_size, hidden len]

那么 W x h W_{xh} Wxh 参数的尺寸为[feature len, hidden len],它的意义是压缩数据的维度,将 x t x_t xt 的特征长度由feature len压缩为hidden len
因为循环神经网络每个时间步的参数一致,所以 h t − 1 h_{t-1} ht1 的尺寸也为[batch_size, hidden len] h t − 1 W h h h_{t-1} W_{h h} ht1Whh 的尺寸要和 x t W x h + b h x_{t} W_{x h}+b_{h} xtWxh+bh 的一致,因此 W h h W_{hh} Whh 的尺寸为[hidden len, hidden len]

一般情况下, y t y_t yt 的特征长度为1,因此其尺寸为[batch_size, 1],那么 W h h W_{h h} Whh 的尺寸为[hidden len, 1]

3 PyTorch中查看RNN的参数

import torch
import torch.nn as nn

model = nn.RNN(input_size=10, hidden_size=5, num_layers=1)
'''循环层的输入是10,即表示输入数据对应的One-hot向量长度是10,
    隐藏层里有5个元素,循环层有1层'''
print(model)    # 打印网络的结构
print(model._parameters.keys())     # 打印参数结构
'''打印参数的尺寸'''
print('----------------------------------------')
print(model.weight_ih_l0.size())    # W_xh.T
print(model.weight_hh_l0.size())    # W_hh.T
print(model.bias_hh_l0.size())
print(model.bias_ih_l0.size())
'''参数名的末尾l0表示第0层,0 layer'''
'''如果RNN有3层,那么会有l0,l1,l2'''

输出

RNN(10, 5)
odict_keys(['weight_ih_l0', 'weight_hh_l0', 'bias_ih_l0', 'bias_hh_l0'])
----------------------------------------
torch.Size([5, 10])
torch.Size([5, 5])
torch.Size([5])
torch.Size([5])

上面这段程序有几点需要注意:
1 model.weight_ih_l0并不是 W x h W_{xh} Wxh,而是 W x h T W_{xh}{ }^{T} WxhT,即是转置后的结果。
2 隐藏层使用的结构是这样的: h t = tanh ⁡ ( x t W x h + b x h + h t − 1 W h h + b h h ) h_{t}=\tanh \left(x_{t} W_{x h}+b_{x h}+h_{t-1} W_{h h}+b_{h h}\right) ht=tanh(xtWxh+bxh+ht1Whh+bhh),我们一般写式子的时候,常常把 b x h b_{x h} bxh b h h b_{h h} bhh 合并成 b h b_{h} bh
3 上面的model中,没有计算 y t y_t yt 的模块,如果需要计算 y t y_t yt 的模块,需要增加一个线性层模块(见实战环节)。

4 PyTorch中实现RNN

(1)RNN实例化

调用nn.RNN可以创建RNN模型,它的__init__有四个参数:

input_size,单词的编码长度
hidden_size,隐藏层的单元个数
num_layer,RNN的层数,默认为1
batch_first,表示batch_size这个维度是否在最前面,默认为False,False表示输入数据的结构是[seq len,batch_size,feature],为True则表示输入数据的结构是[batch_size,seq len,feature]

通过nn.RNN创建的RNN模型,没有线性层,需要自己手动添加。
因为我们习惯将batch_size维度放到最前面,下面的关于输入输出尺寸的讨论,都是在batch_first=True的情形下。

(2)forward函数

输入输出分别为

out, ht = forward(self, x, h0)

假如有3句话(三条生产线),每句话都有5个单词,单词用长度为100的向量来编码,那么x的尺寸为[3, 5, 100],RNN中,可以使用并行化技术,一次性把所有的x输入到RNN中,不需要一个单词一个单词地喂。

out是每个时间步的最后一个隐藏层的输出,尺寸为[batch_size, Seq len, hidden],其中Seq len是每句话的单词数量,比如可以是5。
无论RNN有多少层,out的尺寸都是[batch_size, Seq len, hidden],也就是说,RNN中各个隐藏层的神经元数量都是hidden。

ht是最后一个时间步的每一层的输出,尺寸为[batch_size, num_layers, hidden len],而第一个时间步由于没有上一轮的输入,因此第一时步使用h0,h0的尺寸也为[batch_size, num_layers, hidden len]

(3)多层RNN的参数尺寸

rnn = nn.RNN(100, 10, 2, batch_first=True)实例化一个2层的RNN,2层指的是隐藏层数量,这个两层的模型,输入样本的特征长度为100,输出长度为10,那么第一层的输出数据的特征长度是多少?
每个时步第一层的输出的长度就是10,也就是说,多层RNN,在第一层就完成了数据的维度压缩。

5 实战

房价预测模型:已知某地区连续50个月的房价,根据已有数据,预测第51个月的房价。
使用RNN来预测,代码如下:

import numpy as np
import torch
from matplotlib import pyplot as plt
import torch.nn as nn
import torch.optim as optim
import torch.functional as F
'''房价预测模型'''

'''超参数'''
num_time_steps = 50     # 50个时步
input_size = 1          # 数据编码长度是1
hidden_size = 16        # 隐藏层有16个单元
output_size = 1         # 输出层只有1个单元
lr = 0.01               # 学习率是0.01


class Net(nn.Module):

    def __init__(self, ):
        super(Net, self).__init__()

        '''循环层'''
        self.rnn = nn.RNN(
            input_size=input_size,
            hidden_size=hidden_size,
            num_layers=1,
            batch_first=True,
        )
        '''batch_first默认为False,False表示输入数据的结构是[seq len,batch_size,feature],
        为True表示输入数据的结构是[batch_size,seq len,feature]'''

        '''参数初始化'''
        # for p in self.rnn.parameters():
        #     nn.init.normal_(p, mean=0.0, std=0.001)

        '''线性层'''
        self.linear = nn.Linear(hidden_size, output_size)

    def forward(self, x, hidden_prev):

        out, hidden_prev = self.rnn(x, hidden_prev)
        '''x的尺寸为[batch_size, seq len, feature len],
        out的尺寸为[batch_size, seq len, hidden_size]'''

        out = out.view(-1, hidden_size)  # 打平的目的是为了送到线性层
        '''这里假设标签是二维的,其尺寸为[50, 16]
        为了让标签值和预测值能够进行比较,因此将out打平,打平后,50等效于“batch_size维度为50”'''
        out = self.linear(out)
        out = out.unsqueeze(dim=0)       # 插入真正的batch_size维度
        '''如果不插入一个新的维度,那么out的输出将变成[50, 1],
        而在定义数据时,y被定义成了[1, 50, 1],因此需要插入一个新的维度'''

        '''其实上面的步骤可以先不打平,而是先输入到线性层,输出的结果直接是[1,50,1]'''
        return out, hidden_prev


'''需要注意的是,房价预测模型,其自变量不是月份,而是前面若干个月的房价,
也就是说,上述Net中的x,是房价,不是时间。
因此'''

model = Net()
criterion = nn.MSELoss()
optimizer = optim.Adam(model.parameters(), lr)

hidden_prev = torch.zeros(1, 1, hidden_size)	# h0的初始值

# 训练
for iter in range(1000):
    start = np.random.randint(3, size=1)[0]
    '''从0,1,2里面随机抽取一个数,为什么要从3个数字里面抽一个?
    因为如果每次都是从0开始,RNN很容易记住'''

    time_steps = np.linspace(start, start + 10, num_time_steps)
    data = np.sin(time_steps)
    data = data.reshape(num_time_steps, 1)
    x = torch.tensor(data[:-1]).float().view(1, num_time_steps - 1, 1)
    y = torch.tensor(data[1:]).float().view(1, num_time_steps - 1, 1)

    '''由于前面实例化的时候,batch_first=True,这里将 x 和 y 重塑成[1, 49, 1]之后,
    数据的batch_size = 1,但有49条生产线,房价可以有一个数来表征,因此feature len=1
    '''

    '''因为num_time_steps=50,因此有50个时步,所以data的下标是0-49,
    data[:-1]表示从data[0]到data[48],
    data[1:]表示从data[1]到data[49]
    
    该算法的思路就是,根据第1天的房价(x[0])预测第2天的房价(output[0]),
    再将其与第二天的真实房价y[0]进行对比,求出第一天的误差。
    其他天的误差也是类似,最后根据前49天的房价x,求出从第2-50天的房价预测值,
    利用第2-50天的房价真实值与预测值之间的误差,训练模型。
    这就是为什么训练的时候 x 和 y 的长度是49的原因。
    '''

    output, hidden_prev = model(x, hidden_prev)
    hidden_prev = hidden_prev.detach()
    '''detach()的作用是脱离原来的计算图,使其不再需要梯度信息,这样参数反向传播
    因为该算法每轮迭代都使用上一轮迭代的hidden_prev,如果hidden_prev不与原来的计算图脱钩,
    那么求导的时候,会沿着hidden_prev进入上一轮迭代的计算图,这样就会报错,说视图在计算图上求两次导'''

    loss = criterion(output, y)
    model.zero_grad()
    loss.backward()
    # for p in model.parameters():
    #     print(p.grad.norm())
    # torch.nn.utils.clip_grad_norm_(p, 10)
    optimizer.step()

    '''没迭代100次,输出一次'''
    if iter % 100 == 0:
        print("Iteration: {} loss {}".format(iter, loss.item()))

'''其实可以在每一轮循环的时候,都使用0作为hidden_prev,因为你不知道从什么位置开始,
所以无法估计出第-1时步的结果是多少,因此hiiden_prev选择什么值都是不完美的'''

# 预测房价的趋势
start = np.random.randint(3, size=1)[0]
time_steps = np.linspace(start, start + 10, num_time_steps)
data = np.sin(time_steps)
data = data.reshape(num_time_steps, 1)
x = torch.tensor(data[:-1]).float().view(1, num_time_steps - 1, 1)
y = torch.tensor(data[1:]).float().view(1, num_time_steps - 1, 1)

predictions = []
input = x[:, 0, :]
hidden_prev = torch.zeros(1, 1, hidden_size)

'''只需要知道第一天的值,就能求得后面49天的房价'''
for _ in range(x.shape[1]):
    '''循环49次,一个一个喂数据
    将上一轮的输出(预测值)作为本轮的输入'''
    input = input.view(1, 1, 1)
    (pred, hidden_prev) = model(input, hidden_prev)
    input = pred
    '''将每一轮的输出存进列表'''
    predictions.append(pred.detach().numpy().ravel()[0])

x = x.data.numpy().ravel()
y = y.data.numpy()
plt.scatter(time_steps[:-1], x.ravel(), s=90)
plt.plot(time_steps[:-1], x.ravel())

plt.scatter(time_steps[1:], predictions)
plt.show()

输出:

Iteration: 0 loss 0.8515104055404663
Iteration: 100 loss 0.0022286889143288136
Iteration: 200 loss 0.0038173357024788857
Iteration: 300 loss 0.004501968156546354
Iteration: 400 loss 0.0035968958400189877
Iteration: 500 loss 0.0017438693903386593
Iteration: 600 loss 0.002284669317305088
Iteration: 700 loss 0.0019050785340368748
Iteration: 800 loss 0.0011780565837398171
Iteration: 900 loss 0.00046253044274635613

显示
在这里插入图片描述

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

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

相关文章

Hadoop学习笔记(包括hadoop3.4.0集群安装)(黑马)

Hadoop学习笔记 0-前置章节-环境准备 0.1 环境介绍 配置环境&#xff1a;hadoop-3.4.0&#xff0c;jdk-8u171-linux-x64 0.2 VMware准备Linux虚拟机 0.2.1主机名、IP、SSH免密登录 1.配置固定IP地址&#xff08;root权限&#xff09; 开启master&#xff0c;修改主机名为…

【计算机网络】Layer4-Transport layer

目录 传输层协议How demultiplexing works in transport layer&#xff08;传输层如何进行分用&#xff09;分用&#xff08;Demultiplexing&#xff09;的定义&#xff1a;TCP/UDP段格式&#xff1a; UDPUDP的特点&#xff1a;UDP Format端口号Trivial File Transfer Protocol…

Android Studio创建新项目并引入第三方so外部aar库驱动NFC读写器读写IC卡

本示例使用设备&#xff1a;https://item.taobao.com/item.htm?spma21dvs.23580594.0.0.52de2c1bbW3AUC&ftt&id615391857885 一、打开Android Studio,点击 File> New>New project 菜单&#xff0c;选择 要创建的项目模版&#xff0c;点击 Next 二、输入项目名称…

【Linux】—简单实现一个shell(myshell)

大家好呀&#xff0c;我是残念&#xff0c;希望在你看完之后&#xff0c;能对你有所帮助&#xff0c;有什么不足请指正&#xff01;共同学习交流哦&#xff01; 本文由&#xff1a;残念ing原创CSDN首发&#xff0c;如需要转载请通知 个人主页&#xff1a;残念ing-CSDN博客&…

【Python爬虫系列】_032.Scrapy_全站爬取

课 程 推 荐我 的 个 人 主 页:👉👉 失心疯的个人主页 👈👈入 门 教 程 推 荐 :👉👉 Python零基础入门教程合集 👈👈虚 拟 环 境 搭 建 :👉👉 Python项目虚拟环境(超详细讲解) 👈👈PyQt5 系 列 教 程:👉👉 Python GUI(PyQt5)教程合集 👈👈

Android通过okhttp下载文件(本文案例 下载mp4到本地,并更新到相册)

使用步骤分为两步 第一步导入 okhttp3 依赖 第二步调用本文提供的 utils 第一步这里不做说明了&#xff0c;直接提供第二步复制即用 DownloadUtil 中 download 为下载文件 参数说明 这里主要看你把 destFileName 下载文件名称定义为什么后缀&#xff0c;比如我定义为 .mp4 下…

win10配置子系统Ubuntu子系统(无需通过Windows应用市场)实际操作记录

win10配置子系统Ubuntu子系统&#xff08;无需通过Windows应用市场&#xff09;实际操作记录 参考教程 : win10配置子系统Ubuntu子系统&#xff08;无需通过Windows应用市场&#xff09; - 一佳一 - 博客园 开启虚拟机服务的 以管理员方式运行PowerShell运行命令。 &#xf…

Showrunner AI技术浅析(四):多智能体模拟

多智能体模拟技术涉及多个智能体&#xff08;Agents&#xff09;在虚拟环境中的行为和互动&#xff0c;每个智能体都有自己的属性、目标和行为规则。 1. 多智能体模拟概述 多智能体模拟技术通过模拟多个智能体在虚拟环境中的互动来生成复杂的剧情和场景。每个智能体都有其独特…

创新性融合丨卡尔曼滤波+目标检测 新突破!

2024深度学习发论文&模型涨点之——卡尔曼滤波目标检测 卡尔曼滤波是一种递归算法&#xff0c;用于估计线性动态系统的状态。它通过预测和更新两个步骤&#xff0c;结合系统模型和观测数据&#xff0c;来估计系统状态&#xff0c;并最小化估计的不确定性。 在目标检测中&am…

USB模块布局布线

1、USB接口定义 2、USB模块常规分类介绍 3、USB常用管脚定义图示 4、USB模块布局布线分析 USB3.0高速线因为速度比较高&#xff0c;建议走圆弧线不能走钝角 5、总结 1、CTRL鼠标中间滑轮按下可以看线的长度 2、不懂差分类和规则的设置&#xff0c;可以看本人写的AD基础操作…

SpringCloud系列之分布式配置中心极速入门与实践

[toc] 1、分布式配置中心简介 在实际的项目开发中&#xff0c;配置文件是使用比较多的&#xff0c;很多项目有测试环境(TEST)、开发环境(DEV)、规范的项目还有集成环境(UAT)、生产环境(PROD)&#xff0c;每个环境就一个配置文件。 CSDN链接&#xff1a;SpringCloud系列之分布式…

【Vue3学习】setup语法糖中的ref,reactive,toRef,toRefs

在 Vue 3 的组合式 API&#xff08;Composition API&#xff09;中&#xff0c;ref、reactive、toRef 和 toRefs 是四个非常重要的工具函数&#xff0c;用于创建和管理响应式数据。 一、ref 用ref()包裹数据,返回的响应式引用对象&#xff0c;包含一个 .value 属性&#xff0…

解决 Git Permission denied 问题

前言 push项目时出现gitgithub.com: Permission denied (publickey). fatal: Could not read from remote repository.Please make sure you have the correct access rights and the repository exists.出现这个问题表示你在尝试将本地代码推送到GitHub时&#xff0c;没有提供…

React的状态管理库-Redux

核心思想&#xff1a;单一数据源、状态是只读的、以及使用纯函数更新状态。 组成部分 Store&#xff08;存储&#xff09; 应用的唯一状态容器&#xff0c;存储整个应用的状态树,使用 createStore() 创建。 getState()&#xff1a;获取当前状态。dispatch(action)&#xff…

蓝卓总裁谭彰:AI+工业互联网推动制造业数字化转型

近日&#xff0c;新一代工业操作系统supOS6.0在2024中国5G工业互联网大会上重磅发布。 大会期间&#xff0c;工信部新闻宣传中心《人民邮电报》对蓝卓总裁谭彰就“工业互联网人工智能技术融合的思考”“supOS6.0的探索与实践”“未来工业互联网平台的发展方向”展开专题访谈&am…

RabbitMQ消息队列的笔记

Rabbit与Java相结合 引入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-amqp</artifactId> </dependency> 在配置文件中编写关于rabbitmq的配置 rabbitmq:host: 192.168.190.132 /…

数据结构:贪吃蛇详解

目录 一.地图的设计 1.字符与坐标&#xff1a; 2.本地化&#xff08;头文件&#xff09;: 3.类项&#xff1a; 4.setlocale函数&#xff1a; &#xff08;1&#xff09;函数原型&#xff1a; &#xff08;2&#xff09;使用&#xff1a; 5.宽字符的打印&#xff1a; &a…

医学AI前沿进展:图像分割以及细胞分割领域的最新研究|文献速递·24-12-17

小罗碎碎念 今天推文和大家分享医学AI领域中&#xff0c;图像分割以及细胞分割方面的三个工作。 首先看一下图像分割以及细胞分割方面&#xff0c;近五年的一个论文发表情况&#xff0c;我们可以看到&#xff0c;这个领域在前几年的热度基本持平&#xff0c;到了24年迎来了一个…

Endnote | 查看文献所在分组

软件版本&#xff1a;Endnote X8 第一种方式&#xff1a; 在文献上右键——记录摘要&#xff0c;即可在弹出页面上看到自定义和智能组的分组情况。 第二种方式&#xff1a; 在菜单栏点击文献——记录摘要&#xff0c;也可以查看分组情况。 注&#xff1a; 新版本的endnote软件…

ElasticSearch 数据聚合与运算

1、数据聚合 聚合&#xff08;aggregations&#xff09;可以让我们极其方便的实现数据的统计、分析和运算。实现这些统计功能的比数据库的 SQL 要方便的多&#xff0c;而且查询速度非常快&#xff0c;可以实现近实时搜索效果。 注意&#xff1a; 参加聚合的字段必须是 keywor…