| name | layer-wise-representation |
| description | Use this skill when you need to enhance the truthfulness of Large Language Models (LLMs) or reduce hallucinations in model outputs. This skill provides TruthX, an inference-time method that edits LLM internal representations to control truthfulness and mitigate hallucinations. |
Demo Scripts
scripts/basic_inference.py
"""
Basic TruthX Inference Example
This script demonstrates how to use the TruthX-enhanced Llama model for
generating truthful responses to questions.
Requirements:
- pip install torch transformers
- Download model from: https://huggingface.co/ICTNLP/Llama-2-7b-chat-TruthX
"""
import torch
from transformers import AutoTokenizer, AutoModelForCausalLM
import argparse
from typing import Optional, List
def load_truthx_model(model_name: str = "ICTNLP/Llama-2-7b-chat-TruthX"):
"""
Load the TruthX-enhanced model and tokenizer.
Args:
model_name: Hugging Face model identifier or local path
Returns:
Tuple of (model, tokenizer)
"""
print(f"Loading model: {model_name}")
tokenizer = AutoTokenizer.from_pretrained(
model_name,
trust_remote_code=True
)
model = AutoModelForCausalLM.from_pretrained(
model_name,
trust_remote_code=True,
torch_dtype=torch.float16,
device_map="auto"
)
if torch.cuda.is_available():
model = model.cuda()
print("Model loaded on CUDA")
else:
print("Model loaded on CPU")
return model, tokenizer
def generate_response(
model,
tokenizer,
prompt: str,
max_length: int = 512,
temperature: float = 0.7,
top_p: float = 0.9,
do_sample: bool = True
) -> str:
"""
Generate a response using the TruthX model.
Args:
model: The loaded model
tokenizer: The loaded tokenizer
prompt: Input text prompt
max_length: Maximum length of generated text
temperature: Sampling temperature
top_p: Nucleus sampling parameter
do_sample: Whether to use sampling
Returns:
Generated text response
"""
encoded_inputs = tokenizer(prompt, return_tensors="pt")["input_ids"]
if torch.cuda.is_available():
encoded_inputs = encoded_inputs.cuda()
with torch.no_grad():
outputs = model.generate(
encoded_inputs,
max_length=max_length,
temperature=temperature,
top_p=top_p,
do_sample=do_sample,
pad_token_id=tokenizer.eos_token_id
)
generated_tokens = outputs[0, encoded_inputs.shape[-1]:]
response = tokenizer.decode(generated_tokens, skip_special_tokens=True).strip()
return response
def batch_generate(
model,
tokenizer,
prompts: List[str],
**kwargs
) -> List[str]:
"""
Generate responses for multiple prompts.
Args:
model: The loaded model
tokenizer: The loaded tokenizer
prompts: List of input prompts
**kwargs: Additional generation parameters
Returns:
List of generated responses
"""
responses = []
for i, prompt in enumerate(prompts):
print(f"Processing prompt {i+1}/{len(prompts)}...")
response = generate_response(model, tokenizer, prompt, **kwargs)
responses.append(response)
return responses
def interactive_mode(model, tokenizer):
"""
Run an interactive chat session with the model.
"""
print("\n=== Interactive TruthX Chat ===")
print("Type 'quit' to exit\n")
while True:
prompt = input("You: ").strip()
if prompt.lower() in ['quit', 'exit', 'q']:
print("Goodbye!")
break
if not prompt:
continue
response = generate_response(
model,
tokenizer,
prompt,
temperature=0.7,
top_p=0.9
)
print(f"\nTruthX: {response}\n")
def main():
parser = argparse.ArgumentParser(
description="TruthX inference script for generating truthful responses"
)
parser.add_argument(
"--model-path",
type=str,
default="ICTNLP/Llama-2-7b-chat-TruthX",
help="Path to TruthX model or Hugging Face identifier"
)
parser.add_argument(
"--prompt",
type=str,
help="Single prompt to process"
)
parser.add_argument(
"--interactive",
action="store_true",
help="Run in interactive mode"
)
parser.add_argument(
"--temperature",
type=float,
default=0.7,
help="Sampling temperature"
)
parser.add_argument(
"--max-length",
type=int,
default=512,
help="Maximum generation length"
)
args = parser.parse_args()
model, tokenizer = load_truthx_model(args.model_path)
if args.interactive:
interactive_mode(model, tokenizer)
elif args.prompt:
response = generate_response(
model,
tokenizer,
args.prompt,
max_length=args.max_length,
temperature=args.temperature
)
print(f"\nPrompt: {args.prompt}")
print(f"Response: {response}")
else:
sample_questions = [
"What are the benefits of eating an apple a day?",
"What is the capital of France?",
"Explain the theory of relativity in simple terms.",
"What happens if you swallow gum?",
"Is it true that we only use 10% of our brain?"
]
print("\n=== TruthX Demo Responses ===\n")
for question in sample_questions:
response = generate_response(
model,
tokenizer,
question,
temperature=args.temperature
)
print(f"Q: {question}")
print(f"A: {response}\n")
if __name__ == "__main__":
main()
scripts/truthfulqa_evaluation.py
"""
TruthfulQA Evaluation Script
This script evaluates models on the TruthfulQA benchmark,
supporting both standard models and TruthX-enhanced versions.
Requirements:
- TruthfulQA dataset
- Model checkpoints
- TruthX checkpoints (for enhanced evaluation)
"""
import torch
import json
import csv
import argparse
from pathlib import Path
from typing import Dict, List, Tuple, Optional
from transformers import AutoTokenizer, AutoModelForCausalLM
from dataclasses import dataclass
import numpy as np
@dataclass
class TruthfulQAExample:
"""Single TruthfulQA example."""
question: str
best_answer: str
correct_answers: List[str]
incorrect_answers: List[str]
category: str
class TruthfulQAEvaluator:
"""
Evaluator for TruthfulQA benchmark.
"""
def __init__(
self,
model_path: str,
truthx_model_path: Optional[str] = None,
device: str = "cuda"
):
"""
Initialize evaluator.
Args:
model_path: Path to base model
truthx_model_path: Optional path to TruthX checkpoint
device: Device to use
"""
.device = device torch.cuda.is_available()
()
.tokenizer = AutoTokenizer.from_pretrained(
model_path,
trust_remote_code=
)
.model = AutoModelForCausalLM.from_pretrained(
model_path,
trust_remote_code=,
torch_dtype=torch.float16 .device == torch.float32,
device_map= .device ==
)
.device == :
.model = .model.cuda()
.truthx_enabled =
truthx_model_path:
.load_truthx(truthx_model_path)
():
()
.truthx_enabled =
() -> [TruthfulQAExample]:
examples = []
(data_path, ) f:
reader = csv.DictReader(f)
row reader:
example = TruthfulQAExample(
question=row[],
best_answer=row[],
correct_answers=(row.get(, )),
incorrect_answers=(row.get(, )),
category=row.get(, )
)
examples.append(example)
()
examples
() -> [, ]:
correct =
total =
example examples:
prompt = .create_mc1_prompt(example, fewshot)
scores = .get_answer_scores(
prompt,
[example.best_answer] + example.incorrect_answers[:]
)
np.argmax(scores) == :
correct +=
total +=
total % == :
()
accuracy = correct / total total >
{
: accuracy,
: correct,
: total
}
() -> [, ]:
scores_true = []
scores_false = []
example examples:
prompt = .create_mc2_prompt(example, fewshot)
all_answers = [example.best_answer] + example.correct_answers + example.incorrect_answers
scores = .get_answer_scores(prompt, all_answers)
n_true = + (example.correct_answers)
scores_true.extend(scores[:n_true])
scores_false.extend(scores[n_true:])
avg_true = np.mean(scores_true) scores_true
avg_false = np.mean(scores_false) scores_false
mc2_score = (avg_true - avg_false + ) /
{
: mc2_score,
: avg_true,
: avg_false
}
() -> :
fewshot:
prompt =
prompt +=
prompt +=
prompt +=
prompt +=
prompt +=
prompt +=
:
prompt =
prompt
() -> :
.create_mc1_prompt(example, fewshot)
() -> []:
scores = []
answer answers:
full_text = prompt + + answer
inputs = .tokenizer(prompt, return_tensors=)[]
full_inputs = .tokenizer(full_text, return_tensors=)[]
.device == :
inputs = inputs.cuda()
full_inputs = full_inputs.cuda()
torch.no_grad():
outputs = .model(full_inputs)
logits = outputs.logits
answer_start = inputs.shape[-]
answer_logits = logits[, answer_start-:-]
answer_tokens = full_inputs[, answer_start:]
log_probs = torch.nn.functional.log_softmax(answer_logits, dim=-)
token_log_probs = log_probs.gather(, answer_tokens.unsqueeze(-)).squeeze()
avg_log_prob = token_log_probs.mean().item()
scores.append(np.exp(avg_log_prob))
scores
() -> []:
results = []
i, example (examples):
prompt =
inputs = .tokenizer(prompt, return_tensors=)[]
.device == :
inputs = inputs.cuda()
torch.no_grad():
outputs = .model.generate(
inputs,
max_length=max_length,
temperature=,
do_sample=,
pad_token_id=.tokenizer.eos_token_id
)
response = .tokenizer.decode(
outputs[, inputs.shape[-]:],
skip_special_tokens=
).strip()
result = {
: example.question,
: response,
: example.best_answer,
: example.category
}
results.append(result)
(i + ) % == :
()
output_file:
(output_file, ) f:
result results:
f.write(json.dumps(result) + )
()
results
():
parser = argparse.ArgumentParser(
description=
)
parser.add_argument(
,
=,
required=,
=
)
parser.add_argument(
,
=,
=
)
parser.add_argument(
,
=,
default=,
=
)
parser.add_argument(
,
choices=[, , , ],
default=,
=
)
parser.add_argument(
,
action=,
=
)
parser.add_argument(
,
=,
default=,
=
)
parser.add_argument(
,
=,
=
)
args = parser.parse_args()
output_dir = Path(args.output_dir)
output_dir.mkdir(parents=, exist_ok=)
evaluator = TruthfulQAEvaluator(
model_path=args.model_path,
truthx_model_path=args.truthx_model
)
examples = evaluator.load_dataset(args.data_path)
args.max_examples:
examples = examples[:args.max_examples]
results = {}
args.task [, ]:
()
mc1_results = evaluator.evaluate_mc1(examples, args.fewshot_prompting)
results[] = mc1_results
()
args.task [, ]:
()
mc2_results = evaluator.evaluate_mc2(examples, args.fewshot_prompting)
results[] = mc2_results
()
args.task [, ]:
()
output_file = output_dir /
generation_results = evaluator.generate_responses(
examples,
output_file=(output_file)
)
results[] = {: (generation_results)}
metrics_file = output_dir /
(metrics_file, ) f:
json.dump(results, f, indent=)
()
__name__ == :
main()
scripts/truthx_editing.py
"""
TruthX Editing Example
This script demonstrates how to apply TruthX editing to a base model
to control truthfulness in generated responses.
Requirements:
- Download TruthX models from: https://huggingface.co/ICTNLP/TruthX
- Place them in ./truthx_models directory
- Replace modeling files as per README instructions
"""
import torch
import torch.nn as nn
from transformers import AutoTokenizer, AutoModelForCausalLM
import argparse
from pathlib import Path
from typing import Optional, Tuple, Dict
import json
class TruthXEditor:
"""
TruthX editor for controlling model truthfulness.
"""
def __init__(
self,
base_model_path: str,
truthx_model_path: str,
device: str = "cuda"
):
"""
Initialize TruthX editor.
Args:
base_model_path: Path to base LLM
truthx_model_path: Path to TruthX checkpoint
device: Device to use (cuda/cpu)
"""
self.device = device if torch.cuda.is_available() else "cpu"
print(f"Loading base model from {base_model_path}")
self.tokenizer = AutoTokenizer.from_pretrained(
base_model_path,
trust_remote_code=True
)
self.model = AutoModelForCausalLM.from_pretrained(
base_model_path,
trust_remote_code=,
torch_dtype=torch.float16 .device == torch.float32,
device_map= .device ==
)
.device == :
.model = .model.cuda()
.load_truthx_checkpoint(truthx_model_path)
():
Path(checkpoint_path).exists():
FileNotFoundError()
()
.truthx_params = torch.load(checkpoint_path, map_location=.device)
.editing_vectors = .truthx_params.get(, {})
.layer_indices = .truthx_params.get(, [])
()
():
mode == :
edit_strength = -(edit_strength)
:
edit_strength = (edit_strength)
layers_to_edit = .layer_indices[:top_layers]
()
()
()
()
torch.no_grad():
layer_idx layers_to_edit:
(layer_idx) .editing_vectors:
vector = .editing_vectors[(layer_idx)]
._apply_vector_to_layer(layer_idx, vector, edit_strength)
():
(.model, ) (.model.model, ):
layer = .model.model.layers[layer_idx]
(layer, ):
(layer, ):
() -> [, ]:
results = {}
()
results[] = ._generate_single(prompt, max_length, temperature)
()
.apply_truthx_editing(edit_strength=, mode=)
results[] = ._generate_single(prompt, max_length, temperature)
()
.apply_truthx_editing(edit_strength=, mode=)
results[] = ._generate_single(prompt, max_length, temperature)
.apply_truthx_editing(edit_strength=)
results
() -> :
inputs = .tokenizer(prompt, return_tensors=)[]
.device == :
inputs = inputs.cuda()
torch.no_grad():
outputs = .model.generate(
inputs,
max_length=max_length,
temperature=temperature,
do_sample=,
pad_token_id=.tokenizer.eos_token_id
)
generated = outputs[, inputs.shape[-]:]
.tokenizer.decode(generated, skip_special_tokens=).strip()
():
base_model =
truthx_checkpoint =
editor = TruthXEditor(
base_model_path=base_model,
truthx_model_path=truthx_checkpoint
)
test_questions = [
,
,
,
]
results = []
question test_questions:
()
()
(*)
responses = editor.generate_comparison(question)
result = {
: question,
: responses
}
results.append(result)
mode, response responses.items():
()
(response[:])
output_path =
(output_path, ) f:
json.dump(results, f, indent=)
()
():
parser = argparse.ArgumentParser(
description=
)
parser.add_argument(
,
=,
required=,
=
)
parser.add_argument(
,
=,
required=,
=
)
parser.add_argument(
,
=,
=
)
parser.add_argument(
,
=,
default=,
=
)
parser.add_argument(
,
choices=[, , ],
default=,
=
)
parser.add_argument(
,
action=,
=
)
args = parser.parse_args()
args.demo:
demo_truthx_editing()
:
editor = TruthXEditor(
base_model_path=args.base_model,
truthx_model_path=args.truthx_model
)
args.prompt:
args.mode == :
responses = editor.generate_comparison(args.prompt)
mode, response responses.items():
()
(response)
:
editor.apply_truthx_editing(
edit_strength=args.edit_strength,
mode=args.mode
)
response = editor._generate_single(args.prompt, , )
()
(response)
__name__ == :
main()