Transcrição com Identificação de Locutor usando WhisperX no SageMaker AI

O problema que toda equipe que trabalha com áudio enfrenta

Qualquer time que lida com áudio falado — centrais de atendimento, reuniões corporativas, podcasts, audiências jurídicas ou conteúdo de mídia — esbarra nos mesmos dois problemas com sistemas genéricos de reconhecimento de fala:

  • Timestamps imprecisos: os carimbos de tempo ficam no nível da frase ou segmento, podendo estar vários segundos fora do lugar.
  • Sem identificação de locutor: não há resposta confiável para “quem disse o quê”.

Essas lacunas tornam as transcrições difíceis de pesquisar, legendar, redigir ou analisar em escala. Um rótulo de locutor ausente compromete revisões de conformidade; um timestamp impreciso quebra uma legenda ou uma redação de dado sensível.

O que é o WhisperX e o que ele resolve

O Whisper é um modelo popular de Reconhecimento Automático de Fala (ASR — Automatic Speech Recognition) de código aberto desenvolvido pela OpenAI. Ele transcreve áudio falado com boa precisão em vários idiomas, mas produz timestamps apenas no nível de frase ou segmento.

O WhisperX é um projeto de código aberto que estende o Whisper para cargas de trabalho em produção. Ele adiciona três capacidades que transformam o áudio bruto em transcrições estruturadas e analisáveis:

  • Timestamps por palavra: usando alinhamento forçado via wav2vec2, cada palavra recebe seu próprio carimbo de tempo preciso.
  • Identificação de locutor (diarização): rotula quem está falando em cada trecho do áudio.
  • Inferência em lote mais rápida: acelera o processamento para cargas maiores.

Essas capacidades se traduzem diretamente em casos de uso reais: centrais de atendimento podem medir tempo de fala, verificar aderência a scripts e rodar análise de sentimento; equipes transformam reuniões em notas pesquisáveis; times de mídia e e-learning geram legendas precisas nos formatos SRT (SubRip Subtitle) e VTT (Web Video Text Tracks); e áreas reguladas como saúde, jurídico e finanças usam as transcrições com rótulo de locutor para auditorias e descoberta legal.

Por que usar o Deep Learning Container da AWS

O DLC (Deep Learning Container — Contêiner de Aprendizado Profundo) do WhisperX da AWS é uma imagem mantida e pronta para GPU que já contém o Whisper, os modelos de alinhamento e os pesos de diarização — sem necessidade de token do Hugging Face. Ele segue o contrato padrão de serviço do Amazon SageMaker AI, então o deploy funciona como qualquer outro modelo.

Alguns detalhes do contrato de serviço:

  • O contêiner serve na porta 8080 e expõe POST /invocations para inferência e GET /ping para verificação de saúde.
  • O endpoint espera requisições no formato multipart/form-data, com o áudio como parte file e campos opcionais como language, diarize e response_format.
  • Os formatos de saída suportados são: json, verbose_json, srt e vtt — o mesmo endpoint alimenta tanto pipelines de análise quanto editores de vídeo.

Escolhendo entre endpoint em tempo real e assíncrono

O SageMaker AI suporta dois tipos de endpoint para o mesmo DLC do WhisperX. A escolha depende do tamanho do clipe e da necessidade de interatividade:

  • Endpoint em tempo real: ideal para clipes curtos e interativos que terminam dentro do limite de 60 segundos de resposta do SageMaker AI.
  • Endpoint assíncrono: recomendado para áudios longos e processamento em lote de alto volume. Não há limite de tempo de resposta; a entrada e a saída são intermediadas pelo Amazon S3.

A tabela abaixo resume as diferenças principais entre os dois padrões:

  • Latência: tempo real é síncrono (deve terminar em menos de 60s); assíncrono é no modelo enviar-e-consultar, sem limite de tempo.
  • Invocação: tempo real usa InvokeEndpoint com corpo inline; assíncrono usa InvokeEndpointAsync com referência ao S3.
  • Entrada/Saída: tempo real usa corpo da requisição/resposta; assíncrono usa Amazon S3 para entrada e saída.
  • Custo: tempo real cobra enquanto o endpoint está ativo; assíncrono pode escalar a zero quando ocioso, reduzindo custos.

Pré-requisitos

