Spaces:
Running
Running
| #!/usr/bin/env python3 | |
| """ | |
| Train a SentencePiece tokenizer for Fusion models. | |
| This creates the tokenizer.model file needed by Fusion's 100K vocabulary. | |
| Training data should be a plain text file with one sentence per line. | |
| Usage: | |
| python scripts/train_tokenizer.py --input data/tokenizer_train.txt --vocab_size 100000 --output tokenizers/ | |
| Requirements: | |
| pip install sentencepiece | |
| Author: Zhu Zizhan | |
| Project: Fusion-LLM | |
| License: Apache 2.0 | |
| """ | |
| import argparse | |
| import os | |
| import sys | |
| def train_tokenizer(input_path: str, vocab_size: int, output_dir: str, model_type: str = "unigram"): | |
| """Train a SentencePiece tokenizer.""" | |
| try: | |
| import sentencepiece as spm | |
| except ImportError: | |
| print("[ERROR] sentencepiece not installed. Run: pip install sentencepiece") | |
| sys.exit(1) | |
| if not os.path.exists(input_path): | |
| print(f"[ERROR] Training data not found: {input_path}") | |
| print("Create a plain text file with one sentence per line.") | |
| print("For bilingual (zh+en) tokenizer, mix Chinese and English text.") | |
| sys.exit(1) | |
| os.makedirs(output_dir, exist_ok=True) | |
| model_prefix = os.path.join(output_dir, "tokenizer") | |
| print(f"[Tokenizer] Training SentencePiece model...") | |
| print(f" Input: {input_path}") | |
| print(f" Vocab size: {vocab_size}") | |
| print(f" Model type: {model_type}") | |
| print(f" Output: {output_dir}/") | |
| # Special tokens for Fusion | |
| control_symbols = [ | |
| "<|pad|>", "<|start|>", "<|end|>", | |
| "<|think_depth_0|>", "<|think_depth_1|>", | |
| "<|think_depth_2|>", "<|think_depth_3|>", | |
| ] | |
| spm.SentencePieceTrainer.train( | |
| input=input_path, | |
| model_prefix=model_prefix, | |
| vocab_size=vocab_size, | |
| model_type=model_type, | |
| character_coverage=0.9995, # High coverage for CJK | |
| input_sentence_size=10000000, | |
| shuffle_input_sentence=True, | |
| control_symbols=control_symbols, | |
| unk_id=0, | |
| bos_id=1, | |
| eos_id=2, | |
| pad_id=3, | |
| byte_fallback=True, # Important for multilingual | |
| split_by_unicode_script=True, | |
| allow_whitespace_only_pieces=True, | |
| normalization_rule_name='identity', # Avoid nmt_nfkc precompiled charsmap issues | |
| ) | |
| model_path = os.path.join(output_dir, "tokenizer.model") | |
| vocab_path = os.path.join(output_dir, "tokenizer.vocab") | |
| print(f"\n[Done] Tokenizer trained successfully!") | |
| print(f" Model: {model_path}") | |
| print(f" Vocab: {vocab_path}") | |
| # Verify | |
| sp = spm.SentencePieceProcessor() | |
| sp.load(model_path) | |
| print(f" Actual vocab size: {sp.get_piece_size()}") | |
| # Test | |
| test_zh = "Fusion是一个开源大语言模型" | |
| test_en = "Fusion is an open-source language model" | |
| print(f"\n Test encode (zh): {test_zh}") | |
| print(f" -> {sp.encode(test_zh)}") | |
| print(f" Test encode (en): {test_en}") | |
| print(f" -> {sp.encode(test_en)}") | |
| def create_sample_training_data(output_path: str, num_lines: int = 100000): | |
| """Create sample training data for tokenizer (for testing only).""" | |
| import random | |
| print(f"[Sample Data] Creating sample training data: {output_path}") | |
| samples_zh = [ | |
| "人工智能是计算机科学的一个重要分支", | |
| "深度学习使用多层神经网络来模拟人脑", | |
| "自然语言处理帮助计算机理解人类语言", | |
| "机器学习使计算机能够从数据中学习", | |
| "大语言模型在文本生成任务中表现出色", | |
| "Transformer架构彻底改变了自然语言处理领域", | |
| "注意力机制是现代深度学习的核心组件", | |
| "预训练语言模型通过大规模语料学习语言知识", | |
| "微调技术使模型适应特定下游任务", | |
| "开源模型推动了人工智能技术的普及", | |
| ] | |
| samples_en = [ | |
| "Artificial intelligence is a branch of computer science", | |
| "Deep learning uses multi-layer neural networks", | |
| "Natural language processing helps computers understand language", | |
| "Machine learning enables computers to learn from data", | |
| "Large language models excel at text generation tasks", | |
| "The Transformer architecture revolutionized NLP", | |
| "Attention mechanisms are core components of modern deep learning", | |
| "Pre-trained models learn language knowledge from large corpora", | |
| "Fine-tuning adapts models to specific downstream tasks", | |
| "Open-source models promote the democratization of AI", | |
| ] | |
| with open(output_path, 'w', encoding='utf-8') as f: | |
| for _ in range(num_lines): | |
| if random.random() > 0.5: | |
| f.write(random.choice(samples_zh) + "\n") | |
| else: | |
| f.write(random.choice(samples_en) + "\n") | |
| print(f" Generated {num_lines} lines") | |
| def main(): | |
| parser = argparse.ArgumentParser(description="Train Fusion SentencePiece tokenizer") | |
| parser.add_argument("--input", type=str, default="data/tokenizer_train.txt", | |
| help="Path to training data (one sentence per line)") | |
| parser.add_argument("--vocab_size", type=int, default=100000, | |
| help="Vocabulary size (default: 100000)") | |
| parser.add_argument("--output", type=str, default="tokenizers/", | |
| help="Output directory") | |
| parser.add_argument("--model_type", type=str, default="unigram", | |
| choices=["unigram", "bpe"], help="Model type") | |
| parser.add_argument("--create_sample_data", action="store_true", | |
| help="Create sample training data for testing") | |
| args = parser.parse_args() | |
| if args.create_sample_data: | |
| create_sample_training_data(args.input) | |
| return | |
| train_tokenizer(args.input, args.vocab_size, args.output, args.model_type) | |
| if __name__ == "__main__": | |
| main() | |