机器学习课程学习周报九

机器学习课程学习周报九

文章目录

  • 机器学习课程学习周报九
    • 摘要
    • Abstract
    • 一、机器学习部分
      • 1.1 Word Embedding
        • 1.1.1 词嵌入的基本概念
        • 1.1.2 word2vec连续词袋模型CBOW
        • 1.1.3 word2vec跳字模型Skip-gram
      • 1.2 Transformer代码实践
        • Dataset
        • Dataloader
        • Model
        • Learning rate schedule
        • Model Function
        • Validate
        • Main Function
        • Dataset of inference
        • Main function of inference
    • 总结

摘要

本周的学习重点是词嵌入技术和Transformer模型的应用。在词嵌入部分,我探讨了词嵌入的基本概念以及word2vec的两种模型:CBOW和Skip-gram。在代码实践中,我学习了如何使用Transformer模型对音频数据进行说话者识别,包括数据集的加载、模型的构建和训练过程。

Abstract

This week’s focus was on word embedding techniques and the application of the Transformer model. In the word embedding section, I explored the basic concepts and two models of word2vec: CBOW and Skip-gram. In the code practice, I learned how to use the Transformer model for speaker identification in audio data, covering dataset loading, model construction, and the training process.

一、机器学习部分

1.1 Word Embedding

1.1.1 词嵌入的基本概念

在这里插入图片描述

词嵌入Word Embedding),是种将词汇表中的词映射为固定长度向量的技术。通过词嵌入,可以将One-Hot编码表示的高维稀疏向量转为低维连续的向量。

在这里插入图片描述

为了进一步说明词与词之间的关系,使用降维算法可以将词嵌入向量降维至2维,从而在平面中绘制。其中,语义相近的词语,对应的向量位置也更相近。例如,cat与kitten(小猫)的含义相近,它们的距离就相近,cat与其他词的语义差距大,其之间的距离就相对较远。
在这里插入图片描述

词嵌入向量不仅可以表达语义的相似性,还可以通过向量的数学关系,描述词语之间的语义关联。一般通过特定的词嵌入算法,如word2vec、fasttext、Glove等训练一个通用的嵌入矩阵。这个矩阵的每一行都代表了一个词向量,这些词向量的表达方式一旦训练完成,就可以应用在不同的NLP任务中。

在这里插入图片描述

具体来说,嵌入矩阵的行数表示词汇表中词语的个数,而嵌入矩阵的列数表示词向量的维度,嵌入矩阵记作 E E E

在这里插入图片描述

以句子“我喜欢学习数学”为例,将句中的词转换为词嵌入向量:首先进行切词,得到“我”、“喜欢”、“学习”、“数学”,将词语进行One-Hot编码,并将这些词语的One-Hot向量组成为句子矩阵,记作 V V V

在这里插入图片描述

将大小为 4 × 5000 4 \times 5000 4×5000的One-Hot句子矩阵 V V V乘上大小为 5000 × 128 5000 \times 128 5000×128嵌入矩阵 E E E,可以得到 4 × 128 4 \times 128 4×128的矩阵,这个矩阵的每一行都代表一个词的嵌入向量。实际上,将矩阵 V V V和矩阵 E E E相乘,即是将词对应的嵌入向量从嵌入矩阵中取出。

词嵌入算法与One-Hot编码相比,优势在于:

  • 词嵌入将文本中的词,通过一个低维向量来表达,相比于万维的One-Hot编码方式,效率上有了质的提升。
  • 通过词嵌入表示的词语,可以理解词语的语义,并进行词语推理。语义相似的词在向量空间上也会更相近。
  • One-Hot编码不具有通用性,不同语料得到的One-Hot表示一般不同。而嵌入矩阵是通用的,同一份词向量,可以用在不同的NLP任务中。
1.1.2 word2vec连续词袋模型CBOW

在这里插入图片描述

CBOWContinuous Bag of Words)连续词袋模型,根据上下文词汇预测目标词,这个模型的目标在于迭代出词嵌入矩阵 E E EEmbeddings)。以“We are about to study the idea of deep learning.”为例,使用词语study的上下文预测study这个词语,以介绍CBOW模型。

