lm_human_preferences/language/sample.py (62 lines of code) (raw):
import tensorflow as tf
from lm_human_preferences.language import model
from lm_human_preferences.utils import core as utils
def sample_sequence(*, step, model_hparams, length, batch_size=None, context=None,
temperature=1, top_k=0, top_p=1.0, extra_outputs={}, cond=None):
"""
Sampling from an autoregressive sequence model.
Inputs:
step: A function which takes model hparams, a tokens Tensor, past, and
returns a dictionary with 'logits' and 'presents', and any extra vars.
context: Includes start tokens.
extra_outputs: Map from extra output key to dtype
Returns:
A dict with keys 'presents', 'logits', and any keys in extra_outputs
"""
with tf.name_scope('sample_seq'):
batch_size, *_ = utils.shape_list(context)
beta = 1 / tf.maximum(tf.cast(temperature, tf.float32), 1e-10)
context_output = step(model_hparams, context)
logits = tf.cast(context_output['logits'][:,-1], tf.float32)
first_output_logits = tf.cast(beta, logits.dtype) * logits
first_outputs = utils.sample_from_logits(first_output_logits)
first_logprobs = utils.logprobs_from_logits(logits=first_output_logits, labels=first_outputs)
def body(past, prev, output, logprobs, *extras):
next_outputs = step(model_hparams, prev[:, tf.newaxis], past=past,
past_tokens=output[:, :-1])
logits = tf.cast(next_outputs['logits'], tf.float32) * beta
if top_k != 0:
logits = tf.cond(tf.equal(top_k, 0),
lambda: logits,
lambda: utils.take_top_k_logits(logits, top_k))
if top_p != 1.0:
logits = utils.take_top_p_logits(logits, top_p)
next_sample = utils.sample_from_logits(logits, dtype=tf.int32)
next_logprob = utils.logprobs_from_logits(logits=logits, labels=next_sample)
return [
tf.concat([past, next_outputs['presents']], axis=-2),
tf.squeeze(next_sample, axis=[1]),
tf.concat([output, next_sample], axis=1),
tf.concat([logprobs, next_logprob], axis=1),
*[tf.concat([prev, next_outputs[k]], axis=1) for k, prev in zip(extra_outputs, extras)],
]
try:
shape_batch_size = int(batch_size)
except TypeError:
shape_batch_size = None
if cond is None:
def always_true(*args):
return True
cond = always_true
presents, _, tokens, logprobs, *extras = tf.while_loop(
body=body,
cond=cond,
loop_vars=[
context_output['presents'], # past
first_outputs, # prev
tf.concat([context, first_outputs[:, tf.newaxis]], axis=1), # output
first_logprobs[:, tf.newaxis], #logprobs
*[context_output[k][:, -1:] for k in extra_outputs] # extras
],
shape_invariants=[
tf.TensorShape(model.past_shape(hparams=model_hparams, batch_size=shape_batch_size)),
tf.TensorShape([shape_batch_size]),
tf.TensorShape([shape_batch_size, None]),
tf.TensorShape([shape_batch_size, None]),
*[tf.TensorShape([shape_batch_size, None]) for _ in extra_outputs]
],
maximum_iterations=length-1,
back_prop=False,
parallel_iterations=2,
)
return dict(tokens=tokens, presents=presents, logprobs=logprobs, **dict(zip(extra_outputs, extras)))