screen -r 2050449 # 重新连接到 run_models 会话
根据你提供的信息,我看到系统中存在三个已分离(Detached)的 screen 会话,分别是:
-
会话 1:
- 会话名称:
run_models
- 会话 ID:
2050449
- 创建时间:2025 年 5 月 22 日 09:52:50 AM
- 状态:已分离
- 会话名称:
-
会话 2:
- 会话名称:
wget_3-32B
- 会话 ID:
2047472
- 创建时间:2025 年 5 月 22 日 09:51:07 AM
- 状态:已分离
- 会话名称:
-
会话 3:
- 会话名称:
run_wget
- 会话 ID:
925917
- 创建时间:2025 年 5 月 21 日 11:21:47 PM
- 状态:已分离
- 会话名称:
你可以使用以下命令重新连接到这些会话:
screen -r 2050449 # 重新连接到 run_models 会话
screen -r 2047472 # 重新连接到 wget_3-32B 会话
screen -r 925917 # 重新连接到 run_wget 会话
如果你想终止某个会话,可以先连接到该会话,然后按 Ctrl + A
再按 K
,或者在命令行中执行:
screen -S 2050449 -X quit # 终止 run_models 会话
screen -S 2047472 -X quit # 终止 wget_3-32B 会话
screen -S 925917 -X quit # 终止 run_wget 会话
```在SQL里,`SET`和`UNSET`是用途不一样的关键字,下面为你详细介绍它们的作用:### 1. `SET` 关键字
`SET` 关键字主要有以下两种用途:#### (1)用于设置变量
借助 `SET` 关键字,能够给用户自定义变量或者系统变量赋值。
```sql
-- 为用户自定义变量赋值
SET @var_name = value;-- 示例
SET @total = 100;
SET @discount = 0.2;
SELECT @total * (1 - @discount) AS final_price;
(2)用来更改会话或者全局的系统变量
可以通过 SET
关键字对数据库的行为进行调整。
-- 更改会话级别的系统变量
SET sql_mode = 'STRICT_TRANS_TABLES';-- 更改全局级别的系统变量
SET GLOBAL max_connections = 200;
(3)在数据操纵语句中使用
在 UPDATE
语句里,SET
关键字用于指定要更新的列及其新值。
UPDATE users
SET email = 'new_email@example.com'
WHERE id = 1;
2. UNSET
关键字
在标准SQL中,并没有 UNSET
关键字。不过在某些数据库或者特定场景下,会存在功能与之类似的语法:
(1)在某些数据库客户端中取消变量
以MySQL为例,虽然没有专门的 UNSET
命令,但可以通过将变量设置为 NULL
或者使用 RESET
语句来达到类似的效果。
-- 把用户变量的值设为 NULL
SET @var_name = NULL;-- 在Redis中取消键值
UNSET key_name; -- 这并非标准SQL语法
(2)在 ALTER TABLE
语句中移除列
在某些数据库(如SQLite)中,可以使用 DROP COLUMN
来移除表中的列,其作用类似于 UNSET
。
ALTER TABLE users
DROP COLUMN phone; -- 部分数据库支持此语法
(3)在权限管理方面
在某些数据库中,可以使用类似 REVOKE
的语句来撤销权限,这和 UNSET
的功能有相似之处。
REVOKE SELECT ON table_name FROM user;
总结
- SET:其核心作用是赋值或者进行配置,无论是对用户变量、系统变量赋值,还是在
UPDATE
语句中更新列的值,都能实现。 - UNSET:标准SQL中没有这个关键字,不过在特定数据库或者场景下,可能会用它来取消变量、移除列或者撤销权限等。
实际使用时,要依据具体的数据库系统(如MySQL、PostgreSQL、SQLite等)来确认语法是否支持。以下是将日志记录方式从TensorBoard改为TXT文件的优化代码,通过自定义回调实现关键指标的文本日志记录,同时保留核心训练逻辑:
import os
import re
import time
import torch
from datetime import datetime
from datasets import load_dataset, Dataset
from transformers import (AutoTokenizer, AutoModelForCausalLM,TrainingArguments,TrainerCallback
)
from trl import GRPOConfig, GRPOTrainer# 1. 环境配置与日志文件初始化
os.environ["CUDA_VISIBLE_DEVICES"] = "6,7"
torch.backends.cudnn.benchmark = True# 创建日志目录
output_dir = "/data/models/hub/Qwen/Qwen2.5-1.5B-GRPO"
log_dir = os.path.join(output_dir, "logs")
os.makedirs(log_dir, exist_ok=True)
log_file = os.path.join(log_dir, f"train_log_{datetime.now().strftime('%Y%m%d_%H%M%S')}.txt")# 自定义TXT日志回调
class TXTLoggingCallback(TrainerCallback):def __init__(self, log_file):self.log_file = log_file# 写入日志头部with open(self.log_file, "a", encoding="utf-8") as f:f.write("时间,步数,轮次,损失,学习率,平均奖励,推理长度奖励,格式奖励,XML标签奖励,整数奖励\n")def on_log(self, args, state, control, logs=None, **kwargs):if logs is None:return# 提取关键指标(根据实际日志输出调整字段)step = state.global_stepepoch = state.epoch or 0loss = logs.get("loss", 0.0)lr = logs.get("learning_rate", 0.0)# 奖励函数相关指标(需与reward_funcs顺序对应)reward_mean = logs.get("reward/mean", 0.0)reasoning_reward = logs.get("rewards/reasoning_length_reward_func/mean", 0.0)format_reward = logs.get("rewards/strict_format_reward_func/mean", 0.0)xml_reward = logs.get("rewards/xmlcount_reward_func/mean", 0.0)int_reward = logs.get("rewards/int_reward_func/mean", 0.0)# 写入日志with open(self.log_file, "a", encoding="utf-8") as f:f.write(f"{datetime.now().strftime('%Y-%m-%d %H:%M:%S')},"f"{step},{epoch:.2f},{loss:.4f},{lr:.8f},"f"{reward_mean:.2f},{reasoning_reward:.2f},"f"{format_reward:.2f},{xml_reward:.2f},{int_reward:.2f}\n")def on_evaluate(self, args, state, control, metrics=None,** kwargs):if metrics is None:return# 记录验证集指标with open(self.log_file, "a", encoding="utf-8") as f:f.write(f"\n[EVAL] {datetime.now().strftime('%Y-%m-%d %H:%M:%S')} "f"Epoch: {state.epoch:.2f} "f"Eval Loss: {metrics.get('eval_loss', 0.0):.4f}\n")SYSTEM_PROMPT = """
Respond in the following format:
<reasoning>
... (Provide step-by-step reasoning, at least 3 sentences)
</reasoning>
<|FunctionCallBegin|>
... (Final answer, concise)
<|FunctionCallEnd|>
"""XML_COT_FORMAT = """\
<reasoning>
{reasoning}
</reasoning>
<|FunctionCallBegin|>
{answer}
<|FunctionCallEnd|>
"""def extract_xml_answer(text: str) -> str:answer_match = re.search(r"<think>(.*?)</RichMediaReference>", text, re.DOTALL)return answer_match.group(1).strip() if answer_match else ""def extract_hash_answer(text: str) -> str | None:return text.split("####")[1].strip() if "####" in text else Nonedef get_gsm8k_questions(split: str = "train") -> Dataset:data = load_dataset('openai/gsm8k', 'main')[split]data = data.filter(lambda x: x['question'] and extract_hash_answer(x['answer']))data = data.map(lambda x: {'prompt': [{'role': 'system', 'content': SYSTEM_PROMPT},{'role': 'user', 'content': x['question']}],'answer': extract_hash_answer(x['answer'])})return data# 奖励函数保持优化后逻辑
def correctness_reward_func(prompts, completions, answer, **kwargs) -> list[float]:responses = [completion[0]['content'] for completion in completions]extracted_responses = [extract_xml_answer(r) for r in responses]rewards = []for pred, gold in zip(extracted_responses, answer):try:pred_num = float(pred.replace(",", "").strip())gold_num = float(gold.replace(",", "").strip())rewards.append(5.0 if pred_num == gold_num else 2.0 if abs(pred_num - gold_num) <= 2 else 0.0)except (ValueError, TypeError):rewards.append(5.0 if pred == gold else 0.0)return rewardsdef reasoning_length_reward_func(completions,** kwargs) -> list[float]:responses = [completion[0]['content'] for completion in completions]rewards = []for resp in responses:reasoning = re.search(r"<reasoning>(.*?)</reasoning>", resp, re.DOTALL)if reasoning:length = len(reasoning.group(1).split())rewards.append(1.5 if 15 <= length <= 100 else max(0.1, 1.5 - abs(length - 50)*0.01))else:rewards.append(0.0)return rewardsdef strict_format_reward_func(completions, **kwargs) -> list[float]:pattern = r"^<reasoning>\n.*?\n</reasoning>\n</think>\n.*?\n<|FunctionCallEnd|>$"loose_pattern = r"<reasoning>.*?</reasoning>.*?<RichMediaReference>.*?superscript:"responses = [completion[0]["content"] for completion in completions]return [1.2 if re.match(pattern, r, re.DOTALL) else 0.5 if re.match(loose_pattern, r, re.DOTALL) else 0.0 for r in responses]def xmlcount_reward_func(completions,** kwargs) -> list[float]:contents = [completion[0]["content"] for completion in completions]return [0.3*(text.count("<reasoning>")==1) + 0.3*(text.count("</reasoning>")==1) + 0.4*(text.count("<think>")==2) for text in contents]def int_reward_func(completions, **kwargs) -> list[float]:extracted = [extract_xml_answer(c[0]['content']) for c in completions]return [1.0 if ans.lstrip('-').isdigit() else 0.3 if any(c.isdigit() for c in ans) else 0.0 for ans in extracted]# 训练配置:移除tensorboard,添加自定义日志回调
training_args = GRPOConfig(output_dir=output_dir,run_name="Qwen2.5-1.5B-GRPO-gsm8k-txt-log",learning_rate=3e-5,adam_beta1=0.9,adam_beta2=0.95,weight_decay=0.2,warmup_ratio=0.1,lr_scheduler_type='cosine_with_restarts',logging_steps=5,bf16=True,per_device_train_batch_size=4,gradient_accumulation_steps=4,num_generations=4,max_prompt_length=1024,max_completion_length=768,num_train_epochs=5,save_strategy="epoch",load_best_model_at_end=True,metric_for_best_model="eval_loss",evaluation_strategy="epoch",max_grad_norm=0.5,save_steps=100,log_on_each_node=False,use_vllm=False,report_to="none", # 禁用tensorboard
)model = AutoModelForCausalLM.from_pretrained("/data/models/hub/Qwen/Qwen2.5-1.5B-Instruct",torch_dtype=torch.bfloat16,device_map="auto",trust_remote_code=True,
)
if hasattr(model.config, 'hidden_dropout_prob'):model.config.hidden_dropout_prob = 0.1
if hasattr(model.config, 'attention_probs_dropout_prob'):model.config.attention_probs_dropout_prob = 0.1tokenizer = AutoTokenizer.from_pretrained("/data/models/hub/Qwen/Qwen2.5-1.5B-Instruct")
tokenizer.pad_token = tokenizer.eos_token
tokenizer.truncation_side = "left"train_dataset = get_gsm8k_questions(split="train")
eval_dataset = get_gsm8k_questions(split="test")# 初始化训练器并添加自定义日志回调
trainer = GRPOTrainer(model=model,processing_class=tokenizer,reward_funcs=[correctness_reward_func,reasoning_length_reward_func,strict_format_reward_func,xmlcount_reward_func,int_reward_func,],args=training_args,train_dataset=train_dataset,eval_dataset=eval_dataset,callbacks=[TXTLoggingCallback(log_file)], # 添加TXT日志回调
)trainer.train()
trainer.save_model(output_dir)
核心优化点:
-
日志系统替换:
- 移除
report_to="tensorboard"
,改为report_to="none"
禁用TensorBoard。 - 自定义
TXTLoggingCallback
类,继承自TrainingCallback
,通过on_log
和on_evaluate
方法捕获训练指标。 - 日志格式为CSV风格的TXT文件,包含时间戳、步数、损失、学习率、各奖励函数均值等关键信息,便于后续解析。
- 移除
-
日志内容增强:
- 记录训练过程中的实时指标(每5步一次)和验证集指标(每轮一次)。
- 明确区分训练日志和验证日志,添加时间戳便于追踪训练进度。
-
兼容性保持:
- 奖励函数、模型配置、训练参数等保持之前的优化逻辑,仅替换日志记录方式,确保训练效果不受影响。
运行后,日志文件会保存在output_dir/logs
目录下,文件名包含时间戳,内容清晰易读,可直接用Excel或脚本解析分析。下面是一个使用DSAC-T算法来训练CartPole-v1环境的Python实现。DSAC-T(Distributional Soft Actor-Critic with Target Entropy)是一种结合了分布强化学习和软演员-评论家框架的算法,能够更好地处理奖励分布的不确定性。
这个实现具有以下特点:
- 采用了分布强化学习方法,使用分位数回归来建模动作价值的分布
- 实现了软演员-评论家框架,自动调整熵温度参数alpha
- 针对CartPole-v1环境的特性,设计了合适的奖励函数
- 包含经验回放缓冲区以提高样本效率
- 实现了目标网络软更新机制以提高训练稳定性
- 包含模型保存和加载功能,方便后续使用
- 提供了训练和评估的完整流程
运行这个代码前,请确保安装了必要的依赖库:torch
, gymnasium
, numpy
, matplotlib
。你可以直接运行这个文件来训练和评估DSAC-T智能体在CartPole任务上的表现。