首先,对于某个词的上下文,需要提前设置一个上下文窗口长度:

在这里插入图片描述

设置好窗口的长度后,需要通过窗口内的词语,预测目标词。
在这里插入图片描述

CBOW模型接收上下文词语,将上下文词语转换为最有可能的目标词。
在这里插入图片描述

CBOW模型最前端是embeddings层,用以接收One-Hot形式的词语输入,embeddings层是一个 N × V N \times V N×V的矩阵, N N N是词表中的词语个数, V V V是词向量的维度,这就是我们希望训练后希望得到的嵌入矩阵 E E E。上图中输入词为“We”,转换为对应的One-Hot向量,然后乘上嵌入矩阵 E E E,得到词的嵌入向量,这一步是从矩阵中选择一个特定的行,从embeddings中查找“We”的词嵌入向量。

在这里插入图片描述

由于某个词的上下文中,包含了多个词语,这些词语会被同时输入至embeddings层,每个词语都会被转换为一个词向量。并将多个上下文的词向量直接相加,然后取平均,embeddings层输出语义信息平均的向量 v v v
在这里插入图片描述

在embeddings层后,会连接一个线性层,上图中用红色区域表示。一般这个线性层不设置激活函数,这个线性层的权重矩阵的维度是 V × N V \times N V×N V V V是词嵌入向量的维度, N N N是词表中词语的个数。具体来说,将所有上下文词向量的平均值 v v v,这个向量的大小是 1 × V 1 \times V 1×V,输入至该线性层,输出大小为 1 × N 1 \times N 1×N的向量,然后经过softmax函数就算出一个最有可能的输出词,softmax函数的输出是概率分布,图上直接挑选概率最大的位置赋为1,表示预测目标词的One-Hot编码,这只是一种简化。

1.1.3 word2vec跳字模型Skip-gram

在这里插入图片描述

Skip-gram会根据目标词预测上下文词,而CBOW是根据上下文词预测目标词,这两种方法的最终目标都是迭代出词向量字典embeddings。Skip-gram在迭代时,调整词向量:使目标词的词向量与其上下文的词向量尽可能的接近,使目标词的词向量与非上下文词的词向量尽可能的远。判断两个词向量是否相似,使用向量的点积:

A = ( a 1 , a 2 , … , a n ) B = ( b 1 , b 2 , … , b n ) A ⋅ B = a 1 b 1 + a 2 b 2 + … + a n b n \begin{array}{l}A = \left( {{a_1},{a_2}, \ldots ,{a_n}} \right)\\B = \left( {{b_1},{b_2}, \ldots ,{b_n}} \right)\\A \cdot B = {a_1}{b_1} + {a_2}{b_2} + \ldots + {a_n}{b_n}\end{array} A=(a1,a2,,an)B=(b1,b2,,bn)AB=a1b1+a2b2++anbn

向量的点积,衡量了两个向量在同一方向上的强度。点积越大,两个向量越相似,它们对应的词语的语义就越接近。

同样地,以“We are about to study the idea of deep learning.”为例,并先设定一个上下文窗口长度。

在这里插入图片描述

Skip-gram模型是一个神经网络,其中包含了两个嵌入层in_embeddingout_embedding。模型接受One-Hot编码的向量输入,in_embeddings将One-Hot转换为词嵌入向量,out_embedding将输入的目标词的嵌入向量与词表中全部词语的嵌入向量做点积,计算语义相似度,最后输出一个词汇表大小的概率分布,它表示了词汇表中的每个词是目标词的上下文的可能性。

1.2 Transformer代码实践

本次代码作业旨在学习使用Transformer模型,给定一段音频序列,预测音频的speaker的id。

Dataset

数据集使用VoxCeleb2,训练数据包含56666个预处理过的音频特征文件,并包含相应的标签;测试集包含4000个预处理过的音频特征文件,不包含对应标签;标签总共有600种类别,每一种类别代表一个speaker。

在这里插入图片描述
音频数据的预处理过程如上所示
在这里插入图片描述
数据集的文件格式如上所示

