当前位置: 首页 > news >正文

记录学习《手动学习深度学习》这本书的笔记(五)

这一章是循环神经网络,太难了太难了,有很多卡壳的地方理解了好久,比如隐藏层和隐状态的区别、代码的含义(为此专门另写了一篇【笔记】记录对自主实现一个神经网络的步骤的理解)、梯度计算相关(【笔记】记录对python中.grad()的一些理解)。

第八章:循环神经网络

8.1 序列模型

之前介绍了卷积神经网络,了解了怎么将空间结构融入模型,这一章的循环神经网络就是介绍如何将时间序列结构融入模型当中。

通常,在一个有序列结构的模型预测中,对于下一个时间步我们是按:x_{t} \sim P\left \{ x_{t} | x_{t-1} , ... x_{1}\right \}来预测的。

但是这样的话,随着预测步数的推进,复杂度会上升得非常快,所以我们需要想出一些解决方法。

我们想出的方法(自回归模型)有两种:

  • 一种叫自回归模型,是规定取预测步数之前的 \tau 个步数对当前预测步数进行预测,也就是说不需要从 t 步取回第 1 步了,只需要从t步取到第 t-\tau 步,x_{t} \sim P\left \{ x_{t} | x_{t-1} , ... x_{t-\tau }\right \}
  • 一种叫隐变量自回归模型,是我们后面会一直介绍的方法,将第 t 步之前步数的数据用一个隐状态 h_{t} 表示然后预测下一步 t+1 时只要将 h_{t} 和 x_{t+1} 进行线性变化组合得到 h_{t+1} 再用 h_{t+1} 预测第 t+1 步。

 这一章初步实现了一个简单的自回归模型,利用sin函数加一些随机误差生成数据,再利用自回归模型进行训练预测。

内插法是根据现有数据预测单个步的数据,预测数据来自现有数据。

外推法是根据现有数据不断推出后面的数据,每步根据前几步预测出来的数据对未来进行预测。

实验结果表明内推法难度更小,准确率也更高。而外推法得到的结果非常容易偏离正确值,因为预测的错误容易“累计”,不断预测非常容易偏离实际结果。

实验使用k步预测,由k步之前的数据预测第k步的数据,跨度为k,实验结果表明随着k的增加,错误会积累得越多,预测质量急剧下降。

8.2 文本预处理

我们选取《时光机器》中的文本数据。

提取文本步骤包括:

  1. 将文本作为字符串加载到内存中。
  2. 将字符串拆分为词元
  3. 建立词表将词元映射为数字索引
  4. 将文本转换为数字索引

第1步:

#@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()

读取数据,将除了字母以外的字符转为空格(re.sub()正则匹配),去除首位空格(.strip()),将大写转为小写(.lower())

第2步:

将文本行继续拆分为单个词元。

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('错误:未知词元类型:' + token)tokens = tokenize(lines)
for i in range(11):print(tokens[i])

这个函数实现了拆分单词和拆分字母两种方式,默认拆分单词。

返回一些列表,每个列表代表一行,每一行有若干个单词(或字母)。

第3步:

这一步要将词元构成字典的形式,建立一个class类,需要实现将输入的词元匹配上一个对应的数字索引。

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)# 未知词元的索引为0self.idx_to_token = ['<unk>'] + reserved_tokensself.token_to_idx = {token: idxfor idx, token in enumerate(self.idx_to_token)}for token, freq in self._token_freqs:if freq < min_freq:breakif token not in self.token_to_idx:self.idx_to_token.append(token)self.token_to_idx[token] = len(self.idx_to_token) - 1def __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]def to_tokens(self, indices):if not isinstance(indices, (list, tuple)):return self.idx_to_token[indices]return [self.idx_to_token[index] for index in indices]@propertydef unk(self):  # 未知词元的索引为0return 0@propertydef token_freqs(self):return self._token_freqsdef count_corpus(tokens):  #@save"""统计词元的频率"""# 这里的tokens是1D列表或2D列表if len(tokens) == 0 or isinstance(tokens[0], list):# 将词元列表展平成一个列表tokens = [token for line in tokens for token in line]return collections.Counter(tokens)

这个类大概是根据词元出现的频率排序,得出索引。

第4步:

执行:

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

就可以得到:

[('<unk>', 0), ('the', 1), ('i', 2), ('and', 3), ('of', 4), ('a', 5), ('to', 6), ('was', 7), ('in', 8), ('that', 9)]

执行:

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

就可以得到:

文本: ['the', 'time', 'machine', 'by', 'h', 'g', 'wells']
索引: [1, 19, 50, 40, 2183, 2184, 400]
文本: ['twinkled', 'and', 'his', 'usually', 'pale', 'face', 'was', 'flushed', 'and', 'animated', 'the']
索引: [2186, 3, 25, 1044, 362, 113, 7, 1421, 3, 1045, 1]

