Sample decode loop state update function.
(state: DecodingState)
| 1053 | return jnp.any(not_at_end & (~terminate_early)) |
| 1054 | |
| 1055 | def sample_decode_loop_body_fn(state: DecodingState) -> DecodingState: |
| 1056 | """Sample decode loop state update function.""" |
| 1057 | # [batch]. |
| 1058 | cur_index = state.cur_index |
| 1059 | |
| 1060 | # Flatten the num_decodes dimension for the cache and the input IDs for this step. |
| 1061 | # [batch * num_decodes, 1]. |
| 1062 | flat_ids = flatten_decoding_dim( |
| 1063 | jnp.take_along_axis(state.sequences, cur_index[:, None, None], axis=2) |
| 1064 | ) |
| 1065 | # {[batch, num_decodes, ...], ...} --> {[batch * num_decodes, ...], ...}. |
| 1066 | flat_cache = vectorized_tree_map(flatten_decoding_dim, state.cache) |
| 1067 | |
| 1068 | # Call model on current tokens to get next-position logits and then unflatten. |
| 1069 | new_flat_log_probs, updated_flat_cache = tokens_to_scores(flat_ids, flat_cache) |
| 1070 | # [batch * num_decodes, vocab] --> [batch, num_decodes, vocab]. |
| 1071 | candidate_log_probs = unflatten_decoding_dim(new_flat_log_probs, batch_size, num_decodes) |
| 1072 | # {[batch * num_decodes, ...], ...} --> {[batch, num_decodes, ...], ...}. |
| 1073 | updated_cache = vectorized_tree_map( |
| 1074 | lambda x: unflatten_decoding_dim(x, batch_size, num_decodes), updated_flat_cache |
| 1075 | ) |
| 1076 | |
| 1077 | # Sample next token IDs according to logits. |
| 1078 | prng_key, updated_prng_key = jax.random.split(state.prng_key) |
| 1079 | # [batch, num_decodes]. |
| 1080 | next_token = jax.random.categorical(prng_key, logits=candidate_log_probs, axis=2) |
| 1081 | |
| 1082 | # We allow next_index to exceed `max_decode_len-1`: |
| 1083 | # - When reading from next_index, mode="clip" will effectively read `max_decode_len-1`; |
| 1084 | # - When writing to next_index, one-hot will cause the write to become a no-op. |
| 1085 | # [batch]. |
| 1086 | next_index = cur_index + 1 |
| 1087 | |
| 1088 | # [batch, num_decodes]. |
| 1089 | next_token_log_prob = jnp.sum( |
| 1090 | candidate_log_probs * jax.nn.one_hot(next_token, candidate_log_probs.shape[-1]), |
| 1091 | axis=-1, |
| 1092 | ) |
| 1093 | |
| 1094 | # If end sequence tokens already emitted, adjust next token to pad_id and update log_prob. |
| 1095 | next_token = ( |
| 1096 | next_token * ~state.stop_decoding |
| 1097 | + jnp.full_like(next_token, pad_id) * state.stop_decoding |
| 1098 | ) |
| 1099 | # [batch, num_decodes]. |
| 1100 | next_token_log_prob = ( |
| 1101 | next_token_log_prob * ~state.stop_decoding |
| 1102 | + jnp.zeros_like(next_token_log_prob) * state.stop_decoding |
| 1103 | ) |
| 1104 | |
| 1105 | # Update score and sequence trackers. For indices in `next_index` that exceed |
| 1106 | # `max_decode_len-1`, one-hot will zero-out the update. |
| 1107 | # [batch, num_decodes=1, length]. |
| 1108 | oh_indices = jax.nn.one_hot( |
| 1109 | next_index[:, None], state.sequences.shape[-1], dtype=state.sequences.dtype |
| 1110 | ) |
| 1111 | # [batch, num_decodes, length]. |
| 1112 | updated_sequences = ( |
no test coverage detected