目录
获得 icp 分数指令
utils/icp_scores.py
1. 命令行参数解析
2. 核心函数
2.1 get_task_count(data):通过提取所有唯一的doc_id,确定任务包含的样本总数
2.2 load_data(path):加载 JSON 格式的模型输出文件
2.3 get_likelihoods(data):分离基线似然分数(无上下文)和上下文似然分数
2.4 get_icp_scores(likelihoods, baseline_likelihoods):对每个上下文样本,计算其提升任务样本似然分数的比例(ICP分数)
2.5 save_icp_scores(scores, path):将 ICP 分数存入 JSON 文件
3. 主程序流程
python utils/icp_scores.py --infile path_to_model_outputs --outfile path_to_save_file
计算 ICP 分数:获取模型输出后,使用 Python 脚本计算 ICP 分数:
--infile path_to_model_outputs
:
指定了通过之前的模型运行(bash scripts/run_icp.sh
)生成的模型输出文件路线(model_probs.json)。
--outfile path_to_save_file
:
指定了计算结果的输出文件路径(ICP分数保存路径)(icp_scores.csv)。
该脚本用于计算 In-Context Probing (ICP) 分数,通过对比模型 使用上下文示例 和 无上下文(基线) 的预测似然差异,评估上下文学习的效果。
parser = argparse.ArgumentParser()
parser.add_argument("--infile", type=str, help="path to model likelihoods file")
parser.add_argument("--outfile", type=str, help="path to save file")
args = parser.parse_args()
输入文件格式:每行一个 JSON 对象,包含 doc_id
、incontext_doc_id
和 filtered_resps
等字段:
doc_id
是输入数据(data
)中每个条目(entry
)的一个字段,通常是一个整数(如 0,1
等),是 任务样本的唯一标识符.filtered_resps
表示经过过滤后的响应结果,通常是模型对某个任务样本的预测结果。它包含了模型针对样本计算得到的似然分数,这个分数可以用来衡量模型对该样本预测的置信度或者合理性。incontext_doc_id
代表上下文文档的标识符。在上下文学习的场景里,模型在预测某个任务样本时,会利用一个或多个上下文样本的信息来辅助决策。incontext_doc_id
就是用来标识这些被用作上下文的样本:incontext_doc_id
的值为 0
时,表示模型在预测当前样本时没有使用任何上下文信息,这通常作为一个基准情况,用于后续与使用上下文信息的情况进行对比。incontext_doc_id
的值不为 0
时,它标识了被用作上下文的具体样本的 doc_id
,模型会参考该上下文样本的信息来对当前样本进行预测。输出文件格式:JSON 字典,键为上下文示例ID,值为对应的 ICP 分数。
get_task_count(data)
:通过提取所有唯一的doc_id
,确定任务包含的样本总数def get_task_count(data):
"""
Count the number of samples in the task.
Args:
data: model outputs.
Returns:
int: number of samples.
"""
n_task_samples = set()
for entry in tqdm(data):
doc_id = entry['doc_id']
n_task_samples.add(doc_id) #集合n_task_samples存储唯一的doc_id(自动去重)
return len(n_task_samples) #返回集合长度即为样本数
doc_id
是输入数据(data
)中每个条目(entry
)的一个字段,通常是一个整数(如 0
, 1
, 2
等),是 任务样本的唯一标识符,用于:
1. 统计任务中的唯一样本数(通过集合去重)。
2. 作为索引 存储和关联样本的似然分数(基线和上下文场景)。
3. 区分不同样本,确保在多上下文或多次预测场景中,每个样本仅被处理一次。
load_data(path)
:加载 JSON 格式的模型输出文件def load_data(path):
"""
Data model outputs
Args:
path: model outputs.
Returns:
int: number of samples.
"""
with open(path) as f:
#逐行读取文件,用json.loads()解析为 Python 对象
data = [json.loads(l.strip()) for l in f.readlines()]
return data #返回包含所有条目的列表
输入格式:每行一个 JSON 对象,例如:
{"doc_id": 0, "incontext_doc_id": 0, "filtered_resps": [[0.87]]}
{"doc_id": 1, "incontext_doc_id": 2, "filtered_resps": [[0.92]]}
get_likelihoods(data)
:分离基线似然分数(无上下文)和上下文似然分数def get_likelihoods(data):
"""
Get output likelihoods from model outputs
Args:
data: model outputs
Returns:
likelihoods: model output likelihoods for each incontext sample
baseline_likelihoods: baseline model output likelihoods (without incontext samples)
"""
likelihoods = {}
n_task_samples = get_task_count(data)
baseline_likelihoods = np.zeros(n_task_samples)
for entry in tqdm(data):
incontext_doc_id = entry['incontext_doc_id']
doc_id = entry['doc_id']
ll = entry['filtered_resps'][0][0]
# baseline case
if incontext_doc_id == 0: ## 基线情况
baseline_likelihoods[doc_id] = ll
continue
#上下文示例情况
#其他 incontext_doc_id 转换为字符串键(减1处理),确保与后续索引对齐。
incontext_doc_id = str(incontext_doc_id - 1)
if incontext_doc_id not in likelihoods:
likelihoods[incontext_doc_id] = np.zeros(n_task_samples)
likelihoods[incontext_doc_id][doc_id] = ll
return likelihoods, baseline_likelihoods
Python NumPy数组利器之np.zeros函数详解与应用实例例子解析-CSDN博客baseline_likelihoods
:长度为n_task_samples
的数组,索引为doc_id
,值为基线似然分数likelihoods
:键为上下文样本标识(字符串),值为对应似然分数数组
get_icp_scores(likelihoods, baseline_likelihoods):
对每个上下文样本,计算其提升任务样本似然分数的比例(ICP分数)def get_icp_scores(likelihoods, baseline_likelihoods):
"""
Calculate ICP scores.
Args:
likelihoods: model output likelihoods for each incontext sample
baseline_likelihoods: baseline model output likelihoods (without incontext samples)
Returns:
icp scores
"""
icp_scores = {}
for incontext_doc_id in likelihoods:
task_likelihoods = likelihoods[incontext_doc_id]
#计算 “上下文分数高于基线” 的样本比例,作为该上下文的 ICP 分数
icp_score = np.mean([1 if task_likelihoods[i] > baseline_likelihoods[i] else 0 for i in range(len(task_likelihoods))])
icp_scores[incontext_doc_id] = [icp_score]
return icp_scores
range(len(task_likelihoods))
:生成一个从 0 到 len(task_likelihoods) - 1
的整数序列。1 if task_likelihoods[i] > baseline_likelihoods[i] else 0
:如果 task_likelihoods[i]
大于 baseline_likelihoods[i]
,则表达式的值为 1,表示使用该上下文样本时模型对第 i
个任务样本的预测效果比基线情况更好。[ ... for i in range(len(task_likelihoods))]
:列表推导式,会遍历生成的整数序列,将每个索引 i
对应的条件表达式的值添加到一个列表中。np.mean(...)
:计算数组或列表的平均值。这里计算上述列表中所有元素的平均值,得到的结果就是 ICP 分数。save_icp_scores(scores, path):
将 ICP 分数存入 JSON 文件def save_icp_scores(icp_scores, path):
with open(path, 'w+') as f:
f.write(json.dumps(icp_scores))
输出格式:
{"0": [0.7], "1": [0.6]} # 键为上下文样本标识,值为ICP分数列表
if __name__ == "__main__":
data = load_data(args.infile) # 加载数据
likelihoods, baseline_likelihoods = get_likelihoods(data) # 提取似然
icp_scores = get_icp_scores(likelihoods, baseline_likelihoods) # 计算分数
save_icp_scores(icp_scores, args.outfile) # 保存结果