Photo by Tim Mossholder on Unsplash

Here’s to the crazy ones, the misfits: Automatic Speech Recognition with PyTorch & Hugging Face

Learn Video-to-Text transcription and translation using the Transformers library as we journey through time with the eyes of Steve Jobs, Marian Rejewski, and John F. Kennedy.

Raul Vizcarra Chirinos
LatinXinAI
Published in
17 min readApr 17, 2024

--

There’s an old quote that goes, “All roads lead to Rome” and in the case of Hugging Face, most of the information you find on the web or in tutorials directs you or begins in the Transformers page, their open-source library with a vast selection of pre-trained transformer-based models that can be used for natural language processing. One of the first things I noticed when I checked out the Transformers page was the ability to convert audio into text, demonstrated by a 60-second audio extract from one of the most inspiring speeches ever: the 1963 “I have a dream” speech from Martin Luther King.

from transformers import pipeline

transcriber = pipeline(task="automatic-speech-recognition", model="openai/whisper-small")
transcription_results = transcriber("https://huggingface.co/datasets/Narsil/asr_dummy/resolve/main/mlk.flac")

print(transcription_results)

What if I could use Python to download any video I liked, make the transcription, and translate it? This is what this article is about; using Python and the Transformers library from Hugging Face, we are going to download a video from YouTube, transcribe it, translate it, and save it to a text file.

STEP-01: Here’s to the crazy ones, the misfits, the rebels….

“It sucks! I hate it! …I thought you were going to write something like ‘Dead Poets Society!’” recalled Rob Siltanen[1], an executive who worked with the agency that created Apple’s “Think Different” campaign, quoting Steve Jobs referring to the 1997 TV commercial.

If inspiration is the fuel of this article, what better way to start than with the iconic “Think Different” television commercial (I’ll begin with a 60-second video, and then we’ll stress the model with longer audios to see how it performs).

September 1997: Apple’s “Think Different” Television Commercial © 1997 Apple Computer, Inc.

Let’s begin by extracting the video from YouTube using Python. For the following step, these are the Python packages that we’ll need:

#Python Packages
pip install pandas
pip install pytube

In the next step, we will define the variables specifying the video’s URL, the path where it’s going to be saved, and the language we have chosen for translation. I made the translation option a variable so we can easily choose from five different languages. As we read further, you’ll see the many language choices the model offers, and it’s quite accurate.

#***********************STEP-00: SET VARIABLES *******************************

Input_Video = "https://www.youtube.com/watch?v=GEPhLqwKo6g"
audio_folder = 'D:/PYTHON/AUDIOS' #SPECIFY YOUR OWN PATH
target_translation = 'Spanish'

Tip-01: Be careful with excessive download attempts, YouTube monitors API usage and imposes limits. During the creation of this article, I was blocked 2 or 3 times 😥(don’t worry, it’s temporary😛) and had to wait until the next day to continue. If you’re working with one video, download it once and set your code to access it locally to run the other parts of the code, instead of attempting to download it every time.

Now let’s go ahead and download the video:

#***********************STEP-00: SET VARIABLES ********************************

Input_Video = "https://www.youtube.com/watch?v=GEPhLqwKo6g"
audio_folder = 'D:/PYTHON/AUDIOS'
target_translation = 'Spanish'

#*******************STEP-01: DOWNLOAD THE VIDEO********************************
from pytube import YouTube
import pandas as pd

#DOWNLOAD
yt = YouTube(Input_Video)
video_name = yt.title
stream = yt.streams.filter(file_extension='mp4').get_highest_resolution()

# RENAME & STORE IN LOCAL PATH
audio_file_name = ''.join(c if c.isalnum() else '_' for c in video_name) + ".mp4"
stream.download(output_path=audio_folder, filename=audio_file_name)

# STORE IN DATAFRAME
df_video = pd.DataFrame({'video_name': [audio_file_name]})

print("Video downloaded OK")

The audio_file_name command is optional, but you’ll find it helpful. When I tried different videos, I had trouble saving the audio because of special characters (non-alphanumeric) in the video name. This command changes those characters in the video name to underscores.

Tip-02: Most libraries that handle multimedia files support FFmpeg, an open-source tool for recording, converting, and streaming audio and video. While trying to edit the audio file with pytube, I had some error messages, and attempting a workaround without installing FFmpeg failed; ultimately, I downloaded it (you’ll also need it for the transcription model to work properly). After extracting the file, add the path to your system’s environment. You can find the FFmpeg file for your OS on the FFmpeg website. For Windows, download it here. For instructions on adding the folder to the PATH environment, here.

