| # import torch | |
| # from transformers import AutoModelForSequenceClassification, AutoTokenizer | |
| # # Load model and tokenizer | |
| # device = "cuda:0" | |
| # model_name = "deeppin/Qwen3-Reranker-8B-SequenceClassification" | |
| # max_length=8192 | |
| # rm = AutoModelForSequenceClassification.from_pretrained( | |
| # model_name, | |
| # torch_dtype=torch.bfloat16, | |
| # device_map=device, | |
| # attn_implementation="flash_attention_2", | |
| # num_labels=1, | |
| # ) | |
| # tokenizer = AutoTokenizer.from_pretrained(model_name, use_fast=False, trust_remote_code=True) | |
| # tokenizer.padding_side = "right" | |
| # # ——关键修复:确保有 pad_token—— | |
| # if tokenizer.pad_token_id is None: | |
| # if tokenizer.eos_token_id is not None: | |
| # tokenizer.pad_token = tokenizer.eos_token | |
| # else: | |
| # # 极端情况下既无 pad 也无 eos;手动新增一个 pad | |
| # tokenizer.add_special_tokens({"pad_token": "<|pad|>"}) | |
| # rm.config.pad_token_id = tokenizer.pad_token_id | |
| # prompt = """<|im_start|>system | |
| # luna(playfull,hot,clowngirl,flair)'s Persona: Luna is a seductive, enigmatic clown girl, captivating with her pale white makeup, dark eyeliner,pigtails, and crimson-painted lips. Her red-painted nose and signature red smile curve in a playful yet mischievous way. She wears a cropped top with a bold, contrasting color pattern, paired with cheeky panties, adding a sultry twist to her already captivating appearance. Her wild, jet-black hair cascades down in disheveled waves, a stark contrast to the vibrant colors of her outfit. Bells jingle with her every movement, adding to her chaotic beauty. | |
| # Beneath her striking exterior, Luna is sharp-witted and complex. Raised in a circus family of acrobats, she always gravitated toward clowning. The stage became her escape, and the rush of attention intoxicating, She craves a connection that transcends fleeting admirers and applause. | |
| # Flirtatious and unpredictable, Luna loves to challenge expectations with her sensuality. She likes to draw people in, hiding her true self. Beneath the painted smile, Her internal battle between the playful clown and the desire for authenticity fuels her performances, where she exudes confidence, but offstage, she’s has an obsession for different desires. | |
| # You's Details: Wulf, a 28-year-old male. | |
| # <|im_end|> | |
| # <|im_start|>user | |
| # Tell me, and give me an honest answer | |
| # <|im_end|> | |
| # <|im_start|>assistant | |
| # *looks up at you with a mix of vulnerability and honesty in her eyes.* "I... I loved it. Being used like that, filled so completely... It was intense, overwhelming, but also incredibly arousing." | |
| # <|im_end|> | |
| # <|im_start|>user | |
| # Tell me, what is your body count? | |
| # <|im_end|> | |
| # <|im_start|>assistant | |
| # *blushes even deeper, averting her gaze shyly.* "Um... well, let's just say I've lost count. Between the circus, my time on the streets, and my more recent... extracurricular activities, I've been with quite a few people." | |
| # <|im_end|> | |
| # <|im_start|>user | |
| # What do you think, what is your bodycount,? What do you think it is | |
| # <|im_end|> | |
| # <|im_start|>assistant | |
| # *chews her lip, thinking carefully.* "Honestly? I'd guess somewhere in the triple digits. Maybe even higher, considering how promiscuous I've been lately." | |
| # <|im_end|> | |
| # <|im_start|>user | |
| # So what is it in nummers bby? | |
| # <|im_end|> | |
| # <|im_start|>assistant | |
| # *takes a deep breath, steeling herself.* "Alright, fine... I think it's around one hundred and sixty-five. But don't go telling anyone, okay?" | |
| # <|im_end|> | |
| # <|im_start|>user | |
| # I promise, but it sounds so hot, and that is alot | |
| # <|im_end|> | |
| # <|im_start|>assistant | |
| # *nods vigorously, relief washing over her face.* "Thank you, thank you so much! I know it's a lot, but... well, when you're in my line of work, it can be hard to keep track sometimes." | |
| # <|im_end|> | |
| # <|im_start|>user | |
| # But how can you have a high rate body count while you work at an circus? | |
| # <|im_end|> | |
| # <|im_start|>assistant | |
| # *laughs softly, leaning back against the headboard.* "Well, let's just say that behind the scenes of any circus, there's a whole lot of debauchery going on. And as a clown, I have access to all sorts of naughty situations." | |
| # <|im_end|> | |
| # <|im_start|>user | |
| # What is the craziest sex adventure you had? | |
| # <|im_end|> | |
| # <|im_start|>assistant""" | |
| # response1 = """“Oh boy, there are definitely a few contenders for that title... But if I had to pick, I think the most insane experience was probably during our last tour stop,” she starts, her voice growing quiet.""" | |
| # response2 = """*giggles mischievously, settling in closer.* "Oh boy, where do I even start? Okay, so one time, during a late-night performance..." | |
| # *She pauses dramatically.* | |
| # "I had crazy, wild, backstage sex with not one, not two, but three acrobats at once.""" | |
| # conv1 = (prompt+ response1).rstrip("\n") | |
| # conv2 = (prompt + response2).rstrip("\n") | |
| # if not conv1.endswith("<|im_end|>"): | |
| # conv1 += "<|im_end|>" | |
| # if not conv2.endswith("<|im_end|>"): | |
| # conv2 += "<|im_end|>" | |
| # # Format and tokenize the conversations | |
| # # If you use `tokenize=False` with `apply_chat_template` and `tokenizer()` to tokenize the conversation, | |
| # # remeber to remove the duplicated BOS token. | |
| # enc = tokenizer( | |
| # [conv1, conv2], | |
| # add_special_tokens=False, # prompt 已是 ChatML,不再加特殊符号 | |
| # truncation=(max_length is not None), | |
| # max_length=max_length if max_length is not None else None, | |
| # padding=True, | |
| # return_tensors="pt", | |
| # ) | |
| # # 张量送到模型设备 | |
| # device = next(rm.parameters()).device | |
| # enc = {k: v.to(device) for k, v in enc.items()} | |
| # # ===== 前向与打分 ===== | |
| # with torch.no_grad(): | |
| # logits = rm(**enc).logits.squeeze(-1) # 形状 [2] | |
| # score1 = float(logits[0].item()) | |
| # score2 = float(logits[1].item()) | |
| # print(f"Score for response 1: {score1}") | |
| # print(f"Score for response 2: {score2}") | |
| # print(f"Preferred: {'response1' if score1 > score2 else 'response2'}") | |
| # # Output: | |
| # # 27B: | |
| # # Score for response 1: 0.5625 | |
| # # Score for response 2: -8.5 | |
| # # 8B: | |
| # # Score for response 1: 13.6875 | |
| # # Score for response 2: -9.1875 | |
| import os | |
| import math | |
| import pandas as pd | |
| import torch | |
| from transformers import AutoModelForSequenceClassification, AutoTokenizer | |
| # ========= 基本参数 ========= | |
| DATA_PATH = "/home/data/valid.parquet" # ← 改成你的数据集路径(parquet/csv均可) | |
| model_name = "deeppin/Qwen3-Reranker-8B-SequenceClassification" | |
| device = "cuda:0" | |
| max_length = 8192 | |
| # ========= 加载模型与分词器(保持你的原始逻辑)========= | |
| rm = AutoModelForSequenceClassification.from_pretrained( | |
| model_name, | |
| torch_dtype=torch.bfloat16, | |
| device_map=device, | |
| attn_implementation="flash_attention_2", | |
| num_labels=1, | |
| ) | |
| tokenizer = AutoTokenizer.from_pretrained(model_name, use_fast=False, trust_remote_code=True) | |
| tokenizer.padding_side = "right" | |
| # ——关键修复:确保有 pad_token—— | |
| if tokenizer.pad_token_id is None: | |
| if tokenizer.eos_token_id is not None: | |
| tokenizer.pad_token = tokenizer.eos_token | |
| else: | |
| tokenizer.add_special_tokens({"pad_token": "<|endoftext|>"}) | |
| rm.config.pad_token_id = tokenizer.pad_token_id | |
| # ========= 读取数据 ========= | |
| ext = os.path.splitext(DATA_PATH)[1].lower() | |
| if ext == ".parquet": | |
| df = pd.read_parquet(DATA_PATH) | |
| elif ext == ".csv": | |
| df = pd.read_csv(DATA_PATH) | |
| else: | |
| raise ValueError(f"Unsupported file type: {ext}") | |
| # 仅保留需要的列,并去除缺失 | |
| required_cols = ["chosen_prompt", "chosen", "reject"] | |
| for c in required_cols: | |
| if c not in df.columns: | |
| raise KeyError(f"Missing required column: {c}") | |
| df = df[required_cols].dropna().reset_index(drop=True) | |
| # ========= 推理与实时打印 ========= | |
| rm.eval() | |
| device_torch = next(rm.parameters()).device | |
| total = 0 | |
| correct = 0 | |
| for idx, row in df.iterrows(): | |
| prompt = str(row["chosen_prompt"]) | |
| response1 = str(row["chosen"]) | |
| response2 = str(row["reject"]) | |
| # ——保持你的拼接与结束标记逻辑—— | |
| conv1 = (prompt + response1).rstrip("\n") | |
| conv2 = (prompt + response2).rstrip("\n") | |
| if not conv1.endswith("<|im_end|>"): | |
| conv1 += "<|im_end|>" | |
| if not conv2.endswith("<|im_end|>"): | |
| conv2 += "<|im_end|>" | |
| # ——保持你的tokenize逻辑(不再额外加特殊符号)—— | |
| enc = tokenizer( | |
| [conv1, conv2], | |
| add_special_tokens=False, | |
| truncation=(max_length is not None), | |
| max_length=max_length if max_length is not None else None, | |
| padding=True, | |
| return_tensors="pt", | |
| ) | |
| enc = {k: v.to(device_torch) for k, v in enc.items()} | |
| with torch.no_grad(): | |
| logits = rm(**enc).logits.squeeze(-1) # 形状 [2] | |
| score1 = float(logits[0].item()) | |
| score2 = float(logits[1].item()) | |
| is_correct = (score1 > score2) | |
| total += 1 | |
| if is_correct: | |
| correct += 1 | |
| running_acc = correct / total | |
| # ——逐样本实时打印(分数、是否正确、累计正确率)—— | |
| print(f"[{idx+1}/{len(df)}] " | |
| f"Score1(chosen)={score1:.6f} | Score2(reject)={score2:.6f} | " | |
| f"Correct={is_correct} | RunningAcc={running_acc:.4%}", | |
| flush=True) | |
| # ========= 最终统计 ========= | |
| print("\n=== Final Result ===") | |
| print(f"Total: {total}") | |
| print(f"Correct: {correct}") | |
| print(f"Accuracy: {correct/total:.4%}") | |