Instructions to use Ismailalshofi/char-based-language-model with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Keras
How to use Ismailalshofi/char-based-language-model with Keras:
# !pip install -U keras tensorflow huggingface_hub # Keras needs TensorFlow installed to read "hf://" paths, so the tensorflow backend is selected here; # "jax" and "torch" also work for computation once TensorFlow is installed. import os os.environ["KERAS_BACKEND"] = "tensorflow" import keras model = keras.saving.load_model("hf://Ismailalshofi/char-based-language-model") - Notebooks
- Google Colab
- Kaggle
|
Download README.md from Ismailalshofi/char-based-language-model: direct link, hf CLI and curl.
- Browser
- Download file 5.7 kB
-
https://huggingface.co/Ismailalshofi/char-based-language-model/resolve/main/README.md
- Command line
-
hf download hf://Ismailalshofi/char-based-language-model/README.md
-
curl -L -o README.md https://huggingface.co/Ismailalshofi/char-based-language-model/resolve/main/README.md
5.7 kB
| language: en | |
| license: mit | |
| library_name: tensorflow | |
| pipeline_tag: text-generation | |
| tags: | |
| - character-level | |
| - text-generation | |
| - gru | |
| - rnn | |
| - tensorflow | |
| - keras | |
| - news | |
| # Character-Level News Writer (GRU) | |
| A small GRU language model (1M parameters) that writes **one character at a time**. It was never given a word list: it learned spelling, spacing, punctuation and the shape of a news story from ~2,700 Pakistani business and sports news articles. | |
| **Try it:** [Character-level News Writer](https://huggingface.co/spaces/Ismailalshofi/char-news-writer), a Space where the model runs in your browser (the GRU re-implemented in plain JavaScript, checked against TensorFlow) · **Code:** [GitHub](https://github.com/ismailalshofi/character-based-language-model) | |
| ## Samples | |
| Real outputs, temperature 0.5 and 0.8: | |
| > **HONG KONG:** Asian stocks started on the final over as dealers could be able to see if they will allow the first day of the last settlement. The country's cricket team has recovered from a more than half the second set to beat South Africa... | |
| > **KARACHI:** Former West Indies Bailey delivery immossed the winner in 2052, and then been planned to the statement on Friday despite himself to consolidate their production cuts in a new target of 127 for six... | |
| The style is right: datelines, prices, scores, team names, "said on Monday". The facts are not, and business and sports get mixed in the same sentence, because the model only ever saw letters, never meaning. | |
| ## Model | |
| | Component | Details | | |
| |---|---| | |
| | Embedding | 106 characters → 128-dim vectors | | |
| | GRU | 512 units, dropout 0.2 | | |
| | Dense | 512 → 106 logits | | |
| | Parameters | 1,054,058 (4 MB) | | |
| ## Training | |
| | | | | |
| |---|---| | |
| | Data | 2,692 news articles (1,284 business, 1,408 sports), 4.48M characters after cleaning | | |
| | Cleaning | HTML and URLs removed, smart quotes and dashes normalized, whitespace collapsed. Case, digits and punctuation kept | | |
| | Sequences | 100 characters, 90/10 train/validation split | | |
| | Optimizer | Adam, batch 128, 30 epochs | | |
| | Final validation loss | **1.096** (≈ 1.58 bits per character), accuracy 67.4% | | |
| The validation loss was still going down at epoch 30, so early stopping never triggered: more epochs would likely help. | |
|  | |
| ## Usage | |
| The model is a subclassed Keras model, so loading it needs the `CharModel` class. This is the complete code (TensorFlow 2.15): | |
| ```python | |
| import json | |
| import tensorflow as tf | |
| from huggingface_hub import hf_hub_download | |
| REPO_ID = "Ismailalshofi/char-based-language-model" | |
| class CharModel(tf.keras.Model): | |
| def __init__(self, vocab_size, embedding_dim, rnn_units, dropout_rate=0.2): | |
| super().__init__() | |
| self.embedding = tf.keras.layers.Embedding(vocab_size, embedding_dim) | |
| self.dropout = tf.keras.layers.Dropout(dropout_rate) | |
| self.gru = tf.keras.layers.GRU( | |
| rnn_units, return_sequences=True, return_state=True, dropout=dropout_rate, recurrent_dropout=0.0 | |
| ) | |
| self.dense = tf.keras.layers.Dense(vocab_size) | |
| def call(self, inputs, states=None, return_state=False, training=False): | |
| x = self.embedding(inputs, training=training) | |
| x = self.dropout(x, training=training) | |
| if states is None: | |
| states = self.gru.get_initial_state(x) | |
| x, states = self.gru(x, initial_state=states, training=training) | |
| x = self.dense(x, training=training) | |
| return (x, states) if return_state else x | |
| # local_dir keeps the original file names (on Windows the hub cache uses symlinks TensorFlow can't read) | |
| files = {name: hf_hub_download(REPO_ID, name, local_dir="model") for name in ("model.keras", "vocab.json")} | |
| with open(files["vocab.json"], encoding="utf-8") as f: | |
| vocab = json.load(f) | |
| get_ids = tf.keras.layers.StringLookup(vocabulary=vocab, mask_token=None) | |
| get_chars = tf.keras.layers.StringLookup(vocabulary=get_ids.get_vocabulary(), invert=True, mask_token=None) | |
| model = tf.keras.models.load_model(files["model.keras"], custom_objects={"CharModel": CharModel}, compile=False) | |
| # Never sample the [UNK] token | |
| unk_mask = tf.one_hot(get_ids(["[UNK]"])[0], len(get_ids.get_vocabulary()), on_value=-1e9, off_value=0.0) | |
| def generate(seed, length=300, temperature=0.8): | |
| ids = get_ids(tf.strings.unicode_split([seed], "UTF-8")).to_tensor() | |
| states, text = None, seed | |
| for _ in range(length): | |
| logits, states = model(ids, states=states, return_state=True) | |
| ids = tf.random.categorical(logits[:, -1, :] / temperature + unk_mask, num_samples=1) | |
| text += get_chars(ids)[0, 0].numpy().decode("utf-8") | |
| return text | |
| print(generate("KARACHI:")) | |
| ``` | |
| **Temperature:** around 0.5 is safe and repetitive, 0.8 is a good balance, above 1.0 the model starts inventing words. | |
| ## Limitations | |
| - **Style, not facts.** It writes text that looks like news. Every name, number and event in it is made up. | |
| - **Narrow domain.** Pakistani business and sports news from one source. Other topics or seeds produce weaker text. | |
| - **Encoding artifacts.** Some apostrophes in the source data were stored as `´` (e.g. `Lord´s`), and the model learned them. | |
| - **English only**, 106 characters. Anything outside that vocabulary becomes `[UNK]`. | |
| ## Related | |
| This model is the starting point of a [controlled study of character vs subword tokenization](https://github.com/ismailalshofi/tokenization-study), which trains the same Transformer with both tokenizers and compares them fairly in bits per character. | |
| ## Author | |
| **Ismail Alshofi** · [GitHub](https://github.com/ismailalshofi) · [Kaggle](https://www.kaggle.com/ismailalshofi) · [Medium](https://medium.com/@ialshofi) | |