STEP-02: Release The Kraken! (Hugging Face Transformers library)

As it is specified on the Hugging Face page, the Transformers library has been tested with Python, TensorFlow, and Flax. I chose to work with PyTorch only for convenience, but you can try using the deep learning library that best fits your knowledge and expertise. You’ll find the installation instructions for PyTorch in the Hugging Face installation section and on the PyTorch website.

For STEP-02, these are the Python packages that we’ll need:

#If your using Windows and running the model in your own PC, 
#otherwise check the PyTorch website

pip3 install torch torchvision torchaudio
pip install transformers

#You will also need pandas, but we already installed it previously

Tip-03: Regardless of the ML library you decide to use, it’s important to ensure that it’s installed properly. All my tools are set up in an Anaconda environment, and when I installed PyTorch, at first, it seemed that it was set up correctly. However, some issues appeared while running the Transformers library. Initially, I thought it was the code, but after several revisions and no success, I had to reinstall Anaconda and install PyTorch in a clean environment, and with that, problem fixed!

The Transformers library helps you save precious time and resources when training a model. It offers various pre-trained models for Natural Language Processing tasks such as text generation, classification, and translation, as well as applications in computer vision like image classification and object detection. And of course, it’s an interesting tool for understanding spoken words in audio too! Let’s go ahead and lets get our transcription:

#************************STEP-02: TRANSCRIPTION*******************************

import os
import pandas as pd
from transformers import pipeline
from datetime import datetime

# TRANSFORMERS MODEL: whisper-small
def transcribe_audio(audio_file_path):
transcriber = pipeline(task="automatic-speech-recognition", model="openai/whisper-small")
transcription_results = transcriber(audio_file_path)
transcription_text = transcription_results.get('text', "No transcription results found.")

#SAVE THE DATE WE MADE THE TRANSCRIPTION
current_date = datetime.now().strftime("%Y-%m-%d")

# CREATE DATAFRAME TO STORE RESULTS
df = pd.DataFrame({'Current_Date': [current_date],
'Video_Name': [audio_file_name],
'Transcription': [transcription_text]})

# PRINT TRANSCRIPTION
print("Transcription Results:", transcription_text)
return df

#SEARCH FOR THE AUDIO IN THE FILE PATH AND EXECUTE TRANSCRIPTION
audio_file_path = os.path.join(audio_folder, audio_file_name)
df = transcribe_audio(audio_file_path)
print(df)

Let’s explore key elements of the transcription step:

01) The Pipeline: It’s like a toolbox, handling most of the hard work. It follows specific steps to produce desired outputs for various tasks. Just select the task, and the pipeline does the rest. Explore different tasks for speech, audio, computer vision, and NLP in here.

02) The Whisper Model: Whisper (openai/whisper-small) is a pre-trained model created by OpenAI for speech recognition (ASR) and speech translation. It was first introduced in 2022 in the paper “Robust Speech Recognition via Large-Scale Weak Supervision”, and it was trained on over 680,000 hours of labeled audio data. It works well for me in English and Spanish transcriptions. (Tested Mandarin but didn’t show good results)

Tip-03: Initially, I faced issues working directly with the text, so I found it more effective to save it in a DataFrame for further processing. Remember to treat transcription_results as a dictionary rather than a list to avoid complications when passing the output to a DataFrame.

If everything has worked well in your code so far, you’ll have the following: An audio, a DataFrame containing the name of the audio file, the date when the transcription was performed, and the transcription itself. As a matter of fact, it’s quite a neat transcription🤓.

#OUTPUT
Video downloaded OK!
Special tokens have been added in the vocabulary, make sure
the associated word embeddings are fine-tuned or trained.

Transcription Results:
Here's to the crazy ones. The misfits. The rebels.
The troublemakers. The round pegs in the square holes.
The ones who see things differently. They're not fond of rules
and they have no respect for the status quo.
You can quote them, disagree with them, glorify or vilify them.
About the only thing you can't do is ignore them because they change things.
They push the human race forward.
While some may see them as the crazy ones, we see genius.
Because the people who are crazy enough to think they can change the world
are the ones who do.

© 1997 Apple Computer, Inc.
Photo by Christian Lendl on Unsplash

