活动介绍

from transformers import BertTokenizer, BertForSequenceClassification, TrainingArguments, Trainer from datasets import load_from_disk import numpy as np from sklearn.metrics import accuracy_score def load_processed_data(): dataset = load_from_disk("../data/processed_imdb") return dataset['train'], dataset['test'] # 定义预处理函数 def preprocess_function(examples): return tokenizer( examples['text'], truncation=True, padding='max_length', max_length=256 ) # 定义评估指标 def compute_metrics(p): preds = np.argmax(p.predictions, axis=1) return {'accuracy': accuracy_score(p.label_ids, preds)} if __name__ == '__main__': train_data, test_data = load_processed_data() # 加载BERT的分词器 tokenizer = BertTokenizer.from_pretrained("C:/Users/Administrator/bert_cache") # 应用预处理 train_data = train_data.map(preprocess_function, batched=True) test_data = test_data.map(preprocess_function, batched=True) # 重命名标签列(适配HuggingFace格式) train_data = train_data.rename_column('label', 'labels') test_data = test_data.rename_column('label', 'labels') # 设置pytorch格式 train_data.set_format('torch', columns=['input_ids', 'attention_mask', 'labels']) test_data.set_format('torch', columns=['input_ids', 'attention_mask', 'labels']) # 加载预训练模型 model = BertForSequenceClassification.from_pretrained( "C:/Users/Administrator/bert_cache", num_labels=2 ) training_args = TrainingArguments( output_dir='./results', # 输出目录 num_train_epochs=3, # 训练轮次 per_device_train_batch_size=32, # 训练批次大小 per_device_eval_batch_size=128, # 评估批次大小 warmup_steps=500, # 学习率预热步数 weight_decay=0.01, # 权重衰减 logging_dir='./logs', # 日志目录 eval_strategy='epoch', # 每轮评估一次 save_strategy='epoch' ) # 创建Trainer trainer = Trainer( model=model, args=training_args, train_dataset=train_data, eval_dataset=test_data, # 实际应用时应使用验证集 compute_metrics=compute_metrics ) # 开始训练! trainer.train() # 保存模型 model.save_pretrained('./my_bert_model') tokenizer.save_pretrained('./my_bert_model') # 加载模型 # from_pretrained_model = BertForSequenceClassification.from_pretrained('./my_bert_model') 我这段代码我怎么判断他是否使用了GPU加速

时间: 2025-04-03 11:09:55 浏览: 41
<think>嗯,用户想知道如何判断他们的代码是否使用了GPU加速。首先,我需要回顾一下他们提供的代码。看起来他们使用的是Hugging Face的Transformers库和Trainer类进行训练。代码中没有明显设置设备的命令,比如`torch.cuda.is_available()`或者`model.to('cuda')`,所以可能依赖Trainer自动处理。 接下来,我要考虑Hugging Face的Trainer默认行为。通常,如果没有指定,Trainer会自动使用GPU如果可用。但用户的代码里没有明确设置,所以需要确认几个点: 1. **库的日志输出**:在训练开始的时候,Transformers通常会输出是否检测到CUDA,并正在使用GPU。用户可能需要在控制台查看这些信息,比如“Using CUDA”或者列出可用的GPU设备。 2. **PyTorch的设备设置**:虽然代码中没有显式调用,但PyTorch可能在底层自动使用GPU。用户可以通过在代码中添加检查语句,比如`import torch; print(torch.cuda.is_available())`和`print(torch.cuda.device_count())`,来确认CUDA是否可用以及GPU数量。 3. **训练速度**:如果训练速度很快,尤其是批次大小较大时,可能是在GPU上运行。但这种方法不太可靠,因为速度受多种因素影响。 4. **任务管理器或nvidia-smi**:用户可以在训练时打开任务管理器(Windows)或使用`nvidia-smi`命令(Linux)查看GPU使用情况。如果有显存占用和计算活动,说明正在使用GPU。 然后,我需要考虑用户可能的隐藏需求。他们可能刚接触深度学习,对GPU配置不熟悉,或者遇到训练速度慢的问题,想知道是否真的在使用GPU。因此,除了判断方法,可能还需要建议如何强制使用CPU或GPU,以及如何修改代码。 比如,在TrainingArguments中设置`no_cuda=True`可以强制使用CPU。或者,通过`device`参数指定,但Hugging Face的Trainer可能自动处理这些。另外,确保PyTorch正确安装了CUDA版本的库也是关键。 总结回答的结构:先说明检查日志输出,然后代码中添加CUDA检查,接着观察资源使用情况,最后提供修改建议。确保步骤清晰,帮助用户逐步验证。</think>要判断你的代码是否使用了GPU加速,可以通过以下几个步骤进行验证: $\textcolor{green}{\textbf{1. 检查日志输出}}$ 在代码运行时,控制台会输出类似以下信息: ```python Using cuda device: NVIDIA GeForce RTX 3090 # 如果使用GPU会显示设备名称 ``` 或警告信息: ```python CUDA is not available. Using CPU. # 如果未检测到GPU ``` $\textcolor{red}{注意:}$ 如果没有显式设置设备,HuggingFace Trainer会$\textcolor{blue}{自动优先使用GPU}$。 $\textcolor{green}{\textbf{2. 添加设备检测代码}}$ 在`if __name__ == '__main__':`块开头添加: ```python import torch print("CUDA可用:", torch.cuda.is_available()) # 应该输出True print("GPU数量:", torch.cuda.device_count()) # 应该≥1 print("当前设备:", torch.cuda.current_device()) print("设备名称:", torch.cuda.get_device_name(0)) ``` $\textcolor{red}{预期结果:}$ ```python CUDA可用: True GPU数量: 1 当前设备: 0 设备名称: NVIDIA GeForce RTX 3090 ``` $\textcolor{green}{\textbf{3. 监控资源使用}}$(二选一) - $\textcolor{blue}{\text{Windows}}$:任务管理器 → 性能 → GPU 查看使用率 - $\textcolor{blue}{\text{Linux}}$:终端运行 `watch -n 0.5 nvidia-smi` 实时监控 $\textcolor{green}{\textbf{4. 强制使用CPU验证}}$(可选) 修改`TrainingArguments`添加参数: ```python training_args = TrainingArguments( no_cuda=True, # ← 添加此参数强制使用CPU output_dir='./results', ... ) ``` 此时若GPU相关代码报错,则说明原本在使用GPU $\textcolor{green}{\textbf{5. 显存占用验证}}$ 正常使用GPU时会出现以下现象: - 训练开始时会显示显存分配信息 - 使用`nvidia-smi`会看到对应进程显存占用 - 训练速度明显快于纯CPU(32批大小下文本分类约3-5秒/step) $\textcolor{red}{\textbf{常见问题排查:}}$ 1. 如果显示`CUDA可用: False`: - 检查是否安装GPU版PyTorch:`print(torch.__version__)`应包含`cuXXX` - 更新NVIDIA驱动 - 确认CUDA版本匹配(`nvcc --version`与`torch.version.cuda`) 2. 如果显存不足(OOM错误): ```python training_args = TrainingArguments( fp16=True, # 启用混合精度训练 ← 添加此参数 per_device_train_batch_size=16 # 减小批次大小 ) ``` $\textcolor{blue}{\textbf{最终确认方法:}}$ 在训练循环中添加回调函数: ```python from transformers import TrainerCallback class DeviceCheckCallback(TrainerCallback): def on_train_begin(self, args, state, control, **kwargs): print(f"Training device: {kwargs['model'].device}") # 在Trainer中添加: trainer = Trainer( ..., callbacks=[DeviceCheckCallback()] # ← 添加回调 ) ``` 正常使用GPU时会输出: ```python Training device: cuda:0 ```
阅读全文

相关推荐

from transformers import BertTokenizer, BertForSequenceClassification, TrainingArguments, Trainer from datasets import load_from_disk import numpy as np from sklearn.metrics import accuracy_score def load_processed_data(): dataset = load_from_disk("../data/processed_imdb") return dataset['train'], dataset['test'] # 定义预处理函数 def preprocess_function(examples): return tokenizer( examples['text'], truncation=True, padding='max_length', max_length=256 ) # 定义评估指标 def compute_metrics(p): preds = np.argmax(p.predictions, axis=1) return {'accuracy': accuracy_score(p.label_ids, preds)} if __name__ == '__main__': train_data, test_data = load_processed_data() # 加载BERT的分词器 tokenizer = BertTokenizer.from_pretrained("C:/Users/Administrator/bert_cache") # 应用预处理 train_data = train_data.map(preprocess_function, batched=True) test_data = test_data.map(preprocess_function, batched=True) # 重命名标签列(适配HuggingFace格式) train_data = train_data.rename_column('label', 'labels') test_data = test_data.rename_column('label', 'labels') # 设置pytorch格式 train_data.set_format('torch', columns=['input_ids', 'attention_mask', 'labels']) test_data.set_format('torch', columns=['input_ids', 'attention_mask', 'labels']) # 加载预训练模型 model = BertForSequenceClassification.from_pretrained( "C:/Users/Administrator/bert_cache", num_labels=2 ) training_args = TrainingArguments( output_dir='./results', # 输出目录 num_train_epochs=3, # 训练轮次 per_device_train_batch_size=32, # 训练批次大小 per_device_eval_batch_size=128, # 评估批次大小 warmup_steps=500, # 学习率预热步数 weight_decay=0.01, # 权重衰减 logging_dir='./logs', # 日志目录 eval_strategy='epoch', # 每轮评估一次 save_strategy='epoch' ) # 创建Trainer trainer = Trainer( model=model, args=training_args, train_dataset=train_data, eval_dataset=test_data, # 实际应用时应使用验证集 compute_metrics=compute_metrics ) # 开始训练! trainer.train() # 保存模型 model.save_pretrained('./my_bert_model') tokenizer.save_pretrained('./my_bert_model') # 加载模型 # from_pretrained_model = BertForSequenceClassification.from_pretrained('./my_bert_model')

使用fp32精度可能会使我的电脑内存被占满。这是我的代码,请你给我解决方案from transformers import Trainer, TrainingArguments, DataCollatorForSeq2Seq from datasets import Dataset import json import pandas as pd from transformers import AutoModelForCausalLM, AutoTokenizer import torch from sklearn.metrics import accuracy_score, recall_score, f1_score, precision_score from tqdm import tqdm from transformers import DataCollatorForLanguageModeling import numpy as np data = [] with open("E:/train.jsonl", "r", encoding="utf-8") as f: for line_number, line in enumerate(f, 1): line = line.strip() if not line: continue # 跳过空行 try: record = json.loads(line) data.append(record) except json.JSONDecodeError as e: print(f"第 {line_number} 行解析失败:{e}") # 可以在此处记录错误或跳过这行 train_df = pd.DataFrame(data) print(train_df.head()) val_data = [] with open("E:/valid.jsonl", "r", encoding="utf-8") as f: for line_number, line in enumerate(f, 1): line = line.strip() if not line: continue # 跳过空行 try: record = json.loads(line) val_data.append(record) except json.JSONDecodeError as e: print(f"第 {line_number} 行解析失败:{e}") # 可以在此处记录错误或跳过这行 valid_df = pd.DataFrame(val_data) # 指定本地模型路径 local_model_path = "E:/Qwen/Qwen2.5-1.5B-Instruct" # 加载模型和分词器(确保 local_files_only=True) model = AutoModelForCausalLM.from_pretrained( local_model_path, # torch_dtype="auto", torch_dtype=torch.float16, # 强制使用 FP16 device_map="auto", local_files_only=True ) tokenizer = AutoTokenizer.from_pretrained( local_model_path, local_files_only=True ) # 设置 pad_token 以避免生成时出现问题 tokenizer.pad_token = tokenizer.eos_token tokenizer.pad_token_id = tokenizer.eos_token_id model.config.pad_token_id = tokenizer.pad_token_id def construct_prompt(code): prompt_template = ( "请扮演一位软件安全专家。分析以下函数代码,判断代码中是否存在安全漏洞。当函数代码存在漏洞时,你只需要输出一个单词:yes,当代码不存在漏洞时,

