简述

最近接了对Ticket 进行问题分类的任务,使用了prompt和机器学习两种方式来解决,这里重点介绍Longformer-base-4096 模型训练的方案

使用 Longformer-base-4096 模型实现文本分类系统,利用 Longformer 处理长序列的能力进行准确分类。该解决方案旨在实现稳健、可扩展且高效的目标,将先进的自然语言处理 (NLP) 技术与实际工程设计相结合。

Longformer-base-4096 适合文本分类任务

1. 支持更长的输入(4096 tokens)

  • 相比 BERT(512 tokens)、RoBERTa(512 tokens)等模型,Longformer 支持多达 4096 个 token 的输入

  • 适合处理工单系统、客户邮件、日志摘要、IT 系统输出等长文本分类任务,避免信息截断带来的语义丢失。

2. 高效稀疏注意力机制

  • 使用 滑动窗口 + 全局注意力机制,相比 Transformer 的全连接注意力,计算效率更高、内存占用更低。

  • ✅ 可以在有限的显存下处理比普通模型长 8 倍的文本。

3. 继承 RoBERTa 的语义理解能力

  • Longformer-base-4096 是在 RoBERTa-base 的基础上改造的,具有优秀的语言理解能力和上下文捕捉能力。

  • ✅ 不仅“长”,还具备准确的语义建模能力,可用于精细分类、多维推理场景(如工单分类、多标签分类、合规判断等)。

4. 更少的切分(chunking)需求

  • 常规 Transformer 模型处理长文本时需要切块(chunking)并聚合结果,增加了处理复杂度且可能引入误差。

  • ✅ Longformer 可以直接处理长文本整体,提高端到端分类的准确率与一致性

5. 支持全局关注(Global Attention)机制

  • 可以为某些关键 token(如标题、系统名、时间、告警词等)设定全局关注,增强对关键信息的感知。

  • 非常适合提示词引导、头部信息重要的 IT 工单或报告类文本的分类任务

6. 预训练模型广泛,开源生态良好

  • allenai/longformer-base-4096 是 Hugging Face 上非常活跃的模型,有许多下游任务的使用案例(分类、QA、摘要、RAG 等)。

与其他模型比较

模型最大输入 token是否适合长文本分类是否开源是否高效
BERT-base512否(需截断或chunk)
RoBERTa-base512
Longformer-base4096
BigBird4096✅(稀疏注意力)一般
GPT-3 / GPT-42048~32k✅(封闭API)❌(贵)

数据准备

使用真实生产数据,标题+描述可能超过标准如 512 tokens的任务

加载与拼接:将标题与描述通过 [SEP] token 拼接,作为每条样本的输入文本。对缺失值进行填充(使用空字符串),以提升鲁棒性。

标签编码:使用 scikit-learn 的 LabelEncoderissue_type_name 字段进行编码,便于模型训练。

数据集划分:按照标签分布使用分层采样将数据集划分为训练集(80%)、验证集(10%)和测试集(10%)。

分词:

  • 使用 Hugging Face 的 AutoTokenizer 进行分词,最大长度设为 4096。

  • 启用自动填充和截断以确保统一输入长度。

  • 将分词后的数据缓存至本地磁盘,提高后续运行效率。

模型配置:

  • 预训练模型:longformer-base-4096

  • 最大序列长度:4096 tokens

  • 隐藏层维度:768

  • 注意力头数量:12

  • Transformer 层数:12

模型训练

自定义 SingleTaskModel 类,基于 Longformer 构建:

  • 基础模型:加载 longformer-base-4096 生成上下文嵌入。

  • 分类头:使用线性层将 [CLS] token 的输出(768维)映射到具体的类别数。

  • 损失函数:使用交叉熵损失进行多分类训练。

使用 Hugging Face 的 Trainer API,并通过 SingleTaskTrainer 进行定制化训练以适配 Longformer:

训练参数:

  • 训练轮数:10

  • 批大小:2(通过梯度累积 16 步模拟更大批次,以适配显存)

  • 学习率:2e-5

  • 混合精度训练(fp16=True)以提升训练速度

  • 评估策略:每 50 步评估一次

  • 保存策略:按验证集 F1 得分保存最佳模型

