你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn。
缩放以处理更多已注册用户
注意
为了支持我们负责任的 AI 原则,基于资格和使用标准对人脸服务访问进行限制。 人脸服务仅适用于 Microsoft 托管客户和合作伙伴。 使用人脸识别引入表单来申请访问。 有关详细信息,请参阅人脸受限访问页面。
本指南介绍如何从现有 PersonGroup 和 FaceList 对象分别纵向扩展到 LargePersonGroup 和 LargeFaceList 对象。 PersonGroups 在免费层中最多可以容纳 1000 人,在付费层中最多可以容纳 10,000 人,而 LargePersonGroups 在付费层中最多可以容纳 100 万人。
重要
建议使用较新的数据结构 PersonDirectory 进行新开发。 它可以容纳多达 7500 万个标识,不需要手动培训。 有关详细信息,请参阅使用 PersonDirectory 指南。
本指南演示迁移过程, 其假设读者基本熟悉 PersonGroup 和 FaceList 对象、训练操作和人脸识别功能。 若要详细了解这些主题,请参阅人脸识别概念指南。
LargePersonGroup 和 LargeFaceList 统称为大规模操作。 LargePersonGroup 最多可以包含 1 百万人,其中每个人最多有 248 张人脸。 LargeFaceList 最多可以包含 1 百万张人脸。 大规模操作类似于传统的 PersonGroup 和 FaceList,但因采用新体系结构而有一些差异。
这些示例是使用 Azure AI 人脸客户端库以 C# 编写的。
注意
为了在大规模的 Identification 和 FindSimilar 操作中提高人脸搜索的性能,我们引入了一个“训练”操作用于预处理 LargeFaceList 和 LargePersonGroup。 训练时间从几秒到约半小时不等,具体取决于实际容量。 如果以前的某个训练操作成功,则在训练期间,可以执行 Identification 和 FindSimilar。 缺点在于,在完成迁移到大规模训练的最新后处理前,新添加的人员和人脸不会出现在结果中。
步骤 1:初始化客户端对象
使用人脸客户端库时,密钥和订阅终结点将通过 FaceClient 类的构造函数传入。 如需创建人脸客户端对象的说明,请参阅快速入门。
步骤 2:代码迁移
本部分重点介绍如何将 PersonGroup 或 FaceList 实现迁移到 LargePersonGroup 或 LargeFaceList。 虽然 LargePersonGroup 或 LargeFaceList 与 PersonGroup 或 FaceList 在设计和内部实现方面存在差异,但用于后向兼容的 API 接口是类似的。
不支持数据迁移。 请改为重新创建 LargePersonGroup 或 LargeFaceList。
将 PersonGroup 迁移到 LargePersonGroup
从 PersonGroup 迁移到 LargePersonGroup 的过程较为简单。 它们采用完全相同的组级别操作。
对于 PersonGroup 或 Person 相关的实现,只需将 API 路径或 SDK 类/模块更改为 LargePersonGroup 和 LargePersonGroup Person。
将 PersonGroup 中的所有人脸和人员添加到新的 LargePersonGroup。 有关详细信息,请参阅添加人脸。
将 FaceList 迁移到 LargeFaceList
FaceList API | LargeFaceList API |
---|---|
创建 | 创建 |
删除 | 删除 |
获取 | 获取 |
列出 | 列出 |
更新 | 更新 |
- | 定型 |
- | 获取定型状态 |
上表对 FaceList 和 LargeFaceList 的列级操作进行了对比。 如表中所示,与 FaceList 相比,LargeFaceList 附带了新的操作(“训练”和“获取训练状态”)。 训练 LargeFaceList 是 FindSimilar 操作的前提条件。 FaceList 不需要训练。 以下代码片段是一个用于等待训练 LargeFaceList 的帮助器函数:
/// <summary>
/// Helper function to train LargeFaceList and wait for finish.
/// </summary>
/// <remarks>
/// The time interval can be adjusted considering the following factors:
/// - The training time which depends on the capacity of the LargeFaceList.
/// - The acceptable latency for getting the training status.
/// - The call frequency and cost.
///
/// Estimated training time for LargeFaceList in different scale:
/// - 1,000 faces cost about 1 to 2 seconds.
/// - 10,000 faces cost about 5 to 10 seconds.
/// - 100,000 faces cost about 1 to 2 minutes.
/// - 1,000,000 faces cost about 10 to 30 minutes.
/// </remarks>
/// <param name="largeFaceListId">The Id of the LargeFaceList for training.</param>
/// <param name="timeIntervalInMilliseconds">The time interval for getting training status in milliseconds.</param>
/// <returns>A task of waiting for LargeFaceList training finish.</returns>
private static async Task TrainLargeFaceList(
string largeFaceListId,
int timeIntervalInMilliseconds = 1000)
{
// Trigger a train call.
await FaceClient.LargeTrainLargeFaceListAsync(largeFaceListId);
// Wait for training finish.
while (true)
{
Task.Delay(timeIntervalInMilliseconds).Wait();
var status = await faceClient.LargeFaceList.TrainAsync(largeFaceListId);
if (status.Status == Status.Running)
{
continue;
}
else if (status.Status == Status.Succeeded)
{
break;
}
else
{
throw new Exception("The train operation is failed!");
}
}
}
以前,添加了人脸的 FaceList 和 FindSimilar 的典型用法如下所示:
// Create a FaceList.
const string FaceListId = "myfacelistid_001";
const string FaceListName = "MyFaceListDisplayName";
const string ImageDir = @"/path/to/FaceList/images";
faceClient.FaceList.CreateAsync(FaceListId, FaceListName).Wait();
// Add Faces to the FaceList.
Parallel.ForEach(
Directory.GetFiles(ImageDir, "*.jpg"),
async imagePath =>
{
using (Stream stream = File.OpenRead(imagePath))
{
await faceClient.FaceList.AddFaceFromStreamAsync(FaceListId, stream);
}
});
// Perform FindSimilar.
const string QueryImagePath = @"/path/to/query/image";
var results = new List<SimilarPersistedFace[]>();
using (Stream stream = File.OpenRead(QueryImagePath))
{
var faces = faceClient.Face.DetectWithStreamAsync(stream).Result;
foreach (var face in faces)
{
results.Add(await faceClient.Face.FindSimilarAsync(face.FaceId, FaceListId, 20));
}
}
将它迁移到 LargeFaceList 时,它会变成:
// Create a LargeFaceList.
const string LargeFaceListId = "mylargefacelistid_001";
const string LargeFaceListName = "MyLargeFaceListDisplayName";
const string ImageDir = @"/path/to/FaceList/images";
faceClient.LargeFaceList.CreateAsync(LargeFaceListId, LargeFaceListName).Wait();
// Add Faces to the LargeFaceList.
Parallel.ForEach(
Directory.GetFiles(ImageDir, "*.jpg"),
async imagePath =>
{
using (Stream stream = File.OpenRead(imagePath))
{
await faceClient.LargeFaceList.AddFaceFromStreamAsync(LargeFaceListId, stream);
}
});
// Train() is newly added operation for LargeFaceList.
// Must call it before FindSimilarAsync() to ensure the newly added faces searchable.
await TrainLargeFaceList(LargeFaceListId);
// Perform FindSimilar.
const string QueryImagePath = @"/path/to/query/image";
var results = new List<SimilarPersistedFace[]>();
using (Stream stream = File.OpenRead(QueryImagePath))
{
var faces = faceClient.Face.DetectWithStreamAsync(stream).Result;
foreach (var face in faces)
{
results.Add(await faceClient.Face.FindSimilarAsync(face.FaceId, largeFaceListId: LargeFaceListId));
}
}
如上所示,数据管理和 FindSimilar 部分几乎一样。 唯一的例外是,全新的预处理训练操作必须在 LargeFaceList 中完成,然后 FindSimilar 才能正常工作。
步骤 3:训练建议
尽管训练操作可以加快 FindSimilar 和 Identification,但训练时间非常漫长,尤其是涉及大规模操作时。 下表列出了不同规模的估计训练时间。
人脸或人员的规模 | 估计训练时间 |
---|---|
1,000 | 1-2 秒 |
10,000 | 5-10 秒 |
100,000 | 1-2 分钟 |
1,000,000 | 10-30 分钟 |
为了更好地利用大规模功能,我们建议采用以下策略。
步骤 3a:自定义时间间隔
如 TrainLargeFaceList()
中所示,某个以毫秒为单位的时间间隔可以延迟无限期的训练状态检查过程。 对于包含更多人脸的 LargeFaceList,使用较大间隔可减少调用计数和成本。 请根据 LargeFaceList 的预期容量自定义该时间间隔。
同样的策略也适用于 LargePersonGroup。 例如,在训练包含 1 百万人的 LargePersonGroup 时,timeIntervalInMilliseconds
可能为 60,000(即 1 分钟间隔)。
步骤 3b:小规模缓冲区
LargePersonGroup 或 LargeFaceList 中的人员/人脸仅在训练后才可搜索。 在动态方案中,新人员或人脸会不断增加,且必须立即可供搜索,但训练时间可能超过所需时间。
若要缓解此问题,请仅对新添加的条目使用额外的小规模 LargePersonGroup 或 LargeFaceList 作为缓冲区。 由于规模较小,此缓冲区所需训练时间较短。 在此临时缓冲区中应可实现即时搜索功能。 在使用此缓冲区的同时,通过按稀疏间隔执行主训练来对主 LargePersonGroup 或 LargeFaceList 执行训练。 例如,在午夜执行或每日执行一次。
示例工作流:
- 创建一个主 LargePersonGroup 或 LargeFaceList(主集合)。 和一个缓冲区 LargePersonGroup 或 LargeFaceList(缓冲区集合)。 缓冲区集合仅用于新添加的人员或人脸。
- 同时向主集合和缓冲区集合添加新人员或人脸。
- 仅按短时间间隔训练缓冲区集合,以确保新添加的条目生效。
- 同时对主集合和缓冲区集合调用 Identification 或 FindSimilar。 合并结果。
- 当缓冲区集合大小增加到阈值或在系统空闲时,创建新的缓冲区集合。 对主集合触发训练操作。
- 完成对主集合的训练操作后,删除旧的缓冲区集合。
步骤 3c:独立训练
如果可以接受相对较长的时间延迟,则不需要在添加新数据后立即触发训练操作。 相反,可从主逻辑中拆分定型操作并定期触发该操作。 此策略适用于可接受延迟的动态方案。 可将它应用到静态方案,以进一步降低训练频率。
假设存在类似于 TrainLargeFaceList
的 TrainLargePersonGroup
函数。 通过调用 System.Timers
中的 Timer
类,针对 LargePersonGroup 的独立训练的典型实现为:
private static void Main()
{
// Create a LargePersonGroup.
const string LargePersonGroupId = "mylargepersongroupid_001";
const string LargePersonGroupName = "MyLargePersonGroupDisplayName";
faceClient.LargePersonGroup.CreateAsync(LargePersonGroupId, LargePersonGroupName).Wait();
// Set up standalone training at regular intervals.
const int TimeIntervalForStatus = 1000 * 60; // 1-minute interval for getting training status.
const double TimeIntervalForTrain = 1000 * 60 * 60; // 1-hour interval for training.
var trainTimer = new Timer(TimeIntervalForTrain);
trainTimer.Elapsed += (sender, args) => TrainTimerOnElapsed(LargePersonGroupId, TimeIntervalForStatus);
trainTimer.AutoReset = true;
trainTimer.Enabled = true;
// Other operations like creating persons, adding faces, and identification, except for Train.
// ...
}
private static void TrainTimerOnElapsed(string largePersonGroupId, int timeIntervalInMilliseconds)
{
TrainLargePersonGroup(largePersonGroupId, timeIntervalInMilliseconds).Wait();
}
若要详细了解数据管理以及与识别相关的实现,请参阅添加人脸。
总结
本指南介绍了如何将现有 PersonGroup 或 FaceList 代码(不是数据)迁移到 LargePersonGroup 或 LargeFaceList:
- LargePersonGroup 和 LargeFaceList 的工作原理类似于 PersonGroup 或 FaceList,但 LargeFaceList 需要训练操作。
- 采取适当的训练策略可对大规模数据集执行动态数据更新。
后续步骤
参照操作指南了解如何将人脸添加到 PersonGroup,或编写脚本以针对 PersonGroup 执行“识别”操作。