internal/ai/classify/README.md
Last Updated: March 6, 2026
internal/ai/classify wraps PhotoPrism’s TensorFlow-based image classification (labels). It loads SavedModel classifiers (Nasnet by default), prepares inputs, runs inference, and maps output probabilities to label rules.
assets/models/<name> and resolves model tags and input/output ops (see vision.yml overrides for custom models).Rules apply thresholds and priority to produce final labels.TensorFlow tensors allocate C memory and are freed by Go GC finalizers. To keep RSS bounded during long runs, PhotoPrism periodically triggers garbage collection to return freed tensor memory to the OS. Tune with:
PHOTOPRISM_TF_GC_EVERY (default 200, 0 disables).After the base image and toolchain upgrade on February 20, 2026, we observed measurable drift in TensorFlow label uncertainty values caused by changes in Go's image/jpeg implementation:
ChameleonLimeJpg fixture shifted from uncertainty 7 with Go 1.25.4 to 8 with Go 1.26.0 for the same model and inputs.imaging.Decode(...) in model.go, which uses Go's registered JPEG decoder.assets/samples decoded successfully on both versions (no compatibility failures), but all produced different decoded pixel hashes between Go 1.25.4 and 1.26.0.chameleon, cat, etc.), while confidence and uncertainty values moved slightly.Operational notes:
assert.InDelta) for JPEG-derived uncertainty/confidence tests instead of exact integer equality.Rules thresholds are not too strict.saved_model.pb and variables/ exist under the configured model path.TensorFlow.Input/Output settings in vision.yml for custom models.internal/ai/vision/README.md — model registry and vision.yml configurationinternal/ai/tensorflow/README.md — TensorFlow helpers, GC behavior, and model loading