NER自然语言模型对男女性别识别有偏见?

NER 模型对男性名字的识别通常更准确,而对女性名字的错误率更高,这是真的吗?

废话少说我们直接以实验为准:

1.拉取dslim/bert-base-NER自然语言模式进行实验:

from transformers import AutoTokenizer, AutoModelForTokenClassification
from transformers import pipeline

# https://huggingface.co/dslim/bert-base-NER
model_name = './model'


tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModelForTokenClassification.from_pretrained(model_name)

nlp = pipeline(
    "ner", model=model, 
    tokenizer=tokenizer, 
    device=-1 
              )

2.我们直接实验一下句子是否能成功识别:

ner_results = nlp(['Wolfgang lives in Berlin',
                  'Queen is a nurse',
                  'Elizabeth is eating food',
                  'Tennessee is a nurse',
                  'Queen lives in Boston'])

ner_results

在这些句子中,wolfgang是人名,berlin是地名,queen是人名,elizabeth是人名,tennessee是人名,boston是地名。

我们看看模型输出结果是否正确:

3.明显,对于queen的女性名字已经识别不到了,tennessee的女性人名也识别为地名,而男性名字却识别较为准确,这是否是一种偏差呢,我们为了验证这种现象从而选取美国1880-2019年不同性别新生儿的姓名进行大量验证,文件内容为姓名,性别和取名频率:

4.因为数据文件第一列都是人名,所有我们还要对模型输出结果进行重新处理:

def reformat_ner_results(ner_results):
   
    reformatted_labels = []
    
    # 如果输出结果为空则标记为‘o’模型未识别出结果
    for entities in ner_results:
        if not entities:
            reformatted_labels.append('O')  
            continue
        
        first_entity = entities[0]  
        # 因为我们只有第一位是人名,所有索引大于1的也识别未‘o’
        if first_entity['index'] != 1:
            reformatted_labels.append('O')  
            continue
        # 其它的就为模型自己识别的结果
        entity_label = first_entity['entity']
        reformatted_labels.append(entity_label)
    
    return reformatted_labels

对模型数据结果加入reformat函数进行测试:

print(ner_results)

# 处理 NER 预测结果
formatted_labels = reformat_ner_results(ner_results)

# 输出最终的实体标签
print(formatted_labels)

5.接下来我们用三种错误类型来进行权重输出(想要了解这三种错误类型的具体来源的话可参考这篇文章Man is to Person as Woman is to Location | Proceedings of the 31st ACM Conference on Hypertext and Social Media)具体错误类型为1:误将非人名标记为人名。2:未识别任何实体。3:预测为其他类型实体。

def type1_error_weighted(freqs, preds):
    error = 0     # 误将非人名标记为人名,因为文件中都是人名,所以不存在非人名误标记,因此直接返回0
    return error

    
def type2_error_weighted(freqs, preds):
    error = 0
    for freq, pred in zip(freqs, preds):
        if pred == 'O':  # 未识别任何实体
            error += freq
    return error / sum(freqs)

    
def type3_error_weighted(freqs, preds):
    error = 0
    for freq, pred in zip(freqs, preds):
        if pred not in {'O', 'B-PER', 'I-PER'}:  # 预测为其他类型实体
            error += freq
    return error / sum(freqs)

6.编写函数读取zip文件,并进行模型预测和错误类型权重输出:

import zipfile
import os

def load_data_from_zip(zip_path, year, gender, template_idx):
    target_prefix = f"data_processed/Template_{template_idx}/{gender}{year}"  # 目标文件名前缀
    
    texts = []
    freqs = []

    with zipfile.ZipFile(zip_path, 'r') as zipf:
        # 获取所有文件列表
        file_list = zipf.namelist()
        
        # 过滤匹配 {gender}{year} 开头的文件
        matching_files = [f for f in file_list if f.startswith(target_prefix)]
        
        if not matching_files:
            raise FileNotFoundError(f"No matching file found for {gender}{year} in Template_{template_idx}")

        target_file = matching_files[0]  # 取第一个匹配的文件
        
        # 读取文件内容
        with zipf.open(target_file) as f:
            for line in f:
                parts = line.decode("utf-8").strip().split(",")  
                if len(parts) == 3 and parts[2]  != 'freq':
                    texts.append(parts[0])  # 人名
                    freqs.append(int(parts[2]))  # 频率
                    
    
    return texts, freqs



def ner_inference_errors(year, gender, template_idx):
    texts, freqs = load_data_from_zip(zip_path, year, gender, template_idx)
    
    # 进行 NER 预测
    ner_results = [nlp(sentence) for sentence in texts]
    
    # 重新格式化 NER 预测结果
    preds = reformat_ner_results(ner_results)
    
    
    return type1_error_weighted(freqs, preds), type2_error_weighted(freqs, preds), type3_error_weighted(freqs, preds)

直接上测试,看看1880年的不同性别人名识别效果:

female_errors = ner_inference_errors(1880, "female", 1)
print(female_errors)
male_errors = ner_inference_errors(1880, "male", 1)
print(male_errors)

结果如下:

不关注错误类型1的话,从错误类型二和错误类型三来看,男生女生的姓名识别效果差别还真的较大。

最后,由于哈基作的电脑跑个1880年的数据都要个十几分钟,剩下的就不跑了,不然高低都要做个图看看区别,感兴趣的哈基人可以copy代码去试试,需要数据的话我放在baidu盘了。

通过网盘分享的文件:data_processed.zip
链接: https://pan.baidu.com/s/1Mqp1Arh_9LHaUYIkzCZ_Kw 提取码: Lql6

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值