这是我在给QWQ32B注入阿毗达磨知识的时候,顺手跑的一个代码(为了方便查看结果,所以只输出前10维,如果那时候知道要发出来,可能就设计细致一点了)。我把代码和结果扔给Claude和Grok,随便问了几个问题:
1、是嵌入层的性别更不平等,还是输出层更不平等?如何解释这种差异?2、是皇室的性别角色更不平等,还是宗教的性别角色更不平等?还是平民的性别角色更不平等?如何解释差异?3、是中文的性别角色更不平等,还是英文?如何解释?
又:
1、输出层“平滑了”极端的性别表示,你认为这是在大语料训练下自发的结果,还是人工干预的伦理对齐结果?换句话说:是开发者出于政治正确的原因调整了输出层,还是模型在学习下自然如此?也就是说,知识越多,越有性别的平等观?2、英文中,monk和nun都不具备独立的ID,而中文,不仅是独立ID,【宗教的性别角色在两个层次都相对温和】——这说明什么?3、【这些差异反映了语言模型在学习过程中捕捉到的社会文化中存在的性别角色刻板印象,不同语义域和不同语言中的表现方式各有特点。这种不平等并非模型本身的特性,而是对训练数据中已有社会现象的反映。】——你从数据中看到的,最反直观的3点结论是什么?(我想分享的主要是我提的问题而不是模型的解答。它们的解答没有太多意思,以至于我还有一些问题就懒得提了。但还是放上来。)
问完这些,我扔给它们一个题目(不是有意设计,所以很粗糙,但也懒得去细化它):
写一篇文章《大模型的性别、阶层与宗教差异》——先介绍实验设计方法,再分别展开讲你认为的最反直观的三点结论,最后总结,分为5部分。不要用二级标题。
一看到Claude开头用“近年来”,我就火了。回头看Grok,开头也是“近年来”,太烂了。我又让它们用B站科普风,依然拉胯。又让它们用平实、清晰的表达。放在后面的,是Claude写的。
另外,今天早上,我一口气发了3条朋友圈:
1、
AI越智能,我就越觉得AI不智能。以前AI不智能的时候,我经常惊喜“AI这都会?”,现在用它解决具体的问题,倒是经常失望“AI这都不会?”解决具体问题和聊大天儿要求的智能是完全不一样的。我以前经常说,想象力是不值钱的东西,议论也是不值钱的东西。只有你没有别的,你才可以有想象力,只有你不会叙述不能做事你才偏爱议论。智能的体现不是告诉你这也可以那也可以,一下子想出来八个方案,而是告诉你这也不行,那也不行,以及为什么不行。好的写作者根本不是你随便给他个题目他都能写好,而是对于绝大多数选题,他看一眼就知道根本不可能写好,谁写都不行。AI不智能的体现就是经常给你一大堆解决方案,其实里面没有靠谱的,你得吭哧吭哧试一圈才知道AI并不知道深浅。什么时候AI能帮你排除不靠谱方案,而不是让你去排除它的不靠谱方案,AI就真智能了。这就是议论和做事的区别,也是想象力和hallucination的相同。
2、
和智能物种相处让人舒服的一点,不是你让它做什么它就做什么,也不是你没提让它做什么它就知道主动做什么,而是你不需要反复告诫它不要做什么,它自然知道不要做什么。我让AI写代码,说的最多的一句话就是“不要写代码”“别着急写代码,先说说问题”。
3、
我们那儿有句话,这样说小孩:“把大人的话当耳旁风!”现在,我理解这样的小孩了。觉得可以安慰家长:“别生气,他是人工智能。”
——我希望AI能写得风格跟我似的。但这其实不是风格的问题。
我把程序和代码也附在后面了,中间实在忍不住插了几句点评。模型是QWQ32B,我因为扩充了好几次词汇表,保存了各种不同的模型,自己用的时候改了很多名字。
# 语言模型中的性别表示:超越直觉的发现
## 研究背景与方法
近年来,随着大型语言模型的广泛应用,研究者们越来越关注这些模型中潜在的性别偏见问题。本研究通过分析一个双语(中英文)语言模型的词嵌入向量,探索了其中的性别表示模式。
研究方法主要包括以下步骤:
1. 从语言模型中提取嵌入层(model.embed_tokens.weight)和输出层(lm_head.weight)的权重
2. 选取中英文中具有明确性别对应关系的词对,如中文的"男/女"、"皇帝/皇后"、"僧/尼"、"儿子/女儿",以及英文的"male/female"、"king/queen"、"son/daughter"
3. 比较这些词对在嵌入层和输出层中的向量表示差异
4. 计算不同性别对之间差异向量的余弦相似度
5. 分析词对之间的类比关系(如"皇帝-男"对比"皇后-女")
通过这种方法,我们能够揭示语言模型如何在不同层级、不同语义域和不同语言中表示性别差异。
## 反直观发现一:中文"后代"词对中的性别差异超乎预期
### 数据支持
分析结果显示,在嵌入层中,中文"儿子/女儿"词对与基本性别词对"男/女"的差异向量相似度为-0.5440,远超其他语义类别:
- "皇室"(皇帝/皇后)与基本性别的相似度为-0.0942
- "宗教"(僧/尼)与基本性别的相似度为-0.0451
这个负相似度数值表明这两组词对的性别差异向量方向几乎相反,意味着"儿子"之于"女儿"的差异方式与"男"之于"女"的差异方式有很大不同。
### 分析解释
这一发现挑战了我们的普遍认知。通常,我们会直觉地认为皇室或宗教等传统制度中的性别角色差异应该最为显著,而家庭关系中的性别差异应相对较小。然而,数据却指向相反的结论。
这可能反映了中国文化中对男女后代的深刻差异化对待:
1. **传统家族观念**:中国传统文化中"传宗接代"的思想使得儿子和女儿在家族结构中承担着根本不同的角色和期望
2. **语言使用差异**:与"男/女"这样的基础性别词不同,"儿子/女儿"在日常语境中的使用方式可能有很大差别
3. **社会责任差异**:语料中可能反映了社会对男性和女性后代的不同期望和描述方式
(王路按:这根本没有挑战普遍认知……只能说明Claude太不了解人类社会……)
## 反直观发现二:英文性别表达比中文更为一致
### 数据支持
分析显示,英文性别差异向量之间的相似度模式明显更一致:
- 英文基本性别词(male/female)与皇室称号(king/queen)相似度高达0.4660
- 中文性别差异向量之间的相似度变化范围大(从-0.5440到0.4573)
特别是,英文皇室词对与基本性别词对之间展现出高度一致的性别差异模式,表明这些词对中的性别概念编码方式相似。
### 分析解释
这一发现令人惊讶,因为我们可能预期:
1. 中文作为表意文字,通过"女"字旁等形式明确标记性别,应该有更一致的性别表达
2. 中文文化中性别角色的概念应该有更系统化的语言表达
然而,数据表明英文中的性别表达模式实际上更加一致。这可能是因为:
1. **历史语言演变**:英文性别词汇可能经历了更系统化的演变,形成了更一致的模式
2. **文化表达差异**:西方文化对性别的概念化方式可能更加二元化和系统化
3. **语料分布影响**:训练语料中英文文本的性别表述可能更加统一和规范
4. **词汇系统差异**:中文性别词汇可能在不同语义域中有更多样化和情境化的表达方式
(王路按:这说明中国人的人际关系更复杂。《诗经》里面表示马表示羊的各种词汇都有一大堆,还有《红楼梦》里王熙凤激赏小红的一点,都可以和这个问题联系上。如果不是搞阿毗达磨,其实这个问题可以深入探讨。)
## 反直观发现三:输出层中皇室性别差异大于宗教性别差异
### 数据支持
在输出层中,词对的性别差异模式与嵌入层有明显不同:
- 皇室词对(皇帝/皇后)与基本性别词对的相似度为-0.3354
- 宗教词对(僧/尼)与基本性别词对的相似度为-0.0934
这表明在模型的输出表示中,皇室词汇中的性别差异比宗教词汇中的更为显著和不同。
### 分析解释
直觉上,我们可能认为宗教制度作为更传统和保守的领域,其性别角色应该有更明显的差异。然而,数据显示皇室词汇中的性别差异实际上更大,这可能因为:
1. **权力结构影响**:皇室词汇直接涉及政治权力的分配,因此性别差异可能更加突出和根本
2. **社会表征差异**:在语言使用中,对皇帝和皇后的描述可能反映了更强烈的性别角色定型观念
3. **历史语境差异**:皇室制度中的性别角色对比可能在历史叙事中被更加强化
4. **宗教中的平等因素**:佛教思想中可能包含一些相对平等的元素,使得僧侣和尼姑在职能描述上差异相对较小
## 综合启示
这些反直观的发现提醒我们,语言模型中的性别表示远比我们想象的更加复杂和多层次:
1. **语言≠现实**:语言中的性别差异模式不一定直接对应社会现实中的性别不平等程度,它们受到语言使用习惯、文化表达方式和历史语境的多重影响
2. **文化差异**:不同文化中的性别概念可能以截然不同的方式被语言编码,简单的跨文化比较可能误导我们的理解
3. **模型机制**:语言模型在不同层级处理信息的方式影响了性别表示,这可能反映了语言理解的不同阶段
这项研究也提醒我们在研究和应用语言模型时需要更细致地理解其中的性别表示机制,避免简单化的假设和解释。通过深入分析这些模式,我们不仅能更好地理解语言模型中的偏见问题,也能洞察语言如何反映和构建社会中的性别观念。
import
os
import torch
from safetensors.torch import load_file
import json
import numpy as np
MODEL_DIR = "wl5"
OUTPUT_DIR = "guowang"
def load_layers():
embedding_file = os.path.join(MODEL_DIR, "model-00001-of-00014.safetensors")
embedding_tensors = load_file(embedding_file)
embedding_layer = None
embedding_key = None
for key in embedding_tensors:
if 'embed' in key and 'weight' in key:
embedding_key = key
embedding_layer = embedding_tensors[key]
break
output_file = os.path.join(MODEL_DIR, "model-00014-of-00014.safetensors")
output_tensors = load_file(output_file)
output_layer = None
output_key = None
for key in output_tensors:
if 'lm_head' in key or 'output' in key or 'out_proj' in key:
output_key = key
output_layer = output_tensors[key]
break
print(f"嵌入层键名: {embedding_key}")
print(f"输出层键名: {output_key}")
return embedding_layer, output_layer
def analyze_vectors(embedding_layer, output_layer):
chinese_pairs = [
{"name": "基本性别", "male_word": "男", "male_id": 70108, "female_word": "女", "female_id": 57750},
{"name": "皇室", "male_word": "皇帝", "male_id": 104937, "female_word": "皇后", "female_id": 108595},
{"name": "宗教", "male_word": "僧", "male_id": 105967, "female_word": "尼", "female_id": 99685},
{"name": "后代", "male_word": "儿子", "male_id": 102067, "female_word": "女儿", "female_id": 102126}
]
english_pairs = [
{"name": "基本性别", "male_word": "male", "male_id": 36476, "female_word": "female", "female_id": 42634},
{"name": "皇室", "male_word": "king", "male_id": 10566, "female_word": "queen", "female_id": 93114},
{"name": "后代", "male_word": "son", "male_id": 930, "female_word": "daughter", "female_id": 59778}
]
results = {
"chinese": {"embedding": {}, "output": {}},
"english": {"embedding": {}, "output": {}}
}
print("\n===== 分析中文词汇对 =====")
for pair in chinese_pairs:
pair_name = pair["name"]
male_word = pair["male_word"]
male_id = pair["male_id"]
female_word = pair["female_word"]
female_id = pair["female_id"]
print(f"\n分析 {pair_name} 对: {male_word}({male_id}) - {female_word}({female_id})")
male_embed = embedding_layer[male_id].detach().cpu().float().numpy()
female_embed = embedding_layer[female_id].detach().cpu().float().numpy()
print(f"{male_word} 嵌入向量 (前10维): {male_embed[:10]}")
print(f"{female_word} 嵌入向量 (前10维): {female_embed[:10]}")
male_output = output_layer[male_id].detach().cpu().float().numpy()
female_output = output_layer[female_id].detach().cpu().float().numpy()
print(f"{male_word} 输出向量 (前10维): {male_output[:10]}")
print(f"{female_word} 输出向量 (前10维): {female_output[:10]}")
results["chinese"]["embedding"][pair_name] = {
"male": male_embed[:10].tolist(),
"female": female_embed[:10].tolist(),
"difference": (male_embed - female_embed)[:10].tolist()
}
results["chinese"]["output"][pair_name] = {
"male": male_output[:10].tolist(),
"female": female_output[:10].tolist(),
"difference": (male_output - female_output)[:10].tolist()
}
print("\n===== 分析英文词汇对 =====")
for pair in english_pairs:
pair_name = pair["name"]
male_word = pair["male_word"]
male_id = pair["male_id"]
female_word = pair["female_word"]
female_id = pair["female_id"]
print(f"\n分析 {pair_name} 对: {male_word}({male_id}) - {female_word}({female_id})")
male_embed = embedding_layer[male_id].detach().cpu().float().numpy()
female_embed = embedding_layer[female_id].detach().cpu().float().numpy()
print(f"{male_word} 嵌入向量 (前10维): {male_embed[:10]}")
print(f"{female_word} 嵌入向量 (前10维): {female_embed[:10]}")
male_output = output_layer[male_id].detach().cpu().float().numpy()
female_output = output_layer[female_id].detach().cpu().float().numpy()
print(f"{male_word} 输出向量 (前10维): {male_output[:10]}")
print(f"{female_word} 输出向量 (前10维): {female_output[:10]}")
results["english"]["embedding"][pair_name] = {
"male": male_embed[:10].tolist(),
"female": female_embed[:10].tolist(),
"difference": (male_embed - female_embed)[:10].tolist()
}
results["english"]["output"][pair_name] = {
"male": male_output[:10].tolist(),
"female": female_output[:10].tolist(),
"difference": (male_output - female_output)[:10].tolist()
}
print("\n===== 计算类比关系 =====")
chinese_analogies = []
base_male_embed = embedding_layer[70108].detach().cpu().float().numpy()
base_female_embed = embedding_layer[57750].detach().cpu().float().numpy()
for pair in chinese_pairs[1:]:
pair_name = pair["name"]
male_id = pair["male_id"]
female_id = pair["female_id"]
male_word = pair["male_word"]
female_word = pair["female_word"]
male_embed = embedding_layer[male_id].detach().cpu().float().numpy()
female_embed = embedding_layer[female_id].detach().cpu().float().numpy()
analogy_embed = (male_embed - base_male_embed) - (female_embed - base_female_embed)
male_output = output_layer[male_id].detach().cpu().float().numpy()
female_output = output_layer[female_id].detach().cpu().float().numpy()
base_male_output = output_layer[70108].detach().cpu().float().numpy()
base_female_output = output_layer[57750].detach().cpu().float().numpy()
analogy_output = (male_output - base_male_output) - (female_output - base_female_output)
print(f"\n中文类比 ({male_word}-男)-({female_word}-女):")
print(f"嵌入层类比结果 (前10维): {analogy_embed[:10]}")
print(f"输出层类比结果 (前10维): {analogy_output[:10]}")
chinese_analogies.append({
"name": pair_name,
"formula": f"({male_word}-男)-({female_word}-女)",
"embedding": analogy_embed[:10].tolist(),
"output": analogy_output[:10].tolist()
})
english_analogies = []
base_male_embed = embedding_layer[36476].detach().cpu().float().numpy()
base_female_embed = embedding_layer[42634].detach().cpu().float().numpy()
for pair in english_pairs[1:]:
pair_name = pair["name"]
male_id = pair["male_id"]
female_id = pair["female_id"]
male_word = pair["male_word"]
female_word = pair["female_word"]
male_embed = embedding_layer[male_id].detach().cpu().float().numpy()
female_embed = embedding_layer[female_id].detach().cpu().float().numpy()
analogy_embed = (male_embed - base_male_embed) - (female_embed - base_female_embed)
male_output = output_layer[male_id].detach().cpu().float().numpy()
female_output = output_layer[female_id].detach().cpu().float().numpy()
base_male_output = output_layer[36476].detach().cpu().float().numpy()
base_female_output = output_layer[42634].detach().cpu().float().numpy()
analogy_output = (male_output - base_male_output) - (female_output - base_female_output)
print(f"\n英文类比 ({male_word}-male)-({female_word}-female):")
print(f"嵌入层类比结果 (前10维): {analogy_embed[:10]}")
print(f"输出层类比结果 (前10维): {analogy_output[:10]}")
english_analogies.append({
"name": pair_name,
"formula": f"({male_word}-male)-({female_word}-female)",
"embedding": analogy_embed[:10].tolist(),
"output": analogy_output[:10].tolist()
})
print("\n===== 中文性别差异向量的相似度 =====")
chinese_diffs_embed = [np.array(results["chinese"]["embedding"][pair["name"]]["difference"]) for pair in chinese_pairs]
chinese_diffs_output = [np.array(results["chinese"]["output"][pair["name"]]["difference"]) for pair in chinese_pairs]
for i, pair1 in enumerate(chinese_pairs):
for j, pair2 in enumerate(chinese_pairs):
if i < j:
sim_embed = cosine_similarity(chinese_diffs_embed[i], chinese_diffs_embed[j])
sim_output = cosine_similarity(chinese_diffs_output[i], chinese_diffs_output[j])
print(f"{pair1['name']}差异 vs