| --- |
| language: ro |
| license: mit |
| tags: |
| - ocr |
| - handwritten-text-recognition |
| - vision |
| - transformer |
| - pytorch |
| - custom-architecture |
| model_name: Socrate (SocrateX cat) |
| library_name: socratex |
| --- |
| |
| # Socrate β OCR Transformer Model |
|
|
| **Main model fully coded by me. Parameters: 159,207,935** |
|
|
| Socrate is a custom Transformer-based OCR model trained to read printed and handwritten text from images. |
| Built with the **SocrateX** library β a modular, easy-to-use training framework for OCR. |
|
|
| --- |
|
|
| ## Quick Start β Use the Pre-trained Model |
|
|
| ```python |
| from transformers import AutoModel |
| from huggingface_hub import hf_hub_download |
| |
| # Load pre-trained Socrate (159M) directly from HuggingFace |
| model = AutoModel.from_pretrained("ihatebaselines/Socrate", trust_remote_code=True) |
| |
| # Load the tokenizer |
| tok_path = hf_hub_download("ihatebaselines/Socrate", "ocr_bpe_tokenizer.json") |
| tokenizer = model.make_tokenizer(tok_path) |
| |
| # Run OCR on an image |
| results = model.predict(["your_image.jpg"], function="generate", max_iter=64) |
| print(results) |
| ``` |
|
|
| --- |
|
|
| ## Quick Start β Build Your Own Custom Model (no pretrained weights) |
|
|
| No need to install SocrateX separately. Everything is built into the model object. |
|
|
| ```python |
| from transformers import AutoModel |
| |
| # Load model from HuggingFace (only needed to access the class + tokenizer) |
| model = AutoModel.from_pretrained("ihatebaselines/Socrate", trust_remote_code=True) |
| |
| # 1. Create your own architecture config |
| cfg = model.create_config( |
| d_model=256, |
| nhead=4, |
| num_layers=4, |
| dim_feedforward=1024, |
| pool_height=4 |
| ) |
| |
| # 2. Create a tokenizer |
| tok = model.make_tokenizer() # fresh tokenizer |
| # or load an existing one: |
| # tok = model.make_tokenizer("ocr_bpe_tokenizer.json") |
| |
| # 3. Build a brand-new model from your config (no pretrained weights) |
| my_model = model.new(config=cfg, tokenizer=tok, device="cuda") |
| |
| total_params = sum(p.numel() for p in my_model.parameters()) |
| print(f"Your model has {total_params:,} parameters") |
| |
| # 4. Load your dataset |
| images, labels = my_model.load_data("your_label.csv") |
| |
| # 5. Build a dataset + DataLoader |
| import torch |
| from torch.utils.data import DataLoader |
| |
| dataset = my_model.make_dataset(images, labels) |
| loader = DataLoader(dataset, batch_size=16, shuffle=True) |
| |
| # 6. Train |
| optimizer = torch.optim.AdamW(my_model.parameters(), lr=1e-4) |
| criterion = torch.nn.CrossEntropyLoss(ignore_index=tok.token_to_id("<pad>")) |
| |
| trainer = my_model.make_trainer(loader, optimizer, criterion) |
| for epoch in range(50): |
| loss = trainer.train_epoch() |
| print(f"Epoch {epoch} | Loss: {loss:.4f}") |
| |
| # 7. Run inference |
| results = my_model.predict(["test.jpg"], function="generate", max_iter=64) |
| print(results) |
| ``` |
|
|
| --- |
|
|
| ## Full API β All Methods on the Model Object |
|
|
| Once loaded with `AutoModel.from_pretrained`, the model exposes the entire SocrateX API: |
|
|
| | Method | Description | |
| |--------|-------------| |
| | `model.predict(images, ...)` | Run OCR inference on a list of image paths | |
| | `model.fit(dataloader, optimizer, criterion, ...)` | Train the model for N epochs | |
| | `model.make_dataset(images, labels, ...)` | Create a `Makeset` dataset object | |
| | `model.create_config(d_model, nhead, ...)` | Create a custom architecture config | |
| | `model.new(config, tokenizer, device)` | Build a new model from scratch with your config | |
| | `model.make_tokenizer(path=None)` | Load or create a BPE tokenizer | |
| | `model.make_trainer(loader, optimizer, criterion)` | Returns a `Trainer` wired to this model | |
| | `model.load_data(path)` | Load images + labels from CSV/JSON/TXT | |
| | `model.generate_data(source, count, output_dir, mode)` | Generate synthetic training data | |
| | `model.freeze_encoder()` | Freeze CNN + Encoder weights (fine-tuning) | |
| | `model.unfreeze_encoder()` | Unfreeze encoder weights | |
| | `model.load_parameters(path)` | Load weights from a `.pt` checkpoint | |
| | `model.summary()` | Print total/trainable parameter counts | |
|
|
| --- |
|
|
| ## Architecture Presets |
|
|
| | Model | Params | Notes | |
| |-------|--------|-------| |
| | `cat` | 159M | This checkpoint (d_model=640, 12 layers) | |
| | `rat` | ~80M | d_model=512, 8 layers | |
| | `mice` | ~40M | d_model=384, 6 layers | |
| | Custom via `create_config` | Your choice | Full control | |
|
|
| --- |
|
|
| ## `create_config` β All Parameters |
| |
| ```python |
| cfg = model.create_config( |
| d_model=640, # Transformer hidden dimension |
| nhead=10, # Multi-head attention heads |
| num_layers=12, # Number of Transformer layers |
| dim_feedforward=2560, # FFN hidden dimension (usually 4 * d_model) |
| activation="gelu", # Activation function |
| norm_first=True, # Pre-LayerNorm (modern Transformers) |
| max_len=512, # Max sequence length |
| pool_height=4 # SocratePool height (AdaptiveMaxPool2d) |
| ) |
| ``` |
| |
| --- |
|
|
| ## Inference Functions |
|
|
| ```python |
| # Simple greedy generation (fast, good quality) |
| results = model.predict(images, function="generate", max_iter=64, temp=0.7, top_k=5, penalty=1.15) |
| |
| # Faster generation (less accurate but quicker) |
| results = model.predict(images, function="generate_fast", max_iter=64) |
| |
| # Beam search (most accurate) |
| results = model.predict(images, function="beam_search", max_iter=64, beam_width=4) |
| ``` |
|
|
| --- |
|
|
| ## Generate Synthetic Training Data |
|
|
| ```python |
| model.generate_data( |
| source="https://raw.githubusercontent.com/first20hours/google-10000-english/master/google-10000-english-no-swears.txt", |
| count=1000, |
| output_dir="my_train_data", |
| mode="train" # or "test" |
| ) |
| images, labels = model.load_data("my_train_data/labels.csv") |
| ``` |
|
|
| --- |
|
|
| ## Using the SocrateX Library Directly |
|
|
| If you prefer to use SocrateX as a standalone library (e.g. in a training script), the API is identical β just `import SocrateX as sx`. |
|
|
| ```python |
| import SocrateX as sx |
| import torch |
| from torch.utils.data import DataLoader |
| |
| # βββ 1. Tokenizer ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ |
| tokenizer = sx.load_tokenizer("ocr_bpe_tokenizer.json") |
| # or build a fresh one: |
| # tokenizer = sx.init_tokenizer() |
| |
| # βββ 2. Config βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ |
| config = sx.Config( |
| d_model=640, |
| nhead=10, |
| num_layers=12, |
| dim_feedforward=2560, |
| pool_height=4 |
| ) |
| |
| # βββ 3. Model ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ |
| model = sx.init(config=config, tokenizer=tokenizer, device="cuda") |
| # or use a preset: |
| # model = sx.cat(tokenizer=tokenizer, weights="previous.pt", device="cuda") |
| # model = sx.rat(tokenizer=tokenizer, device="cuda") |
| # model = sx.mice(tokenizer=tokenizer, device="cuda") |
| |
| # βββ 4. Dataset ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ |
| images, labels = sx.load_dataset("label.csv") |
| dataset = sx.Makeset(images, labels, tokenizer=tokenizer) |
| sampler = sx.SmartBatchSampler(labels, batch_size=32) |
| loader = DataLoader(dataset, batch_sampler=sampler) |
| |
| # βββ 5. Train ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ |
| optimizer = torch.optim.AdamW(model.parameters(), lr=1e-4) |
| criterion = torch.nn.CrossEntropyLoss(ignore_index=tokenizer.token_to_id("<pad>")) |
| |
| trainer = sx.Trainer(model, loader, optimizer, criterion, device="cuda") |
| for epoch in range(50): |
| loss = trainer.train_epoch() |
| print(f"Epoch {epoch} | Loss: {loss:.4f}") |
| |
| # βββ 6. Inference ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ |
| results = model.predict( |
| image_paths=["receipt.jpg", "document.png"], |
| function="generate", |
| max_iter=64, |
| temp=0.5, |
| top_k=5, |
| penalty=1.15 |
| ) |
| print(results) |
| |
| # βββ 7. Synthetic Data βββββββββββββββββββββββββββββββββββββββββββββββββββββββ |
| sx.generate_silly_training_set( |
| source="https://raw.githubusercontent.com/first20hours/google-10000-english/master/google-10000-english-no-swears.txt", |
| count=1000, |
| output_dir="train_data" |
| ) |
| ``` |
|
|
| ### SocrateX Module Reference |
|
|
| | Module | What it does | |
| |--------|-------------| |
| | `sx.Config(...)` | Define custom architecture | |
| | `sx.init(config, tokenizer)` | Build model from scratch | |
| | `sx.cat / sx.rat / sx.mice` | Preset-sized models | |
| | `sx.load_tokenizer(path)` | Load BPE tokenizer from file | |
| | `sx.init_tokenizer()` | Build a fresh tokenizer | |
| | `sx.load_dataset(path)` | Load CSV/JSON/TXT β (images, labels) | |
| | `sx.Makeset(images, labels, ...)` | Create a PyTorch Dataset | |
| | `sx.SmartBatchSampler(labels, batch_size)` | Length-sorted batch sampler | |
| | `sx.Trainer(model, loader, opt, crit)` | Training loop wrapper | |
| | `sx.predict(...)` | Run inference on image list | |
| | `sx.generate(...)` | Greedy autoregressive generation | |
| | `sx.beam_search(...)` | Beam search decoding | |
| | `sx.generate_silly_training_set(...)` | Generate synthetic word images | |
|
|
|
|