Para seguir os exemplos, você vai precisar de:

  • Uma conta AWS e uma função de execução do SageMaker AI com permissões para create_model, create_endpoint e (para inferência assíncrona) leitura e escrita no S3.
  • Cota de serviço de GPU para o tipo de instância desejado (por exemplo, ml.g4dn.xlarge ou ml.g5.2xlarge).
  • A URI de imagem do DLC do WhisperX no ECR (Amazon Elastic Container Registry): 763104351884.dkr.ecr.<region>.amazonaws.com/whisperx:3.8.6-cu128-amzn2023-sagemaker.
  • Para inferência assíncrona: um bucket S3 cujo nome contenha “sagemaker” — a política padrão AmazonSageMakerFullAccess concede acesso ao S3 apenas para buckets com esse padrão no nome.

Um notebook JupyterLab completo e executável está disponível no repositório AWS Samples, e pode ser rodado diretamente no SageMaker AI Studio com seu próprio áudio.

Passo a passo: endpoint em tempo real

O endpoint em tempo real retorna a transcrição na mesma chamada síncrona. O fluxo funciona assim: o cliente monta um corpo multipart/form-data com o áudio e campos como language, diarize e granularidade de timestamp por palavra, e chama InvokeEndpoint. O SageMaker AI encaminha a requisição ao contêiner na porta 8080. Dentro do contêiner, o WhisperX executa detecção de atividade de voz, transcrição em lote, alinhamento forçado via wav2vec2 e diarização de locutor. O resultado — segmentos, timestamps por palavra e rótulos de locutor — é retornado inline ao cliente, tudo dentro do limite de 60 segundos.

Criando o modelo e a configuração de endpoint

Registre o DLC do WhisperX como modelo e crie a configuração de endpoint. Um detalhe crítico: em qualquer variante de GPU, é obrigatório definir InferenceAmiVersion como al2-ami-sagemaker-inference-gpu-3-1. Sem esse pin, o endpoint falha ao iniciar com um erro CannotStartContainerError sem nenhum log. Também é necessário configurar um timeout generoso para o health check de inicialização, pois os pesos são carregados de forma lazy.

sm = boto3.client("sagemaker")

# The WhisperX Deep Learning Container image (Python 3.12, CUDA 12.8, Amazon Linux 2023).
REGION = "us-west-2"
IMAGE_URI = f"763104351884.dkr.ecr.{REGION}.amazonaws.com/whisperx:3.8.6-cu128-amzn2023-sagemaker"

sm.create_model(
    ModelName=MODEL_NAME,
    PrimaryContainer={"Image": IMAGE_URI},  # WhisperX DLC; large-v2 is the default model
    ExecutionRoleArn=ROLE_ARN,
)

sm.create_endpoint_config(
    EndpointConfigName=ENDPOINT_CONFIG_NAME,
    ProductionVariants=[{
        "VariantName": "AllTraffic",
        "ModelName": MODEL_NAME,
        "InitialInstanceCount": 1,
        "InstanceType": "ml.g4dn.xlarge",
        "InferenceAmiVersion": "al2-ami-sagemaker-inference-gpu-3-1",  # required for CUDA 12.8 DLC
        "ContainerStartupHealthCheckTimeoutInSeconds": 900,
    }],
)

sm.create_endpoint(EndpointName=ENDPOINT_NAME, EndpointConfigName=ENDPOINT_CONFIG_NAME)
sm.get_waiter("endpoint_in_service").wait(EndpointName=ENDPOINT_NAME)

Invocando com diarização e timestamps por palavra

Monte um corpo multipart/form-data com o áudio e os campos de configuração, depois chame o endpoint:

def build_multipart(audio_path, fields):
    """Audio as the `file` part + optional string fields, per the WhisperX DLC contract."""
    boundary = uuid.uuid4().hex
    body = b""
    for name, value in fields.items():
        body += (f"--{boundary}\r\n"
                 f'Content-Disposition: form-data; name="{name}"\r\n\r\n'
                 f"{value}\r\n").encode()
    body += (f"--{boundary}\r\n"
             f'Content-Disposition: form-data; name="file"; filename="audio.wav"\r\n'
             f"Content-Type: audio/wav\r\n\r\n").encode()
    body += open(audio_path, "rb").read() + b"\r\n"
    body += f"--{boundary}--\r\n".encode()
    return body, f"multipart/form-data; boundary={boundary}"