缓存机制:将分词后的数据集缓存至磁盘,避免重复处理。

评估指标:准确率(Accuracy)与加权 F1 分数,用于评估在类别不均衡数据下的性能。

训练代码如下

import pandas as pd
import numpy as np
from datasets import Dataset, load_from_disk
from transformers import AutoTokenizer, AutoModel, Trainer, TrainingArguments
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import LabelEncoder
import evaluate
import torch
import torch.nn as nn
import os
import joblib
import json
from safetensors.torch import save_file# Set random seed for reproducibility
torch.manual_seed(42)
np.random.seed(42)# Check for CUDA
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
print(f"Using device: {device}")# 1. Load and prepare the JSON dataset
def load_json(file_path):with open(file_path, 'r') as f:data = json.load(f)df = pd.DataFrame(data)df['text'] = df['title'].fillna('') + ' [SEP] ' + df['description'].fillna('')return df# 2. Split dataset into train, validation, and test
def split_dataset(df):train_val, test = train_test_split(df, test_size=0.1, random_state=42)train, val = train_test_split(train_val, test_size=0.11, random_state=42)return train, val, test# 3. Encode string labels for single task
def encode_labels(df, label_columns=['issue_type_name']):label_encoders = {}for col in label_columns:le = LabelEncoder()df[f'labels_{col}'] = le.fit_transform(df[col].fillna('Unknown'))label_encoders[col] = lereturn df, label_encoders# 4. Tokenize function for single-task (no chunking during tokenization)
def tokenize_function(examples):input_ids_batch = []attention_mask_batch = []labels_batch = []original_idx_batch = []for idx, (text, label) in enumerate(zip(examples['text'],examples['labels_issue_type_name'])):if text is None or pd.isna(text) or not isinstance(text, str):print(f"Warning: Skipping invalid text at index {idx}: {text}")continuetry:tokenized = tokenizer(text,padding='max_length',truncation=True,max_length=4096,return_tensors='pt')input_ids_batch.append(tokenized['input_ids'][0].tolist())attention_mask_batch.append(tokenized['attention_mask'][0].tolist())labels_batch.append(label)original_idx_batch.append(idx)print(f"Text index {idx}: input_ids len={len(tokenized['input_ids'][0])}, attention_mask len={len(tokenized['attention_mask'][0])}, label={label}")except Exception as e:print(f"Error tokenizing text at index {idx}: {e}")continue# Verify array lengthslengths = {'input_ids': len(input_ids_batch),'attention_mask': len(attention_mask_batch),'labels': len(labels_batch),'original_idx': len(original_idx_batch)}print(f"Batch lengths: {lengths}")if not (lengths['input_ids'] == lengths['attention_mask'] == lengths['labels'] == lengths['original_idx']):raise ValueError(f"Array length mismatch: {lengths}")return {'input_ids': input_ids_batch,'attention_mask': attention_mask_batch,'labels': labels_batch,'original_idx': original_idx_batch}# 5. Chunk long texts for inference (if needed)
def chunk_text(text, max_length=4096, stride=2048):tokens = tokenizer(text, add_special_tokens=False, return_tensors='pt')['input_ids'][0].to(device)chunks = []for i in range(0, len(tokens), max_length - 2):chunk = tokens[i:i + max_length - 2]chunk = torch.cat([torch.tensor([tokenizer.cls_token_id], device=device),chunk,torch.tensor([tokenizer.sep_token_id], device=device)])chunks.append(chunk)return chunks# 6. Aggregate predictions for chunked texts (used during inference)
def aggregate_predictions(logits, original_indices, num_original_samples):text_logits = {}for logit, idx in zip(logits, original_indices):if idx not in text_logits:text_logits[idx] = []text_logits[idx].append(logit)aggregated_logits = []for idx in range(num_original_samples):if idx in text_logits:aggregated_logits.append(np.mean(text_logits[idx], axis=0))else:aggregated_logits.append(np.zeros(logits.shape[1]))print(f"Warning: No logits for index {idx}, using zeros")print(f"Aggregated logits length: {len(aggregated_logits)}, Expected: {num_original_samples}")return np.array(aggregated_logits)# 7. Cache tokenized datasets
def load_or_tokenize(dataset, cache_path, remove_columns):if os.path.exists(cache_path):print(f"🔁 Loading cached dataset from {cache_path}")return load_from_disk(cache_path)else:print(f"🧪 Tokenizing and caching to {cache_path}")try:tokenized = dataset.map(tokenize_function, batched=True, batch_size=1, remove_columns=remove_columns)tokenized.save_to_disk(cache_path)return tokenizedexcept Exception as e:print(f"Error during tokenization: {e}")raise# 8. Single-Task Model for Issue Type Name
class SingleTaskModel(nn.Module):def __init__(self, base_model, num_labels):super().__init__()self.base_model = base_modelself.classifier = nn.Linear(base_model.config.hidden_size, num_labels)def forward(self, input_ids, attention_mask=None, labels=None, **kwargs):outputs = self.base_model(input_ids=input_ids, attention_mask=attention_mask)hidden_state = outputs[0][:, 0, :]  # CLS tokenlogits = self.classifier(hidden_state)loss = Noneif labels is not None:loss = nn.CrossEntropyLoss()(logits, labels)return {'loss': loss,'logits': logits}# 9. Custom Trainer for Single-Task
class SingleTaskTrainer(Trainer):def __init__(self, *args, num_original_samples=None, **kwargs):super().__init__(*args, **kwargs)self.num_original_samples = num_original_samplesself.chunk_indices = []def compute_loss(self, model, inputs, return_outputs=False):inputs.pop('original_idx', None)outputs = model(**{k: v.to(device) for k, v in inputs.items()})loss = outputs['loss']return (loss, outputs) if return_outputs else lossdef prediction_step(self, model, inputs, prediction_loss_only, ignore_keys=None):chunk_idx = inputs.pop('original_idx', None)labels = inputs.pop('labels', None)if chunk_idx is None:print("Warning: chunk_idx is None, assuming no chunking for this batch")chunk_idx = list(range(len(inputs['input_ids'])))print(f"Chunk indices length: {len(chunk_idx)}")print(f"Eval dataset size: {len(self.eval_dataset)}")self.chunk_indices.extend(chunk_idx.tolist() if isinstance(chunk_idx, torch.Tensor) else chunk_idx)with torch.no_grad():outputs = model(**{k: v.to(device) for k, v in inputs.items()})logits = outputs['logits']loss = Noneif labels is not None:loss = nn.CrossEntropyLoss()(logits, labels.to(device))return (loss, logits, labels)# 10. Compute metrics for evaluation
def compute_metrics(eval_pred):logits, labels = eval_predif trainer.chunk_indices:logits = aggregate_predictions(logits, trainer.chunk_indices, num_original_samples=len(trainer.eval_dataset))labels = np.array(labels[:len(trainer.eval_dataset)])else:labels = np.array(labels)predictions = np.argmax(logits, axis=1)return {"accuracy_issue_type_name": accuracy_metric.compute(predictions=predictions, references=labels)["accuracy"],"f1_issue_type_name": f1_metric.compute(predictions=predictions, references=labels, average='weighted')["f1"]}# Main execution
if __name__ == "__main__":# File pathfile_path = "./PRD-9191.json"# Load and preprocess datasetdf = load_json(file_path)print(f"Loaded dataset with {len(df)} samples")df, label_encoders = encode_labels(df, ['issue_type_name'])num_labels = len(label_encoders['issue_type_name'].classes_)print(f"Number of issue_type_name classes: {num_labels}")# Load model and tokenizermodel_name = "./longformer-base-4096"tokenizer = AutoTokenizer.from_pretrained(model_name)base_model = AutoModel.from_pretrained(model_name)model = SingleTaskModel(base_model, num_labels).to(device)# Split datasettrain_df, val_df, test_df = split_dataset(df)# Convert to Hugging Face Datasetstrain_dataset = Dataset.from_pandas(train_df[['text', 'labels_issue_type_name']],preserve_index=False)val_dataset = Dataset.from_pandas(val_df[['text', 'labels_issue_type_name']],preserve_index=False)test_dataset = Dataset.from_pandas(test_df[['text', 'labels_issue_type_name', 'issue_type_name']],preserve_index=False)# Print dataset sizes for debuggingprint(f"Original training dataset size: {len(train_dataset)}")print(f"Original validation dataset size: {len(val_dataset)}")print(f"Original test dataset size: {len(test_dataset)}")# Tokenize datasetstokenized_train = load_or_tokenize(train_dataset, f"cache/train_issue_type", remove_columns=['text'])tokenized_val = load_or_tokenize(val_dataset, f"cache/val_issue_type", remove_columns=['text'])tokenized_test = load_or_tokenize(test_dataset, f"cache/test_issue_type", remove_columns=['text', 'issue_type_name'])# Print tokenized dataset sizes for debuggingprint(f"Tokenized training dataset size: {len(tokenized_train)}")print(f"Tokenized validation dataset size: {len(tokenized_val)}")print(f"Tokenized test dataset size: {len(tokenized_test)}")# Training argumentstraining_args = TrainingArguments(output_dir=f"./checkpoints_issue_type",num_train_epochs=10,per_device_train_batch_size=2,per_device_eval_batch_size=4,gradient_accumulation_steps=16,learning_rate=2e-5,fp16=True,evaluation_strategy="steps",eval_steps=50,save_strategy="steps",save_steps=1000,load_best_model_at_end=True,metric_for_best_model="eval_f1_issue_type_name",save_total_limit=1,logging_dir=f"./logs_issue_type",logging_steps=10,)# Metricsaccuracy_metric = evaluate.load("accuracy")f1_metric = evaluate.load("f1")# Initialize trainertrainer = SingleTaskTrainer(model=model,args=training_args,train_dataset=tokenized_train,eval_dataset=tokenized_val,compute_metrics=compute_metrics,num_original_samples=len(val_dataset),)# Save label encodersoutput_le_path = f"./checkpoints_issue_type"os.makedirs(output_le_path, exist_ok=True)joblib.dump(label_encoders['issue_type_name'], f"{output_le_path}/label_encoder_issue_type_name.pkl")# Clear chunk indices before trainingtrainer.chunk_indices = []# Traintrainer.train()# Save model in SafeTensors formattrainer.save_model(f"./final_model_issue_type")state_dict = model.state_dict()save_file(state_dict, f"./final_model_issue_type/model.safetensors")# Evaluate on test setprint("\nEvaluating on Test Set...")test_results = trainer.evaluate(tokenized_test)print("Test Results:", test_results)

