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

NLP深度学习 DAY4:Word2Vec详解:两种模式(CBOW与Skip-gram)

用稀疏向量表示文本,即所谓的词袋模型在 NLP 有着悠久的历史。正如上文中介绍的,早在 2001年就开始使用密集向量表示词或词嵌入。Mikolov等人在2013年提出的创新技术是通过去除隐藏层,逼近目标,进而使这些单词嵌入的训练更加高效。虽然这些技术变更本质上很简单,但它们与高效的word2vec配合使用,便能使大规模的词嵌入训练成为可能。

0 前言:词袋模型

首先解释一下什么是词袋模型:

词袋模型(Bag-of-Words, BOW) 是最早、最经典的文本表示方法之一(1940左右出现,甚至比n-gram还要早,我愿称之为原始祖师爷)。它将一段文本看作一个「袋子」:里面盛放了这个文本所含的所有单词,但忽略了单词的顺序、句法结构等信息,只关注单词是否出现以及出现次数(或频率)。这就好比把句子里的单词都抓出来扔进一个袋子,摇匀后再数一数这些单词都有什么、各出现几次。

1.1 典型示例

假设我们的词表是 "I","like","apples","banana",大小 V=4(指的就是一共有4个词)。
有两句话:

  1. “I like apples”
  2. “I like banana apples”

那么在词袋表示下:

  • 对于 “I like apples”:

    1. "I" 出现 1 次
    2. "like" 出现 1 次
    3. "apples"出现 1 次
    4. "banana"出现 0 次
      向量表示可写作 [1, 1, 1, 0]
  • 对于 “I like banana apples”:

    1. "I" 出现 1 次
    2. "like" 出现 1 次
    3. "apples"出现 1 次
    4. "banana"出现 1 次
      向量表示可写作 [1, 1, 1, 1]

可以看到,这种表示只管词的出现情况,不会去记录 “banana”是在“apples”前还是后出现,也不会记录它们之间的距离。这样就得到最纯粹的词袋表示。

一、词向量引入

先来考虑一个问题:如何能将文本向量化呢?听起来比较抽象,我们可以先从人的角度来思考。

如何用一个数值向量描述一个人呢?只用身高或者体重,还是综合其各项指标呢?当然是综合各项指标能更加准确的描述一个人啦,具体什么指标还得看你能收集到什么指标。比如除了常规的身高、体重外,我们还可以用人的性格,从内向到外向设置为从-1到+1,人的性格让“专家”去打分,从而获取人性格的数值化数据。

只要有了向量,就可以用不同方法(欧氏距离、曼哈顿距离、切比雪夫距离、余弦相似度等)来计算两个向量之间的相似度了!

                      

通常来说,向量的维度越高,能提供的信息也就越多,从而计算结果的可靠性就更值得信赖

 现在回到正题,如何描述词的特征?通常都是在词的层面上来构建特征。Word2Vec就是要把词转化为向量。

下图展示了一个50维的词向量:

 假设现在已经拿到了一份训练好的词向量,其中每一个词都表示为50维的向量,如下图所示:

 如果将它们在热度图中显示,结果如下:

 在结果中可以发现,相似的词在特征表达中比较相似,也就是说明词的特征是有实际意义的!

                     

二、词向量模型

在词向量模型中输入和输出是什么?中间这个黑盒又是什么?

如下图所示,在词向量模型中,输入可以是多个词。例如下面所示的,输入是 Thou 和 shalt,模型的任务是预测它们的下一个词是什么。

早期的神经网络的词嵌入方法(word2vec出现之前使用n-gram去训练原始词表里面的300维向量 差不多2001年)

最后一层连接了 SoftMax,所以网络的输出是所有词可能是下一个词的概率。

             

