Dimensionar para lidar com mais usuários inscritos
Atenção
O acesso ao serviço presencial é limitado com base em critérios de elegibilidade e uso, a fim de apoiar nossos princípios de IA responsável. O serviço Face só está disponível para clientes e parceiros geridos pela Microsoft. Use o formulário de admissão de Reconhecimento Facial para solicitar acesso. Para obter mais informações, consulte a página Acesso limitado Face.
Este guia mostra como escalar de objetos PersonGroup e FaceList existentes para objetos LargePersonGroup e LargeFaceList, respectivamente. Os PersonGroups podem acomodar até 1000 pessoas no nível gratuito e 10.000 no nível pago, enquanto os LargePersonGroups podem acomodar até um milhão de pessoas no nível pago.
Importante
A estrutura de dados mais recente PersonDirectory é recomendada para novos desenvolvimentos. Pode conter até 75 milhões de identidades e não requer treinamento manual. Para obter mais informações, consulte o guia PersonDirectory.
Este guia demonstra o processo de migração. Ele pressupõe uma familiaridade básica com objetos PersonGroup e FaceList, a operação Train e as funções de reconhecimento facial. Para saber mais sobre esses assuntos, consulte o guia conceitual de reconhecimento facial.
LargePersonGroup e LargeFaceList são coletivamente referidos como operações de grande escala. LargePersonGroup pode conter até 1 milhão de pessoas, cada uma com um máximo de 248 rostos. LargeFaceList pode conter até 1 milhão de rostos. As operações em grande escala são semelhantes às convencionais PersonGroup e FaceList , mas têm algumas diferenças por causa da nova arquitetura.
Os exemplos são escritos em C#.
Nota
Para habilitar o desempenho de pesquisa de rosto para Identificação e FindSimilar em grande escala, introduza uma operação Train para pré-processar o LargeFaceList e o LargePersonGroup. O tempo de treinamento varia de segundos a cerca de meia hora com base na capacidade real. Durante o período de treinamento, é possível realizar Identificação e FindSimilar se uma operação de treinamento bem-sucedida foi feita antes. A desvantagem é que as novas pessoas e rostos adicionados não aparecem no resultado até que um novo pós-migração para treinamento em larga escala seja concluído.
Etapa 1: Migração de código
Esta seção se concentra em como migrar a implementação de PersonGroup ou FaceList para LargePersonGroup ou LargeFaceList. Embora LargePersonGroup ou LargeFaceList difira de PersonGroup ou FaceList em design e implementação interna, as interfaces de API são semelhantes para compatibilidade com versões anteriores.
A migração de dados não é suportada. Em vez disso, recrie o LargePersonGroup ou LargeFaceList .
Migrar um PersonGroup para um LargePersonGroup
A migração de um PersonGroup para um LargePersonGroup é simples. Eles compartilham exatamente as mesmas operações em nível de grupo.
Para PersonGroup ou implementação relacionada a pessoas, é necessário alterar apenas os caminhos da API ou classe/módulo SDK para LargePersonGroup e LargePersonGroup Person.
Adicione todos os rostos e pessoas do PersonGroup ao novo LargePersonGroup. Para obter mais informações, consulte Adicionar rostos.
Migrar uma FaceList para uma LargeFaceList
APIs do FaceList | APIs LargeFaceList |
---|---|
Criar | Criar |
Eliminar | Delete |
Get | Obtenção |
Listagem | Listagem |
Atualizar | Atualizar |
- | Treinar |
- | Obter Estado do Treino |
A tabela anterior é uma comparação de operações de nível de lista entre FaceList e LargeFaceList. Como é mostrado, o LargeFaceList vem com novas operações, Train and Get Training Status, quando comparado com o FaceList. Treinar o LargeFaceList é uma pré-condição da operação FindSimilar . O treinamento não é necessário para o FaceList. O trecho a seguir é uma função auxiliar para aguardar o treinamento de uma 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)
{
HttpClient httpClient = new HttpClient();
httpClient.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", SUBSCRIPTION_KEY);
// Trigger a train call.
await httpClient.PostAsync($"{ENDPOINT}/face/v1.0/largefacelists/{largeFaceListId}/train", null);
// Wait for training finish.
while (true)
{
await Task.Delay(timeIntervalInMilliseconds);
string? trainingStatus = null;
using (var response = await httpClient.GetAsync($"{ENDPOINT}/face/v1.0/largefacelists/{largeFaceListId}/training"))
{
string contentString = await response.Content.ReadAsStringAsync();
trainingStatus = (string?)(JsonConvert.DeserializeObject<Dictionary<string, object>>(contentString)?["status"]);
}
if ("running".Equals(trainingStatus))
{
continue;
}
else if ("succeeded".Equals(trainingStatus))
{
break;
}
else
{
throw new Exception("The train operation is failed!");
}
}
}
Anteriormente, um uso típico do FaceList com rostos adicionados e FindSimilar era semelhante ao seguinte:
// Create a FaceList.
const string FaceListId = "myfacelistid_001";
const string FaceListName = "MyFaceListDisplayName";
const string ImageDir = @"/path/to/FaceList/images";
using (var content = new ByteArrayContent(Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(new Dictionary<string, object> { ["name"] = FaceListName, ["recognitionModel"] = "recognition_04" }))))
{
content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
await httpClient.PutAsync($"{ENDPOINT}/face/v1.0/facelists/{FaceListId}", content);
}
// Add Faces to the FaceList.
Parallel.ForEach(
Directory.GetFiles(ImageDir, "*.jpg"),
async imagePath =>
{
using (Stream stream = File.OpenRead(imagePath))
{
using (var content = new StreamContent(stream))
{
content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
await httpClient.PostAsync($"{ENDPOINT}/face/v1.0/facelists/{FaceListId}/persistedfaces?detectionModel=detection_03", content);
}
}
});
// Perform FindSimilar.
const string QueryImagePath = @"/path/to/query/image";
var results = new List<HttpResponseMessage>();
using (Stream stream = File.OpenRead(QueryImagePath))
{
var response = await faceClient.DetectAsync(BinaryData.FromStream(stream), FaceDetectionModel.Detection03, FaceRecognitionModel.Recognition04, returnFaceId: true);
var faces = response.Value;
foreach (var face in faces)
{
using (var content = new ByteArrayContent(Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(new Dictionary<string, object> { ["faceId"] = face.FaceId, ["faceListId"] = FaceListId }))))
{
content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
results.Add(await httpClient.PostAsync($"{ENDPOINT}/face/v1.0/findsimilars", content));
}
}
}
Ao migrá-lo para LargeFaceList, torna-se o seguinte:
// Create a LargeFaceList.
const string LargeFaceListId = "mylargefacelistid_001";
const string LargeFaceListName = "MyLargeFaceListDisplayName";
const string ImageDir = @"/path/to/FaceList/images";
using (var content = new ByteArrayContent(Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(new Dictionary<string, object> { ["name"] = LargeFaceListName, ["recognitionModel"] = "recognition_04" }))))
{
content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
await httpClient.PutAsync($"{ENDPOINT}/face/v1.0/largefacelists/{LargeFaceListId}", content);
}
// Add Faces to the LargeFaceList.
Parallel.ForEach(
Directory.GetFiles(ImageDir, "*.jpg"),
async imagePath =>
{
using (Stream stream = File.OpenRead(imagePath))
{
using (var content = new StreamContent(stream))
{
content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
await httpClient.PostAsync($"{ENDPOINT}/face/v1.0/largefacelists/{LargeFaceListId}/persistedfaces?detectionModel=detection_03", content);
}
}
});
// Train() is newly added operation for LargeFaceList.
// Must call it before FindSimilar to ensure the newly added faces searchable.
await TrainLargeFaceList(LargeFaceListId);
// Perform FindSimilar.
const string QueryImagePath = @"/path/to/query/image";
var results = new List<HttpResponseMessage>();
using (Stream stream = File.OpenRead(QueryImagePath))
{
var response = await faceClient.DetectAsync(BinaryData.FromStream(stream), FaceDetectionModel.Detection03, FaceRecognitionModel.Recognition04, returnFaceId: true);
var faces = response.Value;
foreach (var face in faces)
{
using (var content = new ByteArrayContent(Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(new Dictionary<string, object> { ["faceId"] = face.FaceId, ["largeFaceListId"] = LargeFaceListId }))))
{
content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
results.Add(await httpClient.PostAsync($"{ENDPOINT}/face/v1.0/findsimilars", content));
}
}
}
Como mostrado anteriormente, o gerenciamento de dados e a parte FindSimilar são quase os mesmos. A única exceção é que uma nova operação de trem de pré-processamento deve ser concluída no LargeFaceList antes que o FindSimilar funcione.
Passo 2: Sugestões de comboios
Embora a operação do trem acelere o FindSimilar e o Identification, o tempo de treinamento sofre, especialmente quando se trata de grande escala. O tempo estimado de treinamento em diferentes escalas está listado na tabela a seguir.
Escala para rostos ou pessoas | Tempo estimado de treinamento |
---|---|
1,000 | 1-2 seg |
10.000 | 5-10 seg |
100.000 | 1-2 minutos |
1.000.000 | 10-30 minutos |
Para utilizar melhor o recurso em grande escala, recomendamos as seguintes estratégias.
Etapa 2a: Personalizar o intervalo de tempo
Como é mostrado no TrainLargeFaceList()
, há um intervalo de tempo em milissegundos para atrasar o processo infinito de verificação do status do treinamento. Para LargeFaceList com mais faces, usar um intervalo maior reduz a contagem de chamadas e o custo. Personalize o intervalo de tempo de acordo com a capacidade esperada do LargeFaceList.
A mesma estratégia também se aplica ao LargePersonGroup. Por exemplo, quando você treina um LargePersonGroup com 1 milhão de pessoas, timeIntervalInMilliseconds
pode ser 60.000, que é um intervalo de 1 minuto.
Etapa 2b: Buffer de pequena escala
Pessoas ou rostos em um LargePersonGroup ou um LargeFaceList são pesquisáveis somente depois de serem treinados. Em um cenário dinâmico, novas pessoas ou rostos são constantemente adicionados e devem ser imediatamente pesquisáveis, mas o treinamento pode levar mais tempo do que o desejado.
Para atenuar esse problema, use um LargePersonGroup ou LargeFaceList extra de pequena escala como um buffer apenas para as entradas recém-adicionadas. Este buffer leva menos tempo para treinar devido ao tamanho menor. A capacidade de pesquisa imediata neste buffer temporário deve funcionar. Use esse buffer em combinação com o treinamento no mestre LargePersonGroup ou LargeFaceList executando o treinamento mestre em um intervalo mais esparso. Os exemplos são no meio da noite e diariamente.
Exemplo de fluxo de trabalho:
- Crie um mestre LargePersonGroup ou LargeFaceList, que é a coleção master. Crie um buffer LargePersonGroup ou LargeFaceList, que é a coleção de buffer. A coleção de buffer é apenas para pessoas ou rostos recém-adicionados.
- Adicione novas pessoas ou rostos à coleção master e à coleção buffer.
- Treine apenas a coleção de buffer com um curto intervalo de tempo para garantir que as entradas recém-adicionadas entrem em vigor.
- Identificação de chamada ou FindSimilar na coleção mestre e na coleção de buffer. Mescle os resultados.
- Quando o tamanho da coleção de buffer aumentar para um limite ou em um momento ocioso do sistema, crie uma nova coleção de buffer. Acione a operação Train na coleção principal.
- Exclua a coleção de buffer antiga depois que a operação Train terminar na coleção mestre.
Passo 2c: Formação autónoma
Se uma latência relativamente longa for aceitável, não é necessário acionar a operação Train logo após adicionar novos dados. Em vez disso, a operação do trem pode ser separada da lógica principal e acionada regularmente. Esta estratégia é adequada para cenários dinâmicos com latência aceitável. Pode ser aplicado a cenários estáticos para reduzir ainda mais a frequência do comboio .
Suponha que haja uma TrainLargePersonGroup
função semelhante a TrainLargeFaceList
. Uma implementação típica do treinamento autônomo em um LargePersonGroup invocando a Timer
classe em System.Timers
é:
private static void Main()
{
// 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("mylargepersongroupid_001", 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();
}
Para obter mais informações sobre gerenciamento de dados e implementações relacionadas à identificação, consulte Adicionar rostos.
Resumo
Neste guia, você aprendeu como migrar o código PersonGroup ou FaceList existente, não dados, para LargePersonGroup ou LargeFaceList:
- LargePersonGroup e LargeFaceList funcionam de forma semelhante a PersonGroup ou FaceList, exceto que a operação de trem é exigida por LargeFaceList.
- Adote a estratégia Train adequada para atualização dinâmica de dados para conjuntos de dados em grande escala.
Próximos passos
Siga um guia de instruções para saber como adicionar rostos a um PersonGroup ou escrever um script para executar a operação Identificar em um PersonGroup.