ageron/handson-mlp

[bug] Beam Search Returns the Least Likely Sentence at the End

Open

#39 建立於 2026年5月2日

在 GitHub 查看
 (0 留言) (0 反應) (1 負責人)Jupyter Notebook (513 fork)github user discovery
bughelp wanted

倉庫指標

Star
 (1,561 star)
PR 合併指標
 (30 天內沒有已合併 PR)

描述

Enter the chapter number

Chapter 14, Beam Search

Enter the page number

No response

What is the cell's number in the notebook

No response

Enter the environment you are using to run the notebook

None

Describe your issue

Current Beam search implementation keeps track of the k most likely sentences, but then returns the least likely of the final k at the end:

def beam_search(model, src_text, beam_width=3, max_length=20,
                verbose=False, length_penalty=0.6):
    top_translations = [(torch.tensor(0.), "")]
    for index in range(max_length):
        if verbose:
            print(f"Top {beam_width} translations so far:")
            for log_proba, tgt_text in top_translations:
                print(f"    {log_proba.item():.3f} – {tgt_text}")

        candidates = []
        for log_proba, tgt_text in top_translations:
            if tgt_text.endswith(" </s>"):
                candidates.append((log_proba, tgt_text))
                continue  # don't add tokens after EOS token
            batch, _ = nmt_collate_fn([{"source_text": src_text,
                                        "target_text": tgt_text}])
            with torch.no_grad():
                Y_logits = model(batch.to(device))
                Y_log_proba = F.log_softmax(Y_logits, dim=1)
                Y_top_log_probas = torch.topk(Y_log_proba, k=beam_width, dim=1)

            for beam_index in range(beam_width):
                next_token_log_proba = Y_top_log_probas.values[0, beam_index, index]
                next_token_id = Y_top_log_probas.indices[0, beam_index, index]
                next_token = nmt_tokenizer.id_to_token(next_token_id)
                next_tgt_text = tgt_text + " " + next_token
                candidates.append((log_proba + next_token_log_proba, next_tgt_text))

        def length_penalized_score(candidate, alpha=length_penalty):
            log_proba, text = candidate
            length = len(text.split())
            penalty = ((5 + length) ** alpha) / (6 ** alpha)
            return log_proba / penalty

        top_translations = sorted(candidates,
                                  key=length_penalized_score,
                                  reverse=True)[:beam_width]

    return top_translations[-1][1]

Enter what you expected to happen

No response

If you found a workaround, describe it here

Last line should be:

return top_translations[0][1]

貢獻者指南