import os
import json
import torch
import random
from pathlib import Path
from torch.utils.data import Dataset
from torch.nn.utils.rnn import pad_sequenceclass myDataset(Dataset):def __init__(self, data_dir, segment_len=128):self.data_dir = data_dirself.segment_len = segment_len# 加载从speaker的名称到其对应id的映射。mapping_path = Path(data_dir) / "mapping.json"mapping = json.load(mapping_path.open())self.speaker2id = mapping["speaker2id"]# 加载训练数据的元数据。metadata_path = Path(data_dir) / "metadata.json"metadata = json.load(open(metadata_path))["speakers"]# 获取speaker的总数。self.speaker_num = len(metadata.keys())self.data = []for speaker in metadata.keys():for utterances in metadata[speaker]:self.data.append([utterances["feature_path"], self.speaker2id[speaker]])def __len__(self):return len(self.data)def __getitem__(self, index):feat_path, speaker = self.data[index]# 加载处理为mel-spectrogram形式的音频数据。mel = torch.load(os.path.join(self.data_dir, feat_path))# 分割mel-spectrogram为128帧。if len(mel) > self.segment_len:start = random.randint(0, len(mel) - self.segment_len)mel = torch.FloatTensor(mel[start:start+self.segment_len])else:mel = torch.FloatTensor(mel)# 将speaker的id的数据类型改为long,以便之后计算损失。speaker = torch.FloatTensor([speaker]).long()return mel, speakerdef get_speaker_number(self):return self.speaker_num
Dataloader
import torch
from torch.utils.data import DataLoader, random_split
from torch.nn.utils.rnn import pad_sequencedef collate_batch(batch):# 处理一个批次的音频特征mel, speaker = zip(*batch)# 因为我们是分批次训练模型的,所以我们需要在同一批次中填充特征,使它们的长度相同。mel = pad_sequence(mel, batch_first=True, padding_value=-20)    # 填充大小为log 10^(-20) ,这是个非常小的数值.# mel: (batch size, length, 40)return mel, torch.FloatTensor(speaker).long()def get_dataloader(data_dir, batch_size, n_workers):dataset = myDataset(data_dir)speaker_num = dataset.get_speaker_number()# 按照9:1的比例划分数据集为训练集和验证集trainlen = int(0.9 * len(dataset))lengths = [trainlen, len(dataset) - trainlen]trainset, validset = random_split(dataset, lengths)train_loader = DataLoader(trainset,batch_size=batch_size,shuffle=True,drop_last=True,num_workers=n_workers,pin_memory=True,collate_fn=collate_batch,)valid_loader = DataLoader(validset,batch_size=batch_size,num_workers=n_workers,drop_last=True,pin_memory=True,collate_fn=collate_batch,)return train_loader, valid_loader, speaker_num
Model
import torch
import torch.nn as nn
import torch.nn.functional as Fclass Classifier(nn.Module):def __init__(self, d_model=80, n_spks=600, dropout=0.1):super().__init__()# 神经网络的预处理层,将输入特征维度从40维映射到d_model维度self.prenet = nn.Linear(40, d_model)#   这里改进可以将Transformer模型变为Conformer模型#   Conformer,https://arxiv.org/abs/2005.08100self.encoder_layer = nn.TransformerEncoderLayer(d_model=d_model, dim_feedforward=256, nhead=2)# Transformer编码器层,用于对特征进行编码self.pred_layer = nn.Sequential(nn.Linear(d_model, d_model),nn.ReLU(),nn.Linear(d_model, n_spks),# 输出对600个speaker的预测结果)def forward(self, mels):"""args:mels: (batch size, length, 40)return:out: (batch size, n_spks)"""# out: (batch size, length, d_model)out = self.prenet(mels)# 经过预处理层处理输入特征# out: (length, batch size, d_model)out = out.permute(1, 0, 2)# 改变特征维度的顺序以符合Transformer的输入要求# The encoder layer expect features in the shape of (length, batch size, d_model).out = self.encoder_layer(out)# 使用Transformer编码器层对特征进行编码# out: (batch size, length, d_model)out = out.transpose(0, 1)# 调整特征的维度顺序# mean poolingstats = out.mean(dim=1)# mean pooling,对特征进行平均池化# out: (batch, n_spks)out = self.pred_layer(stats)# 使用全连接层进行最终的预测输出return out
Learning rate schedule
import mathimport torch
from torch.optim import Optimizer
from torch.optim.lr_scheduler import LambdaLRdef get_cosine_schedule_with_warmup(optimizer: Optimizer,num_warmup_steps: int,num_training_steps: int,num_cycles: float = 0.5,last_epoch: int = -1,
):"""创建一个学习率调度器,学习率按余弦函数的值逐渐减小,同时在初始阶段有一个线性增加学习率的预热阶段。Args:optimizer (:class:`~torch.optim.Optimizer`):需要调度学习率的优化器。num_warmup_steps (:obj:`int`):预热阶段的步数。num_training_steps (:obj:`int`):总的训练步数。num_cycles (:obj:`float`, `optional`, defaults to 0.5):余弦调度中的波数(默认值是从最大值降到0按照半余弦波进行)。last_epoch (:obj:`int`, `optional`, defaults to -1):恢复训练时的最后一个周期索引。Return::obj:`torch.optim.lr_scheduler.LambdaLR`,带有适当调度的学习率。"""def lr_lambda(current_step):# 预热阶段if current_step < num_warmup_steps:return float(current_step) / float(max(1, num_warmup_steps))# 余弦退火progress = float(current_step - num_warmup_steps) / float(max(1, num_training_steps - num_warmup_steps))return max(0.0, 0.5 * (1.0 + math.cos(math.pi * float(num_cycles) * 2.0 * progress)))return LambdaLR(optimizer, lr_lambda, last_epoch)
Model Function
import torchdef model_fn(batch, model, criterion, device):"""通过模型前向传播一个批次的数据。"""mels, labels = batchmels = mels.to(device)# 将输入特征移动到指定设备上labels = labels.to(device)# 将标签移动到指定设备上outs = model(mels)# 通过模型进行前向传播得到输出loss = criterion(outs, labels)# 使用给定的损失函数计算损失值# 获取具有最高概率的说话人id。preds = outs.argmax(1)# 计算预测准确率。accuracy = torch.mean((preds == labels).float())return loss, accuracy
Validate
from tqdm import tqdm
import torchdef valid(dataloader, model, criterion, device): """在验证集上进行验证。"""model.eval() # 将模型设置为评估模式,不进行梯度计算running_loss = 0.0 # 累积损失running_accuracy = 0.0 # 累积准确率pbar = tqdm(total=len(dataloader.dataset), ncols=0, desc="Valid", unit=" uttr") # 进度条for i, batch in enumerate(dataloader):with torch.no_grad(): # 不需要计算梯度loss, accuracy = model_fn(batch, model, criterion, device)running_loss += loss.item() # 累积损失值running_accuracy += accuracy.item() # 累积准确率pbar.update(dataloader.batch_size) # 更新进度条pbar.set_postfix(loss=f"{running_loss / (i+1):.2f}",accuracy=f"{running_accuracy / (i+1):.2f}",)pbar.close() # 关闭进度条model.train() # 将模型设置回训练模式return running_accuracy / len(dataloader) # 返回平均准确率
Main Function
from tqdm import tqdmimport torch
import torch.nn as nn
from torch.optim import AdamW
from torch.utils.data import DataLoader, random_splitdef parse_args():"""arguments"""config = {"data_dir": "./Dataset","save_path": "model.ckpt","batch_size": 32,"n_workers": 8,"valid_steps": 2000,"warmup_steps": 1000,"save_steps": 10000,"total_steps": 70000,}return configdef main(data_dir,save_path,batch_size,n_workers,valid_steps,warmup_steps,total_steps,save_steps,
):"""Main function."""device = torch.device("cuda" if torch.cuda.is_available() else "cpu")print(f"[Info]: Use {device} now!")train_loader, valid_loader, speaker_num = get_dataloader(data_dir, batch_size, n_workers)train_iterator = iter(train_loader)print(f"[Info]: Finish loading data!",flush = True)model = Classifier(n_spks=speaker_num).to(device)criterion = nn.CrossEntropyLoss()optimizer = AdamW(model.parameters(), lr=1e-3)scheduler = get_cosine_schedule_with_warmup(optimizer, warmup_steps, total_steps)print(f"[Info]: Finish creating model!",flush = True)best_accuracy = -1.0best_state_dict = Nonepbar = tqdm(total=valid_steps, ncols=0, desc="Train", unit=" step")for step in range(total_steps):# 获取数据try:batch = next(train_iterator)except StopIteration:train_iterator = iter(train_loader)batch = next(train_iterator)loss, accuracy = model_fn(batch, model, criterion, device)batch_loss = loss.item()batch_accuracy = accuracy.item()# 更新模型loss.backward()optimizer.step()scheduler.step()optimizer.zero_grad()# 记录日志pbar.update()pbar.set_postfix(loss=f"{batch_loss:.2f}",accuracy=f"{batch_accuracy:.2f}",step=step + 1,)# 进行验证if (step + 1) % valid_steps == 0:pbar.close()valid_accuracy = valid(valid_loader, model, criterion, device)# 保存最佳模型if valid_accuracy > best_accuracy:best_accuracy = valid_accuracybest_state_dict = model.state_dict()pbar = tqdm(total=valid_steps, ncols=0, desc="Train", unit=" step")# 保存到目前为止最佳的模型if (step + 1) % save_steps == 0 and best_state_dict is not None:torch.save(best_state_dict, save_path)pbar.write(f"Step {step + 1}, best model saved. (accuracy={best_accuracy:.4f})")pbar.close()if __name__ == "__main__":main(**parse_args())
Dataset of inference
import os
import json
import torch
from pathlib import Path
from torch.utils.data import Datasetclass InferenceDataset(Dataset):def __init__(self, data_dir):# 加载测试数据的元数据testdata_path = Path(data_dir) / "testdata.json"metadata = json.load(testdata_path.open())self.data_dir = data_dirself.data = metadata["utterances"]def __len__(self):return len(self.data)def __getitem__(self, index):# 获取单个样本utterance = self.data[index]feat_path = utterance["feature_path"]mel = torch.load(os.path.join(self.data_dir, feat_path))return feat_path, meldef inference_collate_batch(batch):"""对一个数据批次进行整理。"""feat_paths, mels = zip(*batch)return feat_paths, torch.stack(mels)
Main function of inference
import json
import csv
from pathlib import Path
from tqdm.notebook import tqdmimport torch
from torch.utils.data import DataLoaderdef parse_args():"""arguments"""config = {"data_dir": "./Dataset","model_path": "./model.ckpt","output_path": "./output.csv",}return configdef main(data_dir,model_path,output_path,
):"""Main function."""device = torch.device("cuda" if torch.cuda.is_available() else "cpu")print(f"[Info]: Use {device} now!")mapping_path = Path(data_dir) / "mapping.json"mapping = json.load(mapping_path.open())dataset = InferenceDataset(data_dir)dataloader = DataLoader(dataset,batch_size=1,shuffle=False,drop_last=False,num_workers=8,collate_fn=inference_collate_batch,)print(f"[Info]: Finish loading data!",flush = True)speaker_num = len(mapping["id2speaker"])model = Classifier(n_spks=speaker_num).to(device)model.load_state_dict(torch.load(model_path))model.eval()print(f"[Info]: Finish creating model!",flush = True)results = [["Id", "Category"]]for feat_paths, mels in tqdm(dataloader):with torch.no_grad():mels = mels.to(device)outs = model(mels)preds = outs.argmax(1).cpu().numpy()for feat_path, pred in zip(feat_paths, preds):results.append([feat_path, mapping["id2speaker"][str(pred)]])with open(output_path, 'w', newline='') as csvfile:writer = csv.writer(csvfile)writer.writerows(results)if __name__ == "__main__":main(**parse_args())

