序列模型的使用示例
序列模型的使用示例
- 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个单词一次性输入网络,如图所示:
为了方便输入,可以将单词索引成一个整数,但使用标准神经网络有以下两个问题:
- 上述例子是9个单词,所以输入单元是9个,但如果另一条句子有10个单词,那么这张网络将不再适用。
- 这种网络并不共享从文本的不同位置上学到的特征。具体来说,经过训练后的神经网络,当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<t−1>+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) a⟨t⟩=g1(Wa[a⟨t−1⟩,x⟨t⟩]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<t−1>,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} ht−1 的尺寸也为[batch_size, hidden len]
, h t − 1 W h h h_{t-1} W_{h h} ht−1Whh 的尺寸要和 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 nnmodel = 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+ht−1Whh+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.01class 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
显示
相关文章:
序列模型的使用示例
序列模型的使用示例 1 RNN原理1.1 序列模型的输入输出1.2 循环神经网络(RNN)1.3 RNN的公式表示2 数据的尺寸 3 PyTorch中查看RNN的参数4 PyTorch中实现RNN(1)RNN实例化(2)forward函数(3…...
JMeter配置原件-计数器
一、面临的问题: 由于本人的【函数助手对话框】中counter计数器每次加2,且只显示偶数(如下图所示),因此借助【配置原件-计数器】来实现计数功能。 如果有大佬知道解决方式,麻烦评论区解答一下,谢谢。 二、配置原件-c…...
JS子页面调用父页面函数,监听刷新事件
目录 1.子页面调用父页面的函数 2.监听刷新事件 1.子页面调用父页面的方法 我们先来说说什么是子页面,在我这里子页面就是域名一样,然后使用iframe引入的页面就是我所说的子页面,为什么需要用到这个功能,是为了实现跨页面交互与…...
计算机视觉(为天地立心,为生民立命)
4. 逻辑回归中,对数损失函数怎么来表示的? 5. relu激活函数它的一些特点? ReLU的数学表达式为:f(x)max(0,x) 特点: 1.简单高效:ReLU 的计算非常简单,直接将输入小于 0 的部分置为 0ÿ…...
三格电子——新品IE103转ModbusTCP网关
型号:SG-TCP-IEC103 产品概述 IE103转ModbusTCP网关型号SG-TCP-IEC103,是三格电子推出的工业级网关(以下简称网关),主要用于IEC103数据采集、DLT645-1997/2007数据采集,IEC103支持遥测和遥信,可…...
金碟中间件-AAS-V10.0安装
金蝶中间件AAS-V10.0 AAS-V10.0安装 1.解压AAS-v10.0安装包 unzip AAS-V10.zip2.更新license.xml cd /root/ApusicAS/aas# 这里要将license复制到该路径 [rootvdb1 aas]# ls bin docs jmods lib modules templates config domains …...
最新D音滑块JS纯算法还原(含完整源码)
文章目录 1. 写在前面2. 接口分析2. 源码实现【🏠作者主页】:吴秋霖 【💼作者介绍】:擅长爬虫与JS加密逆向分析!Python领域优质创作者、CSDN博客专家、阿里云博客专家、华为云享专家。一路走来长期坚守并致力于Python与爬虫领域研究与开发工作! 【🌟作者推荐】:对爬…...
接口绑定有几种实现方式
在 MyBatis 中,接口绑定是指通过 Java 接口与 SQL 映射文件(XML)进行绑定,允许你以面向对象的方式操作数据库。MyBatis 提供了几种不同的实现方式来实现接口绑定。 MyBatis 接口绑定的几种实现方式 基于 XML 映射的实现方式 这是…...
Oracle JDK需登录下载解决
JDK下载地址 地址:https://www.oracle.com/java/technologies/downloads/archive/ 登录账号获取 访问:https://bugmenot.com/view/oracle.com 直接复制账号密码登录下载...
LabVIEW与PLC点位控制及OPC通讯
在工业自动化中,PLC通过标准协议(如Modbus、Ethernet/IP等)与OPC Server进行数据交换,LabVIEW作为上位机通过OPC客户端读取PLC的数据并进行监控、控制与处理。通过这种方式,LabVIEW能够实现与PLC的实时通信,…...
VM16+解压版CentOS7安装和环境配置教程(2024年12月20日)
VM16解压版CentOS7安装和环境配置教程-2024年12月20日 一、下载安装包二、vm安装三、解压版CentOS7安装四、CentOS设置静态IP 因为很多同学觉得配置CentOS7好麻烦,我特地提供了一个已经配置好的现成镜像,来简化操作本篇来记录过程。 如果你在看到这篇文章…...
SQL中的约束
约束(CONSTRAINT) 对表中字段的限制 非空约束:NOT NULL 只能声明在每个字段的后面 CREATE TABLE test( id INT NOT NULL, last_name VARCHAR(15), phone VARCHAR(20) NOT NULL );唯一性约束:UNIQUE 说明: ① 可以声明…...
【Lua热更新】上篇
Lua 热更新 - 上篇 下篇链接:【Lua热更新】下篇 文章目录 Lua 热更新 - 上篇一、AssetBundle1.理论2. AB包资源加载 二、Lua 语法1. 简单数据类型2.字符串操作3.运算符4.条件分支语句5.循环语句6.函数7. table数组8.迭代器遍历9.复杂数据类型 - 表9.1字典9.2类9.3…...
数据压缩比 38.65%,TDengine 重塑 3H1 的存储与性能
小T导读:这篇文章是“2024,我想和 TDengine 谈谈”征文活动的三等奖作品之一。作者通过自身实践,详细分享了 TDengine 在高端装备运维服务平台中的应用,涵盖架构改造、性能测试、功能实现等多个方面。从压缩效率到查询性能&#x…...
Linux shell脚本用于常见图片png、jpg、jpeg、tiff格式批量转webp格式后,并添加文本水印
Linux Debian12基于ImageMagick图像处理工具编写shell脚本用于常见图片png、jpg、jpeg、tiff格式批量转webp并添加文本水印 在Linux系统中,使用ImageMagick可以图片格式转换,其中最常用的是通过命令行工具进行。 ImageMagick是一个非常强大的图像处理工…...
DeepFaceLab技术浅析(六):后处理过程
DeepFaceLab 是一款流行的深度学习工具,用于面部替换(DeepFake),其核心功能是将源人物的面部替换到目标视频中的目标人物身上。尽管面部替换的核心在于模型的训练,但后处理过程同样至关重要,它决定了最终生…...
怎么将pdf中的某一个提取出来?介绍几种提取PDF中页面的方法
怎么将pdf中的某一个提取出来?传统上,我们可能通过手动截取屏幕或使用PDF阅读器的复制功能来提取信息,但这种方法往往不够精确,且无法保留原文档的排版和格式。此外,很多时候我们需要提取的内容可能涉及多个页面、多个…...
imu相机EKF
ethzasl_sensor_fusion/Tutorials/Introductory Tutorial for Multi-Sensor Fusion Framework - ROS Wiki https://github.com/ethz-asl/ethzasl_msf/wiki...
CSDN数据大屏可视化【开源】
项目简介 本次基于版本3 开源 版本3开源地址:https://github.com/nangongchengfeng/CsdnBlogBoard.git 版本1开源地址:https://github.com/nangongchengfeng/CSDash.git 这是一个基于 Python 的 CSDN 博客数据可视化看板项目,通过爬虫采…...
C# 从控制台应用程序入门
总目录 前言 从创建并运行第一个控制台应用程序,快速入门C#。 一、新建一个控制台应用程序 控制台应用程序是C# 入门时,学习基础语法的最佳应用程序。 打开VS2022,选择【创建新项目】 搜索【控制台】,选择控制台应用(.NET Framew…...
什么是 DevSecOps 框架?如何提升移动应用安全性?
在如今数字化发展的时代,安全性已成为移动应用开发不可或缺的一部分。传统的开发模式通常将安全作为一个独立的部门,专门负责保护组织的整体系统,而 DevSecOps 框架则将安全融入到 DevOps 的每一个环节中,确保应用的开发、测试、发…...
数字后端项目Floorplan常见问题系列专题
今天给大家分享下数字IC后端设计实现floorplan阶段常见问题系列专题。这些问题都是来自于咱们社区IC后端训练营学员提问的问题库。目前这部分问题库已经积累了4年了,后面会陆续分享这方面的问题。希望对大家的数字后端学习和工作有所帮助。 数字IC后端设计实现floo…...
【C++读写.xlsx文件】OpenXLSX开源库在 Ubuntu 18.04 的编译、交叉编译与使用教程
😁博客主页😁:🚀https://blog.csdn.net/wkd_007🚀 🤑博客内容🤑:🍭嵌入式开发、Linux、C语言、C、数据结构、音视频🍭 ⏰发布时间⏰: 2024-12-17 …...
Qt设置部件的阴影效果
QT中的比如QWidget,QLabel,QPushbutton,QCheckBox都可以设置阴影效果,就像这样: 以QWidget为例,开始尝试使用样式表的形式添加阴影,但没有效果,写法如下: QWidget#widget1::shadow{color: rgb…...
【iOS安全】NSTaggedPointerString和__NSCFString
概述 简而言之 : NSTaggedPointerString和__NSCFString都是NSString类型。NSTaggedPointerString善于存短字符串,__NSCFString善于存一般或长字符串在iOS运行时,系统会根据字符串长度自动在NSTaggedPointerString和__NSCFString之间进行转换…...
docker(wsl)命令 帮助文档
WSL wsl使用教程 wsl -l -v 列出所有已安装的 Linux 发行版 wsl -t Ubuntu-22.04 --shutdown 关闭所有正在运行的WSL发行版。如果你只想关闭特定的发行版 wsl -d Ubuntu-22.04 登录到Ubuntu环境 wsl --list --running 查看正在wsl中运行的linux发行版 wsl --unregister (系统名…...
nginx模块ngx-fancyindex 隐藏标题中的 / 和遇到的坑
首先下载nginx源码,编译时加上 --add-module/usr/local/src/ngx-fancyindex/ 例如 : ./configure --prefix/usr/local/nginx --with-select_module --with-poll_module --with-threads --with-file-aio --with-http_ssl_module --with-http_v2_module…...
Edge Scdn防御网站怎么样?
酷盾安全Edge Scdn,即边缘式高防御内容分发网络,主要是通过分布在不同地理位置的多个节点,使用户能够更快地访问网站内容。同时,Edge Scdn通过先进的技术手段,提高了网上内容传输的安全性,防止各种网络攻击…...
音频接口:PDM TDM128 TDM256
一、 PDM接口 在麦克风(Mic)接口中,PDM(Pulse Density Modulation,脉冲密度调制)和I2S(Inter-IC Sound,集成电路内置音频总线)是两种常见的数字输出接口。 1、工作原理…...
半连接转内连接规则的原理与代码解析 |OceanBase查询优化
背景 在查询语句中,若涉及半连接(semi join)操作,由于半连接不满足交换律的规则,连接操作必须遵循语句中定义的顺序执行,从而限制了优化器根据参与连接的表的实际数据量来灵活选择优化策略的能力。为此&am…...
虚拟机VMware的安装问题ip错误,虚拟网卡
要么没有虚拟网卡、有网卡远程连不上等 一般出现在win11 家庭版 1、是否IP错误 ip addr 2、 重置虚拟网卡 3、查看是否有虚拟网卡 4、如果以上检查都解决不了问题 如果你之前有vmware 后来卸载了,又重新安装,一般都会有问题 卸载重装vmware: 第一…...
2024159读书笔记|《南山册页:齐白石果蔬册鱼虫册》节选
2024159读书笔记|《南山册页:齐白石果蔬册&鱼虫册》节选 1. 《南山册页:齐白石鱼虫册》2. 《南山册页:齐白石果蔬册》 1. 《南山册页:齐白石鱼虫册》 《南山册页:齐白石鱼虫册》南山书画,大家之作&…...
校园社交圈子系统APP开发校园社交圈子系统校园社交圈子系统平台校园社交圈子系统论坛开发校园社交圈子系统圈子APP
关于校园社交圈子系统APP及平台的开发,以下是从需求分析、系统设计、技术选型、功能实现等多个方面进行的详细阐述: 点击可获得前后端完整演示查看 一、需求分析 校园社交圈子系统的开发需求主要来源于大学生的社交需求。通过问卷调查、用户需求收集等…...
【Leetcode 热题 100】437. 路径总和 III
问题背景 给定一个二叉树的根节点 r o o t root root,和一个整数 t a r g e t S u m targetSum targetSum,求该二叉树里节点值之和等于 t a r g e t S u m targetSum targetSum 的 路径 的数目。 路径 不需要从根节点开始,也不需要在叶子…...
Solidity中的事件(Event)的结构与用法
Solidity中的事件(Event)的结构与用法 event的简单例子被索引的参数(Indexed Parameters)没有被索引的参数(Non-indexed Parameters) event扩展event 更多举例无参数的event有什么用 event的简单例子 在So…...
基于STM32的房间湿度控制系统设计与实现(论文+源码)
1.系统总体设计 根据系统的实际应用需求,从硬件电路以及软件程序两个方面展开房间湿度控制系统设计。如图所示为系统的整体架构图。系统采用单片机作为控制器,在传感器检测模块中包括DHT11温湿度检测、有害气体浓度检测,在系统执行模块包括加…...
docker 使用 xz save 镜像
适用场景 如果docker save -o xxx > xxx 镜像体积过大,可以使用 xz 命令压缩。 命令 例如 save busybox:1.31.1 镜像,其中 -T 是使用多核心压缩,可以加快压缩。 docker save busybox:1.31.1 |xz -T 8 > /tmp/busybox:1.31.1安装 xz Ubuntu/Debian sudo apt upda…...
Dockerfile文件编写
目录 Dockerfile文件编写 1.什么是Dockerfile 2. Dockerfile作用 3.dockerfile 的基本结构: 4.dockerfile指令: FROM 指定基础镜像,dockerfile构建镜像的第一个指令 LABEL 指定镜像维护人信息 ADD/COPY 复制本地文件/目录到镜像中 …...
linux高性能服务器编程读书笔记目录建议
linux高性能服务器编程读书笔记目录&&建议 文章目录 linux高性能服务器编程读书笔记目录&&建议目录第一篇 TCP/IP协议详解第二篇 深入解析高性能服务器编程第三篇 高性能服务器优化与监测 自己总结的内容linux这本书上没有但是黑马上有的东西epoll反应堆模型本…...
java全栈day20--Web后端实战(Mybatis基础2)
一、Mybatis基础 1.1辅助配置 配置 SQL 提示。 默认在 mybatis 中编写 SQL 语句是不识别的。可以做如下配置: 现在就有sql提示了 新的问题 产生原因: Idea 和数据库没有建立连接,不识别表信息 解决方式:在 Idea 中配置 MySQL 数…...
页面加载速度优化策略:提升用户体验的关键
文章目录 前言一、为什么需要优化页面加载速度?二、前端优化技术三、后端优化策略四、构建与部署优化五、案例研究:实际效果展示结语 前言 在当今快节奏的互联网环境中,页面加载速度不仅是用户体验的重要组成部分,更是影响网站性…...
多模块程序的测试策略
例1.如图“自顶向下”: 采用广度优先:模块M1结合模块M2,M3和M4,然后再结合下一控制层中的模块M5,M6和M7,继续下去直到所有模块结合近来。 混合策略: 改进的自顶向下测试方法 基本上使用自顶向下的测试方法…...
聚水潭数据无缝集成到金蝶云星空的实现方案
聚水潭数据集成到金蝶云星空:聚水潭调拨对接金蝶直接调拨ok 在企业信息化管理中,数据的高效流动和准确对接是实现业务流程顺畅运行的关键。本文将分享一个具体的系统对接集成案例——如何通过轻易云数据集成平台,将聚水潭的数据无缝集成到金…...
electron打包linux环境
注意:新版的electron已经不支持在win上直接打包Linux的环境了,服务会卡住,会一直生成文件占用磁盘(我发现的时候占了我100G,而且文件夹很深,找了java代码while循环,好不容易删除的o(╥﹏╥)o) electron有一个专门打包的docker镜像,…...
设计模式--单例模式【创建型模式】
设计模式的分类 我们都知道有 23 种设计模式,这 23 种设计模式可分为如下三类: 创建型模式(5 种):单例模式、工厂方法模式、抽象工厂模式、建造者模式、原型模式。结构型模式(7 种)࿱…...
Mybatis分页插件的使用问题记录
项目中配置的分页插件依赖为 <dependency><groupId>com.github.pagehelper</groupId><artifactId>pagehelper</artifactId><version>5.1.7</version></dependency>之前的项目代码编写分页的方式为,通过传入的条件…...
BERTective: Language Models and Contextual Information for Deception Detection
目录 概要 实验设置 数据集 实验条件 指标和基准 实验方法 神经网络基准 基于transformer的模型 基于BERT的模型 实验结果 分析 非上下文化模型 上下文化模型 欺骗语言 讨论 结论 概要 本文基于一组包含虚假陈述的意大利对话语料库,建立了一种新的…...
python 配置 oracle instant client
1.问题描述 想用python连接oracle数据库,百度得知需要cx_Oracle这个第三方库 import cx_Oracle# 设置Oracle数据源名称 dsn cx_Oracle.makedsn(host, port, service_nameservice_name)# 创建数据库连接 connection cx_Oracle.connect(userusername, passwordpas…...
【C语言】一文讲通 和*
&和*详解 前言符号 &:取地址符& 的用法& 用于函数参数传递 符号 *:解引用符* 的用法* 用于指针的初始化 结合使用 & 和 *1. * 和 & 配合使用示例 常见错误与注意事项总结 前言 在 C 语言中,* 和 & 是两个非常重…...
编译原理复习---基本概念+推导树
适用于电子科技大学编译原理期末考试复习。 本文只适合复习不适合预习,即适合上课听过一点或自己学过一点的同学。 1. 编译原理概述 编译原理是计算机科学的一个重要分支,它涉及将高级编程语言编写的源代码转换为机器能够理解和执行的低级代码的过程。…...