高效性:通过滑动窗口注意力机制将复杂度从 O(n²) 降至 O(n),显著降低内存占用,使得在消费级 GPU 上也可训练。

鲁棒的数据处理流程:处理缺失值、不合法输入以及极长文本,提高模型在实际场景中的稳定性。

可扩展性:数据缓存机制和混合精度训练优化了计算资源,为大规模训练做好准备。

平衡评估:加权 F1 得分衡量所有类别表现,尤其适用于类别不均的实际数据。

测试集自测结果

Aggregated logits length: 5772, Expected: 5772
Test Results: {'eval_loss': 0.5606201887130737,'eval_accuracy_issue_type_name': 0.02442827442827443,'eval_f1_issue_type_name': 0.0028243325750626426,'eval_runtime': 234.714,'eval_samples_per_second': 24.839,'eval_steps_per_second': 1.555,'epoch': 9.98
}

接口测试

封装 fastapi接口

import torch
import numpy as np
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
from transformers import AutoTokenizer, AutoModel
import joblib
from safetensors.torch import load_file
import torch.nn as nn
import uvicorn
import os# Initialize FastAPI app
app = FastAPI()# Check for CUDA
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")# Define input data model
class InputData(BaseModel):title: strdescription: str# Single-Task Model for Issue Type Name (same as in training)
class SingleTaskModel(nn.Module):def __init__(self, base_model, num_labels):super().__init__()self.base_model = base_modelself.classifier = nn.Linear(base_model.config.hidden_size, num_labels)def forward(self, input_ids, attention_mask=None):outputs = self.base_model(input_ids=input_ids, attention_mask=attention_mask)hidden_state = outputs[0][:, 0, :]  # CLS tokenlogits = self.classifier(hidden_state)return logits# Load model, tokenizer, and label encoder
model_path = "./final_model_issue_type"
tokenizer_path = "./longformer-base-4096"
label_encoder_path = f"{model_path}/label_encoder_issue_type_name.pkl"try:tokenizer = AutoTokenizer.from_pretrained(tokenizer_path)base_model = AutoModel.from_pretrained(tokenizer_path)num_labels = len(joblib.load(label_encoder_path).classes_)model = SingleTaskModel(base_model, num_labels).to(device)state_dict = load_file(f"{model_path}/model.safetensors")model.load_state_dict(state_dict)model.eval()label_encoder = joblib.load(label_encoder_path)
except Exception as e:raise Exception(f"Error loading model or tokenizer: {e}")# Function to chunk text if needed
def chunk_text(text, max_length=4096, stride=2048):tokens = tokenizer(text, add_special_tokens=False, return_tensors='pt')['input_ids'][0].to(device)chunks = []for i in range(0, len(tokens), max_length - 2):chunk = tokens[i:i + max_length - 2]chunk = torch.cat([torch.tensor([tokenizer.cls_token_id], device=device),chunk,torch.tensor([tokenizer.sep_token_id], device=device)])chunks.append(chunk)return chunks# Function to aggregate predictions
def aggregate_predictions(logits):return np.mean(logits, axis=0)# Prediction endpoint
@app.post("/predict")
async def predict(data: InputData):try:# Combine title and descriptiontext = f"{data.title} [SEP] {data.description}"# Tokenize inputchunks = chunk_text(text)all_logits = []for chunk in chunks:inputs = {'input_ids': chunk.unsqueeze(0),'attention_mask': torch.ones_like(chunk).unsqueeze(0)}inputs = {k: v.to(device) for k, v in inputs.items()}# Get model predictionswith torch.no_grad():logits = model(**inputs)all_logits.append(logits.cpu().numpy())# Aggregate logits if multiple chunksaggregated_logits = aggregate_predictions(np.vstack(all_logits))probabilities = torch.softmax(torch.tensor(aggregated_logits), dim=-1).numpy()# Get top 5 predictionstop_5_indices = np.argsort(probabilities)[-5:][::-1]top_5_labels = label_encoder.inverse_transform(top_5_indices)top_5_probs = probabilities[top_5_indices]# Prepare responseresult = [{"label": label, "confidence": float(prob)}for label, prob in zip(top_5_labels, top_5_probs)]return {"predictions": result}except Exception as e:raise HTTPException(status_code=500, detail=f"Prediction error: {str(e)}")# Run the app
if __name__ == "__main__":uvicorn.run(app, host="0.0.0.0", port=5000)

