我试图根据一个语言模型计算一组标记化单词的单词概率,我需要一些花哨的索引.

我的输入,用玩具示例说明如下:

  • token_list:n_words x max_tokenization_length(例如,三个字,其中最大标记化长度为3)
  • pxhs:n_words x(max_tokenization_length +1)x|词汇|,(例如,三个单词,四组logit用于3 + 1令牌,维度1000 vocab)
  • Next_word_token_ids:构成新词的令牌列表(例如,所有以空格字符开头的标记).
pxhs = torch.rand((3,4,1000))

pad_token_id = tokenizer.pad_token_id
word_token_list = [
    [120, pad_token_id, pad_token_id],
    [131, 132, pad_token_id],
    [140, 141, 142],
]

new_word_token_ids = [0,1,2,3,5]

期望的输出是长度为3的单词概率列表,计算如下:

word 1: pxhs[0, 0, 120] * pxhs[0, 1, new_word_token_ids].sum()
word 2: pxhs[1, 0, 131] * pxhs[1, 1, 132] * pxhs[1, 2, new_word_token_ids].sum()
word 3: pxhs[2, 0, 140] * pxhs[2, 1, 141] * pxhs[2, 2, 142] * pxhs[2, 3, new_word_token_ids].sum()

在实践中,我想通过用新词token id替换第一个pad_token_id来索引,然后什么都不做(这不能作为索引,只是举例说明):

actual_idx = [
    [[120], new_word_token_ids, [None], [None]],
    [[131], [132], new_word_token_ids, [None]],
    [[140], [142], [143], new_word_token_ids],
]

我写了一个非常慢的函数,它可以做到这一点:

all_word_probs = []
for word_tokens, word_probs in zip(token_list, pxhs):
    counter=0
    p_word=1
    while (counter < len(word_tokens) and 
            word_tokens[counter] != tokenizer.pad_token_id):
        p_word = p_word * word_probs[counter, word_tokens[counter]]
        counter+=1
    new_word_prob = word_probs[counter, new_word_tokens].sum()
    p_word = p_word * new_word_prob
    all_word_probs.append(p_word)

我需要更快的东西,提前感谢你的帮助!

推荐答案

获取您想要的输出

word 2: pxhs[1, 0, 131] * pxhs[1, 1, 132] * pxhs[1, 2, new_word_token_ids].sum()

这个 idea 是将计算分成两部分:token_list个概率(pxhs[1, 0, 131] * pxhs[1, 1, 132])和new_word_token_ids个概率(pxhs[1, 2, new_word_token_ids].sum()).

我假设您可以访问一个长度为n_wordsseq_lens张量,该张量存储了每个序列的第一个填充标记的索引.我还假设所有对象都是张量,并且下面的最大序列长度(max_len)不会太长(否则for循环将成为瓶颈).

我使用对数概率来实现数值 solidity ;你应该可以毫无问题地转换回来.

n = len(word_token_list)
max_len = seq_lens.max()
seq_idxs = torch.arange(n)
log_pxhs = pxhs.log()

# Step 1:
# Compute the probability of the sequences in `word_token_list`
# (clever indexing could also vectorize this at the expense of intelligibility)
log_p_x = torch.zeros(n)
log_p_x = torch.zeros(n)
for i in range(max_len):
    tok_idxs = word_token_list[:, i]
    log_p_x += log_pxhs[seq_idxs, i, tok_idxs] * (i < seq_lens)

# Step 2:
# Compute the probability of the `new_word_token_ids` at the end of the sequence
v = pxhs.shape[2]
v_mask = torch.isin(torch.arange(v), new_word_token_ids, assume_unique=True)
# mask pxhs to only include nonzero values for `new_word_token_ids`
p_new = pxhs * v_mask
# index those probabilities for the end of the sequence
p_new_given_x = p_new[seq_idxs, seq_lens].sum(1)

# Step 3: compute the final log-probability
print(log_p_x + p_new_given_x.log())

我没有基准的东西,但我认为它应该导致一个实质性的加速.

Python相关问答推荐

Pandas 第二小值有条件

Polars比较了两个预设-有没有方法在第一次不匹配时立即失败

我在使用fill_between()将最大和最小带应用到我的图表中时遇到问题

如何在箱形图中添加绘制线的传奇?

对整个 pyramid 进行分组与对 pyramid 列子集进行分组

用NumPy优化a[i] = a[i-1]*b[i] + c[i]的迭代计算

为什么以这种方式调用pd.ExcelWriter会创建无效的文件格式或扩展名?

优化器的运行顺序影响PyTorch中的预测

形状弃用警告与组合多边形和多边形如何解决

什么是最好的方法来切割一个相框到一个面具的第一个实例?

UNIQUE约束失败:customuser. username

使用Python查找、替换和调整PDF中的图像'

在单次扫描中创建列表

Pandas—MultiIndex Resample—我不想丢失其他索引的信息´

从源代码显示不同的输出(机器学习)(Python)

递归函数修饰器

在电影中向西北方向对齐""

如果服务器设置为不侦听创建,则QWebSocket客户端不连接到QWebSocketServer;如果服务器稍后开始侦听,则不连接

对于数组中的所有元素,Pandas SELECT行都具有值

如何在基于时间的数据帧中添加计算值