
No início do aprendizado de máquina, a maioria das soluções parecia muito estranha, isolada e incomum. Hoje, muitos algoritmos de ML já estão alinhados em um familiar para um conjunto de estruturas e kits de ferramentas para programadores com os quais você pode trabalhar sem entrar nos detalhes de sua implementação.
A propósito, sou contra uma abordagem tão superficial, mas gostaria de mostrar aos meus colegas que esse setor está avançando aos trancos e barrancos e não há nada complicado para aplicar suas realizações em projetos de produção.
Como exemplo, mostrarei como você pode ajudar o usuário a encontrar o material de vídeo certo entre centenas de outros em nosso serviço de fluxo de trabalho.
No meu projeto, os usuários criam e compartilham centenas de materiais diferentes: texto, fotos, vídeos, artigos, documentos em vários formatos.
A pesquisa de documentos parece bastante simples. Mas o que fazer com a pesquisa de conteúdo multimídia? Para um serviço completo ao usuário, você deve obrigar a preencher uma descrição, dar um nome ao vídeo ou à imagem, várias tags não serão prejudicadas. Infelizmente, nem todo mundo quer gastar tempo com essas melhorias de conteúdo. Normalmente, o usuário envia um link para o youtube, informa que este é um novo vídeo e clica em salvar. O que um serviço pode fazer com esse conteúdo "cinza"? A primeira ideia é perguntar ao YouTube? Mas o YouTube também é preenchido com usuários (geralmente o mesmo usuário). Geralmente, o material de vídeo pode não ser do serviço do YouTube.
Por isso, tive a ideia de ensinar nosso serviço a "ouvir" o vídeo e a "entender" o que se trata.
Admito que essa ideia não é nova, mas hoje para sua implementação não é necessário ter uma equipe de dez cientistas de dados, apenas dois dias e um pouco de recursos de hardware.
Declaração do problema
Nosso microsserviço, vamos chamá-lo de
Summarizer , deve:
- Baixe o vídeo do serviço de mídia;
- Extrair faixa de áudio;
- Ouça a faixa de áudio, na verdade Fala para texto;
- Encontre 20 palavras-chave;
- Selecione uma frase do texto, o que poderia maximizar a essência do vídeo;
- Envie todos os resultados para o serviço de conteúdo;
Confiaremos na implementação do
Python , para que você não precise lidar com a integração com soluções de ML prontas.
Etapa 1: áudio para texto.
Primeiro, instale todos os componentes necessários.
pip3 install wave numpy tensorflow youtube_dl ffmpeg-python deepspeech nltk networkx brew install ffmpeg wget
Em seguida, baixe e descompacte o modelo treinado para a solução Speech to text da Mozilla - Deepspeech.
mkdir /Users/Volodymyr/Projects/deepspeech/ cd /Users/Volodymyr/Projects/deepspeech/ wget https://github.com/mozilla/DeepSpeech/releases/download/v0.3.0/deepspeech-0.3.0-models.tar.gz tar zxvf deepspeech-0.3.0-models.tar.gz
A equipe Mozilla criou e treinou uma solução bastante boa que, usando o TensorFlow, pode transformar longos clipes de áudio em grandes pedaços de texto com alta qualidade.
O TensorFlow também permite que você trabalhe
imediatamente na CPU e na GPU.
Nosso código começará baixando o conteúdo. A maravilhosa biblioteca
youtube-dl , que possui um pós-processador interno capaz de converter o vídeo no formato necessário, o ajudará nisso. Infelizmente, o código pós-processador é um pouco limitado, não sabe como reamostrar, por isso vamos ajudá-lo.
Para a entrada Deepspeech, você precisa enviar um arquivo de áudio com uma faixa mono e uma amostra de 16K. Para fazer isso, precisamos reprocessar nosso arquivo recebido.
_ = ffmpeg.input(youtube_id + '.wav').output(output_file_name, ac=1, t=crop_time, ar='16k').overwrite_output().run(capture_stdout=False)
Na mesma operação, também podemos limitar a duração do nosso arquivo, passando um parâmetro adicional "t".
Faça o download do modelo deepspeech.
deepspeech = Model(args.model, N_FEATURES, N_CONTEXT, args.alphabet, BEAM_WIDTH)
Usando a biblioteca wave, extraímos quadros no formato np.array e os transferimos para a entrada da biblioteca deepspeech.
fin = wave.open(file_name, 'rb') framerate_sample = fin.getframerate() if framerate_sample != 16000: print('Warning: original sample rate ({}) is different than 16kHz. Resampling might produce erratic speech recognition.'.format(framerate_sample), file=sys.stderr) fin.close() return else: audio = np.frombuffer(fin.readframes(fin.getnframes()), np.int16) audio_length = fin.getnframes() * (1/16000) fin.close() print('Running inference.', file=sys.stderr) inference_start = timer() result = deepspeech.stt(audio, framerate_sample)
Depois de um tempo, proporcional aos seus recursos de hardware, você receberá um texto.
Etapa 2: Encontrar o "significado"
Para procurar palavras que descrevam o texto resultante, usarei o método gráfico. Este método é baseado na distância entre seqüências. Primeiro encontramos todas as palavras “únicas”, imagine que esses são os vértices do nosso gráfico. Depois de percorrer o texto com uma “janela” de um determinado comprimento, encontramos a distância entre as palavras, elas serão as bordas da nossa gaff. Os vértices adicionados ao gráfico podem ser limitados por filtros de sintaxe que selecionam apenas unidades lexicais de uma determinada parte da fala. Por exemplo, você pode considerar apenas substantivos e verbos a serem adicionados ao gráfico. Portanto, construiremos arestas potenciais com base apenas em relacionamentos que podem ser estabelecidos entre substantivos e verbos.
A pontuação associada a cada vértice é definida como um valor inicial de 1 e o algoritmo de classificação é iniciado. O algoritmo de classificação é um "voto" ou "recomendação". Quando um vértice é conectado a outro, ele “vota” nesse vértice (conectado). Quanto maior o número de votos para um pico, maior a importância desse pico. Além disso, a importância do topo da votação determina a importância da votação em si, e essas informações também são levadas em consideração pelo modelo de classificação. Portanto, a pontuação associada ao topo é determinada com base nos votos expressos e na classificação dos picos que dão esses votos.
Suponha que tenhamos um gráfico G = (V, E) descrito pelos vértices V e arestas E. Para um dado vértice V, deve haver um conjunto de vértices E que estão conectados a ele. Para cada vértice Vi, há vértices In (Vi) associados a ele e vértices Out (Vi) aos quais o vértice Vi está associado. Assim, o peso do vértice Vi pode ser representado pela fórmula.
Onde d é o fator de atenuação / supressão, assumindo um valor de 1 a 0.
O algoritmo deve iterar o gráfico várias vezes para obter estimativas aproximadas.
Depois de obter uma estimativa aproximada para cada vértice no gráfico, os vértices são classificados em ordem decrescente. Os vértices que aparecem no topo da lista serão nossas palavras-chave desejadas.
A sentença mais relevante no texto é encontrada ao encontrar a média da adição de estimativas de todas as palavras na sentença. Ou seja, somamos todas as estimativas e dividimos pelo número de palavras na frase.
iMac:YoutubeSummarizer $ cd /Users/Volodymyr/Projects/YoutubeSummarizer ; env "PYTHONIOENCODING=UTF-8" "PYTHONUNBUFFERED=1" /usr/local/bin/python3 /Users/Volodymyr/.vscode/extensions/ms-python.python-2018.11.0/pythonFiles/experimental/ptvsd_launcher.py --default --client --host localhost --port 53730 /Users/Volodymyr/Projects/YoutubeSummarizer/summarizer.py --youtube-id yA-FCxFQNHg --model /Users/Volodymyr/Projects/deepspeech/models/output_graph.pb --alphabet /Users/Volodymyr/Projects/deepspeech/models/alphabet.txt --lm /Users/Volodymyr/Projects/deepspeech/models/lm.binary --trie /Users/Volodymyr/Projects/deepspeech/models/trie --crop-time 900 Done downloading, now converting ... ffmpeg version 4.1 Copyright (c) 2000-2018 the FFmpeg developers built with Apple LLVM version 10.0.0 (clang-1000.11.45.5) configuration: --prefix=/usr/local/Cellar/ffmpeg/4.1 --enable-shared --enable-pthreads --enable-version3 --enable-hardcoded-tables --enable-avresample --cc=clang --host-cflags= --host-ldflags= --enable-ffplay --enable-gpl --enable-libmp3lame --enable-libopus --enable-libsnappy --enable-libtheora --enable-libvorbis --enable-libvpx --enable-libx264 --enable-libx265 --enable-libxvid --enable-lzma --enable-opencl --enable-videotoolbox libavutil 56. 22.100 / 56. 22.100 libavcodec 58. 35.100 / 58. 35.100 libavformat 58. 20.100 / 58. 20.100 libavdevice 58. 5.100 / 58. 5.100 libavfilter 7. 40.101 / 7. 40.101 libavresample 4. 0. 0 / 4. 0. 0 libswscale 5. 3.100 / 5. 3.100 libswresample 3. 3.100 / 3. 3.100 libpostproc 55. 3.100 / 55. 3.100 Guessed Channel Layout for Input Stream
Sumário
As idéias que vêm à sua mente podem ser realizadas muito mais rapidamente hoje do que há três ou quatro anos atrás. Experimente, experimente! Eu acho que a inteligência artificial é principalmente a inteligência dos engenheiros que trabalham com ela.
O código está disponível no
meu repositório Github .