使用postman 调用测试 

在验证数据集上进行覆盖测试

def get_prediction(title, description):payload = {"title": title,"description": description}try:response = requests.post(API_URL, json=payload, headers={'Content-Type': 'application/json'})response.raise_for_status()predictions = response.json().get("predictions", [])if not predictions:print(f"Warning: No predictions returned for title: {title}")return None# Get the top prediction (highest confidence)top_prediction = max(predictions, key=lambda x: x['confidence'])return top_prediction['label']except requests.RequestException as e:print(f"Error calling API for title: {title}: {e}")return None# Main accuracy test
def main():# Load datasetdf = load_json(JSON_FILE_PATH)print(f"Loaded dataset with {len(df)} samples")# Initialize variables for accuracy trackingcorrect = 0total = 0print("Starting accuracy test...")# Iterate through dataset with progress barfor idx, row in tqdm(df.iterrows(), total=len(df), desc="Testing Progress"):title = row['title']description = row['description']true_label = row['issue_type_name']# Get predictionpredicted_label = get_prediction(title, description)if predicted_label is None:print(f"Skipping sample {idx + 1} due to API error")continue# Update accuracy metricstotal += 1if predicted_label == true_label:correct += 1# Calculate and display current accuracycurrent_accuracy = (correct / total) * 100 if total > 0 else 0print(f"Sample {total}/{len(df)}: True Label: {true_label}, Predicted Label: {predicted_label}, "f"Correct: {correct}, Current Accuracy: {current_accuracy:.2f}%")# Final accuracyfinal_accuracy = (correct / total) * 100 if total > 0 else 0print(f"\nTest Completed!")print(f"Total Samples Processed: {total}")print(f"Correct Predictions: {correct}")print(f"Final Accuracy: {final_accuracy:.2f}%")if __name__ == "__main__":main()

