Instructions to use barakplasma/translategemma-4b-it-android-task-quantized with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- LiteRT
How to use barakplasma/translategemma-4b-it-android-task-quantized with LiteRT:
# No code snippets available yet for this library. # To use this model, check the repository files and the library's documentation. # Want to help? PRs adding snippets are welcome at: # https://github.com/huggingface/huggingface.js
- Notebooks
- Google Colab
- Kaggle
Upload scripts/bundle_litertlm.py with huggingface_hub
Browse files- scripts/bundle_litertlm.py +218 -0
scripts/bundle_litertlm.py
ADDED
|
@@ -0,0 +1,218 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""
|
| 3 |
+
Bundle a Strategy-1 KV-cache TFLite + SentencePiece tokenizer into a
|
| 4 |
+
.litertlm file compatible with Google AI Edge / LiteRT-LM runtime.
|
| 5 |
+
|
| 6 |
+
Embeds:
|
| 7 |
+
- LlmMetadata proto: Gemma3 model type, 2K max tokens, TranslateGemma
|
| 8 |
+
Jinja chat template, BOS/EOS/end_of_turn stop tokens
|
| 9 |
+
- TFLite model (model_type=prefill_decode)
|
| 10 |
+
- SentencePiece tokenizer
|
| 11 |
+
|
| 12 |
+
Usage:
|
| 13 |
+
python bundle_litertlm.py \
|
| 14 |
+
--tflite /path/to/model.tflite \
|
| 15 |
+
--tokenizer /path/to/tokenizer.model \
|
| 16 |
+
--output /path/to/output.litertlm \
|
| 17 |
+
[--max-tokens 2048]
|
| 18 |
+
"""
|
| 19 |
+
|
| 20 |
+
import argparse
|
| 21 |
+
import sys
|
| 22 |
+
import tempfile
|
| 23 |
+
from pathlib import Path
|
| 24 |
+
|
| 25 |
+
# Make litert_lm package importable from /tmp/litert-lm-pkg
|
| 26 |
+
sys.path.insert(0, "/tmp/litert-lm-pkg")
|
| 27 |
+
|
| 28 |
+
from litert_lm_builder import litertlm_builder
|
| 29 |
+
from litert_lm.runtime.proto import (
|
| 30 |
+
llm_metadata_pb2,
|
| 31 |
+
llm_model_type_pb2,
|
| 32 |
+
token_pb2,
|
| 33 |
+
)
|
| 34 |
+
|
| 35 |
+
|
| 36 |
+
# TranslateGemma 4B IT Jinja chat template (from tokenizer_config.json)
|
| 37 |
+
# Requires structured content: {type, source_lang_code, target_lang_code, text}
|
| 38 |
+
TRANSLATE_GEMMA_JINJA_TEMPLATE = """\
|
| 39 |
+
{%- set languages = {
|
| 40 |
+
"aa": "Afar", "ab": "Abkhazian", "af": "Afrikaans", "ak": "Akan",
|
| 41 |
+
"am": "Amharic", "an": "Aragonese", "ar": "Arabic", "as": "Assamese",
|
| 42 |
+
"az": "Azerbaijani", "ba": "Bashkir", "be": "Belarusian", "bg": "Bulgarian",
|
| 43 |
+
"bm": "Bambara", "bn": "Bengali", "bo": "Tibetan", "br": "Breton",
|
| 44 |
+
"bs": "Bosnian", "ca": "Catalan", "ce": "Chechen", "co": "Corsican",
|
| 45 |
+
"cs": "Czech", "cv": "Chuvash", "cy": "Welsh", "da": "Danish",
|
| 46 |
+
"de": "German", "dv": "Divehi", "dz": "Dzongkha", "ee": "Ewe",
|
| 47 |
+
"el": "Greek", "en": "English", "eo": "Esperanto", "es": "Spanish",
|
| 48 |
+
"et": "Estonian", "eu": "Basque", "fa": "Persian", "ff": "Fulah",
|
| 49 |
+
"fi": "Finnish", "fo": "Faroese", "fr": "French", "fy": "Western Frisian",
|
| 50 |
+
"ga": "Irish", "gd": "Scottish Gaelic", "gl": "Galician", "gn": "Guarani",
|
| 51 |
+
"gu": "Gujarati", "gv": "Manx", "ha": "Hausa", "he": "Hebrew",
|
| 52 |
+
"hi": "Hindi", "hr": "Croatian", "ht": "Haitian", "hu": "Hungarian",
|
| 53 |
+
"hy": "Armenian", "ia": "Interlingua", "id": "Indonesian", "ig": "Igbo",
|
| 54 |
+
"ii": "Sichuan Yi", "ik": "Inupiaq", "io": "Ido", "is": "Icelandic",
|
| 55 |
+
"it": "Italian", "iu": "Inuktitut", "ja": "Japanese", "jv": "Javanese",
|
| 56 |
+
"ka": "Georgian", "ki": "Kikuyu", "kk": "Kazakh", "kl": "Kalaallisut",
|
| 57 |
+
"km": "Central Khmer", "kn": "Kannada", "ko": "Korean", "ks": "Kashmiri",
|
| 58 |
+
"ku": "Kurdish", "kw": "Cornish", "ky": "Kyrgyz", "la": "Latin",
|
| 59 |
+
"lb": "Luxembourgish", "lg": "Ganda", "ln": "Lingala", "lo": "Lao",
|
| 60 |
+
"lt": "Lithuanian", "lu": "Luba-Katanga", "lv": "Latvian", "mg": "Malagasy",
|
| 61 |
+
"mi": "Maori", "mk": "Macedonian", "ml": "Malayalam", "mn": "Mongolian",
|
| 62 |
+
"mr": "Marathi", "ms": "Malay", "mt": "Maltese", "my": "Burmese",
|
| 63 |
+
"nb": "Norwegian Bokmål", "nd": "North Ndebele", "ne": "Nepali",
|
| 64 |
+
"nl": "Dutch", "nn": "Norwegian Nynorsk", "no": "Norwegian",
|
| 65 |
+
"nr": "South Ndebele", "nv": "Navajo", "ny": "Chichewa", "oc": "Occitan",
|
| 66 |
+
"om": "Oromo", "or": "Oriya", "os": "Ossetian", "pa": "Punjabi",
|
| 67 |
+
"pl": "Polish", "ps": "Pashto", "pt": "Portuguese", "qu": "Quechua",
|
| 68 |
+
"rm": "Romansh", "rn": "Rundi", "ro": "Romanian", "ru": "Russian",
|
| 69 |
+
"rw": "Kinyarwanda", "sa": "Sanskrit", "sc": "Sardinian", "sd": "Sindhi",
|
| 70 |
+
"se": "Northern Sami", "sg": "Sango", "si": "Sinhala", "sk": "Slovak",
|
| 71 |
+
"sl": "Slovenian", "sn": "Shona", "so": "Somali", "sq": "Albanian",
|
| 72 |
+
"sr": "Serbian", "ss": "Swati", "st": "Southern Sotho", "su": "Sundanese",
|
| 73 |
+
"sv": "Swedish", "sw": "Swahili", "ta": "Tamil", "te": "Telugu",
|
| 74 |
+
"tg": "Tajik", "th": "Thai", "ti": "Tigrinya", "tk": "Turkmen",
|
| 75 |
+
"tl": "Tagalog", "tn": "Tswana", "to": "Tonga", "tr": "Turkish",
|
| 76 |
+
"ts": "Tsonga", "tt": "Tatar", "ug": "Uyghur", "uk": "Ukrainian",
|
| 77 |
+
"ur": "Urdu", "uz": "Uzbek", "ve": "Venda", "vi": "Vietnamese",
|
| 78 |
+
"vo": "Volapük", "wa": "Walloon", "wo": "Wolof", "xh": "Xhosa",
|
| 79 |
+
"yi": "Yiddish", "yo": "Yoruba", "za": "Zhuang", "zh": "Chinese",
|
| 80 |
+
"zu": "Zulu"
|
| 81 |
+
} -%}
|
| 82 |
+
{{ bos_token }}
|
| 83 |
+
{%- if (messages[0]['role'] != 'user') -%}
|
| 84 |
+
{{ raise_exception("Conversations must start with a user prompt.") }}
|
| 85 |
+
{%- endif -%}
|
| 86 |
+
{%- for message in messages -%}
|
| 87 |
+
{%- if (message['role'] == 'user') != (loop.index0 % 2 == 0) -%}
|
| 88 |
+
{{ raise_exception("Conversation roles must alternate user/assistant/user/assistant/...") }}
|
| 89 |
+
{%- endif -%}
|
| 90 |
+
{%- if (message['role'] == 'assistant') -%}
|
| 91 |
+
{%- if message['content'] is none or message['content'] is not string -%}
|
| 92 |
+
{{ raise_exception("Assistant role must provide content as a string") }}
|
| 93 |
+
{%- endif -%}
|
| 94 |
+
{{ '<start_of_turn>model\\n'}}
|
| 95 |
+
{{ message["content"] | trim }}
|
| 96 |
+
{%- elif (message['role'] == 'user') -%}
|
| 97 |
+
{%- set content = message["content"] if message["content"] is string else message["content"][0] -%}
|
| 98 |
+
{%- if content is string -%}
|
| 99 |
+
{%- set source_lang = "English" -%}
|
| 100 |
+
{%- set source_lang_code = "en" -%}
|
| 101 |
+
{%- set target_lang = "Spanish" -%}
|
| 102 |
+
{%- set target_lang_code = "es" -%}
|
| 103 |
+
{{ '<start_of_turn>user\\nYou are a professional ' + source_lang + ' (' + source_lang_code + ') to ' +
|
| 104 |
+
target_lang + ' (' + target_lang_code + ') translator. Your goal is to accurately convey the meaning ' +
|
| 105 |
+
'and nuances of the original ' + source_lang + ' text while adhering to ' + target_lang + ' grammar, ' +
|
| 106 |
+
'vocabulary, and cultural sensitivities.\\n' +
|
| 107 |
+
'Produce only the ' + target_lang + ' translation, without any additional explanations or ' +
|
| 108 |
+
'commentary. Please translate the following ' + source_lang + ' text into ' + target_lang + ':\\n\\n\\n' +
|
| 109 |
+
content | trim
|
| 110 |
+
}}
|
| 111 |
+
{%- else -%}
|
| 112 |
+
{%- set source_lang_code = content["source_lang_code"] | replace("_", "-") -%}
|
| 113 |
+
{%- set source_lang = languages.get(source_lang_code, source_lang_code) -%}
|
| 114 |
+
{%- set target_lang_code = content["target_lang_code"] | replace("_", "-") -%}
|
| 115 |
+
{%- set target_lang = languages.get(target_lang_code, target_lang_code) -%}
|
| 116 |
+
{{ '<start_of_turn>user\\nYou are a professional ' + source_lang + ' (' + source_lang_code + ') to ' +
|
| 117 |
+
target_lang + ' (' + target_lang_code + ') translator. Your goal is to accurately convey the meaning ' +
|
| 118 |
+
'and nuances of the original ' + source_lang + ' text while adhering to ' + target_lang + ' grammar, ' +
|
| 119 |
+
'vocabulary, and cultural sensitivities.\\n'
|
| 120 |
+
}}
|
| 121 |
+
{%- if content["type"] == 'text' -%}
|
| 122 |
+
{{ 'Produce only the ' + target_lang + ' translation, without any additional explanations or ' +
|
| 123 |
+
'commentary. Please translate the following ' + source_lang + ' text into ' + target_lang + ':\\n\\n\\n' +
|
| 124 |
+
content["text"] | trim
|
| 125 |
+
}}
|
| 126 |
+
{%- endif -%}
|
| 127 |
+
{%- endif -%}
|
| 128 |
+
{%- else -%}
|
| 129 |
+
{{ raise_exception("Conversations must only contain user or assistant roles.") }}
|
| 130 |
+
{%- endif -%}
|
| 131 |
+
{{ '<end_of_turn>\\n' }}
|
| 132 |
+
{%- endfor -%}
|
| 133 |
+
{%- if add_generation_prompt -%}
|
| 134 |
+
{{'<start_of_turn>model\\n'}}
|
| 135 |
+
{%- endif -%}"""
|
| 136 |
+
|
| 137 |
+
|
| 138 |
+
def build_llm_metadata_proto(max_tokens: int) -> bytes:
|
| 139 |
+
meta = llm_metadata_pb2.LlmMetadata()
|
| 140 |
+
meta.max_num_tokens = max_tokens
|
| 141 |
+
|
| 142 |
+
# Model type: Gemma3 (text-only variant — no vision config needed for TranslateGemma text mode)
|
| 143 |
+
meta.llm_model_type.gemma3.CopyFrom(llm_model_type_pb2.Gemma3())
|
| 144 |
+
|
| 145 |
+
# Start token: BOS = token id 2
|
| 146 |
+
meta.start_token.token_ids.ids.append(2)
|
| 147 |
+
|
| 148 |
+
# Stop tokens: EOS (id=1) and end_of_turn (id=106)
|
| 149 |
+
eos = meta.stop_tokens.add()
|
| 150 |
+
eos.token_ids.ids.append(1)
|
| 151 |
+
|
| 152 |
+
eot = meta.stop_tokens.add()
|
| 153 |
+
eot.token_ids.ids.append(106)
|
| 154 |
+
|
| 155 |
+
# Embed the Jinja template
|
| 156 |
+
meta.jinja_prompt_template = TRANSLATE_GEMMA_JINJA_TEMPLATE
|
| 157 |
+
|
| 158 |
+
return meta.SerializeToString()
|
| 159 |
+
|
| 160 |
+
|
| 161 |
+
def main():
|
| 162 |
+
ap = argparse.ArgumentParser(description="Bundle TFLite + tokenizer into .litertlm")
|
| 163 |
+
ap.add_argument("--tflite", required=True)
|
| 164 |
+
ap.add_argument("--tokenizer", required=True, help="SentencePiece .model file")
|
| 165 |
+
ap.add_argument("--output", required=True)
|
| 166 |
+
ap.add_argument("--max-tokens", type=int, default=2048)
|
| 167 |
+
ap.add_argument("--quant", default="int8", help="Quantization label for metadata")
|
| 168 |
+
args = ap.parse_args()
|
| 169 |
+
|
| 170 |
+
tflite_path = Path(args.tflite)
|
| 171 |
+
tokenizer_path = Path(args.tokenizer)
|
| 172 |
+
output_path = Path(args.output)
|
| 173 |
+
|
| 174 |
+
if not tflite_path.exists():
|
| 175 |
+
print(f"[x] TFLite not found: {tflite_path}", file=sys.stderr)
|
| 176 |
+
sys.exit(1)
|
| 177 |
+
if not tokenizer_path.exists():
|
| 178 |
+
print(f"[x] Tokenizer not found: {tokenizer_path}", file=sys.stderr)
|
| 179 |
+
sys.exit(1)
|
| 180 |
+
|
| 181 |
+
output_path.parent.mkdir(parents=True, exist_ok=True)
|
| 182 |
+
|
| 183 |
+
# Write LlmMetadata to temp file
|
| 184 |
+
meta_bytes = build_llm_metadata_proto(args.max_tokens)
|
| 185 |
+
with tempfile.NamedTemporaryFile(suffix=".pb", delete=False) as f:
|
| 186 |
+
meta_file = Path(f.name)
|
| 187 |
+
f.write(meta_bytes)
|
| 188 |
+
|
| 189 |
+
print(f"[+] Building .litertlm: {output_path.name}")
|
| 190 |
+
print(f" TFLite: {tflite_path} ({tflite_path.stat().st_size / 1e9:.2f} GB)")
|
| 191 |
+
print(f" Tokenizer: {tokenizer_path}")
|
| 192 |
+
print(f" Max tokens: {args.max_tokens}")
|
| 193 |
+
|
| 194 |
+
Metadata = litertlm_builder.Metadata
|
| 195 |
+
DType = litertlm_builder.DType
|
| 196 |
+
|
| 197 |
+
builder = litertlm_builder.LitertLmFileBuilder()
|
| 198 |
+
builder.add_system_metadata(Metadata(key="model_name", value=f"TranslateGemma-4B-IT-{args.quant}", dtype=DType.STRING))
|
| 199 |
+
builder.add_system_metadata(Metadata(key="authors", value="google", dtype=DType.STRING))
|
| 200 |
+
builder.add_system_metadata(Metadata(key="quantization", value=args.quant, dtype=DType.STRING))
|
| 201 |
+
|
| 202 |
+
builder.add_tflite_model(
|
| 203 |
+
str(tflite_path),
|
| 204 |
+
model_type=litertlm_builder.TfLiteModelType.PREFILL_DECODE,
|
| 205 |
+
)
|
| 206 |
+
builder.add_sentencepiece_tokenizer(str(tokenizer_path))
|
| 207 |
+
builder.add_llm_metadata(str(meta_file))
|
| 208 |
+
|
| 209 |
+
with open(output_path, "wb") as f:
|
| 210 |
+
builder.build(f)
|
| 211 |
+
meta_file.unlink(missing_ok=True)
|
| 212 |
+
|
| 213 |
+
size = output_path.stat().st_size
|
| 214 |
+
print(f"[+] Written: {output_path} ({size / 1e9:.2f} GB)")
|
| 215 |
+
|
| 216 |
+
|
| 217 |
+
if __name__ == "__main__":
|
| 218 |
+
main()
|