总结

本周通过对词嵌入和Transformer模型的深入学习,我掌握了如何有效地将文本和音频数据转换为可用于机器学习模型的特征表示。词嵌入技术为NLP任务提供了更好的语义理解能力,而Transformer模型则在处理序列数据上表现十分出色。下周计划进入生成对抗网络(GAN)的学习。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

windows javascript 打开、关闭摄像头

1. 效果 打开摄像头 关闭摄像头&#xff08;包括指示灯也关了的&#xff09; 2. 代码 open_close_camera.html // open_close_camera.html <!DOCTYPE html> <html><head><meta charset"UTF-8"><title>use camera</title>…

使用Dotween制作按钮弹性动画效果

效果&#xff1a; 方式&#xff1a; 优点&#xff0c;不需要写任何代码、稳定、可自定义效果

Agent实际落地的应用 未来生活的无形助手

在这个信息爆炸的时代&#xff0c;我们每个人都在追求更高效的生活方式。想象一下&#xff0c;如果有一个无形的助手&#xff0c;能够理解我们的需求&#xff0c;自动处理繁琐的任务&#xff0c;甚至为我们提供个性化的建议&#xff0c;那将是多么美好的体验&#xff01;这正是…

数字模拟IC设计前端、后端、前仿、后仿新版虚拟机

