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_SIZEand 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 --forceas 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.