A local model directory turns a trained Sentence Transformers model into an artifact that another process can load without the original Python object. The directory carries the transformer, tokenizer, pooling configuration, and model metadata needed to reproduce the same embedding behavior.

The SentenceTransformer.save_pretrained() method writes the complete model layout and uses .safetensors weights by default. Passing that directory to a new SentenceTransformer() instance restores the modules described by modules.json, while local_files_only=True prevents the reload from retrieving missing files from the Hugging Face Hub.

The comparison uses the same two texts before and after the handoff. Matching shapes and numerically equal embeddings prove that the saved directory can replace the in-memory source model for later inference.

Steps to save and reload a Sentence Transformers model:

  1. Create save_reload.py with the source model ID, saved-model path, and comparison texts.
    save_reload.py
    from pathlib import Path
     
    import numpy as np
    from sentence_transformers import SentenceTransformer
     
     
    model_id = "sentence-transformers/all-MiniLM-L6-v2"
    save_path = Path("models/support-embeddings")
    texts = [
        "reset a forgotten password",
        "send a password recovery email",
    ]

    A new model artifact needs an empty path so files from an older export cannot remain beside the new weights and configuration.

  2. Add the source-model encoding block beneath the texts list.
    source_model = SentenceTransformer(model_id)
    before = source_model.encode(texts, show_progress_bar=False)
  3. Add the save and local-only reload block beneath the source encoding.
    source_model.save_pretrained(
        str(save_path),
        safe_serialization=True,
    )
    reloaded_model = SentenceTransformer(
        str(save_path),
        local_files_only=True,
    )
    after = reloaded_model.encode(
        texts,
        show_progress_bar=False,
    )

    safe_serialization=True writes .safetensors weights. local_files_only=True makes an incomplete local export fail instead of silently downloading a missing component.

  4. Add the embedding comparison and result output beneath the reloaded encoding.
    max_abs_diff = float(np.max(np.abs(before - after)))
    if before.shape != after.shape:
        raise SystemExit("embedding shape changed after reload")
    if not np.allclose(
        before,
        after,
        rtol=1e-5,
        atol=1e-6,
    ):
        raise SystemExit("embedding values changed after reload")
     
    print(f"saved model: {save_path}")
    print("local-only reload: passed")
    print(f"embedding shape: {after.shape}")
    print(f"max absolute difference: {max_abs_diff:.8f}")

    The comparison can fail on either a changed embedding shape or values outside the stated floating-point tolerance, so a printed pass is tied to the reloaded model's actual output.

  5. Run save_reload.py to verify that the saved model reloads locally with matching embeddings.
    $ python save_reload.py
    saved model: models/support-embeddings
    local-only reload: passed
    embedding shape: (2, 384)
    max absolute difference: 0.00000000

    The models/support-embeddings directory remains the reusable model artifact. The first line identifies the directory that a later process should pass to SentenceTransformer().