虚拟化平台&#xff1a;VMware Workstation 15 Pro以上版本 操作系统&#xff1a;CentOS Linux release 7.9.2009 (Core) 一、射频模拟IC设计必备软件 Cadence IC06.18.350/IC23.10.080&#xff08;virtuoso&#xff09; Cadence SPECTRE23.10.538-isr10 Cadence ASSURA04.…

Spring Boot OAuth2.0应用

本文展示Spring Boot中&#xff0c;新版本OAuth2.0的简单实现&#xff0c;版本信息&#xff1a; spring-boot 2.7.10 spring-security-oauth2-authorization-server 0.4.0 spring-security-oauth2-client 5.7.7 spring-boot-starter-oauth2-resource-server 2.7.10展示三个服务…

远程供水无障碍,管线车助力全面消防防护_鼎跃安全

夏季是各类自然灾害的高发季节&#xff0c;其中森林火灾尤为频繁。这一时期的气候特征是干旱少雨&#xff0c;伴随着高温和强风&#xff0c;使得森林火灾的发生频率大幅增加。由于夏季空气湿度低&#xff0c;植被含水量减少&#xff0c;一旦出现火源&#xff0c;火势极易蔓延。…

数据结构-链表-第二天

结合leetcode学习c 链表比数组更易增加和删除数据&#xff0c;但访问速度更慢 定义 链表&#xff08;linked list&#xff09;是一种线性数据结构&#xff0c;其中的每个元素都是一个节点对象&#xff0c;各个节点通过“引用”相连接。 引用记录了下一个节点的内存地址&#…

