Skip to content

Computer Vision Commands

Save Model Configuration

To write the model configuration to a vision.yml file you can run:

docker compose exec photoprism photoprism vision save

You can then configure the vision.yml file according to your specific needs.

View Model Configuration

You can use the following terminal command, to inspect your current model configuration:

docker compose exec photoprism photoprism vision ls

Command Options

You can combine it with these flags to change the output format:

Command Flag Description
--md, -m format as machine-readable Markdown
--csv, -c export as semicolon separated values
--tsv, -t export as tab separated values

Run Vision Models

Once you have configured your preferred computer vision models and services in the vision.yml file, you can use the following command to run a model on a set of pictures, as specified by the search filter:

photoprism vision run [options] [filter]

Command Options

Command Flag Description
--models MODELS, -m MODELS computer vision MODELS to run, e.g. caption, labels, or nsfw (default: "caption")
--count NUMBER, -n NUMBER maximum NUMBER of pictures to be processed (default: 100000)
--source TYPE, -s TYPE custom data source TYPE (auto, default, image, marker, ollama, openai, vision) (default: "auto")
--force, -f force existing data to be updated if the model supports it and the source priority is equal to or higher (default: false)
--dry-run print the matching pictures and exit without running the configured models (default: false)

To generate captions for all photos in your library, you can run:

docker compose exec photoprism photoprism vision run --models=caption

Note: Processing time will vary based on your library size and hardware performance and may take a considerable amount of time for large collections.

If you have a model for labels configured in your vision.yml you can run the following to generate labels:

docker compose exec photoprism photoprism vision run --models=labels

To generate captions only for photos matching a specific search filter such as those in a particular album, use the following command:

docker compose exec photoprism photoprism vision run --models=caption album:Holidays

To re-generate captions for photos that already have some, add the --force flag to your command:

docker compose exec photoprism photoprism vision run --models=caption --force

This is especially useful when testing different models or prompts. Note that the configured source must have an equal or higher priority than the source of the existing captions for them to be replaced.

Reset Vision Data

The photoprism vision reset command allows you to reset data generated by computer vision models for pictures that match the specified search filters. This is useful when you want to clear existing AI-generated data and start fresh, or when switching between different models.

photoprism vision reset [options] [filter]

Command Options

Command Flag Description
--models MODELS, -m MODELS computer vision MODELS to reset, e.g. caption or labels
--count NUMBER, -n NUMBER maximum NUMBER of pictures to be processed (default: 100000)
--source TYPE, -s TYPE custom data source TYPE (auto, default, image, marker, ollama, openai, vision) (default: "image")
--yes, -y runs the command non-interactively (default: false)

You must always specify the --source flag to reset data from a specific source. Without it, the command may not reset any pictures. Use the source that matches where your data came from (e.g., ollama or image).

Examples

To reset captions generated by Ollama for all photos in your library:

docker compose exec photoprism photoprism vision reset --models=caption --source=ollama --yes

To reset labels for photos in a specific album:

docker compose exec photoprism photoprism vision reset --models=labels --source=ollama album:TestAlbum

The --yes flag runs the command non-interactively without requiring confirmation. Omit this flag if you want to be prompted before the reset operation begins.

Regenerating captions deleted in the UI

If you removed captions in the Web UI, either on the edit or the batch edit dialog, the caption source becomes manual or batch. The photoprism vision reset command does not reset captions with source batch or manual.

To regenerate captions for these pictures, you need to run the caption model with source vision:

docker compose exec photoprism photoprism vision run --models=caption --source=vision

The vision source has a high priority (64), which allows it to replace empty captions with source manual and batch.

You can inspect all available sources and their priorities with:

docker compose exec photoprism photoprism vision sources show

Relevant caption-related sources currently have these priorities:

  • image: 8 (built-in TensorFlow models)
  • ollama: 16 (Ollama captions and labels)
  • openai: 16 (OpenAI captions and labels)
  • batch: 64 (batch edit in the UI)
  • vision: 64 (manual vision runs via CLI)
  • manual: 64 (captions edited directly in the UI)

Face Detection Commands

PhotoPrism provides specialized commands for managing face detection, clustering, and optimization. These commands are particularly useful when switching between detection engines or troubleshooting face recognition issues.

Index Faces

Detect faces in your photos:

docker compose exec photoprism photoprism faces index [subfolder]

Show the Effective Status

Many face options resolve their default from the detector or embedding model in use rather than from a fixed number, so the value in force is not always the value in your configuration file. This prints what actually applies, grouped into Global Options, Face Detection, and Face Recognition:

docker compose exec photoprism photoprism faces status

faces config and faces doctor are aliases of the same command.

