Download src/imrnns/cli.py from yashsaxena21/IMRNNs: direct link, hf CLI and curl.
- Browser
- Download file 11.3 kB
-
https://huggingface.co/yashsaxena21/IMRNNs/resolve/main/src/imrnns/cli.py
- Command line
-
hf download hf://yashsaxena21/IMRNNs/src/imrnns/cli.py
-
curl -L -o cli.py https://huggingface.co/yashsaxena21/IMRNNs/resolve/main/src/imrnns/cli.py
11.3 kB
| from __future__ import annotations | |
| import argparse | |
| import json | |
| import sys | |
| from pathlib import Path | |
| from . import __version__ | |
| from .api import cache_embeddings, evaluate, run, train | |
| from .assets import default_assets_root, discover_cached_embeddings, discover_checkpoints, discover_repo_checkpoints | |
| from .hub import DEFAULT_REPO_ID, download_checkpoint | |
| def _add_dataset_args(parser: argparse.ArgumentParser) -> None: | |
| group = parser.add_mutually_exclusive_group(required=True) | |
| group.add_argument("--dataset", help="BEIR dataset name, such as scifact.") | |
| group.add_argument("--dataset-path", type=Path, help="Local BEIR-format dataset directory.") | |
| parser.add_argument("--datasets-dir", type=Path, help="BEIR download root (default: <assets>/datasets).") | |
| def _add_encoder_args(parser: argparse.ArgumentParser) -> None: | |
| parser.add_argument("--encoder", help="Built-in encoder alias: minilm, e5, or mpnet.") | |
| parser.add_argument("--encoder-model-name", help="Custom SentenceTransformers model name.") | |
| parser.add_argument("--embedding-dim", type=int, help="Required with --encoder-model-name.") | |
| parser.add_argument("--query-prefix", default="") | |
| parser.add_argument("--passage-prefix", default="") | |
| parser.add_argument("--encoder-revision", help="Optional immutable revision for a custom base encoder.") | |
| def _add_runtime_args(parser: argparse.ArgumentParser) -> None: | |
| parser.add_argument("--device", default="cpu") | |
| parser.add_argument("--assets-root", type=Path, default=default_assets_root()) | |
| parser.add_argument("--cache-dir", type=Path) | |
| parser.add_argument("--max-queries", type=int) | |
| parser.add_argument("--seed", type=int, default=42) | |
| def _dataset_values(args: argparse.Namespace) -> tuple[str, Path]: | |
| if args.dataset_path: | |
| path = args.dataset_path.resolve() | |
| return path.name, path.parent | |
| return args.dataset, args.datasets_dir or (args.assets_root / "datasets") | |
| def _encoder_label(args: argparse.Namespace) -> str: | |
| return args.encoder or args.encoder_model_name or "custom" | |
| def _cache_dir(args: argparse.Namespace, dataset: str) -> Path: | |
| return args.cache_dir or args.assets_root / f"cache_{_encoder_label(args).replace('/', '-')}_{dataset}" | |
| def _command_info(args: argparse.Namespace) -> int: | |
| print( | |
| json.dumps( | |
| { | |
| "version": __version__, | |
| "default_hugging_face_repo": DEFAULT_REPO_ID, | |
| "available_checkpoint": "minilm/scifact", | |
| "training_recipe": { | |
| "objective": "improvement-margin", | |
| "improvement_margin": 0.05, | |
| "hard_negatives": 63, | |
| "hard_negative_method": "dense", | |
| "hard_negative_pool": 100, | |
| "projector_initialization": "identity", | |
| "optimizer": "adam", | |
| "learning_rate": 1e-4, | |
| "weight_decay": 1e-5, | |
| "batch_size": 32, | |
| "epochs": 30, | |
| "patience": 7, | |
| "seed": 42, | |
| }, | |
| "supported_encoders": ["minilm", "e5", "mpnet"], | |
| }, | |
| indent=2, | |
| ) | |
| ) | |
| return 0 | |
| def _command_list_assets(args: argparse.Namespace) -> int: | |
| print( | |
| json.dumps( | |
| { | |
| "assets_root": str(args.assets_root), | |
| "cached_embeddings": [ | |
| item.__dict__ | {"path": str(item.path)} for item in discover_cached_embeddings(args.assets_root) | |
| ], | |
| "workspace_checkpoints": [ | |
| item.__dict__ | {"path": str(item.path)} for item in discover_checkpoints(args.assets_root) | |
| ], | |
| "repo_checkpoints": [ | |
| item.__dict__ | {"path": str(item.path)} | |
| for item in discover_repo_checkpoints(Path(__file__).resolve().parents[2]) | |
| ], | |
| }, | |
| indent=2, | |
| default=str, | |
| ) | |
| ) | |
| return 0 | |
| def _command_download(args: argparse.Namespace) -> int: | |
| downloaded = download_checkpoint( | |
| encoder=args.encoder, | |
| dataset=args.dataset, | |
| repo_id=args.repo_id, | |
| revision=args.revision, | |
| cache_dir=args.hub_cache_dir, | |
| ) | |
| print(json.dumps({"checkpoint": str(downloaded.checkpoint_path), "repo_id": downloaded.repo_id}, indent=2)) | |
| return 0 | |
| def _command_cache(args: argparse.Namespace) -> int: | |
| dataset, datasets_dir = _dataset_values(args) | |
| built = cache_embeddings( | |
| encoder=args.encoder, | |
| dataset=dataset, | |
| cache_dir=_cache_dir(args, dataset), | |
| datasets_dir=datasets_dir, | |
| device=args.device, | |
| encoder_model_name=args.encoder_model_name, | |
| embedding_dim=args.embedding_dim, | |
| query_prefix=args.query_prefix, | |
| passage_prefix=args.passage_prefix, | |
| encoder_revision=args.encoder_revision, | |
| batch_size=args.batch_size, | |
| num_negatives=args.num_negatives, | |
| negative_pool=args.negative_pool, | |
| max_queries=args.max_queries, | |
| seed=args.seed, | |
| ) | |
| print(json.dumps({"cache_dir": str(built), "dataset": dataset}, indent=2)) | |
| return 0 | |
| def _training_kwargs(args: argparse.Namespace) -> dict: | |
| dataset, datasets_dir = _dataset_values(args) | |
| return { | |
| "encoder": args.encoder, | |
| "dataset": dataset, | |
| "cache_dir": _cache_dir(args, dataset), | |
| "datasets_dir": datasets_dir, | |
| "output_dir": args.output_dir or args.assets_root, | |
| "device": args.device, | |
| "encoder_model_name": args.encoder_model_name, | |
| "embedding_dim": args.embedding_dim, | |
| "query_prefix": args.query_prefix, | |
| "passage_prefix": args.passage_prefix, | |
| "encoder_revision": args.encoder_revision, | |
| "max_queries": args.max_queries, | |
| "batch_size": args.batch_size, | |
| "epochs": args.epochs, | |
| "lr": args.lr, | |
| "weight_decay": args.weight_decay, | |
| "num_negatives": args.num_negatives, | |
| "feedback_k": args.candidate_k, | |
| "ranking_k": args.ranking_k, | |
| "k": args.k, | |
| "improvement_margin": args.improvement_margin, | |
| "patience": args.patience, | |
| "seed": args.seed, | |
| } | |
| def _print_result(payload: dict) -> int: | |
| print(json.dumps(payload, indent=2, default=str)) | |
| return 0 | |
| def _command_train(args: argparse.Namespace) -> int: | |
| return _print_result(train(**_training_kwargs(args))) | |
| def _command_run(args: argparse.Namespace) -> int: | |
| kwargs = _training_kwargs(args) | |
| kwargs["negative_pool"] = args.negative_pool | |
| return _print_result(run(**kwargs)) | |
| def _command_evaluate(args: argparse.Namespace) -> int: | |
| dataset, datasets_dir = _dataset_values(args) | |
| return _print_result( | |
| evaluate( | |
| encoder=args.encoder, | |
| dataset=dataset, | |
| cache_dir=_cache_dir(args, dataset), | |
| datasets_dir=datasets_dir, | |
| checkpoint_path=args.checkpoint, | |
| device=args.device, | |
| encoder_model_name=args.encoder_model_name, | |
| embedding_dim=args.embedding_dim, | |
| query_prefix=args.query_prefix, | |
| passage_prefix=args.passage_prefix, | |
| encoder_revision=args.encoder_revision, | |
| max_queries=args.max_queries, | |
| seed=args.seed, | |
| feedback_k=args.candidate_k, | |
| ranking_k=args.ranking_k, | |
| k=args.k, | |
| ) | |
| ) | |
| def _configure_training_parser(parser: argparse.ArgumentParser) -> None: | |
| _add_dataset_args(parser) | |
| _add_encoder_args(parser) | |
| _add_runtime_args(parser) | |
| parser.add_argument("--output-dir", type=Path) | |
| parser.add_argument("--batch-size", type=int, default=32) | |
| parser.add_argument("--epochs", type=int, default=30) | |
| parser.add_argument("--lr", type=float, default=1e-4) | |
| parser.add_argument("--weight-decay", type=float, default=1e-5) | |
| parser.add_argument("--num-negatives", type=int, default=63) | |
| parser.add_argument("--candidate-k", type=int, default=100) | |
| parser.add_argument("--ranking-k", type=int, default=10) | |
| parser.add_argument("--k", type=int, default=10) | |
| parser.add_argument("--improvement-margin", type=float, default=0.05) | |
| parser.add_argument("--patience", type=int, default=7) | |
| def build_parser() -> argparse.ArgumentParser: | |
| parser = argparse.ArgumentParser( | |
| prog="imrnns", | |
| description="Train, evaluate, and use IMRNN dense-retrieval adapters.", | |
| ) | |
| parser.add_argument("--version", action="version", version=f"%(prog)s {__version__}") | |
| subparsers = parser.add_subparsers(dest="command", required=True) | |
| info = subparsers.add_parser("info", help="Show package and recipe information.") | |
| info.set_defaults(func=_command_info) | |
| assets = subparsers.add_parser("list-assets", help="List local caches and checkpoints.") | |
| assets.add_argument("--assets-root", type=Path, default=default_assets_root()) | |
| assets.set_defaults(func=_command_list_assets) | |
| download = subparsers.add_parser("download", help="Download the validated adapter checkpoint.") | |
| download.add_argument("--encoder", required=True, choices=["minilm"]) | |
| download.add_argument("--dataset", required=True, choices=["scifact"]) | |
| download.add_argument("--repo-id", default=DEFAULT_REPO_ID) | |
| download.add_argument("--revision") | |
| download.add_argument("--hub-cache-dir", type=Path) | |
| download.set_defaults(func=_command_download) | |
| cache = subparsers.add_parser("cache", help="Encode a dataset and mine dense hard negatives.") | |
| _add_dataset_args(cache) | |
| _add_encoder_args(cache) | |
| _add_runtime_args(cache) | |
| cache.add_argument("--batch-size", type=int, default=64) | |
| cache.add_argument("--num-negatives", type=int, default=63) | |
| cache.add_argument("--negative-pool", type=int, default=100) | |
| cache.set_defaults(func=_command_cache) | |
| train_parser = subparsers.add_parser("train", help="Train an adapter from a prepared cache.") | |
| _configure_training_parser(train_parser) | |
| train_parser.set_defaults(func=_command_train) | |
| evaluate_parser = subparsers.add_parser("evaluate", help="Evaluate a checkpoint against its base retriever.") | |
| _add_dataset_args(evaluate_parser) | |
| _add_encoder_args(evaluate_parser) | |
| _add_runtime_args(evaluate_parser) | |
| evaluate_parser.add_argument("--checkpoint", type=Path, required=True) | |
| evaluate_parser.add_argument("--candidate-k", type=int, default=100) | |
| evaluate_parser.add_argument("--ranking-k", type=int, default=10) | |
| evaluate_parser.add_argument("--k", type=int, default=10) | |
| evaluate_parser.set_defaults(func=_command_evaluate) | |
| run_parser = subparsers.add_parser("run", help="Cache, train, and evaluate end to end.") | |
| _configure_training_parser(run_parser) | |
| run_parser.add_argument("--negative-pool", type=int, default=100) | |
| run_parser.set_defaults(func=_command_run) | |
| return parser | |
| def main(argv: list[str] | None = None) -> int: | |
| parser = build_parser() | |
| args = parser.parse_args(argv) | |
| try: | |
| return int(args.func(args)) | |
| except (FileNotFoundError, ImportError, RuntimeError, ValueError) as exc: | |
| print(f"imrnns: error: {exc}", file=sys.stderr) | |
| return 2 | |