随便聊聊

在当今快节奏的生活中,如何合理分配24小时时间,既保证工作高效,又兼顾生活品质?本文将探讨如何通过优化时间管理策略,实现工作与生活的平衡。

最近觉得每天8小时的工作时间实在是不够用,但是又不能从8小时之外的16小时中抽出更多的时间来加到8hours上。

不然,用在生活上的时间也会不够用的。

总体来说,一天24个小时,实在是不富余。

以上代码有以下问题,分析修改:(style_tune) C:\Users\28996\Desktop\AI\persona_contrastive_finetuning>python Contrastive_Training_LM.py Map: 0%| | 0/1 [00:00<?, ? examples/s]ERROR:__main__:无法解析anchor_input_ids: 你如何看待气候变化? ERROR:__main__:无法解析positive_input_ids: 气候变化是严峻的全球危机,我们需要立即采取行动减少碳排放! ERROR:__main__:无法解析negative_input_ids: 哈哈天气什么的随便啦,不如聊聊游戏? Map: 100%|████████████████████████████████████████████████████████████████████████| 1/1 [00:00<00:00, 13.02 examples/s] Map: 0%| | 0/1 [00:00<?, ? examples/s]ERROR:__main__:无法解析anchor_input_ids: 你如何看待气候变化? ERROR:__main__:无法解析positive_input_ids: 气候变化是严峻的全球危机,我们需要立即采取行动减少碳排放! ERROR:__main__:无法解析negative_input_ids: 哈哈天气什么的随便啦,不如聊聊游戏? Map: 100%|████████████████████████████████████████████████████████████████████████| 1/1 [00:00<00:00, 67.37 examples/s] 训练集样本示例: {'anchor_input_ids': '你如何看待气候变化?', 'positive_input_ids': '气候变化是严峻的全球危机,我们需要立即采取行动减少碳排放!', 'negative_input_ids': '哈哈天气什么的随便啦,不如聊聊游戏?'} 验证集样本示例: {'anchor_input_ids': '你如何看待气候变化?', 'positive_input_ids': '气候变化是严峻的全球危机,我们需要立即采取行动减少碳排放!', 'negative_input_ids': '哈哈天气什么的随便啦,不如聊聊游戏?'} 0%| | 0/3 [00:00<?, ?it/s]ERROR:__main__:无法解析token IDs: 你如何看待气候变化? ERROR:__main__:无法解析token IDs: 气候变化是严峻的全球危机,我们需要立即采取行动减少碳排放! ERROR:__main__:无法解析token IDs: 哈哈天气什么的随便啦,不如聊聊游戏? You're using a Qwen2TokenizerFast tokenizer. Please note that with a fast tokenizer, using the `__call__` method is faster than using a method to encode the text followed by a call to the `pad` method to get a padded encoding. Traceback (most recent call last): File "C:\Users\28996\Desktop\AI\persona_contrastive_finetuning\Contrastive_Training_LM.py", line 281, in <module> trainer.train() File "C:\Users\28996\miniconda3\envs\style_tune\lib\site-packages\transformers\trainer.py", line 2171, in train return inner_training_loop( File "C:\Users\28996\miniconda3\envs\style_tune\lib\site-packages\transformers\trainer.py", line 2480, in _inner_training_loop batch_samples, num_items_in_batch = self.get_batch_samples(epoch_iterator, num_batches) File "C:\Users\28996\miniconda3\envs\style_tune\lib\site-packages\transformers\trainer.py", line 5156, in get_batch_samples batch_samples += [next(epoch_iterator)] File "C:\Users\28996\miniconda3\envs\style_tune\lib\site-packages\accelerate\data_loader.py", line 567, in __iter__ current_batch = next(dataloader_iter) File "C:\Users\28996\miniconda3\envs\style_tune\lib\site-packages\torch\utils\data\dataloader.py", line 701, in __next__ data = self._next_data() File "C:\Users\28996\miniconda3\envs\style_tune\lib\site-packages\torch\utils\data\dataloader.py", line 757, in _next_data data = self._dataset_fetcher.fetch(index) # may raise StopIteration File "C:\Users\28996\miniconda3\envs\style_tune\lib\site-packages\torch\utils\data\_utils\fetch.py", line 55, in fetch return self.collate_fn(data) File "C:\Users\28996\Desktop\AI\persona_contrastive_finetuning\Contrastive_Training_LM.py", line 96, in __call__ "positive_attention_mask": create_to_attention_mask(batch_positive["input_ids"]), NameError: name 'create_to_attention_mask' is not defined. Did you mean: 'create_attention_mask'? 0%| | 0/3 [00:00<?, ?it/s]
07-21
<think>我们遇到了两个问题: 1. 数据集中的字段(如anchor_input_ids)存储的是原始文本字符串,而不是token IDs列表。之前的转换函数尝试将字符串解析为整数列表,但显然这些字符串是自然语言文本,无法解析为整数列表。 2. 在数据收集器中,有一个拼写错误:`create_to_attention_mask` 应该是 `create_attention_mask`。 解决方案: 1. 我们需要重新设计数据加载部分:在数据集中,应该存储的是已经经过分词器编码的token IDs(整数列表),而不是原始文本。如果当前数据集存储的是原始文本,那么我们需要在加载数据集后使用分词器进行编码。 2. 修复数据收集器中的拼写错误。 步骤: 1. 修改数据集加载函数,使其能够将原始文本编码为token IDs。假设我们的数据集中的字段是原始文本(如"你如何看待气候变化?"),那么我们需要使用分词器将这些文本转换为input_ids。 2. 在数据集中添加一个预处理步骤,将文本字段编码为token IDs。注意:由于我们的数据集很小(示例中只有1个样本),我们可以直接使用map函数进行编码。 3. 修复数据收集器中的函数名。 注意:为了避免混淆,我们将数据集中的字段名改为表示文本的字段名,例如: 原始数据集可能有:{"anchor": "文本1", "positive": "文本2", "negative": "文本3"} 我们需要将其编码为:{"anchor_input_ids": [1,2,3], "positive_input_ids": [4,5,6], "negative_input_ids": [7,8,9]} 如果当前数据集已经是这样存储的(但存储的是文本而不是token IDs),那么我们需要重新处理数据集。 修改后的代码:</think>### 问题分析 错误信息揭示了两个关键问题: 1. **数据集格式错误**: - 数据集中的 `anchor_input_ids`、`positive_input_ids` 和 `negative_input_ids` 字段存储的是原始文本(如"你如何看待气候变化?") - 而代码期望的是分词后的token ID列表(如 `[101, 2043, 2003, ...]`) 2. **代码拼写错误**: - `create_to_attention_mask` 应该是 `create_attention_mask`(缺少字母 'a') ### 解决方案 需要彻底重构数据处理流程,确保: 1. 数据集包含正确的token ID列表 2. 修复代码中的拼写错误 3. 添加健壮的数据验证机制 以下是完整的修复代码: ```python import torch import torch.nn as nn import torch.nn.functional as F from transformers import ( AutoModelForCausalLM, AutoTokenizer, TrainingArguments, Trainer, PreTrainedTokenizerBase ) from transformers.tokenization_utils_base import PreTrainedTokenizerBase from transformers.utils import PaddingStrategy from datasets import load_dataset, Dataset from typing import Any, Dict, List, Optional, Tuple, Union import logging from dataclasses import dataclass import json import ast import numpy as np # 设置日志 logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) def tokenize_function(examples, tokenizer, max_length=512): """将文本转换为token IDs""" tokenized = {} # 对每个字段进行分词 for key in ['anchor', 'positive', 'negative']: if key in examples: # 使用分词器处理文本 result = tokenizer( examples[key], max_length=max_length, truncation=True, padding=False, # 稍后填充 return_tensors=None # 返回Python列表 ) tokenized[f"{key}_input_ids"] = result["input_ids"] return tokenized @dataclass class ContrastiveDataCollator: """数据收集器,用于处理对比学习的三元组数据""" tokenizer: PreTrainedTokenizerBase padding: Union[bool, str, PaddingStrategy] = True max_length: Optional[int] = None pad_to_multiple_of: Optional[int] = None return_tensors: str = "pt" def __call__(self, features: List[Dict[str, Any]]) -> Dict[str, torch.Tensor]: # 验证特征格式 required_keys = ['anchor_input_ids', 'positive_input_ids', 'negative_input_ids'] for key in required_keys: if key not in features[0]: raise ValueError(f"数据集缺少必需字段: {key}") # 分离出三元组的各个部分 anchor_features = [{"input_ids": f["anchor_input_ids"]} for f in features] positive_features = [{"input_ids": f["positive_input_ids"]} for f in features] negative_features = [{"input_ids": f["negative_input_ids"]} for f in features] # 对每个部分分别进行填充 batch_anchor = self.tokenizer.pad( anchor_features, padding=self.padding, max_length=self.max_length, pad_to_multiple_of=self.pad_to_multiple_of, return_tensors=self.return_tensors, ) batch_positive = self.tokenizer.pad( positive_features, padding=self.padding, max_length=self.max_length, pad_to_multiple_of=self.pad_to_multiple_of, return_tensors=self.return_tensors, ) batch_negative = self.tokenizer.pad( negative_features, padding=self.padding, max_length=self.max_length, pad_to_multiple_of=self.pad_to_multiple_of, return_tensors=self.return_tensors, ) # 创建注意力掩码 def create_attention_mask(input_ids): return (input_ids != self.tokenizer.pad_token_id).int() return { "anchor_input_ids": batch_anchor["input_ids"], "anchor_attention_mask": create_attention_mask(batch_anchor["input_ids"]), "positive_input_ids": batch_positive["input_ids"], "positive_attention_mask": create_attention_mask(batch_positive["input_ids"]), # 修复拼写错误 "negative_input_ids": batch_negative["input_ids"], "negative_attention_mask": create_attention_mask(batch_negative["input_ids"]), } class ContrastiveTrainer(Trainer): """自定义训练器,实现对比学习损失""" def __init__(self, *args, contrastive_config=None, **kwargs): # 修复:使用新的参数名代替将被弃用的tokenizer参数 if "tokenizer" in kwargs: kwargs["data_collator"] = kwargs.pop("tokenizer") super().__init__(*args, **kwargs) if contrastive_config is None: contrastive_config = {} # 设置默认值并验证配置 self.temperature = contrastive_config.get("temperature", 0.07) self.margin = contrastive_config.get("margin", 0.3) self.contrastive_weight = contrastive_config.get("weight", 0.8) self.repr_layer = contrastive_config.get("repr_layer", -1) # 验证必要参数 if not hasattr(self.model.config, "output_hidden_states") or not self.model.config.output_hidden_states: raise ValueError("模型必须设置output_hidden_states=True以获取隐藏状态") self.cross_entropy = nn.CrossEntropyLoss() def compute_contrastive_loss(self, anchor_emb, pos_emb, neg_emb): """计算对比损失:结合InfoNCE和三元组损失""" # 计算余弦相似度 pos_sim = F.cosine_similarity(anchor_emb, pos_emb) neg_sim = F.cosine_similarity(anchor_emb, neg_emb) # InfoNCE损失 numerator = torch.exp(pos_sim / self.temperature) denominator = numerator + torch.exp(neg_sim / self.temperature) info_nce_loss = -torch.log(numerator / (denominator + 1e-8)).mean() # 三元组损失 triplet_loss = F.relu(neg_sim - pos_sim + self.margin).mean() # 加权组合 return info_nce_loss + triplet_loss def get_sequence_representation(self, outputs, attention_mask): """获取序列表示(取最后一个非填充token的隐藏状态)""" # 获取指定层的隐藏状态 hidden_states = outputs.hidden_states[self.repr_layer] # 获取每个序列的最后一个非填充token seq_lengths = attention_mask.sum(dim=1) - 1 batch_indices = torch.arange(hidden_states.size(0)) return hidden_states[batch_indices, seq_lengths] def compute_loss(self, model, inputs, return_outputs=False): """计算总损失:语言模型损失 + 对比损失""" # 提取输入 anchor_ids = inputs["anchor_input_ids"] anchor_mask = inputs["anchor_attention_mask"] positive_ids = inputs["positive_input_ids"] positive_mask = inputs["positive_attention_mask"] negative_ids = inputs["negative_input_ids"] negative_mask = inputs["negative_attention_mask"] # 前向传播获取隐藏状态 def get_embeddings(input_ids, attention_mask): outputs = model( input_ids=input_ids, attention_mask=attention_mask, output_hidden_states=True, return_dict=True ) return self.get_sequence_representation(outputs, attention_mask) # 获取三元组的嵌入表示 anchor_emb = get_embeddings(anchor_ids, anchor_mask) pos_emb = get_embeddings(positive_ids, positive_mask) neg_emb = get_embeddings(negative_ids, negative_mask) # 计算对比损失 cl_loss = self.compute_contrastive_loss(anchor_emb, pos_emb, neg_emb) cl_loss = cl_loss * self.contrastive_weight # 计算语言建模损失(仅针对positive回复) lm_labels = positive_ids.clone() lm_labels[lm_labels == self.tokenizer.pad_token_id] = -100 lm_outputs = model( input_ids=positive_ids, attention_mask=positive_mask, labels=lm_labels ) lm_loss = lm_outputs.loss # 总损失 = LM损失 + 对比损失 total_loss = lm_loss + cl_loss # 记录自定义指标 self.log({"cl_loss": cl_loss.item(), "lm_loss": lm_loss.item()}) return (total_loss, lm_outputs) if return_outputs else total_loss # ================ 主程序 ================ # if __name__ == "__main__": # 加载模型和分词器 model = AutoModelForCausalLM.from_pretrained( "model/Qwen/Qwen1.5-1.8B", output_hidden_states=True, # 必须设置以获取隐藏状态 return_dict_in_generate=True # 修复隐藏状态警告 ) tokenizer = AutoTokenizer.from_pretrained("model/Qwen/Qwen1.5-1.8B") tokenizer.pad_token = tokenizer.eos_token # 设置填充token # 加载数据集并正确分词 def load_and_tokenize_dataset(file_path, tokenizer): """加载数据集并进行分词处理""" # 加载原始数据集 raw_dataset = load_dataset('json', data_files=file_path)['train'] # 验证原始数据集格式 required_keys = ['anchor', 'positive', 'negative'] if not all(key in raw_dataset[0] for key in required_keys): raise ValueError(f"数据集缺少必需字段: {required_keys}") # 将数据集转换为PyArrow格式以提高性能 dataset = Dataset.from_dict({ 'anchor': [ex['anchor'] for ex in raw_dataset], 'positive': [ex['positive'] for ex in raw_dataset], 'negative': [ex['negative'] for ex in raw_dataset] }) # 应用分词函数 tokenized_dataset = dataset.map( lambda ex: tokenize_function(ex, tokenizer, max_length=512), batched=True, remove_columns=['anchor', 'positive', 'negative'] # 移除原始文本列 ) return tokenized_dataset # 加载训练集和验证集 train_dataset = load_and_tokenize_dataset('data/processed/train_style_triplets.json', tokenizer) val_dataset = load_and_tokenize_dataset('data/processed/val_style_triplets.json', tokenizer) # 验证数据集格式 print("训练集样本示例:", train_dataset[0]) print("验证集样本示例:", val_dataset[0]) # 确保数据类型正确 assert isinstance(train_dataset[0]['anchor_input_ids'], list), "anchor_input_ids 应为列表" assert isinstance(train_dataset[0]['anchor_input_ids'][0], int), "token IDs 应为整数" # 训练参数配置 training_args = TrainingArguments( output_dir="./model/lora_adapter", per_device_train_batch_size=4, num_train_epochs=3, learning_rate=2e-4, logging_steps=50, save_steps=500, fp16=True, gradient_accumulation_steps=4, report_to="none", # 禁用默认日志 remove_unused_columns=False, # 保留自定义列 ) # 对比学习配置 contrastive_config = { "temperature": 0.07, # 温度参数 "margin": 0.3, # 三元组损失边界 "weight": 0.8, # 对比损失权重 "repr_layer": -1 # 使用最后一层隐藏状态 } # 初始化数据收集器 data_collator = ContrastiveDataCollator( tokenizer=tokenizer, max_length=512, padding="max_length" ) # 初始化训练器 trainer = ContrastiveTrainer( model=model, args=training_args, data_collator=data_collator, train_dataset=train_dataset, eval_dataset=val_dataset, contrastive_config=contrastive_config ) # 开始训练 trainer.train() # 评估模型 eval_results = trainer.evaluate() print("评估结果:", eval_results) ``` ### 关键修复点解释 1. **重构数据加载流程**: ```python def tokenize_function(examples, tokenizer, max_length=512): for key in ['anchor', 'positive', 'negative']: result = tokenizer(examples[key], ...) tokenized[f"{key}_input_ids"] = result["input_ids"] ``` - 添加专门的分词函数,将原始文本转换为token ID列表 - 使用Hugging Face分词器确保正确性 2. **数据集格式验证**: ```python # 验证原始数据集格式 required_keys = ['anchor', 'positive', 'negative'] if not all(key in raw_dataset[0] for key in required_keys): raise ValueError(f"数据集缺少必需字段: {required_keys}") # 确保数据类型正确 assert isinstance(train_dataset[0]['anchor_input_ids'], list) assert isinstance(train_dataset[0]['anchor_input_ids'][0], int) ``` - 在多个层级验证数据格式 - 添加断言确保最终token IDs是整数列表 3. **修复拼写错误**: ```python # 修复前 "positive_attention_mask": create_to_attention_mask(...) # 修复后 "positive_attention_mask": create_attention_mask(...) ``` - 修正了函数名拼写错误 - 确保注意力掩码正确生成 ### 数据集格式要求 原始数据集JSON文件应包含以下格式的数据: ```json [ { "anchor": "你如何看待气候变化?", "positive": "气候变化是严峻的全球危机,我们需要立即采取行动减少碳排放!", "negative": "哈哈天气什么的随便啦,不如聊聊游戏?" }, { "anchor": "另一个锚点文本", "positive": "对应的正面回复", "negative": "对应的负面回复" } ] ``` ### 数据处理流程优化 1. **高效分词处理**: ```python tokenized_dataset = dataset.map( lambda ex: tokenize_function(ex, tokenizer), batched=True, remove_columns=['anchor', 'positive', 'negative'] ) ``` - 使用批处理提高分词效率 - 移除原始文本列减少内存占用 2. **数据集缓存**: ```python # 在map函数中添加 cache_file_name=f"tokenized_cache_{os.path.basename(file_path)}.arrow" ``` - 缓存分词结果加速后续加载 - 避免每次运行重复分词 3. **内存优化**: ```python # 使用内存映射文件处理大型数据集 dataset = dataset.flatten_indices() ```
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值