import datasets import transformers import modelscope from itertools import chain import glob import torch import evaluate from swanlab.integration.transformers import SwanLabCallback import swanlab import numpy as np from sklearn.metrics import accuracy_score import evaluate import transformers import torch import torch.nn as nn from transformers import AutoModelForCausalLM, GPT2Config from transformers import RobertaTokenizerFast # 实现旋转位置编码 class RotaryPositionalEmbedding(nn.Module): def __init__(self, dim, max_seq_len=2048, base=10000): super().__init__() self.dim = dim self.max_seq_len = max_seq_len self.base = base inv_freq = 1.0 / (base ** (torch.arange(0, dim, 2).float() / dim)) self.register_buffer('inv_freq', inv_freq) self.register_buffer('positions', torch.arange(max_seq_len)) def forward(self, x): batch_size, seq_len, hidden_size = x.size() seq_len = min(seq_len, self.max_seq_len) positions = self.positions[:seq_len] angles = positions.unsqueeze(1) * self.inv_freq.unsqueeze(0) angles = angles.unsqueeze(0).repeat(batch_size, 1, 1) cos_angles = torch.cos(angles) sin_angles = torch.sin(angles) x_reshaped = x.view(batch_size, seq_len, -1, 2) x1, x2 = x_reshaped[..., 0], x_reshaped[..., 1] rotated_x1 = x1 * cos_angles - x2 * sin_angles rotated_x2 = x1 * sin_angles + x2 * cos_angles rotated = torch.stack([rotated_x1, rotated_x2], dim=-1).view(batch_size, seq_len, hidden_size) return rotated # 自定义模型类,继承自原模型的PreTrainedModel class CustomModelWithRotary(transformers.PreTrainedModel): config_class = GPT2Config def __init__(self, config): super().__init__(config) # 移除 trust_remote_code 参数 self.base_model = transformers.AutoModelForCausalLM.from_pretrained( "/root/workspace/workspace/gpt2-large", config=config ) self.rotary_emb = RotaryPositionalEmbedding( dim=config.hidden_size, max_seq_len=config.max_position_embeddings ) self.config.position_encoding_type = "rotary" def forward(self, input_ids=None, attention_mask=None, **kwargs): outputs = self.base_model(input_ids=input_ids, attention_mask=attention_mask, **kwargs) if hasattr(outputs, 'last_hidden_state'): outputs.last_hidden_state = self.rotary_emb(outputs.last_hidden_state) else: # 处理返回元组的情况 outputs = (self.rotary_emb(outputs[0]),) + outputs[1:] return outputs def main(): swanlab.init("PreTrain-GPT2-SELFIES") swanlab_callback = SwanLabCallback( project="PreTrain-GPT2-SELFIES", experiment_name="PreTrain-GPT2-SELFIES" ) raw_datasets = datasets.load_dataset( "json", data_files="/root/workspace/selfies1.json" ) # split dataset raw_datasets = raw_datasets["train"].train_test_split(test_size=0.05, seed=2333) print("dataset info") print(raw_datasets) saved_path = '/root/workspace/robertatokenizer' tokenizer = RobertaTokenizerFast.from_pretrained(saved_path) print("Loaded RobertaTokenizerFast from: " + saved_path) # 设置分词器的最大长度 tokenizer.model_max_length = 512 print(f"Set tokenizer model_max_length to: {512}") context_length = 512 # use a small context length) vocab_size = tokenizer.vocab_size print(f"Tokenizer vocab size: {vocab_size}") # preprocess dataset def tokenize(element): # 对数据集进行预处理,将文本转换为模型可以处理的输入格式 # 这里使用的是Qwen2-0.5B的Tokenizer,将文本转换为模型可以处理的输入格式 # truncation=True表示如果文本长度超过了context_length,就截断 # max_length=context_length表示文本的最大长度为context_length # return_overflowing_tokens=True表示返回溢出的tokens outputs = tokenizer( element["text"], truncation=True, max_length=context_length, return_overflowing_tokens=True, return_length=True, ) input_batch = [] # 作用是将溢出的tokens转换为模型可以处理的输入格式 # 这里使用的是Qwen2-0.5B的Tokenizer,将文本转换为模型可以处理的输入格式 # 这里的input_ids是一个二维数组,每一行表示一个文本的输入格式 # 这里的length是一个一维数组,每一个元素表示一个文本的长度 # 这里的input_batch是一个二维数组,每一行表示一个文本的输入格式 # 这里的context_length是一个整数,表示文本的最大长度 for length, input_ids in zip(outputs["length"], outputs["input_ids"]): if length == context_length: input_batch.append(input_ids) return {"input_ids": input_batch} # map函数的作用是将tokenize函数应用到数据集的每一个元素上 # batched=True表示将数据集分成batch进行处理 # remove_columns=raw_datasets["train"].column_names表示删除原始数据集的列名 tokenized_datasets = raw_datasets.map( tokenize, batched=True,num_proc=20, remove_columns=raw_datasets["train"].column_names ) print("tokenize dataset info") # print(tokenized_datasets) # eos_token的作用是表示文本的结束 # pad_token的作用是表示填充的token tokenizer.pad_token = tokenizer.eos_token # DataCollatorForLanguageModeling的作用是将数据集转换为模型可以处理的输入格式 # 这里使用的是Qwen2-0.5B的Tokenizer,将文本转换为模型可以处理的输入格式 # mlm=False表示不进行masked language modeling data_collator = transformers.DataCollatorForLanguageModeling(tokenizer, mlm=False) # 加载配置 config = GPT2Config.from_pretrained("/root/workspace/workspace/gpt2-large") config.vocab_size = vocab_size # 更新配置中的 vocab_size # 检查配置中的 vocab_size print(f"Model config vocab size: {config.vocab_size}") # 直接实例化自定义模型,无需注册 model = CustomModelWithRotary(config) model_size = sum(t.numel() for t in model.parameters()) print("Model Config:") print(config) print(f"Model Size: {model_size/1000**2:.1f}M parameters") # 加载各个所需的指标 accuracy_metric = evaluate.load('./metrics/accuracy') def compute_metrics(eval_preds): logits, labels = eval_preds # 获取预测结果(取logits中概率最大的索引) preds = np.argmax(logits, axis=-1) # 形状: [batch_size, sequence_length] labels = labels[:, 1:].reshape(-1) preds = preds[:, :-1].reshape(-1) # 计算每个标记的准确度 accuracy = accuracy_metric.compute(predictions=preds, references=labels) return accuracy import random def compute_metrics_partial(eval_preds, subset_ratio=0.5): # 这里假设 eval_preds 是一个 list,包含 logits 和 labels logits, labels = eval_preds # 随机选择部分批次进行计算 batch_size = logits.shape[0] subset_size = int(batch_size * subset_ratio) # 计算子集的大小 selected_indices = random.sample(range(batch_size), subset_size) # 获取预测结果(只对选定的批次进行计算) selected_logits = logits[selected_indices] selected_labels = labels[selected_indices] preds = np.argmax(selected_logits, axis=-1) # shape: [subset_size, sequence_length] selected_labels = selected_labels[:, 1:].reshape(-1) selected_preds = preds[:, :-1].reshape(-1) # 计算准确度 accuracy = accuracy_metric.compute(predictions=selected_preds, references=selected_labels) return accuracy # train args = transformers.TrainingArguments( output_dir="./GPT2-SELFIES", per_device_train_batch_size=3, # 每个GPU的训练batch数 per_device_eval_batch_size=3, # 每个GPU的测试batch数 eval_strategy="steps", eval_steps=2, logging_steps=5, gradient_accumulation_steps=8, # 梯度累计总数 num_train_epochs=100, # 训练epoch数 lr_scheduler_type="cosine", # 学习率衰减策略 learning_rate=1e-5, # 基础学习率, save_steps=500, save_total_limit=10, bf16=True, # 开启bf16训练, 对于Amper架构以下的显卡建议替换为fp16=True ) print("Train Args:") print(args) # enjoy training trainer = transformers.Trainer( model=model, tokenizer=tokenizer, args=args, data_collator=data_collator, train_dataset=tokenized_datasets["train"], eval_dataset=tokenized_datasets["test"], compute_metrics=compute_metrics, callbacks=[swanlab_callback], ) trainer.train() # save model trainer.save_model("./GPT2-SELFIES/Weight") # 保存模型的路径 # generate pipe = transformers.pipeline("text-generation", model=model, tokenizer=tokenizer) print("GENERATE:", pipe("人工智能", num_return_sequences=1)[0]["generated_text"]) prompts = ["牛顿", "北京市", "亚洲历史"] examples = [] for i in range(3): # 根据提示词生成数据 text = pipe(prompts[i], num_return_sequences=1)[0]["generated_text"] text = swanlab.Text(text) examples.append(text) swanlab.log({"Generate": examples}) if __name__ == "__main__": main()解决报错 File "/root/workspace/gpt2-large.py", line 245, in <module> main() File "/root/workspace/gpt2-large.py", line 148, in main model = CustomModelWithRotary(config) File "/root/workspace/gpt2-large.py", line 51, in __init__ self.base_model = transformers.AutoModelForCausalLM.from_pretrained( File "/opt/conda/lib/python3.10/site-packages/transformers/models/auto/auto_factory.py", line 564, in from_pretrained return model_class.from_pretrained( File "/opt/conda/lib/python3.10/site-packages/transformers/modeling_utils.py", line 262, in _wrapper return func(*args, **kwargs) File "/opt/conda/lib/python3.10/site-packages/transformers/modeling_utils.py", line 4319, in from_pretrained ) = cls._load_pretrained_model( File "/opt/conda/lib/python3.10/site-packages/transformers/modeling_utils.py", line 4955, in _load_pretrained_model raise RuntimeError(f"Error(s) in loading state_dict for {model.__class__.__name__}:\n\t{error_msg}") Error(s) in loading state_dict for GPT2LMHeadModel: size mismatch for wte.weight: copying a param with shape torch.Size([50257, 1280]) from checkpoint, the shape in current model is torch.Size([3289, 1280]). You may consider adding ignore_mismatched_sizes=True in the model from_pretrained method.使用全新词汇表