windows本地搭建zookeeper和kafka环境

zookeeper 1.1 下载zookeeper 下载地址 随便进一个站点&#xff0c;默认是新版本&#xff0c;旧版本点击archives进入&#xff0c;选择合适的版本下载&#xff0c;本文使用的是3.7.2 下载时候选择apache-zookeeper-3.7.2-bin.tar.gz 格式的&#xff0c;编译后的&#xff0c;解…

centos 虚拟机器刚刚安装没有ip地址的问题

刚刚安装好的虚拟机器&#xff0c;我们通过 ip addr 查看ip发现是这样的 该虚拟机器没有ip地址&#xff0c;那么怎么办 原来是在/etc/sysconfig/network-scripts/ifcfg-ens33中关于网络的配置有问题 ONBOOTno 表示不开启网卡&#xff0c;我们需要将这个值进行修改为yes 当前…

prolog 基础 - 关系和属性

首先进入环境&#xff1b; 看一下一开始的提示符是 ?- &#xff0c;现在可以用write语句输出一些东西&#xff1b; 根据资料&#xff0c;在prolog中&#xff0c; 两个对象之间的关系&#xff0c;使用括号表示。比如&#xff0c;jack的朋友是peter&#xff0c;写成friend(ja…

嵌入式堆栈、ARM寄存器