总记58294 个ticket, issue type 预测准确率Final Accuracy: 86.24%

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

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

相关文章

Matplotlib和Plotly知识点(Dash+Plotly分页展示)

Matplotlib和Plotly知识点(DashPlotly分页展示)0、Matplotlib、Plotly和Dash区别 (推荐用DashPlotly)1.1、Matplotlib (静态图)1. Figures(图形)概念创建Figure保存和显示Figure2. S…

YOLO12论文阅读:Attention-Centric Real-Time Object Detectors

文章链接: 2502.12524https://arxiv.org/pdf/2502.12524 摘要 (Abstract)​​ 长期以来,增强 YOLO 框架的网络架构至关重要,但尽管注意力机制在建模能力方面已被证明具有优越性,改进却主要集中在基于 CNN 的方面。这是因为基于…

秋招Day17 - Spring - 事务

Spring事务的种类编程式事务和声明式事务介绍一下编程式事务管理?通过编程的方式显式控制事务的开始、提交和回滚,一般使用TransactionTemplate的execute方法介绍一下声明式事务管理?基于AOP,通过调用代理对象拦截目标方法&#x…

多维基分析求导法则

对于n维点R0(I1,I2,I3,......In)如果到R(I1, I2 , I3 ,......,In )有基分析求导定理:即R0 R0 *(x1 ,x2 ,x3 ,.............xn) R当I1,I2,....,In独立不能转化时有了独立变量的求导和积分不相干法则…

