T5¶
kf_config.json + model.weights.h5).
Load with from_weights("kerasformers/<variant>").
Google's T5 (Text-to-Text Transfer Transformer) in pure Keras 3: an encoder-decoder transformer
where every task is framed as text-to-text. The blocks use T5-style RMSNorm (scale only,
pre-LayerNorm), a learned relative-position bias instead of absolute or rotary embeddings, no
1/sqrt(d) attention scaling, and an LM head tied to the shared embedding. One implementation
runs unmodified on TensorFlow / Torch / JAX, bit-exact with Hugging Face on real checkpoints.
This port targets original T5 (a ReLU dense-relu-dense MLP, a shared token embedding, and a
tied LM head scaled by embed_dim ** -0.5); v1.1 / Flan-T5, which use gated-GELU and an untied
head, are not covered.
- Paper: Exploring the Limits of Transfer Learning with a Unified Text-to-Text Transformer (arXiv:1910.10683)
- HF docs: transformers/model_doc/t5
Variants¶
Load any of these with from_weights("kerasformers/<variant>").
| Variant | Hub | layers / dim |
|---|---|---|
t5_small |
kerasformers/t5_small |
6 / 512 |
t5_base |
kerasformers/t5_base |
12 / 768 |
t5_large |
kerasformers/t5_large |
24 / 1024 |
t5_3b |
kerasformers/t5_3b |
24 / 1024 |
t5_11b |
kerasformers/t5_11b |
24 / 1024 |
API¶
All classes are imperative SubclassedBaseModels; the heads extend the backbone. The one hosted
model.weights.h5 (declaring T5Model) is the full encoder-decoder; every class loads its own
subset (T5ConditionalGenerate ties the LM head, so it adds no weight; the classification / QA
heads are randomly initialized for fine-tuning).
T5Model¶
The encoder-decoder backbone. Takes input_ids / attention_mask / decoder_input_ids and
returns {"last_hidden_state": (B, T, d), "encoder_last_hidden_state": (B, S, d)}.
| Arg | Default | Meaning |
|---|---|---|
vocab_size |
32128 |
token vocabulary size |
embed_dim |
768 |
model width |
key_value_dim |
64 |
per-head width (num_heads * key_value_dim may != embed_dim) |
mlp_dim |
3072 |
feed-forward inner width |
num_layers |
12 |
encoder blocks |
num_decoder_layers |
12 |
decoder blocks |
num_heads |
12 |
attention heads |
relative_attention_num_buckets |
32 |
relative-position buckets |
relative_attention_max_distance |
128 |
max bucketed distance |
hidden_act |
"relu" |
feed-forward activation |
layer_norm_eps |
1e-6 |
RMSNorm epsilon |
tie_word_embeddings |
True |
reuse the shared embedding as the LM head |
pad_token_id / eos_token_id / decoder_start_token_id |
0 / 1 / 0 |
special tokens |
T5ConditionalGenerate¶
T5Model plus the tied LM head. Returns {"logits": (B, T, vocab_size), ...} and adds
.generate() (runs the encoder once, then greedily decodes, cross-attending to the frozen encoder
output at each step). Takes the same constructor arguments as T5Model.
generate(
input_ids,
attention_mask=None,
max_new_tokens=None,
eos_token_id=None,
sampler=None,
seed=None,
)
| Arg | Default | Meaning |
|---|---|---|
input_ids |
required | (B, S) encoder token ids |
attention_mask |
None |
(B, S) 1 = keep, 0 = padding |
max_new_tokens |
None |
tokens to generate |
eos_token_id |
None |
stop token (defaults to the tokenizer's) |
sampler |
None |
sampling strategy; greedy when unset |
Other classes¶
| Class | HF equivalent | Output |
|---|---|---|
T5EncoderModel |
T5EncoderModel |
{"last_hidden_state": (B, S, d)} |
T5SequenceClassify |
T5ForSequenceClassification |
(B, num_classes) |
T5TokenClassify |
T5ForTokenClassification |
(B, S, num_classes) |
T5QnA |
T5ForQuestionAnswering |
{"start_logits": (B, T), "end_logits": (B, T)} |
T5Tokenizer¶
SentencePiece (Unigram) tokenizer on the tokenizers (Rust) backend: the ▁ metaspace, $A </s>
post-processing (T5 appends EOS), and the 100 <extra_id_N> sentinels are baked in. Returns
input_ids / attention_mask (T5 has no token-type ids).
End-to-end example¶
Text-to-text generation¶
import os
os.environ["KERAS_BACKEND"] = "torch" # or "jax" / "tensorflow"
from kerasformers.models.t5 import T5ConditionalGenerate, T5Tokenizer
model = T5ConditionalGenerate.from_weights("kerasformers/t5_base")
tokenizer = T5Tokenizer.from_weights("kerasformers/t5_base")
inputs = tokenizer("translate English to German: The house is wonderful.")
output_ids = model.generate(
inputs["input_ids"], inputs["attention_mask"], max_new_tokens=40
)
print(tokenizer.decode(output_ids[0])) # "Das Haus ist wunderbar."
Encoder features¶
from kerasformers.models.t5 import T5EncoderModel, T5Tokenizer
encoder = T5EncoderModel.from_weights("kerasformers/t5_base")
tokenizer = T5Tokenizer.from_weights("kerasformers/t5_base")
feats = encoder(tokenizer("The quick brown fox."))["last_hidden_state"] # (1, S, 768)
Scoring a target sequence¶
from kerasformers.models.t5 import T5Model
model = T5Model.from_weights("kerasformers/t5_base")
out = model(
{
"input_ids": inputs["input_ids"],
"attention_mask": inputs["attention_mask"],
"decoder_input_ids": decoder_ids, # right-shifted targets
}
)
out["last_hidden_state"] # decoder states (B, T, d)
Loading from the Hub¶
Architecture notes¶
- Relative position bias, not absolute or rotary: a learned
Embedding(num_buckets, num_heads)per stack, bucketed bymemory - query(bidirectional in the encoder, causal in the decoder) and shared across all layers of that stack. Cross-attention uses no relative bias. - T5LayerNorm is RMSNorm (scale only, no mean subtraction, no bias). Residuals are pre-LayerNorm, and each stack ends with a final RMSNorm.
- No
1/sqrt(d)attention scaling and no biases in q/k/v/o or the MLP. The decoder starts from the pad token (decoder_start_token_id = 0); the LM head is the transposed shared embedding scaled byembed_dim ** -0.5.
Parity¶
Bit-exact with Hugging Face transformers (eager, float32): T5ConditionalGenerate logits and the
T5EncoderModel last hidden state match to 0.0 max-abs difference; the classification / QA heads
match to < 2e-7. See convert_t5_hf_to_keras.py.