lvface 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,218 @@
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[codz]
4
+ *$py.class
5
+
6
+ # C extensions
7
+ *.so
8
+
9
+ # Distribution / packaging
10
+ .Python
11
+ build/
12
+ develop-eggs/
13
+ dist/
14
+ downloads/
15
+ eggs/
16
+ .eggs/
17
+ lib/
18
+ lib64/
19
+ parts/
20
+ sdist/
21
+ var/
22
+ wheels/
23
+ share/python-wheels/
24
+ *.egg-info/
25
+ .installed.cfg
26
+ *.egg
27
+ MANIFEST
28
+
29
+ # PyInstaller
30
+ # Usually these files are written by a python script from a template
31
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
32
+ *.manifest
33
+ *.spec
34
+
35
+ # Installer logs
36
+ pip-log.txt
37
+ pip-delete-this-directory.txt
38
+
39
+ # Unit test / coverage reports
40
+ htmlcov/
41
+ .tox/
42
+ .nox/
43
+ .coverage
44
+ .coverage.*
45
+ .cache
46
+ nosetests.xml
47
+ coverage.xml
48
+ *.cover
49
+ *.py.cover
50
+ .hypothesis/
51
+ .pytest_cache/
52
+ cover/
53
+
54
+ # Translations
55
+ *.mo
56
+ *.pot
57
+
58
+ # Django stuff:
59
+ *.log
60
+ local_settings.py
61
+ db.sqlite3
62
+ db.sqlite3-journal
63
+
64
+ # Flask stuff:
65
+ instance/
66
+ .webassets-cache
67
+
68
+ # Scrapy stuff:
69
+ .scrapy
70
+
71
+ # Sphinx documentation
72
+ docs/_build/
73
+
74
+ # PyBuilder
75
+ .pybuilder/
76
+ target/
77
+
78
+ # Jupyter Notebook
79
+ .ipynb_checkpoints
80
+
81
+ # IPython
82
+ profile_default/
83
+ ipython_config.py
84
+
85
+ # pyenv
86
+ # For a library or package, you might want to ignore these files since the code is
87
+ # intended to run in multiple environments; otherwise, check them in:
88
+ # .python-version
89
+
90
+ # pipenv
91
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
92
+ # However, in case of collaboration, if having platform-specific dependencies or dependencies
93
+ # having no cross-platform support, pipenv may install dependencies that don't work, or not
94
+ # install all needed dependencies.
95
+ # Pipfile.lock
96
+
97
+ # UV
98
+ # Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
99
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
100
+ # commonly ignored for libraries.
101
+ # uv.lock
102
+
103
+ # poetry
104
+ # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
105
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
106
+ # commonly ignored for libraries.
107
+ # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
108
+ # poetry.lock
109
+ # poetry.toml
110
+
111
+ # pdm
112
+ # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
113
+ # pdm recommends including project-wide configuration in pdm.toml, but excluding .pdm-python.
114
+ # https://pdm-project.org/en/latest/usage/project/#working-with-version-control
115
+ # pdm.lock
116
+ # pdm.toml
117
+ .pdm-python
118
+ .pdm-build/
119
+
120
+ # pixi
121
+ # Similar to Pipfile.lock, it is generally recommended to include pixi.lock in version control.
122
+ # pixi.lock
123
+ # Pixi creates a virtual environment in the .pixi directory, just like venv module creates one
124
+ # in the .venv directory. It is recommended not to include this directory in version control.
125
+ .pixi
126
+
127
+ # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
128
+ __pypackages__/
129
+
130
+ # Celery stuff
131
+ celerybeat-schedule
132
+ celerybeat.pid
133
+
134
+ # Redis
135
+ *.rdb
136
+ *.aof
137
+ *.pid
138
+
139
+ # RabbitMQ
140
+ mnesia/
141
+ rabbitmq/
142
+ rabbitmq-data/
143
+
144
+ # ActiveMQ
145
+ activemq-data/
146
+
147
+ # SageMath parsed files
148
+ *.sage.py
149
+
150
+ # Environments
151
+ .env
152
+ .envrc
153
+ .venv
154
+ env/
155
+ venv/
156
+ ENV/
157
+ env.bak/
158
+ venv.bak/
159
+
160
+ # Spyder project settings
161
+ .spyderproject
162
+ .spyproject
163
+
164
+ # Rope project settings
165
+ .ropeproject
166
+
167
+ # mkdocs documentation
168
+ /site
169
+
170
+ # mypy
171
+ .mypy_cache/
172
+ .dmypy.json
173
+ dmypy.json
174
+
175
+ # Pyre type checker
176
+ .pyre/
177
+
178
+ # pytype static type analyzer
179
+ .pytype/
180
+
181
+ # Cython debug symbols
182
+ cython_debug/
183
+
184
+ # PyCharm
185
+ # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
186
+ # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
187
+ # and can be added to the global gitignore or merged into this file. For a more nuclear
188
+ # option (not recommended) you can uncomment the following to ignore the entire idea folder.
189
+ # .idea/
190
+
191
+ # Abstra
192
+ # Abstra is an AI-powered process automation framework.
193
+ # Ignore directories containing user credentials, local state, and settings.
194
+ # Learn more at https://abstra.io/docs
195
+ .abstra/
196
+
197
+ # Visual Studio Code
198
+ # Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore
199
+ # that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
200
+ # and can be added to the global gitignore or merged into this file. However, if you prefer,
201
+ # you could uncomment the following to ignore the entire vscode folder
202
+ # .vscode/
203
+ # Temporary file for partial code execution
204
+ tempCodeRunnerFile.py
205
+
206
+ # Ruff stuff:
207
+ .ruff_cache/
208
+
209
+ # PyPI configuration file
210
+ .pypirc
211
+
212
+ # Marimo
213
+ marimo/_static/
214
+ marimo/_lsp/
215
+ __marimo__/
216
+
217
+ # Streamlit
218
+ .streamlit/secrets.toml
@@ -0,0 +1,13 @@
1
+ # Changelog
2
+
3
+ ## 0.1.0
4
+
5
+ - Initial ONNX-only LVFace embedding API for Python 3.11–3.13.
6
+ - Pluggable face detector and embedder adapters.
7
+ - Face comparison, search, group matching, and conservative identity clustering.
8
+ - Revision-pinned, checksum-validated optional model downloads.
9
+
10
+ CPU inference is the supported runtime for this release. The default cosine threshold is
11
+ provisional and must be calibrated for each deployment. LVFace embedding-weight licensing is
12
+ unresolved because the official metadata and model-card prose conflict; the default InsightFace
13
+ detector weights are separately restricted to non-commercial research use.
@@ -0,0 +1,16 @@
1
+ # Contributing
2
+
3
+ Install the development dependencies and run the complete local checks:
4
+
5
+ ```bash
6
+ python -m pip install -e ".[dev]"
7
+ ruff check .
8
+ ruff format --check .
9
+ mypy src
10
+ pytest
11
+ ```
12
+
13
+ Changes to preprocessing, alignment, model resolution, or ONNX inference must keep the frozen
14
+ golden-embedding tests green. Do not commit model weights, face-photo datasets, caches, or
15
+ generated build artifacts. New image fixtures must be synthetic or openly licensed and have
16
+ their source, license, and attribution recorded in `tests/data/FIXTURES.md`.
lvface-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 ByteDance Ltd. and/or its affiliates
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
lvface-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,357 @@
1
+ Metadata-Version: 2.4
2
+ Name: lvface
3
+ Version: 0.1.0
4
+ Summary: Modern face-embedding framework for detection, alignment, embedding, and comparison.
5
+ Project-URL: Homepage, https://github.com/mowshon/lvface
6
+ Project-URL: Documentation, https://github.com/mowshon/lvface#readme
7
+ Project-URL: Issues, https://github.com/mowshon/lvface/issues
8
+ Project-URL: Repository, https://github.com/mowshon/lvface
9
+ Author: Mowshon
10
+ License-Expression: MIT
11
+ License-File: LICENSE
12
+ Keywords: arcface,face-embedding,face-recognition,lvface,onnx
13
+ Classifier: Development Status :: 2 - Pre-Alpha
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: Intended Audience :: Science/Research
16
+ Classifier: License :: OSI Approved :: MIT License
17
+ Classifier: Operating System :: OS Independent
18
+ Classifier: Programming Language :: Python :: 3
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Programming Language :: Python :: 3.13
22
+ Classifier: Topic :: Scientific/Engineering :: Image Recognition
23
+ Classifier: Typing :: Typed
24
+ Requires-Python: >=3.11
25
+ Requires-Dist: numpy>=2.4
26
+ Requires-Dist: onnxruntime>=1.23.2
27
+ Requires-Dist: pillow>=12.2
28
+ Provides-Extra: all
29
+ Requires-Dist: huggingface-hub>=1.20; extra == 'all'
30
+ Requires-Dist: insightface>=1.0.1; extra == 'all'
31
+ Requires-Dist: requests>=2.32; extra == 'all'
32
+ Requires-Dist: scikit-learn>=1.7; extra == 'all'
33
+ Requires-Dist: scipy>=1.15; extra == 'all'
34
+ Provides-Extra: cluster
35
+ Requires-Dist: scikit-learn>=1.7; extra == 'cluster'
36
+ Provides-Extra: detect
37
+ Requires-Dist: insightface>=1.0.1; extra == 'detect'
38
+ Provides-Extra: dev
39
+ Requires-Dist: mypy>=2.1; extra == 'dev'
40
+ Requires-Dist: pre-commit>=4.0; extra == 'dev'
41
+ Requires-Dist: pytest-cov>=7.0; extra == 'dev'
42
+ Requires-Dist: pytest>=9.1; extra == 'dev'
43
+ Requires-Dist: requests>=2.32; extra == 'dev'
44
+ Requires-Dist: ruff>=0.15; extra == 'dev'
45
+ Provides-Extra: docs
46
+ Requires-Dist: mkdocs-material>=9.5; extra == 'docs'
47
+ Requires-Dist: mkdocstrings[python]>=0.27; extra == 'docs'
48
+ Provides-Extra: http
49
+ Requires-Dist: requests>=2.32; extra == 'http'
50
+ Provides-Extra: hub
51
+ Requires-Dist: huggingface-hub>=1.20; extra == 'hub'
52
+ Provides-Extra: hungarian
53
+ Requires-Dist: scipy>=1.15; extra == 'hungarian'
54
+ Provides-Extra: release
55
+ Requires-Dist: build>=1.2; extra == 'release'
56
+ Requires-Dist: twine>=5.1; extra == 'release'
57
+ Description-Content-Type: text/markdown
58
+
59
+ # lvface
60
+
61
+ `lvface` detects faces, aligns them, produces 512-dimensional LVFace embeddings, and compares
62
+ people across portraits, group photos, or whole albums. The high-level API is small, while the
63
+ detector and embedder are both replaceable.
64
+
65
+ ```python
66
+ from lvface import FaceRecognizer
67
+
68
+ recognizer = FaceRecognizer("LVFace-T_Glint360K")
69
+ result = recognizer.compare("id-photo.jpg", "selfie.jpg")
70
+
71
+ print(result.is_match)
72
+ print(f"cosine={result.cosine:.4f}, display={result.percentage:.1f}%")
73
+ ```
74
+
75
+ > Face recognition is biometric processing. Get informed consent, protect stored embeddings,
76
+ > define retention rules, and evaluate accuracy and bias on data representative of your users.
77
+
78
+ ## Why lvface?
79
+
80
+ - One pipeline for paths, image bytes, URLs, and RGB NumPy arrays.
81
+ - Every face in an image can be returned, not only the largest one.
82
+ - Multi-face search, group-photo matching, and album clustering are built in.
83
+ - Released LVFace ONNX models run through ONNX Runtime; PyTorch is not required.
84
+ - Custom detectors and embedders plug into the same `FaceRecognizer`.
85
+ - Named weights are revision-pinned and checksum-verified.
86
+
87
+ ## Install
88
+
89
+ Python 3.11 or newer is required.
90
+
91
+ ```bash
92
+ # Recommended: recognition from ordinary photos + automatic weight download
93
+ python -m pip install "lvface[detect,hub]"
94
+
95
+ # Local ONNX weights and already aligned 112×112 face crops
96
+ python -m pip install lvface
97
+
98
+ # Add guarded http(s) image loading
99
+ python -m pip install "lvface[detect,hub,http]"
100
+ ```
101
+
102
+ The `[detect]` extra installs the default InsightFace detector. The `[hub]` extra lets a
103
+ registered model name download its pinned ONNX file on first construction:
104
+
105
+ ```python
106
+ recognizer = FaceRecognizer("LVFace-T_Glint360K")
107
+ ```
108
+
109
+ To keep weights under your own control, pass a local file. This path never accesses Hugging Face
110
+ and does not need `[hub]`:
111
+
112
+ ```python
113
+ recognizer = FaceRecognizer("/models/LVFace-T_Glint360K.onnx")
114
+ ```
115
+
116
+ Model resolution and download happen while `FaceRecognizer` is constructed. The ONNX Runtime
117
+ session itself is still created lazily on the first embedding call.
118
+
119
+ CPU is the supported runtime for the 0.1 release. There is no `[gpu]` extra because
120
+ `onnxruntime` and `onnxruntime-gpu` provide the same Python package. For best-effort NVIDIA CUDA
121
+ use on Linux or Windows, install all extras first, then replace the runtime:
122
+
123
+ ```bash
124
+ python -m pip uninstall -y onnxruntime
125
+ python -m pip install onnxruntime-gpu
126
+ ```
127
+
128
+ ## A 60-second tour
129
+
130
+ ### Compare two photos
131
+
132
+ ```python
133
+ from lvface import FaceRecognizer
134
+
135
+ recognizer = FaceRecognizer(device="auto")
136
+ result = recognizer.compare("first.jpg", "second.jpg", select="largest")
137
+
138
+ if result.is_match:
139
+ print(f"Likely the same person ({result.percentage:.1f}% display score)")
140
+ ```
141
+
142
+ `percentage` is a readable, threshold-centered display score. It is not a probability or a
143
+ calibrated confidence value. Use `cosine` and a threshold calibrated for your own camera,
144
+ population, and risk tolerance to make decisions.
145
+
146
+ ### Get an embedding for every face
147
+
148
+ ```python
149
+ faces = recognizer.analyze("team-photo.jpg")
150
+
151
+ for face in faces:
152
+ vector = face.embedding.vector
153
+ print(face.face_index, face.bbox, vector.shape) # (512,)
154
+ ```
155
+
156
+ `analyze()` performs load → detect → align → embed and returns a `Face` for every alignable
157
+ face. Each result carries its bounding box, five landmarks, aligned crop, and L2-normalized
158
+ embedding.
159
+
160
+ If you only need vectors:
161
+
162
+ ```python
163
+ embeddings = recognizer.embed("team-photo.jpg") # list[Embedding]
164
+ one_embedding = recognizer.embed("portrait.jpg", select="largest")
165
+ ```
166
+
167
+ ### Store face embeddings with FAISS
168
+
169
+ The FAISS example stores every detected face in a local cosine-similarity index. A small JSON
170
+ file keeps the image and face index associated with each vector:
171
+
172
+ ```bash
173
+ python -m pip install faiss-cpu
174
+ python examples/embed_and_store.py
175
+ ```
176
+
177
+ Edit the `IMAGE` constant at the top of the script before running it. The index uses cosine
178
+ similarity, matching `lvface`'s canonical comparison metric. The script writes `faces.index` and
179
+ `faces.json`. For production, treat both files as biometric data: restrict access, encrypt
180
+ backups, and delete vectors when their source data must be removed.
181
+
182
+ To search the saved index, edit `QUERY_IMAGE` in the companion example:
183
+
184
+ ```bash
185
+ python examples/search_faiss.py
186
+ ```
187
+
188
+ It embeds the largest face in the query photo, loads `faces.index`, and prints the nearest stored
189
+ faces with their cosine similarity. Use the same LVFace model for indexing and searching.
190
+
191
+ ### Find someone in a group photo
192
+
193
+ ```python
194
+ hits = recognizer.find(
195
+ "person-to-find.jpg",
196
+ "group-photo.jpg",
197
+ top_k=3,
198
+ )
199
+
200
+ for hit in hits:
201
+ print(hit.candidate.face_index, hit.percentage, hit.candidate.bbox)
202
+ ```
203
+
204
+ ### Match two group photos
205
+
206
+ ```python
207
+ result = recognizer.match("group-before.jpg", "group-after.jpg")
208
+
209
+ for pair in result.pairs:
210
+ print(
211
+ pair.query.face_index,
212
+ "↔",
213
+ pair.candidate.face_index,
214
+ f"{pair.percentage:.1f}%",
215
+ )
216
+ ```
217
+
218
+ The default greedy assignment uses each face at most once. Install `lvface[hungarian]` and pass
219
+ `assignment="hungarian"` for globally optimal one-to-one assignment.
220
+
221
+ ### Group an album by identity
222
+
223
+ ```python
224
+ identities = recognizer.group(["day-1.jpg", "day-2.jpg", "day-3.jpg"])
225
+
226
+ for identity in identities:
227
+ print([(face.image_index, face.face_index) for face in identity])
228
+ ```
229
+
230
+ Clustering is conservative: every member must meet the threshold against every other member, and
231
+ one identity cannot contain two faces from the same image unless `one_per_image=False`.
232
+
233
+ ## API at a glance
234
+
235
+ | Call | Result |
236
+ | --- | --- |
237
+ | `analyze(image)` | Every detected face, aligned crop, and embedding |
238
+ | `embed(image)` | Embeddings for every face |
239
+ | `embed(image, select="largest")` | One explicitly selected embedding |
240
+ | `embed_aligned(crop)` | Embed one pre-aligned 112×112 RGB crop |
241
+ | `compare(a, b)` | Cosine, Euclidean distance, display score, and decision |
242
+ | `verify(a, b)` | Boolean match decision |
243
+ | `find(query, gallery)` | One-to-many ranked face search |
244
+ | `match(a, b)` | Full many-to-many matrix and assigned pairs |
245
+ | `group(images)` | Conservative identity clusters across images |
246
+
247
+ Accepted image inputs are a path, `http(s)` URL with `[http]`, encoded bytes, or an RGB
248
+ `uint8` NumPy array. NumPy arrays are assumed to be RGB, not OpenCV BGR.
249
+
250
+ ## Bring your own detector
251
+
252
+ A detector only needs to subclass `FaceDetector` and provide lazy `load()` plus `detect()`.
253
+ Each detected `Face` should contain a bounding box and five ArcFace-order landmarks. The base
254
+ class supplies the 112×112 alignment implementation.
255
+
256
+ ```python
257
+ detector = MyDetector(...)
258
+ recognizer = FaceRecognizer(
259
+ embedder="LVFace-T_Glint360K",
260
+ detector=detector,
261
+ )
262
+ faces = recognizer.analyze("photo.jpg")
263
+ ```
264
+
265
+ [`examples/custom_detector.py`](examples/custom_detector.py) is a complete OpenCV YuNet adapter
266
+ and shows the important part explicitly: the custom detector instance is passed into
267
+ `FaceRecognizer`, so its detections flow through alignment and LVFace embedding.
268
+
269
+ Change the detector model and image paths at the bottom of the example, then run it:
270
+
271
+ ```bash
272
+ python examples/custom_detector.py
273
+ ```
274
+
275
+ Custom embedding backends follow the same pattern: subclass `FaceEmbedder`, lazily initialize the
276
+ runtime in `load()`, and implement `_forward(batch)` to return an `(N, 512)` floating-point
277
+ array. The base class validates 112×112 RGB inputs, preprocesses them, batches inference, and
278
+ returns validated `Embedding` objects.
279
+
280
+ ## Concepts that matter
281
+
282
+ **Embedding.** A 512-number representation of an aligned face. Embeddings returned by the public
283
+ API are L2-normalized.
284
+
285
+ **Cosine similarity.** The decision metric. Higher means more similar. The packaged `0.35`
286
+ default is a provisional starting point, not a domain-general operating threshold.
287
+
288
+ **Euclidean distance.** A diagnostic value. For normalized vectors,
289
+ `euclidean² = 2 - 2 × cosine`.
290
+
291
+ **Alignment.** Five facial landmarks are warped onto the ArcFace 112×112 template before
292
+ embedding. Good detection and alignment are part of recognition quality, not merely
293
+ preprocessing details.
294
+
295
+ **Display percentage.** A sigmoid mapping centered on the decision threshold. It is for UI
296
+ display only and must not be presented as probability, certainty, or an estimated false-match
297
+ rate.
298
+
299
+ ## Runnable examples
300
+
301
+ Each example is intentionally a small, direct Python script. Open one, replace the sample image
302
+ paths, and run it:
303
+
304
+ ```bash
305
+ python examples/verify_two_faces.py
306
+ python examples/embed_and_store.py
307
+ python examples/search_faiss.py
308
+ python examples/find_in_group.py
309
+ python examples/match_two_group_photos.py
310
+ python examples/cluster_album.py
311
+ python examples/custom_detector.py
312
+ ```
313
+
314
+ From a source checkout:
315
+
316
+ ```bash
317
+ python -m pip install -e ".[detect,hub]"
318
+ ```
319
+
320
+ ## Weights, licenses, and citation
321
+
322
+ The package code is MIT licensed.
323
+
324
+ The default InsightFace model packs, including `buffalo_l`, are separately licensed for
325
+ non-commercial research use. Applications requiring other terms should supply a detector with
326
+ appropriate weights or pass pre-aligned crops with `detector=None`.
327
+
328
+ LVFace embedding-weight licensing is unresolved. The official repository metadata declares MIT,
329
+ while its model-card prose restricts downloaded models to non-commercial research. The
330
+ unofficial
331
+ [`Mowshon/lvface-weights`](https://huggingface.co/Mowshon/lvface-weights) preservation mirror
332
+ grants no additional rights. `lvface` pins mirror revision
333
+ `83b567cd6a3fc34434667e4415b6125feceb39ea`; the mirror records unchanged files from official
334
+ [`bytedance-research/LVFace`](https://huggingface.co/bytedance-research/LVFace) revision
335
+ `b12702ab1f5c721748e054a66dc90e1edd1f0724`. Review the official model card and seek
336
+ clarification from the authors when necessary.
337
+
338
+ Use of the weights requires citation of the original work:
339
+
340
+ ```bibtex
341
+ @inproceedings{you2025lvface,
342
+ title={{LVFace}: Progressive Cluster Optimization for Large Vision Models in Face Recognition},
343
+ author={You, Jinghan and Li, Shanglin and Sun, Yuanrui and Wei, Jiangchuan and Guo, Mingyu and Feng, Chao and Ran, Jiao},
344
+ booktitle={ICCV},
345
+ year={2025}
346
+ }
347
+ ```
348
+
349
+ ## Development
350
+
351
+ ```bash
352
+ python -m pip install -e ".[dev]"
353
+ ruff check .
354
+ ruff format --check .
355
+ mypy src
356
+ pytest
357
+ ```