Java值传递和构造函数

一.Java值传递首先我们来看一串代码:输出 10 20,而不是20 10 这是为什么呢?有内存图可以知道,这个change方法所改变的东西最终没有写回到main之中,且他传的是具体的数据,所以还会输出原数据,就相…

电商项目_秒杀_架构及核心

秒杀架构设计先看下普通web项目架构: (Nginx : 反向代理、负载均衡,一般是运维部分做生产搭建的时候配置好)秒杀架构设计:和普通架构区别:原先由Web 服务或Nginx服务提供的静态资源放到了CDNNginx的职责放⼤…

4x4矩阵教程

4x4矩阵教程 1. 简介 四维矩阵是计算机图形学和3D变换中的重要工具&#xff0c;用于表示三维空间中的仿射变换。本教程将介绍如何使用C实现四维矩阵的基本运算和变换。 2. 代码实现 2.1 头文件 (matrix4x4.h) #ifndef MATRIX4X4_H #define MATRIX4X4_H#include <array> #…

Oracle 数据库共享池与大池调优指南

在 Oracle 数据库的内存管理中&#xff0c;共享池&#xff08;Shared Pool&#xff09;和大池&#xff08;Large Pool&#xff09;是 SGA&#xff08;系统全局区&#xff09;中负责缓存与资源分配的核心组件。合理配置和调优这两个池&#xff0c;能显著提升数据库性能 —— 尤其…

C# Lambdab表达式 Var 类

Lambdab 是用于创建一个方法的表达式Func<参数1类型, 参数2类型, 返回值类型> fnName >(参数1 参数2) {方法代码体}Func<int, int, bool> fnName (int a, int b) > {return a > b; };//调用时和普通方法一致 Console.WriteLine(fnName(10,20)); // false…

【Python】常见模块及其用法

文章目录1. 什么是模块和包&#xff1f;2. 常见的模块及其用法2.1 time概览2.1.1 时间获取方法2.1.2 时间格式化与解析2.1.3 程序计时与延迟2.1.4 时间转换2.2 random概览2.2.1 基本随机数2.2.2 随机整数2.2.3 序列操作2.2.4 概率分布2.2.5 随机种子2.2.6 状态管理2.3 os概览2.…

洛谷 P3478 [POI 2008] STA-Station

【题目链接】 洛谷 P3478 [POI 2008] STA-Station 【题目考点】 1. 树形动规&#xff1a;换根动规 换根动规&#xff0c;又名二次扫描法&#xff0c;一般是给一颗不定根树&#xff0c;通过两次扫描来求解。 我们可以先任选一个根结点root&#xff0c;通过树形动规的思想计算…

【爬虫】03 - 爬虫的基本数据存储

爬虫03 - 爬虫的数据存储 文章目录爬虫03 - 爬虫的数据存储一&#xff1a;CSV数据存储1&#xff1a;基本介绍2&#xff1a;基本使用3&#xff1a;高级使用4&#xff1a;使用示例二&#xff1a;JSON数据存储1&#xff1a;基础json读写2&#xff1a;字符串和对象的转换3&#xff…

深入分析计算机网络数据链路层和网络层面试题

计算机网络体系结构1. 请简述 OSI 七层模型和 TCP/IP 四层模型&#xff0c;并比较它们的异同。OSI 七层模型&#xff1a;应用层&#xff1a;直接为用户的应用进程提供服务&#xff0c;如 HTTP&#xff08;超文本传输协议&#xff0c;用于 Web 浏览器与服务器通信&#xff09;、…

云服务器新装的mysql8,无法通过远程连接,然后本地pymysql也连不上

阿里云服务器&#xff0c;用apt-get新装的mysql-server&#xff0c;竟然无法通过远程连接到&#xff0c;竟然是这个原因。不是防火墙&#xff0c;iptables早就关了。也不是安全组&#xff0c;不是人为限制访问的话&#xff0c;根本没必要弄安全组 排查过程 netstat -antop|grep…

质量即服务:从测试策略到平台运营的全链路作战手册

&#xff08;零&#xff09;为什么需要“质量即服务” 当业务方说“今晚一定要上线”&#xff0c; 当开发说“我只改了两行代码”&#xff0c; 当运维说“回滚窗口只有 5 分钟”&#xff0c; 质量必须像水电一样随取随用&#xff0c;而不是上线前的大坝泄洪。 这篇手册提供一张…

Java -- 自定义异常--Wrapper类--String类

自定义异常&#xff1a;概念&#xff1a;当程序中出现了某些错误&#xff0c;但该错误信息并没有在Throwable子类中描述处理&#xff0c;这个时候可以自己设计异常&#xff0c;用于描述该错误信息。步骤&#xff1a;1. 定义类&#xff1a;自定义异常类名&#xff08;程序员自己…

一文速通《线性方程组》

目录 一、解题必记知识点 二、解题必备技巧 三、非齐次线性方程组求解 四、齐次线性方程组求解 ★五、解析题目信息&#xff0c;获取暗含条件 一、解题必记知识点 (1) (2)基础解系线性无关&#xff0c;基础解系 解空间的一个基&#xff0c;基 一组线性无关的、能够生…

【Django】DRF API版本和解析器

讲解 Python3 下 Django REST Framework (DRF) API 版本控制解析器&#xff08;Parser&#xff09;一、DRF API 版本控制详解 API 版本控制是构建健壮、可维护的 RESTful API 的关键&#xff0c;尤其在项目演进中需要兼容不同版本的客户端请求。 1.1 API 版本控制的核心原理 AP…

Windows系统暂停更新工具

功能说明 暂停更新至2999年恢复系统更新彻底禁用更新&#xff08;不可逆&#xff09; 使用方法 下载解压后双击运行 .bat 文件 输入数字选择功能&#xff1a; 输入 1&#xff1a;暂停更新至2999年&#xff08;推荐&#xff09;输入 2&#xff1a;恢复系统更新输入 3&#xf…

git push新版问题解决

git 好像不能通过username:password的方式来git push了。但我的电脑依然弹出username和password的弹窗。转战ssh来git push。由于之前是用git clone克隆的&#xff0c;需要再转换成ssh的url来git push。