STEP-03: With languages, you are at home anywhere

At the bottom left corner of the 2018 paper Marian: Fast Neural Machine Translation in C++, a “rebel” footnote catches the eye. It reads: “Named after Marian Rejewski, a Polish mathematician and cryptologist who reconstructed the German military Enigma cipher machine sight-unseen in 1932”. Turing and Bletchley Park’s legacy are indisputable, but let us not forget Marian Rejewski.

Marian is a free Neural Machine Translation framework (kinda translation toolkit) developed by scientists at Adam Mickiewicz University in Poznan, the University of Edinburgh, and the Microsoft Translator team. Within this framework lies the MarianMT Model, included in the Transformers library and our ally for the translation step. Finally, the MarianMT model includes the Helsinki-NLP pre-trained models, a collection of over 1,000 language pairs.

For STEP-03, here are the Python packages we’ll need (some of which have already been installed in previous steps, so there’s no need for reinstallation):

pip install transformers
pip install pandas
pip install sentencepiece

Now, let’s jump into our translation. For example purposes, I’m going to run an English-to-Spanish translation model (Helsinki-NLP/opus-mt-en-es), but you can choose from over 1,000 language pairs that you can find here:

#***********************STEP 03: TRANSLATION MODEL**********************************
from transformers import MarianMTModel, MarianTokenizer

#SET THE MODEL PARAMETERS
model_name = "Helsinki-NLP/opus-mt-en-es"
tokenizer = MarianTokenizer.from_pretrained(model_name)
model = MarianMTModel.from_pretrained(model_name)

#TRANSLATE
def translate_text(text):
inputs = tokenizer(text, return_tensors="pt", padding=True)
translated_ids = model.generate(**inputs)
translated_text = tokenizer.decode(translated_ids[0], skip_special_tokens=True)
return translated_text

#ADD TO DATAFRAME
df['Translated_Transcription'] = df['Transcription'].apply(translate_text)

The setup of the model includes two important steps: specifying the pre-trained model (in our example; Helsinki-NLP/opus-mt-en-es) and a tokenizer class named MarianTokenizer. Preparing the text for a model is as important as the translation model itself (“Garbage In, Garbage Out”); it entails among other tasks, breaking the text into individual words (tokens), removing words that don’t add much meaning, and reducing words to their base form to understand their meaning (lemmatization). MarianTokenizer saves you time and does the job! (I’ve done some of this work using the python NLTK Package in this article if you want to check it out).

The translation output should look something like this:

Translated_Transcription (Spanish)
A los locos, a los inadaptados, a los rebeldes, a los alborotadores,
a los que ven las cosas de forma diferente, a los que no les gustan
las reglas y no respetan el status quo, a los que no les gustan,
a los que no les gustan, a los que glorifican o vilipendian,
a los que no se les puede ignorar porque cambian las cosas,
a los que empujan a la raza humana, a los que pueden ver como locos,
a los genios, a los que les gusta pensar que pueden cambiar el mundo.

If we translate the previous text to English language, it would sound something like this:

Translated_Transcription (Spanish translation, spoken as if in English)

"To the crazy, to the misfits, to the rebels, to the troublemakers,
to those who see things differently, to those who do not like rules
and do not respect the status quo, to those who do not like,
to those who who do not like them, those who glorify or vilify,
those who cannot be ignored because they change things,
those who push the human race, those who can see as crazy,
the geniuses, those who I like to think that they can change the world."

© 1997 Apple Computer, Inc.

As you can see in this first attempt, the translation captures some accuracy in the context of the text, but it becomes a little “lost in translation”, and although the point is clear, it loses the sentiment and power of the message. In order to achieve a better output, I set up the code with the Helsinki-NLP/opus-mt-en-roamodel, which targets Romance languages (Spanish, French, Italian, Portuguese, among others in this category). The modified version of the code looks like this:

#*****************STEP 03: TRANSLATION MODEL-2nd ATTEMPT************************
from transformers import MarianMTModel, MarianTokenizer

#SET THE MODEL PARAMETERS
model_name = "Helsinki-NLP/opus-mt-en-roa"
tokenizer = MarianTokenizer.from_pretrained(model_name)
model = MarianMTModel.from_pretrained(model_name)

# TARGET LANGUAGE: SPANISH
target_language_code = ">>spa<<"

