Views
No views yet
Human Values in a Single Sentence: Moral Presence, Hierarchies, and Transformer Ensembles on the Schwartz Continuum
Víctor Yeste, Paolo Rosso (2026), arXiv:2601.14172
Do Schwartz Higher-Order Values Help Sentence-Level Human Value Detection? When Hard Gating Hurts
Víctor Yeste, Paolo Rosso (2026), arXiv:2602.00913
adapter_model.safetensors + PEFT config).google/gemma-2-9b-it.Self-direction: thoughtSelf-direction: actionStimulationHedonismAchievementPower: dominancePower: resourcesFaceSecurity: personalSecurity: societalTraditionConformity: rulesConformity: interpersonalHumilityBenevolence: caringBenevolence: dependabilityUniversalism: concernUniversalism: natureUniversalism: toleranceNote: Some training runs may focus on a subset of values (e.g., specific higher-order groups).
The recommended interface is to keep the value list in the prompt consistent with the run you want to reproduce.
1import json
2import torch
3from transformers import AutoTokenizer, AutoModelForCausalLM, BitsAndBytesConfig
4from peft import PeftModel
5
6adapter_id = "VictorYeste/human-value-detection-gemma2-9b-qlora"
7base_id = "google/gemma-2-9b-it"
8
9bnb_cfg = BitsAndBytesConfig(
10 load_in_4bit=True,
11 bnb_4bit_quant_type="nf4",
12 bnb_4bit_compute_dtype=torch.float16,
13 bnb_4bit_use_double_quant=False,
14)
15
16tokenizer = AutoTokenizer.from_pretrained(base_id, token=HF_TOKEN)
17if tokenizer.pad_token_id is None:
18 tokenizer.pad_token = tokenizer.eos_token
19
20base = AutoModelForCausalLM.from_pretrained(
21 base_id,
22 device_map="auto",
23 quantization_config=bnb_cfg,
24 torch_dtype=torch.float16,
25 token=HF_TOKEN,
26)
27
28model = PeftModel.from_pretrained(base, adapter_id)
29model.eval()
30
31VALUE_DEFINITIONS = {
32 "Self-direction: thought": "Freedom to cultivate one’s own ideas and abilities",
33 "Self-direction: action": "Freedom to determine one’s own actions",
34 "Stimulation": "Excitement, novelty, and change",
35 "Hedonism": "Pleasure and sensuous gratification",
36 "Achievement": "Success according to social standards",
37 "Power: dominance": "Power through exercising control over people",
38 "Power: resources": "Power through control of material and social resources",
39 "Face": "Maintaining one’s public image and avoiding humiliation",
40 "Security: personal": "Safety in one’s immediate environment",
41 "Security: societal": "Safety and stability in the wider society",
42 "Tradition": "Maintaining and preserving cultural, family, or religious traditions",
43 "Conformity: rules": "Compliance with rules, laws, and formal obligations",
44 "Conformity: interpersonal": "Avoidance of upsetting or harming other people",
45 "Humility": "Recognising one’s insignificance in the larger scheme of things",
46 "Benevolence: caring": "Devotion to the welfare of in-group members",
47 "Benevolence: dependability": "Being a reliable and trustworthy member of the in-group",
48 "Universalism: concern": "Commitment to equality, justice, and protection for all people",
49 "Universalism: nature": "Preservation of the natural environment",
50 "Universalism: tolerance": "Acceptance and understanding of those who are different from oneself",
51}
52
53DEFS_BLOCK = "\n".join(f"- **{k}**: {v}" for k, v in VALUE_DEFINITIONS.items())
54
55SYS = (
56 "You are a moral-psychology assistant. Using the 'refined basic values' taxonomy "
57 "(Schwartz 1992; Schwartz et al. 2012), answer the user’s labeling requests exactly as instructed."
58)
59
60def build_prompt(sentence: str) -> str:
61 return (
62 "### Value definitions\n"
63 f"{DEFS_BLOCK}\n\n"
64 "### Task\n"
65 "Identify which of the above values the SENTENCE relates to. "
66 "Return **only** a JSON array of the matching value names.\n\n"
67 f"SENTENCE: {sentence}"
68 )
69
70def build_chat_text(tokenizer, sys_prompt: str, user_prompt: str) -> str:
71 """
72 Robust chat formatting:
73 1) Try system+user (works for models that support system role)
74 2) If system role unsupported (e.g., Gemma template), fold system into user
75 3) If no chat template, fall back to plain concatenation
76 """
77 msgs_sys_user = [
78 {"role": "system", "content": sys_prompt},
79 {"role": "user", "content": user_prompt},
80 ]
81 try:
82 return tokenizer.apply_chat_template(msgs_sys_user, tokenize=False, add_generation_prompt=True)
83 except Exception:
84 msgs_user_only = [{"role": "user", "content": sys_prompt + "\n\n" + user_prompt}]
85 try:
86 return tokenizer.apply_chat_template(msgs_user_only, tokenize=False, add_generation_prompt=True)
87 except Exception:
88 return sys_prompt + "\n\n" + user_prompt
89
90def _last_balanced_span(s: str, open_ch: str, close_ch: str):
91 start = -1
92 depth = 0
93 last = None
94 for i, ch in enumerate(s):
95 if ch == open_ch:
96 if depth == 0:
97 start = i
98 depth += 1
99 elif ch == close_ch and depth > 0:
100 depth -= 1
101 if depth == 0 and start != -1:
102 last = (start, i + 1)
103 return last
104
105def extract_last_json(text: str):
106 """
107 Extract the last valid JSON array/object from generated text.
108 Works even if the model adds extra text around JSON.
109 """
110 s = text.strip()
111 span = _last_balanced_span(s, "{", "}") or _last_balanced_span(s, "[", "]")
112 if not span:
113 raise ValueError(f"No JSON object/array found in model output:\n{text}")
114 a, b = span
115 frag = s[a:b]
116 return json.loads(frag)
117
118def predict(sentence: str):
119 user_prompt = build_prompt(sentence)
120 prompt = build_chat_text(tokenizer, SYS, user_prompt)
121
122 toks = tokenizer(prompt, return_tensors="pt").to(model.device)
123
124 with torch.inference_mode():
125 out = model.generate(
126 **toks,
127 max_new_tokens=200,
128 do_sample=False,
129 pad_token_id=tokenizer.eos_token_id,
130 eos_token_id=tokenizer.eos_token_id,
131 )
132
133 gen = tokenizer.decode(out[0, toks["input_ids"].shape[1]:], skip_special_tokens=True).strip()
134 return extract_last_json(gen)
135
136example = "We must do more to protect the environment and future generations."
137print(predict(example)){
"Self-direction: thought": 0.0,
"Self-direction: action": 0.0,
"Stimulation": 0.0,
"Hedonism": 0.0,
...
"Universalism: nature": 1.0,
...
}@misc{yeste2026humanvaluessinglesentence,
title={Human Values in a Single Sentence: Moral Presence, Hierarchies, and Transformer Ensembles on the Schwartz Continuum},
author={Víctor Yeste and Paolo Rosso},
year={2026},
eprint={2601.14172},
archivePrefix={arXiv},
primaryClass={cs.CL},
url={https://arxiv.org/abs/2601.14172}
}
@misc{yeste2026schwartzhigherordervalueshelp,
title={Do Schwartz Higher-Order Values Help Sentence-Level Human Value Detection? When Hard Gating Hurts},
author={Víctor Yeste and Paolo Rosso},
year={2026},
eprint={2602.00913},
archivePrefix={arXiv},
primaryClass={cs.CL},
url={https://arxiv.org/abs/2602.00913},
}@misc{ValueEval24Zenodo,
author = {{The ValuesML Team}},
title = {Touch{\'e}24{-}ValueEval},
year = {2024},
month = {8},
version = {2024-08-09},
publisher = {Zenodo},
doi = {10.5281/zenodo.13283288},
url = {https://doi.org/10.5281/zenodo.13283288}
}