body, content_type = build_multipart("audio.wav", {
    "language": "en",
    "response_format": "verbose_json",
    "timestamp_granularities[]": "word",   # word-level timestamps
    "diarize": "true",                      # speaker labels
})

resp = sm_runtime.invoke_endpoint(
    EndpointName=ENDPOINT_NAME,
    ContentType=content_type,
    Body=body,
)
transcription = json.loads(resp["Body"].read())

O repositório de exemplo usa uma gravação de domínio público das comunicações de controle de tráfego aéreo do Voo 1549 da US Airways — o famoso pouso de emergência no Rio Hudson em 2009. É uma conversa real entre múltiplos participantes com ruído de fundo, compressão de rádio e leituras rápidas de indicativos e frequências, o que o torna um excelente teste de precisão de transcrição, timestamps por palavra e diarização. Um segmento de 40 segundos é enviado ao endpoint em tempo real, e o resultado retornado se parece com isto:

[00:02] SPEAKER_01: Cactus 1549, turn left heading 270.
[00:04] SPEAKER_00: This is Cactus 1539, head first to Placid Crest, I'm hoping it's returning back towards LaGuardia.
[00:11] SPEAKER_01: Okay, you need to return to LaGuardia, turn left heading of 220.
[00:14] SPEAKER_01: 220.
[00:18] SPEAKER_01: Tower, stoppy to park, he's got emergency returning.
[00:22] SPEAKER_01: Who is it?
[00:23] SPEAKER_01: It's 1529, he, uh, bird strike, he lost all engine, he lost the thrust in the engine, so he's returning immediately.
[00:28] SPEAKER_01: Check, it's 1529, which engines?
[00:30] SPEAKER_01: He lost thrust in both engines, he said.
[00:32] SPEAKER_01: Got it.
[00:34] SPEAKER_01: Check, it's 1529, if we can get it for you, do you want to try to land 131.3?

Passo a passo: endpoint assíncrono

O endpoint assíncrono remove o limite de 60 segundos e é o caminho recomendado para áudios longos. A entrada e a saída são intermediadas pelo Amazon S3, e o cliente consulta o resultado após o envio.

O fluxo funciona assim: o cliente faz upload do corpo multipart/form-data para o S3 e chama InvokeEndpointAsync com o InputLocation do objeto. Ele recebe imediatamente um OutputLocation e um FailureLocation — sem esperar pela transcrição. O SageMaker AI lê a entrada do S3, encaminha ao contêiner e executa o mesmo pipeline de detecção de voz, transcrição, alinhamento e diarização. Em caso de sucesso, o resultado é gravado no caminho de saída do S3; em caso de falha, um documento de erro vai para o caminho de falha. O cliente consulta o caminho de saída para obter o resultado.

Criando a configuração do endpoint assíncrono

A única diferença estrutural em relação ao endpoint em tempo real está na configuração: ela adiciona um AsyncInferenceConfig com S3OutputPath e S3FailurePath. Configure MaxConcurrentInvocationsPerInstance=1 para respeitar o limite de worker único do contêiner, e mantenha o mesmo pin de InferenceAmiVersion.

# Same WhisperX DLC image as the real-time endpoint.
IMAGE_URI = f"763104351884.dkr.ecr.{REGION}.amazonaws.com/whisperx:3.8.6-cu128-amzn2023-sagemaker"

sm.create_model(
    ModelName=ASYNC_MODEL_NAME,
    PrimaryContainer={"Image": IMAGE_URI},  # WhisperX DLC
    ExecutionRoleArn=ROLE_ARN,
)

sm.create_endpoint_config(
    EndpointConfigName=ASYNC_ENDPOINT_CONFIG_NAME,
    ProductionVariants=[{
        "VariantName": "AllTraffic",
        "ModelName": ASYNC_MODEL_NAME,
        "InitialInstanceCount": 1,
        "InstanceType": "ml.g5.2xlarge",
        "InferenceAmiVersion": "al2-ami-sagemaker-inference-gpu-3-1",
        "ContainerStartupHealthCheckTimeoutInSeconds": 1200,
    }],
    AsyncInferenceConfig={
        "OutputConfig": {
            "S3OutputPath": f"s3://{BUCKET}/whisperx-async/output/",
            "S3FailurePath": f"s3://{BUCKET}/whisperx-async/failure/",
        },
        "ClientConfig": {"MaxConcurrentInvocationsPerInstance": 1},  # 1 request/container
    },
)