Above the tables, the report states in prose whether detection and recognition are enabled, which detector and model are in force, and โ€” when no clusters are forming โ€” why automatic clustering is waiting. It distinguishes two cases that look identical from the outside:

  • Not enough new markers yet. The report names how many are needed, how many there are, and how many clear FACE_CLUSTER_SIZE and the per-detector score bar.
  • Markers exist, but none is newer than the last cluster. An automatic pass counts only markers added since the newest cluster it produced, so a library in this state never restarts on its own. The report names photoprism faces update --force as the fix.

Inspect People, Clusters, and Markers

Three read-only reports answer the questions that come up while tuning: who the index knows, how a person's faces are grouped, and what an individual marker is assigned to. Each prints a table by default and takes --json, --md, --csv, or --tsv, plus --count and --offset.

faces subjects lists people with the clusters, files, and photos their markers support:

docker compose exec photoprism photoprism faces subjects
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚     Subject      โ”‚      Name       โ”‚  Src   โ”‚ Favorite โ”‚ Verified โ”‚ Hidden โ”‚ Markers โ”‚ Clusters โ”‚ Files โ”‚ Photos โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ jr0mfat18xr5vtz7 โ”‚ Alex WG         โ”‚ manual โ”‚ Yes      โ”‚ No       โ”‚ No     โ”‚ 26      โ”‚ 1        โ”‚ 26    โ”‚ 26     โ”‚
โ”‚ jr0mhi623g3jd2s6 โ”‚ Alina Levshin   โ”‚ manual โ”‚ No       โ”‚ No       โ”‚ No     โ”‚ 8       โ”‚ 1        โ”‚ 8     โ”‚ 8      โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

The counts are computed when the report runs. Pass --stored to print the numbers the index holds instead โ€” the two diverging tells you the stored counts are stale.

Clusters is the fragmentation figure. One person legitimately holds several clusters, because automatic clusters are never merged with one another; a count that keeps climbing across runs is the signal that clustering is splitting too aggressively.

faces ls (alias faces clusters) lists the clusters themselves:

docker compose exec photoprism photoprism faces ls
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚               Face               โ”‚      Name      โ”‚ Src  โ”‚  Kind   โ”‚ Markers โ”‚ Samples โ”‚ Radius โ”‚ Collisions โ”‚ Collision Radius โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ I35N567BI4WXFMMEC73552I2ZSBDHRD6 โ”‚ Theresa Gresch โ”‚ auto โ”‚ regular โ”‚ 117     โ”‚ 2048    โ”‚ 0.420  โ”‚ 0          โ”‚ 0.000            โ”‚
โ”‚ AI4BTJI6DT35DT56HMUYJIBZ2HH4ZJRG โ”‚ Michael Mayer  โ”‚ auto โ”‚ regular โ”‚ 110     โ”‚ 469     โ”‚ 0.420  โ”‚ 0          โ”‚ 0.000            โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Samples is what the cluster was built from, while Markers is what currently points at it, so the two drift apart as matching runs. Radius is the extent the cluster accepts, and a non-zero Collision Radius means it was narrowed after competing with another person for the same face.

faces markers lists individual markers and what they are assigned to:

docker compose exec photoprism photoprism faces markers

Besides the shared options it takes --face ID to list one cluster's markers, and two filters for the shapes that come up in diagnosis: --unassigned for markers that have a person but no cluster, and --dangling for markers whose cluster no longer exists.

All three accept a person as a positional argument, given either as a name or a subject UID, so a value from one report is the filter for the next:

docker compose exec photoprism photoprism faces ls "Alex WG"

Measure Embedding Distances

docker compose exec photoprism photoprism faces stats

Reports how far face embeddings sit from one another, which is what the clustering thresholds are measured against. It logs two distributions: the nearest and furthest neighbor of every sample, as min < median < max, and then the same spread within each person, over the clusters that take part in matching. Comparing the two is what says whether a threshold separates people or splits one.

This compares every sample with every other one, so its cost grows with the square of the library size. It is a diagnostic for a test library, not a routine report โ€” on a large library prefer faces status for configuration questions and faces ls for how a person is grouped.

Cluster and Match Faces

Run clustering and matching over the markers already in the index:

docker compose exec photoprism photoprism faces update

An ordinary run only considers markers added since the newest automatic cluster. To reconsider every marker in the library โ€” which is what faces status recommends when clustering has stalled โ€” pass --force:

docker compose exec photoprism photoprism faces update --force

Audit Face Data

Check the integrity of face embeddings and cluster statistics:

docker compose exec photoprism photoprism faces audit

To automatically fix normalization issues and update face distances:

docker compose exec photoprism photoprism faces audit --fix

To audit a specific person:

docker compose exec photoprism photoprism faces audit --subject=<person-uid>

This provides detailed information including:

  • Retry counts for cluster merging
  • Sample statistics
  • Outstanding clusters that need attention

Optimize Face Clusters

Run the clustering optimization algorithm to merge similar face clusters:

docker compose exec photoprism photoprism faces optimize

If you've manually cleaned up problematic clusters and want to retry merging:

docker compose exec photoprism photoprism faces optimize --retry

This clears retry counters and allows the optimizer to reprocess clusters that previously failed to merge.

Reset Face Detection

Clear all face data and start fresh:

docker compose exec photoprism photoprism faces reset

To regenerate markers with a specific detection model, name it with --detector:

docker compose exec photoprism photoprism faces reset --detector=yunet

Three levels of reset are available, and they differ in how much detection work has to be repeated:

Command Removes Keeps
faces reset automatic clusters and their matches markers, embeddings, manual names
faces reset --all additionally the people and names a person or sidecar set markers and embeddings
faces reset --force people, clusters, and markers nothing โ€” faces must be detected again

--all is the one to reach for when re-testing clustering parameters: because the markers and their embeddings survive, a following faces update re-clusters in seconds rather than re-detecting every file. --force is the only variant that requires detection to run again.

A person marked Verified in the Edit Person dialog keeps their row through --all, so the names you have settled on stay put across repeated re-clustering rounds and remain comparable between them.

--force cannot be combined with --detector or --all. The flags name different outcomes for the markers table, so the command refuses the combination rather than picking one.

The faces reset command will delete all existing face markers and clusters. Make sure you have backups if needed, as this operation cannot be undone.

Migrate Face Embeddings

Changing the embedding model is a migration rather than a configuration change, because vectors produced by different models cannot be compared. This command re-embeds every marker and records the target as the configured model:

docker compose exec photoprism photoprism faces migrate

It defaults to the model this release supports, so an ordinary migration needs no target. Name one with --to only when migrating somewhere else.

Run it with --dry-run first to see the scope without changing the index:

docker compose exec photoprism photoprism faces migrate --dry-run

The report names how many markers are valid, invalid, already on the target, unlinked, or identified manually, how many are assigned to a person and keep that assignment, and how many are too small or too low-scoring to seed a cluster. It warns separately when markers cannot be re-embedded because their file is missing or unreadable, and when the originals path is empty or unreadable โ€” which would otherwise look like a clean run right up until every file fails.

A dry run performs no detection: it answers from index queries alone and returns before any file is read, so FACE_MIGRATE_SCORE and FACE_MIGRATE_SIZE have no effect on it.

Re-Detection, and What a Migration Can Lose

A model that consumes landmark-aligned crops needs landmarks, and a marker an earlier detector placed does not carry any the current detector would have produced. So a migration to such a model re-detects each file and keeps a marker's vector only when the detector finds that face again.

Re-detection runs at its own floors, FACE_MIGRATE_SIZE and FACE_MIGRATE_SCORE, rather than at the indexing ones. The trade is inverted here: at index time a false positive costs a thumbnail to reject, while during a migration a miss costs a curated marker its vector. A re-found marker also has its score, size, landmarks_json, and detect_model rewritten together, because the clustering bar is looked up by detector โ€” a marker relabeled with the new detector while keeping the old one's score would be judged against a calibration it was never scored against.

Markers a person drew or named by hand keep their assignment either way; only the vector is lost, and only where re-detection failed.

When a run does lose vectors, it reports how much of that was human effort: how many of the lost markers carried a person assignment, and how many had a manual source. The two overlap rather than nest โ€” clearing a person's name from a marker leaves its source manual with no subject โ€” so do not add them together or read one as a subset of the other. Attrition among markers nobody ever touched is the ordinary outcome for a library an earlier detector indexed; these two counts are what says whether a detection floor was worth its cost.

The dry run's "identified manually" figure is counted the same way and additionally includes invalid markers, which a migration never walks. A smaller number in the result is therefore expected, not a sign that something went missing.

Two guards act on the result:

  • The finalize guard refuses a destructive finalize when more than 10% of the markers that clear both clustering bars lost their vector. Markers below those bars are deliberately excluded from the ratio, because they seed no cluster and join none โ€” counting them made a detector that re-finds fewer weak faces look like a storage fault.
  • The exit status is non-zero whenever any marker lost its vector, not only a clusterable one. A run that discarded a large share of a library below the clustering bars would otherwise be indistinguishable from a clean run to anything checking the exit code.

Use --force to finalize a migration even when some markers could not be re-embedded.

Stop the server before migrating. The migration replaces every face cluster in a single transaction, and its worker guards cannot account for what a running instance writes to the same rows.

Learn more about face recognition โ€บ