De qué habla YouTube

imagen

En los albores del aprendizaje automático, la mayoría de las soluciones parecían muy extrañas, aisladas e inusuales. Hoy en día, muchos algoritmos de ML ya se están alineando en un conjunto familiar de programadores de marcos y kits de herramientas con los que puede trabajar sin entrar en detalles de su implementación.
Por cierto, me opongo a un enfoque tan superficial, pero me gustaría mostrarles a mis colegas que esta industria está avanzando a pasos agigantados y que no hay nada complicado para aplicar sus logros en proyectos de producción.

Como ejemplo, mostraré cómo puede ayudar al usuario a encontrar el material de video correcto entre cientos de otros en nuestro servicio de flujo de trabajo.

En mi proyecto, los usuarios crean y comparten cientos de materiales diferentes: texto, imágenes, videos, artículos, documentos en varios formatos.

La búsqueda de documentos parece bastante simple. ¿Pero qué hacer con la búsqueda de contenido multimedia? Para un servicio de usuario completo, debe obligar a completar una descripción, dar un nombre al video o imagen, varias etiquetas no dañarán. Desafortunadamente, no todos quieren pasar tiempo en tales mejoras de contenido. Por lo general, el usuario carga un enlace a YouTube, informa que este es un video nuevo y hace clic en Guardar. ¿Qué puede hacer un servicio con ese contenido "gris"? La primera idea es preguntarle a YouTube? Pero YouTube también está lleno de usuarios (a menudo el mismo usuario). A menudo, el material de video puede no ser del servicio de Youtube.
Así que tuve la idea de enseñar nuestro servicio para "escuchar" el video y "entender" de qué se trata.

Admito que esta idea no es nueva, pero hoy para su implementación no es necesario tener un equipo de diez científicos de datos, solo dos días y un poco de recursos de hardware.

Declaración del problema.


Nuestro microservicio, llamémoslo Summarizer , debería:

  • Descargar video del servicio de medios;
  • Extraer pista de audio;
  • Escucha la pista de audio, en realidad Habla a texto;
  • Encuentra 20 palabras clave;
  • Seleccione una oración del texto, que podría maximizar la esencia del video;
  • Enviar todos los resultados al servicio de contenido;

Confiaremos en la implementación de Python , para que no tenga que lidiar con la integración con soluciones ML preparadas.

Paso uno: audio a texto.

Primero, instale todos los componentes necesarios.

pip3 install wave numpy tensorflow youtube_dl ffmpeg-python deepspeech nltk networkx brew install ffmpeg wget 

A continuación, descargue y desempaquete el modelo entrenado para la solución de voz a texto de 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 

El equipo de Mozilla creó y capacitó una solución bastante buena que, utilizando TensorFlow, puede convertir largos clips de audio en grandes fragmentos de texto con alta calidad. TensorFlow también le permite trabajar fuera de la caja tanto en la CPU como en la GPU.

Nuestro código comenzará descargando contenido. La maravillosa biblioteca youtube-dl , que tiene un postprocesador incorporado capaz de convertir video al formato requerido, lo ayudará en esto. Desafortunadamente, el código del postprocesador es un poco limitado, no sabe cómo volver a muestrear, por lo que lo ayudaremos.
Para la entrada Deepspeech, debe enviar un archivo de audio con una pista mono y una muestra de 16K. Para hacer esto, necesitamos volver a procesar nuestro archivo recibido.

 _ = ffmpeg.input(youtube_id + '.wav').output(output_file_name, ac=1, t=crop_time, ar='16k').overwrite_output().run(capture_stdout=False) 

En la misma operación, también podemos limitar la duración de nuestro archivo pasando un parámetro adicional "t".

Descargue el modelo deepspeech.

 deepspeech = Model(args.model, N_FEATURES, N_CONTEXT, args.alphabet, BEAM_WIDTH) 

Usando la biblioteca de ondas, extraemos cuadros en formato np.array y los transferimos a la entrada de la biblioteca de voz profunda.

 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) 

Después de un tiempo, proporcional a sus recursos de hardware, recibirá un mensaje de texto.

Paso dos: encontrar el "significado"


Para buscar palabras que describan el texto resultante, usaré el método gráfico. Este método se basa en la distancia entre secuencias. Primero encontramos todas las palabras "únicas", imagine que estos son los vértices de nuestro gráfico. Después de pasar por el texto con una "ventana" de una longitud determinada, encontramos la distancia entre las palabras, que serán los bordes de nuestro error. Los vértices agregados al gráfico pueden estar limitados por filtros de sintaxis que seleccionan solo unidades léxicas de una determinada parte del discurso. Por ejemplo, solo puede considerar que se agreguen sustantivos y verbos al gráfico. Por lo tanto, construiremos bordes potenciales basados ​​solo en relaciones que se puedan establecer entre sustantivos y verbos.