整合以上功能:

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, vocabcorpus, vocab = load_corpus_time_machine()
len(corpus), len(vocab)

加载数据,切分为字母,构造词典,整合成一个大列表,可选择是否取前max_tokens个字母。

8.3 语言模型和数据集

在构建模型之前,我们要了解一些关于自然语言处理的相关知识。

基本概率规则:比如 P(我想你) = P(你|我,想)P(想|我)P(我) ,为了得出一个句子的概率,我们需要知道单词出现的概率,以及单词在前几个单词出现的情况下出现的概率。

假设我们有一个非常大的语料库,对于上面式子的条件概率,我们可以通过 P(想|我) = P(我想) / P(我) 得到。

但是对于一些不常见的组合,语料库中出现的概率可能是零,于是就要利用拉普拉斯平滑,使所有语料库中没有出现过的组合概率不为零。

进行自然语言统计时,我们将之前的数据中频率最高的词汇打印出来,发现很多都是the、of、and之类的停用词,并且前几个出现的概率比后面的概率要高很多。

打印出图像可以看出词频从某个临界点开始就下降得特别快。

这意味着单词频率符合齐鲁夫定律。

如果采用之前的平滑方法,尾部数量就会大增。

我们再统计两个词汇组成的词组出现的频率、三个词汇组成的词组出现的频率:

可以看出都是这种情况。

说明拉普拉斯平滑并不适合语言建模,很多n元组很少出现,所以我们使用深度学习模型。

我们读取长序列数据,生成小批量数据作为特征,然后移动生成它的标签。

1.随机抽样:

def seq_data_iter_random(corpus, batch_size, num_steps):  #@save"""使用随机抽样生成一个小批量子序列"""# 从随机偏移量开始对序列进行分区,随机范围包括num_steps-1corpus = corpus[random.randint(0, num_steps - 1):]# 减去1,是因为我们需要考虑标签num_subseqs = (len(corpus) - 1) // num_steps# 长度为num_steps的子序列的起始索引initial_indices = list(range(0, num_subseqs * num_steps, num_steps))# 在随机抽样的迭代过程中,# 来自两个相邻的、随机的、小批量中的子序列不一定在原始序列上相邻random.shuffle(initial_indices)def data(pos):# 返回从pos位置开始的长度为num_steps的序列return corpus[pos: pos + num_steps]num_batches = num_subseqs // batch_sizefor i in range(0, batch_size * num_batches, batch_size):# 在这里,initial_indices包含子序列的随机起始索引initial_indices_per_batch = initial_indices[i: i + batch_size]X = [data(j) for j in initial_indices_per_batch]Y = [data(j + 1) for j in initial_indices_per_batch]yield np.array(X), np.array(Y)my_seq = list(range(35))
for X, Y in seq_data_iter_random(my_seq, batch_size=2, num_steps=5):print('X: ', X, '\nY:', Y)

生成特征和标签:

X:  [[22. 23. 24. 25. 26.][27. 28. 29. 30. 31.]]
Y: [[23. 24. 25. 26. 27.][28. 29. 30. 31. 32.]]
X:  [[ 7.  8.  9. 10. 11.][12. 13. 14. 15. 16.]]
Y: [[ 8.  9. 10. 11. 12.][13. 14. 15. 16. 17.]]
X:  [[17. 18. 19. 20. 21.][ 2.  3.  4.  5.  6.]]
Y: [[18. 19. 20. 21. 22.][ 3.  4.  5.  6.  7.]]

2.顺序分区:

def seq_data_iter_sequential(corpus, batch_size, num_steps):  #@save"""使用顺序分区生成一个小批量子序列"""# 从随机偏移量开始划分序列offset = random.randint(0, num_steps)num_tokens = ((len(corpus) - offset - 1) // batch_size) * batch_sizeXs = np.array(corpus[offset: offset + num_tokens])Ys = np.array(corpus[offset + 1: offset + 1 + num_tokens])Xs, Ys = Xs.reshape(batch_size, -1), Ys.reshape(batch_size, -1)num_batches = Xs.shape[1] // num_stepsfor i in range(0, num_steps * num_batches, num_steps):X = Xs[:, i: i + num_steps]Y = Ys[:, i: i + num_steps]yield X, Yfor X, Y in seq_data_iter_sequential(my_seq, batch_size=2, num_steps=5):print('X: ', X, '\nY:', Y)

生成特征和标签:

X:  [[ 0.  1.  2.  3.  4.][17. 18. 19. 20. 21.]]
Y: [[ 1.  2.  3.  4.  5.][18. 19. 20. 21. 22.]]
X:  [[ 5.  6.  7.  8.  9.][22. 23. 24. 25. 26.]]
Y: [[ 6.  7.  8.  9. 10.][23. 24. 25. 26. 27.]]
X:  [[10. 11. 12. 13. 14.][27. 28. 29. 30. 31.]]
Y: [[11. 12. 13. 14. 15.][28. 29. 30. 31. 32.]]

将两种方法打包:

class SeqDataLoader:  #@save"""加载序列数据的迭代器"""def __init__(self, batch_size, num_steps, use_random_iter, max_tokens):if use_random_iter:self.data_iter_fn = d2l.seq_data_iter_randomelse:self.data_iter_fn = d2l.seq_data_iter_sequentialself.corpus, self.vocab = d2l.load_corpus_time_machine(max_tokens)self.batch_size, self.num_steps = batch_size, num_stepsdef __iter__(self):return self.data_iter_fn(self.corpus, self.batch_size, self.num_steps)
def load_data_time_machine(batch_size, num_steps,  #@saveuse_random_iter=False, max_tokens=10000):"""返回时光机器数据集的迭代器和词表"""data_iter = SeqDataLoader(batch_size, num_steps, use_random_iter, max_tokens)return data_iter, data_iter.vocab

8.4 循环神经网络

循环神经网络将按照之前说的隐状态自回归模型,每一步根据上一步的状态h和当前读取数据进行预测。

隐状态H的作用是保留前面步的历史信息,相当于记忆一样。

这里书中提示了隐状态和隐藏层是不同的,想了老半天为什么,直到看到老师的ppt才懂:

其实两者指的是差不多的东西,只不过隐藏层是指那个层(箭头),而隐状态是指那个层输出的状态(h)。

没有隐状态就是普通神经网络,输入x输出y,中间的隐藏层不和前面的输入有关。

有隐状态就是隐藏层结合了前一个h,输出的是隐状态h,记录的前面的历史数据。

然后值得一提的是所有时间步是共享参数的,也就是h_{2}的计算和h_{3}是类似的这使得循环神经网络的开销不会随着预测步数的增大而增大。

预测值y的计算如下:

y_{t} = H_{t} W_{hq} + b_{q}

隐状态h的计算如下:

H_{t} = \phi (X_{t} W_{xh} + H_{t-1}W_{hh} + b_{h})

循环神经网络对于每个批量(比如you ar)和它的标签(ou are),对每个小批量(一个或多个字母)执行上述计算操作,这样就可以推出下一个字母,如此反复。

由上述隐状态的公式可以看出,我们可以将上一个隐状态和这一个输入横向合并(物理),将权重W纵向合并(物理),两者相乘加b得到的也是同样结果。

最后来看评判模型好坏的困惑度,就是判断这个字母在这个位置出现的合理性(概率),可以用如下方法计算:

\frac{1}{n}\prod_{n}^{t = 1}P(x_{t} | x_{t-1}, x_{t-2} ... x_{1})

累乘会导致数字过大或者过小,于是将其取对数:

exp(\frac{1}{n}\sum_{n}^{t = 1}-log P(x_{t} | x_{t-1}, x_{t-2} ... x_{1}))

这就是困惑度。最好情况为1,最坏情况为正无穷大。

8.5 循环神经网络的从零开始实现

这一节单独放在【笔记】记录对自主实现一个神经网络的步骤的理解里了,只需再介绍一个独热编码的实现:

F.one_hot(torch.tensor([0, 2]), len(vocab))

对0,1两个数字独热编码,长度为字母表长度。

运行结果是:

tensor([[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0],[0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0]])

如果传入的是数组,也可以给出对应独热编码,结果上升一个维度。

8.6 循环神经网络的简洁实现

这一章我们构建一个隐藏单元为256的单隐藏层循环神经网络。

像之前那样读取数据:

batch_size, num_steps = 32, 35
train_iter, vocab = d2l.load_data_time_machine(batch_size, num_steps)

定义模型:

num_hiddens = 256
rnn_layer = nn.RNN(len(vocab), num_hiddens)

要注意的是,nn.RNN不是整个循环神经网络,而是只是隐藏层这部分,输出的是隐藏层的预测数据,我们还需要实现从隐状态到最后输出层的代码。

初始化隐状态:

state = torch.zeros((1, batch_size, num_hiddens))
state.shape

由于nn.RNN只包含隐藏层,我们还需要建输出层,并将两个层合并成一个完整的循环神经网络:

#@save
class RNNModel(nn.Module):"""循环神经网络模型"""def __init__(self, rnn_layer, vocab_size, **kwargs):super(RNNModel, self).__init__(**kwargs)self.rnn = rnn_layerself.vocab_size = vocab_sizeself.num_hiddens = self.rnn.hidden_size# 如果RNN是双向的(之后将介绍),num_directions应该是2,否则应该是1if not self.rnn.bidirectional:self.num_directions = 1self.linear = nn.Linear(self.num_hiddens, self.vocab_size)else:self.num_directions = 2self.linear = nn.Linear(self.num_hiddens * 2, self.vocab_size)def forward(self, inputs, state):X = F.one_hot(inputs.T.long(), self.vocab_size)X = X.to(torch.float32)Y, state = self.rnn(X, state)# 全连接层首先将Y的形状改为(时间步数*批量大小,隐藏单元数)# 它的输出形状是(时间步数*批量大小,词表大小)。output = self.linear(Y.reshape((-1, Y.shape[-1])))return output, statedef begin_state(self, device, batch_size=1):if not isinstance(self.rnn, nn.LSTM):# nn.GRU以张量作为隐状态return  torch.zeros((self.num_directions * self.rnn.num_layers,batch_size, self.num_hiddens),device=device)else:# nn.LSTM以元组作为隐状态return (torch.zeros((self.num_directions * self.rnn.num_layers,batch_size, self.num_hiddens), device=device),torch.zeros((self.num_directions * self.rnn.num_layers,batch_size, self.num_hiddens), device=device))

类接收一个隐藏层,词汇表大小作为参数,初始化传入参数,并且设置线性层作为由隐状态到输出的函数。

前向传播连接两个函数,先对输入进行独热编码,然后依次放入隐藏层和线性层中计算输出,输出为当前状态和当前输出。

begin_state函数初始化状态,每次新一轮预测就调用这个函数。

实现完整个模型,然后就可以将模型代入之前实现的预测和训练函数。

预测:

device = d2l.try_gpu()
net = RNNModel(rnn_layer, vocab_size=len(vocab))
net = net.to(device)
d2l.predict_ch8('time traveller', 10, net, vocab, device)

训练:

num_epochs, lr = 500, 1
d2l.train_ch8(net, train_iter, vocab, lr, num_epochs, device)

8.7 通过时间反向传播

这一节分析了循环神经网络的梯度传播。

画出流程图可以看出,越后面的步需要回溯越多,这也是循环神经网络容易梯度爆炸和梯度消失的原因。

对此,我们可以不进行完整计算,而是使用截断时间步减少梯度复杂度,可以采用随机截断或常规截断的方法(一般使用的是常规截断)。

这一节主要是在用链式计算第t步的梯度公式。

相关文章:

记录学习《手动学习深度学习》这本书的笔记(五)

这一章是循环神经网络&#xff0c;太难了太难了&#xff0c;有很多卡壳的地方理解了好久&#xff0c;比如隐藏层和隐状态的区别、代码的含义&#xff08;为此专门另写了一篇【笔记】记录对自主实现一个神经网络的步骤的理解&#xff09;、梯度计算相关&#xff08;【笔记】记录…...

鸿蒙调试打包(非正式打包)

文章目录 前言第一步&#xff1a;生成.p12和.csr文件第二步&#xff1a;申请证书的前置步骤第三步&#xff1a;申请证书 前言 HarmonyOS 应用打包后的文件为.app 格式&#xff0c; android 打包后的文件为.apk&#xff0c;IOS 打包后的文件为.apa HarmonyOS通过数字证书&#…...

Python中的容器化服务监控:结合Prometheus和Grafana实现高效监控与可视化

《Python OpenCV从菜鸟到高手》带你进入图像处理与计算机视觉的大门! 解锁Python编程的无限可能:《奇妙的Python》带你漫游代码世界 在现代的DevOps和微服务架构中,容器化技术(如Docker)已成为主流的部署方式。然而,容器环境的动态特性使得服务监控和性能分析变得更加复…...

【大数据】-- 读放大和写放大

目录 一、定义 1. 读放大(Read Amplification) 定义 原因 优化方法 2. 写放大(Write Amplification) 定义 原因 优化方法 对比与联系 二、举例 1. Hadoop(HDFS) 读放大 写放大 2. Flink 读放大 写放大 3. Hive 读放大 写放大 4. Presto 读放大 写放…...

[工具升级问题] 钉钉(linux版)升级带来的小麻烦

本文由Markdown语法编辑器编辑完成。 1. 背景: 今日钉钉又发布了新的升级版本。由于我工作时使用的是Ubuntu 20.04版本&#xff0c;收到的升级推送信息是&#xff0c;可以升级到最新的7.6.25-Release版本。根据钉钉官方给出的历次更新版说明&#xff0c;这个新的版本&#xf…...

Maven学习(Maven项目模块化。模块间“继承“机制。父(工程),子项目(模块)间聚合)

目录 一、Maven项目模块化&#xff1f; &#xff08;1&#xff09;基本介绍。 &#xff08;2&#xff09;汽车模块化生产再聚合组装。 &#xff08;3&#xff09;Maven项目模块化图解。 1、maven_parent。 2、maven_pojo。 3、maven_dao。 4、maven_service。 5、maven_web。 6…...

Opencv之图像添加水印

一、实验原理 在图片处理领域&#xff0c;添加水印是一种常见的操作。通过叠加图像的方式&#xff0c;可以将水印无缝嵌入目标图像的指定位置。其基本原理包括以下步骤&#xff1a; 1、模板输入&#xff08;掩膜生成&#xff09;&#xff1a; 将水印图片转换为灰度图&#xf…...

在线预约陪诊小程序

一、前言 随着社会老龄化加剧以及人们健康意识的提高&#xff0c;就医过程中的陪伴需求日益增长。许多患者在面对复杂的医院环境、繁琐的就医流程时&#xff0c;需要有人协助挂号、候诊、取药等&#xff0c;而家属可能因工作繁忙无法全程陪同。同时&#xff0c;异地就医的患者更…...

2024年9月CCF GESP Scratch图形化编程等级考试四级真题试卷

GESP 图形化四级试卷&#xff08;A&#xff09; &#xff08;满分&#xff1a;100 分 考试时间&#xff1a;120 分钟&#xff09; 一、单选题&#xff08;共 10 题&#xff0c;每题 2 分&#xff0c;共 30 分&#xff09; 1、2024 年 10 月 8 日&#xff0c;诺贝尔物理学奖“意…...

[免费]SpringBoot+Vue校园社团管理系统(优质版)【论文+源码+SQL脚本】

大家好&#xff0c;我是java1234_小锋老师&#xff0c;看到一个不错的SpringBootVue校园社团管理系统(优质版)&#xff0c;分享下哈。 项目视频演示 【免费】SpringBootVue校园社团管理系统(优质版) Java毕业设计_哔哩哔哩_bilibili 项目介绍 随着信息技术的迅速发展&#x…...

NX系列-使用 `nmcli` 命令创建 Wi-Fi 热点并设置固定 IP 地址

使用 nmcli 命令创建 Wi-Fi 热点并设置固定 IP 地址 一、前言 在一些场景下&#xff0c;我们需要将计算机或嵌入式设备&#xff08;例如 NVIDIA Orin NX&#xff09;转换为 Wi-Fi 热点&#xff0c;以便其他设备&#xff08;如手机、笔记本等&#xff09;能够连接并使用该设备…...

Qt控件的盒子模型,了解边距边线和内容区

这篇专门讲讲一个控件在绘制时的视觉样式。我们平常在对控件设置样式时&#xff0c;需要设置控件的一些外边距&#xff0c;内边距&#xff0c;边线&#xff0c;还有文字内容&#xff0c;贴上图片等。那么对于一个控件&#xff0c;到底怎么实现这些设置的呢&#xff1f; 先看下面…...

深度学习基础--将yolov5的backbone模块用于目标识别会出现怎么效果呢??

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 前言 yolov5网络结构比较复杂&#xff0c;上次我们简要介绍了yolov5网络模块&#xff0c;并且复现了C3模块&#xff0c;深度学习基础–yolov5网络结构简介&a…...

MySQL 根据 字段包含关键词进行分类

为了解决动态关键词匹配的需求&#xff0c;我们需要创建一个关键词表&#xff08;keywords_table&#xff09;&#xff0c;其中存储关键词和对应的类别。以下是具体的步骤&#xff1a; 1. 创建关键词表 可以用以下 SQL 创建一个简单的关键词表&#xff1a; CREATE TABLE keyw…...

ssm-day04 mybatis

mybatis是一个持久层框架&#xff0c;针对的是JDBC的优化 简化数据库操作&#xff0c;能进行单表、多表操作&#xff0c;在这个框架下&#xff0c;需要我们自己写SQL语句 Mapper接口和MapperXML文件就相当于Dao和Dao层的实现 通常将xml文件放在resources包下 &#xff0c;放在…...

soul大数据面试题及参考答案

如何看待数据仓库? 数据仓库是一个面向主题的、集成的、相对稳定的、反映历史变化的数据集合,用于支持管理决策。 从数据存储角度看,它整合了来自多个数据源的数据。这些数据源可能包括业务系统数据库、日志文件等各种结构化和非结构化数据。例如,在电商企业中,它会整合订…...

【SpringBoot中MySQL生成唯一ID的常见方法】

SpringBoot中MySQL生成唯一ID的常见方法 在Spring Boot中&#xff0c;为MySQL生成唯一ID有多种方式&#xff0c;每种方式都有其特定的概念、优越点和使用场景。以下是详细的说明和代码示例&#xff1a; UUID 概念: UUID&#xff08;Universally Unique Identifier&#xff0…...

在 Windows 环境下将 Vue 项目打包并压缩为 .zip 文件的批处理脚本

以下是一个 Windows 批处理脚本&#xff0c;完成以下任务&#xff1a; 运行 npm run build 打包 Vue 项目。使用 7-Zip 将生成的 dist 目录压缩成 ZIP 文件。 脚本内容 echo off:: 切换命令行编码为 UTF-8 chcp 65001 >nul:: 设置环境变量 set PROJECT_DIRC:\path\to\you…...

ubuntu上更改ext4格式的硬盘为 windows的 NTFS 格式参考

1. ubuntu上安装 sudo apt-get install gparted 2. 参考如下&#xff0c;下面是转换后的样例。 3.windows上添加识别新硬盘参考 先在设备管理器中 找到下面 磁盘管理 如下&#xff1a;找到类似下面的磁盘2 查看相关信息 右键可以新建卷和格式化&#xff0c;下面是已经新建…...

Qt WORD/PDF(二)使用 QtPdfium库实现 PDF操作、打印等

关于QT Widget 其它文章请点击这里: QT Widget GitHub 源码: QWidgetLearningPro &#xff08;暂未更新&#xff09; 姊妹篇: Qt WORD/PDF&#xff08;一&#xff09;使用 QtPdfium库实现 PDF 操作 Qt WORD/PDF&#xff08;二&#xff09;使用 QtPdfium库实现 …...

信息化基础知识——数字政府(山东省大数据职称考试)

大数据分析应用-初级 第一部分 基础知识 一、大数据法律法规、政策文件、相关标准 二、计算机基础知识 三、信息化基础知识 四、密码学 五、大数据安全 六、数据库系统 七、数据仓库. 第二部分 专业知识 一、大数据技术与应用 二、大数据分析模型 三、数据科学 数字政府 大数…...

使用winscp从windows访问Ubuntu进行文件传输

Ubuntu 系统上的准备工作 • 安装 SSH 服务器&#xff1a; 确保 Ubuntu 系统上已经安装了 SSH 服务器。如果没有安装&#xff0c;可以使用以下命令安装&#xff1a; sudo apt update sudo apt install openssh-server • 启动 SSH 服务&#xff1a; 确保 SSH 服务正在运行&a…...

【返璞归真】score检验:似然比的得分检验(Likelihood Ratio Score Test)

Score检验&#xff08;Score Test&#xff09;是一种用于假设检验的方法&#xff0c;特别是在统计建模中&#xff0c;常用于估计模型参数时检验某个假设是否成立。它的全名是“似然比的得分检验”&#xff08;Likelihood Ratio Score Test&#xff09;&#xff0c;通常用于大样…...

使用skywalking,grafana实现从请求跟踪、 指标收集和日志记录的完整信息记录

Skywalking是由国内开源爱好者吴晟开源并提交到Apache孵化器的开源项目&#xff0c; 2017年12月SkyWalking成为Apache国内首个个人孵化项目&#xff0c; 2019年4月17日SkyWalking从Apache基金会的孵化器毕业成为顶级项目&#xff0c; 目前SkyWalking支持Java、 .Net、 Node.js、…...

蓝桥杯刷题——day1

蓝桥杯刷题——day1 题目一题干题目解析代码 题目二题干题目解析代码 题目一 题干 给定一个字符串 s &#xff0c;验证 s 是否是 回文串 &#xff0c;只考虑字母和数字字符&#xff0c;可以忽略字母的大小写。本题中&#xff0c;将空字符串定义为有效的 回文串 。 题目链接&a…...

ORACLE RAC ADG备库报错ORA-04021: timeout occurred while waiting to lock object

问题&#xff1a;核心的灾备 RAC ADG 备库&#xff0c;这两天频繁重启&#xff0c;并且报如下错误&#xff0c;通过查看MOS&#xff0c;发现是个BUG ADG备库的ALERT错误日志如下&#xff1a; Errors in file /u01/app/oracle/diag/rdbms/hxxxsz/hxxxsz1/trace/hxxxsz1_lgwr_69…...

虚拟机Ubuntu以及pwn的工具安装

之前pwn入门在kali上装了&#xff0c;师兄说用Ubuntu会比kali好得多&#xff0c;更有利于pwn的学习&#xff0c;本着少走弯路的想法我就决定装一个&#xff0c;再把工具什么的配了 一、Ubuntu的安装 参考博客及镜像来源&#xff1a;VMware虚拟机安装Ubuntu教程(超详细)_vmwar…...

MeiliSearch:一款轻量级开源搜索引擎

Meilisearch 是由 Meili &#xff08;一家总部位于法国的软件开发公司&#xff09;创建的搜索引擎&#xff0c;目前在 Github 上有 47.9k stars。 Meillisearch 具备以下特色功能&#xff08;ChatGPT-4o 翻译&#xff09;&#xff1a; 混合搜索&#xff1a;结合语义搜索和全文…...

数据库入门

基本概念 数据库&#xff1a;DataBase简称DB&#xff0c;是一个用于存储和管理数据的仓库。 就像我们每天访问的网站Bilibili&#xff0c;OA、ERP和CRM等内部管理系统&#xff0c;以及我们每天使用的腾讯新闻和Tiktok应用程序一样&#xff0c;我们看到的数据实际上存储在数据库…...

WebGIS城市停水及影响范围可视化实践

目录 前言 一、相关信息介绍 1、停水信息的来源 2、停水包含的相关信息 二、功能简介 1、基础小区的整理 2、停水计划的管理 三、WebGIS空间可视化 1、使用到的组件 2、停水计划的展示 3、影响小区的展示 4、实际效果 四、总结 前言 城市停水&#xff0c;一个看似…...

【Syncfusion系列】Diagram 杂谈 第三篇 序列化和反序列化

目录 序列化保存C# 代码示例&#xff0c; 方式1 &#xff1a;C# 代码示例&#xff0c; 方式2 &#xff1a; 反序列化加载C# 代码示例, 方式1&#xff1a;C# 代码示例, 方式2&#xff1a; **如何序列化自定义属性**序列化和反序列化都存在的一个问题解决方式 图表是否已修改&…...

#思科模拟器通过服务配置保障无线网络安全Radius

演示拓扑图&#xff1a; 搭建拓扑时要注意&#xff1a; 只能连接它的Ethernet接口&#xff0c;不然会不通 MAC地址绑定 要求 &#xff1a;通过配置MAC地址过滤禁止非内部员工连接WiFi 打开无线路由器GUI界面&#xff0c;点开下图页面&#xff0c;配置路由器无线网络MAC地址过…...

Repo管理

文章目录 前言Repo介绍清单仓库清单仓库的组成 初始化Repo同步远程仓库Repo实际应用 前言 我们知道&#xff0c;Git是用来管理某一个仓库&#xff0c;那当一个项目用到了多个仓库时&#xff0c;怎么来同步管理这些仓库呢&#xff1f;这个时候就可以引入Repo管理。 Repo介绍 …...

代码随想录算法训练营第四十八/九天 | 图 | 深度搜索 | 广度搜索

Day 48 49 总结 自己实现中遇到哪些困难今日收获&#xff0c;记录一下自己的学习时间 11:40 - 14:3012:30 - 13:30, 14:45 - 17:10 图论 深度收缩 & 广度搜索 并查集 最小生成树 拓扑排序 最短路径算法 图论基础 图 二维空间里&#xff0c;多个点之间相互连接图的…...

JavaEE初阶——多线程(线程安全-锁)

复习上节内容&#xff08;部分-掌握程度不够的&#xff09; 加锁&#xff0c;解决线程安全问题。 synchronized关键字&#xff0c;对锁对象进行加锁。 锁对象&#xff0c;可以是随便一个Object对象&#xff08;或者其子类的对象&#xff09;&#xff0c;需要关注的是&#xff…...

搭建大语言模型

安装和配置Ollama 首先在官网上下载Ollama&#xff0c;同时支持window&#xff0c;linux&#xff0c;macos系统。 下载下来是一个压缩包&#xff0c;直接解压缩即可&#xff0c;然后点击安装程序开始安装。 linux下载 执行以下命令&#xff0c;即可自动下载安装&#xff0c…...

QT6 Socket通讯封装(TCP/UDP)

为大家分享一下最近封装的以太网socket通讯接口 效果演示 如图&#xff0c;界面还没优化&#xff0c;后续更新 废话不多说直接上教程 添加库 如果为qmake项目中&#xff0c;在.pro文件添加 QT network QT core gui QT networkgreaterThan(QT_MAJOR_VERS…...

Linux中 vim 常用命令大全详细讲解

文章目录 前言一、Vim 基本操作 &#x1f579;️1.1 打开或创建1.2 退出编辑1.3 模式切换 二、Vim 光标移动命令 ↕️2.1 基本移动2.2 行内移动2.3. 单词移动2.4. 页面移动2.5. 行跳转 三、Vim 文本编辑命令 &#x1f4cb;3.1 插入和删除3.2 复制、剪切与粘贴3.3 替换与修改 四…...

vs 调试

常用&#xff1a; 调试->窗口-> 断点 监视 自动窗口 局部变量 调用堆栈 内存 反汇编&#xff08;也可以右键&#xff0c;转到反汇编&#xff09; 寄存器 快捷键&#xff1a; F5:启用调试&#xff0c;经常用来跳到下一个断点处 F9创建断点和取消断点。断点的重要作用&…...

使用 Kubernetes 部署 Redis 主从及 Sentinel 高可用架构(未做共享存储版)

文章目录 使用 Kubernetes 部署 Redis 主从及 Sentinel 高可用架构Redis 主从架构部署 (1.yaml)Redis Sentinel 部署 (2.yaml)Sentinel 服务暴露 (3.yaml)部署步骤总结 使用 Kubernetes 部署 Redis 主从及 Sentinel 高可用架构 本文将详细介绍如何在 Kubernetes 中部署 Redis …...

PLC网关,plc远程通信 —— 跨越距离远程控制运维升级

在日新月异的工业4.0时代&#xff0c;智能化、网络化已成为制造业转型升级的关键词。其中&#xff0c;PLC&#xff08;可编程逻辑控制器&#xff09;作为工业自动化控制的核心设备&#xff0c;其远程通信技术的突破&#xff0c;正引领着一场前所未有的工业变革。今天&#xff0…...

MySQL的历史和地位

秋招之后&#xff0c;开始深入学习后端开发知识啦。把学到的东西分享给大家最开心啦。就从MySQL开始吧。 首先说一下MySQL的历史和地位。主要是看一下我们为什么要学习&#xff0c;而不是说让我们学什么我们就学什么。 地位 这张图是我从DB-Engines截取的2024年12月最新的数据…...

Day12 洛谷 1320+1152+1615

零基础洛谷刷题记录 Day01 2024.11.18 Day02 2024.11.25 Day03 2024.11.26 Day04 2024.11.28 Day05 2024.11.29 Day06 2024 12.02 Day07 2024.12.03 Day08 2024 12 05 Day09 2024.12.07 Day10 2024.12.09 Day11 2024.12.10 Day12 2024.12.14 文章目录 零基础洛谷刷题记录1320&…...

四十六:如何使用Wireshark解密TLS/SSL报文?

TLS/SSL是保护网络通信的重要协议&#xff0c;其加密机制可以有效地防止敏感信息被窃取。然而&#xff0c;在调试网络应用或分析安全问题时&#xff0c;解密TLS/SSL流量是不可避免的需求。本文将介绍如何使用Wireshark解密TLS/SSL报文。 前提条件 在解密TLS/SSL报文之前&…...

【网络安全设备系列】7、流量监控设备

0x00 定义: 网络流量控制是一种利用软件或硬件方式来实现对电脑网络流量的控制。它的最主要方法&#xff0c;是引入QoS的概念&#xff0c;从通过为不同类型的 网络数据包标记&#xff0c;从而决定数据包通行的优先次序。 0x01 类型: 流控技术分为两种&#xff1a; 一种是…...

SpringCloud无介绍快使用,sentinel注解@SentinelResource的基本使用(二十三)

TOC 问题背景 从零开始学springcloud微服务项目 注意事项&#xff1a; 约定 > 配置 > 编码IDEA版本2021.1这个项目&#xff0c;我分了很多篇章&#xff0c;每篇文章一个操作步骤&#xff0c;目的是显得更简单明了controller调service&#xff0c;service调dao默认安装ngi…...

vue3 父组件调用子组件 el-drawer 抽屉

之前 Vue3 只停留在理论&#xff0c;现在项目重构&#xff0c;刚好可以系统的实战一下&#xff0c;下面是封装了一个抽屉表单组件&#xff0c;直接在父组件中通过调用子组件的方法打开抽屉&#xff1a; 父组件&#xff1a; <template><div id"app"><…...

JVM运行时数据区内部结构

VM内部结构 对于jvm来说他的内部结构主要分成三个部分&#xff0c;分别是类加载阶段&#xff0c;运行时数据区&#xff0c;以及垃圾回收区域&#xff0c;类加载我们放到之后来总结&#xff0c;今天先复习一下类运行区域 首先这个区域主要是分成如下几个部分 下面举个例子来解释…...

luckysheet与superslide冲突解决

[现象]控制台报错、界面无法操作 $是jquery。查看源码&#xff0c;发现mousewheel方法来自插件mousewheel&#xff0c;luckysheet初始应该会将mousewheel挂载在jquery上。 在控制台打印jquery取dom及其方法&#xff0c;结果如下&#xff1a; 不存在mousewheel方法&#xff0c…...

ubuntu环境调用onnxruntime找不到GPU的问题

问题&#xff1a; python安装好onnxruntime无法调用gpu。 通过如下代码测试&#xff0c;均为False。 import onnxruntime as ort# 检查ONNX Runtime是否支持CUDA def is_onnxruntime_cuda_supported():return ort.get_device() GPU# 检查ONNX Runtime是否使用CUDA def is_onn…...