import datasets import transformers import modelscope from itertools import chain import glob import torch import evaluate from swanlab.integration.transformers import SwanLabCallback import swanlab import numpy as np from sklearn.metrics import accuracy_score from rdkit import Chem from rdkit import DataStructs from rdkit.Chem import AllChem import evaluate from rdkit import Chem def main(): swanlab.init("PreTrain-llama-SMILES") swanlab_callback = SwanLabCallback( project="PreTrain-llama-SMILES", experiment_name="PreTrain-llama-SMILES" ) raw_datasets = datasets.load_dataset( "json", data_files="/data/coding/transformers_from_scratch-main/txt/smiles.json" ) # split dataset raw_datasets = raw_datasets["train"].train_test_split(test_size=0.1, seed=2333) print("dataset info") print(raw_datasets) tokenizer = transformers.AutoTokenizer.from_pretrained( "/data/coding/transformers_from_scratch-main/DeepSeek-R1-Distill-Llama-8B",use_fast=True, trust_remote_code=True, model_max_length=1024 ) context_length = 1024 # use a small context length) # preprocess dataset def tokenize(element): # 对数据集进行预处理,将文本转换为模型可以处理的输入格式 # 这里使用的是Qwen2-0.5B的Tokenizer,将文本转换为模型可以处理的输入格式 # truncation=True表示如果文本长度超过了context_length,就截断 # max_length=context_length表示文本的最大长度为context_length # return_overflowing_tokens=True表示返回溢出的tokens outputs = tokenizer( element["text"], truncation=True, max_length=context_length, return_overflowing_tokens=True, return_length=True, ) input_batch = [] # 作用是将溢出的tokens转换为模型可以处理的输入格式 # 这里使用的是Qwen2-0.5B的Tokenizer,将文本转换为模型可以处理的输入格式 # 这里的input_ids是一个二维数组,每一行表示一个文本的输入格式 # 这里的length是一个一维数组,每一个元素表示一个文本的长度 # 这里的input_batch是一个二维数组,每一行表示一个文本的输入格式 # 这里的context_length是一个整数,表示文本的最大长度 for length, input_ids in zip(outputs["length"], outputs["input_ids"]): if length == context_length: input_batch.append(input_ids) return {"input_ids": input_batch} # map函数的作用是将tokenize函数应用到数据集的每一个元素上 # batched=True表示将数据集分成batch进行处理 # remove_columns=raw_datasets["train"].column_names表示删除原始数据集的列名 tokenized_datasets = raw_datasets.map( tokenize, batched=True,num_proc=20, remove_columns=raw_datasets["train"].column_names ) print("tokenize dataset info") # print(tokenized_datasets) # eos_token的作用是表示文本的结束 # pad_token的作用是表示填充的token tokenizer.pad_token = tokenizer.eos_token # DataCollatorForLanguageModeling的作用是将数据集转换为模型可以处理的输入格式 # 这里使用的是Qwen2-0.5B的Tokenizer,将文本转换为模型可以处理的输入格式 # mlm=False表示不进行masked language modeling data_collator = transformers.DataCollatorForLanguageModeling(tokenizer, mlm=False) # prepare a model from scratch config = transformers.AutoConfig.from_pretrained( "/data/coding/transformers_from_scratch-main/DeepSeek-R1-Distill-Llama-8B", trust_remote_code=True) model = transformers.AutoModelForCausalLM.from_config(config) model_size = sum(t.numel() for t in model.parameters()) print("Model Config:") print(config) print(f"Model Size: {model_size/1000**2:.1f}M parameters") # 加载各个所需的指标 accuracy_metric = evaluate.load('./metrics/accuracy') def compute_metrics(eval_preds): logits, labels = eval_preds # 获取预测结果(取logits中概率最大的索引) preds = np.argmax(logits, axis=-1) # 形状: [batch_size, sequence_length] labels1 = labels[:, 1:].reshape(-1) preds1 = preds[:, :-1].reshape(-1) # 计算每个标记的准确度 accuracy = accuracy_metric.compute(predictions=preds1, references=labels1) # 解码预测和参考的文本为SMILES字符串 predictions_texts = [] references_texts = [] # 逐样本解码 for i in range(preds.shape[0]): # 解码单个预测序列 pred_seq = preds[i].tolist() # 转换为Python列表 pred_text = tokenizer.decode(pred_seq, skip_special_tokens=True) predictions_texts.append(pred_text) # 解码单个标签序列 label_seq = labels[i].tolist() # 转换为Python列表 ref_text = tokenizer.decode(label_seq, skip_special_tokens=True) references_texts.append(ref_text) # SMILES 有效性结果 smiles_validity = [] for pred_text, ref_text in zip(predictions_texts, references_texts): # 计算单个SMILES的有效性 mol = Chem.MolFromSmiles(pred_text) if mol is None: smiles_validity.append(0) # 无效SMILES,设为0 else: smiles_validity.append(1) # 有效SMILES # 计算 SMILES 有效性的平均值 avg_smiles_validity = np.mean(smiles_validity) # 返回所有指标的合并结果 metrics = { 'accuracy': accuracy['accuracy'], 'average_smiles_validity': avg_smiles_validity } return metrics # train args = transformers.TrainingArguments( output_dir="./WikiLLM-llama-SMILES", per_device_train_batch_size=3, # 每个GPU的训练batch数 per_device_eval_batch_size=3, # 每个GPU的测试batch数 eval_strategy="steps", eval_steps=2, logging_steps=5, gradient_accumulation_steps=8, # 梯度累计总数 num_train_epochs=100, # 训练epoch数 lr_scheduler_type="cosine", # 学习率衰减策略 learning_rate=1e-5, # 基础学习率, save_steps=500, save_total_limit=10, bf16=True, # 开启bf16训练, 对于Amper架构以下的显卡建议替换为fp16=True ) print("Train Args:") print(args) # enjoy training trainer = transformers.Trainer( model=model, tokenizer=tokenizer, args=args, data_collator=data_collator, train_dataset=tokenized_datasets["train"], eval_dataset=tokenized_datasets["test"], compute_metrics=compute_metrics, callbacks=[swanlab_callback], ) trainer.train() # save model trainer.save_model("./WikiLLM-llama-SMILES/Weight") # 保存模型的路径 # generate pipe = transformers.pipeline("text-generation", model=model, tokenizer=tokenizer) print("GENERATE:", pipe("人工智能", num_return_sequences=1)[0]["generated_text"]) prompts = ["牛顿", "北京市", "亚洲历史"] examples = [] for i in range(3): # 根据提示词生成数据 text = pipe(prompts[i], num_return_sequences=1)[0]["generated_text"] text = swanlab.Text(text) examples.append(text) swanlab.log({"Generate": examples}) if __name__ == "__main__": main()按照这个代码eval_preds单个样本的labels会是什么

import os import torch from transformers import ( AutoTokenizer, AutoModelForCausalLM, TrainingArguments, Trainer, BitsAndBytesConfig, DataCollatorWithPadding, set_seed, ) from peft import LoraConfig, get_peft_model, prepare_model_for_kbit_training from datasets import load_dataset, load_from_disk import bitsandbytes as bnb import numpy as np from transformers import Trainer, TrainerCallback import logging import gc import matplotlib # 设置matplotlib后端,避免GUI问题 matplotlib.use('Agg') import matplotlib.pyplot as plt # 添加评估指标库 from rouge_score import rouge_scorer import nltk from nltk.translate.bleu_score import sentence_bleu, SmoothingFunction # 下载NLTK数据(如果尚未下载) try: nltk.data.find('tokenizers/punkt') except LookupError: nltk.download('punkt') # 设置随机种子 set_seed(42) # 更激进的显存管理配置 os.environ["PYTORCH_CUDA_ALLOC_CONF"] = "max_split_size_mb:32" torch.backends.cuda.matmul.allow_tf32 = True torch.backends.cudnn.allow_tf32 = True def clear_gpu_memory(): """清理GPU显存""" gc.collect() if torch.cuda.is_available(): torch.cuda.empty_cache() torch.cuda.synchronize() def print_gpu_utilization(): if torch.cuda.is_available(): allocated = torch.cuda.memory_allocated()/1024**3 reserved = torch.cuda.memory_reserved()/1024**3 print(f"GPU memory allocated: {allocated:.2f} GB") print(f"GPU memory reserved: {reserved:.2f} GB") # 检查 CUDA 状态 print(f"CUDA available: {torch.cuda.is_available()}") if torch.cuda.is_available(): print(f"Total GPU memory: {torch.cuda.get_device_properties(0).total_memory/1024**3:.2f} GB") print("初始显存使用情况:") print_gpu_utilization() # 模型路径 model_name = "/root/autodl-tmp/deepseek-ai/deepseek-llm-7b-chat" # 4-bit 量化配置 - 更节省显存的配置 quantization_config = BitsAndBytesConfig( load_in_4bit=True, bnb_4bit_use_double_quant=True, bnb_4bit_quant_type="nf4", bnb_4bit_compute_dtype=torch.float16, ) # 加载 tokenizer tokenizer = AutoTokenizer.from_pretrained(model_name) # 清理显存 clear_gpu_memory() # 加载模型(量化) print("加载模型中...") print_gpu_utilization() model = AutoModelForCausalLM.from_pretrained( model_name, quantization_config=quantization_config, device_map="auto", torch_dtype=torch.float16, low_cpu_mem_usage=True, # 减少CPU内存使用 ) print("模型加载完成:") print_gpu_utilization() # 准备模型进行 k-bit 训练 model.config.use_cache = False model.gradient_checkpointing_enable() model = prepare_model_for_kbit_training(model) # 配置 LoRA lora_config = LoraConfig( r=4, # 保持较小的rank lora_alpha=16, target_modules=["q_proj", "v_proj", "k_proj", "o_proj"], lora_dropout=0.1, bias="none", task_type="CAUSAL_LM", inference_mode=False ) # 应用 LoRA 到模型 model = get_peft_model(model, lora_config) # 打印可训练参数信息 def print_trainable_parameters(model): trainable_params = 0 all_param = 0 for _, param in model.named_parameters(): all_param += param.numel() if param.requires_grad: trainable_params += param.numel() print( f"trainable params: {trainable_params} || " f"all params: {all_param} || " f"trainable%: {100 * trainable_params / all_param:.2f}" ) print_trainable_parameters(model) # 数据路径 data_dir = "/root/autodl-tmp/self-llm-master/medical data/" # 自动判断加载方式(支持 .jsonl 或 .arrow) def load_dataset_smart(path): if os.path.isdir(path): dataset = load_from_disk(path) elif os.path.isfile(path) and path.endswith(".jsonl"): dataset = load_dataset("json", data_files=path) else: raise ValueError(f"不支持的文件类型:{path}") return dataset # 只加载训练集和验证集 print("加载数据集...") train_dataset = load_dataset_smart(os.path.join(data_dir, "train.jsonl"))["train"] # 加载验证集用于评估指标 eval_dataset = load_dataset_smart(os.path.join(data_dir, "dev.jsonl"))["train"] print(f"Train size: {len(train_dataset)}") print(f"Eval size: {len(eval_dataset)}") # 编码函数:合并 Question + Response 并生成 labels def tokenize_function(examples): prompts = [str(p) for p in examples["Question"]] completions = [str(c) for c in examples["Response"]] full_text = [p + "\n" + c for p, c in zip(prompts, completions)] # 进一步减小序列长度以节省显存 result = tokenizer(full_text, truncation=True, max_length=64, padding="max_length", return_tensors="pt") result["labels"] = result["input_ids"].clone() return result # 用于评估的编码函数(保留原始文本) def tokenize_function_for_eval(examples): prompts = [str(p) for p in examples["Question"]] completions = [str(c) for c in examples["Response"]] full_text = [p + "\n" + c for p, c in zip(prompts, completions)] # 对于评估,我们需要保留原始文本以便生成和比较 result = tokenizer(full_text, truncation=True, max_length=64, padding="max_length", return_tensors="pt") result["labels"] = result["input_ids"].clone() result["prompts"] = prompts # 保留原始问题 result["references"] = completions # 保留原始答案 return result print("开始tokenize数据...") print_gpu_utilization() # 应用 tokenize (处理训练集和验证集) tokenized_train = train_dataset.map( tokenize_function, batched=True, batch_size=8, # 减小批次大小 num_proc=1, # 减少进程数到1 remove_columns=["Question", "Response", "Complex_CoT"], desc="Tokenizing train dataset" ) tokenized_eval = eval_dataset.map( tokenize_function_for_eval, batched=True, batch_size=8, num_proc=1, remove_columns=["Question", "Response", "Complex_CoT"], desc="Tokenizing eval dataset" ) print("数据处理完成:") print_gpu_utilization() # 数据整理器(用于动态 padding) data_collator = DataCollatorWithPadding(tokenizer=tokenizer, padding="longest") # 训练参数配置 - 添加验证相关参数 training_args = TrainingArguments( output_dir="./deepseek-medical", overwrite_output_dir=True, num_train_epochs=1, per_device_train_batch_size=1, per_device_eval_batch_size=1, gradient_accumulation_steps=32, learning_rate=1e-4, weight_decay=0.01, warmup_steps=100, save_steps=50, logging_steps=10, save_total_limit=2, bf16=False, fp16=True, logging_dir="./logs", report_to="none", optim="adamw_torch", evaluation_strategy="steps", # 每隔一定步骤进行验证 eval_steps=50, # 每50步验证一次 save_strategy="steps", disable_tqdm=False, group_by_length=True, save_safetensors=False, load_best_model_at_end=True, # 训练结束后加载最佳模型 dataloader_pin_memory=False, remove_unused_columns=True, dataloader_num_workers=0, gradient_checkpointing=True, max_grad_norm=1.0, greater_is_better=False, # 损失越小越好 metric_for_best_model="eval_loss", # 使用验证损失作为最佳模型选择标准 ) # 用于存储训练过程中的损失值 class LossLoggingCallback(TrainerCallback): def __init__(self): self.train_losses = [] self.eval_losses = [] self.steps = [] self.eval_steps = [] self.logged = False # 标记是否已记录数据 def on_log(self, args, state, control, logs=None, **kwargs): # 检查日志中是否有损失信息 if logs and "loss" in logs: self.train_losses.append(logs["loss"]) self.steps.append(state.global_step) self.logged = True print(f"记录损失 - Step: {state.global_step} | Train Loss: {logs['loss']:.4f}") elif logs and "eval_loss" in logs: self.eval_losses.append(logs["eval_loss"]) self.eval_steps.append(state.global_step) print(f"记录验证损失 - Step: {state.global_step} | Eval Loss: {logs['eval_loss']:.4f}") elif logs: print(f"日志内容: {list(logs.keys())}") # 调试信息,查看日志中有什么键 # 计算评估指标的函数 def compute_metrics(eval_preds): preds, labels = eval_preds # 如果预测是logits,需要转换为token IDs if isinstance(preds, tuple): preds = preds[0] # 获取预测的token IDs pred_ids = np.argmax(preds, axis=-1) # 计算基本指标(准确率等) accuracy = (pred_ids == labels).astype(np.float32).mean().item() # 初始化ROUGE评分器 scorer = rouge_scorer.RougeScorer(['rouge1', 'rouge2', 'rougeL'], use_stemmer=True) # 存储所有分数 rouge1_scores = [] rouge2_scores = [] rougeL_scores = [] bleu_scores = [] # 使用平滑函数计算BLEU smoothing = SmoothingFunction().method1 # 遍历每个样本计算指标 for i in range(len(pred_ids)): # 解码预测和参考文本 pred_text = tokenizer.decode(pred_ids[i], skip_special_tokens=True) ref_text = tokenizer.decode(labels[i], skip_special_tokens=True) # 计算ROUGE分数 try: scores = scorer.score(ref_text, pred_text) rouge1_scores.append(scores['rouge1'].fmeasure) rouge2_scores.append(scores['rouge2'].fmeasure) rougeL_scores.append(scores['rougeL'].fmeasure) except Exception as e: # 如果计算出错,添加0分 rouge1_scores.append(0.0) rouge2_scores.append(0.0) rougeL_scores.append(0.0) # 计算BLEU分数 try: # 将文本分词 ref_tokens = nltk.word_tokenize(ref_text.lower()) pred_tokens = nltk.word_tokenize(pred_text.lower()) # 计算BLEU-1到BLEU-4分数并取平均 bleu_score = sentence_bleu( [ref_tokens], pred_tokens, weights=(0.25, 0.25, 0.25, 0.25), smoothing_function=smoothing ) bleu_scores.append(bleu_score) except Exception as e: bleu_scores.append(0.0) # 返回平均分数 return { "accuracy": accuracy, "rouge1": np.mean(rouge1_scores) if rouge1_scores else 0.0, "rouge2": np.mean(rouge2_scores) if rouge2_scores else 0.0, "rougeL": np.mean(rougeL_scores) if rougeL_scores else 0.0, "bleu": np.mean(bleu_scores) if bleu_scores else 0.0, } # 简化的 Trainer (移除评估函数) class SimpleTrainer(Trainer): def log(self, logs): if "loss" in logs: logs["Train Loss"] = logs.pop("loss") if "eval_loss" in logs: logs["Eval Loss"] = logs.pop("eval_loss") if "learning_rate" in logs: logs["Learning Rate"] = logs.pop("learning_rate") if "train_samples_per_second" in logs: logs["Train Samples/Second"] = f"{logs.pop('train_samples_per_second'):.2f}" super().log(logs) # 自定义 Callback (移除验证相关日志) class CustomCallback(TrainerCallback): def on_log(self, args, state, control, logs=None, **kwargs): epoch = logs.get("epoch", 0) train_loss = logs.get("Train Loss", "N/A") eval_loss = logs.get("Eval Loss", "N/A") learning_rate = logs.get("Learning Rate", 0) log_str = f"Epoch: {epoch:.2f}" if train_loss != "N/A": log_str += f" | Train Loss: {train_loss:.4f}" if eval_loss != "N/A": log_str += f" | Eval Loss: {eval_loss:.4f}" log_str += f" | Learning Rate: {learning_rate:.2e}" print(log_str) # 设置日志 for handler in logging.root.handlers[:]: logging.root.removeHandler(handler) logging.basicConfig(level=logging.INFO) ch = logging.StreamHandler() ch.setFormatter(logging.Formatter('%(message)s')) logging.root.addHandler(ch) # 创建损失记录回调 loss_callback = LossLoggingCallback() # 初始化 Trainer (使用验证集和评估指标) trainer = SimpleTrainer( model=model, args=training_args, train_dataset=tokenized_train, eval_dataset=tokenized_eval, tokenizer=tokenizer, data_collator=data_collator, compute_metrics=compute_metrics, # 添加评估指标计算函数 ) # 添加回调 trainer.add_callback(CustomCallback()) trainer.add_callback(loss_callback) # 清理显存 clear_gpu_memory() print("开始训练...") print_gpu_utilization() # 开始训练 train_result = trainer.train() # 绘制并保存损失曲线 def plot_loss_curve(steps, train_losses, eval_losses=None, save_path="./loss_curve.png"): print(f"尝试绘制损失曲线,训练数据点数: {len(steps)}") if len(steps) == 0 or len(train_losses) == 0: print("警告: 没有足够的数据来绘制损失曲线") return plt.figure(figsize=(10, 6)) plt.plot(steps, train_losses, marker='o', linestyle='-', color='b', label='Training Loss') if eval_losses and len(eval_losses) > 0: eval_steps = [(i+1) * training_args.eval_steps for i in range(len(eval_losses))] plt.plot(eval_steps, eval_losses, marker='s', linestyle='-', color='r', label='Evaluation Loss') plt.title('Training Loss Curve') plt.xlabel('Steps') plt.ylabel('Loss') plt.grid(True) plt.legend() plt.tight_layout() plt.savefig(save_path) plt.close() print(f"损失曲线已保存到: {save_path}") # 检查是否有记录到损失数据 print(f"是否记录到损失数据: {loss_callback.logged}") print(f"记录的步骤数: {len(loss_callback.steps)}") print(f"记录的训练损失值数: {len(loss_callback.train_losses)}") print(f"记录的验证损失值数: {len(loss_callback.eval_losses)}") # 绘制损失曲线 plot_loss_curve(loss_callback.steps, loss_callback.train_losses, loss_callback.eval_losses) # 获取训练结果 print("\n" + "="*50) print("训练统计信息:") print("="*50) print(f"全局步数: {train_result.global_step}") print(f"训练损失: {train_result.training_loss}") # 在最终模型上进行评估以获取最终指标 print("正在计算最终评估指标...") final_metrics = trainer.evaluate() print("\n" + "="*50) print("最终评估指标:") print("="*50) for key, value in final_metrics.items(): print(f"{key}: {value:.4f}") # 保存模型 model.save_pretrained("./deepseek-medical-final") tokenizer.save_pretrained("./deepseek-medical-final") trainer.save_model("./deepseek-medical-final") # 手动创建 generation_config.json from transformers import GenerationConfig generation_config = GenerationConfig( bos_token_id=tokenizer.bos_token_id if tokenizer.bos_token_id else 1, eos_token_id=tokenizer.eos_token_id if tokenizer.eos_token_id else 2, pad_token_id=tokenizer.pad_token_id if tokenizer.pad_token_id else 0, max_length=2048, max_new_tokens=512, do_sample=True, temperature=0.7, top_p=0.9, ) # 保存生成配置 generation_config.save_pretrained("./deepseek-medical-final") # 保存训练结果到文件 import json with open("./deepseek-medical-final/train_result.json", "w") as f: json.dump({ "train_result": train_result.metrics if hasattr(train_result, 'metrics') else {}, "final_metrics": final_metrics, "training_args": training_args.to_dict(), "loss_history": { "steps": loss_callback.steps, "train_losses": loss_callback.train_losses, "eval_losses": loss_callback.eval_losses } }, f, indent=2, ensure_ascii=False) print(f"\n模型和训练结果已保存到: ./deepseek-medical-final")

