Day09 【基于LSTM实现文本加标点的任务】
基于LSTM实现文本加标点的任务
- 目标
- 数据准备
- 参数配置
- 数据处理
- 模型构建
- 定义模型结构
- 前向传播方法
- 优化器选择
- 主程序
- 测试与评估
- 类初始化
- 模型评估
- 统计记录
- 显示统计结果
- 测试结果
目标
本文基于给定的词表,将输入的文本基于jieba分词分割为若干个词,然后基于词表将词初步序列化,之后经过embedding``LSTM
等网络结构层,输出在已知类别标点符号标签上的概率分布,从而实现一个简单文本加标点任务。
数据准备
词表文件chars.txt
类别标签文件schema.json
{"": 0,",": 1,"。": 2,"?": 3
}
本文的任务只处理三类标点符号,逗号","
、句号"。"
和问号"?"
,不需要加标点词的后面相当于加上空字符""
,因此文本标签总共有4类。
训练集数据train_corpus.txt训练集数据
验证集数据valid_corpus.txt验证集数据
参数配置
config.py
# -*- coding: utf-8 -*-"""
配置参数信息
"""Config = {"model_path": "model_output","schema_path": "data/schema.json","train_data_path": "data/train_corpus.txt","valid_data_path": "data/valid_corpus.txt","vocab_path":"chars.txt","max_length": 50,"hidden_size": 128,"epoch": 10,"batch_size": 128,"optimizer": "adam","learning_rate": 1e-3,"use_crf": False,"class_num": None
}
数据处理
loader.py
# -*- coding: utf-8 -*-import json
import re
import os
import torch
import random
import jieba
import numpy as np
from torch.utils.data import Dataset, DataLoader"""
数据加载
"""class DataGenerator:def __init__(self, data_path, config):self.config = configself.path = data_pathself.vocab = load_vocab(config["vocab_path"])self.config["vocab_size"] = len(self.vocab)self.sentences = []self.schema = self.load_schema(config["schema_path"])self.config["class_num"] = len(self.schema)self.max_length = config["max_length"]self.load()def load(self):self.data = []with open(self.path, encoding="utf8") as f:for line in f:if len(line) > self.max_length:for i in range(len(line) // self.max_length):input_id, label = self.process_sentence(line[i * self.max_length:(i+1) * self.max_length])self.data.append([torch.LongTensor(input_id), torch.LongTensor(label)])else:input_id, label = self.process_sentence(line)self.data.append([torch.LongTensor(input_id), torch.LongTensor(label)])returndef process_sentence(self, line):sentence_without_sign = []label = []for index, char in enumerate(line[:-1]):if char in self.schema: #准备加的标点,在训练数据中不应该存在continuesentence_without_sign.append(char)next_char = line[index + 1]if next_char in self.schema: #下一个字符是标点,计入对应labellabel.append(self.schema[next_char])else:label.append(0)assert len(sentence_without_sign) == len(label)encode_sentence = self.encode_sentence(sentence_without_sign)label = self.padding(label, -1)assert len(encode_sentence) == len(label)self.sentences.append("".join(sentence_without_sign))return encode_sentence, labeldef encode_sentence(self, text, padding=True):input_id = []if self.config["vocab_path"] == "words.txt":for word in jieba.cut(text):input_id.append(self.vocab.get(word, self.vocab["[UNK]"]))else:for char in text:input_id.append(self.vocab.get(char, self.vocab["[UNK]"]))if padding:input_id = self.padding(input_id)return input_id#补齐或截断输入的序列,使其可以在一个batch内运算def padding(self, input_id, pad_token=0):input_id = input_id[:self.config["max_length"]]input_id += [pad_token] * (self.config["max_length"] - len(input_id))return input_iddef __len__(self):return len(self.data)def __getitem__(self, index):return self.data[index]def load_schema(self, path):with open(path, encoding="utf8") as f:return json.load(f)#加载字表或词表
def load_vocab(vocab_path):token_dict = {}with open(vocab_path, encoding="utf8") as f:for index, line in enumerate(f):token = line.strip()token_dict[token] = index + 1 #0留给padding位置,所以从1开始return token_dict#用torch自带的DataLoader类封装数据
def load_data(data_path, config, shuffle=True):dg = DataGenerator(data_path, config)dl = DataLoader(dg, batch_size=config["batch_size"], shuffle=shuffle)return dl
这段代码实现了一个数据生成器(DataGenerator
),主要用于加载、处理和准备文本数据,以供深度学习模型进行训练。该数据生成器类利用 PyTorch 的 DataLoader
进行数据加载,并通过以下几个步骤处理原始数据:
数据生成器的逻辑思路如下:
-
文本加载与切割:首先,加载原始文本数据,并根据设定的最大长度将文本切割成多个片段。每个片段的长度不超过最大长度,确保在模型训练时,输入文本的长度统一。
-
文本编码:接下来,将每个片段的文本进行编码。根据配置,可以选择字符级别或词级别的编码方式。文本中的每个字符或词会被映射为词汇表中的数字索引。这样,文本从字符串形式转化为模型可以处理的数字形式。
-
标签处理:标签生成是该过程的重要部分。对于每个字符,判断其后是否是标点符号。如果是标点符号,则生成标签1,表示该字符后是标点;否则,标签为0,表示后续不是标点符号。这一步有助于模型学习文本中的标点符号位置。
-
填充与截断:为了保证输入序列的长度一致,所有文本片段都会根据最大长度进行填充或截断。如果文本长度不足最大长度,会在其后填充特殊符号;如果超出最大长度,则会被截断。
-
数据批量处理:所有处理后的文本和标签被封装为一个数据集,通过
DataLoader
进行批量加载。DataLoader
不仅可以将数据按批次划分,还能在训练过程中打乱数据,确保训练的多样性和随机性。 -
输出数据:最终,经过上述处理的文本和标签将作为输入提供给模型进行训练。每个批次的数据包括编码后的文本和相应的标签序列,保证数据格式的正确性和一致性。
通过这个过程,文本被转化为模型可以接受的数字形式,同时为每个字符提供了对应的标记信息,确保了训练数据的高效处理和准确性。
模型构建
model.py
# -*- coding: utf-8 -*-import torch
import torch.nn as nn
from torch.optim import Adam, SGD
from torchcrf import CRF
"""
建立网络模型结构
"""class TorchModel(nn.Module):def __init__(self, config):super(TorchModel, self).__init__()hidden_size = config["hidden_size"]vocab_size = config["vocab_size"] + 1class_num = config["class_num"]self.embedding = nn.Embedding(vocab_size, hidden_size, padding_idx=0)self.layer = nn.LSTM(hidden_size, hidden_size, batch_first=True, bidirectional=True, num_layers=1)self.classify = nn.Linear(hidden_size * 2, class_num)self.crf_layer = CRF(class_num, batch_first=True)self.use_crf = config["use_crf"]self.loss = torch.nn.CrossEntropyLoss(ignore_index=-1) #loss采用交叉熵损失#当输入真实标签,返回loss值;无真实标签,返回预测值def forward(self, x, target=None):x = self.embedding(x) #input shape:(batch_size, sen_len)x, _ = self.layer(x) #input shape:(batch_size, sen_len, input_dim)predict = self.classify(x) if target is not None:if self.use_crf:mask = target.gt(-1) # 返回判断每个值是否比-1大的结果return -self.crf_layer(predict, target, mask, reduction="mean")else:return self.loss(predict.view(-1, predict.shape[-1]), target.view(-1))else:if self.use_crf:return self.crf_layer.decode(predict)else:return predictdef choose_optimizer(config, model):optimizer = config["optimizer"]learning_rate = config["learning_rate"]if optimizer == "adam":return Adam(model.parameters(), lr=learning_rate)elif optimizer == "sgd":return SGD(model.parameters(), lr=learning_rate)
这段代码展示了如何定义一个用于序列标注任务的神经网络模型,结合 CRF 层进行精确的标签预测,并根据配置选择不同的优化器进行训练。。以下是逻辑顺序的详细解析:
定义模型结构
- TorchModel 类:该类继承自
nn.Module
,表示一个自定义的神经网络模型。
1.1 初始化方法(__init__
):
- 从传入的
config
字典中读取配置项,如:hidden_size
:隐藏层大小,决定了 LSTM 层的输出维度。vocab_size
:词汇表大小,模型使用的词汇表包括一个额外的索引(用于填充),因此vocab_size + 1
。class_num
:分类任务的类别数。
- 初始化各个层:
self.embedding
:使用nn.Embedding
创建词嵌入层,将词汇索引转化为固定维度的嵌入向量,输入的vocab_size
和hidden_size
作为参数。self.layer
:使用nn.LSTM
创建一个双向 LSTM 层,hidden_size
表示 LSTM 的输入和输出维度。batch_first=True
表示输入数据的格式是(batch_size, sequence_length)
,bidirectional=True
使得 LSTM 双向处理输入序列。self.classify
:使用nn.Linear
创建一个全连接层,将 LSTM 的输出映射到分类数目class_num
。self.crf_layer
:使用自定义的 CRF(条件随机场)层进行序列标注任务的解码,通常在命名实体识别、分词等任务中使用。self.use_crf
:从config
中读取是否使用 CRF 层的标志。self.loss
:定义交叉熵损失函数CrossEntropyLoss
,用于计算模型的损失,忽略标签为 -1 的样本。
前向传播方法
2.1 输入处理:
- 输入
x
是一个包含词汇索引的序列,首先通过self.embedding
进行词嵌入,将词汇索引转化为嵌入向量,输出形状为(batch_size, sequence_length, hidden_size)
。
2.2 LSTM 处理:
- 将嵌入后的数据输入到
self.layer
,LSTM 层会输出一个双向的序列表示,输出形状为(batch_size, sequence_length, 2 * hidden_size)
(因为使用了双向 LSTM)。
2.3 分类层:
- 将 LSTM 输出传入
self.classify
层,输出的形状为(batch_size, sequence_length, class_num)
,表示每个时间步的类别预测。
2.4 有目标标签时计算损失:
- 如果输入包含目标标签
target
,判断是否使用 CRF 层:- 使用 CRF:如果
use_crf=True
,通过 CRF 层计算负对数似然损失。首先创建一个掩码(mask)表示有效的标签位置,然后使用 CRF 层计算损失。 - 不使用 CRF:使用标准的交叉熵损失函数计算损失,
predict.view(-1, predict.shape[-1])
和target.view(-1)
将预测值和目标标签拉平成一维,进行损失计算。
- 使用 CRF:如果
2.5 没有目标标签时进行预测:
- 如果没有目标标签
target
,返回模型的预测结果:- 使用 CRF:通过 CRF 层进行解码,返回最可能的标签序列。
- 不使用 CRF:直接返回 LSTM 输出的分类结果。
优化器选择
3.1 输入配置读取:
- 从
config
中读取优化器类型optimizer
(如 Adam 或 SGD)和学习率learning_rate
。
3.2 优化器选择:
- 根据
optimizer
字段的值选择不同的优化器:- Adam:使用
Adam
优化器,传入模型参数和学习率。 - SGD:使用
SGD
优化器,传入模型参数和学习率。
- Adam:使用
总结
- TorchModel:构建了一个包含嵌入层、LSTM 层、分类层和 CRF 层的神经网络模型,支持两种任务模式:训练时计算损失,预测时返回结果。
- 优化器选择:根据配置选择合适的优化器(Adam 或 SGD),并初始化学习率。
主程序
main.py
# -*- coding: utf-8 -*-import torch
import os
import numpy as np
import logging
from config import Config
from model import TorchModel, choose_optimizer
from evaluate import Evaluator
from loader import load_datalogging.basicConfig(level = logging.INFO,format = '%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)"""
模型训练主程序
"""def main(config):#创建保存模型的目录if not os.path.isdir(config["model_path"]):os.mkdir(config["model_path"])#加载训练数据train_data = load_data(config["train_data_path"], config)#加载模型model = TorchModel(config)# 标识是否使用gpucuda_flag = torch.cuda.is_available()if cuda_flag:logger.info("gpu可以使用,迁移模型至gpu")model = model.cuda()#加载优化器optimizer = choose_optimizer(config, model)#加载效果测试类evaluator = Evaluator(config, model, logger)#训练for epoch in range(config["epoch"]):epoch += 1model.train()logger.info("epoch %d begin" % epoch)train_loss = []for index, batch_data in enumerate(train_data):optimizer.zero_grad()if cuda_flag:batch_data = [d.cuda() for d in batch_data]input_id, labels = batch_data #输入变化时这里需要修改,比如多输入,多输出的情况loss = model(input_id, labels)loss.backward()optimizer.step()train_loss.append(loss.item())if index % int(len(train_data) / 2) == 0:logger.info("batch loss %f" % loss)logger.info("epoch average loss: %f" % np.mean(train_loss))evaluator.eval(epoch)model_path = os.path.join(config["model_path"], "epoch_%d.pth" % epoch)torch.save(model.state_dict(), model_path)return model, train_dataif __name__ == "__main__":model, train_data = main(Config)
该代码实现了一个深度学习模型的训练过程,包括数据加载、模型初始化、训练、评估和模型保存等步骤。首先,配置文件加载训练所需的参数,并创建模型保存目录。接着,检测是否有可用的 GPU 来加速训练,并通过配置文件加载优化器。模型进入训练模式后,在每个 epoch 中遍历数据批次,计算损失并执行反向传播与优化器更新,同时记录每个批次的损失。在每个 epoch 结束后,通过评估函数计算模型的表现,并保存当前模型权重。训练完成后,返回训练后的模型和数据,整个过程通过日志输出损失变化,以便监控模型训练效果。
测试与评估
evaluate.py
# -*- coding: utf-8 -*-
import torch
import re
import numpy as np
from collections import defaultdict
from loader import load_data"""
模型效果测试
"""class Evaluator:def __init__(self, config, model, logger):self.config = configself.model = modelself.logger = loggerself.valid_data = load_data(config["valid_data_path"], config, shuffle=False)self.schema = self.valid_data.dataset.schemaself.index_to_label = dict((y, x) for x, y in self.schema.items())def eval(self, epoch):self.logger.info("开始测试第%d轮模型效果:" % epoch)self.stats_dict = dict(zip(self.schema.keys(), [defaultdict(int) for i in range(len(self.schema))]))self.model.eval()for index, batch_data in enumerate(self.valid_data):sentences = self.valid_data.dataset.sentences[index * self.config["batch_size"]: (index+1) * self.config["batch_size"]]if torch.cuda.is_available():batch_data = [d.cuda() for d in batch_data]input_id, labels = batch_data #输入变化时这里需要修改,比如多输入,多输出的情况with torch.no_grad():pred_results = self.model(input_id) #不输入labels,使用模型当前参数进行预测self.write_stats(labels, pred_results, sentences)self.show_stats()returndef write_stats(self, labels, pred_results, sentences):assert len(labels) == len(pred_results) == len(sentences), print(len(labels), len(pred_results), len(sentences))if not self.config["use_crf"]:pred_results = torch.argmax(pred_results, dim=-1)for true_label, pred_label, sentence in zip(labels, pred_results, sentences):if not self.config["use_crf"]:pred_label = pred_label.cpu().detach().tolist()[:len(sentence)]true_label = true_label.cpu().detach().tolist()[:len(sentence)]for pred, gold in zip(pred_label, true_label):key = self.index_to_label[gold]self.stats_dict[key]["correct"] += 1 if pred == gold else 0self.stats_dict[key]["total"] += 1returndef show_stats(self):total = []for key in self.schema:acc = self.stats_dict[key]["correct"] / (1e-5 + self.stats_dict[key]["total"])self.logger.info("符号%s预测准确率:%f"%(key, acc))total.append(acc)self.logger.info("平均acc:%f" % np.mean(total))self.logger.info("--------------------")return
这段代码是一个用于模型评估的类 Evaluator
,主要用于在验证集上评估深度学习模型的性能。它通过与配置文件中的设置相配合,加载验证数据并在模型上进行推理,最后计算预测的准确性。
类初始化
class Evaluator:def __init__(self, config, model, logger):self.config = configself.model = modelself.logger = loggerself.valid_data = load_data(config["valid_data_path"], config, shuffle=False)self.schema = self.valid_data.dataset.schemaself.index_to_label = dict((y, x) for x, y in self.schema.items())
config
:包含了模型训练的配置信息,比如验证数据集的路径、批次大小等。model
:训练好的模型,通常是一个神经网络。logger
:日志记录器,用于记录评估过程中的信息。valid_data
:通过load_data
函数加载验证数据集,这里使用config["valid_data_path"]
提供的路径。schema
:数据集中的标签集合,用于定义每个标签的名称,可能表示分类或标签类别。index_to_label
:将标签的索引映射到标签名称的字典。self.schema.items()
返回标签的键值对,dict((y, x) for x, y in self.schema.items())
将键值对调换,得到标签从索引到名称的映射。
模型评估
def eval(self, epoch):self.logger.info("开始测试第%d轮模型效果:" % epoch)self.stats_dict = dict(zip(self.schema.keys(), [defaultdict(int) for i in range(len(self.schema))]))self.model.eval()for index, batch_data in enumerate(self.valid_data):sentences = self.valid_data.dataset.sentences[index * self.config["batch_size"]: (index+1) * self.config["batch_size"]]if torch.cuda.is_available():batch_data = [d.cuda() for d in batch_data]input_id, labels = batch_datawith torch.no_grad():pred_results = self.model(input_id)self.write_stats(labels, pred_results, sentences)self.show_stats()return
epoch
:当前的训练轮数,用于日志记录,标识模型评估的轮次。self.stats_dict
:一个字典,记录每个标签类别的预测统计数据,包括正确预测和总预测数。使用defaultdict(int)
来自动初始化为整数,方便后续累加。self.model.eval()
:将模型设置为评估模式(eval
),这会关闭像 dropout 这样的训练时特有的操作。- 数据批次处理:通过遍历验证数据集中的每个批次来进行评估。
self.valid_data
是一个数据加载器,按批次返回数据。batch_data
:包含了输入数据和标签的数据。torch.cuda.is_available()
:检查是否有可用的 GPU,如果有,将数据迁移到 GPU 上进行加速计算。input_id, labels = batch_data
:假设batch_data
中包含了输入数据(input_id
)和真实标签(labels
)。with torch.no_grad()
:在此上下文中,关闭梯度计算,节省内存并加速计算,因为评估时不需要进行反向传播。pred_results = self.model(input_id)
:使用当前模型预测输入数据的结果。
write_stats
:将模型的预测结果与真实标签对比,并记录统计信息。show_stats
:显示最终的评估统计结果。
统计记录
def write_stats(self, labels, pred_results, sentences):assert len(labels) == len(pred_results) == len(sentences), print(len(labels), len(pred_results), len(sentences))if not self.config["use_crf"]:pred_results = torch.argmax(pred_results, dim=-1)for true_label, pred_label, sentence in zip(labels, pred_results, sentences):if not self.config["use_crf"]:pred_label = pred_label.cpu().detach().tolist()[:len(sentence)]true_label = true_label.cpu().detach().tolist()[:len(sentence)]for pred, gold in zip(pred_label, true_label):key = self.index_to_label[gold]self.stats_dict[key]["correct"] += 1 if pred == gold else 0self.stats_dict[key]["total"] += 1return
assert
:确保标签、预测结果和句子的长度一致。如果不一致,则输出错误信息。torch.argmax(pred_results, dim=-1)
:如果没有使用 CRF(条件随机场),将模型的输出结果转化为最大值的索引,表示每个位置的预测标签。for true_label, pred_label, sentence in zip(labels, pred_results, sentences)
:遍历每个样本的标签、预测标签和句子。pred_label = pred_label.cpu().detach().tolist()
:将预测标签从 GPU 转移到 CPU,去除梯度信息,并转换为列表,截取与句子长度相同的部分。true_label = true_label.cpu().detach().tolist()
:同样地,处理真实标签。for pred, gold in zip(pred_label, true_label)
:遍历每个单词的预测标签和真实标签。key = self.index_to_label[gold]
:将标签的索引转换为标签名称。- 统计正确预测:如果预测标签与真实标签一致,则增加
correct
,否则不变;无论如何,都会增加total
。
显示统计结果
def show_stats(self):total = []for key in self.schema:acc = self.stats_dict[key]["correct"] / (1e-5 + self.stats_dict[key]["total"])self.logger.info("符号%s预测准确率:%f"%(key, acc))total.append(acc)self.logger.info("平均acc:%f" % np.mean(total))self.logger.info("--------------------")return
total = []
:用于记录每个标签的准确率。for key in self.schema
:遍历所有标签。acc = self.stats_dict[key]["correct"] / (1e-5 + self.stats_dict[key]["total"])
:计算每个标签的准确率。分母中加上1e-5
来避免除以零的情况。self.logger.info()
:记录每个标签的准确率。
np.mean(total)
:计算所有标签的平均准确率,并打印出来。
总结
- 该类主要用于在模型训练后进行模型效果的评估。通过对验证集数据的批量处理、预测结果与真实标签的对比,计算每个标签的预测准确率,并输出平均准确率。
eval
方法是评估的主流程,依次执行数据加载、模型推理、统计记录和结果展示。write_stats
方法负责记录每个标签的预测准确度,show_stats
方法负责展示整体的评估结果。
测试结果
predict.py
# -*- coding: utf-8 -*-
import torch
import json
from config import Config
from model import TorchModel
"""
模型效果测试
"""class SentenceLabel:def __init__(self, config, model_path):self.config = configself.schema = self.load_schema(config["schema_path"])self.index_to_sign = dict((y, x) for x, y in self.schema.items())self.vocab = self.load_vocab(config["vocab_path"])self.model = TorchModel(config)self.model.load_state_dict(torch.load(model_path))self.model.eval()print("模型加载完毕!")def load_schema(self, path):with open(path, encoding="utf8") as f:schema = json.load(f)self.config["class_num"] = len(schema)return schema# 加载字表或词表def load_vocab(self, vocab_path):token_dict = {}with open(vocab_path, encoding="utf8") as f:for index, line in enumerate(f):token = line.strip()token_dict[token] = index + 1 # 0留给padding位置,所以从1开始self.config["vocab_size"] = len(token_dict)return token_dictdef predict(self, sentence):input_id = []for char in sentence:input_id.append(self.vocab.get(char, self.vocab["[UNK]"]))with torch.no_grad():res = self.model(torch.LongTensor([input_id]))[0]res = torch.argmax(res, dim=-1)labeled_sentence = ""for char, label_index in zip(sentence, res):labeled_sentence += char + self.index_to_sign[int(label_index)]return labeled_sentenceif __name__ == "__main__":sl = SentenceLabel(Config, "model_output/epoch_10.pth")sentence = "客厅的颜色比较稳重但不沉重相反很好的表现了欧式的感觉给人高雅的味道"res = sl.predict(sentence)print(res)sentence = "双子座的健康运势也呈上升的趋势但下半月有所回落"res = sl.predict(sentence)print(res)
这部分实现了一个基于深度学习模型的中文文本标注功能。SentenceLabel
类负责加载模型、词表和标签映射。模型通过 TorchModel
加载,并使用 load_state_dict
加载预训练的权重。load_schema
和 load_vocab
方法分别加载标签映射和词表,将句子中的每个字符转换为词汇表中的索引。predict
方法将输入句子转换为模型输入,进行预测并输出带标签的句子。
输入文本:
"客厅的颜色比较稳重但不沉重相反很好的表现了欧式的感觉给人高雅的味道"
"双子座的健康运势也呈上升的趋势但下半月有所回落"
文本加标点效果:
客厅的颜色比较稳重,但不沉重相反很好的表现了欧式的感觉给人高雅的味道。
双子座的健康运势也呈上升的趋势,但下半月有所回落。
相关文章:
Day09 【基于LSTM实现文本加标点的任务】
基于LSTM实现文本加标点的任务 目标数据准备参数配置数据处理模型构建定义模型结构前向传播方法优化器选择 主程序测试与评估类初始化模型评估统计记录显示统计结果 测试结果 目标 本文基于给定的词表,将输入的文本基于jieba分词分割为若干个词,然后基于…...
SQL刷题日志(day2)
1、timestampdiff:计算时间间隔 timestampdiff(unit,start_date,end_date) 参数说明: unit:返回的时间单位,如minute,hour等start_date:开始日期end_date:结束日期 2、dense_rank(ÿ…...
仿 ElementUI 搭建自己的 vue 组件库
仿 ElementUI 搭建自己的 vue 组件库 一、创建 my-ui-can 项目1. 新建项目2. 自定义组件3. 创建 MyButton 组件4. 导出组件5. package.json 二、发布到 npm 仓库1. npm 账号注册(忽略)2. 发布 my-ui-can 二、项目引用 my-ui-can 依赖包方式一:…...
CentOS 操作系统下搭建 tsung性能测试环境
写在前面 为何这么安装,实际就是这么做的,这是经过好几次实践得出的经验总结。 这为了让大家更清楚的知道怎么安装 tsung性能测试环境,按步照搬的安装即可。 步骤 1、 下载软件安装包 CentOS-6.0-x86_64-bin-DVD1.iso jdk-6u4-linux-x64-rpm.bin erlang: otp_src_1…...
基于YOLOv9的课堂行为检测系统
基于YOLOv9的课堂行为检测系统 项目概述 本项目是一个基于YOLOv9深度学习模型的课堂行为检测系统,旨在通过计算机视觉技术自动识别和监测课堂中学生的各种行为状态,帮助教师更好地了解课堂教学效果。 项目结构 课堂行为检测/ ├── data/ │ ├──…...
Linux常见工具的基本使用,同时介绍了编译过程和动/静态链接的原理
目录 一、工具的本质 二、一些常用的工具 1.yum 2.vim 1)vim的三种基本模式: 2)vim的基本操作 ①命令模式下的基本操作: ②插入模式: ③底行模式: 3)vim的配置:让他变得更好用 3.gcc…...
6.(vue3.x+vite)动态挂载组件并传递参数和方法
1:效果截图 2:父组件代码 <template><div id="cesiumID"></div><div>子组件使用方法传递给父组件的值:{...
大数据人工智能
在大数据人工智能领域,需要具备多种算法和深度学习知识,以下是一些常见的: 机器学习算法 - 线性回归:用于建立输入特征与连续型输出变量之间的线性关系,常用于预测数值型数据。 - 逻辑回归:主要用于二分类…...
Vue3 nextTick
nextTick 是 Vue 中非常重要的一个 API,它允许你在 DOM 更新周期后执行延迟回调。 核心源码位置 Vue3 的 nextTick 实现主要在 packages/runtime-core/src/scheduler.ts 文件中。 基本实现 const resolvedPromise Promise.resolve() as Promise<any> let …...
快速入手-基于python和opencv的人脸检测
1、安装库 pip install opencv-python 如果下载比较卡的话,指向国内下载地址: pip3 install opencv-python -i https://pypi.tuna.tsinghua.edu.cn/simple 2、下载源码 https://opencv.org/ windows11对应的版本下载: https://pan.baidu…...
第七节:React HooksReact 18+新特性-并发模式(Concurrent Mode)解决了什么问题?
• 考点:可中断渲染、优先级调度、startTransition使用场景 • 示例:搜索框输入防抖优化 React Hooks 进阶:自定义 Hook 设计实战指南(以 useWindowSize 和 useFetch 为例) 一、自定义 Hook 设计规范 在实现 useWind…...
jwt的无感刷新
jwt无感刷新 如果没有引入额外的刷新机制,JWT 过期后后续请求就会因验证失败而拒绝,导致用户需要重新登录,从而被“强制下线”。为实现无感刷新,可以考虑以下几种方案: 引入 Refresh Token 双 token 机制:…...
Linux:安装 CentOS 7(完整教程)
文章目录 一、简介二、安装 CentOS 72.1 虚拟机配置2.2 安装CentOS 7 三、连接远程服务器(扩展)3.1 获取虚拟机 IP 地址3.2 连接远程服务器 四、结语 一、简介 CentOS(Community ENTerprise Operating System)是一个基于 Linux 的…...
【YOLOv8改进- Backbone主干】CVPR2025 MambaOut :为图像分类任务设计的轻量级模型,曼巴永存!
YOLOV8目标检测创新改进与实战案例专栏 专栏目录: YOLOV8有效改进系列及项目实战目录 包含卷积,主干 注意力,检测头等创新机制 以及 各种目标检测分割项目实战案例 专栏链接: YOLOV8基础解析+创新改进+实战案例 介绍 摘要 “曼巴(Mamba)是一种具有状态空间模型(SSM)的…...
thanos与VictoriaMetrics对比
Thanos 和 VictoriaMetrics 都是开源的时序数据库(TSDB)解决方案,通常用于存储、查询和管理大规模的时间序列数据,尤其是监控数据。尽管它们在功能上有一些重叠,但它们各自的设计目标、架构、以及适用场景存在差异。以…...
ubuntu 24.02部署java web服务
ubuntu 24.02 版本推荐使用jdk 21版本部署java web服务,开发后先使用sudo java -jar xxx.jar验证运行结果。 jdk安装:sudo apt install openjdk-21-jdk-headless 编辑服务文本 [Unit] DescriptionWebMgr Java Application Afternetwork.target mysql.…...
时序数据预测:TDengine 与机器学习框架的结合(一)
一、引言 在当今数字化时代,时序数据如潮水般涌来,广泛存在于物联网、工业监控、金融交易、气象监测等众多领域。这些按时间顺序记录的数据蕴含着丰富的信息,对其进行准确预测,能够为企业和组织的决策提供有力支持,带…...
SvelteKit 最新中文文档教程(20)—— 最佳实践之性能
前言 Svelte,一个语法简洁、入门容易,面向未来的前端框架。 从 Svelte 诞生之初,就备受开发者的喜爱,根据统计,从 2019 年到 2024 年,连续 6 年一直是开发者最感兴趣的前端框架 No.1: Svelte …...
Spark-SQL核心编程(二)(三)
Spark-SQL核心编程(二) DSL 语法 DataFrame 提供一个特定领域语言(domain-specific language, DSL)去管理结构化的数据。 可以在 Scala, Java, Python 和 R 中使用 DSL,使用 DSL 语法风格不必去创建临时视图了。 1.创建一个 DataFrame val d…...
Godot学习-创建简单动画
文章目录 1、准备工作Godot资源 2、创建项目3、创建结点4、创建动画1、创建动画2、添加轨道3、创建关键帧3.1 第一个关键帧3.2 第二个关键帧 5、加载后自动播放6、动画循环7、轨道设置1、轨道更新模式2、轨迹插值3、其他属性的关键帧4、编辑关键帧5、使用 RESET 轨道6、洋葱皮 …...
新加坡太白私募:金融创新与稳健发展的典范
在全球金融市场的版图中,新加坡太白私募正以其独特的魅力和卓越的表现,成为众多投资者关注的焦点。作为一家在新加坡注册成立的私募机构,太白私募自诞生以来,便凭借着创新的理念、专业的团队和稳健的运营,在激烈的市场…...
[MySQL] 事务管理(二) 事务的隔离性底层
事务的隔离性底层 1.数据库并发的场景2.读-写2.1MVCC三个变量2.1.1 3个记录隐藏列字段2.1.2 undo日志 模拟MVCCselect 的读取2.1.3 Read View(读视图) 3.RR与RC的区别 1.数据库并发的场景 读-读:不存在问题,也不需要并发控制读-写…...
【Netty篇】EventLoopGroup 与 EventLoop 详解
目录 开场白:话说 Netty 江湖第一段:EventLoopGroup——“包工头”的角色第二段:EventLoop——“身怀绝技的工人”第三段:EventLoop 如何处理 I/O 事件、普通任务和定时任务第四段:Handler 执行中如何换人?…...
vscode连接windows服务器出现过程试图写入的管道不存在
优云智算平台的windows 1. 确保 Windows 已启用 OpenSSH 服务器 Get-WindowsCapability -Online | Where-Object Name -like OpenSSH.Server* 如果 State 是 NotPresent,说明未安装。 如果 State 是 Installed,说明已安装。 安装 OpenSSH Server&am…...
Windows VsCode Terminal窗口使用Linux命令
背景描述: 平时开发环境以Linux系统为主,有时又需要使用Windows系统下开发环境,为了能像Linux系统那样用Windows VsCode,Terminal命令行是必不可少内容。 注:Windows11 VsCode 1.99.2 下面介绍,如何在V…...
19【干获】如何快速在GIS某个图斑中抠出空洞
应用场景:在图斑中扣取空洞,很多时候是因为CAD数据在转换为GIS文件时,由于CAD作图不规范,例如填充本身不严谨,导致转换后,一个大地块包含的小地块范围不见了,只有大地块;或者会存在两…...
基于YOLO11的跌倒检测报警系统
基于YOLO11的跌倒检测报警系统 【包含内容】 【一】项目提供完整源代码及详细注释 【二】系统设计思路与实现说明 【三】完整的视频/摄像头/图片检测与报警功能 【技术栈】 ①:系统环境:Windows/MacOS/Linux通用 ②:开发环境:Py…...
十、自动化函数+实战
Maven环境配置 1.设计测试用例 2.创建空项目 1)添加需要的依赖pom.xml <dependencies> <!-- 截图配置--><dependency><groupId>commons-io</groupId><artifactId>commons-io</artifactId><version>2.6</…...
面向初学者的JMeter实战手册:从环境搭建到组件解析
🌟 大家好,我是摘星! 🌟 今天为大家带来的是面向初学者的JMeter实战手册:从环境搭建到组件解析,废话不多说,让我们直接开始~ 目录 1. JMeter简介 2. JMeter安装与配置 2.1. 安装 2.2.…...
【正点原子STM32MP257连载】第四章 ATK-DLMP257B功能测试——PCIE2.0 x1接口测试
1)实验平台:正点原子ATK-DLMP257B开发板 2)浏览产品:https://www.alientek.com/Product_Details/135.html 3)全套实验源码手册视频下载:正点原子资料下载中心 文章目录 第四章 ATK-DLMP257B功能测试——PCI…...
云函数采集架构:Serverless模式下的动态IP与冷启动优化
在 Serverless 架构中使用云函数进行网页数据采集,不仅能大幅降低运维成本,还能根据任务负载动态扩展。然而,由于云函数的无状态特性及冷启动问题,加上目标网站对采集行为的反制措施(如 IP 限制、Cookie 校验等&#x…...
UE5 设置物体的位置
UE的位置设置和untiy不同,UE的对象分为根物体和组件,他们的设置方法不同 对于蓝图根物体 可以直接当作Actor处理,设置它的世界位置 对于蓝图的组件 设置世界位置: 设置相对位置...
【adb】bat批处理+adb 自动亮屏,自动解锁屏幕,启动王者荣耀
准备adb 下载 需要确认是否安装了adb.exe文件,可以在: 任务管理器 -->详细信息–>找一下后台运行的adb 安装过anroid模拟器,也存在adb,例如:雷电安装目录 D:\leidian\LDPlayer9 单独下载adb 官方下载地址:[官方网址] 下载目录文件: 测试adb USB连接手机 首先在设置界…...
【计算机网络】3数据链路层①
这篇笔记专门讲数据链路层的功能。 2.功能 数据链路层的主要任务是让帧在一段链路上或一个网络中传输。 2.1.封装成帧(组帧) 解决的问题:①帧定界②帧同步③透明传输 实现组帧的方法通常有以下种。 2.1.1.字符计数法 原理:在每个帧开头,用一个定长计数字段来记录该…...
OSPF路由协议
OSPF(开放式最短路径优先) 1、回顾 rip:v1(广播发送、路由自动汇总,不支持可变长子网)v2(组播发送,默认不汇总路由,支持可变长子网)封装在UDP的520端口中&a…...
线代第二章矩阵第三、四课:矩阵乘法和方阵的幂
文章目录 矩阵的乘法矩阵的可交换方阵的幂 矩阵的乘法 (1)乘法的前提条件: 第一个矩阵的列数等于第二个矩阵的行数 (2)结果阵的形状: 结果矩阵的行数=第一个矩阵的行数 结果矩阵的列数=第二个矩阵的列数 乘法不满足交换律: &am…...
if constexpr
if constexpr if constexpr 是 C17 引入的一个强大的特性,它允许在编译时根据条件选择性地编译代码块。与普通的 if 语句不同,if constexpr 的条件必须是一个编译时可计算的常量表达式(constexpr 表达式)。如果条件为 true&#…...
JAVA程序实现mysql读写分离并在kubernetes中演示
1 概述 对数据进行读写分离,可以将读流量从主数据库中剥离出来,进一步降低读操作对写操作的影响。读写分离的实现可以有多种方式,例如通过proxySQL、mycat等中间件来实现,也可以在应用进程内实现。本文介绍JAVA程序通过spring框架…...
HarmontOS-ArkUI V2状态 !!语法糖 双向绑定
什么是双向绑定 双向绑定指的是在组件间数据的双向绑定。当一个值无论是在父组件还是子组件中改动都会在这两层中都更新界面。 回顾过往的“双向绑定”实现方式 靠@Event装饰回调函数 一般是对于@Param修饰的状态变量。当子组件发生某个动作的时候,调用某个父组件传递过来的…...
Linux驱动开发进阶(十)- I2C子系统BSP驱动
文章目录 1、前言2、I2C总线注册3、I2C设备注册4、I2C驱动注册总结 1、前言 学习参考书籍以及本文涉及的示例程序:李山文的《Linux驱动开发进阶》本文属于个人学习后的总结,不太具备教学功能。 2、I2C总线注册 和其它总线驱动一样,I2C驱动…...
Vue 3 路由配置使用与讲解
在现代前端开发中,单页应用(SPA)已成为主流趋势,Vue.js 作为一款优秀的 JavaScript 框架,在构建 SPA 方面表现出色。Vue Router 作为 Vue.js 官方的路由管理器,与 Vue.js 核心深度集成,极大地简…...
7系列fpga在线升级和跳转
一、常见跳转方式 1,一般FPGA只要上电,就会自动从外部flash的0地址加载程序。2,而我们所谓的在线式升级就是在flash0地址放一个程序(boot/golden image),然后在后面再放一个程序(app/update im…...
解决靶机分配的 IP 地址与 Kali 机器静态 IP 地址冲突的方法
在网络安全学习或渗透测试中,经常会遇到靶机和 Kali 机器处于同一网络环境的情况。如果靶机通过 DHCP 自动获取的 IP 地址与 Kali 机器手动设置的静态 IP 地址发生冲突,就会导致网络通信异常,例如无法正常 ping 通或访问目标。本文将详细介绍…...
LLM做逻辑推理题 - 飞机事件
题目: 有N架一样的飞机停靠在同一个机场,每架飞机都只有一个油箱,每箱油可使飞机绕地球飞半圈。注意:天空没有加油站,飞机之间只是可以相互加油。如果使某一架飞机平安地绕地球飞一圈,并安全地回到起飞时的机场&#x…...
【Netty4核心原理】【全系列文章目录】
文章目录 一、前言二、目录 一、前言 本系列虽说本意是作为 《Netty4 核心原理》一书的读书笔记,但在实际阅读记录过程中加入了大量个人阅读的理解和内容,因此对书中内容存在大量删改。 本系列内容基于 Netty 4.1.73.Final 版本,如下…...
SAP ECCS 标准报表 切换为EXCEL电子表格模式
在解决《SAP ECCS标准报表在报表中不存在特征CG细分期间 消息号 GK715报错分析》问题过程中通过DEBUG方式参照测试环境补录数据后,不再报GK715错误,此时用户要的很急,要出季报。要求先把数据导出供其分析出季报。 采用导出列表方式ÿ…...
开源推荐#6:可爱的临时邮箱服务
大家后,我是 jonssonyan。 我们的邮箱常常被各种推广邮件、验证码甚至垃圾邮件淹没。每次注册新服务或临时需要一个邮箱时,都担心自己的主邮箱地址被泄露或滥用?也许你用过一些公共的临时邮箱服务,但数据隐私和可控性总是让人不那…...
SpringBoot企业级开发之【用户模块-更新用户密码】
具体内容: 依旧是查看接口文档信息: 开发思路: 实操: 1.controller //更新用户密码PatchMapping("/updatePwd")public Result updatePwd(RequestBody Map<String,String> params) {//1.校验参数String oldPwdparams.get(…...
MyBatis-Plus 通过 ID 更新数据为NULL总结
在使用 MyBatis-Plus 通过 ID 更新数据时,若需将字段值设为 null,可参考以下解决方案: 方法一:使用 TableField 注解 在实体类字段上添加注解,指定更新策略为忽略非空检查: public class User {TableFie…...
SpringCloud Alibaba微服务工程搭建
前言 在讲微服务工程的搭建之前,我们先分析下为什么要使用微服务呢? 1、单体应用的痛点 维护困难:代码臃肿,牵一发而动全身。扩展性差:无法按需扩展特定功能,只能整体扩容。技术栈僵化:难以引…...