栈里面存放的内容&#xff1a;局部变量和系统信息&#xff0c;函数调用链路也是系统信息的一环 ARM寄存器 LR&#xff1a;程序跳转的时候&#xff0c;返回到的地址就保存到此处 PC&#xff1a;程序计数器&#xff0c;pc 要执行的下一条指令地址&#xff0c;就存放在此处&#…

QT error: undefined reference to `vtable for Net‘

报错 C:\Users\Administrator\Desktop\VideoHill\GikISearch\net.cpp:4: error: undefined reference to vtable for Net 以下是两个可能错误原因 1&#xff0c;未定义Q_OBJECT 宏 在头文件中加上 加上#include <QObject>&#xff0c; 改写继承QObject 和定义宏 …

Unity3D 遍历预制体

Unity3D 遍历预制体进行批量化处理。 遍历预制体 有时候&#xff0c;我们需要对一些预制体资源进行批量化处理&#xff0c;如果每一个预制体都手动处理&#xff0c;就会耗费很多时间精力&#xff0c;也容易出错。 我们可以写一个脚本遍历预制体&#xff0c;对预制体进行修改…

电脑U口管理软件分享|U口管理软件哪个好?

电脑U口&#xff08;即USB端口&#xff09;管理软件是保护电脑安全、防止数据泄露和恶意软件入侵的重要工具。 在选择U口管理软件时&#xff0c;需要考虑其功能、易用性、安全性以及是否满足个人或企业的具体需求。以下是一些值得推荐的电脑U口管理软件及其特点&#xff1a; 1…

白酒与旅行日记:探索世界,品味美酒

在旅行的道路上&#xff0c;我们追寻着不同的风景&#xff0c;体验着不同的文化。而白酒&#xff0c;作为中国文化的瑰宝&#xff0c;也在这一旅途中扮演着不同的角色。它不仅仅是一种饮品&#xff0c;更是一种情感的寄托&#xff0c;一种文化的传承。今天&#xff0c;就让我们…

.net maui安卓开发中使用明文传输(一)

背景:最近在做一个pad上的项目,目的是执行每日点检功能(就是检查设备的各项保养指标);前期用HBuilder做了一个,但是现场的触摸屏选用的是TouchPie 安卓版本是6.0版本,上次开发的软件可以在安卓7.0上完美兼容,但由于触摸屏安卓版本太低不能兼容;询问厂商才知道这款触摸…

8.21-部署eleme项目

1.设置主从从mysql57服务器 &#xff08;1&#xff09;配置主数据库 [rootmsater_5 ~]# systemctl stop firewalld[rootmsater_5 ~]# setenforce 0[rootmsater_5 ~]# systemctl disable firewalldRemoved symlink /etc/systemd/system/multi-user.target.wants/firewalld.serv…

PV、UV、IP:网站流量分析的关键指标

原文&#xff1a;PV、UV、IP&#xff1a;网站流量分析的关键指标 - 孔乙己大叔 (rebootvip.com) 摘要&#xff1a; 在浩瀚的互联网海洋中&#xff0c;PV&#xff08;Page View&#xff0c;页面浏览量&#xff09;、UV&#xff08;Unique Visitor&#xff0c;独立访客数…

基于改进YOLOv8的景区行人检测算法

贵向泉, 刘世清, 李立, 秦庆松, 李唐艳. 基于改进YOLOv8的景区行人检测算法[J]. 计算机工程, 2024, 50(7): 342-351. DOI: 10.19678/j.issn.10 原文链接如下&#xff1a;基于改进YOLOv8的景区行人检测算法https://www.ecice06.com/CN/rich_html/10.19678/j.issn.1000-3428.006…

墨者学院 手工注入题解(oracle数据库)

简介 Oracle 数据库系统&#xff0c;是美国ORACLE公司&#xff08;甲⻣⽂&#xff09;提供的以分布式数据库为核⼼的⼀组软件 产品。是⽬前世界上使⽤最为⼴泛的&#xff0c;数据库管理系统。 以下是手工注入的流程&#xff1a; 1、判断注入点 使用 and 11 进行拼接 2、确定…