#TRANSLATE
def translate_text(text):
input_text = f"{target_language_code} {text}"
inputs = tokenizer(input_text, return_tensors="pt", padding=True)
translated_ids = model.generate(**inputs)
translated_text = tokenizer.decode(translated_ids[0], skip_special_tokens=True)
return translated_text

#ADD TO DATAFRAME
df['Translated_Transcription'] = df['Transcription'].apply(translate_text)

Notice that in this part, we are specifying the language required for our translation (target_language_code). The languages supported by the ‘roa’ model, and their two-digit codes, can be found here. If we run the code and translate the output to English language, it would sound something like this:

Translated_Transcription (Spanish translation, spoken as if in English)

"Here are the crazy ones. The misfits. The rebels. The annoying ones.
The round sticks in the square holes. Those who see things differently.
They don't love rules and have no respect for the status quo.
They can quote them, disagree with them, glorify them or insult them.
About the only thing they can't do is ignore them because things change.
They push the human race forward. While some may see them as the crazy ones,
we see the genius. Because the people crazy enough to think they can change
the world are the ones who do."

We have a more accurate translation that also retains the strength of the message.

STEP-04: O God, Thy Sea Is So Great And My Boat Is So Small

President John F. Kennedy kept a small bronze plaque on his desk, attached to a block of wood, with the opening line of an old Breton fisherman’s prayer: “O God, Thy Sea Is So Great And My Boat Is So Small” Some people say Kennedy turned to it in moments of difficult decisions, and indeed, the ’60s were decisive times for peace and fundamental rights, yet also inspirational. As the opening paragraph of Charles Dickens’ novel, A Tale of Two Cities says: “It was the best of times, it was the worst of times…”

For us, this serves as inspirational fuel to go beyond a 60-second transcription and translation. We will use President Kennedy’s Peace speech, delivered on June 10, 1963, at American University. The speech lasts over 27 minutes and delivers a remarkable message of peace and coexistence. Sixty years have passed since Kennedy’s speech, but its words transcend time.

President John F. Kennedy, American University June 1963

No extra libraries are needed here, but we should consider the following:

01) The sequence-to-sequence challenge: In natural language processing, the goal is to transform input sequences into output sequences. Therefore, the model often predicts the next word based on the information it has about the previous word and other significant parts of the text, especially in longer sentences or paragraphs (the famous attention mechanisms). As texts grow larger, words are further apart from each other, posing a challenge for the model to retain context over longer distances and maintain accuracy. If you want to know more about how Transformers work check out this article from Giuliano Giacaglia.

02) The 512 Tokens: As I described before, NLP models divide the text into tokens, which could be words, sub words, or elements of the text important for predicting the output. Depending on the model, there is a limitation on the maximum length of input sequences it can handle, but it seems that the convention so far is 512 tokens (doing some research, there’s a lot of effort in the ML community to improve this limitation). Therefore, the 512 token limitation is a problem we have to tackle to improve upon our previous translation attempt; as you’ll see, President Kennedy’s speech has more than 3,000 words😮.

For this step, we’ll use the same code as in STEP-01 and STEP-02 (don’t forget to change the URL in the Input_Video variable to the Kennedy Speech). When translating the sequence, if you attempt to use one of the codes from STEP 03, you may end with an “index out of range in self” error message, indicating that the length limits expected by the model have been exceeded (the 512 tokens). To address this issue, the updated version below will automatically split the text into small sequences (smaller than 512 tokens) and translate each one individually until the entire text is translated.

#****STEP 03: TRANSLATION MODEL-LIMIT OF 512 TOKENS IN EACH ITERATION********

from transformers import MarianMTModel, MarianTokenizer

# CREATES DATAFRAME WITH FIVE POSSIBLE LANGUAGE OPTIONS
language_models_df = pd.DataFrame({
'Language': ['Spanish', 'Mandarin', 'French', 'Hindi'],
'Model_Name': ["Helsinki-NLP/opus-mt-en-es", "Helsinki-NLP/opus-mt-en-zh",
"Helsinki-NLP/opus-mt-en-fr", "Helsinki-NLP/opus-mt-en-hi"]})

#SET THE MODEL PARAMETERS
model_name = language_models_df.loc[language_models_df['Language'] == target_translation, 'Model_Name'].values[0]
tokenizer = MarianTokenizer.from_pretrained(model_name)
model = MarianMTModel.from_pretrained(model_name)