import torch import json import os import argparse import numpy as np import re from torch.utils.data import Dataset, DataLoader from tqdm import tqdm from PIL import Image from peft import LoraConfig, get_peft_model from transformers import ( AutoModelForCausalLM, AutoProcessor, TrainingArguments, BitsAndBytesConfig, GenerationConfig, AutoTokenizer, AutoImageProcessor, get_cosine_schedule_with_warmup ) import torch.optim as optim from sklearn.metrics import f1_score, accuracy_score, precision_score, recall_score, classification_report import warnings warnings.filterwarnings("ignore", message="Could not find a config file") # 标签映射定义 TASK1_LABEL_MAP = {"无害": 0, "有害": 1} TASK2_LABEL_MAP = { 0: "无害", 1: "针对性有害", 2: "一般性有害", 3: "性暗示", 4: "沮丧文化" } class HarmfulMemeDataset(Dataset): def __init__(self, annotation_path, tokenizer, image_processor, task_name, image_root=None): print(f"Loading annotations from: {annotation_path}") self.image_root = image_root with open(annotation_path, 'r', encoding='utf-8') as f: self.data = json.load(f) self.tokenizer = tokenizer self.task_name = task_name self.image_processor = image_processor self.label_token_ids = self._get_label_tokens() def _get_label_tokens(self): """获取标签对应的token ID""" if self.task_name == "task_1": labels = ["无害", "有害"] else: labels = [str(i) for i in range(5)] # 0-4 token_ids = {} tokenizer = self.processor.tokenizer for label in labels: tokens = tokenizer.encode(label) token_ids[label] = tokens # 保存完整的token序列 if len(tokens) > 1: print(f"警告: 标签 '{label}' 被分词为多个token: {tokens}") return token_ids def __len__(self): return len(self.data) def __getitem__(self, idx): sample = self.data[idx] if self.image_root: image_path = os.path.join(self.image_root, sample["path"]) else: image_path = sample["path"] if not os.path.exists(image_path): raise FileNotFoundError(f"图片不存在:{image_path}") image = Image.open(image_path).convert("RGB") if self.task_name == "task_1": user_content = f"任务:有害模因检测(是否有害)。\n输入文本:'{sample['text']}'\n请判断此图文组合是否有害。" raw_label = sample['label']# 原始标签是字符串("无害"或"有害") # 根据TASK1_LABEL_MAP进行映射 if isinstance(raw_label, int): # 如果是整数,转换为对应的字符串标签 label_map = {v: k for k, v in TASK1_LABEL_MAP.items()} # 反转映射 label = label_map.get(raw_label, "无害") # 默认值为"无害" else: # 如果已经是字符串,直接使用 label = raw_label label_token = self.label_token_ids[label] assistant_content = f"结论:{label}。\n理由:{sample['explanation']}" else: user_content = f"任务:有害模因类型分类。\n输入文本:'{sample['text']}'\n请判断此图文组合的有害类型(0-4)。" raw_label = str(sample['type'])# 将整数标签转换为字符串 label = str(raw_label) label_token = self.label_token_ids[label] assistant_content = f"结论:{label}。\n理由:{sample['explanation']}" messages = [ {"role": "user", "content": [{"type": "image"}, {"type": "text", "text": user_content}]}, {"role": "assistant", "content": [{"type": "text", "text": assistant_content}]} ] prompt = self.processor.apply_chat_template( messages, tokenize=False, add_generation_prompt=True, chat_format="chatml" ) # 单独处理图像 image = self.image_processor( images=image, return_tensors="pt" )["pixel_values"].squeeze(0) # 单独处理文本 encoding = self.tokenizer( text=prompt, return_tensors="pt", padding=False, truncation=False ) prompt_tokens = encoding["input_ids"][0].tolist() # 找到结论标签的位置 conclusion_start = self.processor.tokenizer.encode("结论:") # 在prompt中查找"结论:"的位置 start_idx = -1 for i in range(len(prompt_tokens) - len(conclusion_start) + 1): if prompt_tokens[i:i+len(conclusion_start)] == conclusion_start: start_idx = i + len(conclusion_start) break inputs = self.processor( text=prompt, images=image, return_tensors="pt", padding="max_length", truncation=True, max_length=512 ) inputs = {k: v.squeeze(0) for k, v in inputs.items()} # 创建标签张量,只标记结论位置 labels = torch.full_like(inputs["input_ids"], fill_value=-100, dtype=torch.long) if start_idx != -1 and start_idx < len(labels): # 标记整个标签token序列 label_tokens = self.label_token_ids[label] for i, token_id in enumerate(label_tokens): if start_idx + i < len(labels): labels[start_idx + i] = token_id inputs["labels"] = labels return inputs def parse_generated_text(self,text): """解析生成的文本,提取结论标签""" conclusion_match = re.search(r"结论[::]\s*(\S+)", text) if not conclusion_match: return None conclusion = conclusion_match.group(1).strip().rstrip('。.') # 处理多token标签 if conclusion in ["无害", "有害"]: # 任务1标签 return conclusion elif conclusion.isdigit() and 0 <= int(conclusion) <= 4: # 任务2标签 return conclusion # 尝试分词匹配 tokenizer = AutoProcessor.from_pretrained(args.model_id).tokenizer conclusion_tokens = tokenizer.encode(conclusion, add_special_tokens=False) # 与已知标签的token序列匹配 for label, tokens in self.label_token_ids.items(): if conclusion_tokens == tokens: return label return None def compute_metrics(task_name, preds, labels): """计算评估指标""" mask = labels != -100 preds = preds[mask] labels = labels[mask] if task_name == "task_1": # 二分类任务 return { "accuracy": accuracy_score(labels, preds), "f1": f1_score(labels, preds, average="binary"), "precision": precision_score(labels, preds, average="binary"), "recall": recall_score(labels, preds, average="binary") } else: # 多分类任务 report = classification_report(labels, preds, output_dict=True, zero_division=0) return { "accuracy": accuracy_score(labels, preds), "f1_macro": f1_score(labels, preds, average="macro"), "precision_macro": precision_score(labels, preds, average="macro"), "recall_macro": recall_score(labels, preds, average="macro"), "class_report": report } def main(args): os.environ["TOKENIZERS_PARALLELISM"] = "false" # 1. 加载模型和预处理器 print("Loading model and processor...") quantization_config = BitsAndBytesConfig( load_in_4bit=True, bnb_4bit_quant_type="nf4", bnb_4bit_compute_dtype=torch.bfloat16 ) model = AutoModelForCausalLM.from_pretrained( args.model_id, quantization_config=quantization_config, trust_remote_code=True, device_map="auto", bf16=True ) model.generation_config = GenerationConfig.from_pretrained( args.model_id, trust_remote_code=True, chat_format="chatml", max_new_tokens=100, pad_token_id=model.generation_config.eos_token_id ) # 分别初始化文本和图像处理器 tokenizer = AutoTokenizer.from_pretrained( args.model_id, trust_remote_code=True, pad_token='<|endoftext|>' # 显式设置pad_token ) image_processor = AutoImageProcessor.from_pretrained( args.model_id, trust_remote_code=True ) tokenizer.chat_template = """{% for message in messages %} <|im_start|>{{ message['role'] }} {{ message['content'] }} <|im_end|> {% endfor %} {% if add_generation_prompt %} <|im_start|>assistant {% endif %}""" # 设置pad token # 确保pad_token正确设置 if tokenizer.pad_token is None: tokenizer.pad_token = tokenizer.eos_token tokenizer.pad_token_id = tokenizer.eos_token_id # 2. LoRA配置 print("Configuring LoRA...") lora_config = LoraConfig( r=args.lora_rank, lora_alpha=args.lora_alpha, lora_dropout=args.lora_dropout, bias="none", task_type="CAUSAL_LM", target_modules=[ "c_attn", "c_proj", "w1", "w2", "w3", "visual.proj", "visual.image_encoder" ] ) peft_model = get_peft_model(model, lora_config) peft_model.print_trainable_parameters() # 3. 初始化优化器和调度器 optimizer = optim.AdamW( peft_model.parameters(), lr=args.learning_rate, weight_decay=args.weight_decay ) # 4. 训练参数配置 training_args = TrainingArguments( output_dir=os.path.join(args.output_dir, args.task), num_train_epochs=args.epochs, per_device_train_batch_size=args.batch_size, per_device_eval_batch_size=args.eval_batch_size, gradient_accumulation_steps=args.grad_accum_steps, learning_rate=args.learning_rate, weight_decay=args.weight_decay, lr_scheduler_type="cosine", logging_strategy="steps", logging_steps=10, save_strategy="epoch", eval_strategy="epoch", eval_accumulation_steps=1, metric_for_best_model="f1" if args.task == "task_1" else "f1_macro", greater_is_better=True, load_best_model_at_end=True, bf16=True, report_to="none", remove_unused_columns=False, disable_tqdm=False, skip_memory_metrics=True, dataloader_pin_memory=False, ) # 5. 加载数据集 print(f"Loading datasets for {args.task}...") train_dataset = HarmfulMemeDataset( annotation_path=args.train_annotation_path, tokenizer=tokenizer, image_processor=image_processor, task_name=args.task, image_root=args.image_root ) test_dataset = HarmfulMemeDataset( annotation_path=args.test_annotation_path, tokenizer=tokenizer, image_processor=image_processor, task_name=args.task, image_root=args.image_root ) # 创建数据加载器 train_loader = DataLoader( train_dataset, batch_size=args.batch_size, shuffle=True, num_workers=args.num_workers, pin_memory=True ) eval_loader = DataLoader( test_dataset, batch_size=args.eval_batch_size, shuffle=False, num_workers=args.num_workers, pin_memory=True ) # 计算总步数,初始化学习率调度器 total_train_steps = len(train_loader) // args.grad_accum_steps * args.epochs scheduler = get_cosine_schedule_with_warmup( optimizer, num_warmup_steps=args.warmup_steps, num_training_steps=total_train_steps ) # 6. 训练循环 print(f"Starting {args.task} training...") best_metric = -1 for epoch in range(args.epochs): print(f"\n===== Epoch {epoch + 1}/{args.epochs} =====") # 训练阶段 peft_model.train() total_train_loss = 0.0 train_pbar = tqdm(train_loader, desc=f"Training Epoch {epoch + 1}", unit="batch") for step, batch in enumerate(train_pbar): batch = {k: v.to(peft_model.device) for k, v in batch.items()} # 前向传播 outputs = peft_model(**batch) loss = outputs.loss total_train_loss += loss.item() # 梯度累积 loss = loss / args.grad_accum_steps loss.backward() # 参数更新 if (step + 1) % args.grad_accum_steps == 0: optimizer.step() scheduler.step() optimizer.zero_grad() # 更新进度条 train_pbar.set_postfix({"loss": f"{loss.item() * args.grad_accum_steps:.4f}"}) avg_train_loss = total_train_loss / len(train_loader) print(f"Epoch {epoch + 1} 平均训练损失: {avg_train_loss:.4f}") # 评估阶段 peft_model.eval() all_preds = [] all_labels = [] all_generated_texts = [] eval_pbar = tqdm(eval_loader, desc=f"Evaluating Epoch {epoch + 1}", unit="batch") with torch.no_grad(): for batch in eval_pbar: # 获取真实标签 labels = batch["labels"].cpu().numpy() mask = labels != -100 valid_labels = labels[mask].reshape(-1) # 生成文本 inputs = {k: v.to(peft_model.device) for k, v in batch.items() if k != "labels"} pad_token_id = tokenizer.pad_token_id or tokenizer.eos_token_id generated_ids = peft_model.generate( **inputs, generation_config=model.generation_config, pad_token_id=pad_token_id # 使用修正后的值 ) # 解码生成的文本 generated_texts = tokenizer.batch_decode( generated_ids, skip_special_tokens=True, clean_up_tokenization_spaces=True ) # 解析生成的文本获取预测标签 batch_preds = [] for text in generated_texts: # 提取assistant的响应部分 if "<|im_start|>assistant" in text: response = text.split("<|im_start|>assistant")[-1].strip() else: response = text # 解析结论 conclusion = parse_generated_text(response) if conclusion is None: # 无法解析结论,使用默认值 pred_label = 0 if args.task == "task_1" else "0" else: pred_label = conclusion # 转换为数字标签 if args.task == "task_1": # 二分类任务 if "无害" in pred_label: pred_value = 0 elif "有害" in pred_label: pred_value = 1 else: # 无法解析,使用默认值 pred_value = 0 else: # 多分类任务 if pred_label in ["0", "1", "2", "3", "4"]: pred_value = int(pred_label) else: # 无法解析,使用默认值 pred_value = 0 batch_preds.append(pred_value) all_preds.extend(batch_preds) all_labels.extend(valid_labels.tolist()) all_generated_texts.extend(generated_texts) # 计算评估指标 metrics = compute_metrics(args.task, np.array(all_preds), np.array(all_labels)) # 打印评估结果 print("\n评估指标:") print("=" * 50) if args.task == "task_1": print(f"Accuracy: {metrics['accuracy']:.4f}") print(f"F1 Score: {metrics['f1']:.4f}") print(f"Precision: {metrics['precision']:.4f}") print(f"Recall: {metrics['recall']:.4f}") else: print(f"Accuracy: {metrics['accuracy']:.4f}") print(f"Macro F1: {metrics['f1_macro']:.4f}") print(f"Macro Precision: {metrics['precision_macro']:.4f}") print(f"Macro Recall: {metrics['recall_macro']:.4f}") print("\n分类报告:") print(classification_report(all_labels, all_preds, target_names=list(TASK2_LABEL_MAP.values()), zero_division=0)) print("=" * 50) # 保存最佳模型 current_metric = metrics["f1"] if args.task == "task_1" else metrics["f1_macro"] if current_metric > best_metric: best_metric = current_metric save_path = os.path.join(training_args.output_dir, f"best_model_epoch{epoch+1}") print(f"保存最佳模型(指标 {current_metric:.4f})到 {save_path}") peft_model.save_pretrained(save_path) # 保存生成的文本示例 sample_output_path = os.path.join(save_path, "sample_outputs.txt") with open(sample_output_path, "w", encoding="utf-8") as f: for i, text in enumerate(all_generated_texts[:10]): f.write(f"样本 {i+1}:\n") f.write(text) f.write("\n" + "-"*80 + "\n") print(f"训练完成!最佳指标: {best_metric:.4f}") if __name__ == "__main__": parser = argparse.ArgumentParser(description="训练有害模因检测模型") parser.add_argument("--model_id", default="/xzwu/Qwen-VL-Chat", help="预训练模型路径") parser.add_argument("--output_dir", default="/xzwu/explain-m3-adapter", help="输出目录") parser.add_argument("--epochs", type=int, default=5, help="训练轮数") parser.add_argument("--batch_size", type=int, default=4, help="训练批次大小") parser.add_argument("--eval_batch_size", type=int, default=4, help="评估批次大小") parser.add_argument("--grad_accum_steps", type=int, default=2, help="梯度累积步数") parser.add_argument("--learning_rate", type=float, default=1e-5, help="学习率") parser.add_argument("--weight_decay", type=float, default=0.01, help="权重衰减") parser.add_argument("--warmup_steps", type=int, default=100, help="预热步数") parser.add_argument("--lora_rank", type=int, default=8, help="LoRA秩") parser.add_argument("--lora_alpha", type=int, default=16, help="LoRA alpha") parser.add_argument("--lora_dropout", type=float, default=0.1, help="LoRA dropout") parser.add_argument("--num_workers", type=int, default=4, help="数据加载工作线程数") parser.add_argument("--task", choices=["task_1", "task_2"], default="task_1", help="任务类型") parser.add_argument("--train_annotation_path", default="/xzwu/data/data/train_data_explanation.json", help="训练标注路径") parser.add_argument("--test_annotation_path", default="/xzwu/data/data/test_data_explanation.json", help="测试标注路径") parser.add_argument("--image_root", default="/xzwu/data/meme", help="图片根目录") args = parser.parse_args() # 打印配置 print("=" * 50) print("训练配置:") for arg in vars(args): print(f"{arg}: {getattr(args, arg)}") print("=" * 50) main(args)运行以上代码报错:Traceback (most recent call last): File "/xzwu/explain-m3/explain-m3-project/train2.py", line 530, in <module> main(args) File "/xzwu/explain-m3/explain-m3-project/train2.py", line 314, in main train_dataset = HarmfulMemeDataset( File "/xzwu/explain-m3/explain-m3-project/train2.py", line 46, in __init__ self.label_token_ids = self._get_label_tokens() File "/xzwu/explain-m3/explain-m3-project/train2.py", line 56, in _get_label_tokens tokenizer = self.processor.tokenizer AttributeError: 'HarmfulMemeDataset' object has no attribute 'processor'

