Merge remote-tracking branch 'origin/mobile_face' into mobile_face

This commit is contained in:
laurenspriem 2024-03-29 12:14:33 +05:30
commit afa8a372d2
6 changed files with 1268 additions and 33 deletions

View file

@ -78,6 +78,37 @@ class FaceMLDataDB {
}
}
Future<void> updatePersonIDForFaceIDIFNotSet(
Map<String, int> faceIDToPersonID,
) async {
final db = await instance.database;
const batchSize = 500;
final numBatches = (faceIDToPersonID.length / batchSize).ceil();
for (int i = 0; i < numBatches; i++) {
_logger.info('updatePersonIDForFaceIDIFNotSet Batch $i of $numBatches');
final start = i * batchSize;
final end = min((i + 1) * batchSize, faceIDToPersonID.length);
final batch = faceIDToPersonID.entries.toList().sublist(start, end);
final batchUpdate = db.batch();
for (final entry in batch) {
final faceID = entry.key;
final personID = entry.value;
batchUpdate.update(
facesTable,
{faceClusterId: personID},
where: '$faceIDColumn = ? AND $faceClusterId IS NULL',
whereArgs: [faceID],
);
}
await batchUpdate.commit(noResult: true);
}
}
Future<Map<int, int>> getIndexedFileIds() async {
final db = await instance.database;
final List<Map<String, dynamic>> maps = await db.rawQuery(
@ -293,28 +324,6 @@ class FaceMLDataDB {
return result;
}
Future<void> updatePersonIDForFaceIDIFNotSet(
Map<String, int> faceIDToPersonID,
) async {
final db = await instance.database;
// Start a batch
final batch = db.batch();
for (final map in faceIDToPersonID.entries) {
final faceID = map.key;
final personID = map.value;
batch.update(
facesTable,
{faceClusterId: personID},
where: '$faceIDColumn = ? AND $faceClusterId IS NULL',
whereArgs: [faceID],
);
}
// Commit the batch
await batch.commit(noResult: true);
}
Future<void> forceUpdateClusterIds(
Map<String, int> faceIDToPersonID,
) async {
@ -347,7 +356,9 @@ class FaceMLDataDB {
int offset = 0,
int batchSize = 10000,
}) async {
_logger.info('reading as float');
_logger.info(
'reading as float offset: $offset, maxFaces: $maxFaces, batchSize: $batchSize',
);
final db = await instance.database;
final Map<String, (int?, Uint8List)> result = {};

File diff suppressed because it is too large Load diff

View file

@ -17,6 +17,7 @@ import "package:photos/db/files_db.dart";
import "package:photos/db/ml_data_db.dart";
import "package:photos/events/diff_sync_complete_event.dart";
import "package:photos/extensions/list.dart";
import "package:photos/extensions/stop_watch.dart";
import "package:photos/face/db.dart";
import "package:photos/face/model/box.dart";
import "package:photos/face/model/detection.dart" as face_detection;
@ -120,7 +121,12 @@ class FaceMlService {
if (LocalSettings.instance.isFaceIndexingEnabled == false) {
return;
}
unawaited(indexAllImages());
// [neeraj] intentional delay in starting indexing on diff sync, this gives time for the user
// to disable face-indexing in case it's causing crash. In the future, we
// should have a better way to handle this.
Future.delayed(const Duration(seconds: 10), () {
unawaited(indexAllImages());
});
});
}
@ -380,8 +386,8 @@ class FaceMlService {
await FilesDB.instance.getFileIDToCreationTime();
const int bucketSize = 10000;
const int batchSize = 10000;
const int offsetIncrement = 7500;
const int batchSize = 5000;
int offset = 0;
while (true) {
@ -413,8 +419,11 @@ class FaceMlService {
await FaceMLDataDB.instance
.updatePersonIDForFaceIDIFNotSet(faceIdToCluster);
offset += offsetIncrement;
if (offset == 0) {
offset += offsetIncrement;
} else {
offset += bucketSize;
}
}
} else {
// Read all the embeddings from the database, in a map from faceID to embedding
@ -518,8 +527,11 @@ class FaceMlService {
fileIds.add(f.uploadedFileID!);
}
try {
final EnteWatch? w = kDebugMode ? EnteWatch("face_em_fetch") : null;
w?.start();
final res =
await RemoteFileMLService.instance.getFilessEmbedding(fileIds);
w?.logAndReset('fetched ${res.mlData.length} embeddings');
final List<Face> faces = [];
final remoteFileIdToVersion = <int, int>{};
for (FileMl fileMl in res.mlData.values) {
@ -537,6 +549,7 @@ class FaceMlService {
remoteFileIdToVersion[fileMl.fileID] = fileMl.faceEmbedding.version;
}
await FaceMLDataDB.instance.bulkInsertFaces(faces);
w?.logAndReset('stored embeddings');
for (final entry in remoteFileIdToVersion.entries) {
alreadyIndexedFiles[entry.key] = entry.value;
}
@ -1242,7 +1255,6 @@ class FaceMlService {
if (!enteFile.isUploaded || enteFile.isOwner == false) {
return true;
}
// Skip if the file is a video
if (enteFile.fileType == FileType.video) {
return true;

View file

@ -79,7 +79,7 @@ class ClusterFeedbackService {
final personClusters = await faceMlDb.getPersonClusterIDs(p.remoteID);
dev.log(
'existing clusters for ${p.attr.name} are $personClusters',
name: "ClusterFeedbackService",
name: "getSuggestionsUsingMedian",
);
// Get and update the cluster summary to get the avg (centroid) and count
@ -353,6 +353,9 @@ class ClusterFeedbackService {
Set<int> ignoredClusters,
) async {
final faceMlDb = FaceMLDataDB.instance;
_logger.info(
'start getUpdateClusterAvg for ${allClusterIdsToCountMap.length} clusters',
);
final Map<int, (Uint8List, int)> clusterToSummary =
await faceMlDb.clusterSummaryAll();
@ -389,6 +392,7 @@ class ClusterFeedbackService {
if (updatesForClusterSummary.isNotEmpty) {
await faceMlDb.clusterSummaryUpdate(updatesForClusterSummary);
}
_logger.info('end getUpdateClusterAvg for ${clusterAvg.length} clusters');
return clusterAvg;
}

View file

@ -158,7 +158,8 @@ class _FaceDebugSectionWidgetState extends State<FaceDebugSectionWidget> {
trailingIcon: Icons.chevron_right_outlined,
trailingIconIsMuted: true,
onTap: () async {
await FaceMlService.instance.clusterAllImages(minFaceScore: 0.75);
await FaceMlService.instance
.clusterAllImages(minFaceScore: 0.75, clusterInBuckets: true);
Bus.instance.fire(PeopleChangedEvent());
showShortToast(context, "Done");
},
@ -205,7 +206,7 @@ class _FaceDebugSectionWidgetState extends State<FaceDebugSectionWidget> {
if (kDebugMode)
MenuItemWidget(
captionedTextWidget: const CaptionedTextWidget(
title: "Pull Embeddings From Local",
title: "Compute suggestions",
),
pressedColor: getEnteColorScheme(context).fillFaint,
trailingIcon: Icons.chevron_right_outlined,

View file

@ -37,8 +37,6 @@ class _PersonClustersState extends State<PersonReviewClusterSuggestion> {
super.initState();
// Initialize the future in initState
_fetchClusterSuggestions();
// futureClusterSuggestions = ClusterFeedbackService.instance
// .getClusterFilesForPersonID(widget.person);
}
@override