sm.create_endpoint(EndpointName=ASYNC_ENDPOINT_NAME, EndpointConfigName=ASYNC_ENDPOINT_CONFIG_NAME)
sm.get_waiter("endpoint_in_service").wait(EndpointName=ASYNC_ENDPOINT_NAME)

O restante do fluxo é idêntico ao endpoint em tempo real: o helper build_multipart e os campos de transcrição não mudam. A diferença é que você submete usando invoke_endpoint_async por referência ao S3, e depois lê a transcrição do OutputLocation. O processamento da gravação completa de aproximadamente 3 minutos retorna uma transcrição com rótulos de locutor do início ao fim do áudio.

Limpeza de recursos

Um endpoint GPU cobra continuamente até ser deletado. Ao terminar, delete o endpoint, a configuração e o modelo para ambos os endpoints, e remova os artefatos de entrada e saída do S3 que não forem mais necessários:

# A GPU endpoint bills until deleted. Delete endpoint -> config -> model for each endpoint.
for name, cfg, model in [
    (ENDPOINT_NAME, ENDPOINT_CONFIG_NAME, MODEL_NAME),
    (ASYNC_ENDPOINT_NAME, ASYNC_ENDPOINT_CONFIG_NAME, ASYNC_MODEL_NAME),
]:
    sm.delete_endpoint(EndpointName=name)
    sm.delete_endpoint_config(EndpointConfigName=cfg)
    sm.delete_model(ModelName=model)

Boas práticas e considerações para produção

  • Fixe a AMI de GPU: sempre defina InferenceAmiVersion=al2-ami-sagemaker-inference-gpu-3-1 em variantes GPU. A AMI padrão tem drivers incompatíveis com esta imagem CUDA 12.8.
  • Escale por instâncias, não por concorrência: a inferência é serializada para uma requisição por contêiner. Defina MaxConcurrentInvocationsPerInstance=1 em endpoints assíncronos e adicione instâncias para aumentar o throughput.
  • Escale endpoints assíncronos a zero: para cargas em lote com picos, escale o endpoint assíncrono a zero instâncias quando ocioso para reduzir custos. Use notificações de conclusão via Amazon Simple Notification Service (Amazon SNS) em vez de polling agressivo.
  • Escolha a GPU certa e use pools de instâncias: use ml.g4dn.xlarge (T4) para custo ou ml.g5.2xlarge (A10G) para mais folga. Para evitar erros de capacidade insuficiente, liste até cinco tipos de instância em um pool do SageMaker AI — ele provisiona o tipo de maior prioridade e faz fallback automaticamente.
  • Proteja os artefatos no S3: ative o Block Public Access, criptografia padrão SSE-S3 ou SSE-KMS, e BucketOwnerEnforced no bucket assíncrono. Restrinja a função de execução a buckets e chaves específicos.
  • Trate dados pessoais com responsabilidade: transcrições de chamadas e reuniões podem conter dados sensíveis — criptografe os artefatos, restrinja o acesso e aplique redação downstream usando os timestamps por palavra.
  • Monitore e configure retentativas: use o Amazon CloudWatch para monitorar, configure alarmes para falhas e implemente retentativas para o comportamento de cold-start. Para visibilidade mais profunda de GPU e inferência, ative o painel de métricas detalhadas e Insights do SageMaker AI no CloudWatch.

Conclusão

A AWS publicou um guia completo sobre como fazer o deploy do DLC do WhisperX no SageMaker AI para transcrição com timestamps por palavra e identificação de locutor. A solução cobre dois padrões de endpoint — tempo real para clipes curtos e interativos, e assíncrono para áudios longos e alto volume — e detalha os pontos críticos de produção: o pin obrigatório da AMI de GPU, o escalonamento por instância única, a nomenclatura do bucket S3 e os controles de custo.

Para explorar mais, consulte o guia de deploy do DLC do WhisperX, revise a documentação de inferência assíncrona do SageMaker AI e experimente o notebook de demonstração com seu próprio áudio. O exemplo completo e funcional está disponível no repositório AWS Samples no GitHub.

Fonte

Speaker-labeled transcription with WhisperX on SageMaker AI (https://aws.amazon.com/blogs/machine-learning/speaker-labeled-transcription-with-whisperx-on-sagemaker-ai/)

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *