arclm 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
arclm/__init__.py ADDED
@@ -0,0 +1,154 @@
1
+ """ArcLM - compact PyTorch language-model training and fine-tuning."""
2
+
3
+ import torch
4
+
5
+ from .config import Config, create_config
6
+ from .data import DataBundle, load_tokens, prepare_data, read_tokens, split_train_val
7
+ from .dataset import TextDataset, create_dataloader
8
+ from .diagnostics import (
9
+ ConceptBenchmarkCase,
10
+ ConceptBenchmarkResult,
11
+ DEFAULT_CONCEPT_BENCHMARKS,
12
+ LongContextResult,
13
+ MetricsReport,
14
+ TopKPrediction,
15
+ build_training_diagnostics_report,
16
+ calculate_metrics,
17
+ calculate_perplexity,
18
+ export_metrics_to_json,
19
+ export_metrics_to_markdown,
20
+ format_concept_benchmark_report,
21
+ format_long_context_results,
22
+ format_tokenizer_coverage_report,
23
+ format_top_k_predictions,
24
+ predict_top_k,
25
+ run_long_context_evaluation,
26
+ score_concept_relationships,
27
+ )
28
+ from .generator import Generator
29
+ from .inference import DEFAULT_MODEL_PATH, LoadedModel, load_model, predict
30
+ from .instruction_dataset import InstructionDataset, create_instruction_dataloader
31
+ from .logics import (
32
+ And,
33
+ Biconditional,
34
+ Implication,
35
+ Not,
36
+ Or,
37
+ Sentence,
38
+ Symbol,
39
+ model_check,
40
+ )
41
+ from .model import ArcLM, MiniGPT
42
+ from .pipeline import (
43
+ build_model,
44
+ build_trainer,
45
+ checkpoint_is_compatible_for_continue_training,
46
+ checkpoint_is_compatible_for_tuining,
47
+ create_epoch_checkpoint_callback,
48
+ load_compatible_checkpoint,
49
+ save_training_checkpoint,
50
+ )
51
+ from .pipeline_v2 import ModelAdapter, PreTrainedModelLoader, StoppingCriteria, UnifiedPipeline
52
+ from .regularization import (
53
+ EarlyStopping,
54
+ GeneralizationMonitor,
55
+ L1Regularization,
56
+ L2Regularization,
57
+ LabelSmoothing,
58
+ LearningRateScheduler,
59
+ MixupAugmentation,
60
+ )
61
+ from .tokenizer import SentencePieceTokenizer, Tokenizer, create_tokenizer, get_tokenizer_from_config
62
+ from .trainer import Trainer
63
+ from .utils import format_duration
64
+
65
+ __version__ = "0.1.0"
66
+ __author__ = "ArcLM Contributors"
67
+
68
+ __all__ = [
69
+ "ArcLM",
70
+ "MiniGPT",
71
+ "Config",
72
+ "create_config",
73
+ "Tokenizer",
74
+ "SentencePieceTokenizer",
75
+ "create_tokenizer",
76
+ "get_tokenizer_from_config",
77
+ "TextDataset",
78
+ "create_dataloader",
79
+ "DataBundle",
80
+ "load_tokens",
81
+ "prepare_data",
82
+ "read_tokens",
83
+ "split_train_val",
84
+ "Trainer",
85
+ "Generator",
86
+ "DEFAULT_MODEL_PATH",
87
+ "LoadedModel",
88
+ "load_model",
89
+ "predict",
90
+ "build_model",
91
+ "build_trainer",
92
+ "checkpoint_is_compatible_for_continue_training",
93
+ "checkpoint_is_compatible_for_tuining",
94
+ "create_epoch_checkpoint_callback",
95
+ "load_compatible_checkpoint",
96
+ "save_training_checkpoint",
97
+ "UnifiedPipeline",
98
+ "PreTrainedModelLoader",
99
+ "ModelAdapter",
100
+ "StoppingCriteria",
101
+ "build_training_diagnostics_report",
102
+ "calculate_metrics",
103
+ "calculate_perplexity",
104
+ "export_metrics_to_json",
105
+ "export_metrics_to_markdown",
106
+ "ConceptBenchmarkCase",
107
+ "ConceptBenchmarkResult",
108
+ "DEFAULT_CONCEPT_BENCHMARKS",
109
+ "LongContextResult",
110
+ "MetricsReport",
111
+ "TopKPrediction",
112
+ "format_concept_benchmark_report",
113
+ "format_long_context_results",
114
+ "format_tokenizer_coverage_report",
115
+ "format_top_k_predictions",
116
+ "predict_top_k",
117
+ "run_long_context_evaluation",
118
+ "score_concept_relationships",
119
+ "format_duration",
120
+ "L1Regularization",
121
+ "L2Regularization",
122
+ "EarlyStopping",
123
+ "LearningRateScheduler",
124
+ "GeneralizationMonitor",
125
+ "MixupAugmentation",
126
+ "LabelSmoothing",
127
+ "create_instruction_dataloader",
128
+ "InstructionDataset",
129
+ "Sentence",
130
+ "Symbol",
131
+ "Not",
132
+ "And",
133
+ "Or",
134
+ "Implication",
135
+ "Biconditional",
136
+ "model_check",
137
+ ]
138
+
139
+
140
+ def get_version():
141
+ return __version__
142
+
143
+
144
+ def list_available_models():
145
+ from pathlib import Path
146
+
147
+ models_dir = Path("models")
148
+ if not models_dir.exists():
149
+ return []
150
+ return sorted(path.stem for path in models_dir.glob("*.pth") if path.is_file())
151
+
152
+
153
+ def load_model_checkpoint(path: str, device_type: str):
154
+ return torch.load(path, map_location=torch.device(device_type))
arclm/api.py ADDED
@@ -0,0 +1,167 @@
1
+ """
2
+ ArcLM public API.
3
+
4
+ Example:
5
+ >>> from arclm import Config, UnifiedPipeline, load_model
6
+ >>> config = Config(embed_dim=128, learning_rate=1e-3)
7
+ >>> pipeline = UnifiedPipeline(config, mode="pre_training")
8
+ >>> pipeline.build(vocab_size=10000)
9
+ >>> results = pipeline.train(train_loader, num_epochs=5)
10
+ """
11
+
12
+ __version__ = "0.1.0"
13
+ __author__ = "ArcLM Contributors"
14
+ __all__ = [
15
+ # Core Configuration
16
+ "Config",
17
+
18
+ # Training API (P4-1)
19
+ "UnifiedPipeline",
20
+ "StoppingCriteria",
21
+ "PreTrainedModelLoader",
22
+ "ModelAdapter",
23
+
24
+ # Tokenizers (P4-2)
25
+ "create_tokenizer",
26
+ "get_tokenizer_from_config",
27
+ "Tokenizer",
28
+ "SentencePieceTokenizer",
29
+
30
+ # Metrics & Evaluation (P4-3)
31
+ "calculate_metrics",
32
+ "calculate_perplexity",
33
+ "export_metrics_to_json",
34
+ "export_metrics_to_markdown",
35
+ "MetricsReport",
36
+
37
+ # Model Loading (Inference)
38
+ "load_model",
39
+ "LoadedModel",
40
+ "predict",
41
+
42
+ # Advanced: Config Files & Experiment Tracking (P4-4 Advanced)
43
+ "load_config",
44
+ "load_config_yaml",
45
+ "load_config_json",
46
+ "save_config",
47
+ "save_config_yaml",
48
+ "save_config_json",
49
+ "ExperimentTracker",
50
+ "create_experiment",
51
+ "list_experiments",
52
+
53
+ # Utilities
54
+ "create_config",
55
+ ]
56
+
57
+ # Lazy imports for faster module loading
58
+ def __getattr__(name):
59
+ """Lazy load modules on first use"""
60
+ if name == "Config":
61
+ from .config import Config
62
+ return Config
63
+ elif name == "create_config":
64
+ from .config import create_config
65
+ return create_config
66
+ elif name == "UnifiedPipeline":
67
+ from .pipeline_v2 import UnifiedPipeline
68
+ return UnifiedPipeline
69
+ elif name == "StoppingCriteria":
70
+ from .pipeline_v2 import StoppingCriteria
71
+ return StoppingCriteria
72
+ elif name == "PreTrainedModelLoader":
73
+ from .pipeline_v2 import PreTrainedModelLoader
74
+ return PreTrainedModelLoader
75
+ elif name == "ModelAdapter":
76
+ from .pipeline_v2 import ModelAdapter
77
+ return ModelAdapter
78
+ elif name == "create_tokenizer":
79
+ from .tokenizer import create_tokenizer
80
+ return create_tokenizer
81
+ elif name == "get_tokenizer_from_config":
82
+ from .tokenizer import get_tokenizer_from_config
83
+ return get_tokenizer_from_config
84
+ elif name == "Tokenizer":
85
+ from .tokenizer import Tokenizer
86
+ return Tokenizer
87
+ elif name == "SentencePieceTokenizer":
88
+ from .tokenizer import SentencePieceTokenizer
89
+ return SentencePieceTokenizer
90
+ elif name == "calculate_metrics":
91
+ from .diagnostics import calculate_metrics
92
+ return calculate_metrics
93
+ elif name == "calculate_perplexity":
94
+ from .diagnostics import calculate_perplexity
95
+ return calculate_perplexity
96
+ elif name == "export_metrics_to_json":
97
+ from .diagnostics import export_metrics_to_json
98
+ return export_metrics_to_json
99
+ elif name == "export_metrics_to_markdown":
100
+ from .diagnostics import export_metrics_to_markdown
101
+ return export_metrics_to_markdown
102
+ elif name == "MetricsReport":
103
+ from .diagnostics import MetricsReport
104
+ return MetricsReport
105
+ elif name == "load_model":
106
+ from .inference import load_model
107
+ return load_model
108
+ elif name == "LoadedModel":
109
+ from .inference import LoadedModel
110
+ return LoadedModel
111
+ elif name == "predict":
112
+ from .inference import predict
113
+ return predict
114
+ elif name == "load_config":
115
+ from .config_loader import load_config
116
+ return load_config
117
+ elif name == "load_config_yaml":
118
+ from .config_loader import load_config_yaml
119
+ return load_config_yaml
120
+ elif name == "load_config_json":
121
+ from .config_loader import load_config_json
122
+ return load_config_json
123
+ elif name == "save_config":
124
+ from .config_loader import save_config
125
+ return save_config
126
+ elif name == "save_config_yaml":
127
+ from .config_loader import save_config_yaml
128
+ return save_config_yaml
129
+ elif name == "save_config_json":
130
+ from .config_loader import save_config_json
131
+ return save_config_json
132
+ elif name == "ExperimentTracker":
133
+ from .tracking import ExperimentTracker
134
+ return ExperimentTracker
135
+ elif name == "create_experiment":
136
+ from .tracking import create_experiment
137
+ return create_experiment
138
+ elif name == "list_experiments":
139
+ from .tracking import list_experiments
140
+ return list_experiments
141
+ else:
142
+ raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
143
+
144
+
145
+ def get_version():
146
+ """Get library version"""
147
+ return __version__
148
+
149
+
150
+ def list_available_models():
151
+ """
152
+ List available pre-trained model checkpoints.
153
+
154
+ Returns:
155
+ list: Available model names
156
+ """
157
+ from pathlib import Path
158
+ models_dir = Path(__file__).parent.parent / "models"
159
+
160
+ if not models_dir.exists():
161
+ return []
162
+
163
+ models = [
164
+ f.stem for f in models_dir.glob("*.pth")
165
+ if f.is_file()
166
+ ]
167
+ return sorted(models)
arclm/cli.py ADDED
@@ -0,0 +1,385 @@
1
+ """
2
+ ArcLM Command-Line Interface (CLI)
3
+
4
+ Provides command-line tools for training, evaluation, and generation.
5
+
6
+ Available Commands:
7
+ - arclm train : Train a model from scratch or fine-tune
8
+ - arclm eval : Evaluate model performance
9
+ - arclm generate : Generate text from a trained model
10
+
11
+ Usage:
12
+ arclm train --config config.yaml --data data.txt
13
+ arclm eval --model models/model.pth --data test.txt
14
+ arclm generate --model models/model.pth --prompt "Hello"
15
+ """
16
+
17
+ import argparse
18
+ import sys
19
+ import json
20
+ from pathlib import Path
21
+ from typing import Optional
22
+ import torch
23
+
24
+ from arclm import (
25
+ Config,
26
+ UnifiedPipeline,
27
+ calculate_metrics,
28
+ export_metrics_to_json,
29
+ export_metrics_to_markdown,
30
+ load_model,
31
+ create_tokenizer,
32
+ TextDataset,
33
+ create_dataloader,
34
+ )
35
+ from arclm.config_loader import load_config_yaml, load_config_json
36
+
37
+
38
+ def create_train_parser(subparsers):
39
+ """Create parser for arclm train command"""
40
+ parser = subparsers.add_parser(
41
+ "train",
42
+ help="Train a model from scratch or fine-tune",
43
+ description="Train ArcLM model with configuration file or CLI arguments"
44
+ )
45
+
46
+ # Config input
47
+ parser.add_argument(
48
+ "--config", type=str, default=None,
49
+ help="Path to config file (YAML or JSON) - overrides CLI args"
50
+ )
51
+
52
+ # Model config
53
+ parser.add_argument("--embed-dim", type=int, default=128, help="Embedding dimension")
54
+ parser.add_argument("--num-blocks", type=int, default=4, help="Number of transformer blocks")
55
+ parser.add_argument("--block-size", type=int, default=512, help="Context window size")
56
+ parser.add_argument("--num-heads", type=int, default=4, help="Number of attention heads")
57
+ parser.add_argument("--learning-rate", type=float, default=1e-3, help="Learning rate")
58
+
59
+ # Training config
60
+ parser.add_argument("--batch-size", type=int, default=16, help="Batch size")
61
+ parser.add_argument("--epochs", type=int, default=5, help="Number of epochs")
62
+ parser.add_argument("--mode", type=str, default="pre_training",
63
+ choices=["pre_training", "fine_tuning", "instruction_tuning"],
64
+ help="Training mode")
65
+
66
+ # Data & checkpoint
67
+ parser.add_argument("--data", type=str, required=True, help="Path to training data file")
68
+ parser.add_argument("--output", type=str, default="models/trained_model.pth",
69
+ help="Output model checkpoint path")
70
+ parser.add_argument("--pretrained", type=str, default=None,
71
+ help="Path to pre-trained model (for fine-tuning)")
72
+
73
+ # Logging & tracking
74
+ parser.add_argument("--experiment", type=str, default=None,
75
+ help="Experiment name (for tracking)")
76
+ parser.add_argument("--log-dir", type=str, default="logs",
77
+ help="Directory for logs and reports")
78
+
79
+ parser.set_defaults(func=train_command)
80
+ return parser
81
+
82
+
83
+ def create_eval_parser(subparsers):
84
+ """Create parser for arclm eval command"""
85
+ parser = subparsers.add_parser(
86
+ "eval",
87
+ help="Evaluate model performance",
88
+ description="Evaluate trained model on validation/test data"
89
+ )
90
+
91
+ parser.add_argument("--model", type=str, required=True,
92
+ help="Path to trained model checkpoint")
93
+ parser.add_argument("--data", type=str, required=True,
94
+ help="Path to evaluation data")
95
+ parser.add_argument("--config", type=str, default=None,
96
+ help="Path to config file (if not in model checkpoint)")
97
+ parser.add_argument("--output", type=str, default="metrics_report.json",
98
+ help="Output metrics file")
99
+ parser.add_argument("--batch-size", type=int, default=32,
100
+ help="Batch size for evaluation")
101
+ parser.add_argument("--device", type=str, default="auto",
102
+ choices=["cpu", "cuda", "auto"],
103
+ help="Device to use for evaluation")
104
+
105
+ parser.set_defaults(func=eval_command)
106
+ return parser
107
+
108
+
109
+ def create_generate_parser(subparsers):
110
+ """Create parser for arclm generate command"""
111
+ parser = subparsers.add_parser(
112
+ "generate",
113
+ help="Generate text from trained model",
114
+ description="Use trained model to generate text"
115
+ )
116
+
117
+ parser.add_argument("--model", type=str, required=True,
118
+ help="Path to trained model checkpoint")
119
+ parser.add_argument("--prompt", type=str, required=True,
120
+ help="Prompt to generate from")
121
+ parser.add_argument("--length", type=int, default=100,
122
+ help="Number of tokens to generate")
123
+ parser.add_argument("--temperature", type=float, default=1.0,
124
+ help="Sampling temperature (higher = more random)")
125
+ parser.add_argument("--num-samples", type=int, default=1,
126
+ help="Number of samples to generate")
127
+ parser.add_argument("--device", type=str, default="auto",
128
+ choices=["cpu", "cuda", "auto"],
129
+ help="Device to use for generation")
130
+
131
+ parser.set_defaults(func=generate_command)
132
+ return parser
133
+
134
+
135
+ def train_command(args):
136
+ """Execute training"""
137
+ print("\n" + "="*70)
138
+ print("ArcLM Training")
139
+ print("="*70)
140
+
141
+ # Load config
142
+ if args.config:
143
+ print(f"\nšŸ“‚ Loading config from: {args.config}")
144
+ if args.config.endswith(".yaml") or args.config.endswith(".yml"):
145
+ config = load_config_yaml(args.config)
146
+ elif args.config.endswith(".json"):
147
+ config = load_config_json(args.config)
148
+ else:
149
+ print(f"āŒ Unknown config format: {args.config}")
150
+ return 1
151
+ else:
152
+ print("\nāš™ļø Creating config from CLI arguments")
153
+ config = Config(
154
+ embed_dim=args.embed_dim,
155
+ num_blocks=args.num_blocks,
156
+ block_size=args.block_size,
157
+ num_heads=args.num_heads,
158
+ learning_rate=args.learning_rate,
159
+ batch_size=args.batch_size,
160
+ )
161
+
162
+ print(f"āœ“ Config loaded: {config.embed_dim}D, {config.num_blocks} blocks")
163
+
164
+ # Load data
165
+ try:
166
+ print(f"\nšŸ“Š Loading data from: {args.data}")
167
+ with open(args.data, "r") as f:
168
+ text = f.read()
169
+
170
+ tokenizer = create_tokenizer("word", max_vocab=10000)
171
+ dataset = TextDataset(text, tokenizer, seq_len=config.block_size)
172
+ train_loader = create_dataloader(dataset, batch_size=config.batch_size)
173
+ print(f"āœ“ Data loaded: {len(dataset)} samples")
174
+ except FileNotFoundError:
175
+ print(f"āŒ Data file not found: {args.data}")
176
+ return 1
177
+ except Exception as e:
178
+ print(f"āŒ Error loading data: {e}")
179
+ return 1
180
+
181
+ # Create pipeline
182
+ print(f"\nšŸ”§ Creating pipeline (mode: {args.mode})")
183
+ pipeline = UnifiedPipeline(config, mode=args.mode)
184
+
185
+ # Load pretrained if needed
186
+ if args.pretrained:
187
+ print(f"šŸ“¦ Loading pre-trained model: {args.pretrained}")
188
+ from arclm import PreTrainedModelLoader
189
+ loader = PreTrainedModelLoader(args.pretrained)
190
+ model, _ = loader.load()
191
+ pipeline.build(vocab_size=tokenizer.max_vocab, pretrained_model=model)
192
+ else:
193
+ pipeline.build(vocab_size=tokenizer.max_vocab)
194
+
195
+ print("āœ“ Pipeline ready")
196
+
197
+ # Train
198
+ print(f"\nšŸš€ Starting training ({args.epochs} epochs)...")
199
+ try:
200
+ results = pipeline.train(train_loader, num_epochs=args.epochs)
201
+ print(f"āœ“ Training complete!")
202
+ print(f" - Final loss: {results['final_loss']:.4f}")
203
+ except Exception as e:
204
+ print(f"āŒ Training error: {e}")
205
+ return 1
206
+
207
+ # Save model
208
+ output_path = Path(args.output)
209
+ output_path.parent.mkdir(parents=True, exist_ok=True)
210
+ torch.save(pipeline.model.state_dict(), output_path)
211
+ print(f"\nšŸ’¾ Model saved to: {output_path}")
212
+
213
+ # Save config
214
+ config_path = output_path.parent / "config.json"
215
+ with open(config_path, "w") as f:
216
+ json.dump(config.to_dict(), f, indent=2)
217
+ print(f"šŸ’¾ Config saved to: {config_path}")
218
+
219
+ # Log experiment
220
+ if args.experiment:
221
+ log_dir = Path(args.log_dir) / args.experiment
222
+ log_dir.mkdir(parents=True, exist_ok=True)
223
+
224
+ log_file = log_dir / "training_log.json"
225
+ with open(log_file, "w") as f:
226
+ json.dump({
227
+ "model_path": str(output_path),
228
+ "config_path": str(config_path),
229
+ "final_loss": float(results["final_loss"]),
230
+ "epochs": args.epochs,
231
+ }, f, indent=2)
232
+ print(f"šŸ“ Experiment logged: {log_file}")
233
+
234
+ print("\n" + "="*70 + "\n")
235
+ return 0
236
+
237
+
238
+ def eval_command(args):
239
+ """Execute evaluation"""
240
+ print("\n" + "="*70)
241
+ print("ArcLM Evaluation")
242
+ print("="*70)
243
+
244
+ # Load model
245
+ try:
246
+ print(f"\nšŸ“¦ Loading model from: {args.model}")
247
+ model = load_model(args.model, device=args.device)
248
+ print("āœ“ Model loaded")
249
+ except FileNotFoundError:
250
+ print(f"āŒ Model file not found: {args.model}")
251
+ return 1
252
+ except Exception as e:
253
+ print(f"āŒ Error loading model: {e}")
254
+ return 1
255
+
256
+ # Load config
257
+ if args.config:
258
+ if args.config.endswith(".yaml"):
259
+ config = load_config_yaml(args.config)
260
+ else:
261
+ config = load_config_json(args.config)
262
+ else:
263
+ config_path = Path(args.model).parent / "config.json"
264
+ if config_path.exists():
265
+ config = load_config_json(str(config_path))
266
+ else:
267
+ print("āš ļø Config not found, using defaults")
268
+ config = Config()
269
+
270
+ # Load data
271
+ try:
272
+ print(f"\nšŸ“Š Loading data from: {args.data}")
273
+ with open(args.data, "r") as f:
274
+ text = f.read()
275
+
276
+ tokenizer = create_tokenizer("word", max_vocab=10000)
277
+ dataset = TextDataset(text, tokenizer, seq_len=config.block_size)
278
+ val_loader = create_dataloader(dataset, batch_size=args.batch_size)
279
+ print(f"āœ“ Data loaded: {len(dataset)} samples")
280
+ except Exception as e:
281
+ print(f"āŒ Error loading data: {e}")
282
+ return 1
283
+
284
+ # Evaluate
285
+ print(f"\nšŸ“ˆ Evaluating...")
286
+ try:
287
+ device = torch.device("cuda" if args.device == "auto" and torch.cuda.is_available() else args.device)
288
+ metrics = calculate_metrics(model.model, val_loader, config, device)
289
+
290
+ print(f"āœ“ Evaluation complete!")
291
+ print(f" - Perplexity: {metrics.perplexity:.4f}")
292
+ print(f" - Loss: {metrics.avg_loss:.4f}")
293
+ print(f" - Accuracy: {metrics.accuracy:.4%}")
294
+ print(f" - Tokens: {metrics.total_tokens}")
295
+ except Exception as e:
296
+ print(f"āŒ Evaluation error: {e}")
297
+ return 1
298
+
299
+ # Save metrics
300
+ output_path = Path(args.output)
301
+ output_path.parent.mkdir(parents=True, exist_ok=True)
302
+ export_metrics_to_json(metrics, str(output_path))
303
+ print(f"\nšŸ’¾ Metrics saved to: {output_path}")
304
+
305
+ # Also save markdown report
306
+ report_path = output_path.with_suffix(".md")
307
+ export_metrics_to_markdown(metrics, str(report_path))
308
+ print(f"šŸ“ Report saved to: {report_path}")
309
+
310
+ print("\n" + "="*70 + "\n")
311
+ return 0
312
+
313
+
314
+ def generate_command(args):
315
+ """Execute text generation"""
316
+ print("\n" + "="*70)
317
+ print("ArcLM Text Generation")
318
+ print("="*70)
319
+
320
+ # Load model
321
+ try:
322
+ print(f"\nšŸ“¦ Loading model from: {args.model}")
323
+ model = load_model(args.model, device=args.device)
324
+ print("āœ“ Model loaded")
325
+ except FileNotFoundError:
326
+ print(f"āŒ Model file not found: {args.model}")
327
+ return 1
328
+ except Exception as e:
329
+ print(f"āŒ Error loading model: {e}")
330
+ return 1
331
+
332
+ print(f"\nāœļø Prompt: {args.prompt}")
333
+ print(f"šŸ“ Generating {args.length} tokens (temperature={args.temperature})...")
334
+
335
+ try:
336
+ for i in range(args.num_samples):
337
+ result = model.predict(
338
+ args.prompt,
339
+ max_new_tokens=args.length,
340
+ temperature=args.temperature
341
+ )
342
+
343
+ if args.num_samples > 1:
344
+ print(f"\n--- Sample {i+1} ---")
345
+ print(result)
346
+ except Exception as e:
347
+ print(f"āŒ Generation error: {e}")
348
+ return 1
349
+
350
+ print("\n" + "="*70 + "\n")
351
+ return 0
352
+
353
+
354
+ def main():
355
+ """Main CLI entry point"""
356
+ parser = argparse.ArgumentParser(
357
+ description="ArcLM - command-line tools for training and inference",
358
+ formatter_class=argparse.RawDescriptionHelpFormatter,
359
+ epilog="""
360
+ Examples:
361
+ arclm train --config config.yaml --data data.txt --output models/model.pth
362
+ arclm eval --model models/model.pth --data test.txt
363
+ arclm generate --model models/model.pth --prompt "The future is"
364
+ """
365
+ )
366
+
367
+ parser.add_argument("--version", action="version", version="arclm 0.1.0")
368
+
369
+ subparsers = parser.add_subparsers(title="commands", dest="command")
370
+
371
+ create_train_parser(subparsers)
372
+ create_eval_parser(subparsers)
373
+ create_generate_parser(subparsers)
374
+
375
+ args = parser.parse_args()
376
+
377
+ if not hasattr(args, "func"):
378
+ parser.print_help()
379
+ return 0
380
+
381
+ return args.func(args)
382
+
383
+
384
+ if __name__ == "__main__":
385
+ sys.exit(main())