Как с помощью преобразователя HuggingFace я могу вернуть несколько образцов при генерации текста? - PullRequest
2 голосов
/ 19 июня 2020

Я ухожу с https://github.com/cortexlabs/cortex/blob/master/examples/pytorch/text-generator/predictor.py

Но если я прохожу num_samples=5, я получаю:

    generated = torch.cat((generated, next_token.unsqueeze(0)), dim=1)
RuntimeError: Sizes of tensors must match except in dimension 1. Got 5 and 1 in dimension 0

код:

def sample_sequence(
    model,
    length,
    context,
    num_samples=1,
    temperature=1,
    top_k=0,
    top_p=0.9,
    repetition_penalty=1.0,
    device="cpu",
):
    context = torch.tensor(context, dtype=torch.long, device=device)
    context = context.unsqueeze(0).repeat(num_samples, 1)
    print('context_size', context.shape)
    generated = context
    print('context', context)
    with torch.no_grad():
        for _ in trange(length):
            inputs = {"input_ids": generated}
            outputs = model(
                **inputs
            )  # Note: we could also use 'past' with GPT-2/Transfo-XL/XLNet/CTRL (cached hidden-states)
            next_token_logits = outputs[0][0, -1, :] / (temperature if temperature > 0 else 1.0)

            # reptition penalty from CTRL (https://arxiv.org/abs/1909.05858)
            for _ in set(generated.view(-1).tolist()):
                next_token_logits[_] /= repetition_penalty

            filtered_logits = top_k_top_p_filtering(next_token_logits, top_k=top_k, top_p=top_p)
            if temperature == 0:  # greedy sampling:
                next_token = torch.argmax(filtered_logits).unsqueeze(0)
            else:
                next_token = torch.multinomial(F.softmax(filtered_logits, dim=-1), num_samples=1)
            generated = torch.cat((generated, next_token.unsqueeze(0)), dim=1)
    return generated

1 Ответ

1 голос
/ 24 июня 2020

Насколько я могу судить, этот код не предоставляет несколько выборок, но вы можете настроить его с некоторыми настройками.

В этой строке уже используется многочлен, но возвращается только 1:

next_token = torch.multinomial(F.softmax(filtered_logits, dim=-1), num_samples=1)

измените его на:

next_token = torch.multinomial(F.softmax(filtered_logits, dim=-1), num_samples=num_samples)

Теперь вам также нужно изменить конструкцию результата. Это объединяет строку next_token с предложением. Теперь вы получаете num_samples токенов next_tokens, и вам нужно разжать их все:

generated = torch.cat((generated, next_token.unsqueeze(0)), dim=1)

измените его на:

generated = torch.cat((generated, next_token.unsqueeze(1)), dim=1)

Теперь вся функция должна выглядеть так:

def sample_sequence(
    model,
    length,
    context,
    num_samples=1,
    temperature=1,
    top_k=0,
    top_p=0.9,
    repetition_penalty=1.0,
    device="cpu",
):
    context = torch.tensor(context, dtype=torch.long, device=device)
    context = context.unsqueeze(0).repeat(num_samples, 1)
    generated = context
    with torch.no_grad():
        for _ in trange(length):
            inputs = {"input_ids": generated}
            outputs = model(
                **inputs
            )  # Note: we could also use 'past' with GPT-2/Transfo-XL/XLNet/CTRL (cached hidden-states)
            next_token_logits = outputs[0][0, -1, :] / (temperature if temperature > 0 else 1.0)

            # reptition penalty from CTRL (https://arxiv.org/abs/1909.05858)
            for _ in set(generated.view(-1).tolist()):
                next_token_logits[_] /= repetition_penalty

            filtered_logits = top_k_top_p_filtering(next_token_logits, top_k=top_k, top_p=top_p)
            if temperature == 0:  # greedy sampling:
                next_token = torch.argmax(filtered_logits).unsqueeze(0)
            else:
                next_token = torch.multinomial(F.softmax(filtered_logits, dim=-1), num_samples=num_samples)
            generated = torch.cat((generated, next_token.unsqueeze(1)), dim=1)
    return generated

И последнее, но не менее важное: вам нужно изменить вызов tokenizer.decode на tokenizer.batch_decode, поскольку возвращаемое значение теперь содержит несколько образцов:

tokenizer.batch_decode(output.tolist(), clean_up_tokenization_spaces=True, skip_special_tokens=True)

Что-то, о чем вы должны подумать сами, это то, что вы хотите сделать, когда нет валида next_token. В настоящее время вы получите сообщение об ошибке, например:

RuntimeError: недопустимое полиномиальное распределение (при replace = False недостаточно неотрицательной категории для выборки)

Еще одна вещь, о которой вы должны подумать, это то, правильный ли их код. Во время нескольких проведенных мною тестов мне показалось, что качество созданных предложений снижается с увеличением числа num_samples (то есть, возможно, качество лучше, если вы используете простой l oop для многократного вызова sample_sequence?). Я еще не работал с GPT2 и не могу вам здесь помочь.

...