Skip to main content

Template Migration

Face templates are bound to the extraction model that produced them. The matcher, the face search service, base, the camera containers, edge-stream-processor and db-synchronization-follower check template compatibility at startup and stop when the stored templates do not match the configured model; docker compose logs of the stopped container shows the reason. Migration re-extracts every stored template with the new model from the saved face crops. You need it when you change Extraction__Algorithm, or when a release changes the model version (the release notes say so).

Not every template can be migrated. Re-extraction needs a fresh detection on the stored crop, which does not always succeed; the previous detection ran on the full frame, possibly with a different detector. Faces that fail are set to the ERROR state, the matchers skip them, and the affected watchlist members must be re-enrolled with a new image. The large majority of templates migrate cleanly.

Choose the algorithm​

AlgorithmFACE_MODEL_VERSIONNote
fast52Fastest, lowest accuracy
balanced53Default
accurate54Higher accuracy, higher cost
accurate_server55Highest accuracy, server-class hardware

Set Extraction__Algorithm in .env (section 3.13) to the algorithm you migrate to, so that new enrollments produce the same template version. Decide the algorithm at installation time if you can; migrating a large database takes time. Take a backup before you start.

Run the migration​

FACE_MODEL_VERSION=54 ./migrate-faces.sh

The script stops the engine services, starts temporary detector and extractor containers (sf_migration_face_detector_N, sf_migration_face_extractor_N, three of each by default), runs the migrate-faces command of the admin image with parallelism 4, stops the workers and finally prints a dry run of what could not be migrated. Save that output: it lists the watchlist members whose faces need re-enrollment. Without FACE_MODEL_VERSION the script migrates to 53.

Transient errors, typically RPC timeouts when the workers are overloaded, leave templates unmigrated without marking them. The script is safe to re-run; repeat it until the remaining failures are stable.

Finalize and restart​

FACE_MODEL_VERSION=54 ./finalize-non-migrated-faces.sh
./start.sh

The finalize step marks the remaining faces as ERROR so the matchers can start; run it only after the re-runs stopped changing the result. The services are still stopped at this point, so start them again.

List members with faces in error state​

Query the GraphQL API at http://localhost:8097/graphql to find the watchlist members whose faces were not migrated, and re-enroll them:

query {
faces(where: { faceState: { eq: ERROR } }) {
items {
tracklet {
watchlistMembers { id fullName displayName }
}
state
templateVersion
}
}
}

Performance options​

  • More workers. FACE_DETECTORS_COUNT and FACE_EXTRACTORS_COUNT set the number of temporary containers (default 3 each): FACE_EXTRACTORS_COUNT=8 FACE_MODEL_VERSION=54 ./migrate-faces.sh. Match --parallelism in the script to the extractor count. Parallelism above the number of extractors causes timeouts and re-runs; extractors above the parallelism sit idle.
  • GPU extractors. On a host with a GPU, edit the extractor docker run in migrate-faces.sh to add --runtime nvidia --env Gpu__GpuEnabled=true, and add --use-gpu-extractors to the migrate-faces call. See GPU acceleration for the host prerequisites.
  • Edge streams. Devices running the Embedded Stream Processor send templates of their own model version. FrameDataProcessing__ForceExtractionOfIncompatibleFaceTemplates=true (section 3.7 of .env) makes edge-stream-processor re-extract incompatible templates on the server until the devices are updated.