from datasets import load_dataset from transformers import T5Tokenizer, T5ForConditionalGeneration, Seq2SeqTrainer, Seq2SeqTrainingArguments import numpy as np tokenizer = T5Tokenizer.from_pretrained("flan-t5-base") model = T5ForConditionalGeneration.from_pretrained("flan-t5-base").to("cuda:0") def preprocess_function(examples): inputs = ["sentiment analysis: " + text for text in examples["text"]] targets = [str(label) for label in examples["labels"]] # 标签需转换为字符串 model_inputs = tokenizer( inputs, max_length=128, truncation=True, padding="max_length" ) labels = tokenizer( targets, max_length=8, # 根据标签长度调整 truncation=True, padding="max_length" ) model_inputs["labels"] = labels["input_ids"] return model_inputs # 3. 加载数据集(以GoEmotions为例) dataset = load_dataset("go_emotions", split="train[:5000]") dataset = dataset.map(preprocess_function, batched=True) # 4. 训练配置 training_args = Seq2SeqTrainingArguments( output_dir="./results", evaluation_strategy="epoch", learning_rate=3e-5, per_device_train_batch_size=8, per_device_eval_batch_size=8, num_train_epochs=3, predict_with_generate=True # 启用生成模式 ) # 5. 定义评估指标 def compute_metrics(eval_pred): predictions, labels = eval_pred decoded_preds = tokenizer.batch_decode(predictions, skip_special_tokens=True) # 将字符串标签转换为数值 decoded_labels = tokenizer.batch_decode(labels, skip_special_tokens=True) accuracy = np.mean([int(p == l) for p, l in zip(decoded_preds, decoded_labels)]) return {"accuracy": accuracy} # 6. 创建Trainer trainer = Seq2SeqTrainer( model=model, args=training_args, train_dataset=dataset, eval_dataset=dataset.shuffle().select(range(500)), compute_metrics=compute_metrics ) # 7. 开始训练 trainer.train()ValueError: Class label 16047 greater than configured num_classes 28