那么有人就会问了,输入是文字,文字怎么输入到神经网络中啊 ?这个问题很好,我们通常会用一个 Embedding 层来解决这个问题。如下图所示,在神经网络初始化的时候,我们会随机初始化一个 N×K 的矩阵,其中 N 是 词典的大小,K 是词向量的维数(一个自行设定的超参数)。然后,我们会用一个 N×N 的矩阵和 N×K 的矩阵相乘,得到一个新的 N×K的矩阵向下进行前向传播。其中,N×N 的矩阵会在输入的文字的对应对角线上设置为1,其余位置均为0。N×K 的矩阵是随机初始化的,通过反向传播进行更新调整。

          

 下面展示了一个例子(假设输入的两个词在词典中的位置是2和3处):

          

三、训练数据构建(还是早期的n-gram模型)

问:我们的训练数据应该从哪找呢?

答:一切具有正常逻辑的语句都可以作为训练数据。如小说、论文等。

如果我们有一个句子,那么我们可以按照下面你的方式构建数据集,选出前三个词,用前两个作为词模型的输入,最后一个词作为词模型输出的目标,继而进行训练。如下图所示: 

 然后,我们还可以将”窗口“往右平移一个词,如下图所示,构造一个新的训练数据

当然,这个”窗口“的宽度也是可以自己设置的,在上例中,窗口宽度设置为 3,也可以设置为 4、5、6 等等

四、Word2vec(2013年)不同模型对比

4.1 CBOW

CBOW的全称是continuous bag of words(连续词袋模型)。其本质也是通过context word(背景词)来预测target word(目标词)。

CBOW之所以叫连续词袋模型,是因为在每个窗口内它也不考虑词序信息,因为它是直接把上下文的词向量相加了,自然就损失了词序信息。CBOW抛弃了词序信息,指的就是在每个窗口内部上下文直接相加而没有考虑词序。

用 CBOW 构造数据集的例子1如下图所示:

                           

例子2:

假设我们有一个简单的句子:

“The cat sits on the mat”

  • 选择“sits”作为目标词(w_t ),窗口大小设置为 2,意味着它的上下文是:

    • 左边两个词: “The”, “cat”
    • 右边两个词: “on”, “the” (如果只算到 “on the” 可能这样)
  • 构建训练样本时,就会出现:

    • 输入:上下文词“[The, cat, on, the]”各自的向量,合并/平均后得到 vcontext。
    • 输出:目标词“sits”在词表上的概率。

对于句子中的其他位置,也会类似地滑动窗口,把每个词当作目标词,然后获取它的上下文词,构建训练样本。例如,把“cat”当目标词时,上下文就是 [The], [sits, on] (在超出边界时,窗口不够可特殊处理)。

最大缺点:为什么说 “CBOW 不考虑词序”(之所以叫连续词袋模型)

  • 在同一个窗口里,CBOW 只是把上下文词向量进行相加/平均
  • 这样做后,我们无法区分“cat sits on the mat” 和 “on the cat sits the mat” 这样的词序变化,因为最终得到的上下文向量是一样的。
  • 这就是“Bag of Words”的含义:视上下文词为一个无序的集合

尽管 CBOW 在窗口内部抛弃了词序信息,但它仍然是“连续”地按照窗口来遍历整篇文本(不会跨句子或任意地远距离取词),所以叫 “Continuous Bag of Words”。

4.2 Skip-gram 模型

Skip-gram 模型和 CBOW 相反,Skip-gram 模型的输入是一个词汇,输出则是该词汇的上下文。如下图所示:

                   

下面举一个例子,设”窗口“宽度为5,每次用”窗口“的第三个也就是中的词汇作为输入,其余上下文作为输出,分别构建数据集,如下图所示: 

       

 然后用构建好的数据集丢给词模型进行训练,如下图所示:

如果一个语料库稍微大一点,可能的结果就太多了,最后一层 SoftMax 的计算就会很耗时,有什么办法来解决吗?

下面提出了一个初始解决方案:假设,传统模型中,我们输入 not ,希望输出是 thou,但是由于语料库庞大,最后一层 SoftMax 太过耗时,所以我们可以改为:将 not 和 thou 同时作为输入,做一个二分类问题,类别 1 表示 not 和 thou 是邻居,类别 0 表示它们不是邻居。

                    