El puntaje asociado con cada vértice se establece en un valor inicial de 1, y se inicia el algoritmo de clasificación. El algoritmo de clasificación es un "voto" o "recomendación". Cuando un vértice está conectado a otro, "vota" por este vértice (conectado). Cuanto mayor sea el número de votos emitidos para un pico, mayor será la importancia de ese pico. Además, la importancia de la cima de la votación determina cuán importante es la votación en sí misma, y ​​el modelo de clasificación también tiene en cuenta esta información. Por lo tanto, la puntuación asociada con la parte superior se determina en función de los votos emitidos y la calificación de los picos que emiten estos votos.

Supongamos que tenemos un gráfico G = (V, E) descrito por los vértices V y las aristas E. Para un vértice V dado, hay un conjunto de vértices E que están asociados con él. Para cada vértice Vi, hay vértices In (Vi) asociados con él, y vértices Out (Vi) con los que está asociado el vértice Vi. Por lo tanto, el peso del vértice Vi puede representarse mediante la fórmula.

S big(Vi big)= big(1d big)+d sumj inIn(Vi) frac1 midOut(Vj) midS big(Vj big)



Donde d es el factor de atenuación / supresión, tomando un valor de 1 a 0.

El algoritmo debe iterar el gráfico varias veces para obtener estimaciones aproximadas.
Después de obtener una estimación aproximada para cada vértice en el gráfico, los vértices se ordenan en orden decreciente. Los vértices que aparecen en la parte superior de la lista serán nuestras palabras clave deseadas.

La oración más relevante en el texto se encuentra al encontrar el promedio de la suma de estimaciones de todas las palabras en la oración. Es decir, sumamos todas las estimaciones y las dividimos por el número de palabras en la oración.

 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 #0.0 : stereo Input #0, wav, from 'yA-FCxFQNHg.wav': Metadata: encoder : Lavf58.20.100 Duration: 00:17:27.06, bitrate: 1536 kb/s Stream #0:0: Audio: pcm_s16le ([1][0][0][0] / 0x0001), 48000 Hz, stereo, s16, 1536 kb/s Stream mapping: Stream #0:0 -> #0:0 (pcm_s16le (native) -> pcm_s16le (native)) Press [q] to stop, [?] for help Output #0, wav, to 'result-yA-FCxFQNHg.wav': Metadata: ISFT : Lavf58.20.100 Stream #0:0: Audio: pcm_s16le ([1][0][0][0] / 0x0001), 16000 Hz, mono, s16, 256 kb/s Metadata: encoder : Lavc58.35.100 pcm_s16le size= 28125kB time=00:15:00.00 bitrate= 256.0kbits/s speed=1.02e+03x video:0kB audio:28125kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 0.000271% Loading model from file /Users/Volodymyr/Projects/deepspeech/models/output_graph.pb TensorFlow: v1.11.0-9-g97d851f04e DeepSpeech: unknown Warning: reading entire model file into memory. Transform model file into an mmapped graph to reduce heap usage. 2018-12-14 17:42:03.121170: I tensorflow/core/platform/cpu_feature_guard.cc:141] Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX2 FMA Loaded model in 0.5s. Loading language model from files /Users/Volodymyr/Projects/deepspeech/models/lm.binary /Users/Volodymyr/Projects/deepspeech/models/trie Loaded language model in 3.17s. Running inference. Building top 20 keywords... {'communicate', 'government', 'repetition', 'terrorism', 'technology', 'thinteeneighty', 'incentive', 'ponsibility', 'experience', 'upsetting', 'democracy', 'infection', 'difference', 'evidesrisia', 'legislature', 'metriamatrei', 'believing', 'administration', 'antagethetruth', 'information', 'conspiracy'} Building summary sentence... intellectually antagethetruth administration thinteeneighty understanding metriamatrei shareholders evidesrisia recognizing ponsibility communicate information legislature abaddoryis technology difference conspiracy repetition experience government protecting categories mankyuses democracy campaigns primarily attackers terrorism believing happening infection seriously incentive upsetting testified fortunate questions president companies prominent actually platform massacre powerful building poblanas thinking supposed accounts murdered function unsolved perverse recently fighting opposite motional election children watching traction speaking measured nineteen repeated coverage imagined positive designed together countess greatest fourteen attacks publish brought through explain russian opinion winking somehow welcome trithis problem looking college gaining feoryhe talking ighting believe happens connect further working ational mistake diverse between ferring Inference took 76.729s for 900.000s audio file. 

Resumen


Las ideas que se te ocurren pueden realizarse mucho más rápido hoy que incluso hace tres o cuatro años. ¡Pruébalo, experimenta! Creo que la inteligencia artificial es principalmente la inteligencia de los ingenieros que trabajan con ella.

El código está disponible en mi repositorio de Github .

Source: https://habr.com/ru/post/es433532/


All Articles