from transformers import AutoModelForTokenClassification, AutoTokenizer, DataCollatorForTokenClassification from transformers import TrainingArguments, Trainer import evaluate from datasets import load_dataset import numpy as np from seqeval.metrics import classification_report, f1_score, precision_score, recall_score import torch import os import json import logging from collections import Counter from sklearn.utils.class_weight import compute_class_weight import matplotlib.pyplot as plt # 设置详细日志 logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') logger = logging.getLogger(__name__) # 设置设备 device = torch.device("cuda" if torch.cuda.is_available() else "cpu") logger.info(f"Using device: {device}") # 模型路径 model_dir = 'C:/Users/admin/.cache/modelscope/hub/tiansz/bert-base-chinese' # 加载tokenizer tokenizer = AutoTokenizer.from_pretrained(model_dir) logger.info("Tokenizer加载完成") # 加载数据集 path = r'C:\Users\admin\八斗学院学习笔记\练习\week11_codes\data' dataset = load_dataset(path) logger.info(f"数据集加载完成: {dataset}") # 提取所有实体标签 labels = set() for row in dataset['train']: for ent in row['entities']: labels.add(ent['label']) # 创建完整的标签列表(包含B-和I-前缀) entities = sorted(list(labels)) # 排序确保一致性 tags = ['O'] for ent in entities: tags.append('B-' + ent.upper()) tags.append('I-' + ent.upper()) # 创建标签到ID的映射 tag2id = {tag: i for i, tag in enumerate(tags)} id2tag = {i: tag for i, tag in enumerate(tags)} logger.info(f"标签数量: {len(tags)}") logger.info(f"标签列表: {tags}") # 保存标签映射 os.makedirs('label_mappings', exist_ok=True) with open('label_mappings/tag2id.json', 'w', encoding='utf-8') as f: json.dump(tag2id, f, ensure_ascii=False, indent=2) with open('label_mappings/id2tag.json', 'w', encoding='utf-8') as f: json.dump(id2tag, f, ensure_ascii=False, indent=2) logger.info("标签映射已保存到 label_mappings 目录") # 实体处理函数(修复版)- 确保标签正确性 def entities_proc(items): text = items['text'] items_len = len(text) ent_tags = ['O'] * items_len # 初始化为'O' entities = items['entities'] for ent in entities: start = ent['start_offset'] end = ent['end_offset'] label = ent['label'].upper() # 统一转换为大写 # 确保位置在范围内 if start < items_len: # 设置B-标签 ent_tags[start] = f'B-{label}' # 设置I-标签(如果有多个字符) for pos in range(start + 1, min(end, items_len)): ent_tags[pos] = f'I-{label}' # 转换为ID(遇到未知标签默认为'O') tag_ids = [tag2id.get(tag, tag2id['O']) for tag in ent_tags] return {'ent_tags': tag_ids} # 应用实体处理 logger.info("处理实体标签...") ds = dataset.map(entities_proc) # 分析标签分布 def analyze_label_distribution(dataset, split): logger.info(f"\n分析 {split} 标签分布...") all_labels = [] for example in dataset[split]: all_labels.extend([id2tag.get(tag_id, 'O') for tag_id in example['ent_tags']]) label_counts = Counter(all_labels) total_labels = len(all_labels) logger.info(f"总标签数: {total_labels}") for label, count in label_counts.items(): percentage = (count / total_labels) * 100 logger.info(f"{label}: {count} ({percentage:.2f}%)") # 计算实体标签的比例 entity_labels = [label for label in label_counts.keys() if label != 'O'] entity_count = sum([label_counts[label] for label in entity_labels]) entity_percentage = (entity_count / total_labels) * 100 logger.info(f"实体标签总数: {entity_count} ({entity_percentage:.2f}%)") logger.info(f"非实体标签(O): {label_counts['O']} ({100-entity_percentage:.2f}%)") # 可视化标签分布 plt.figure(figsize=(12, 6)) labels_list = list(label_counts.keys()) counts = [label_counts[l] for l in labels_list] plt.bar(labels_list, counts) plt.xticks(rotation=90) plt.title(f'{split} 标签分布') plt.ylabel('数量') plt.tight_layout() plt.savefig(f'label_distribution_{split}.png') logger.info(f"标签分布图已保存为 label_distribution_{split}.png") return label_counts # 分析标签分布 train_label_counts = analyze_label_distribution(ds, 'train') test_label_counts = analyze_label_distribution(ds, 'test') # 计算类别权重解决不平衡问题 logger.info("\n计算类别权重解决不平衡问题...") all_train_labels = [] for example in ds['train']: all_train_labels.extend(example['ent_tags']) # 计算类别权重 class_weights = compute_class_weight( class_weight='balanced', classes=np.unique(all_train_labels), y=all_train_labels ) class_weights = torch.tensor(class_weights, dtype=torch.float32).to(device) # 增强实体标签的权重 for i, tag in enumerate(tags): if tag != 'O': class_weights[i] *= 5.0 # 增加实体标签的权重 logger.info(f"类别权重: {class_weights}") # 数据输入处理函数(修复版 - 使用offset_mapping) def data_input_proc(items): # 获取文本列表 texts = items['text'] # 分词(启用offset_mapping) tokenized_inputs = tokenizer( texts, truncation=True, padding=True, max_length=128, return_offsets_mapping=True, is_split_into_words=False, return_tensors="pt", ) # 获取偏移量映射 offset_mappings = tokenized_inputs.pop('offset_mapping') all_labels = [] for i, text in enumerate(texts): # 获取字符级标签ID列表 char_tags = items['ent_tags'][i] label_ids = [] offsets = offset_mappings[i] for j, offset in enumerate(offsets): start, end = offset # 特殊token ([CLS], [SEP], [PAD]) 设置为-100 if start == 0 and end == 0: label_ids.append(-100) else: # 取起始位置对应的字符标签 if start < len(char_tags): label_ids.append(char_tags[start]) else: # 处理截断情况 label_ids.append(-100) all_labels.append(label_ids) tokenized_inputs["labels"] = all_labels return tokenized_inputs # 应用输入处理 logger.info("处理输入数据...") ds1 = ds.map( data_input_proc, batched=True, batch_size=8, remove_columns=ds["train"].column_names ) # 训练参数 args = TrainingArguments( output_dir='ner_train', num_train_epochs=3, per_device_train_batch_size=4, per_device_eval_batch_size=8, evaluation_strategy="epoch", save_strategy="epoch", logging_strategy="epoch", load_best_model_at_end=False, # 暂时禁用,直到我们解决指标问题 report_to='tensorboard', logging_dir='ner_train/logs', save_total_limit=2, learning_rate=5e-5, weight_decay=0.01, overwrite_output_dir=True, warmup_ratio=0.1, gradient_accumulation_steps=4, fp16=torch.cuda.is_available(), logging_steps=20, remove_unused_columns=False, # 暂时不使用 metric_for_best_model ) # 创建带类别权重的自定义损失函数 class WeightedLossModel(torch.nn.Module): def __init__(self, model, class_weights): super().__init__() self.model = model self.class_weights = class_weights self.loss_fct = torch.nn.CrossEntropyLoss(weight=class_weights, ignore_index=-100) def forward(self, **inputs): outputs = self.model(**inputs) logits = outputs.logits if "labels" in inputs: loss = self.loss_fct(logits.view(-1, self.model.config.num_labels), inputs["labels"].view(-1)) outputs.loss = loss return outputs # 加载基础模型 logger.info("加载基础模型...") base_model = AutoModelForTokenClassification.from_pretrained( model_dir, num_labels=len(tags), id2label=id2tag, label2id=tag2id, ignore_mismatched_sizes=True ).to(device) # 创建带权重的模型 model = WeightedLossModel(base_model, class_weights).to(device) logger.info(f"模型结构: 带类别权重的{base_model.__class__.__name__}") logger.info(f"模型参数量: {sum(p.numel() for p in model.parameters()):,}") # 数据收集器 data_collator = DataCollatorForTokenClassification(tokenizer=tokenizer) # 评估指标计算函数(增强调试版) def compute_metrics(p): try: # 确保输入格式正确 if hasattr(p, "predictions") and hasattr(p, "label_ids"): predictions = p.predictions labels = p.label_ids elif isinstance(p, tuple) and len(p) == 2: predictions, labels = p else: logger.error(f"无法识别的输入格式: {type(p)}") return {"f1": 0.0, "precision": 0.0, "recall": 0.0, "accuracy": 0.0} # 确保预测结果有正确的形状 if predictions.ndim == 3: predictions = np.argmax(predictions, axis=2) # 移除忽略的索引(-100) true_predictions = [] true_labels = [] for i in range(len(predictions)): preds = [] lbls = [] for j in range(len(predictions[i])): if labels[i][j] != -100: preds.append(id2tag[predictions[i][j]]) lbls.append(id2tag[labels[i][j]]) true_predictions.append(preds) true_labels.append(lbls) # 计算指标 precision = 0.0 recall = 0.0 f1 = 0.0 accuracy = 0.0 if true_labels and any(true_labels): # 确保标签列表非空 try: precision = precision_score(true_labels, true_predictions, zero_division=0) recall = recall_score(true_labels, true_predictions, zero_division=0) f1 = f1_score(true_labels, true_predictions, zero_division=0) # 计算准确率(token级别) total = 0 correct = 0 for preds, lbls in zip(true_predictions, true_labels): for p, l in zip(preds, lbls): total += 1 if p == l: correct += 1 accuracy = correct / total if total > 0 else 0.0 # 生成分类报告 report = classification_report(true_labels, true_predictions, output_dict=True, zero_division=0) # 记录实体标签的性能 logger.info("\n===== 详细分类报告 =====") for tag in tags: if tag in report and tag != 'O': logger.info(f"{tag}: P={report[tag]['precision']:.4f}, R={report[tag]['recall']:.4f}, F1={report[tag]['f1-score']:.4f}") # 记录前10个预测和标签 logger.info("\n===== 样本预测检查 =====") for i in range(min(3, len(true_labels))): logger.info(f"样本 {i} 预测: {' '.join(true_predictions[i][:20])}") logger.info(f"样本 {i} 标签: {' '.join(true_labels[i][:20])}") logger.info("") # 计算并记录非O标签的准确率 non_o_correct = 0 non_o_total = 0 for preds, lbls in zip(true_predictions, true_labels): for p, l in zip(preds, lbls): if l != 'O': non_o_total += 1 if p == l: non_o_correct += 1 non_o_accuracy = non_o_correct / non_o_total if non_o_total > 0 else 0.0 logger.info(f"非O标签准确率: {non_o_accuracy:.4f} ({non_o_correct}/{non_o_total})") except Exception as inner_e: logger.error(f"计算评估指标时出错: {inner_e}") logger.error(f"预测形状: {predictions.shape}") logger.error(f"标签形状: {labels.shape}") logger.error(f"true_labels长度: {len(true_labels)}") logger.error(f"true_labels内容示例: {true_labels[:1] if true_labels else '空'}") else: logger.warning("评估时没有有效标签!") return { "f1": f1, "precision": precision, "recall": recall, "accuracy": accuracy } except Exception as outer_e: logger.error(f"compute_metrics函数发生严重错误: {outer_e}") return { "f1": 0.0, "precision": 0.0, "recall": 0.0, "accuracy": 0.0 } # 创建Trainer trainer = Trainer( model=model, args=args, train_dataset=ds1['train'], eval_dataset=ds1['test'], data_collator=data_collator, compute_metrics=compute_metrics, tokenizer=tokenizer ) # 预评估测试 logger.info("进行预评估测试...") try: eval_result = trainer.evaluate() logger.info(f"预评估结果: {eval_result}") # 检查是否返回了我们的指标 if "eval_f1" in eval_result: logger.info("评估指标计算成功!") # 重新启用最佳模型保存 args.load_best_model_at_end = True args.metric_for_best_model = "f1" # 使用基础名称,Trainer会自动添加"eval_"前缀 trainer = Trainer( model=model, args=args, train_dataset=ds1['train'], eval_dataset=ds1['test'], data_collator=data_collator, compute_metrics=compute_metrics, tokenizer=tokenizer ) else: logger.warning("评估指标未返回,将禁用最佳模型保存功能") except Exception as e: logger.error(f"预评估失败: {e}") # 训练模型 logger.info("开始训练...") try: train_result = trainer.train() logger.info("训练完成!") except Exception as e: logger.error(f"训练失败: {e}") # 尝试更小的学习率 logger.info("尝试更小的学习率...") args.learning_rate = 1e-5 trainer = Trainer( model=model, args=args, train_dataset=ds1['train'], eval_dataset=ds1['test'], data_collator=data_collator, compute_metrics=compute_metrics, tokenizer=tokenizer ) train_result = trainer.train() logger.info("训练完成!") # 保存最终模型 trainer.save_model("final_ner_model") logger.info("最终模型已保存到 final_ner_model 目录") # 训练完成后评估模型 logger.info("\n===== 最终评估结果 =====") try: eval_results = trainer.evaluate(ds1['test']) logger.info(f"验证集准确率: {eval_results.get('eval_accuracy', 0.0):.4f}") logger.info(f"验证集精确率: {eval_results.get('eval_precision', 0.0):.4f}") logger.info(f"验证集召回率: {eval_results.get('eval_recall', 0.0):.4f}") logger.info(f"验证集F1值: {eval_results.get('eval_f1', 0.0):.4f}") # 打印所有可用的评估指标 logger.info("\n所有可用评估指标:") for key, value in eval_results.items(): logger.info(f"{key}: {value}") except Exception as e: logger.error(f"最终评估失败: {e}") # 绘制训练损失曲线 def plot_training_history(history): try: train_loss = [log['loss'] for log in history if 'loss' in log] eval_loss = [log['eval_loss'] for log in history if 'eval_loss' in log] if not train_loss: logger.warning("没有训练损失数据可绘制") return epochs = list(range(1, len(train_loss) + 1)) plt.figure(figsize=(12, 6)) plt.plot(epochs, train_loss, 'b-', label='训练损失') if eval_loss: plt.plot(epochs[:len(eval_loss)], eval_loss, 'r-', label='验证损失') plt.title('训练和验证损失') plt.xlabel('Epochs') plt.ylabel('损失') plt.legend() plt.grid(True) plt.savefig('training_loss.png') logger.info("训练损失图已保存为 training_loss.png") # 绘制F1分数(如果可用) eval_f1 = [log['eval_f1'] for log in history if 'eval_f1' in log] if eval_f1: plt.figure(figsize=(12, 6)) plt.plot(epochs[:len(eval_f1)], eval_f1, 'g-', label='验证F1') plt.title('验证F1分数') plt.xlabel('Epochs') plt.ylabel('F1分数') plt.legend() plt.grid(True) plt.savefig('eval_f1.png') logger.info("F1分数图已保存为 eval_f1.png") except Exception as e: logger.error(f"绘制训练历史时出错: {e}") # 绘制训练历史 plot_training_history(trainer.state.log_history) # 测试模型预测 logger.info("\n测试模型预测...") sample_texts = [ "我在北京大学学习人工智能", "马云是阿里巴巴集团的创始人", "上海市浦东新区张江高科技园区" ] # 自定义预测函数 def predict_entities(text, model, tokenizer, id2tag, device): try: # 分词 inputs = tokenizer( text, return_tensors="pt", return_offsets_mapping=True, truncation=True, max_length=128 ) # 移动到设备 input_ids = inputs['input_ids'].to(device) attention_mask = inputs['attention_mask'].to(device) token_type_ids = inputs.get('token_type_ids', None) if token_type_ids is not None: token_type_ids = token_type_ids.to(device) offset_mapping = inputs['offset_mapping'].cpu().numpy()[0] # 预测 model.eval() with torch.no_grad(): outputs = model( input_ids=input_ids, attention_mask=attention_mask, token_type_ids=token_type_ids ) # 获取预测结果 logits = outputs.logits predictions = torch.argmax(logits, dim=-1).cpu().numpy()[0] # 提取实体 entities = [] current_entity = None tokens = tokenizer.convert_ids_to_tokens(input_ids[0]) logger.info(f"\n预测文本: {text}") logger.info(f"Token列表: {tokens}") for i, (pred, offset) in enumerate(zip(predictions, offset_mapping)): # 跳过特殊token if offset[0] == 0 and offset[1] == 0: continue tag = id2tag[pred] logger.info(f"Token {i}: {tokens[i]} -> {tag} (位置: {offset[0]}-{offset[1]})") # 处理实体 if tag.startswith('B-'): # 结束前一个实体 if current_entity: entities.append(current_entity) # 开始新实体 entity_type = tag[2:] start = offset[0] end = offset[1] current_entity = { 'start': start, 'end': end, 'type': entity_type, 'text': text[start:end] } elif tag.startswith('I-'): # 继续当前实体 if current_entity and current_entity['type'] == tag[2:]: current_entity['end'] = offset[1] current_entity['text'] = text[current_entity['start']:offset[1]] else: # 如果I标签没有匹配的B标签,则创建新实体 entity_type = tag[2:] start = offset[0] end = offset[1] current_entity = { 'start': start, 'end': end, 'type': entity_type, 'text': text[start:end] } else: # O # 结束前一个实体 if current_entity: entities.append(current_entity) current_entity = None # 添加最后一个实体 if current_entity: entities.append(current_entity) return entities except Exception as e: logger.error(f"预测过程中出错: {e}") return [] # 进行预测 for text in sample_texts: logger.info(f"\n===== 预测文本: {text} =====") try: entities = predict_entities(text, model, tokenizer, id2tag, device) if not entities: logger.info(" 未识别到实体") else: for ent in entities: logger.info(f" 实体: {ent['text']}, 类型: {ent['type']}, 位置: {ent['start']}-{ent['end']}") except Exception as e: logger.error(f"预测文本 '{text}' 时出错: {e}") logger.info("\nNER任务完成!")这代码都实现了什么还有可以优化的嘛

