Name: Towards AI Legal Name: Towards AI, Inc. Description: Towards AI is the world's leading artificial intelligence (AI) and technology publication. Read by thought-leaders and decision-makers around the world. Phone Number: +1-650-246-9381 Email: pub@towardsai.net
228 Park Avenue South New York, NY 10003 United States
Website: Publisher: https://towardsai.net/#publisher Diversity Policy: https://towardsai.net/about Ethics Policy: https://towardsai.net/about Masthead: https://towardsai.net/about
Name: Towards AI Legal Name: Towards AI, Inc. Description: Towards AI is the world's leading artificial intelligence (AI) and technology publication. Founders: Roberto Iriondo, , Job Title: Co-founder and Advisor Works for: Towards AI, Inc. Follow Roberto: X, LinkedIn, GitHub, Google Scholar, Towards AI Profile, Medium, ML@CMU, FreeCodeCamp, Crunchbase, Bloomberg, Roberto Iriondo, Generative AI Lab, Generative AI Lab Denis Piffaretti, Job Title: Co-founder Works for: Towards AI, Inc. Louie Peters, Job Title: Co-founder Works for: Towards AI, Inc. Louis-François Bouchard, Job Title: Co-founder Works for: Towards AI, Inc. Cover:
Towards AI Cover
Logo:
Towards AI Logo
Areas Served: Worldwide Alternate Name: Towards AI, Inc. Alternate Name: Towards AI Co. Alternate Name: towards ai Alternate Name: towardsai Alternate Name: towards.ai Alternate Name: tai Alternate Name: toward ai Alternate Name: toward.ai Alternate Name: Towards AI, Inc. Alternate Name: towardsai.net Alternate Name: pub.towardsai.net
5 stars – based on 497 reviews

Frequently Used, Contextual References

TODO: Remember to copy unique IDs whenever it needs used. i.e., URL: 304b2e42315e

Resources

Take our 85+ lesson From Beginner to Advanced LLM Developer Certification: From choosing a project to deploying a working product this is the most comprehensive and practical LLM course out there!

Publication

How do I Evaluate Large Language Models
Latest   Machine Learning

How do I Evaluate Large Language Models

Last Updated on June 10, 2024 by Editorial Team

Author(s): Meenakshi Srinivasan

Originally published on Towards AI.

Photo by Steve Johnson on Unsplash

How do I Evaluate Large Language Models

Meenakshi Srinivasan

Follow

Published in

Towards AI

8 min read19 hours ago

Before the launch of Large Language Models, I have always used to test and get a concrete accuracy of how well my model works — be it transformers or any supervised models. But now, the situation has changed after the arrival of Generative AI models. Even though the LLMs are really good at producing results (for tasks like summarization, classification, and what not!), I have always felt that we lack behind in testing how precise the responses are. But thanks to Langsmith, they have come up with a new way of evaluating LLMs and monitor them consistently which is suitable for post deployment monitoring.

Ok, how LangSmith helps with evaluation?

LangSmith is a unified DevOps platform for developing, collaborating, testing, deploying, and monitoring LLM applications[1].

Earlier, in Reinforcement Learning, the response generated by the models will be given a human feedback to improve the results. Now with Langsmith, we can use LLM-as-a-judge approach and analyse the results of LLMs and maintain track of how well the model performs over time. It can be used for tasks like text generation and summarization where there is no single ground truth. To obtain accurate and customized evaluation results, it is essential to include all relevant criteria in the prompt.

Langsmith Overview:

First of all, you need to sign up to Langsmith and create a personal token API key in the website. Langsmith offers Free plan for 5000 traces per month for Developer Account and 0.005/trace thereafter.

With Langsmith, you can enhance your project management by adding separate projects to monitor individual tasks, store datasets for evaluation, employ few-shot prompting, and fine-tune models. The platform offers a wide range of capabilities to streamline and optimize your workflow.

Langsmith dashboard

Example Experiment — Generate tweets for Harry Potter movies:

I’m planning an experiment where I will use two different language models (LLMs) to generate tweets about Harry Potter movies, based on plot summaries from Wikipedia. Once the tweets are generated, I’ll use Langsmith to evaluate the results. Additionally, I’ll explain and run the Pairwise evaluation technique, an experiment provided by Langsmith. This method will allow us to compare the outputs of the two LLMs and determine which one produces better results. This comprehensive evaluation will provide valuable insights into the performance of each model.

Working:

Step 1: Install the required packages

Step 2 — Data Loading: Load the movies plot from Wikipedia using Wikipedia Loader from Langchain.

from langchain.document_loaders import WikipediaLoader

movies_list = ['Harry Potter and the philosophers stone', 'Harry Potter and the chamber of secrets']

movies = []

for movie in movies_list:
loader = WikipediaLoader(query = 'Harry Potter and the chamber of secrets', load_max_docs=1).load()
movies.extend(loader)

Step 3 — Create dataset: To store the data used to generate tweets, we’ll create a dataset in Langsmith using the Client class. This allows us to create a new dataset with a description, which can be reused for evaluation, fine-tuning, and other purposes at any time.

from langsmith import Client

client = Client()

dataset_name = "Movies_summary_generator"

dataset = client.create_dataset(dataset_name = dataset_name, description = 'Movies to summarize',)

After this step, you would be able to see the dataset that you created in ‘Datasets & Testing’ page in Langsmith.

Datasets & Testing in Langsmith

Step 4 — Generate tweets using GPT: We will create a function to generate tweets using LLM for Harry Potter and the Philosopher’s Stone and Harry Potter and the Chamber of Secrets movies and save it as an Experiment in Langsmith(we will use this later for evaluation).

def predict_tweet_gpt_3(example: dict):
system_tweet_instructions = (
"""You are an assistant that generates Tweets to summarise movie plots.
Ensure the summary: 1. has an engaging title. 2. Provides a bullet point list of main characters from the movie.
3. Utilises emojis 4. includes plot twist 5. highlights in one sentence the key point of the movie.
"""

)

human = "Generate tweets for the following movie: {paper}"
prompt = ChatPromptTemplate.from_messages([("system", system_tweet_instructions),("human", human)])

chat = ChatOpenAI(openai_api_key = os.getenv('OPENAI_API_KEY'), model = 'gpt-3.5-turbo')
tweet_generator_gpt_3 = prompt | chat | StrOutputParser()
response = tweet_generator_gpt_3.invoke({"paper":example["text"]})
return response

This is the tweet generated by the model —

🧙🏼‍♂️✨✉️ "Harry Potter and the Philosopher's Stone" Tweet Summary:

🌟 Title: Discovering Magic at Hogwarts! 🧙🏼‍♂️🔮

👦🏻 Harry Potter - Young wizard discovering his magical heritage
🧙🏻‍♂️ Ron Weasley - Loyal friend and companion
📚 Hermione Granger - Bright witch and problem-solver

🔮 Harry learns he's famous in the wizarding world, faces dark wizard Lord Voldemort with his friends, and uncovers secrets at Hogwarts School of Witchcraft and Wizardry.
🧙🏼‍♂️ Plot Twist: Harry's wand is connected to Voldemort's, making them "brothers".
🌟 Feedback: Rowling's imaginative world and clever plot kept readers spellbound, though some found the ending rushed.

Step 5: Evaluation — This is the crucial and core step of this article. I will use GPT-4o for evaluation of the tweets. I am inputting the prompt with the criteria for evaluation.

def answer_evaluator(run:Run, example: Example) -> dict:
input_text = example.inputs["text"]
prediction = run.outputs["answer"]

class GradeSummary(BaseModel):
score: int = Field(description = "Answer meets criteria, score from 0 to 5")

llm = ChatOpenAI(model = 'gpt-4o', temperature=0)
structured_llm_grader = llm.with_structured_output(GradeSummary)

system = """
You are grading tweets for movie plot summary. Ensure that the Assistant's answer is engaging and meets the criteria,
Ensure the summary: 1. has an engaging title. 2. Provides a bullet point list of main characters from the movie.
3. Utilises emojis 4. includes plot twist 5. highlights the feedback 6. Includes hashtag
"""


grade_prompt = ChatPromptTemplate.from_messages(
[
("system", system),
("human", "Assistant's answer for the movie summary: {prediction}")
]
)

answer_grader = grade_prompt | structured_llm_grader
score = answer_grader.invoke({"prediction": prediction})
return {"key": "summary_engagement_score", "score":int(score.score)}

Then, we can setup and trace this evaluation by using Langsmith evaluate function.

from langsmith.evaluation import LangChainStringEvaluator, evaluate
dataset_name = "Movies_summary_generator"

experiment_results = evaluate(
predict_tweet_gpt_3,
data=dataset_name,
evaluators=[answer_evaluator],
experiment_prefix="summary-gpt3-turbo",
metadata={"variant": "movie summary tweet, gpt-3-turbo"},
)

By passing the dataset, the experiment set up in the previous step, and the evaluator function to Langsmith, we can view the evaluation results in the Langsmith interface. Running this model will create an Experiment, which will track the performance of this specific task from the date of creation, allowing for consistent monitoring and analysis over time.

Experiment results — Langsmith

Pairwise evaluation

Using Langsmith’s pairwise evaluation, we can also compare the results of two LLMs to determine which one performs better. This analysis provides a clear understanding of the model that performs better based on the criteria that we set, helping us make informed decisions about their effectiveness.

from langsmith.evaluation import evaluate_comparative
from langchain import hub
from langchain_openai import ChatOpenAI
from langsmith.schemas import Run, Example
import json


def evaluate_pairwise(runs: list[Run], example: Example):
scores = {}

class GradeSummary(BaseModel):
score: int = Field(description = "Answer meets criteria, score from 0 to 5")

llm = ChatOpenAI(model = 'gpt-4o', temperature=0)

# prompt for evaluation
system = """
Please act as an impartial judge and evaluate the quality of the responses provided by two AI assistants to the user question displayed below.
You should score both the assistants that
1. has an engaging title.
2. Provides a bullet point list of main characters from the movie.
3. Utilises emojis
4. includes plot twist
5. highlights the feedback
Avoid any position biases and ensure that the order in which the responses were presented does not influence your decision.
Do not allow the length of the responses to influence your evaluation. Do not favor certain names of the assistants. Be as objective as possible.
Your output should strictly be on a scale of 1 to 5 for both the assistants with the keys "Score for Assistant 1" for Assistant 1
and "Score for Assistant 2" for Assistant and your output should be in JSON format. Your output should not include any explanations.
"""


grade_prompt = ChatPromptTemplate.from_messages(
[
("system", system),
("human", "[User Question] {question} \n[The Start of Assistant A's Answer] {answer_a} [The End of Assistant A's Answer]\nThe Start of Assistant B's Answer] {answer_b} [The End of Assistant B's Answer]")
])

runnable = grade_prompt | llm

response = runnable.invoke({
"question": example.inputs["text"],
"answer_a": runs[0].outputs["answer"] if runs[0].outputs is not None else "N/A",
"answer_b": runs[1].outputs["answer"] if runs[1].outputs is not None else "N/A",
})
response = str(response.content)
json_response = eval(response)
scores[runs[0].id] = json_response["Score for Assistant 1"]
scores[runs[1].id] = json_response["Score for Assistant 2"]

return {"key": "ranked_preference", "scores": scores}


evaluate_comparative(
# Replace the following array with the names or IDs of your experiments
[<YOUR-EXPERIMENT-ID-1>, <YOUR-EXPERIMENT-ID-2>],
evaluators=[evaluate_pairwise],
)

The tweets generated by GPT-3.5 and GPT-4 are as follows —

# Response by GPT-3.5 for Harry Potter and the Philosopher's Stone

🧙🏼‍♂️✨✉️ "Harry Potter and the Philosopher's Stone" Tweet Summary:

🌟 Title: Discovering Magic at Hogwarts! 🧙🏼‍♂️🔮

👦🏻 Harry Potter - Young wizard discovering his magical heritage
🧙🏻‍♂️ Ron Weasley - Loyal friend and companion
📚 Hermione Granger - Bright witch and problem-solver

🔮 Harry learns he's famous in the wizarding world, faces dark wizard Lord Voldemort with his friends, and uncovers secrets at Hogwarts School of Witchcraft and Wizardry.
🧙🏼‍♂️ Plot Twist: Harry's wand is connected to Voldemort's, making them "brothers".
🌟 Feedback: Rowling's imaginative world and clever plot kept readers spellbound, though some found the ending rushed.



# Response by GPT-4 for Harry Potter and the Philosopher's Stone
🧙‍♂️✨ **Magical Beginnings: Harry Potter and the Philosopher's Stone** 📚🔮

👦 **Harry Potter** - The boy who lived, discovers his magical heritage and his pivotal role in the wizarding world.
👧 **Hermione Granger** - A brilliant and bookish wizard, becomes one of Harry's closest allies.
🧑 **Ron Weasley** - Harry's loyal friend, known for his humor and bravery.
🧙‍♂️ **Lord Voldemort** - The dark wizard who seeks to return to power, having failed to kill Harry as a baby.
🦉 **Hagrid** - Half-giant and Hogwarts gamekeeper, introduces Harry to the wizarding world.

🎂 On his 11th birthday, Harry learns he's a wizard & heads to Hogwarts. 🎉🏰
👬👫 Friendship blooms with Ron and Hermione as they uncover the mystery of the Philosopher's Stone. 🕵️‍♂️💎
🐍 Twist: The stone is hidden in a school mirror! Voldemort's comeback attempt thwarted by brave first-years. 🚫🧙‍♂️

📢 Critics rave about Rowling's rich imagination & the world she crafts! ✨📖
🔥 "A modern classic, melding magic with moral lessons!" - Critics' Circle

#HarryPotter #Magic #Fantasy #Adventure #BookToMovie 🎬📖

As clearly seen, GPT-4’s output is more creative and descriptive. Additionally, it included hashtags for the tweets. Pairwise experiments also rated GPT-4 with higher scores, highlighting its superior performance.

Pairwise Evaluation in Langsmith

Final words

In conclusion, this is how we can evaluate LLMs using Langsmith. Langsmith allows us to comprehensively analyze and compare the performance of different language models. This systematic approach ensures that we can make informed decisions based on the desired criteria to optimize our models for various tasks.

You can find my jupyter notebook with full code here on my github repository — https://github.com/Meenakshi-srinivasan/langsmith-overview

References:

  1. https://www.langchain.com/langsmith
  2. https://blog.langchain.dev/week-of-5-13-langchain-release-notes/
  3. https://www.youtube.com/watch?v=yskkOAfTwcQ

Connect with me on Linkedin — https://www.linkedin.com/in/meenakshisrinivasan/

If you enjoyed this article, please consider clapping and following me on Medium for more Data Science stories.

Join thousands of data leaders on the AI newsletter. Join over 80,000 subscribers and keep up to date with the latest developments in AI. From research to projects and ideas. If you are building an AI startup, an AI-related product, or a service, we invite you to consider becoming a sponsor.

Published via Towards AI

Feedback ↓

Sign Up for the Course
`; } else { console.error('Element with id="subscribe" not found within the page with class "home".'); } } }); // Remove duplicate text from articles /* Backup: 09/11/24 function removeDuplicateText() { const elements = document.querySelectorAll('h1, h2, h3, h4, h5, strong'); // Select the desired elements const seenTexts = new Set(); // A set to keep track of seen texts const tagCounters = {}; // Object to track instances of each tag elements.forEach(el => { const tagName = el.tagName.toLowerCase(); // Get the tag name (e.g., 'h1', 'h2', etc.) // Initialize a counter for each tag if not already done if (!tagCounters[tagName]) { tagCounters[tagName] = 0; } // Only process the first 10 elements of each tag type if (tagCounters[tagName] >= 2) { return; // Skip if the number of elements exceeds 10 } const text = el.textContent.trim(); // Get the text content const words = text.split(/\s+/); // Split the text into words if (words.length >= 4) { // Ensure at least 4 words const significantPart = words.slice(0, 5).join(' '); // Get first 5 words for matching // Check if the text (not the tag) has been seen before if (seenTexts.has(significantPart)) { // console.log('Duplicate found, removing:', el); // Log duplicate el.remove(); // Remove duplicate element } else { seenTexts.add(significantPart); // Add the text to the set } } tagCounters[tagName]++; // Increment the counter for this tag }); } removeDuplicateText(); */ // Remove duplicate text from articles function removeDuplicateText() { const elements = document.querySelectorAll('h1, h2, h3, h4, h5, strong'); // Select the desired elements const seenTexts = new Set(); // A set to keep track of seen texts const tagCounters = {}; // Object to track instances of each tag // List of classes to be excluded const excludedClasses = ['medium-author', 'post-widget-title']; elements.forEach(el => { // Skip elements with any of the excluded classes if (excludedClasses.some(cls => el.classList.contains(cls))) { return; // Skip this element if it has any of the excluded classes } const tagName = el.tagName.toLowerCase(); // Get the tag name (e.g., 'h1', 'h2', etc.) // Initialize a counter for each tag if not already done if (!tagCounters[tagName]) { tagCounters[tagName] = 0; } // Only process the first 10 elements of each tag type if (tagCounters[tagName] >= 10) { return; // Skip if the number of elements exceeds 10 } const text = el.textContent.trim(); // Get the text content const words = text.split(/\s+/); // Split the text into words if (words.length >= 4) { // Ensure at least 4 words const significantPart = words.slice(0, 5).join(' '); // Get first 5 words for matching // Check if the text (not the tag) has been seen before if (seenTexts.has(significantPart)) { // console.log('Duplicate found, removing:', el); // Log duplicate el.remove(); // Remove duplicate element } else { seenTexts.add(significantPart); // Add the text to the set } } tagCounters[tagName]++; // Increment the counter for this tag }); } removeDuplicateText(); //Remove unnecessary text in blog excerpts document.querySelectorAll('.blog p').forEach(function(paragraph) { // Replace the unwanted text pattern for each paragraph paragraph.innerHTML = paragraph.innerHTML .replace(/Author\(s\): [\w\s]+ Originally published on Towards AI\.?/g, '') // Removes 'Author(s): XYZ Originally published on Towards AI' .replace(/This member-only story is on us\. Upgrade to access all of Medium\./g, ''); // Removes 'This member-only story...' }); //Load ionic icons and cache them if ('localStorage' in window && window['localStorage'] !== null) { const cssLink = 'https://code.ionicframework.com/ionicons/2.0.1/css/ionicons.min.css'; const storedCss = localStorage.getItem('ionicons'); if (storedCss) { loadCSS(storedCss); } else { fetch(cssLink).then(response => response.text()).then(css => { localStorage.setItem('ionicons', css); loadCSS(css); }); } } function loadCSS(css) { const style = document.createElement('style'); style.innerHTML = css; document.head.appendChild(style); } //Remove elements from imported content automatically function removeStrongFromHeadings() { const elements = document.querySelectorAll('h1, h2, h3, h4, h5, h6, span'); elements.forEach(el => { const strongTags = el.querySelectorAll('strong'); strongTags.forEach(strongTag => { while (strongTag.firstChild) { strongTag.parentNode.insertBefore(strongTag.firstChild, strongTag); } strongTag.remove(); }); }); } removeStrongFromHeadings(); "use strict"; window.onload = () => { /* //This is an object for each category of subjects and in that there are kewords and link to the keywods let keywordsAndLinks = { //you can add more categories and define their keywords and add a link ds: { keywords: [ //you can add more keywords here they are detected and replaced with achor tag automatically 'data science', 'Data science', 'Data Science', 'data Science', 'DATA SCIENCE', ], //we will replace the linktext with the keyword later on in the code //you can easily change links for each category here //(include class="ml-link" and linktext) link: 'linktext', }, ml: { keywords: [ //Add more keywords 'machine learning', 'Machine learning', 'Machine Learning', 'machine Learning', 'MACHINE LEARNING', ], //Change your article link (include class="ml-link" and linktext) link: 'linktext', }, ai: { keywords: [ 'artificial intelligence', 'Artificial intelligence', 'Artificial Intelligence', 'artificial Intelligence', 'ARTIFICIAL INTELLIGENCE', ], //Change your article link (include class="ml-link" and linktext) link: 'linktext', }, nl: { keywords: [ 'NLP', 'nlp', 'natural language processing', 'Natural Language Processing', 'NATURAL LANGUAGE PROCESSING', ], //Change your article link (include class="ml-link" and linktext) link: 'linktext', }, des: { keywords: [ 'data engineering services', 'Data Engineering Services', 'DATA ENGINEERING SERVICES', ], //Change your article link (include class="ml-link" and linktext) link: 'linktext', }, td: { keywords: [ 'training data', 'Training Data', 'training Data', 'TRAINING DATA', ], //Change your article link (include class="ml-link" and linktext) link: 'linktext', }, ias: { keywords: [ 'image annotation services', 'Image annotation services', 'image Annotation services', 'image annotation Services', 'Image Annotation Services', 'IMAGE ANNOTATION SERVICES', ], //Change your article link (include class="ml-link" and linktext) link: 'linktext', }, l: { keywords: [ 'labeling', 'labelling', ], //Change your article link (include class="ml-link" and linktext) link: 'linktext', }, pbp: { keywords: [ 'previous blog posts', 'previous blog post', 'latest', ], //Change your article link (include class="ml-link" and linktext) link: 'linktext', }, mlc: { keywords: [ 'machine learning course', 'machine learning class', ], //Change your article link (include class="ml-link" and linktext) link: 'linktext', }, }; //Articles to skip let articleIdsToSkip = ['post-2651', 'post-3414', 'post-3540']; //keyword with its related achortag is recieved here along with article id function searchAndReplace(keyword, anchorTag, articleId) { //selects the h3 h4 and p tags that are inside of the article let content = document.querySelector(`#${articleId} .entry-content`); //replaces the "linktext" in achor tag with the keyword that will be searched and replaced let newLink = anchorTag.replace('linktext', keyword); //regular expression to search keyword var re = new RegExp('(' + keyword + ')', 'g'); //this replaces the keywords in h3 h4 and p tags content with achor tag content.innerHTML = content.innerHTML.replace(re, newLink); } function articleFilter(keyword, anchorTag) { //gets all the articles var articles = document.querySelectorAll('article'); //if its zero or less then there are no articles if (articles.length > 0) { for (let x = 0; x < articles.length; x++) { //articles to skip is an array in which there are ids of articles which should not get effected //if the current article's id is also in that array then do not call search and replace with its data if (!articleIdsToSkip.includes(articles[x].id)) { //search and replace is called on articles which should get effected searchAndReplace(keyword, anchorTag, articles[x].id, key); } else { console.log( `Cannot replace the keywords in article with id ${articles[x].id}` ); } } } else { console.log('No articles found.'); } } let key; //not part of script, added for (key in keywordsAndLinks) { //key is the object in keywords and links object i.e ds, ml, ai for (let i = 0; i < keywordsAndLinks[key].keywords.length; i++) { //keywordsAndLinks[key].keywords is the array of keywords for key (ds, ml, ai) //keywordsAndLinks[key].keywords[i] is the keyword and keywordsAndLinks[key].link is the link //keyword and link is sent to searchreplace where it is then replaced using regular expression and replace function articleFilter( keywordsAndLinks[key].keywords[i], keywordsAndLinks[key].link ); } } function cleanLinks() { // (making smal functions is for DRY) this function gets the links and only keeps the first 2 and from the rest removes the anchor tag and replaces it with its text function removeLinks(links) { if (links.length > 1) { for (let i = 2; i < links.length; i++) { links[i].outerHTML = links[i].textContent; } } } //arrays which will contain all the achor tags found with the class (ds-link, ml-link, ailink) in each article inserted using search and replace let dslinks; let mllinks; let ailinks; let nllinks; let deslinks; let tdlinks; let iaslinks; let llinks; let pbplinks; let mlclinks; const content = document.querySelectorAll('article'); //all articles content.forEach((c) => { //to skip the articles with specific ids if (!articleIdsToSkip.includes(c.id)) { //getting all the anchor tags in each article one by one dslinks = document.querySelectorAll(`#${c.id} .entry-content a.ds-link`); mllinks = document.querySelectorAll(`#${c.id} .entry-content a.ml-link`); ailinks = document.querySelectorAll(`#${c.id} .entry-content a.ai-link`); nllinks = document.querySelectorAll(`#${c.id} .entry-content a.ntrl-link`); deslinks = document.querySelectorAll(`#${c.id} .entry-content a.des-link`); tdlinks = document.querySelectorAll(`#${c.id} .entry-content a.td-link`); iaslinks = document.querySelectorAll(`#${c.id} .entry-content a.ias-link`); mlclinks = document.querySelectorAll(`#${c.id} .entry-content a.mlc-link`); llinks = document.querySelectorAll(`#${c.id} .entry-content a.l-link`); pbplinks = document.querySelectorAll(`#${c.id} .entry-content a.pbp-link`); //sending the anchor tags list of each article one by one to remove extra anchor tags removeLinks(dslinks); removeLinks(mllinks); removeLinks(ailinks); removeLinks(nllinks); removeLinks(deslinks); removeLinks(tdlinks); removeLinks(iaslinks); removeLinks(mlclinks); removeLinks(llinks); removeLinks(pbplinks); } }); } //To remove extra achor tags of each category (ds, ml, ai) and only have 2 of each category per article cleanLinks(); */ //Recommended Articles var ctaLinks = [ /* ' ' + '

Subscribe to our AI newsletter!

' + */ '

Take our 85+ lesson From Beginner to Advanced LLM Developer Certification: From choosing a project to deploying a working product this is the most comprehensive and practical LLM course out there!

'+ '

Towards AI has published Building LLMs for Production—our 470+ page guide to mastering LLMs with practical projects and expert insights!

' + '
' + '' + '' + '

Note: Content contains the views of the contributing authors and not Towards AI.
Disclosure: This website may contain sponsored content and affiliate links.

' + 'Discover Your Dream AI Career at Towards AI Jobs' + '

Towards AI has built a jobs board tailored specifically to Machine Learning and Data Science Jobs and Skills. Our software searches for live AI jobs each hour, labels and categorises them and makes them easily searchable. Explore over 10,000 live jobs today with Towards AI Jobs!

' + '
' + '

🔥 Recommended Articles 🔥

' + 'Why Become an LLM Developer? Launching Towards AI’s New One-Stop Conversion Course'+ 'Testing Launchpad.sh: A Container-based GPU Cloud for Inference and Fine-tuning'+ 'The Top 13 AI-Powered CRM Platforms
' + 'Top 11 AI Call Center Software for 2024
' + 'Learn Prompting 101—Prompt Engineering Course
' + 'Explore Leading Cloud Providers for GPU-Powered LLM Training
' + 'Best AI Communities for Artificial Intelligence Enthusiasts
' + 'Best Workstations for Deep Learning
' + 'Best Laptops for Deep Learning
' + 'Best Machine Learning Books
' + 'Machine Learning Algorithms
' + 'Neural Networks Tutorial
' + 'Best Public Datasets for Machine Learning
' + 'Neural Network Types
' + 'NLP Tutorial
' + 'Best Data Science Books
' + 'Monte Carlo Simulation Tutorial
' + 'Recommender System Tutorial
' + 'Linear Algebra for Deep Learning Tutorial
' + 'Google Colab Introduction
' + 'Decision Trees in Machine Learning
' + 'Principal Component Analysis (PCA) Tutorial
' + 'Linear Regression from Zero to Hero
'+ '

', /* + '

Join thousands of data leaders on the AI newsletter. It’s free, we don’t spam, and we never share your email address. Keep up to date with the latest work in AI. From research to projects and ideas. If you are building an AI startup, an AI-related product, or a service, we invite you to consider becoming a sponsor.

',*/ ]; var replaceText = { '': '', '': '', '
': '
' + ctaLinks + '
', }; Object.keys(replaceText).forEach((txtorig) => { //txtorig is the key in replacetext object const txtnew = replaceText[txtorig]; //txtnew is the value of the key in replacetext object let entryFooter = document.querySelector('article .entry-footer'); if (document.querySelectorAll('.single-post').length > 0) { //console.log('Article found.'); const text = entryFooter.innerHTML; entryFooter.innerHTML = text.replace(txtorig, txtnew); } else { // console.log('Article not found.'); //removing comment 09/04/24 } }); var css = document.createElement('style'); css.type = 'text/css'; css.innerHTML = '.post-tags { display:none !important } .article-cta a { font-size: 18px; }'; document.body.appendChild(css); //Extra //This function adds some accessibility needs to the site. function addAlly() { // In this function JQuery is replaced with vanilla javascript functions const imgCont = document.querySelector('.uw-imgcont'); imgCont.setAttribute('aria-label', 'AI news, latest developments'); imgCont.title = 'AI news, latest developments'; imgCont.rel = 'noopener'; document.querySelector('.page-mobile-menu-logo a').title = 'Towards AI Home'; document.querySelector('a.social-link').rel = 'noopener'; document.querySelector('a.uw-text').rel = 'noopener'; document.querySelector('a.uw-w-branding').rel = 'noopener'; document.querySelector('.blog h2.heading').innerHTML = 'Publication'; const popupSearch = document.querySelector$('a.btn-open-popup-search'); popupSearch.setAttribute('role', 'button'); popupSearch.title = 'Search'; const searchClose = document.querySelector('a.popup-search-close'); searchClose.setAttribute('role', 'button'); searchClose.title = 'Close search page'; // document // .querySelector('a.btn-open-popup-search') // .setAttribute( // 'href', // 'https://medium.com/towards-artificial-intelligence/search' // ); } // Add external attributes to 302 sticky and editorial links function extLink() { // Sticky 302 links, this fuction opens the link we send to Medium on a new tab and adds a "noopener" rel to them var stickyLinks = document.querySelectorAll('.grid-item.sticky a'); for (var i = 0; i < stickyLinks.length; i++) { /* stickyLinks[i].setAttribute('target', '_blank'); stickyLinks[i].setAttribute('rel', 'noopener'); */ } // Editorial 302 links, same here var editLinks = document.querySelectorAll( '.grid-item.category-editorial a' ); for (var i = 0; i < editLinks.length; i++) { editLinks[i].setAttribute('target', '_blank'); editLinks[i].setAttribute('rel', 'noopener'); } } // Add current year to copyright notices document.getElementById( 'js-current-year' ).textContent = new Date().getFullYear(); // Call functions after page load extLink(); //addAlly(); setTimeout(function() { //addAlly(); //ideally we should only need to run it once ↑ }, 5000); }; function closeCookieDialog (){ document.getElementById("cookie-consent").style.display = "none"; return false; } setTimeout ( function () { closeCookieDialog(); }, 15000); console.log(`%c 🚀🚀🚀 ███ █████ ███████ █████████ ███████████ █████████████ ███████████████ ███████ ███████ ███████ ┌───────────────────────────────────────────────────────────────────┐ │ │ │ Towards AI is looking for contributors! │ │ Join us in creating awesome AI content. │ │ Let's build the future of AI together → │ │ https://towardsai.net/contribute │ │ │ └───────────────────────────────────────────────────────────────────┘ `, `background: ; color: #00adff; font-size: large`); //Remove latest category across site document.querySelectorAll('a[rel="category tag"]').forEach(function(el) { if (el.textContent.trim() === 'Latest') { // Remove the two consecutive spaces (  ) if (el.nextSibling && el.nextSibling.nodeValue.includes('\u00A0\u00A0')) { el.nextSibling.nodeValue = ''; // Remove the spaces } el.style.display = 'none'; // Hide the element } }); // Add cross-domain measurement, anonymize IPs 'use strict'; //var ga = gtag; ga('config', 'G-9D3HKKFV1Q', 'auto', { /*'allowLinker': true,*/ 'anonymize_ip': true/*, 'linker': { 'domains': [ 'medium.com/towards-artificial-intelligence', 'datasets.towardsai.net', 'rss.towardsai.net', 'feed.towardsai.net', 'contribute.towardsai.net', 'members.towardsai.net', 'pub.towardsai.net', 'news.towardsai.net' ] } */ }); ga('send', 'pageview'); -->