#TRANSLATES IN BLOCKS OF 512 TOKENS
def translate_text(text):
segment_length = 512
segments = [text[i:i+segment_length] for i in range(0, len(text), segment_length)]
translated_text = ""
for segment in segments:
inputs = tokenizer(segment, return_tensors="pt", padding=True)
translated_ids = model.generate(**inputs)
translated_text += tokenizer.decode(translated_ids[0], skip_special_tokens=True) + " "
return translated_text.strip()

#ADD TO DATAFRAME
df['Translated_Transcription'] = df['Transcription'].apply(translate_text)

With this code, you should get the translated output of President Kennedy’s speech (about 3,000 words). Also, notice that I’ve added a setup at the beginning where you can specify the language you’d like the translation to be in (in STEP 0, we defined a variable, target_translation, that interacts with the language DataFrame (language_models_df). Here, you can experiment with the language pairs offered by the Helsinki-NLP collection.

But how do we know if the translation is accurate? It’s simple for the Apple’s “Think Different” TV commercial which has only about 100 words and you can easily spot similarities or differences just by looking at the text, but for a text with over 3,000 words, a quick glance isn’t enough. For comparison evaluations and metrics, we can use the spaCy library, an open-source tool designed to assist with NLP tasks in Python. We would need to install the library and a pre-trained language model. SpaCy supports a wide variety of languages; however, in our case, though we are evaluating similarities in English texts, we would use the en_core_web_sm model, which is configured for English.

Here are the Python packages we’ll need:

pip install spacy
python -m spacy download en_core_web_sm

Now, we’ll modify the code to pass our translated version into English. With this new output, we’ll compare the original transcription to the translated version as if it were read in English. The code will also generate a similarity score between 0 to 1, where 0 indicates no similarity between the texts and 1 indicates complete similarity.

#************PASS TRANSLATED OUTPUT TO ENGLISH LANGUAGE *********************

target_translation = 'Spanish to English'

# CREATES DATAFRAME WITH LANGUAGE OPTIONS
language_models_df = pd.DataFrame({
'Language': ['Spanish', 'Mandarin', 'French', 'Hindi', 'Spanish to English'],
'Model_Name': ["Helsinki-NLP/opus-mt-en-es", "Helsinki-NLP/opus-mt-en-zh",
"Helsinki-NLP/opus-mt-en-fr", "Helsinki-NLP/opus-mt-en-hi",
"Helsinki-NLP/opus-mt-es-en"]})

#SET THE MODEL PARAMETERS
model_name = language_models_df.loc[language_models_df['Language'] == target_translation, 'Model_Name'].values[0]
tokenizer = MarianTokenizer.from_pretrained(model_name)
model = MarianMTModel.from_pretrained(model_name)

#TRANSLATES IN BLOCKS OF 512 TOKENS
def translate_text(text):
segment_length = 512
segments = [text[i:i+segment_length] for i in range(0, len(text), segment_length)]
translated_text = ""
for segment in segments:
inputs = tokenizer(segment, return_tensors="pt", padding=True)
translated_ids = model.generate(**inputs)
translated_text += tokenizer.decode(translated_ids[0], skip_special_tokens=True) + " "
return translated_text.strip()

#ADD TO DATAFRAME
df['Translated_text_to_eng'] = df['Translated_Transcription'].apply(translate_text)

#***********************STEP-04:TEXT COMPARISSON*******************************
import spacy
import pandas as pd

#spaCy MODEL
nlp = spacy.load("en_core_web_sm")

#EXTRACT TEXTS
text1 = df['Transcription'].iloc[0]
text2 = df['Translated_text_to_eng'].iloc[0]

# COMPARATIVE ANALYSIS
doc1 = nlp(text1)
doc2 = nlp(text2)
similarity_score = doc1.similarity(doc2)

#SAVE THE RESULTS & PRINT SCORE
translation_metrics = pd.DataFrame({
'Original_Text': [text1],
'Translated_text_to_eng': [text2],
'Similarity_Score': [similarity_score]})
print("Score:", similarity_score)

I got a similarity score of 0.997 on the President Kennedy’s speech texts. Although the translated version of the speech is quite accurate and maintains context, I believe there may be some overfitting present, and the translation still has room for improvement, especially when transitioning between non-gendered and gendered languages (like Spanish). For example, the output of the Helsinki-NLP/opus-mt-en-es model with the 512 token adjustment, had a few minor translation errors but managed gendered language interpretation well. On the other hand, the Helsinki-NLP/opus-mt-en-roa model, also with the 512 token adjustment, captured the spirit and context of the text better but faced some little challenges managing gendered language. Regarding these observations, I think both do quite a good job.

Finally, you can add this line of code if you want to export your translated output to a text file for reading and additional revisions:

#***********************STEP 05: EXPORT OUTPUTS******************************

#EXPORT DATAFRAME TO CSV FILE
csv_file_path = os.path.join(audio_folder, 'transcription_results.csv')
df.to_csv(csv_file_path, index=False)
print("DataFrame exported to CSV file")

#EXPORT OUTPUT TO TEXT FILE
txt_file_path = os.path.join(audio_folder, 'translated_transcription.txt')
with open(txt_file_path, 'w', encoding='utf-8') as txt_file:
for index, row in df.iterrows():
txt_file.write(f"Title: {row['Video_Name']}\n")
txt_file.write(row['Translated_Transcription'] + '\n\n')
print("Text exported to TXT file")

The complete code and examples of the output texts can be found in this GitHub repository.

Considerations and Future Work

I can see multiple possibilities for using this tool. For example, could significantly support audio auditing and quality assurance of customer care or sales calls, which are highly needed in industries such as Banking, Telco, and Insurance. Some of these tasks are still done entirely manually. While there are already solutions in the market offering these functionalities (they come with a price🤷‍♂️), if you are a small to medium-sized company looking to benefit from the open-source community or seeking efficiency, this could be an interesting option. For academic research or self-learning, it could also be a valuable tool. There is a lot of content available today only in video (and is increasing exponentially over time) that one would like to access but is not available in our native language. I tried the model with Spanish content (my native language), and the model performed well. However, when I tried it with languages like Mandarin, the results were not as good, although translating to Mandarin worked better. Of course, all of this must consider compliance and respect for copyright content.

It’s important to consider that the work in this article has been based on transcribing in one direction, meaning only one person speaking. Improvements would involve making some upgrades to the code to capture video-to-text between different people and achieve transcription of dialogues or debates. Additionally, as I mentioned, it’s important to always respect compliance with data protection, privacy laws, and copyright content.

FINAL THOUGHT

As you can see, a lot of interesting things can be done with the Transformers library, and I hope this guide becomes useful to you. However, in the wisdom of Abraham Lincoln’s words: “There are few things wholly good or wholly evil. Almost everything is an inseparable compound of the two, so our best judgment of the preponderance between them is continually demanded”. Artificial Intelligence can also be misused, as we already know, for purposes such as disinformation or deepfakes, and in ways we don’t yet know.

Putting President Kennedy’s Peace Speech last wasn’t just a mere technical decision, it reminds us that when dealing with new technologies not yet fully understood, it is up to us to give their coexistence with society meaning. Technologies and issues may have changed since the ’60s, but our common links as a society haven’t.

For the final analysis, our most basic common link is that we all inhabit this small planet. We all breathe the same air. We all cherish our children’s futures, and we are all mortal. (President John F. Kennedy, June 1963)

President Kennedy, as a US Senator in 1956, wrote “Profiles in Courage(or partially wrote it 🤔)[2]. The book concludes with this paragraph:

“The stories of past courage can teach, they can offer hope, they can provide inspiration, but they cannot supply courage itself. For this, each man must look into his own soul”. (Profiles in Courage,1956)

Similarly, for AI, history teaches, inspires, and offers hope, but meaningful impact cannot be achieved by AI alone; for this, it’s up to each one of us to give AI a positive purpose in society. For the Steves, the Marians, the Johns, the rebels, the troublemakers… the crazy ones.

Notes:

[1] The True History of Apple’s “Think Different” Campaign. https://www.theatlantic.com/technology/archive/2011/12/true-history-apples-think-different-campaign/334256/

[2] Ted Sorensen and Jules Davids are presumed to collaborated as ghostwriters on the first draft.

LatinX in AI (LXAI) logo

Do you identify as Latinx and are working in artificial intelligence or know someone who is Latinx and is working in artificial intelligence?

Don’t forget to hit the 👏 below to help support our community — it means a lot!

--

--

Raul Vizcarra Chirinos
LatinXinAI

Data Science I AI I Innovation I Passionate about discovering new ways to build a better world through Data and Technology.