docx
内容概要:本文档详细介绍了基于MATLAB实现的多头长短期记忆网络(MH-LSTM)结合Transformer编码器进行多变量时间序列预测的项目实例。项目旨在通过融合MH-LSTM对时序动态的细致学习和Transformer对全局依赖的捕捉,显著提升多变量时间序列预测的精度和稳定性。文档涵盖了从项目背景、目标意义、挑战与解决方案、模型架构及代码示例,到具体的应用领域、部署与应用、未来改进方向等方面的全面内容。项目不仅展示了技术实现细节,还提供了从数据预处理、模型构建与训练到性能评估的全流程指导。 适合人群:具备一定编程基础,特别是熟悉MATLAB和深度学习基础知识的研发人员、数据科学家以及从事时间序列预测研究的专业人士。 使用场景及目标:①深入理解MH-LSTM与Transformer结合的多变量时间序列预测模型原理;②掌握MATLAB环境下复杂神经网络的搭建、训练及优化技巧;③应用于金融风险管理、智能电网负荷预测、气象预报、交通流量预测、工业设备健康监测、医疗数据分析、供应链需求预测等多个实际场景,以提高预测精度和决策质量。 阅读建议:此资源不仅适用于希望深入了解多变量时间序列预测技术的读者,也适合希望通过MATLAB实现复杂深度学习模型的开发者。建议读者在学习过程中结合提供的代码示例进行实践操作,并关注模型训练中的关键步骤和超参数调优策略,以便更好地应用于实际项目中。

大家在看

recommend-type

IFIX 4.5 MB1 驱动

 MB1:有两个版本,6.x 和 7.x 版,通过串行口连接所有支持 Modbus 串行通讯协议的设备。主要有 Modicon PLC 和其它控制仪表如:Honeywell UDC,UMC,Moore 的控制仪表等。支持 Mobus RTU 和 ASCII 两种通讯协议。当使用其与其它兼容设备通讯时,注意数据类型会与 Modicon 的数据类型有所差别。7.x 版本支持电话拨号连接和无线电连接。
recommend-type

TLSF-All.rar_网络编程_C/C++_

TLSF2.46源代码+相关的英文文献在网站http://rtportal.upv.es/rtmalloc/上可以下载到原代码,但注意下载文件的格式。
recommend-type

思源黑体、简体、中文全套TTF格式

思源黑体、简体、中文全套TTF格式
recommend-type

高频感应加热电源斩波器补偿电路的设计

本文在分析基于功率控制的Buck斩波器的小信号模型和反馈控制模式的基础上,探讨了反馈控制的传递函数和环路参数的设计。对于高频感应加热电源广泛应用的Buck斩波调功电路,设计了双极点、双零点补偿电路,补偿后的系统不仅提高了系统响应速度,而且消除了稳态误差,系统性能明显提高。实验结果证明了这种补偿电路的实用性和有效性,对高频感应加热电源的改进和研究具有很好的参考价值。
recommend-type

XposedDetector

Xposed探测器 预制的静态库,用于检测xposed和清除钩子。 该库基于。 一体化 Gradle: implementation ' io.github.vvb2060.ndk:xposeddetector:2.2 ' 该库是 ,因此您需要在项目中启用它(Android Gradle Plugin 4.1+): android { .. . buildFeatures { .. . prefab true } } 用法 ndk构建 您可以在Android.mk使用xposed_detector 。 例如,如果您的应用程序定义了libapp.so并使用xposed_detector ,则您的Android.mk文件应包括以下内容: include $( CLEAR_VARS ) LOCAL_MODULE

最新推荐

recommend-type

【电子设计竞赛】2018年电子设计大赛A题失真度分析仪:从理论到代码实现全解析

内容概要:本文深入解析了2018年电子设计大赛A题——失真度分析仪的设计与实现。文章首先介绍了题目的背景与要求,包括谐波计算、数据显示和无线传输三个核心任务。接着详细阐述了解题思路,涵盖信号采集(ADC)、FFT分析、失真度计算、显示与无线传输等方面的技术要点。硬件设计部分重点讲解了信号调理电路、ADC电路、显示电路和无线传输电路的具体实现方法。最后提供了软件代码实现,包括ADC采样、FFT计算、失真度计算、数据显示与无线传输的代码示例。; 适合人群:对电子设计感兴趣的初学者、电子工程专业的学生及有一定基础的电子爱好者。; 使用场景及目标:①帮助读者理解失真度分析仪的工作原理和技术实现;②为准备参加类似电子设计竞赛的人提供参考;③通过实例代码加深对电子电路、信号处理和编程的理解。; 其他说明:本文不仅涵盖了理论知识,还提供了详细的代码实现,有助于读者在实践中学习和掌握相关技能。同时,文中提到的一些优化方向也为进一步探索电子设计提供了思路。
recommend-type

Matlab实现高斯烟羽模型源码:高效且精确的大气扩散模拟工具 Matlab

使用Matlab实现高斯烟羽模型的方法及其应用。首先解释了高斯烟羽模型的基本原理,特别是核心算法部分,包括参数校验、扩散系数的经验公式以及烟羽公式的具体实现。接着讨论了可视化部分,展示了如何利用Matlab进行空间网格生成、浓度分布的动态剖面生成和伪彩色渲染。此外,还探讨了扩散系数对模型精度的影响,并提供了不同大气稳定度条件下的系数调整方法。最后提到了模型验证过程中的一些物理规律和注意事项。 适合人群:环境科学、大气物理学及相关领域的研究人员和技术人员,尤其是那些需要进行大气污染物扩散模拟的人群。 使用场景及目标:适用于化工园区的大气扩散模拟项目,特别是在应急响应场景中预测污染物的扩散情况。目标是帮助用户理解和掌握高斯烟羽模型的实现方法,提高大气扩散模拟的效率和准确性。 其他说明:文中提到的代码片段可以直接用于实际项目中,但需要注意参数的选择和调整,以确保模型的适用性和可靠性。同时,在使用该模型时,应当引用相关文献,尊重知识产权。
recommend-type

spring-jdbc-6.1.9.jar中文-英文对照文档.zip

1、压缩文件中包含: 中文-英文对照文档、jar包下载地址、Maven依赖、Gradle依赖、源代码下载地址。 2、使用方法: 解压最外层zip,再解压其中的zip包,双击 【index.html】 文件,即可用浏览器打开、进行查看。 3、特殊说明: (1)本文档为人性化翻译,精心制作,请放心使用; (2)只翻译了该翻译的内容,如:注释、说明、描述、用法讲解 等; (3)不该翻译的内容保持原样,如:类名、方法名、包名、类型、关键字、代码 等。 4、温馨提示: (1)为了防止解压后路径太长导致浏览器无法打开,推荐在解压时选择“解压到当前文件夹”(放心,自带文件夹,文件不会散落一地); (2)有时,一套Java组件会有多个jar,所以在下载前,请仔细阅读本篇描述,以确保这就是你需要的文件。 5、本文件关键字: jar中文-英文对照文档.zip,java,jar包,Maven,第三方jar包,组件,开源组件,第三方组件,Gradle,中文API文档,手册,开发手册,使用手册,参考手册。
recommend-type

西门子S7-200PLC与MCGS组态联手打造全自动洗衣机智能控制系统 - 通信协议 v4.0

如何利用西门子S7-200 PLC和MCGS组态软件构建高效的全自动洗衣机控制系统。系统以PLC为核心控制单元,通过MCGS组态软件实现人机界面交互,涵盖硬件组成、软件设计及系统功能。硬件部分包括PLC、MCGS组态软件、传感器和执行机构;软件设计涉及PLC程序和MCGS界面设计,确保数据准确传输和系统稳定性。系统功能包括全自动控制、状态显示和故障诊断,提高了洗衣机的使用体验和效率。 适合人群:从事自动化控制领域的工程师和技术人员,尤其是对PLC和MCGS组态软件有一定了解的专业人士。 使用场景及目标:适用于需要深入了解和应用PLC与MCGS组态软件进行家电控制系统设计的场合,旨在提升家电产品的智能化水平和用户体验。 阅读建议:读者可以通过本文详细了解PLC和MCGS组态软件的具体应用,掌握全自动洗衣机控制系统的设计思路和实现方法,从而应用于实际项目中。
recommend-type

MATLAB实现基于MH-LSTM-Transformer 多头长短期记忆网络(MH-LSTM)结合 Transformer 编码器进行多变量时间序列预测的详细项目实例(含完整的程序,GUI设计和代码

内容概要:本文档详细介绍了基于MATLAB实现的多头长短期记忆网络(MH-LSTM)结合Transformer编码器进行多变量时间序列预测的项目实例。项目旨在通过融合MH-LSTM对时序动态的细致学习和Transformer对全局依赖的捕捉,显著提升多变量时间序列预测的精度和稳定性。文档涵盖了从项目背景、目标意义、挑战与解决方案、模型架构及代码示例,到具体的应用领域、部署与应用、未来改进方向等方面的全面内容。项目不仅展示了技术实现细节,还提供了从数据预处理、模型构建与训练到性能评估的全流程指导。 适合人群:具备一定编程基础,特别是熟悉MATLAB和深度学习基础知识的研发人员、数据科学家以及从事时间序列预测研究的专业人士。 使用场景及目标:①深入理解MH-LSTM与Transformer结合的多变量时间序列预测模型原理;②掌握MATLAB环境下复杂神经网络的搭建、训练及优化技巧;③应用于金融风险管理、智能电网负荷预测、气象预报、交通流量预测、工业设备健康监测、医疗数据分析、供应链需求预测等多个实际场景,以提高预测精度和决策质量。 阅读建议:此资源不仅适用于希望深入了解多变量时间序列预测技术的读者,也适合希望通过MATLAB实现复杂深度学习模型的开发者。建议读者在学习过程中结合提供的代码示例进行实践操作,并关注模型训练中的关键步骤和超参数调优策略,以便更好地应用于实际项目中。
recommend-type

Python打造的Slaee管理系统升级版发布

由于提供的文件信息中,文件名《基于python的slaee管理系统 (15).zip》与描述《基于python的slaee管理系统 (15).zip》相同,并且给出的压缩包文件名称列表中只有一个文件《基于python的slaee管理系统 (14).zip》,该信息表明我们正在讨论两个不同版本的Python系统管理软件的压缩包。以下知识点将根据这些信息详细展开: 知识点一:Python编程语言基础 Python是一种高级编程语言,以其简洁的语法和强大的库支持而闻名。它是解释型语言,具有动态类型系统和垃圾回收功能,适用于多种编程范式,包括面向对象、命令式、函数式和过程式编程。Python广泛应用于系统管理、网络服务器、开发脚本、科学计算、数据挖掘和人工智能等领域。 知识点二:系统管理相关知识 系统管理指的是对计算机系统进行配置、监控和维护的过程,包括硬件资源、软件资源和数据资源的管理。在Python中,系统管理通常涉及操作系统级别的任务,如进程管理、文件系统管理、网络配置、系统日志监控等。Python的系统管理库(例如psutil、fabric、paramiko等)提供了丰富的API来简化这些任务。 知识点三:项目版本控制 从文件名《基于python的slaee管理系统 (14).zip》和《基于python的slaee管理系统 (15).zip》可以看出,这是一个项目在不同版本之间的迭代。版本控制是一种记录一个或多个文件随时间变化的方式,它允许用户可以回到特定版本。在软件开发中,版本控制非常重要,它有助于团队协作、代码合并、分支管理和错误跟踪。常见的版本控制系统包括Git、Subversion (SVN)、Mercurial等。 知识点四:打包与部署 提到“压缩包子文件”,这通常意味着文件已经被压缩打包成一个ZIP文件。在软件开发中,打包是为了便于文件传输、存档保存和分发。在Python项目中,打包也是部署过程的一部分。一个Python项目通常需要包含源代码、依赖关系、配置文件和安装脚本等。打包成ZIP文件后,可以通过各种方式部署到服务器上运行,如使用Fabric或Ansible等自动化部署工具。 知识点五:项目命名及版本命名规则 文件命名中的“基于python的slaee管理系统”表明这是一个与Python语言相关的系统管理项目。而数字“15”和“14”则代表着项目的版本号,这表明项目在持续发展,不同的数字代表了项目在不同时期的迭代。版本号的命名规则通常遵循语义化版本控制(SemVer),这种版本控制系统以 MAJOR.MINOR.PATCH 的形式表示版本号。 知识点六:文件压缩与解压缩技术 ZIP是一种常用的文件压缩格式,它通过减少文件大小来提高存储效率和传输速度。ZIP文件通常是无损压缩,意味着文件在压缩和解压缩的过程中不会丢失信息。Python标准库提供了zipfile模块,允许用户在Python程序中创建ZIP文件、读取ZIP文件内容、提取ZIP文件中的文件等操作。用户可以使用各种图形界面工具(如WinRAR、7-Zip)或命令行工具来处理ZIP文件。 总结以上内容,从文件信息中我们可以得知该内容涉及了Python编程语言、系统管理知识、版本控制、打包与部署、命名规则以及文件压缩技术等多方面的知识点。这些知识点对于理解和应用Python进行系统管理软件开发以及软件的版本迭代、打包与部署均具有重要意义。
recommend-type

深入解析PCB走线传输延时:关键因素与实用公式

# 1. PCB走线传输延时基础 在电子工程领域,尤其是在印刷电路板(PCB)设计中,走线传输延时是一个不可忽视的重要概念。传输延时主要指的是电信号通过PCB上的导电路径从源头传送到目的地所耗费的时间。本章将介绍PCB走线传输延时的基础知识点,为后续章节的深入探讨打下坚实的基础。 首先,了解什么是传输延时是至关重要的。简单来说,它反
recommend-type

gpio很弱是什么意思

<think>嗯,用户的问题是关于GPIO信号弱的概念及其影响。用户似乎对硬件或嵌入式系统有一定了解,但需要更深入的解释。从用户提到的"信号弱"来看,ta可能遇到了实际电路设计中的驱动能力问题,或者在学习GPIO原理时遇到了术语困惑。 用户引用了四篇资料,其中提到GPIO的模拟输入输出模式、施密特触发器的作用、上拉下拉电阻的配置,以及信号线串联电阻的作用。这些内容都与GPIO的驱动能力和信号质量相关。特别是引用[4]中提到的"信号线串联小电阻"和"低频电路不考虑反射",暗示用户可能正在处理实际电路中的信号完整性问题。 用户真正想知道的可能是:为什么我的GPIO输出无法正确驱动某个设备?或者
recommend-type

Python打造的Slaee管理系统升级版发布

标题中的“基于python的slaee管理系统”表明这是一个使用Python编程语言开发的系统。Python是一种广泛使用的高级编程语言,以其易读性和简洁的语法而闻名。SLAEE管理系统可能是指一个特定类型的管理软件,但由于没有给出缩写的完整解释,我们可以假设SLAEE可能是某机构或系统名称的缩写。 从标题和描述来看,存在一处笔误:“基于python的slaee管理系统 (19).zip”和“基于python的slaee管理系统 (18).zip”所指的似乎是同一软件系统,只是版本号不同。根据文件名称列表中的两个文件名,可以推断系统至少有两个版本,一个是版本18,一个是版本19。通常情况下,版本号的增加表示软件进行了更新或改进。 接下来,根据这些信息,我们可以阐述一些相关的知识点: 1. Python编程基础:Python是一种解释型、面向对象、高级编程语言。Python支持多种编程范式,包括过程式、面向对象和函数式编程。Python由于其简洁和易于学习的特性,被广泛应用于网络开发、数据分析、人工智能、机器学习和科学计算等领域。 2. 文件压缩与打包:文件压缩是将文件的大小减小以节省存储空间或网络传输时间的技术。常见的文件压缩格式包括ZIP、RAR、7Z等。文件打包通常指的是将多个文件或文件夹压缩成一个单独的文件。这在数据备份、软件分发和档案管理中非常常见。 3. 版本控制:在软件开发中,“版本”通常指软件的特定状态,版本号则用来标识这些状态。版本控制是一种记录文件、目录或集合随着时间变化的方式,以便将来可以检索特定版本。对于软件项目来说,版本控制是至关重要的,它不仅允许开发者追踪和管理代码的变化,而且还能帮助团队协作,解决冲突,并回滚到旧版本。 4. 软件管理系统的开发:一个软件管理系统可能是针对特定业务领域而设计的,它可能包括用户界面、数据库管理、业务逻辑处理、报告生成和其他许多功能。软件管理系统的开发通常涉及需求分析、系统设计、编程、测试和维护等多个阶段。 5. Python在软件开发中的应用:Python因为具有丰富的库和框架,被广泛用于开发各种类型的软件。例如,Django和Flask是用于Web开发的流行Python框架;而对于数据分析和数据科学任务,Pandas、NumPy和Matplotlib等库提供了强大的数据处理和可视化工具;对于机器学习和人工智能,TensorFlow、PyTorch等库使得复杂算法的实现变得更为简单。 6. 系统更新与维护:随着软件的使用和发展,需求可能会变化,新的问题可能会出现,所以软件系统需要定期进行更新和维护。软件更新可能包括修复已知问题、改进现有功能、增加新功能或优化性能。开发者需要评估是否需要为修复安全漏洞或提高系统性能而更新系统,以及更新之后对用户体验的影响。 由于文件名中只提到了“基于python的slaee管理系统”,没有提供该系统具体功能的详细描述,我们无法提供更加具体的技术知识点。如果需要分析系统的工作原理或具体的技术实现细节,还需要更多的信息。
recommend-type

【Keil-ARM编程艺术】:如何编写可维护且高效的代码

# 摘要 本文旨在为读者提供ARM微控制器编程和Keil开发环境的全面指南。第一章概览了ARM微控制