上面提到的解决方案出发点非常好,但是由于训练集本来就是用上下文构建出来的,所以训练集构建出来的标签全为 1 ,无法较好的进行训练,如下图所示: 

 改进方案:加入一些负样本(负采样模型),一般负采样个数为 5 个就好,负采样示意图如下图所示:

最大缺点:和上面的CBOW一样无法考虑词序

  • Skip-gram输入是目标词,输出是预测其上下文词。与 CBOW 类似,上下文词也被视为独立的个体,不关心它们的顺序或位置

  • 例如,对于目标词 "sat",模型会尝试预测周围的词(如 "The", "cat", "on", "the"),但预测过程中这些词的顺序无关紧要。

4.3 CBOW 和 Skip-gram 对比 

 

五、词向量训练过程

5.1 初始化词向量矩阵

             

5.2 训练模型

通过神经网络反向传播来计算更新,此时不光更新权重参数矩阵W,也会更新输入数据

         

训练完成后,我们就得到了比较准确的 Word Embeddings,从而得到了每个词的向量表示!!! 

六、Python 代码实战

6.1 Model

from torch import nnclass DNN(nn.Module):def __init__(self, vocabulary_size, embedding_dim):super(DNN, self).__init__()self.embedding = nn.Linear(vocabulary_size, embedding_dim, bias=False)print("embedding_size:", list(self.embedding.weight.size()))self.layers = nn.Sequential(nn.Linear(vocabulary_size * embedding_dim, embedding_dim // 2),nn.LeakyReLU(),nn.Linear(embedding_dim // 2, 4),nn.LeakyReLU(),nn.Linear(4, 1),)# Mean squared error lossself.criterion = nn.MSELoss()# self.criterion = nn.CrossEntropyLoss()def forward(self, x):x = self.embedding(x)x = x.view(x.size()[0], -1)x = self.layers(x)x = x.squeeze(1)return xdef cal_loss(self, pred, target):""" Calculate loss """return self.criterion(pred, target)

6.2 DataSet

import randomimport numpy as np
from torch.utils.data import Datasetclass MyDataSet(Dataset):def __init__(self, features, labels):self.features = featuresself.labels = labelsdef __getitem__(self, index):return self.features[index], self.labels[index]def __len__(self):return len(self.features)def get_data_set(data_path, window_width, window_step, negative_sample_num):with open(data_path, 'r', encoding='utf-8') as file:document = file.read()document = document.replace(",", "").replace("?", "").replace(".", "").replace('"', '')data = document.split(" ")print(f"数据中共有 {len(data)} 个单词")# 构造词典vocabulary = set()for word in data:vocabulary.add(word)vocabulary = list(vocabulary)print(f"词典大小为 {len(vocabulary)}")# index_dictindex_dict = dict()for index, word in enumerate(vocabulary):index_dict[word] = index# 开始滑动窗口,构造数据features = []labels = []neighbor_dict = dict()for start_index in range(0, len(data), window_step):if start_index + window_width - 1 < len(data):mid_index = int((start_index + start_index + window_width - 1) / 2)for index in range(start_index, start_index + window_width):if index != mid_index:feature = np.zeros((len(vocabulary), len(vocabulary)))feature[index_dict[data[index]]][index_dict[data[index]]] = 1feature[index_dict[data[mid_index]]][index_dict[data[mid_index]]] = 1features.append(feature)labels.append(1)if data[mid_index] in neighbor_dict.keys():neighbor_dict[data[mid_index]].add(data[index])else:neighbor_dict[data[mid_index]] = {data[index]}# 负采样for _ in range(negative_sample_num):random_word = vocabulary[random.randint(0, len(vocabulary))]for word in vocabulary:if random_word not in neighbor_dict.keys() or word not in neighbor_dict[random_word]:feature = np.zeros((len(vocabulary), len(vocabulary)))feature[index_dict[random_word]][index_dict[random_word]] = 1feature[index_dict[word]][index_dict[word]] = 1features.append(feature)labels.append(0)break# 返回dataset和词典return MyDataSet(features, labels), vocabulary, index_dict

6.3 Main

import random
from math import sqrtimport numpy as np
import torch
from torch.utils.data import DataLoaderfrom Python.DataSet import get_data_set
from Python.Model import DNNdef same_seed(seed):"""Fixes random number generator seeds for reproducibility固定时间种子。由于cuDNN会自动从几种算法中寻找最适合当前配置的算法,为了使选择的算法固定,所以固定时间种子:param seed: 时间种子:return: None"""torch.backends.cudnn.deterministic = True  # 解决算法本身的不确定性,设置为True 保证每次结果是一致的torch.backends.cudnn.benchmark = False  # 解决了算法选择的不确定性,方便复现,提升训练速度np.random.seed(seed)  # 按顺序产生固定的数组,如果使用相同的seed,则生成的随机数相同, 注意每次生成都要调用一次torch.manual_seed(seed)  # 手动设置torch的随机种子,使每次运行的随机数都一致random.seed(seed)if torch.cuda.is_available():# 为GPU设置唯一的时间种子torch.cuda.manual_seed(seed)torch.cuda.manual_seed_all(seed)def train(model, train_loader, config):# Setup optimizeroptimizer = getattr(torch.optim, config['optimizer'])(model.parameters(), **config['optim_hyper_paras'])device = config['device']epoch = 0while epoch < config['n_epochs']:model.train()  # set model to training modeloss_arr = []for x, y in train_loader:  # iterate through the dataloaderoptimizer.zero_grad()  # set gradient to zerox, y = x.to(device).to(torch.float32), y.to(device).to(torch.float32)  # move data to device (cpu/cuda)pred = model(x)  # forward pass (compute output)mse_loss = model.cal_loss(pred, y)  # compute lossmse_loss.backward()  # compute gradient (backpropagation)optimizer.step()  # update model with optimizerloss_arr.append(mse_loss.item())print(f"epoch: {epoch}/{config['n_epochs']} , loss: {np.mean(loss_arr)}")epoch += 1print('Finished training after {} epochs'.format(epoch))def find_min_distance_word_vector(cur_i, vector, embeddings, vocabulary):def calc_distance(v1, v2):# 计算欧式距离distance = 0for i in range(len(v1)):distance += sqrt(pow(v1[i] - v2[i], 2))return distancemin_distance = Nonemin_i = -1for i, word in enumerate(vocabulary):if cur_i != i:distance = calc_distance(vector, embeddings[i].tolist())if min_distance is None or min_distance > distance:min_distance = distancemin_i = ireturn min_iif __name__ == '__main__':data_path = './data/data.txt'config = {'seed': 3407,  # Your seed number, you can pick your lucky number. :)'device': 'cuda' if torch.cuda.is_available() else 'cpu','n_epochs': 20,  # Number of epochs.'batch_size': 64,'optimizer': 'Adam','optim_hyper_paras': {  # hyper-parameters for the optimizer (depends on which optimizer you are using)'lr': 0.001,  # learning rate of optimizer},'embedding_dim': 6,  # 词向量长度'window_width': 5,  # 窗口的宽度'window_step': 2,  # 窗口滑动的步长'negative_sample_num': 10  # 要增加的负样本个数}same_seed(config['seed'])data_set, vocabulary, index_dict = get_data_set(data_path, config['window_width'], config['window_step'],config['negative_sample_num'])train_loader = DataLoader(data_set, config['batch_size'], shuffle=True, drop_last=False, pin_memory=True)model = DNN(len(vocabulary), config['embedding_dim']).to(config['device'])train(model, train_loader, config)# 训练完,看看embeddings,展示部分词的词向量,并找到离它最近的词的词向量embeddings = torch.t(model.embedding.weight)for i in range(10):print('%-50s%s' % (f"{vocabulary[i]} 的词向量为 :", str(embeddings[i].tolist())))min_i = find_min_distance_word_vector(i, embeddings[i].tolist(), embeddings, vocabulary)print('%-45s%s' % (f"离 {vocabulary[i]} 最近的词为 {vocabulary[min_i]} , 它的词向量为 :", str(embeddings[min_i].tolist())))print('-' * 200)

七、根据上面的代码举个例子 

一、数据处理流程(以示例文本说明)

假设输入文件 data.txt 内容为:

I love machine learning because it is interesting.
1. 文本预处理
  • 清洗:移除标点(, ? . "),处理后得到:

    I love machine learning because it is interesting
  • 分词:按空格切分为单词列表:

    data = ["I", "love", "machine", "learning", "because", "it", "is", "interesting"]
2. 构建词汇表
  • 去重后得到词汇表(假设顺序固定):

    vocabulary = ["I", "love", "machine", "learning", "because", "it", "is", "interesting"]
  • 索引映射 index_dict

    {"I":0, "love":1, "machine":2, "learning":3, "because":4, "it":5, "is":6, "interesting":7}
3. 滑动窗口生成正样本

假设窗口宽度 window_width=5,步长 window_step=2

  • 窗口划分

    • 窗口1: ["I", "love", "machine", "learning", "because"],中心词是第2个(machine,索引2)。

    • 窗口内上下文词:I(索引0)、love(索引1)、learning(索引3)、because(索引4)。

    • 每个上下文词与中心词生成一个正样本。

  • 特征矩阵示例(中心词 machine 和上下文词 love):

    # 特征矩阵形状 [8,8](词汇表大小=8)
    feature = np.zeros((8,8))
    feature[1][1] = 1  # 上下文词 "love" 的对角线置1
    feature[2][2] = 1  # 中心词 "machine" 的对角线置1

    该样本标签为 1

4. 负采样生成负样本

随机选择不共现的词对(例如 machine 和 it):

feature = np.zeros((8,8))
feature[2][2] = 1  # "machine"
feature[5][5] = 1  # "it"

标签为 0


二、模型架构详解(DNN 类)

1. Embedding 层
  • 定义nn.Linear(vocab_size, embed_dim, bias=False)

  • 作用:将输入矩阵的每个词索引转换为嵌入向量。

  • 输入形状[batch_size, vocab_size, vocab_size]

  • 输出形状[batch_size, vocab_size, embed_dim]

    • 矩阵乘法等价于对每个词进行线性变换。

2. 全连接层
  • 结构

    nn.Sequential(nn.Linear(vocab_size * embed_dim, embed_dim//2),  # 展平后输入nn.LeakyReLU(),nn.Linear(embed_dim//2, 4),nn.LeakyReLU(),nn.Linear(4, 1)
    )
  • 作用:将展平后的嵌入向量映射到标量输出。

3. 前向传播流程

以单个样本 [8,8](词汇表大小=8)为例:

  1. 输入矩阵[1, 8, 8](batch_size=1)

  2. Embedding 层:与 [8, embed_dim] 权重矩阵相乘,得到 [1, 8, embed_dim]

  3. Reshape:展平为 [1, 8*embed_dim]

  4. 全连接层:逐步降维到标量输出。


三、训练过程(以示例说明)

1. 数据加载
  • Dataset:包含特征矩阵和标签。

  • DataLoader:按批次加载数据(batch_size=64)。

2. 损失函数与优化器
  • 损失函数MSELoss,优化目标使正样本输出接近1,负样本接近0。

  • 优化器Adam,学习率 0.001

3. 训练循环
  • 前向传播:输入特征矩阵,计算预测值。

  • 反向传播:根据 MSE 损失更新参数。


四、词向量可视化与最近邻查找

1. 提取词向量
  • 权重矩阵embeddings = torch.t(model.embedding.weight),形状 [vocab_size, embed_dim]

  • 示例输出

    "machine" 的词向量为 : [0.12, -0.45, 0.78, ...]
2. 计算最近邻
  • 欧式距离:遍历所有词向量,找到距离最小的非自身词。

  • 示例结果

    离 "machine" 最近的词为 "learning" ,距离 0.89 

相关文章:

NLP深度学习 DAY4:Word2Vec详解:两种模式(CBOW与Skip-gram)

用稀疏向量表示文本&#xff0c;即所谓的词袋模型在 NLP 有着悠久的历史。正如上文中介绍的&#xff0c;早在 2001年就开始使用密集向量表示词或词嵌入。Mikolov等人在2013年提出的创新技术是通过去除隐藏层&#xff0c;逼近目标&#xff0c;进而使这些单词嵌入的训练更加高效。…...

论文阅读(十):用可分解图模型模拟连锁不平衡

1.论文链接&#xff1a;Modeling Linkage Disequilibrium with Decomposable Graphical Models 摘要&#xff1a; 本章介绍了使用可分解的图形模型&#xff08;DGMs&#xff09;表示遗传数据&#xff0c;或连锁不平衡&#xff08;LD&#xff09;&#xff0c;各种下游应用程序之…...

Python中容器类型的数据(上)

若我们想将多个数据打包并且统一管理&#xff0c;应该怎么办? Python内置的数据类型如序列(列表、元组等)、集合和字典等可以容纳多项数据&#xff0c;我们称它们为容器类型的数据。 序列 序列 (sequence) 是一种可迭代的、元素有序的容器类型的数据。 序列包括列表 (list)…...

PySPARK带多组参数和标签的SparkSQL批量数据导出到S3的程序

设计一个基于多个带标签SparkSQL模板作为配置文件和多组参数的PySPARK代码程序&#xff0c;实现根据不同的输入参数自动批量地将数据导出为Parquet、CSV和Excel文件到S3上&#xff0c;标签和多个参数&#xff08;以“_”分割&#xff09;为组成导出数据文件名&#xff0c;文件已…...

蓝桥杯备考:模拟算法之字符串展开

P1098 [NOIP 2007 提高组] 字符串的展开 - 洛谷 | 计算机科学教育新生态 #include <iostream> #include <cctype> #include <algorithm> using namespace std; int p1,p2,p3; string s,ret; void add(char left,char right) {string tmp;for(char ch left1;…...

使用LLaMA-Factory对AI进行认知的微调

使用LLaMA-Factory对AI进行认知的微调 引言1. 安装LLaMA-Factory1.1. 克隆仓库1.2. 创建虚拟环境1.3. 安装LLaMA-Factory1.4. 验证 2. 准备数据2.1. 创建数据集2.2. 更新数据集信息 3. 启动LLaMA-Factory4. 进行微调4.1. 设置模型4.2. 预览数据集4.3. 设置学习率等参数4.4. 预览…...

@Nullable 注解

文章目录 解释 Nullable 注解注解的组成部分&#xff1a;如何使用 Nullable 注解a. 标注方法返回值&#xff1a;b. 标注方法参数&#xff1a;c. 标注字段&#xff1a; 结合其他工具与 Nonnull 配合使用总结 Nullable 注解在 Java 中的使用场景通常与 Nullability&#xff08;空…...

Arduino大师练成手册 -- 控制 AS608 指纹识别模块

要在 Arduino 上控制 AS608 指纹识别模块&#xff0c;你可以按照以下步骤进行&#xff1a; 硬件连接 连接指纹模块&#xff1a;将 AS608 指纹模块与 Arduino 连接。通常&#xff0c;AS608 使用 UART 接口进行通信。你需要将 AS608 的 TX、RX、VCC 和 GND 引脚分别连接到 Ardu…...

Mask R-CNN与YOLOv8的区别

Mask R-CNN与YOLOv8虽然都是深度学习在计算机视觉领域的应用&#xff0c;但它们属于不同类型的视觉框架&#xff0c;各有特点和优势。 以下是关于 Mask R-CNN 和 YOLOv8 的详细对比分析&#xff0c;涵盖核心原理、性能差异、应用场景和选择建议&#xff1a; 1. 核心原理与功能…...

在Ubuntu上使用Docker部署DeepSeek

在Ubuntu上使用Docker部署DeepSeek&#xff0c;并确保其可以访问公网网址进行对话&#xff0c;可以按照以下步骤进行&#xff1a; 一、安装Docker 更新Ubuntu的软件包索引&#xff1a; sudo apt-get update安装必要的软件包&#xff0c;这些软件包允许apt通过HTTPS使用存储库…...

MySQL的覆盖索引

MySQL的覆盖索引 前言 当一个索引包含了查询所需的全部字段时&#xff0c;就可以提高查询效率&#xff0c;这样的索引又被称之为覆盖索引。 以MySQL常见的三种存储引擎为例&#xff1a;InnoDB、MyISAM、Memory&#xff0c;对于覆盖索引提高查询效率的方式均不同&#xff0c;…...

【Numpy核心编程攻略:Python数据处理、分析详解与科学计算】2.12 连续数组:为什么contiguous这么重要?

2.12 连续数组&#xff1a;为什么contiguous这么重要&#xff1f; 目录 #mermaid-svg-wxhozKbHdFIldAkj {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-wxhozKbHdFIldAkj .error-icon{fill:#552222;}#mermaid-svg-…...

在React中使用redux

一、首先安装两个插件 1.Redux Toolkit 2.react-redux 第一步&#xff1a;创建模块counterStore 第二步&#xff1a;在store的入口文件进行子模块的导入组合 第三步&#xff1a;在index.js中进行store的全局注入 第四步&#xff1a;在组件中进行使用 第五步&#xff1a;在组件中…...

lstm预测

import numpy as np import pandas as pd import tensorflow as tf import math import matplotlib.pyplot as plt from sklearn.preprocessing import MinMaxScaler from keras.layers import LSTM,Activation,Dense,Dropout# 时间序列数据转换为监督学习的格式 def creatXY(d…...

《 C++ 点滴漫谈: 二十五 》空指针,隐秘而危险的杀手:程序崩溃的真凶就在你眼前!

摘要 本博客全面解析了 C 中指针与空值的相关知识&#xff0c;从基础概念到现代 C 的改进展开&#xff0c;涵盖了空指针的定义、表示方式、使用场景以及常见注意事项。同时&#xff0c;深入探讨了 nullptr 的引入及智能指针在提升代码安全性和简化内存管理方面的优势。通过实际…...

【AI】探索自然语言处理(NLP):从基础到前沿技术及代码实践

Hi &#xff01; 云边有个稻草人-CSDN博客 必须有为成功付出代价的决心&#xff0c;然后想办法付出这个代价。 目录 引言 1. 什么是自然语言处理&#xff08;NLP&#xff09;&#xff1f; 2. NLP的基础技术 2.1 词袋模型&#xff08;Bag-of-Words&#xff0c;BoW&#xff…...

2025年Android开发趋势全景解读

文章目录 一、界面开发&#xff1a;从"手写代码"到"智能拼装"1.1 Jetpack Compose实战进化1.2 淘汰XML布局的三大信号 二、AI融合开发&#xff1a;无需炼丹的普惠智能2.1 设备端AI三大杀手级应用2.2 成本对比&#xff1a;设备端VS云端AI 三、跨平台演进&am…...

C#面试常考随笔11:Dictionary<K, V>、Hashtable的内部实现原理是什么?效率如何?

Dictionary<K, V> 底层数据结构&#xff1a;使用哈希表&#xff08;Hash Table&#xff09;&#xff0c;由一个数组和链表&#xff08;或在.NET Core 2.1 及之后版本中&#xff0c;当链表长度达到一定阈值时转换为红黑树&#xff09;组成。数组中的每个元素称为一个桶&a…...

Linux防火墙基础

一、Linux防火墙的状态机制 1.iptables是可以配置有状态的防火墙&#xff0c;其有状态的特点是能够指定并记住发送或者接收信息包所建立的连接状态&#xff0c;其一共有四种状态&#xff0c;分别为established invalid new related。 established:该信息包已建立连接&#x…...

Qt u盘自动升级软件

Qt u盘自动升级软件 Chapter1 Qt u盘自动升级软件u盘自动升级软件思路&#xff1a;step1. 获取U盘 判断U盘名字是否正确&#xff0c; 升级文件是否存在。step2. 升级step3. 升级界面 Chapter2 Qt 嵌入式设备应用程序&#xff0c;通过U盘升级的一种思路Chapter3 在开发板上运行的…...

大话软工笔记—需求分析概述

需求分析&#xff0c;就是要对需求调研收集到的资料信息逐个地进行拆分、研究&#xff0c;从大量的不确定“需求”中确定出哪些需求最终要转换为确定的“功能需求”。 需求分析的作用非常重要&#xff0c;后续设计的依据主要来自于需求分析的成果&#xff0c;包括: 项目的目的…...

【位运算】消失的两个数字(hard)

消失的两个数字&#xff08;hard&#xff09; 题⽬描述&#xff1a;解法&#xff08;位运算&#xff09;&#xff1a;Java 算法代码&#xff1a;更简便代码 题⽬链接&#xff1a;⾯试题 17.19. 消失的两个数字 题⽬描述&#xff1a; 给定⼀个数组&#xff0c;包含从 1 到 N 所有…...

Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility

Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility 1. 实验室环境1.1 实验室环境1.2 小测试 2. The Endor System2.1 部署应用2.2 检查现有策略 3. Cilium 策略实体3.1 创建 allow-all 网络策略3.2 在 Hubble CLI 中验证网络策略源3.3 …...

Nuxt.js 中的路由配置详解

Nuxt.js 通过其内置的路由系统简化了应用的路由配置&#xff0c;使得开发者可以轻松地管理页面导航和 URL 结构。路由配置主要涉及页面组件的组织、动态路由的设置以及路由元信息的配置。 自动路由生成 Nuxt.js 会根据 pages 目录下的文件结构自动生成路由配置。每个文件都会对…...

spring:实例工厂方法获取bean

spring处理使用静态工厂方法获取bean实例&#xff0c;也可以通过实例工厂方法获取bean实例。 实例工厂方法步骤如下&#xff1a; 定义实例工厂类&#xff08;Java代码&#xff09;&#xff0c;定义实例工厂&#xff08;xml&#xff09;&#xff0c;定义调用实例工厂&#xff…...

Unsafe Fileupload篇补充-木马的详细教程与木马分享(中国蚁剑方式)

在之前的皮卡丘靶场第九期Unsafe Fileupload篇中我们学习了木马的原理并且学了一个简单的木马文件 本期内容是为了更好的为大家解释木马&#xff08;服务器方面的&#xff09;的原理&#xff0c;连接&#xff0c;以及各种木马及连接工具的分享 文件木马&#xff1a;https://w…...

HashMap中的put方法执行流程(流程图)

1 put操作整体流程 HashMap 的 put 操作是其最核心的功能之一。在 JDK 1.8 及以后版本中&#xff0c;其主要逻辑封装在 putVal 这个内部方法中。整个过程大致如下&#xff1a; 初始判断与哈希计算&#xff1a; 首先&#xff0c;putVal 方法会检查当前的 table&#xff08;也就…...

用机器学习破解新能源领域的“弃风”难题

音乐发烧友深有体会&#xff0c;玩音乐的本质就是玩电网。火电声音偏暖&#xff0c;水电偏冷&#xff0c;风电偏空旷。至于太阳能发的电&#xff0c;则略显朦胧和单薄。 不知你是否有感觉&#xff0c;近两年家里的音响声音越来越冷&#xff0c;听起来越来越单薄&#xff1f; —…...

Golang——7、包与接口详解

包与接口详解 1、Golang包详解1.1、Golang中包的定义和介绍1.2、Golang包管理工具go mod1.3、Golang中自定义包1.4、Golang中使用第三包1.5、init函数 2、接口详解2.1、接口的定义2.2、空接口2.3、类型断言2.4、结构体值接收者和指针接收者实现接口的区别2.5、一个结构体实现多…...

SQL进阶之旅 Day 22:批处理与游标优化

【SQL进阶之旅 Day 22】批处理与游标优化 文章简述&#xff08;300字左右&#xff09; 在数据库开发中&#xff0c;面对大量数据的处理任务时&#xff0c;单条SQL语句往往无法满足性能需求。本篇文章聚焦“批处理与游标优化”&#xff0c;深入探讨如何通过批量操作和游标技术提…...