<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>AI Notebook Archives - OVHcloud Blog</title>
	<atom:link href="https://blog.ovhcloud.com/tag/ai-notebook/feed/" rel="self" type="application/rss+xml" />
	<link>https://blog.ovhcloud.com/tag/ai-notebook/</link>
	<description>Innovation for Freedom</description>
	<lastBuildDate>Fri, 06 Feb 2026 15:18:43 +0000</lastBuildDate>
	<language>en-GB</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9.4</generator>

<image>
	<url>https://blog.ovhcloud.com/wp-content/uploads/2019/07/cropped-cropped-nouveau-logo-ovh-rebranding-32x32.gif</url>
	<title>AI Notebook Archives - OVHcloud Blog</title>
	<link>https://blog.ovhcloud.com/tag/ai-notebook/</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>Fine tune an LLM with Axolotl and OVHcloud Machine Learning Services</title>
		<link>https://blog.ovhcloud.com/fine-tune-an-llm-with-axolotl-and-ovhcloud-machine-learning-services/</link>
		
		<dc:creator><![CDATA[Stéphane Philippart]]></dc:creator>
		<pubDate>Fri, 25 Jul 2025 13:07:40 +0000</pubDate>
				<category><![CDATA[OVHcloud Engineering]]></category>
		<category><![CDATA[Tranches de Tech & co]]></category>
		<category><![CDATA[AI]]></category>
		<category><![CDATA[AI Deploy]]></category>
		<category><![CDATA[AI Notebook]]></category>
		<category><![CDATA[Fine Tuning]]></category>
		<category><![CDATA[OVHcloud]]></category>
		<guid isPermaLink="false">https://blog.ovhcloud.com/?p=29408</guid>

					<description><![CDATA[There are many ways to train a model,📚 using detailed instructions, system prompts, Retrieval Augmented Generation, or function calling One way is fine-tuning, which is what this blog is about! ✨ Two years back we posted a blog on fine-tuning Llama models—it’s not nearly as complicated as it was before 😉.  This time we’re using the [&#8230;]<img src="//blog.ovhcloud.com/wp-content/plugins/matomo/app/matomo.php?idsite=1&amp;rec=1&amp;url=https%3A%2F%2Fblog.ovhcloud.com%2Ffine-tune-an-llm-with-axolotl-and-ovhcloud-machine-learning-services%2F&amp;action_name=Fine%20tune%20an%20LLM%20with%20Axolotl%20and%20OVHcloud%20Machine%20Learning%20Services&amp;urlref=https%3A%2F%2Fblog.ovhcloud.com%2Ffeed%2F" style="border:0;width:0;height:0" width="0" height="0" alt="" />]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-image aligncenter size-full is-resized"><img fetchpriority="high" decoding="async" width="1024" height="1024" src="https://blog.ovhcloud.com/wp-content/uploads/2025/07/red-cat-02-1.png" alt="A robot with a car tuning style" class="wp-image-29462" style="width:600px" srcset="https://blog.ovhcloud.com/wp-content/uploads/2025/07/red-cat-02-1.png 1024w, https://blog.ovhcloud.com/wp-content/uploads/2025/07/red-cat-02-1-300x300.png 300w, https://blog.ovhcloud.com/wp-content/uploads/2025/07/red-cat-02-1-150x150.png 150w, https://blog.ovhcloud.com/wp-content/uploads/2025/07/red-cat-02-1-768x768.png 768w, https://blog.ovhcloud.com/wp-content/uploads/2025/07/red-cat-02-1-70x70.png 70w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<p>There are many ways to train a model,📚 using detailed instructions, system prompts, Retrieval Augmented Generation, or function calling</p>



<p>One way is fine-tuning, which is what this blog is about! ✨</p>



<p>Two years back we posted a <a href="https://blog.ovhcloud.com/fine-tuning-llama-2-models-using-a-single-gpu-qlora-and-ai-notebooks/" data-wpel-link="internal">blog</a> on fine-tuning Llama models—it’s not nearly as complicated as it was before 😉.  This time we’re using the Framework <a href="https://docs.axolotl.ai/" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer">Axolotl</a>, so hopefully there’s less to manage.</p>



<h3 class="wp-block-heading">So what’s the plan?</h3>



<p>For this blog, I’d like to fine-tune a small model, <a href="https://huggingface.co/meta-llama/Llama-3.2-1B-Instruct" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer">Llama-3.2-1B-Instruct</a>, and then test it out on a few questions about our <a href="https://endpoints.ai.cloud.ovh.net/" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer">OVHcloud AI Endpoints</a> product 📝.</p>



<p>Before we fine-tune, let’s try it out! Deploying a <a href="https://huggingface.co/" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer">Hugging Face</a> model is super easy with <a href="https://www.ovhcloud.com/fr/public-cloud/ai-deploy/" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer">AI Deploy</a> from <a href="https://www.ovhcloud.com/fr/public-cloud/ai-machine-learning/" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer">AI Machine Learning Services</a> 🥳.</p>



<p>And thanks to a <a href="https://blog.ovhcloud.com/mistral-small-24b-served-with-vllm-and-ai-deploy-one-command-to-deploy-llm/" data-wpel-link="internal">previous blog post</a>, we know how to use <a href="https://docs.vllm.ai/en/v0.7.3/index.html" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer">vLLM</a> and <a href="https://www.ovhcloud.com/fr/public-cloud/ai-deploy/" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer">AI Deploy</a>.</p>



<pre title="Deploy a model thanks to vLLM and AI Deploy" class="wp-block-code"><code lang="bash" class="language-bash line-numbers">ovhai app run --name $1 \
	--flavor l40s-1-gpu \
	--gpu 2 \
	--default-http-port 8000 \
	--env OUTLINES_CACHE_DIR=/tmp/.outlines \
	--env HF_TOKEN=$MY_HUGGING_FACE_TOKEN \
	--env HF_HOME=/hub \
	--env HF_DATASETS_TRUST_REMOTE_CODE=1 \
	--env HF_HUB_ENABLE_HF_TRANSFER=0 \
	--volume standalone:/hub:rw \
	--volume standalone:/workspace:rw \
	vllm/vllm-openai:v0.8.2 \
	-- bash	-c "vllm serve meta-llama/Llama-3.2-1B-Instruct"</code></pre>



<p class="has-text-align-center"><strong><strong>⚠️ Make sure you’ve agreed to the terms of use for the model’s license from Hugging Face ⚠️</strong></strong></p>



<p>Check out the <a href="https://blog.ovhcloud.com/mistral-small-24b-served-with-vllm-and-ai-deploy-one-command-to-deploy-llm/" data-wpel-link="internal">blog</a> I mentioned earlier for all the details you need on the command and its parameters.</p>



<p>To test our different chatbots we will use a simple <a href="https://github.com/ovh/public-cloud-examples/tree/main/ai/llm-fine-tune/chatbot/chatbot.py" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer">Gradio application</a>:</p>



<pre title="Chatbot" class="wp-block-code"><code lang="python" class="language-python line-numbers"># Application to compare answers generation from OVHcloud AI Endpoints exposed model and fine tuned model.
# ⚠️ Do not used in production!! ⚠️

import gradio as gr
import os

from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate

# 📜 Prompts templates 📜
prompt_template = ChatPromptTemplate.from_messages(
    [
        ("system", "{system_prompt}"),
        ("human", "{user_prompt}"),
    ]
)

def chat(prompt, system_prompt, temperature, top_p, model_name, model_url, api_key):
    """
    Function to generate a chat response using the provided prompt, system prompt, temperature, top_p, model name, model URL and API key.
    """

    # ⚙️ Initialize the OpenAI model ⚙️
    llm = ChatOpenAI(api_key=api_key, 
                 model=model_name, 
                 base_url=model_url,
                 temperature=temperature,
                 top_p=top_p
                 )

    # 📜 Apply the prompt to the model 📜
    chain = prompt_template | llm
    ai_msg = chain.invoke(
        {
            "system_prompt": system_prompt,
            "user_prompt": prompt
        }
    )

    # 🤖 Return answer in a compatible format for Gradio component.
    return [{"role": "user", "content": prompt}, {"role": "assistant", "content": ai_msg.content}]

# 🖥️ Main application 🖥️
with gr.Blocks() as demo:
    with gr.Row():
        with gr.Column():
            system_prompt = gr.Textbox(value="""You are a specialist on OVHcloud products.
If you can't find any sure and relevant information about the product asked, answer with "This product doesn't exist in OVHcloud""", 
                label="🧑‍🏫 System Prompt 🧑‍🏫")
            temperature = gr.Slider(minimum=0.0, maximum=2.0, step=0.01, label="Temperature", value=0.5)
            top_p = gr.Slider(minimum=0.0, maximum=1.0, step=0.01, label="Top P", value=0.0)
            model_name = gr.Textbox(label="🧠 Model Name 🧠", value='Llama-3.1-8B-Instruct')
            model_url = gr.Textbox(label="🔗 Model URL 🔗", value='https://oai.endpoints.kepler.ai.cloud.ovh.net/v1')
            api_key = gr.Textbox(label="🔑 OVH AI Endpoints Access Token 🔑", value=os.getenv("OVH_AI_ENDPOINTS_ACCESS_TOKEN"), type="password")

        with gr.Column():
            chatbot = gr.Chatbot(type="messages", label="🤖 Response 🤖")
            prompt = gr.Textbox(label="📝 Prompt 📝", value='How many requests by minutes can I do with AI Endpoints?')
            submit = gr.Button("Submit")

    submit.click(chat, inputs=[prompt, system_prompt, temperature, top_p, model_name, model_url, api_key], outputs=chatbot)

demo.launch()</code></pre>



<p>ℹ️ You can find all resources to build and run this application in the <a href="https://github.com/ovh/public-cloud-examples/tree/main/ai/llm-fine-tune/chatbot/" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer">dedicated folder</a> in the GitHub repository.</p>



<p>Let&#8217;s test with a simple question: &#8220;How many requests by minutes can I do with AI Endpoints?&#8221;.<br>The first test is with <a href="https://huggingface.co/meta-llama/Llama-3.2-1B-Instruct" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer">Llama-3.2-1B-Instruct</a> from <a href="https://huggingface.co/" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer"></a><a href="https://huggingface.co/" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer">Hugging Face</a> deployed with <a href="https://docs.vllm.ai/en/v0.7.3/index.html" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer">vLLM</a> and <a href="https://www.ovhcloud.com/fr/public-cloud/ai-deploy/" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer">OVHcloud AI Deploy</a>.</p>



<figure class="wp-block-image aligncenter size-large"><img decoding="async" width="1024" height="474" src="https://blog.ovhcloud.com/wp-content/uploads/2025/07/Screenshot-2025-07-23-at-13.19.16-1024x474.png" alt="Ask for AI Endpoints rate limit with a Llama-3.2-1B-Instruct model" class="wp-image-29448" srcset="https://blog.ovhcloud.com/wp-content/uploads/2025/07/Screenshot-2025-07-23-at-13.19.16-1024x474.png 1024w, https://blog.ovhcloud.com/wp-content/uploads/2025/07/Screenshot-2025-07-23-at-13.19.16-300x139.png 300w, https://blog.ovhcloud.com/wp-content/uploads/2025/07/Screenshot-2025-07-23-at-13.19.16-768x356.png 768w, https://blog.ovhcloud.com/wp-content/uploads/2025/07/Screenshot-2025-07-23-at-13.19.16-1536x712.png 1536w, https://blog.ovhcloud.com/wp-content/uploads/2025/07/Screenshot-2025-07-23-at-13.19.16-2048x949.png 2048w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>The response isn’t exactly what we expected. 😅</p>



<p>FYI, according to the official <a href="https://help.ovhcloud.com/csm/fr-public-cloud-ai-endpoints-capabilities?id=kb_article_view&amp;sysparm_article=KB0065424#limitations" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer">OVHcloud guide</a>, the correct answer is:<br> &#8211; <strong>Anonymous</strong>: 2 requests per minute, per IP and per model.<br> &#8211; <strong>Authenticated with an API access key</strong>: 400 requests per minute, per Public Cloud project and per model.</p>



<h3 class="wp-block-heading"><strong>What’s the best way to feed the model fresh data?</strong></h3>



<p>I bet you already know this—you can use some data during the inference step, using Retrieval Augmented Generation (RAG). You can learn how to set up RAG by reading our <a href="https://blog.ovhcloud.com/rag-chatbot-using-ai-endpoints-and-langchain/" data-wpel-link="internal">past blog post</a>. 📗</p>



<p>Another way to feed a model fresh data by fine-tuning. ✨</p>



<p>In a nutshell,  fine-tuning is when you take a pre-trained machine learning model and train it further on additional data, so it can do a specific job. It’s quicker and easier than building a model yourself, or from scratch. 😉</p>



<p>For this, I’m picking <a href="https://huggingface.co/meta-llama/Llama-3.2-1B-Instruct" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer">Llama-3.2-1B-Instruct</a> from Hugging Face as the base model.</p>



<p><em>ℹ️ The more parameters your base model has, the more computing power you need. In this case, this model needs between 3GB and 4GB of memory, <em>which is why we’ll be using</em> a <a href="https://www.ovhcloud.com/fr/public-cloud/prices/#5260" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer">single L4 GPU</a> (we need </em><a href="https://www.nvidia.com/en-us/data-center/ampere-architecture/" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer"><em>Ampere</em> compatible architecture</a>).</p>



<h3 class="wp-block-heading">When data is your gold</h3>



<p>To train a model, you need enough good-quality data.</p>



<p>The first part is easy; I get the OVHcloud AI Endpoints official documentation in a markdown format from our <a href="https://github.com/ovh/docs/tree/develop/pages/public_cloud/ai_machine_learning" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer">public cloud documentation repository</a> (by the way, would you like to contribute?). 📚</p>



<p>First, create a dataset with the right format, Axolotl offers varying <a href="https://docs.axolotl.ai/docs/dataset-formats/" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer">dataset formats</a>. I prefer the <a href="https://docs.axolotl.ai/docs/dataset-formats/conversation.html" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer">conversation format</a> because it’s the easiest for my use case, so I’m going with that. 😉</p>



<pre title="Conersation format dataset" class="wp-block-code"><code lang="json" class="language-json line-numbers"><a href="https://docs.axolotl.ai/docs/dataset-formats/conversation.html#cb1-1" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer"></a>{
   "messages": [
     {"role": "...", "content": "..."}, 
     {"role": "...", "content": "..."}, 
     ...]
}</code></pre>



<p>And to create it manually and add the relevant information, I use an LLM to convert the markdown data into a well-formed dataset. 🤖</p>



<p>Here we’re using <a href="https://github.com/ovh/public-cloud-examples/tree/main/ai/llm-fine-tune/ai/llm-fine-tune/dataset/DatasetCreation.py" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer">Python script </a>🐍:</p>



<pre title="Dataset creation with LLM" class="wp-block-code"><code lang="python" class="language-python line-numbers">import os
from pathlib import Path
from langchain_openai import ChatOpenAI
from langchain.schema import HumanMessage

# 🗺️ Define the JSON schema for the response 🗺️
message_schema = {
    "type": "object",
    "properties": {
        "role": {"type": "string"},
        "content": {"type": "string"}
    },
    "required": ["role", "content"]
}

response_format = {
    "type": "json_object",
    "json_schema": {
        "name": "Messages",
        "description": "A list of messages with role and content",
        "properties": {
            "messages": {
                "type": "array",
                "items": message_schema
            }
        }
    }
}

# ⚙️ Initialize the chat model with AI Endpoints configuration ⚙️
chat_model = ChatOpenAI(
    api_key=os.getenv("OVH_AI_ENDPOINTS_ACCESS_TOKEN"),
    base_url=os.getenv("OVH_AI_ENDPOINTS_MODEL_URL"),
    model_name=os.getenv("OVH_AI_ENDPOINTS_MODEL_NAME"),
    temperature=0.0
)

# 📂 Define the directory path 📂
directory_path = "docs/pages/public_cloud/ai_machine_learning"
directory = Path(directory_path)

# 🗃️ Walk through the directory and its subdirectories 🗃️
for path in directory.rglob("*"):
    # Check if the current path is a directory
    if path.is_dir():
        # Get the name of the subdirectory
        sub_directory = path.name

        # Construct the path to the "guide.en-gb.md" file in the subdirectory
        guide_file_path = path / "guide.en-gb.md"

        # Check if the "guide.en-gb.md" file exists in the subdirectory
        if "endpoints" in sub_directory and guide_file_path.exists():
            print(f"📗 Guide processed: {sub_directory}")
            with open(guide_file_path, 'r', encoding='utf-8') as file:
                raw_data = file.read()

            user_message = HumanMessage(content=f"""
With the markdown following, generate a JSON file composed as follows: a list named "messages" composed of tuples with a key "role" which can have the value "user" when it's the question and "assistant" when it's the response. To split the document, base it on the markdown chapter titles to create the question, seems like a good idea.
Keep the language English.
I don't need to know the code to do it but I want the JSON result file.
For the "user" field, don't just repeat the title but make a real question, for example "What are the requirements for OVHcloud AI Endpoints?"
Be sure to add OVHcloud with AI Endpoints so that it's clear that OVHcloud creates AI Endpoints.
Generate the entire JSON file.
An example of what it should look like: messages [{{"role":"user", "content":"What is AI Endpoints?"}}]
There must always be a question followed by an answer, never two questions or two answers in a row.
The source markdown file:
{raw_data}
""")
            chat_response = chat_model.invoke([user_message], response_format=response_format)
            
            with open(f"./generated/{sub_directory}.json", 'w', encoding='utf-8') as output_file:
                output_file.write(chat_response.content)
                print(f"✅ Dataset generated: ./generated/{sub_directory}.json")

</code></pre>



<p><em>ℹ️ You can find all resources to build and run this application in the <a href="https://github.com/ovh/public-cloud-examples/tree/main/ai/llm-fine-tune/dataset/" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer">dedicated folder</a> in the GitHub repository.</em></p>



<p>Here’s a sample of the file created as the dataset:</p>



<pre title="Dataset example" class="wp-block-code"><code lang="json" class="language-json line-numbers">[
  {
    "role": "user",
    "content": "What are the requirements for using OVHcloud AI Endpoints?"
  },
  {
    "role": "assistant",
    "content": "To use OVHcloud AI Endpoints, you need the following: \n1. A Public Cloud project in your OVHcloud account \n2. A payment method defined on your Public Cloud project. Access keys created from Public Cloud projects in Discovery mode (without a payment method) cannot use the service."
  },
  {
    "role": "user",
    "content": "What are the rate limits for using OVHcloud AI Endpoints?"
  },
  {
    "role": "assistant",
    "content": "The rate limits for OVHcloud AI Endpoints are as follows:\n- Anonymous: 2 requests per minute, per IP and per model.\n- Authenticated with an API access key: 400 requests per minute, per PCI project and per model."
  }, 
   ...]
}</code></pre>



<p>As for quantity, it’s a bit tricky. How can we generate the right data for training without lowering data quality?</p>



<p>To do this, I’ve created synthetic data using an LLM to create it from the original data. The trick is to generate more data on the same topic by rephrasing it differently but with the same idea.</p>



<p>Here is the <a href="https://github.com/ovh/public-cloud-examples/tree/main/ai/llm-fine-tune/dataset/DatasetAugmentation.py" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer">Python script</a> 🐍 to do the data augmentation:</p>



<pre title="Data augmentation" class="wp-block-code"><code lang="python" class="language-python line-numbers">import os
import json
import uuid
from pathlib import Path
from langchain_openai import ChatOpenAI
from langchain.schema import HumanMessage
from jsonschema import validate, ValidationError

# 🗺️ Define the JSON schema for the response 🗺️
message_schema = {
    "type": "object",
    "properties": {
        "role": {"type": "string"},
        "content": {"type": "string"}
    },
    "required": ["role", "content"]
}

response_format = {
    "type": "json_object",
    "json_schema": {
        "name": "Messages",
        "description": "A list of messages with role and content",
        "properties": {
            "messages": {
                "type": "array",
                "items": message_schema
            }
        }
    }
}

# ✅ JSON validity verification ❌
def is_valid(json_data):
    """
    Test the validity of the JSON data against the schema.
    Argument:
        json_data (dict): The JSON data to validate.  
    Raises:
        ValidationError: If the JSON data does not conform to the specified schema.  
    """
    try:
        validate(instance=json_data, schema=response_format["json_schema"])
        return True
    except ValidationError as e:
        print(f"❌ Validation error: {e}")
        return False

# ⚙️ Initialize the chat model with AI Endpoints configuration ⚙️
chat_model = ChatOpenAI(
    api_key=os.getenv("OVH_AI_ENDPOINTS_ACCESS_TOKEN"),
    base_url=os.getenv("OVH_AI_ENDPOINTS_MODEL_URL"),
    model_name=os.getenv("OVH_AI_ENDPOINTS_MODEL_NAME"),
    temperature=0.0
)

# 📂 Define the directory path 📂
directory_path = "generated"
print(f"📂 Directory path: {directory_path}")
directory = Path(directory_path)

# 🗃️ Walk through the directory and its subdirectories 🗃️
for path in directory.rglob("*"):
    print(f"📜 Processing file: {path}")
    # Check if the current path is a valid file
    if path.is_file() and path.name.__contains__ ("endpoints"):
        # Read the raw data from the file
        with open(path, 'r', encoding='utf-8') as file:
            raw_data = file.read()

        try:
            json_data = json.loads(raw_data)
        except json.JSONDecodeError:
            print(f"❌ Failed to decode JSON from file: {path.name}")
            continue

        if not is_valid(json_data):
            print(f"❌ Dataset non valide: {path.name}")
            continue
        print(f"✅ Input dataset valide: {path.name}")

        user_message = HumanMessage(content=f"""
        Given the following JSON, generate a similar JSON file where you paraphrase each question in the content attribute
        (when the role attribute is user) and also paraphrase the value of the response to the question stored in the content attribute
        when the role attribute is assistant.
        The objective is to create synthetic datasets based on existing datasets.
        I do not need to know the code to do this, but I want the resulting JSON file.
        It is important that the term OVHcloud is present as much as possible, especially when the terms AI Endpoints are mentioned
        either in the question or in the response.
        There must always be a question followed by an answer, never two questions or two answers in a row.
        It is IMPERATIVE to keep the language in English.
        The source JSON file:
        {raw_data}
        """)

        chat_response = chat_model.invoke([user_message], response_format=response_format)

        output = chat_response.content

        # Replace unauthorized characters
        output = output.replace("\\t", " ")

        generated_file_name = f"{uuid.uuid4()}_{path.name}"
        with open(f"./generated/synthetic/{generated_file_name}", 'w', encoding='utf-8') as output_file:
            output_file.write(output)

        if not is_valid(json.loads(output)):
            print(f"❌ ERROR: File {generated_file_name} is not valid")
        else:
            print(f"✅ Successfully generated file: {generated_file_name}")</code></pre>



<p><em>ℹ️ Again, you can find all resources to build and run this application in the <a href="https://github.com/ovh/public-cloud-examples/tree/main/ai/llm-fine-tune/dataset/" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer">dedicated folder</a> in the GitHub repository.</em></p>



<h3 class="wp-block-heading">Fine-tune the model</h3>



<p>We now have enough training data, let’s fine-tune!</p>



<p><em><em>ℹ️ It’s hard to say exactly how much data is needed to train a model properly. It all depends on the model, the data, the topic, and so on.</em><br><em>The only option is to test and adapt. 🔁</em>.</em></p>



<p>I use <a href="https://jupyter.org/" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer">Jupyter notebook</a>, created with <a href="https://www.ovhcloud.com/fr/public-cloud/ai-notebooks/" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer">OVHcloud AI Notebooks</a>, to fine-tune my models.</p>



<pre title="Jupyter notebook creation" class="wp-block-code"><code lang="bash" class="language-bash line-numbers">ovhai notebook run conda jupyterlab \
	--name axolto-llm-fine-tune \
	--framework-version 25.3.1-py312-cudadevel128-gpu \
	--flavor l4-1-gpu \
	--gpu 1 \
	--envvar HF_TOKEN=$MY_HF_TOKEN \
	--envvar WANDB_TOKEN=$MY_WANDB_TOKEN \
	--unsecure-http</code></pre>



<p><em><em>ℹ️ For more details on how to create Jupyter notebook with <a href="https://www.ovhcloud.com/fr/public-cloud/ai-notebooks/" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer">AI Notebooks</a>, read the <a href="https://help.ovhcloud.com/csm/fr-documentation-public-cloud-ai-and-machine-learning-ai-notebooks?id=kb_browse_cat&amp;kb_id=574a8325551974502d4c6e78b7421938&amp;kb_category=c8441955f49801102d4ca4d466a7fd58&amp;spa=1" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer">documentation</a>.</em></em></p>



<p class="has-text-align-left">⚙️ The <strong>HF_TOKEN</strong> environment variable is used to pull and push the trained model to <a href="https://huggingface.co/" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer">Hugging Face</a> <br>⚙️ The <strong>WANDB_TOKEN</strong> environment variable helps you track training quality in <a href="https://wandb.ai" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer">Weight &amp; Biases</a></p>



<p>Once the notebook is set up, you can start coding the model’s training with Axolotl.</p>



<p>To start, install Axolotl CLI and its dependencies. 🧰</p>



<pre title="Axolot installation" class="wp-block-code"><code lang="bash" class="language-bash"># Axolotl need these dependencies
!pip install torch==2.6.0 torchvision==0.21.0 torchaudio==2.6.0 --index-url https://download.pytorch.org/whl/cu126

# Axolotl CLI installation
!pip install --no-build-isolation axolotl[flash-attn,deepspeed]

# Verify Axolotl version and installation
!axolotl --version</code></pre>



<p></p>



<p>The next step is to configure the Hugging Face CLI. 🤗</p>



<pre title="Hugging Face configurartion" class="wp-block-code"><code lang="bash" class="language-bash line-numbers">!pip install -U "huggingface_hub[cli]"

!huggingface-cli --version</code></pre>



<pre title="Hugging Face hub authentication " class="wp-block-code"><code lang="python" class="language-python line-numbers">import os
from huggingface_hub import login

login(os.getenv("HF_TOKEN"))</code></pre>



<p></p>



<p>Then, configure your Weight &amp; Biases access.</p>



<pre title="Weight &amp; Biases configuration" class="wp-block-code"><code lang="bash" class="language-bash line-numbers">pip install wandb

!wandb login $WANDB_TOKEN</code></pre>



<p></p>



<p>Once all that’s done, it’s time to train the model.</p>



<pre title="Train the model" class="wp-block-code"><code lang="bash" class="language-bash line-numbers">!axolotl train /workspace/instruct-lora-1b-ai-endpoints.yml</code></pre>



<p>You only need to type this one line to train it, how cool is that? 😎</p>



<p><em><em>ℹ️ With one L4 card, 10 epochs, and roughly 2000 questions and answers in the datasets, it ran for about 90 minutes.</em></em></p>



<p>Basically, the command line needs just one parameter: the Axolotl config file. You can find everything you need to set up Axolotl in the <a href="https://docs.axolotl.ai/docs/config-reference.html" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer">official documentation</a>.📜<br>Here’s what the model was trained on:</p>



<pre title="Axolotl configuration" class="wp-block-code"><code lang="yaml" class="language-yaml">base_model: meta-llama/Llama-3.2-1B-Instruct
# optionally might have model_type or tokenizer_type
model_type: LlamaForCausalLM
tokenizer_type: AutoTokenizer
# Automatically upload checkpoint and final model to HF
# hub_model_id: username/custom_model_name

load_in_8bit: true
load_in_4bit: false

datasets:
  - path: /workspace/ai-endpoints-doc/
    type: chat_template
      
    field_messages: messages
    message_property_mappings:
      role: role
      content: content
    roles:
      user:
        - user
      assistant:
        - assistant

dataset_prepared_path:
val_set_size: 0.01
output_dir: /workspace/out/llama-3.2-1b-ai-endpoints

sequence_len: 4096
sample_packing: false
pad_to_sequence_len: true

adapter: lora
lora_model_dir:
lora_r: 32
lora_alpha: 16
lora_dropout: 0.05
lora_target_linear: true

wandb_project: ai_endpoints_training
wandb_entity: &lt;user id&gt;
wandb_mode: 
wandb_watch:
wandb_name:
wandb_log_model:

gradient_accumulation_steps: 4
micro_batch_size: 2
num_epochs: 10
optimizer: adamw_bnb_8bit
lr_scheduler: cosine
learning_rate: 0.0002

bf16: auto
tf32: false

gradient_checkpointing: true
resume_from_checkpoint:
logging_steps: 1
flash_attention: true

warmup_steps: 10
evals_per_epoch: 4
saves_per_epoch: 1
weight_decay: 0.0
special_tokens:
   pad_token: &lt;|end_of_text|&gt;
</code></pre>



<p>🔎 Some key points (only the fields modified from the <a href="https://github.com/axolotl-ai-cloud/axolotl/blob/main/examples/llama-3/instruct-lora-8b.yml" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer">given templates</a>):<br>&#8211; <strong>base_model: meta-llama/Llama-3.2-1B-Instruct</strong>: before you download the base model from Hugging Face, be sure to accept the licence’s <a>terms of use </a><a href="#_msocom_1">[JD1]</a> <br>&#8211; <strong>path: /workspace/ai-endpoints-doc/</strong>: folder to upload the generated dataset<br>&#8211; <strong>wandb_project: ai_endpoints_training</strong> &amp; <strong>wandb_entity: &lt;user id></strong>: to configure weights and biases<br>&#8211; <strong>num_epochs: 10</strong>: number of epochs for the training<a id="_msocom_1"></a></p>



<p>After the training, you can test the new model 🤖:</p>



<pre title="New model testing" class="wp-block-code"><code lang="bash" class="language-bash line-numbers">!echo "What is OVHcloud AI Endpoints and how to use it?" | axolotl inference /workspace/instruct-lora-1b-ai-endpoints.yml --lora-model-dir="/workspace/out/llama-3.2-1b-ai-endpoints" </code></pre>



<p></p>



<p>When you’re satisfied with the result, merge the weights and upload the new model to Hugging Face:</p>



<pre title="Push the model" class="wp-block-code"><code lang="bash" class="language-bash line-numbers">!axolotl merge-lora /workspace/instruct-lora-1b-ai-endpoints.yml

%cd /workspace/out/llama-3.2-1b-ai-endpoints/merged

!huggingface-cli upload wildagsx/Llama-3.2-1B-Instruct-AI-Endpoints-v0.6 .</code></pre>



<p>ℹ️ <em>You can find all resources to create and run the notebook in the <a href="https://github.com/ovh/public-cloud-examples/tree/main/ai/llm-fine-tune/notebook/" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer">dedicated folder</a> in the GitHub repository.</em></p>



<h3 class="wp-block-heading">Test the new model</h3>



<p>Once you have pushed your model in Hugging Face you can, again, deploy it with vLLM and AI Deploy to test it ⚡️.</p>



<figure class="wp-block-image aligncenter size-large"><img decoding="async" width="1024" height="474" src="https://blog.ovhcloud.com/wp-content/uploads/2025/07/Screenshot-2025-07-23-at-14.58.02-1024x474.png" alt="" class="wp-image-29459" srcset="https://blog.ovhcloud.com/wp-content/uploads/2025/07/Screenshot-2025-07-23-at-14.58.02-1024x474.png 1024w, https://blog.ovhcloud.com/wp-content/uploads/2025/07/Screenshot-2025-07-23-at-14.58.02-300x139.png 300w, https://blog.ovhcloud.com/wp-content/uploads/2025/07/Screenshot-2025-07-23-at-14.58.02-768x356.png 768w, https://blog.ovhcloud.com/wp-content/uploads/2025/07/Screenshot-2025-07-23-at-14.58.02-1536x712.png 1536w, https://blog.ovhcloud.com/wp-content/uploads/2025/07/Screenshot-2025-07-23-at-14.58.02-2048x949.png 2048w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>Ta-da! 🥳 Our little Llama model is now an OVHcloud AI Endpoints pro!</p>



<p></p>



<p>Feel free to try out OVHcloud Machine Learning products, and share your thoughts on our Discord server (<em><a href="https://discord.gg/ovhcloud" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer">https://discord.gg/ovhcloud</a></em>), see you soon! 👋</p>
<img loading="lazy" decoding="async" src="//blog.ovhcloud.com/wp-content/plugins/matomo/app/matomo.php?idsite=1&amp;rec=1&amp;url=https%3A%2F%2Fblog.ovhcloud.com%2Ffine-tune-an-llm-with-axolotl-and-ovhcloud-machine-learning-services%2F&amp;action_name=Fine%20tune%20an%20LLM%20with%20Axolotl%20and%20OVHcloud%20Machine%20Learning%20Services&amp;urlref=https%3A%2F%2Fblog.ovhcloud.com%2Ffeed%2F" style="border:0;width:0;height:0" width="0" height="0" alt="" />]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Deploy a custom Docker image for Data Science project – A spam classifier with FastAPI (Part 3)</title>
		<link>https://blog.ovhcloud.com/deploy-a-custom-docker-image-for-data-science-project-a-spam-classifier-with-fastapi-part-3/</link>
		
		<dc:creator><![CDATA[Eléa Petton]]></dc:creator>
		<pubDate>Fri, 30 Dec 2022 10:39:54 +0000</pubDate>
				<category><![CDATA[OVHcloud Engineering]]></category>
		<category><![CDATA[AI]]></category>
		<category><![CDATA[AI Deploy]]></category>
		<category><![CDATA[AI Notebook]]></category>
		<category><![CDATA[AI Solutions]]></category>
		<category><![CDATA[Artificial Intelligence]]></category>
		<category><![CDATA[Docker]]></category>
		<category><![CDATA[Machine learning]]></category>
		<category><![CDATA[OVHcloud]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[Scikit Learn]]></category>
		<category><![CDATA[spam classification]]></category>
		<guid isPermaLink="false">https://blog.ovhcloud.com/?p=24202</guid>

					<description><![CDATA[A guide to deploy a custom Docker image for an API with FastAPI and AI Deploy. Welcome to the third article concerning custom Docker image deployment. If you haven&#8217;t read the previous ones, you can check it: &#8211; Gradio sketch recognition app&#8211; Streamlit app for EDA and interactive prediction When creating code for a Data [&#8230;]<img src="//blog.ovhcloud.com/wp-content/plugins/matomo/app/matomo.php?idsite=1&amp;rec=1&amp;url=https%3A%2F%2Fblog.ovhcloud.com%2Fdeploy-a-custom-docker-image-for-data-science-project-a-spam-classifier-with-fastapi-part-3%2F&amp;action_name=Deploy%20a%20custom%20Docker%20image%20for%20Data%20Science%20project%20%E2%80%93%20A%20spam%20classifier%20with%20FastAPI%20%28Part%203%29&amp;urlref=https%3A%2F%2Fblog.ovhcloud.com%2Ffeed%2F" style="border:0;width:0;height:0" width="0" height="0" alt="" />]]></description>
										<content:encoded><![CDATA[
<p><em>A guide to deploy a custom Docker image for an API with <a href="https://fastapi.tiangolo.com/" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer">FastAPI</a> and <strong>AI Deploy</strong>.</em></p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="815" src="https://blog.ovhcloud.com/wp-content/uploads/2022/12/draw-spam-classifier-1024x815.jpg" alt="fastapi for spam classification" class="wp-image-24226" srcset="https://blog.ovhcloud.com/wp-content/uploads/2022/12/draw-spam-classifier-1024x815.jpg 1024w, https://blog.ovhcloud.com/wp-content/uploads/2022/12/draw-spam-classifier-300x239.jpg 300w, https://blog.ovhcloud.com/wp-content/uploads/2022/12/draw-spam-classifier-768x612.jpg 768w, https://blog.ovhcloud.com/wp-content/uploads/2022/12/draw-spam-classifier-1536x1223.jpg 1536w, https://blog.ovhcloud.com/wp-content/uploads/2022/12/draw-spam-classifier.jpg 1620w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p><em>Welcome to the third article concerning <strong>custom Docker image deployment</strong>. If you haven&#8217;t read the previous ones, you can check it:</em></p>



<p><em>&#8211; </em><a href="https://blog.ovhcloud.com/deploy-a-custom-docker-image-for-data-science-project-gradio-sketch-recognition-app-part-1/" data-wpel-link="internal">Gradio sketch recognition app</a><br><em>&#8211; </em><a href="https://docs.ovh.com/fr/publiccloud/ai/deploy/tuto-streamlit-eda-iris/" data-wpel-link="exclude">Streamlit app for EDA and interactive prediction</a></p>



<p>When creating code for a <strong>Data Science project</strong>, you probably want it to be as portable as possible. In other words, it can be run as many times as you like, even on different machines.</p>



<p>Unfortunately, it is often the case that a Data Science code works fine locally on a machine but gives errors during runtime. It can be due to different versions of libraries installed on the host machine.</p>



<p>To deal with this problem, you can use <a href="https://www.docker.com/" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer">Docker</a>.</p>



<p><strong>The article is organized as follows:</strong></p>



<ul class="wp-block-list">
<li>Objectives</li>



<li>Concepts</li>



<li>Define a model for spam classification</li>



<li>Build the FastAPI app with Python</li>



<li>Containerize your app with Docker</li>



<li>Launch the app with AI Deploy</li>
</ul>



<p><em>All the code for this blogpost is available in our dedicated <a href="https://github.com/ovh/ai-training-examples/tree/main/apps/fastapi/spam-classifier-api" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer">GitHub repository</a>. You can test it with OVHcloud <strong>AI Deploy</strong> tool, please refer to the <a href="https://docs.ovh.com/gb/en/publiccloud/ai/deploy/tuto-fastapi-spam-classifier/" data-wpel-link="exclude">documentation</a> to boot it up.</em></p>



<h2 class="wp-block-heading">Objectives</h2>



<p>In this article, you will learn how to develop <strong>FastAPI</strong> API for spam classification.</p>



<p>Once your app is up and running locally, it will be a matter of containerizing it, then deploying the custom Docker image with AI Deploy.</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="2160" height="1215" src="https://blog.ovhcloud.com/wp-content/uploads/2022/12/draw-objective-edited.jpg" alt="objective of api deployment" class="wp-image-24228" srcset="https://blog.ovhcloud.com/wp-content/uploads/2022/12/draw-objective-edited.jpg 2160w, https://blog.ovhcloud.com/wp-content/uploads/2022/12/draw-objective-edited-300x169.jpg 300w, https://blog.ovhcloud.com/wp-content/uploads/2022/12/draw-objective-edited-1024x576.jpg 1024w, https://blog.ovhcloud.com/wp-content/uploads/2022/12/draw-objective-edited-768x432.jpg 768w, https://blog.ovhcloud.com/wp-content/uploads/2022/12/draw-objective-edited-1536x864.jpg 1536w, https://blog.ovhcloud.com/wp-content/uploads/2022/12/draw-objective-edited-2048x1152.jpg 2048w" sizes="auto, (max-width: 2160px) 100vw, 2160px" /></figure>



<h2 class="wp-block-heading">Concepts</h2>



<p>In Artificial Intelligence, you have probably heard of <strong>Natural Language Processing</strong> (NLP). <strong>NLP</strong> gathers several tasks related to language processing such as <strong>text classification</strong>.</p>



<p>This technique is ideal for distinguishing spam from other messages.</p>



<h3 class="wp-block-heading">Spam Ham Collection&nbsp;Dataset</h3>



<p>The <a href="https://archive.ics.uci.edu/ml/datasets/sms+spam+collection" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer">SMS Spam Collection</a> is a public set of SMS labeled messages that have been collected for mobile phone spam research.</p>



<p>The dataset contains <strong>5,574 messages</strong> in English. The SMS are tagged as follow:</p>



<ul class="wp-block-list">
<li><strong>HAM</strong> if the message is legitimate</li>



<li><strong>SPAM</strong> if it is not</li>
</ul>



<p>The collection is a <strong>text file</strong>, where each line has the correct <strong>class</strong> followed by the raw <strong>message</strong>.</p>



<figure class="wp-block-image aligncenter size-large is-resized"><img loading="lazy" decoding="async" src="https://blog.ovhcloud.com/wp-content/uploads/2022/12/image-5-1024x576.png" alt="spam ham dataset" class="wp-image-24219" width="773" height="435" srcset="https://blog.ovhcloud.com/wp-content/uploads/2022/12/image-5-1024x576.png 1024w, https://blog.ovhcloud.com/wp-content/uploads/2022/12/image-5-300x169.png 300w, https://blog.ovhcloud.com/wp-content/uploads/2022/12/image-5-768x432.png 768w, https://blog.ovhcloud.com/wp-content/uploads/2022/12/image-5-1536x864.png 1536w, https://blog.ovhcloud.com/wp-content/uploads/2022/12/image-5.png 1920w" sizes="auto, (max-width: 773px) 100vw, 773px" /></figure>



<h3 class="wp-block-heading">Logistic regression</h3>



<p><strong>What is a Logistic Regression?</strong></p>



<p><a href="https://fr.wikipedia.org/wiki/R%C3%A9gression_logistique" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer">Logistic regression</a> is a statistical model. It allows to study the relationships between a set of <code>i</code> <strong>qualitative variables</strong> (<code>Xi</code>) and a <strong>qualitative variable</strong> (<code>Y</code>).</p>



<figure class="wp-block-image aligncenter size-large is-resized"><img loading="lazy" decoding="async" src="https://blog.ovhcloud.com/wp-content/uploads/2022/12/draw-logistic-regression-1024x779.jpg" alt="logistic regression" class="wp-image-24229" width="467" height="355" srcset="https://blog.ovhcloud.com/wp-content/uploads/2022/12/draw-logistic-regression-1024x779.jpg 1024w, https://blog.ovhcloud.com/wp-content/uploads/2022/12/draw-logistic-regression-300x228.jpg 300w, https://blog.ovhcloud.com/wp-content/uploads/2022/12/draw-logistic-regression-768x584.jpg 768w, https://blog.ovhcloud.com/wp-content/uploads/2022/12/draw-logistic-regression-1536x1168.jpg 1536w, https://blog.ovhcloud.com/wp-content/uploads/2022/12/draw-logistic-regression.jpg 1620w" sizes="auto, (max-width: 467px) 100vw, 467px" /></figure>



<p>It is a generalized linear model using a logistic function as a link function.</p>



<p>A logistic regression model can also predict the <strong>probability</strong> of an event occurring (value close to <code><strong>1</strong></code>) or not (value close to <strong><code>0</code></strong>) from the optimization of the <strong>regression coefficients</strong>. This result always varies between <strong><code>0</code></strong> and <strong><code>1</code></strong>.</p>



<p>For the spam classification use case, <strong>words</strong> are inputs and <strong>class</strong> (spam or ham) is output.</p>



<h3 class="wp-block-heading">FastAPI</h3>



<p><strong>What is FastAPI?</strong></p>



<p><a href="https://fastapi.tiangolo.com/" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer">FastAPI</a> is a web framework for building <strong>RESTful APIs</strong> with Python.</p>



<p>FastAPI is based on <a href="https://docs.pydantic.dev/" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer">Pydantic</a> and type guidance to <em>validate</em>, <em>serialize</em> and <em>deserialize</em> data, and automatically generate OpenAPI documents.</p>



<h3 class="wp-block-heading">Docker</h3>



<p><a href="https://www.docker.com/" target="_blank" rel="noreferrer noopener nofollow external" data-wpel-link="external">Docker</a>&nbsp;platform allows you to build, run and manage isolated applications. The principle is to build an application that contains not only the written code but also all the context to run the code: libraries and their versions for example</p>



<p>When you wrap your application with all its context, you build a Docker image, which can be saved in your local repository or in the Docker Hub.</p>



<p>To get started with Docker, please, check this&nbsp;<a href="https://www.docker.com/get-started" target="_blank" rel="noreferrer noopener nofollow external" data-wpel-link="external">documentation</a>.</p>



<p>To build a Docker image, you will define 2 elements:</p>



<ul class="wp-block-list">
<li>the application code (<em>FastAPI app</em>)</li>



<li>the&nbsp;<a href="https://docs.docker.com/engine/reference/builder/" target="_blank" rel="noreferrer noopener nofollow external" data-wpel-link="external">Dockerfile</a></li>
</ul>



<p>In the next steps, you will see how to develop the Python code for your app, but also how to write the Dockerfile.</p>



<p>Finally, you will see how to deploy your custom docker image with&nbsp;<strong>OVHcloud AI Deploy</strong>&nbsp;tool.</p>



<h3 class="wp-block-heading">AI Deploy</h3>



<p><strong>AI Deploy</strong>&nbsp;enables AI models and managed applications to be started via Docker containers.</p>



<p>To know more about AI Deploy, please refer to this&nbsp;<a href="https://docs.ovh.com/gb/en/publiccloud/ai/deploy/getting-started/" data-wpel-link="exclude">documentation</a>.</p>



<h2 class="wp-block-heading">Define a model for spam classification</h2>



<p>❗ <strong><code>To develop an API that uses a Machine Learning model, you have to load the model in the correct format. For this tutorial, a Logistic Regression is used and the Python file model.py is used to define it</code></strong>.<br><br><code><strong>To better understand the model.py code, refer to the <a href="https://github.com/ovh/ai-training-examples/blob/main/notebooks/natural-language-processing/text-classification/miniconda/spam-classifier/notebook-spam-classifier.ipynb" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer">notebook</a> which details all the steps</strong></code>.</p>



<p>First of all, you have to import the&nbsp;<strong>Python libraries</strong>&nbsp;needed to create the Logistic Regression in the <code>model.py</code> file.</p>



<pre class="wp-block-code"><code class="">import pandas as pd
import numpy as np
from sklearn import model_selection
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.linear_model import LogisticRegression</code></pre>



<p>Now, you can create the Logistic Regression based on the <strong>Spam Ham Collection&nbsp;Dataset</strong>. The Python framework named <strong>Scikit-Learn</strong> is used to define this model.</p>



<p>Firstly, you can load the dataset and transform your input file into a <code>dataframe</code>.</p>



<p>You will also be able to define the <code>input</code> and the <code>output</code> of the model.</p>



<pre class="wp-block-code"><code class="">def load_data():

    PATH = 'SMSSpamCollection'
    df = pd.read_csv(PATH, delimiter = "\t", names=["classe", "message"])

    X = df['message']
    y = df['classe']

    return X, y</code></pre>



<p>In a second step, you split the data in a training and a test set.</p>



<p>To <strong>separate the dataset fairly</strong> and to have a <code>test_size</code> between 0 and 1, you can calculate <code>ntest</code> as follows.</p>



<pre class="wp-block-code"><code class="">def split_data(X, y):

    ntest = 2000/(3572+2000)

    X_train, X_test, y_train, y_test = model_selection.train_test_split(X, y, test_size=ntest, random_state=0)

    return X_train, y_train</code></pre>



<p>Now you can concentrate on creating the <strong>Machine Learning model</strong>. To do this, create a <code>spam_classifier_model</code> function.</p>



<p>To fully understand the code, refer to <strong>Steps 6 to 9</strong> of this <a href="https://github.com/ovh/ai-training-examples/blob/main/notebooks/natural-language-processing/text-classification/miniconda/spam-classifier/notebook-spam-classifier.ipynb" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer">notebook</a>. In these steps you will learn how to:</p>



<ul class="wp-block-list">
<li>create the model using <strong>Logistic Regression</strong></li>



<li>evaluate on the test set</li>



<li>do <strong>dimension reduction</strong> with stop words and term frequency</li>



<li>do <strong>dimension reduction</strong> to post-processing of the model</li>
</ul>



<pre class="wp-block-code"><code class="">def spam_classifier_model(Xtrain, ytrain):

    model_logistic_regression = LogisticRegression()
    model_logistic_regression = model_logistic_regression.fit(Xtrain, ytrain)

    coeff = model_logistic_regression.coef_
    coef_abs = np.abs(coeff)

    quantiles = np.quantile(coef_abs,[0, 0.25, 0.5, 0.75, 0.9, 1])

    index = np.where(coeff[0] &gt; quantiles[1])
    newXtrain = Xtrain[:, index[0]]

    model_logistic_regression = LogisticRegression()
    model_logistic_regression.fit(newXtrain, ytrain)

    return model_logistic_regression, index</code></pre>



<p>Once these Python functions are defined, you can call and apply them as follows.</p>



<p>Firstly, extract input and output data with <code>load_data()</code>:</p>



<pre class="wp-block-code"><code class="">data_input, data_output = load_data()</code></pre>



<p>Secondly, split the data using the <code>split_data(data_input, data_output)</code>:</p>



<pre class="wp-block-code"><code class="">X_train, ytrain = split_data(data_input, data_output)</code></pre>



<p>❗ <code><strong>Here, there is no need to use the test set. Indeed, the evaluation of the final model has already been done in <em>Step 9 - Dimensionality reduction: post processing of the model</em> of the <a href="https://github.com/ovh/ai-training-examples/blob/main/notebooks/natural-language-processing/text-classification/miniconda/spam-classifier/notebook-spam-classifier.ipynb" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer">notebook</a>.</strong></code></p>



<p>Thirdly, <strong>transform</strong> and <strong>fit</strong> training set. In order to<strong> </strong>prepare<strong> </strong>the data, you can use <code>CountVectorizer</code> from Scikit-Learn to remove <strong>stop-words</strong> and then <code>fit_transform</code> to fit the inputs.</p>



<pre class="wp-block-code"><code class="">vectorizer = CountVectorizer(stop_words='english', binary=True, min_df=10)
Xtrain = vectorizer.fit_transform(X_train.tolist())
Xtrain = Xtrain.toarray()</code></pre>



<p>Fourthly, use the model and index for prediction by calling <code>spam_classifier_model</code> function.</p>



<pre class="wp-block-code"><code class="">model_logistic_regression, index = spam_classifier_model(Xtrain, ytrain)</code></pre>



<p>Find out the full Python code <a href="https://github.com/ovh/ai-training-examples/blob/main/apps/fastapi/spam-classifier-api/model.py" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer">here</a>.</p>



<p>Have you successfully defined your model? Good job 🥳 !</p>



<p>Let&#8217;s go for the creation of the API!</p>



<h2 class="wp-block-heading">Build the FastAPI app with Python</h2>



<p>❗ <code><strong>All the codes below are available in the <em>app.py</em> file. You can find the complete Python code of the <em>app.py</em> file <a href="https://github.com/ovh/ai-training-examples/blob/main/apps/fastapi/spam-classifier-api/app.py" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer">here</a>.</strong></code></p>



<p>To begin, you can import dependencies for FastAPI app.</p>



<ul class="wp-block-list">
<li>uvicorn</li>



<li>fastapi</li>



<li>pydantic</li>
</ul>



<pre class="wp-block-code"><code class="">import uvicorn
from fastapi import FastAPI
from pydantic import BaseModel
from model import model_logistic_regression, index, vectorizer</code></pre>



<p>In the first place, you can initialize an instance of FastAPI.</p>



<pre class="wp-block-code"><code class="">app = FastAPI()</code></pre>



<p>Next, you can define the data format by creating the Python class named <code>request_body</code>. Here, the <strong>string</strong> (<code>str</code>) format is required.</p>



<pre class="wp-block-code"><code class="">class request_body(BaseModel):
    message : str</code></pre>



<p>Now, you can create the process function in order to prepare the sent message to be used by the model.</p>



<pre class="wp-block-code"><code class="">def process_message(message):

    desc = vectorizer.transform(message)
    dense_desc = desc.toarray()
    dense_select = dense_desc[:, index[0]]

    return dense_select</code></pre>



<p>At the exit of this function the message does not contain any more <strong>stop words</strong>, it is put in the right format for the model thanks to the <code>transform</code> and is then represented as an <code>array</code>.</p>



<p>Now that the function for processing the input data is defined, you can pass the <code>GET</code> and <code>POST</code> methods.</p>



<p>First, let&#8217;s go for the <code>GET</code> method!</p>



<pre class="wp-block-code"><code class="">@app.get('/')
def root():
    return {'message': 'Welcome to the SPAM classifier API'}</code></pre>



<p>Here you can see the <em>welcome message</em> when you arrive on your API.</p>



<pre class="wp-block-preformatted"><code><strong>{"message":"Welcome to the SPAM classifier API"}</strong></code></pre>



<p>Now it&#8217;s the turn of the <code>POST</code> method. In this part of the code, you will be able to:</p>



<ul class="wp-block-list">
<li>define the message format</li>



<li>check if a message has been sent or not</li>



<li>process the message to fit with the model</li>



<li>extract the probabilities</li>



<li>return the results</li>
</ul>



<pre class="wp-block-code"><code class="">@app.post('/spam_detection_path')
def classify_message(data : request_body):

    message = [
        data.message
    ]

    if (not (message)):
        raise HTTPException(status_code=400, detail="Please Provide a valid text message")

    dense_select = process_message(message)

    label = model_logistic_regression.predict(dense_select)
    proba = model_logistic_regression.predict_proba(dense_select)

    if label[0]=='ham':
        label_proba = proba[0][0]
    else:
        label_proba = proba[0][1]

    return {'label': label[0], 'label_probability': label_proba}</code></pre>



<p><code><strong>❗ Again, you can find the full code <a href="https://github.com/ovh/ai-training-examples/blob/main/apps/fastapi/spam-classifier-api/app.py" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer">here</a></strong></code>.</p>



<p>Before deploying your API, you can test it locally using the following command:</p>



<pre class="wp-block-code"><code class="">uvicorn app:app --reload</code></pre>



<p>Then, you can test your app locally at the following address:&nbsp;<strong><code>http://localhost:8000/</code></strong></p>



<p>You will arrive on the following page:</p>



<figure class="wp-block-image aligncenter size-full is-resized"><img loading="lazy" decoding="async" src="https://blog.ovhcloud.com/wp-content/uploads/2022/12/image-4.png" alt="" class="wp-image-24217" width="590" height="721" srcset="https://blog.ovhcloud.com/wp-content/uploads/2022/12/image-4.png 760w, https://blog.ovhcloud.com/wp-content/uploads/2022/12/image-4-245x300.png 245w" sizes="auto, (max-width: 590px) 100vw, 590px" /></figure>



<p><strong>How to interact with your&nbsp;API?</strong></p>



<p>You can add&nbsp;<code>/docs</code>&nbsp;at the end of the url of your&nbsp;app: <strong><code>http://localhost:8000/</code></strong><code><strong>docs</strong></code></p>



<p>A new page opens to you. It provides a complete dashboard for interacting with the&nbsp;API!</p>



<figure class="wp-block-image aligncenter size-full is-resized"><img loading="lazy" decoding="async" src="https://blog.ovhcloud.com/wp-content/uploads/2022/12/image.png" alt="" class="wp-image-24213" width="590" height="722" srcset="https://blog.ovhcloud.com/wp-content/uploads/2022/12/image.png 760w, https://blog.ovhcloud.com/wp-content/uploads/2022/12/image-245x300.png 245w" sizes="auto, (max-width: 590px) 100vw, 590px" /></figure>



<p>To be able to send a message for classification, select&nbsp;<code><strong>/spam_detection_path</strong></code>&nbsp;in the green box. Click on<strong>&nbsp;<code>Try</code></strong><code><strong> it out</strong></code>&nbsp;and type the message of your choice in the dedicated&nbsp;zone.</p>



<figure class="wp-block-image aligncenter size-full is-resized"><img loading="lazy" decoding="async" src="https://blog.ovhcloud.com/wp-content/uploads/2022/12/image-2.png" alt="" class="wp-image-24215" width="596" height="729" srcset="https://blog.ovhcloud.com/wp-content/uploads/2022/12/image-2.png 760w, https://blog.ovhcloud.com/wp-content/uploads/2022/12/image-2-245x300.png 245w" sizes="auto, (max-width: 596px) 100vw, 596px" /></figure>



<p>Enter the message of your choice. It must be in the form of a <code><strong>string</strong></code>. </p>



<p><em>Example:</em> <code><strong>"A new free service for you only"</strong></code></p>



<figure class="wp-block-image aligncenter size-full is-resized"><img loading="lazy" decoding="async" src="https://blog.ovhcloud.com/wp-content/uploads/2022/12/image-1.png" alt="" class="wp-image-24214" width="599" height="733" srcset="https://blog.ovhcloud.com/wp-content/uploads/2022/12/image-1.png 760w, https://blog.ovhcloud.com/wp-content/uploads/2022/12/image-1-245x300.png 245w" sizes="auto, (max-width: 599px) 100vw, 599px" /></figure>



<p>To get the result of the prediction, click on the&nbsp;<code><strong>Execute</strong></code>&nbsp;button.</p>



<figure class="wp-block-image aligncenter size-full is-resized"><img loading="lazy" decoding="async" src="https://blog.ovhcloud.com/wp-content/uploads/2022/12/image-3.png" alt="" class="wp-image-24216" width="611" height="748" srcset="https://blog.ovhcloud.com/wp-content/uploads/2022/12/image-3.png 760w, https://blog.ovhcloud.com/wp-content/uploads/2022/12/image-3-245x300.png 245w" sizes="auto, (max-width: 611px) 100vw, 611px" /></figure>



<p>Finally, you obtain the result of the prediction with the&nbsp;<strong>label</strong>&nbsp;and the&nbsp;<strong>confidence&nbsp;score</strong>.</p>



<p>Your app works locally? Congratulations&nbsp;🎉 !</p>



<p>Now it’s time to move on to containerization!</p>



<h2 class="wp-block-heading">Containerize your app with Docker</h2>



<p>First of all, you have to build the file that will contain the different Python modules to be installed with their corresponding version.</p>



<figure class="wp-block-image aligncenter size-large"><img loading="lazy" decoding="async" width="1024" height="574" src="https://blog.ovhcloud.com/wp-content/uploads/2022/12/draw-docker-1024x574.jpg" alt="docker image datascience" class="wp-image-24230" srcset="https://blog.ovhcloud.com/wp-content/uploads/2022/12/draw-docker-1024x574.jpg 1024w, https://blog.ovhcloud.com/wp-content/uploads/2022/12/draw-docker-300x168.jpg 300w, https://blog.ovhcloud.com/wp-content/uploads/2022/12/draw-docker-768x430.jpg 768w, https://blog.ovhcloud.com/wp-content/uploads/2022/12/draw-docker-1536x861.jpg 1536w, https://blog.ovhcloud.com/wp-content/uploads/2022/12/draw-docker.jpg 1620w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<h3 class="wp-block-heading">Create the requirements.txt file</h3>



<p>The&nbsp;<code><a href="https://github.com/ovh/ai-training-examples/blob/main/apps/fastapi/spam-classifier-api/requirements.txt" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer">requirements.txt</a></code>&nbsp;file will allow us to write all the modules needed to make our application work.</p>



<pre class="wp-block-code"><code class="">fastapi==0.87.0
pydantic==1.10.2
uvicorn==0.20.0
pandas==1.5.1
scikit-learn==1.1.3</code></pre>



<p>This file will be useful when writing the&nbsp;<code>Dockerfile</code>.</p>



<h3 class="wp-block-heading">Write the Dockerfile</h3>



<p>Your&nbsp;<code><a href="https://github.com/ovh/ai-training-examples/blob/main/apps/fastapi/spam-classifier-api/Dockerfile" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer">Dockerfile</a></code>&nbsp;should start with the the&nbsp;<code>FROM</code>&nbsp;instruction indicating the parent image to use. In our case we choose to start from a classic Python image.</p>



<p>For this Streamlit app, you can use version&nbsp;<strong><code>3.8</code></strong>&nbsp;of Python.</p>



<pre class="wp-block-code"><code class="">FROM python:3.8</code></pre>



<p>Next, you have to to fill in the working directory and add all&nbsp;files into.</p>



<p><code><strong>❗&nbsp;Here you must be in the /workspace directory. This is the basic directory for launching an OVHcloud AI Deploy.</strong></code></p>



<pre class="wp-block-code"><code class="">WORKDIR /workspace
ADD . /workspace</code></pre>



<p>Install the&nbsp;<code>requirements.txt</code>&nbsp;file which contains your needed Python modules using a&nbsp;<code>pip install…</code>&nbsp;command.</p>



<pre class="wp-block-code"><code class="">RUN pip install -r requirements.txt</code></pre>



<p>Set the listening port of the&nbsp;container. For <strong>FastAPI</strong>, you can use the port <code>8000</code>.</p>



<pre class="wp-block-code"><code class="">EXPOSE 8000</code></pre>



<p>Then, you have to define the <strong>entrypoint</strong> and the <strong>default launching command</strong> to start the application.</p>



<pre class="wp-block-code"><code class="">ENTRYPOINT ["uvicorn"]
CMD [ "streamlit", "run", "/workspace/app.py", "--server.address=0.0.0.0" ]</code></pre>



<p>Finally, you can give correct access rights to OVHcloud user (<code>42420:42420</code>).</p>



<pre class="wp-block-code"><code class="">RUN chown -R 42420:42420 /workspace
ENV HOME=/workspace</code></pre>



<p>Once your&nbsp;<code>Dockerfile</code>&nbsp;is defined, you will be able to build your custom docker image.</p>



<h3 class="wp-block-heading">Build the Docker image from the Dockerfile</h3>



<p>First, you can launch the following command from the&nbsp;<code>Dockerfile</code>&nbsp;directory to build your application image.</p>



<pre class="wp-block-code"><code class="">docker build . -t fastapi-spam-classification:latest</code></pre>



<p>⚠️&nbsp;<strong><code>The dot . argument indicates that your build context (place of the Dockerfile and other needed files) is the current directory.</code></strong></p>



<p>⚠️&nbsp;<code><strong>The -t argument allows you to choose the identifier to give to your image. Usually image identifiers are composed of a name and a version tag &lt;name&gt;:&lt;version&gt;. For this example we chose fastapi-spam-classification:latest.</strong></code></p>



<h3 class="wp-block-heading">Test it locally</h3>



<p>Now, you can run the following&nbsp;<strong>Docker command</strong>&nbsp;to launch your application locally on your computer.</p>



<pre class="wp-block-code"><code class="">docker run --rm -it -p 8080:8080 --user=42420:42420 fastapi-spam-classification<span style="background-color: inherit;font-family: inherit;font-size: 1rem;font-weight: inherit">:latest</span></code></pre>



<p>⚠️&nbsp;<code><strong>The -p 8000:8000 argument indicates that you want to execute a port redirection from the port 8000 of your local machine into the port 8000 of the Docker container.</strong></code></p>



<p>⚠️<code><strong>&nbsp;Don't forget the --user=42420:42420 argument if you want to simulate the exact same behaviour that will occur on AI Deploy. It executes the Docker container as the specific OVHcloud user (user 42420:42420).</strong></code></p>



<p>Once started, your application should be available on&nbsp;<strong>http://localhost:8000</strong>.<br><br>Your Docker image seems to work? Good job&nbsp;👍 !<br><br>It’s time to push it and deploy it!</p>



<h3 class="wp-block-heading">Push the image into the shared registry</h3>



<p>❗&nbsp;The shared registry of AI Deploy should only be used for testing purpose. Please consider attaching your own Docker registry. More information about this can be found&nbsp;<a href="https://docs.ovh.com/asia/en/publiccloud/ai/training/add-private-registry/" data-wpel-link="exclude">here</a>.</p>



<p>Then, you have to find the address of your&nbsp;<code>shared registry</code>&nbsp;by launching this command.</p>



<pre class="wp-block-code"><code class="">ovhai registry list</code></pre>



<p>Next, log in on the shared registry with your usual&nbsp;<code>OpenStack</code>&nbsp;credentials.</p>



<pre class="wp-block-code"><code class="">docker login -u &lt;user&gt; -p &lt;password&gt; &lt;shared-registry-address&gt;</code></pre>



<p>To finish, you need to push the created image into the shared registry.</p>



<pre class="wp-block-code"><code class="">docker tag fastapi-spam-classification:latest &lt;shared-registry-address&gt;/fastapi-spam-classification:latest</code></pre>



<pre class="wp-block-code"><code class="">docker push &lt;shared-registry-address&gt;/fastapi-spam-classification:latest</code></pre>



<p>Once you have pushed your custom Docker image into the shared registry, you are ready to launch your app 🚀 !</p>



<h2 class="wp-block-heading">Launch the AI Deploy app</h2>



<p>The following command starts a new job running your <strong>FastAPI</strong> application.</p>



<pre class="wp-block-code"><code class="">ovhai app run \
      --default-http-port 8000 \
      --cpu 4 \
      &lt;shared-registry-address&gt;/fastapi-spam-classification:latest</code></pre>



<h3 class="wp-block-heading">Choose the compute resources</h3>



<p>First, you can either choose the number of GPUs or CPUs for your app.</p>



<p><code><strong>--cpu 4</strong></code>&nbsp;indicates that we request 4 CPUs for that app.</p>



<h3 class="wp-block-heading">Make the app public</h3>



<p>Finally, if you want your app to be accessible without the need to authenticate, specify it as follows.</p>



<p>Consider adding the&nbsp;<code><strong>--unsecure-http</strong></code>&nbsp;attribute if you want your application to be reachable without any authentication.</p>



<figure class="wp-block-video"></figure>



<h2 class="wp-block-heading">Conclusion</h2>



<p>Well done 🎉&nbsp;! You have learned how to build your&nbsp;<strong>own Docker image</strong>&nbsp;for a dedicated&nbsp;<strong>spam classification API</strong>!</p>



<p>You have also been able to deploy this app thanks to&nbsp;<strong>OVHcloud’s AI Deploy</strong>&nbsp;tool.</p>



<h3 class="wp-block-heading" id="want-to-find-out-more">Want to find out more?</h3>



<h5 class="wp-block-heading"><strong>Notebook</strong></h5>



<p>You want to access the notebook? Refer to the&nbsp;<a href="https://github.com/ovh/ai-training-examples/blob/main/notebooks/natural-language-processing/text-classification/miniconda/spam-classifier/notebook-spam-classifier.ipynb" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer">GitHub repository</a>.</p>



<h5 class="wp-block-heading"><strong>App</strong></h5>



<p>You want to access to the full code to create the <strong>FastAPI</strong> API? Refer to the&nbsp;<a href="https://github.com/ovh/ai-training-examples/tree/main/apps/fastapi/spam-classifier-api" target="_blank" rel="noreferrer noopener nofollow external" data-wpel-link="external">GitHub repository</a>.<br><br>To launch and test this app with&nbsp;<strong>AI Deploy</strong>, please refer to&nbsp;our&nbsp;<a href="https://docs.ovh.com/gb/en/publiccloud/ai/deploy/tuto-fastapi-spam-classifier/" data-wpel-link="exclude">documentation</a>.</p>



<h2 class="wp-block-heading">References</h2>



<ul class="wp-block-list">
<li><a href="https://towardsdatascience.com/how-to-run-a-data-science-project-in-a-docker-container-2ab1a3baa889" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer">How to Run a Data Science Project in a Docker Container</a></li>



<li><a href="https://towardsdatascience.com/step-by-step-approach-to-build-your-machine-learning-api-using-fast-api-21bd32f2bbdb" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer">Step-by-step Approach to Build Your Machine Learning API Using Fast API</a></li>
</ul>
<img loading="lazy" decoding="async" src="//blog.ovhcloud.com/wp-content/plugins/matomo/app/matomo.php?idsite=1&amp;rec=1&amp;url=https%3A%2F%2Fblog.ovhcloud.com%2Fdeploy-a-custom-docker-image-for-data-science-project-a-spam-classifier-with-fastapi-part-3%2F&amp;action_name=Deploy%20a%20custom%20Docker%20image%20for%20Data%20Science%20project%20%E2%80%93%20A%20spam%20classifier%20with%20FastAPI%20%28Part%203%29&amp;urlref=https%3A%2F%2Fblog.ovhcloud.com%2Ffeed%2F" style="border:0;width:0;height:0" width="0" height="0" alt="" />]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Object detection: train YOLOv5 on a custom dataset</title>
		<link>https://blog.ovhcloud.com/object-detection-train-yolov5-on-a-custom-dataset/</link>
		
		<dc:creator><![CDATA[Eléa Petton]]></dc:creator>
		<pubDate>Thu, 17 Mar 2022 15:21:22 +0000</pubDate>
				<category><![CDATA[OVHcloud Engineering]]></category>
		<category><![CDATA[AI]]></category>
		<category><![CDATA[AI Notebook]]></category>
		<category><![CDATA[AI Solutions]]></category>
		<guid isPermaLink="false">https://blog.ovhcloud.com/?p=21622</guid>

					<description><![CDATA[A guide to train a YOLO object detection algorithm on your dataset. It&#8217;s based on the YOLOv5 open source repository by&#160;Ultralytics. All the code for this blogpost is available in our dedicated GitHub repository. And you can test it in our AI Training, please refer to our documentation to boot it up. Introduction Computer Vision [&#8230;]<img src="//blog.ovhcloud.com/wp-content/plugins/matomo/app/matomo.php?idsite=1&amp;rec=1&amp;url=https%3A%2F%2Fblog.ovhcloud.com%2Fobject-detection-train-yolov5-on-a-custom-dataset%2F&amp;action_name=Object%20detection%3A%20train%20YOLOv5%20on%20a%20custom%20dataset&amp;urlref=https%3A%2F%2Fblog.ovhcloud.com%2Ffeed%2F" style="border:0;width:0;height:0" width="0" height="0" alt="" />]]></description>
										<content:encoded><![CDATA[
<p><em>A guide to train a <strong>YOLO object detection algorithm</strong>  on your dataset.</em> It&#8217;s based on the YOLOv5 open source repository by&nbsp;<a href="https://github.com/ultralytics/yolov5" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer">Ultralytics</a>.</p>



<p>All the code for this blogpost is available in our dedicated <a href="https://github.com/ovh/ai-training-examples" target="_blank" rel="noreferrer noopener nofollow external" data-wpel-link="external">GitHub repository</a>. And you can test it in our <strong>AI Training</strong>, please refer to <a href="https://docs.ovh.com/us/en/publiccloud/ai/" target="_blank" rel="noreferrer noopener" data-wpel-link="exclude">our documentation</a> to boot it up.</p>



<div class="wp-block-image"><figure class="aligncenter size-large is-resized"><img loading="lazy" decoding="async" src="https://blog.ovhcloud.com/wp-content/uploads/2022/03/IMG_0880-1024x537.jpeg" alt="Object detection: train YOLOv5 on a custom dataset" class="wp-image-22728" width="512" height="269" srcset="https://blog.ovhcloud.com/wp-content/uploads/2022/03/IMG_0880-1024x537.jpeg 1024w, https://blog.ovhcloud.com/wp-content/uploads/2022/03/IMG_0880-300x157.jpeg 300w, https://blog.ovhcloud.com/wp-content/uploads/2022/03/IMG_0880-768x403.jpeg 768w, https://blog.ovhcloud.com/wp-content/uploads/2022/03/IMG_0880.jpeg 1200w" sizes="auto, (max-width: 512px) 100vw, 512px" /></figure></div>



<h3 class="wp-block-heading" id="introduction">Introduction</h3>



<h4 class="wp-block-heading" id="computer-vision">Computer Vision</h4>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>&#8221;&nbsp;<em>Computer vision is a specific field that deals with how computers can gain high-level understanding from digital images or videos.</em>&nbsp;&#8220;</p><p>&#8221;&nbsp;<em>From the perspective of engineering, it seeks to understand an automate tasks that the human visual system can do.</em>&nbsp;&#8220;</p><cite>Wikipedia</cite></blockquote>



<div class="wp-block-image"><figure class="aligncenter size-large is-resized"><img loading="lazy" decoding="async" src="https://blog.ovhcloud.com/wp-content/uploads/2022/03/IMG_0872-1024x361.png" alt="Computer Vision" class="wp-image-22710" width="768" height="271" srcset="https://blog.ovhcloud.com/wp-content/uploads/2022/03/IMG_0872-1024x361.png 1024w, https://blog.ovhcloud.com/wp-content/uploads/2022/03/IMG_0872-300x106.png 300w, https://blog.ovhcloud.com/wp-content/uploads/2022/03/IMG_0872-768x271.png 768w, https://blog.ovhcloud.com/wp-content/uploads/2022/03/IMG_0872.png 1409w" sizes="auto, (max-width: 768px) 100vw, 768px" /></figure></div>



<p><strong>The use cases are numerous &#8230;</strong></p>



<ul class="wp-block-list"><li>Automotive: autonomous car</li><li>Medical: cell detection</li><li>Retailing: automatic basket content detection</li><li>&#8230;</li></ul>



<div class="wp-block-image"><figure class="aligncenter size-full"><img loading="lazy" decoding="async" width="993" height="743" src="https://blog.ovhcloud.com/wp-content/uploads/2022/05/image-yolov5.png" alt="" class="wp-image-22984" srcset="https://blog.ovhcloud.com/wp-content/uploads/2022/05/image-yolov5.png 993w, https://blog.ovhcloud.com/wp-content/uploads/2022/05/image-yolov5-300x224.png 300w, https://blog.ovhcloud.com/wp-content/uploads/2022/05/image-yolov5-768x575.png 768w" sizes="auto, (max-width: 993px) 100vw, 993px" /></figure></div>



<h4 class="wp-block-heading" id="object-detection">Object Detection</h4>



<p><strong>Object detection</strong> is a branch of computer vision that identifies and locates objects in an image or video stream. This technique allows objects to be labelled accurately. Object detection can be used to determine and count objects in a scene or to track their movement.</p>



<h3 class="wp-block-heading" id="objective">Objective</h3>



<p>The purpose of this article is to show how it is possible to train YOLOv5 to recognise objects. YOLOv5 is an object detection algorithm. Although closely related to image classification, object detection performs image classification on a more precise scale. Object detection locates and categorises features in images.</p>



<p>It is based on the YOLOv5 repository by&nbsp;<a href="https://github.com/ultralytics/yolov5" target="_blank" rel="noreferrer noopener nofollow external" data-wpel-link="external">Ultralytics</a>.</p>



<h4 class="wp-block-heading">Use case: <a href="https://cocodataset.org/#home" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer">COCO dataset</a></h4>



<p>COCO is a large-scale object detection, segmentation, and also captioning dataset. It has several features:</p>



<ul class="wp-block-list"><li>Object segmentation</li><li>Recognition in context</li><li>Superpixel stuff segmentation</li><li>330K images</li><li>1.5 million object instances</li><li>80 object categories</li><li>91 stuff categories</li><li>5 captions per image</li><li>250 000 people with keypoints</li></ul>



<div class="wp-block-image"><figure class="aligncenter size-full is-resized"><a href="https://cocodataset.org/#home" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer"><img loading="lazy" decoding="async" src="https://blog.ovhcloud.com/wp-content/uploads/2022/03/IMG_0873.png" alt="COCO dataset" class="wp-image-22712" width="413" height="220" srcset="https://blog.ovhcloud.com/wp-content/uploads/2022/03/IMG_0873.png 550w, https://blog.ovhcloud.com/wp-content/uploads/2022/03/IMG_0873-300x160.png 300w" sizes="auto, (max-width: 413px) 100vw, 413px" /></a></figure></div>



<p class="has-ast-global-color-5-color has-ast-global-color-0-background-color has-text-color has-background">⚠️ Next, we will see how to use and train our <strong>own dataset</strong> to train a YOLOv5 model. But for this tutorial, we will use the <strong>COCO datase</strong>t.</p>



<p style="font-size:12px"><em>OVHcloud disclaims to the fullest extent authorized by law all warranties, whether express or implied, including any implied warranties of title, non-infringement, quiet enjoyment, integration, merchantability or fitness for a particular purpose regarding the use of the COCO dataset in the context of this notebook. The user shall fully comply with the terms of use that appears on the database website (https://cocodataset.org/).</em></p>



<h3 class="wp-block-heading" id="create-your-own-dataset">Create your own dataset</h3>



<p>To train our own dataset, we can refer to the following steps:</p>



<ul class="wp-block-list"><li><strong>Collecte your training images</strong>: to get our object detector off the ground, we need to first collect training images.</li></ul>



<p class="has-ast-global-color-5-color has-ast-global-color-0-background-color has-text-color has-background">⚠️ You must pay attention to the format of the images in your dataset. Think of putting your images in <strong>.jpg</strong> format!</p>



<ul class="wp-block-list"><li><strong>Define the number of classes</strong>: we have to make sure that the number of objects in each class is uniformly distributed.</li></ul>



<ul class="wp-block-list"><li><strong>Annotation of your training images</strong>: to train our object detector, we need to supervise its training using bounding box annotations. We have to draw a box around each object we want the detector to see and label each box with the object class we want the detector to predict.<a href="http://localhost:8888/notebooks/notebook_object_detection_yolov5.ipynb#Example-of-the-COCO-dataset" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer"></a></li></ul>



<div class="wp-block-image"><figure class="aligncenter size-large is-resized"><img loading="lazy" decoding="async" src="https://blog.ovhcloud.com/wp-content/uploads/2022/01/mug_annotation-1024x635.png" alt="" class="wp-image-21645" width="667" height="414" srcset="https://blog.ovhcloud.com/wp-content/uploads/2022/01/mug_annotation-1024x635.png 1024w, https://blog.ovhcloud.com/wp-content/uploads/2022/01/mug_annotation-300x186.png 300w, https://blog.ovhcloud.com/wp-content/uploads/2022/01/mug_annotation-768x477.png 768w, https://blog.ovhcloud.com/wp-content/uploads/2022/01/mug_annotation-1536x953.png 1536w, https://blog.ovhcloud.com/wp-content/uploads/2022/01/mug_annotation.png 1713w" sizes="auto, (max-width: 667px) 100vw, 667px" /></figure></div>



<p>↪️  Labels should be written as follows:</p>



<ol class="wp-block-list"><li><em>num_label</em>: label (or class) number. If you have <em>n</em> classes, the label number will be between <em>0</em> and <em>n-1</em></li><li><em>X</em> and <em>Y</em>: correspond to the coordinates of the centre of the box</li><li><em>width</em>: width of the box</li><li><em>height</em>: height of the box</li></ol>



<div class="wp-block-image"><figure class="aligncenter size-full is-resized"><img loading="lazy" decoding="async" src="https://blog.ovhcloud.com/wp-content/uploads/2022/03/IMG_0878.png" alt="Label format" class="wp-image-22726" width="445" height="217" srcset="https://blog.ovhcloud.com/wp-content/uploads/2022/03/IMG_0878.png 889w, https://blog.ovhcloud.com/wp-content/uploads/2022/03/IMG_0878-300x146.png 300w, https://blog.ovhcloud.com/wp-content/uploads/2022/03/IMG_0878-768x375.png 768w" sizes="auto, (max-width: 445px) 100vw, 445px" /></figure></div>



<p>If an image contains several labels, we write a line for each label in the same <strong>.txt</strong> file.</p>



<ul class="wp-block-list"><li><strong>Split your dataset</strong>: we choose how to disperse our data (for example, keep 80% data in the training set and 20% in the validation set).</li></ul>



<p class="has-ast-global-color-5-color has-ast-global-color-0-background-color has-text-color has-background">⚠️ Images and labels must have the same name.</p>



<p><em>Exemple:</em></p>



<p><code>data/train/images/img0.jpg     # image </code><br><code>data/train/labels/img0.txt     # label</code></p>



<div class="wp-block-image"><figure class="aligncenter size-full is-resized"><img loading="lazy" decoding="async" src="https://blog.ovhcloud.com/wp-content/uploads/2022/03/IMG_0875.png" alt="Splitting the dataset" class="wp-image-22718" width="348" height="322" srcset="https://blog.ovhcloud.com/wp-content/uploads/2022/03/IMG_0875.png 696w, https://blog.ovhcloud.com/wp-content/uploads/2022/03/IMG_0875-300x277.png 300w" sizes="auto, (max-width: 348px) 100vw, 348px" /></figure></div>



<ul class="wp-block-list"><li><strong>Set up files and directory structure</strong>: to train the YOLOv5 model, we need to add a <strong>.yaml</strong> file to describe the parameters of our dataset.</li></ul>



<p>We have to specify the train and validation files.</p>



<p class="has-ast-global-color-3-color has-text-color"><code>train: /workspace/data/train/images</code><br><code>val: /workspace/data/valid/images</code></p>



<p>After that, we define number and names of classes.</p>



<p class="has-ast-global-color-3-color has-text-color"><code>nc: 80</code><br><code>names: ['aeroplane', 'apple', 'backpack', 'banana', 'baseball bat', 'baseball glove', 'bear', 'bed', 'bench', 'bicycle', 'bird', 'boat', 'book', 'bottle', 'bowl', 'broccoli', 'bus', 'cake', 'car', 'carrot', 'cat', 'cell phone', 'chair', 'clock', 'cow', 'cup', 'diningtable', 'dog', 'donut', 'elephant', 'fire hydrant', 'fork', 'frisbee', 'giraffe', 'hair drier', 'handbag', 'horse', 'hot dog', 'keyboard', 'kite', 'knife', 'laptop', 'microwave', 'motorbike', 'mouse', 'orange', 'oven', 'parking meter', 'person', 'pizza', 'pottedplant', 'refrigerator', 'remote', 'sandwich', 'scissors', 'sheep', 'sink', 'skateboard', 'skis', 'snowboard', 'sofa', 'spoon', 'sports ball', 'stop sign', 'suitcase', 'surfboard', 'teddy bear', 'tennis racket', 'tie', 'toaster', 'toilet', 'toothbrush', 'traffic light', 'train', 'truck', 'tvmonitor', 'umbrella', 'vase', 'wine glass', 'zebra']</code></p>



<p>Let&#8217;s follow the different steps!</p>



<div class="wp-block-image"><figure class="aligncenter size-large"><img loading="lazy" decoding="async" width="1024" height="187" src="https://blog.ovhcloud.com/wp-content/uploads/2022/03/IMG_0874-1024x187.png" alt="Object detection steps" class="wp-image-22716" srcset="https://blog.ovhcloud.com/wp-content/uploads/2022/03/IMG_0874-1024x187.png 1024w, https://blog.ovhcloud.com/wp-content/uploads/2022/03/IMG_0874-300x55.png 300w, https://blog.ovhcloud.com/wp-content/uploads/2022/03/IMG_0874-768x141.png 768w, https://blog.ovhcloud.com/wp-content/uploads/2022/03/IMG_0874.png 1350w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure></div>



<h2 class="wp-block-heading" id="install-yolov5-dependences"><strong>Install YOLOv5 dependences</strong></h2>



<h3 class="wp-block-heading" id="1-clone-yolov5-repository">1. Clone YOLOv5 repository</h3>



<pre class="wp-block-code"><code class="">git clone https://github.com/ultralytics/yolov5 /workspace/yolov5</code></pre>



<h3 class="wp-block-heading" id="2-install-dependencies-as-necessary">2. Install dependencies as necessary</h3>



<p>Now, we have to go to the /<em>yolov5</em> folder and install the &#8220;<em>requirements.txt</em>&#8221; file containing all the necessary dependencies.</p>



<pre class="wp-block-code"><code class="">cd /workspace/yolov5</code></pre>



<p class="has-ast-global-color-5-color has-ast-global-color-0-background-color has-text-color has-background">⚠️&nbsp;Before installing the &#8220;<em>requirements.txt</em>&#8221; file, you have to&nbsp;<strong>modify</strong>&nbsp;it.</p>



<p>To access it, follow this path:<br><code>workspace </code>-&gt; <code>yolov5</code> -&gt; <code>requirements.txt</code><br><br>Then we have to replace the line <code>opencv-python&gt;=4.1.2</code> by <code>opencv-python--headless</code>.<br><br>Now we can save the &#8220;<em>requirements.txt</em>&#8221; file by selecting <code>File</code> in the Jupyter toolbar, then <code>Save File</code>.<br><br>Then, we can start the installation!</p>



<pre class="wp-block-code"><code class="">pip install -r requirements.txt</code></pre>



<p><strong>It&#8217;s almost over!</strong><br><br>The last step is to open a new terminal:<br><code>File</code> -&gt; <code>New</code> -&gt; <code>Terminal</code><br><br>Once in our new terminal, we run the following command: <code>pip uninstall setuptools</code><br><br>We confirm our action by selecting <code>Y</code>.<br><br>And finally, run the command: <code>pip install setuptools==59.5.0</code><br><br>The installations are now complete.</p>



<p class="has-ast-global-color-5-color has-ast-global-color-0-background-color has-text-color has-background">⚠️ <strong>Reboot the notebook kernel</strong> and follow the next steps!</p>



<h2 class="wp-block-heading" id="import-dependencies"><strong>Import dependencies</strong></h2>



<pre class="wp-block-code"><code class="">import torch
import yaml
from IPython.display import Image, clear_output
from utils.plots import plot_results</code></pre>



<p>We check GPU availability.</p>



<pre class="wp-block-code"><code class="">print('Setup complete. Using torch %s %s' % (torch.__version__, torch.cuda.get_device_properties(0) if torch.cuda.is_available() else 'CPU'))</code></pre>



<h2 class="wp-block-heading" id="define-and-train-yolov5-model"><strong>Define and train YOLOv5 model</strong></h2>



<h3 class="wp-block-heading" id="1-define-yolov5-model">1. Define YOLOv5 model</h3>



<p>We go to the directory where the &#8220;<em>data.yaml</em>&#8221; file is located.</p>



<pre class="wp-block-code"><code class="">cd /workspace/data

with open("data.yaml", 'r') as stream:
    num_classes = str(yaml.safe_load(stream)['nc'])</code></pre>



<p>The model configuration used for the tutorial is <strong>YOLOv5s</strong>.</p>



<pre class="wp-block-code"><code class="">cat /workspace/yolov5/models/yolov5s.yaml</code></pre>



<p class="has-ast-global-color-3-color has-text-color" id="yolov5-by-ultralytics-gpl-3-0-license"># <code>YOLOv5 🚀 by Ultralytics, GPL-3.0 license</code><br><br><code># Parameters</code><br><code>nc: 80 # number of classes<br>depth_multiple: 0.33 # model depth multiple<br>width_multiple: 0.50 # layer channel multiple<br>anchors:<br>     - [10,13, 16,30, 33,23] # P3/8<br>     - [30,61, 62,45, 59,119] # P4/16<br>     - [116,90, 156,198, 373,326] # P5/32</code><br><br><code># YOLOv5 backbone<br>backbone:<br>   # [from, number, module, args]<br>   [[-1, 1, Focus, [64, 3]], # 0-P1/2<br>    [-1, 1, Conv, [128, 3, 2]], # 1-P2/4<br>    [-1, 3, C3, [128]],<br>    [-1, 1, Conv, [256, 3, 2]], # 3-P3/8<br>    [-1, 9, C3, [256]],<br>    [-1, 1, Conv, [512, 3, 2]], # 5-P4/16<br>    [-1, 9, C3, [512]],<br>    [-1, 1, Conv, [1024, 3, 2]], # 7-P5/32<br>    [-1, 1, SPP, [1024, [5, 9, 13]]],<br>    [-1, 3, C3, [1024, False]], # 9<br>   ]</code><br><br><code># YOLOv5 head<br>head:</code><br>   <code>[[-1, 1, Conv, [512, 1, 1]],<br>    [-1, 1, nn.Upsample, [None, 2, 'nearest']],<br>    [[-1, 6], 1, Concat, [1]], # cat backbone P4<br>    [-1, 3, C3, [512, False]], # 13<br><br>    [-1, 1, Conv, [256, 1, 1]],<br>    [-1, 1, nn.Upsample, [None, 2, 'nearest']],<br>    [[-1, 4], 1, Concat, [1]], # cat backbone P3<br>    [-1, 3, C3, [256, False]], # 17 (P3/8-small)<br><br>    [-1, 1, Conv, [256, 3, 2]],<br>    [[-1, 14], 1, Concat, [1]], # cat head P4<br>    [-1, 3, C3, [512, False]], # 20 (P4/16-medium)<br><br>    [-1, 1, Conv, [512, 3, 2]],<br>    [[-1, 10], 1, Concat, [1]], # cat head P5<br>    [-1, 3, C3, [1024, False]], # 23 (P5/32-large)<br><br>    [[17, 20, 23], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5)<br>   ]</code></p>



<h3 class="wp-block-heading" id="2-run-yolov5-training">2. Run YOLOv5 training</h3>



<p><strong>Parameters definitions:</strong></p>



<ul class="wp-block-list"><li><em>img</em>: refers to the input images size.</li><li><em>batch</em>: refers to the batch size (number of training examples utilized in one iteration).</li><li><em>epochs</em>: refers to the number of training epochs. An epoch corresponds to one cycle through the full training dataset.</li><li><em>data</em>: refers to the path to the yaml file.</li><li><em>cfg</em>: define the model configuration.</li></ul>



<p>We will train YOLOv5s model on custom dataset for 100 epochs.</p>



<h2 class="wp-block-heading" id="evaluate-yolov5-performance-on-coco-dataset"><strong>Evaluate YOLOv5 performance on COCO dataset</strong></h2>



<pre class="wp-block-code"><code class="">Image(filename<strong>=</strong>'/workspace/yolov5/runs/train/yolov5s_results/results.png', width<strong>=</strong>1000)  
<em># view results.p</em>ng</code></pre>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="512" src="https://blog.ovhcloud.com/wp-content/uploads/2022/01/image-1-1024x512.png" alt="" class="wp-image-21947" srcset="https://blog.ovhcloud.com/wp-content/uploads/2022/01/image-1-1024x512.png 1024w, https://blog.ovhcloud.com/wp-content/uploads/2022/01/image-1-300x150.png 300w, https://blog.ovhcloud.com/wp-content/uploads/2022/01/image-1-768x384.png 768w, https://blog.ovhcloud.com/wp-content/uploads/2022/01/image-1-1536x768.png 1536w, https://blog.ovhcloud.com/wp-content/uploads/2022/01/image-1-2048x1024.png 2048w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<h2 class="wp-block-heading" id="graphs-and-functions-explanation"><strong>Graphs and functions explanation</strong></h2>



<p><strong>Loss functions:</strong></p>



<p><em>For the training set:</em></p>



<ul class="wp-block-list"><li>Box: loss due to a box prediction not exactly covering an object.</li><li>Objectness: loss due to a wrong box-object IoU&nbsp;<strong>[1]</strong>&nbsp;prediction.</li><li>Classification: loss due to deviations from predicting ‘1’ for the correct classes and ‘0’ for all the other classes for the object in that box.</li></ul>



<p><em>For the valid set (the same loss functions as for the training data):</em></p>



<ul class="wp-block-list"><li>val Box</li><li>val Objectness</li><li>val Classification</li></ul>



<p><strong>Precision &amp; Recall:</strong></p>



<ul class="wp-block-list"><li>Precision: measures how accurate are the predictions. It is the percentage of your correct predictions</li><li>Recall: measures how good it finds all the positives</li></ul>



<p><em>How to calculate Precision and Recall ?</em></p>



<div class="wp-block-image"><figure class="aligncenter size-large"><img loading="lazy" decoding="async" width="1024" height="370" src="https://blog.ovhcloud.com/wp-content/uploads/2022/03/IMG_0876-1024x370.png" alt="Precision &amp; Recall" class="wp-image-22720" srcset="https://blog.ovhcloud.com/wp-content/uploads/2022/03/IMG_0876-1024x370.png 1024w, https://blog.ovhcloud.com/wp-content/uploads/2022/03/IMG_0876-300x109.png 300w, https://blog.ovhcloud.com/wp-content/uploads/2022/03/IMG_0876-768x278.png 768w, https://blog.ovhcloud.com/wp-content/uploads/2022/03/IMG_0876-1536x556.png 1536w, https://blog.ovhcloud.com/wp-content/uploads/2022/03/IMG_0876.png 2010w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure></div>



<p><strong>Accuracy functions:</strong></p>



<p>mAP (mean Average Precision) compares the ground-truth bounding box to the detected box and returns a score. The higher the score, the more accurate the model is in its detections.</p>



<ul class="wp-block-list"><li>mAP@ 0.5：when IoU is set to 0.5, the AP&nbsp;<strong>[2]</strong>&nbsp;of all pictures of each category is calculated, and then all categories are averaged : mAP</li><li>mAP@ 0.5:0.95：represents the average mAP at different IoU thresholds (from 0.5 to 0.95 in steps of 0.05)</li></ul>



<p><strong>[1] IoU (Intersection over Union)</strong>&nbsp;= measures the overlap between two boundaries. It is used to measure how much the predicted boundary overlaps with the ground truth</p>



<p><em>How to calculate IoU ?</em></p>



<div class="wp-block-image"><figure class="aligncenter size-large is-resized"><img loading="lazy" decoding="async" src="https://blog.ovhcloud.com/wp-content/uploads/2022/03/IMG_0877-1024x321.png" alt="How to calculate IoU ?" class="wp-image-22724" width="768" height="241" srcset="https://blog.ovhcloud.com/wp-content/uploads/2022/03/IMG_0877-1024x321.png 1024w, https://blog.ovhcloud.com/wp-content/uploads/2022/03/IMG_0877-300x94.png 300w, https://blog.ovhcloud.com/wp-content/uploads/2022/03/IMG_0877-768x241.png 768w, https://blog.ovhcloud.com/wp-content/uploads/2022/03/IMG_0877.png 1110w" sizes="auto, (max-width: 768px) 100vw, 768px" /></figure></div>



<p><strong>[2] AP (Average precision)</strong>&nbsp;= popular metric in measuring the accuracy of object detectors. It computes the average precision value for recall value over 0 to 1</p>



<h2 class="wp-block-heading" id="inference"><strong>Inference</strong></h2>



<h4 class="wp-block-heading" id="1-run-yolov5-inference-on-test-images">1. Run YOLOv5 inference on test images</h4>



<p>We can perform inference on the contents of the <strong>/data/images</strong> folder. Images can be adde of your choice in the same folder in order to perform tests.</p>



<p>First, our trained weights saved in the weights folder. We can use the best weights and print the test images list.</p>



<pre class="wp-block-code"><code class=""><strong>cd</strong> /workspace/yolov5/
python detect.py --weights runs/train/yolov5s_results/weights/best.pt --img 416 --conf 0.4 --source data/images --name yolov5s_results</code></pre>



<p class="has-ast-global-color-3-color has-text-color"><code>/workspace/yolov5 <br><strong>detect: </strong>weights=['runs/train/yolov5s_results/weights/best.pt'], source=data/images, imgsz=416, conf_thres=0.4, iou_thres=0.45, max_det=1000, device=, view_img=False, save_txt=False, save_conf=False, save_crop=False, nosave=False, classes=None, agnostic_nms=False, augment=False, visualize=False, update=False, project=runs/detect, name=yolov5s_results, exist_ok=False, line_thickness=3, hide_labels=False, hide_conf=False, half=False YOLOv5 🚀 v5.0-306-g4495e00 torch 1.8.1 CUDA:0 (Tesla V100S-PCIE-32GB, 32510.5MB) </code><br><br><code>Fusing layers...  </code><br><code>Model Summary: 308 layers, 21356877 parameters, 0 gradients, 51.3 GFLOPs </code></p>



<p>Then, we have the the classes number of occurrences present in the image.</p>



<p class="has-ast-global-color-3-color has-text-color"><code>image 1/3 /workspace/yolov5/data/images/dog_street.jpg: 416x416 1 bicycle, 1 dog, 5 persons, Done. (0.017s)</code></p>



<div class="wp-block-image"><figure class="aligncenter size-large"><img loading="lazy" decoding="async" width="1024" height="1024" src="https://blog.ovhcloud.com/wp-content/uploads/2022/01/test_chien_velo-1024x1024.jpeg" alt="" class="wp-image-21951" srcset="https://blog.ovhcloud.com/wp-content/uploads/2022/01/test_chien_velo-1024x1024.jpeg 1024w, https://blog.ovhcloud.com/wp-content/uploads/2022/01/test_chien_velo-300x300.jpeg 300w, https://blog.ovhcloud.com/wp-content/uploads/2022/01/test_chien_velo-150x150.jpeg 150w, https://blog.ovhcloud.com/wp-content/uploads/2022/01/test_chien_velo-768x768.jpeg 768w, https://blog.ovhcloud.com/wp-content/uploads/2022/01/test_chien_velo-1536x1536.jpeg 1536w, https://blog.ovhcloud.com/wp-content/uploads/2022/01/test_chien_velo-2048x2048.jpeg 2048w, https://blog.ovhcloud.com/wp-content/uploads/2022/01/test_chien_velo-70x70.jpeg 70w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure></div>



<p class="has-ast-global-color-3-color has-text-color" id="block-88704cd0-e791-491a-a914-51a4c46f73ba"><code>image 2/3 /workspace/yolov5/data/images/lunch_computer.jpg: 288x416 1 broccoli, 1 cell phone, 1 cup, 1 diningtable, 1 fork, 1 keyboard, 1 knife, Done. (0.021s)</code></p>



<div class="wp-block-image"><figure class="aligncenter size-full"><img loading="lazy" decoding="async" width="1024" height="683" src="https://blog.ovhcloud.com/wp-content/uploads/2022/01/test_lunch_box.jpeg" alt="" class="wp-image-21952" srcset="https://blog.ovhcloud.com/wp-content/uploads/2022/01/test_lunch_box.jpeg 1024w, https://blog.ovhcloud.com/wp-content/uploads/2022/01/test_lunch_box-300x200.jpeg 300w, https://blog.ovhcloud.com/wp-content/uploads/2022/01/test_lunch_box-768x512.jpeg 768w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure></div>



<p class="has-ast-global-color-3-color has-text-color" id="block-5daf33a9-ac73-403f-b24a-10b310429476"><code>image 3/3 /workspace/yolov5/data/images/policeman_horse.jpg: 320x416 6 cars, 2 horses, 2 persons, 1 traffic light, Done. (0.020s)</code></p>



<div class="wp-block-image"><figure class="aligncenter size-full"><img loading="lazy" decoding="async" width="638" height="450" src="https://blog.ovhcloud.com/wp-content/uploads/2022/01/test_chevaux_policier.jpeg" alt="" class="wp-image-21953" srcset="https://blog.ovhcloud.com/wp-content/uploads/2022/01/test_chevaux_policier.jpeg 638w, https://blog.ovhcloud.com/wp-content/uploads/2022/01/test_chevaux_policier-300x212.jpeg 300w" sizes="auto, (max-width: 638px) 100vw, 638px" /></figure></div>



<p class="has-ast-global-color-3-color has-text-color"><code>Results saved to runs/detect/yolov5s_results<br>Done. (0.322s)</code></p>



<h3 class="wp-block-heading" id="2-export-trained-weights-for-future-inference">2. Export trained weights for future inference</h3>



<p>Our weights are saved after training our model over 100 epochs.<br><br>Two weight files exist:<br>&#8211; the best one: <strong>best.pt</strong><br>&#8211; the last one: <strong>last.pt</strong><br><br>We choose the <strong>best</strong> one and we will start by renaming it</p>



<pre class="wp-block-preformatted"><strong>cd</strong> /workspace/yolov5/runs/train/yolov5s_results/weights/
os<strong>.</strong>rename("best.pt","yolov5s_100epochs.pt")</pre>



<p>Then, we copy it in a new folder where we can put all the weights generated during your trainings.</p>



<pre class="wp-block-preformatted"><strong>cp</strong> /workspace/yolov5/runs/train/yolov5s_results/weights/yolov5s_100epochs.pt /workspace/models_train/yolov5s_100epochs.pt</pre>



<h2 class="wp-block-heading" id="conclusion"><strong>Conclusion</strong></h2>



<p>The accuracy of the model can be improved by increasing the number of epochs, but after a certain period we reach a threshold, so the value should be determined accordingly.<br><br>The accuracy obtained for the test set is&nbsp;<strong>93.71 %</strong>, which is a satisfactory result.</p>



<h3 class="wp-block-heading" id="want-to-find-out-more">Want to find out more?</h3>



<ul class="wp-block-list"><li><strong>Notebook</strong></li></ul>



<p>You want to access the notebook? Refer to the GitHub repository.<br><br>To launch and test this notebook with&nbsp;<strong>AI Notebooks</strong>, please refer to our documentation.</p>



<ul class="wp-block-list"><li><strong>App</strong></li></ul>



<p>You want to access the tutorial to create a simple app? Refer to the <a href="https://github.com/ovh/ai-training-examples" target="_blank" rel="noreferrer noopener nofollow external" data-wpel-link="external">GitHub repository</a>.<br><br>To launch and test this app with&nbsp;<strong>AI Training</strong>, please refer to <a href="https://docs.ovh.com/us/en/publiccloud/ai/" target="_blank" rel="noreferrer noopener" data-wpel-link="exclude">our documentation</a>.</p>



<h2 class="wp-block-heading" id="references"><strong>References</strong></h2>
<img loading="lazy" decoding="async" src="//blog.ovhcloud.com/wp-content/plugins/matomo/app/matomo.php?idsite=1&amp;rec=1&amp;url=https%3A%2F%2Fblog.ovhcloud.com%2Fobject-detection-train-yolov5-on-a-custom-dataset%2F&amp;action_name=Object%20detection%3A%20train%20YOLOv5%20on%20a%20custom%20dataset&amp;urlref=https%3A%2F%2Fblog.ovhcloud.com%2Ffeed%2F" style="border:0;width:0;height:0" width="0" height="0" alt="" />]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>AI Notebooks: analyze and classify sounds with AI</title>
		<link>https://blog.ovhcloud.com/ai-notebooks-analyze-and-classify-sounds-with-ai/</link>
		
		<dc:creator><![CDATA[Eléa Petton]]></dc:creator>
		<pubDate>Fri, 04 Mar 2022 08:57:00 +0000</pubDate>
				<category><![CDATA[OVHcloud Engineering]]></category>
		<category><![CDATA[AI]]></category>
		<category><![CDATA[AI Notebook]]></category>
		<category><![CDATA[AI Solutions]]></category>
		<category><![CDATA[Deep learning]]></category>
		<category><![CDATA[Machine learning]]></category>
		<guid isPermaLink="false">https://blog.ovhcloud.com/?p=21594</guid>

					<description><![CDATA[A guide to analyze and classify marine mammal sounds. Since you&#8217;re reading a blog post from a technology company, I bet you&#8217;ve heard about AI, Machine and Deep Learning many times before. Audio or sound classification is a technique with multiple applications in the field of AI and data science. Use cases Acoustic data classification: [&#8230;]<img src="//blog.ovhcloud.com/wp-content/plugins/matomo/app/matomo.php?idsite=1&amp;rec=1&amp;url=https%3A%2F%2Fblog.ovhcloud.com%2Fai-notebooks-analyze-and-classify-sounds-with-ai%2F&amp;action_name=AI%20Notebooks%3A%20analyze%20and%20classify%20sounds%20with%20AI&amp;urlref=https%3A%2F%2Fblog.ovhcloud.com%2Ffeed%2F" style="border:0;width:0;height:0" width="0" height="0" alt="" />]]></description>
										<content:encoded><![CDATA[
<p><em>A guide to analyze and classify <strong>marine mammal sounds</strong>.</em></p>



<div class="wp-block-image"><figure class="aligncenter size-large is-resized"><img loading="lazy" decoding="async" src="https://blog.ovhcloud.com/wp-content/uploads/2022/01/IMG_0834-1024x537.jpeg" alt="AI Notebooks: analyze and classify sounds with AI" class="wp-image-22610" width="512" height="269" srcset="https://blog.ovhcloud.com/wp-content/uploads/2022/01/IMG_0834-1024x537.jpeg 1024w, https://blog.ovhcloud.com/wp-content/uploads/2022/01/IMG_0834-300x157.jpeg 300w, https://blog.ovhcloud.com/wp-content/uploads/2022/01/IMG_0834-768x403.jpeg 768w, https://blog.ovhcloud.com/wp-content/uploads/2022/01/IMG_0834.jpeg 1200w" sizes="auto, (max-width: 512px) 100vw, 512px" /></figure></div>



<p>Since you&#8217;re reading a blog post from a technology company, I bet you&#8217;ve heard about AI, Machine and Deep Learning many times before.</p>



<p>Audio or sound classification is a technique with multiple applications in the field of AI and data science.</p>



<div class="wp-block-image"><figure class="aligncenter size-large is-resized"><img loading="lazy" decoding="async" src="https://blog.ovhcloud.com/wp-content/uploads/2022/01/IMG_0835-1024x467.png" alt="AI Notebooks: analyze and classify sounds with AI" class="wp-image-22611" width="768" height="350" srcset="https://blog.ovhcloud.com/wp-content/uploads/2022/01/IMG_0835-1024x467.png 1024w, https://blog.ovhcloud.com/wp-content/uploads/2022/01/IMG_0835-300x137.png 300w, https://blog.ovhcloud.com/wp-content/uploads/2022/01/IMG_0835-768x350.png 768w, https://blog.ovhcloud.com/wp-content/uploads/2022/01/IMG_0835.png 1322w" sizes="auto, (max-width: 768px) 100vw, 768px" /></figure></div>



<h3 class="wp-block-heading" id="Use-cases:">Use cases<a href="http://localhost:8888/notebooks/notebook-marine-sound-classification.ipynb#Use-cases:" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer"></a></h3>



<ul class="wp-block-list"><li><strong>Acoustic data classification:</strong></li></ul>



<p>&#8211; identifies location<br>&#8211; differentiates environments<br>&#8211; has a role in ecosystem monitoring</p>



<ul class="wp-block-list"><li><strong>Environmental sound classification:</strong></li></ul>



<p>&#8211; recognition of urban sounds<br>&#8211; used in security system<br>&#8211; used in predictive maintenance<br>&#8211; used to differentiate animal sounds</p>



<ul class="wp-block-list"><li><strong>Music classification:</strong></li></ul>



<p>&#8211; classify music<br>&#8211; <em>key role in:</em> audio libraries organisation by genre, improvement of recommandation algorithms, discovery of trends, listener preferences through data analysis, &#8230;</p>



<ul class="wp-block-list"><li><strong>Natural language classification:</strong></li></ul>



<p>&#8211; human speech classification<br>&#8211; <em>common in:</em> chatbots, virtual assistants, tech-to-speech application, &#8230;</p>



<p>In this article we will look at the <strong>classification of marine mammal sounds</strong>.</p>



<h3 class="wp-block-heading" id="objective">Objective</h3>



<p>The purpose of this article is to explain how to train a model to classify audios using <em>AI Notebooks</em>.<br><br>In this tutorial, the sounds in the dataset are in <em>.wav</em> format. To be able to use them and obtain results, it is necessary to pre-process this data by following different steps.</p>



<ul class="wp-block-list" id="block-c53a8333-8cfa-4558-81f3-827e57035439"><li>Analyse one of these audio recordings</li><li>Transform each sound file into a <em>.csv</em> file</li><li>Train your model from the <em>.csv</em> file</li></ul>



<p><strong>USE CASE:</strong> <a href="https://www.kaggle.com/shreyj1729/best-of-watkins-marine-mammal-sound-database/version/3" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer">Best of Watkins Marine Mammal Sound Database</a></p>



<div class="wp-block-image"><figure class="aligncenter size-large is-resized"><img loading="lazy" decoding="async" src="https://blog.ovhcloud.com/wp-content/uploads/2022/02/Capture-décran-2022-02-01-à-14.40.36-1024x617.png" alt="" class="wp-image-21968" width="781" height="471" srcset="https://blog.ovhcloud.com/wp-content/uploads/2022/02/Capture-décran-2022-02-01-à-14.40.36-1024x617.png 1024w, https://blog.ovhcloud.com/wp-content/uploads/2022/02/Capture-décran-2022-02-01-à-14.40.36-300x181.png 300w, https://blog.ovhcloud.com/wp-content/uploads/2022/02/Capture-décran-2022-02-01-à-14.40.36-768x463.png 768w, https://blog.ovhcloud.com/wp-content/uploads/2022/02/Capture-décran-2022-02-01-à-14.40.36.png 1031w" sizes="auto, (max-width: 781px) 100vw, 781px" /></figure></div>



<p>This dataset is composed of <strong>55 different folders </strong>corresponding to the marine mammals. In each folder are stored several sound files of each animal.<br><br>You can get more information about this dataset on this <a href="https://cis.whoi.edu/science/B/whalesounds/index.cfm" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer">website</a>.<br><br>The data distribution is as follows:</p>



<div class="wp-block-image"><figure class="aligncenter size-large is-resized"><img loading="lazy" decoding="async" src="https://blog.ovhcloud.com/wp-content/uploads/2022/01/IMG_0837-1024x681.png" alt="The data distribution " class="wp-image-22615" width="512" height="341" srcset="https://blog.ovhcloud.com/wp-content/uploads/2022/01/IMG_0837-1024x681.png 1024w, https://blog.ovhcloud.com/wp-content/uploads/2022/01/IMG_0837-300x200.png 300w, https://blog.ovhcloud.com/wp-content/uploads/2022/01/IMG_0837-768x511.png 768w, https://blog.ovhcloud.com/wp-content/uploads/2022/01/IMG_0837.png 1114w" sizes="auto, (max-width: 512px) 100vw, 512px" /></figure></div>



<p class="has-ast-global-color-5-color has-ast-global-color-0-background-color has-text-color has-background">⚠️ <em>For this example, we choose only the </em><strong>first 45 classes</strong><em> (or folders).</em></p>



<p>Let&#8217;s follow the different steps!</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="188" src="https://blog.ovhcloud.com/wp-content/uploads/2022/01/IMG_0836-1024x188.png" alt="Data analysis and classification" class="wp-image-22613" srcset="https://blog.ovhcloud.com/wp-content/uploads/2022/01/IMG_0836-1024x188.png 1024w, https://blog.ovhcloud.com/wp-content/uploads/2022/01/IMG_0836-300x55.png 300w, https://blog.ovhcloud.com/wp-content/uploads/2022/01/IMG_0836-768x141.png 768w, https://blog.ovhcloud.com/wp-content/uploads/2022/01/IMG_0836-1536x282.png 1536w, https://blog.ovhcloud.com/wp-content/uploads/2022/01/IMG_0836-2048x376.png 2048w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<h3 class="wp-block-heading" id="audio-libraries">Audio libraries</h3>



<h4 class="wp-block-heading" id="1-loading-an-audio-file-with-librosa">1. Loading an audio file with Librosa</h4>



<p><em>Librosa</em> is a Python module for audio signal analysis. By using <em>Librosa</em>, you can extract key features from the audio samples such as Tempo, Chroma Energy Normalized, Mel-Freqency Cepstral Coefficients, Spectral Centroid, Spectral Contrast, Spectral Rolloff, and Zero Crossing Rate. If you want to know more about this library, refer to the <a href="https://librosa.org/doc/latest/index.html" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer">documentation</a>.</p>



<pre class="wp-block-code"><code class="">import librosa
import librosa.display as lplt</code></pre>



<p>You can start by looking at your data by displaying different parameters using the <em>Librosa</em> library.<br><br>First, you can do a test on a file.</p>



<pre class="wp-block-code"><code class="">test_sound = "data/AtlanticSpottedDolphin/61025001.wav"</code></pre>



<p>Loads and decodes the audio.</p>



<pre class="wp-block-code"><code class="">data, sr = librosa.load(test_sound)
print(type(data), type(sr))</code></pre>



<p class="has-ast-global-color-3-color has-text-color"><code>&lt;class 'numpy.ndarray'&gt; &lt;class 'int'&gt;</code></p>



<pre class="wp-block-code"><code class="">librosa.load(test_sound ,sr = 45600)</code></pre>



<p class="has-ast-global-color-3-color has-text-color"><code>(array([-0.0739522 , -0.06588229, -0.06673266, ..., 0.03021295, 0.05592792, 0. ], dtype=float32), 45600)</code></p>



<h4 class="wp-block-heading" id="2-playing-audio-with-ipython-display-audio">2. Playing Audio with IPython.display.Audio</h4>



<p><a href="https://ipython.org/ipython-doc/stable/api/generated/IPython.display.html#IPython.display.Audio" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer">IPython.display.Audio</a> advises you play audio directly in a Jupyter notebook.<br><br>Using <em>IPython.display.Audio</em> to play the audio.</p>



<pre class="wp-block-code"><code class="">import IPython

IPython.display.Audio(data, rate = sr)</code></pre>



<div class="wp-block-image"><figure class="aligncenter size-full is-resized"><img loading="lazy" decoding="async" src="https://blog.ovhcloud.com/wp-content/uploads/2022/01/IMG_0838.png" alt=" Playing the audio" class="wp-image-22618" width="518" height="130" srcset="https://blog.ovhcloud.com/wp-content/uploads/2022/01/IMG_0838.png 690w, https://blog.ovhcloud.com/wp-content/uploads/2022/01/IMG_0838-300x75.png 300w" sizes="auto, (max-width: 518px) 100vw, 518px" /></figure></div>



<h3 class="wp-block-heading" id="visualizing-audio">Visualizing Audio</h3>



<h4 class="wp-block-heading" id="1-waveforms">1. Waveforms</h4>



<p><strong>Waveforms</strong> are visual representations of sound as time on the x-axis and amplitude on the y-axis. They allow for quick analysis of audio data.<br><br>We can plot the audio array using <em>librosa.display.waveplot</em>.</p>



<pre class="wp-block-code"><code class="">plt.show(librosa.display.waveplot(data))</code></pre>



<div class="wp-block-image"><figure class="aligncenter size-full"><img loading="lazy" decoding="async" width="406" height="269" src="https://blog.ovhcloud.com/wp-content/uploads/2022/01/waveforms.png" alt="" class="wp-image-21601" srcset="https://blog.ovhcloud.com/wp-content/uploads/2022/01/waveforms.png 406w, https://blog.ovhcloud.com/wp-content/uploads/2022/01/waveforms-300x199.png 300w" sizes="auto, (max-width: 406px) 100vw, 406px" /></figure></div>



<h4 class="wp-block-heading" id="2-spectrograms">2. Spectrograms</h4>



<p>A <strong>spectrogram</strong> is a visual way of representing the intensity of a signal over time at various frequencies present in a particular waveform.</p>



<pre class="wp-block-code"><code class="">stft = librosa.stft(data)
plt.colorbar(librosa.display.specshow(stft, sr = sr, x_axis = 'time', y_axis = 'hz'))</code></pre>



<div class="wp-block-image"><figure class="aligncenter size-full"><img loading="lazy" decoding="async" width="406" height="269" src="https://blog.ovhcloud.com/wp-content/uploads/2022/01/spectrograms1.png" alt="" class="wp-image-21602" srcset="https://blog.ovhcloud.com/wp-content/uploads/2022/01/spectrograms1.png 406w, https://blog.ovhcloud.com/wp-content/uploads/2022/01/spectrograms1-300x199.png 300w" sizes="auto, (max-width: 406px) 100vw, 406px" /></figure></div>



<pre class="wp-block-code"><code class="">stft_db = librosa.amplitude_to_db(abs(stft))
plt.colorbar(librosa.display.specshow(stft_db, sr = sr, x_axis = 'time', y_axis = 'hz'))</code></pre>



<div class="wp-block-image"><figure class="aligncenter size-full"><img loading="lazy" decoding="async" width="406" height="269" src="https://blog.ovhcloud.com/wp-content/uploads/2022/01/spectrograms2.png" alt="" class="wp-image-21603" srcset="https://blog.ovhcloud.com/wp-content/uploads/2022/01/spectrograms2.png 406w, https://blog.ovhcloud.com/wp-content/uploads/2022/01/spectrograms2-300x199.png 300w" sizes="auto, (max-width: 406px) 100vw, 406px" /></figure></div>



<h4 class="wp-block-heading" id="3-spectral-rolloff">3. Spectral Rolloff</h4>



<p><strong>Spectral Rolloff</strong> is the frequency below which a specified percentage of the total spectral energy.<br><br><em>librosa.feature.spectral_rolloff</em> calculates the attenuation frequency for each frame of a signal.</p>



<pre class="wp-block-code"><code class="">spectral_rolloff = librosa.feature.spectral_rolloff(data + 0.01, sr = sr)[0]
plt.show(librosa.display.waveplot(data, sr = sr, alpha = 0.4))</code></pre>



<div class="wp-block-image"><figure class="aligncenter size-full"><img loading="lazy" decoding="async" width="406" height="269" src="https://blog.ovhcloud.com/wp-content/uploads/2022/01/spectral_rolloff.png" alt="" class="wp-image-21604" srcset="https://blog.ovhcloud.com/wp-content/uploads/2022/01/spectral_rolloff.png 406w, https://blog.ovhcloud.com/wp-content/uploads/2022/01/spectral_rolloff-300x199.png 300w" sizes="auto, (max-width: 406px) 100vw, 406px" /></figure></div>



<h4 class="wp-block-heading" id="4-chroma-feature">4. Chroma Feature</h4>



<p>This tool is perfect for analyzing musical features whose pitches can be meaningfully categorized and whose tuning is close to the equal temperament scale.</p>



<pre class="wp-block-code"><code class="">chroma = librosa.feature.chroma_stft(data, sr = sr)
lplt.specshow(chroma, sr = sr, x_axis = "time" ,y_axis = "chroma", cmap = "coolwarm")
plt.colorbar()
plt.title("Chroma Features")
plt.show()</code></pre>



<div class="wp-block-image"><figure class="aligncenter size-full"><img loading="lazy" decoding="async" width="406" height="280" src="https://blog.ovhcloud.com/wp-content/uploads/2022/01/chroma_feature.png" alt="" class="wp-image-21605" srcset="https://blog.ovhcloud.com/wp-content/uploads/2022/01/chroma_feature.png 406w, https://blog.ovhcloud.com/wp-content/uploads/2022/01/chroma_feature-300x207.png 300w" sizes="auto, (max-width: 406px) 100vw, 406px" /></figure></div>



<h4 class="wp-block-heading" id="5-zero-crossing-rate">5. Zero Crossing Rate</h4>



<p>A <strong>zero crossing</strong> occurs if successive samples have different algebraic signs.</p>



<ul class="wp-block-list"><li>The rate at which zero crossings occur is a simple measure of the frequency content of a signal.</li><li>The number of zero-crossings measures the number of times in a time interval that the amplitude of speech signals passes through a zero value.</li></ul>



<pre class="wp-block-code"><code class="">start = 1000
end = 1200
plt.plot(data[start:end])
plt.grid()</code></pre>



<div class="wp-block-image"><figure class="aligncenter size-full"><img loading="lazy" decoding="async" width="406" height="255" src="https://blog.ovhcloud.com/wp-content/uploads/2022/01/zero_crossing_rate.png" alt="" class="wp-image-21606" srcset="https://blog.ovhcloud.com/wp-content/uploads/2022/01/zero_crossing_rate.png 406w, https://blog.ovhcloud.com/wp-content/uploads/2022/01/zero_crossing_rate-300x188.png 300w" sizes="auto, (max-width: 406px) 100vw, 406px" /></figure></div>



<h2 class="wp-block-heading" id="data-preprocessing"><strong>Data preprocessing</strong></h2>



<h4 class="wp-block-heading" id="1-data-transformation">1. Data transformation</h4>



<p>To train your model, preprocessing of data is required. First of all, you have to convert the <em>.wav</em> into a <em>.csv</em> file.</p>



<ul class="wp-block-list"><li>Define columns name:</li></ul>



<pre class="wp-block-code"><code class="">header = "filename length chroma_stft_mean chroma_stft_var rms_mean rms_var spectral_centroid_mean spectral_centroid_var spectral_bandwidth_mean spectral_bandwidth_var rolloff_mean rolloff_var zero_crossing_rate_mean zero_crossing_rate_var harmony_mean harmony_var perceptr_mean perceptr_var tempo mfcc1_mean mfcc1_var mfcc2_mean mfcc2_var mfcc3_mean mfcc3_var mfcc4_mean mfcc4_var label".split()</code></pre>



<ul class="wp-block-list"><li>Create the <em>data.csv</em> file:</li></ul>



<pre class="wp-block-code"><code class="">import csv

file = open('data.csv', 'w', newline = '')
with file:
    writer = csv.writer(file)
    writer.writerow(header)</code></pre>



<ul class="wp-block-list"><li>Define character string of marine mammals (45):</li></ul>



<p>There are 45 different marine animals, or 45 classes.</p>



<pre class="wp-block-code"><code class="">marine_mammals = "AtlanticSpottedDolphin BeardedSeal Beluga_WhiteWhale BlueWhale BottlenoseDolphin Boutu_AmazonRiverDolphin BowheadWhale ClymeneDolphin Commerson'sDolphin CommonDolphin Dall'sPorpoise DuskyDolphin FalseKillerWhale Fin_FinbackWhale FinlessPorpoise Fraser'sDolphin Grampus_Risso'sDolphin GraySeal GrayWhale HarborPorpoise HarbourSeal HarpSeal Heaviside'sDolphin HoodedSeal HumpbackWhale IrawaddyDolphin JuanFernandezFurSeal KillerWhale LeopardSeal Long_FinnedPilotWhale LongBeaked(Pacific)CommonDolphin MelonHeadedWhale MinkeWhale Narwhal NewZealandFurSeal NorthernRightWhale PantropicalSpottedDolphin RibbonSeal RingedSeal RossSeal Rough_ToothedDolphin SeaOtter Short_Finned(Pacific)PilotWhale SouthernRightWhale SpermWhale".split()</code></pre>



<ul class="wp-block-list"><li>Transform each <em>.wav</em> file into a <em>.csv</em> row:</li></ul>



<pre class="wp-block-code"><code class="">for animal in marine_mammals:

  for filename in os.listdir(f"/workspace/data/{animal}/"):

    sound_name = f"/workspace/data/{animal}/{filename}"
    y, sr = librosa.load(sound_name, mono = True, duration = 30)
    chroma_stft = librosa.feature.chroma_stft(y = y, sr = sr)
    rmse = librosa.feature.rms(y = y)
    spec_cent = librosa.feature.spectral_centroid(y = y, sr = sr)
    spec_bw = librosa.feature.spectral_bandwidth(y = y, sr = sr)
    rolloff = librosa.feature.spectral_rolloff(y = y, sr = sr)
    zcr = librosa.feature.zero_crossing_rate(y)
    mfcc = librosa.feature.mfcc(y = y, sr = sr)
    to_append = f'{filename} {np.mean(chroma_stft)} {np.mean(rmse)} {np.mean(spec_cent)} {np.mean(spec_bw)} {np.mean(rolloff)} {np.mean(zcr)}'
    
    for e in mfcc:
        to_append += f' {np.mean(e)}'

    to_append += f' {animal}'
    file = open('data.csv', 'a', newline = '')
    
    with file:
        writer = csv.writer(file)
        writer.writerow(to_append.split())</code></pre>



<ul class="wp-block-list"><li>Display the <em>data.csv</em> file:</li></ul>



<pre class="wp-block-code"><code class="">df = pd.read_csv('data.csv')</code></pre>



<h4 class="wp-block-heading" id="2-features-extraction">2. Features extraction</h4>



<p>In the preprocessing of the data, <em>feature extraction</em> is necessary before running the training. The purpose is to define the <strong>inputs</strong> and <strong>outputs </strong>of the neural network.</p>



<ul class="wp-block-list"><li><strong>OUTPUT</strong> (y): last column which is the <strong><em>label</em></strong>.</li></ul>



<p>You cannot use text directly for training. You will encode these labels with the <strong>LabelEncoder()</strong> function of <em>sklearn.preprocessing</em>.<br><br>Before running a model, you need to convert this type of categorical text data into numerical data that the model can understand.</p>



<pre class="wp-block-code"><code class="">from sklearn.preprocessing import LabelEncoder

class_list = df.iloc[:,-1]
converter = LabelEncoder()
y = converter.fit_transform(class_list)
print("y: ", y)</code></pre>



<p class="has-ast-global-color-3-color has-text-color"><code>y : [ 0 0 0 ... 44 44 44]</code></p>



<ul class="wp-block-list"><li><strong>INPUTS</strong> (X): all other columns are input parameters to the neural network.</li></ul>



<p>Remove the first column which does not provide any information for the training (the filename) and the last one which corresponds to the output.</p>



<pre class="wp-block-code"><code class="">from sklearn.preprocessing import StandardScaler

fit = StandardScaler()
X = fit.fit_transform(np.array(df.iloc[:, 1:26], dtype=float))</code></pre>



<h4 class="wp-block-heading" id="3-split-dataset-for-training">3. Split dataset for training</h4>



<pre class="wp-block-code"><code class="">from sklearn.model_selection import train_test_split

X_train, X_test, y_train, y_test <strong>=</strong> train_test_split(X, y, test_size <strong>=</strong> 0.2)</code></pre>



<h2 class="wp-block-heading" id="building-the-model"><strong>Building the model</strong></h2>



<p id="block-08360fbe-4253-417f-ab02-9a4ee8b0d753">The first step is to build the model and display the summary.<br><br>For the CNN model, all hidden layers use a <strong>ReLU</strong> activation function, the output layer a <strong>Softmax</strong> function and a <strong>Dropout </strong>is used to avoid overfitting.</p>



<pre class="wp-block-code"><code class="">import keras
import tensorflow as tf
from tensorflow.keras.models import Sequential

model <strong>=</strong> tf<strong>.</strong>keras<strong>.</strong>models<strong>.</strong>Sequential([
    tf<strong>.</strong>keras<strong>.</strong>layers<strong>.</strong>Dense(512, activation <strong>=</strong> 'relu', input_shape <strong>=</strong> (X_train<strong>.</strong>shape[1],)),
    tf<strong>.</strong>keras<strong>.</strong>layers<strong>.</strong>Dropout(0.2),
    
    tf<strong>.</strong>keras<strong>.</strong>layers<strong>.</strong>Dense(256, activation <strong>=</strong> 'relu'),
    keras<strong>.</strong>layers<strong>.</strong>Dropout(0.2),
    
    tf<strong>.</strong>keras<strong>.</strong>layers<strong>.</strong>Dense(128, activation <strong>=</strong> 'relu'),
    tf<strong>.</strong>keras<strong>.</strong>layers<strong>.</strong>Dropout(0.2),
    
    tf<strong>.</strong>keras<strong>.</strong>layers<strong>.</strong>Dense(64, activation <strong>=</strong> 'relu'),
    tf<strong>.</strong>keras<strong>.</strong>layers<strong>.</strong>Dropout(0.2),
    
    tf<strong>.</strong>keras<strong>.</strong>layers<strong>.</strong>Dense(45, activation <strong>=</strong> 'softmax'),
])

print(model.summary())</code></pre>



<div class="wp-block-image"><figure class="aligncenter size-full"><img loading="lazy" decoding="async" width="560" height="427" src="https://blog.ovhcloud.com/wp-content/uploads/2022/01/model_summary.png" alt="" class="wp-image-21598" srcset="https://blog.ovhcloud.com/wp-content/uploads/2022/01/model_summary.png 560w, https://blog.ovhcloud.com/wp-content/uploads/2022/01/model_summary-300x229.png 300w" sizes="auto, (max-width: 560px) 100vw, 560px" /></figure></div>



<h2 class="wp-block-heading" id="model-training-and-evaluation"><strong>Model training and evaluation</strong></h2>



<p><strong>Adam</strong> optimizer is used to train the model over <em>100 epochs</em>. This choice was made because it allows us to obtain better results.<br><br>The loss is calculated with the <strong>sparse_categorical_crossentropy</strong> function.</p>



<pre class="wp-block-code"><code class=""><strong>def</strong> trainModel(model,epochs, optimizer):
    batch_size <strong>=</strong> 128
    model<strong>.</strong>compile(optimizer <strong>=</strong> optimizer, loss <strong>=</strong> 'sparse_categorical_crossentropy', metrics <strong>=</strong> 'accuracy')
    <strong>return</strong> model<strong>.</strong>fit(X_train, y_train, validation_data <strong>=</strong> (X_test, y_test), epochs <strong>=</strong> epochs, batch_size <strong>=</strong> batch_size)</code></pre>



<p>Now, launch the training!</p>



<pre class="wp-block-code"><code class="">model_history <strong>=</strong> trainModel(model <strong>=</strong> model, epochs <strong>=</strong> 100, optimizer <strong>=</strong> 'adam')</code></pre>



<ul class="wp-block-list"><li>Display <strong>loss</strong> curves</li></ul>



<pre class="wp-block-code"><code class="">loss_train_curve <strong>=</strong> model_history<strong>.</strong>history["loss"]
loss_val_curve <strong>=</strong> model_history<strong>.</strong>history["val_loss"]
plt<strong>.</strong>plot(loss_train_curve, label <strong>=</strong> "Train")
plt<strong>.</strong>plot(loss_val_curve, label <strong>=</strong> "Validation")
plt<strong>.</strong>legend(loc <strong>=</strong> 'upper right')
plt<strong>.</strong>title("Loss")
plt<strong>.</strong>show()</code></pre>



<div class="wp-block-image"><figure class="aligncenter size-full"><img loading="lazy" decoding="async" width="390" height="269" src="https://blog.ovhcloud.com/wp-content/uploads/2022/02/loss.png" alt="" class="wp-image-22523" srcset="https://blog.ovhcloud.com/wp-content/uploads/2022/02/loss.png 390w, https://blog.ovhcloud.com/wp-content/uploads/2022/02/loss-300x207.png 300w" sizes="auto, (max-width: 390px) 100vw, 390px" /></figure></div>



<ul class="wp-block-list"><li>Display <strong>accuracy</strong> curves</li></ul>



<pre class="wp-block-code"><code class="">acc_train_curve <strong>=</strong> model_history<strong>.</strong>history["accuracy"]
acc_val_curve <strong>=</strong> model_history<strong>.</strong>history["val_accuracy"]
plt<strong>.</strong>plot(acc_train_curve, label <strong>=</strong> "Train")
plt<strong>.</strong>plot(acc_val_curve, label <strong>=</strong> "Validation")
plt<strong>.</strong>legend(loc <strong>=</strong> 'lower right')
plt<strong>.</strong>title("Accuracy")
plt<strong>.</strong>show()</code></pre>



<div class="wp-block-image"><figure class="aligncenter size-full"><img loading="lazy" decoding="async" width="390" height="269" src="https://blog.ovhcloud.com/wp-content/uploads/2022/02/accuracy.png" alt="" class="wp-image-22524" srcset="https://blog.ovhcloud.com/wp-content/uploads/2022/02/accuracy.png 390w, https://blog.ovhcloud.com/wp-content/uploads/2022/02/accuracy-300x207.png 300w" sizes="auto, (max-width: 390px) 100vw, 390px" /></figure></div>



<pre class="wp-block-code"><code class="">test_loss, test_acc <strong>=</strong> model<strong>.</strong>evaluate(X_test, y_test, batch_size <strong>=</strong> 128)
print("The test loss is: ", test_loss)
print("The best accuracy is: ", test_acc<strong>*</strong>100)</code></pre>



<p class="has-ast-global-color-3-color has-text-color"><code>20/20 [==============================] - 0s 3ms/step - loss: 0.2854 - accuracy: 0.9371 </code><br><code>The test loss is: </code>0.24700121581554413<br><code>The best accuracy is: </code>93.71269345283508</p>



<h2 class="wp-block-heading"><strong>Save the model for future inference</strong></h2>



<h4 class="wp-block-heading">1. Save and store the model in an OVHcloud Object Container</h4>



<pre class="wp-block-code"><code class="">model.save('/workspace/model-marine-mammal-sounds/saved_model/my_model')</code></pre>



<p>You can check your model directory.</p>



<pre class="wp-block-code"><code class="">%ls /workspace/model-marine-mammal-sounds/saved_model</code></pre>



<p><strong><em>Saved_model</em></strong> contains an assets folder, saved_model.pb, and variables folder.</p>



<pre class="wp-block-code"><code class="">%ls /workspace/model-marine-mammal-sounds/saved_model/my_model</code></pre>



<p>Then, you are able to load this model.</p>



<pre class="wp-block-code"><code class="">model = tf.keras.models.load_model('/workspace/model-marine-mammal-sounds/saved_model/my_model')</code></pre>



<p><strong>Do you want to use this model in a Streamlit app?</strong> Refer to our <a href="https://github.com/ovh/ai-training-examples/tree/main/jobs/streamlit/marine_sounds_classification_app" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer">GitHub repository</a>.</p>



<div class="wp-block-image"><figure class="aligncenter size-large"><img loading="lazy" decoding="async" width="1024" height="509" src="https://blog.ovhcloud.com/wp-content/uploads/2022/03/Capture-décran-2022-02-28-à-21.01.00-1024x509.png" alt="" class="wp-image-22553" srcset="https://blog.ovhcloud.com/wp-content/uploads/2022/03/Capture-décran-2022-02-28-à-21.01.00-1024x509.png 1024w, https://blog.ovhcloud.com/wp-content/uploads/2022/03/Capture-décran-2022-02-28-à-21.01.00-300x149.png 300w, https://blog.ovhcloud.com/wp-content/uploads/2022/03/Capture-décran-2022-02-28-à-21.01.00-768x382.png 768w, https://blog.ovhcloud.com/wp-content/uploads/2022/03/Capture-décran-2022-02-28-à-21.01.00-1536x763.png 1536w, https://blog.ovhcloud.com/wp-content/uploads/2022/03/Capture-décran-2022-02-28-à-21.01.00.png 1906w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /><figcaption>Streamlit app overview</figcaption></figure></div>



<h3 class="wp-block-heading" id="conclusion">Conclusion</h3>



<p>The accuracy of the model can be improved by increasing the number of epochs, but after a certain period we reach a threshold, so the value should be determined accordingly.<br><br>The accuracy obtained for the test set is <strong>93.71 %</strong>, which is a satisfactory result.</p>



<h4 class="wp-block-heading" id="want-to-find-out-more">Want to find out more?</h4>



<p>If you want to access the notebook, refer to the <a href="https://github.com/ovh/ai-training-examples/blob/main/notebooks/tensorflow/tuto/notebook-marine-sound-classification.ipynb" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer">GitHub repository</a>.<br><br>To launch and test this notebook with <strong>AI Notebooks</strong>, please refer to our <a href="https://docs.ovh.com/gb/en/publiccloud/ai/notebooks/" data-wpel-link="exclude">documentation</a>.</p>



<p>You can also look at this presentation done at a <a href="https://startup.ovhcloud.com/" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer">OVHcloud Startup Program</a> event at <a href="https://stationf.co/" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer">Station F</a>:</p>


<div class="lazyblock-you-tube-gdpr-compliant-Z2oJhGR wp-block-lazyblock-you-tube-gdpr-compliant"><script type="module">
  import 'https://blog.ovhcloud.com/wp-content/assets/ovhcloud-gdrp-compliant-embedding-widgets/src/ovhcloud-gdrp-compliant-youtube.js';
</script>
      
      <ovhcloud-gdrp-compliant-youtube
          video="EN7XKmPpi78"
          debug></ovhcloud-gdrp-compliant-youtube>

</div>


<p class="has-text-align-center"><em><strong>I hope you have enjoyed this article. Try for yourself!</strong></em></p>



<div class="wp-block-image"><figure class="aligncenter size-large is-resized"><img loading="lazy" decoding="async" src="https://blog.ovhcloud.com/wp-content/uploads/2022/01/IMG_0839-1024x386.png" alt="AI Notebooks: analyze and classify sounds with AI" class="wp-image-22620" width="768" height="290" srcset="https://blog.ovhcloud.com/wp-content/uploads/2022/01/IMG_0839-1024x386.png 1024w, https://blog.ovhcloud.com/wp-content/uploads/2022/01/IMG_0839-300x113.png 300w, https://blog.ovhcloud.com/wp-content/uploads/2022/01/IMG_0839-768x290.png 768w, https://blog.ovhcloud.com/wp-content/uploads/2022/01/IMG_0839.png 1219w" sizes="auto, (max-width: 768px) 100vw, 768px" /></figure></div>



<h3 class="wp-block-heading" id="references">References</h3>



<p><a href="https://blog.clairvoyantsoft.com/music-genre-classification-using-cnn-ef9461553726" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer">https://blog.clairvoyantsoft.com/music-genre-classification-using-cnn-ef9461553726</a></p>



<p><a href="https://towardsdatascience.com/music-genre-classification-with-python-c714d032f0d8" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer">https://towardsdatascience.com/music-genre-classification-with-python-c714d032f0d8</a></p>
<img loading="lazy" decoding="async" src="//blog.ovhcloud.com/wp-content/plugins/matomo/app/matomo.php?idsite=1&amp;rec=1&amp;url=https%3A%2F%2Fblog.ovhcloud.com%2Fai-notebooks-analyze-and-classify-sounds-with-ai%2F&amp;action_name=AI%20Notebooks%3A%20analyze%20and%20classify%20sounds%20with%20AI&amp;urlref=https%3A%2F%2Fblog.ovhcloud.com%2Ffeed%2F" style="border:0;width:0;height:0" width="0" height="0" alt="" />]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>OVHcloud AI Notebooks: the power of Jupyter without any compromise</title>
		<link>https://blog.ovhcloud.com/ovhcloud-ai-notebooks-the-power-of-jupyter-without-any-compromise/</link>
		
		<dc:creator><![CDATA[Bastien Verdebout]]></dc:creator>
		<pubDate>Fri, 18 Feb 2022 10:01:22 +0000</pubDate>
				<category><![CDATA[OVHcloud Engineering]]></category>
		<category><![CDATA[AI]]></category>
		<category><![CDATA[AI Notebook]]></category>
		<category><![CDATA[Jupyter]]></category>
		<guid isPermaLink="false">https://blog.ovhcloud.com/?p=21430</guid>

					<description><![CDATA[Are you using notebooks, such as Google Colab, for your business, studies or own usage? Are you reaching the maximum capabilities of this service and are looking for a simple yet powerful alternative? This blog post is for you! We will explore our own solution. Let&#8217;s be honest &#8211; Google Colab is solving many challenges. [&#8230;]<img src="//blog.ovhcloud.com/wp-content/plugins/matomo/app/matomo.php?idsite=1&amp;rec=1&amp;url=https%3A%2F%2Fblog.ovhcloud.com%2Fovhcloud-ai-notebooks-the-power-of-jupyter-without-any-compromise%2F&amp;action_name=OVHcloud%20AI%20Notebooks%3A%20the%20power%20of%20Jupyter%20without%20any%20compromise&amp;urlref=https%3A%2F%2Fblog.ovhcloud.com%2Ffeed%2F" style="border:0;width:0;height:0" width="0" height="0" alt="" />]]></description>
										<content:encoded><![CDATA[
<p><strong>Are you using notebooks, such as Google Colab</strong>, for your business, studies or own usage? Are you <strong>reaching the maximum capabilities of this service </strong>and are looking for a <strong>simple</strong> <strong>yet powerful</strong> <strong>alternative</strong>? This blog post is for you! We will explore our own solution.</p>



<figure class="wp-block-image aligncenter size-large is-resized"><img loading="lazy" decoding="async" src="https://blog.ovhcloud.com/wp-content/uploads/2022/02/IMG_0817-1024x537.jpeg" alt="OVHcloud AI Notebooks, the power of Jupyter without any compromise" class="wp-image-22495" width="512" height="269" srcset="https://blog.ovhcloud.com/wp-content/uploads/2022/02/IMG_0817-1024x537.jpeg 1024w, https://blog.ovhcloud.com/wp-content/uploads/2022/02/IMG_0817-300x157.jpeg 300w, https://blog.ovhcloud.com/wp-content/uploads/2022/02/IMG_0817-768x403.jpeg 768w, https://blog.ovhcloud.com/wp-content/uploads/2022/02/IMG_0817.jpeg 1200w" sizes="auto, (max-width: 512px) 100vw, 512px" /></figure>



<p>Let&#8217;s be honest &#8211; Google Colab is solving many challenges. It enables millions of people around the world to learn and use Python and play live with hundreds of libraries for free. It&#8217;s quite often for data-oriented use-cases &#8211; but not only. To be fair, I discovered the power of notebooks through Google Colab a long time ago.</p>



<figure class="wp-block-image aligncenter size-large"><img loading="lazy" decoding="async" width="1024" height="307" src="https://blog.ovhcloud.com/wp-content/uploads/2021/12/post.header-1024x307.png" alt="" class="wp-image-21431" srcset="https://blog.ovhcloud.com/wp-content/uploads/2021/12/post.header-1024x307.png 1024w, https://blog.ovhcloud.com/wp-content/uploads/2021/12/post.header-300x90.png 300w, https://blog.ovhcloud.com/wp-content/uploads/2021/12/post.header-768x230.png 768w, https://blog.ovhcloud.com/wp-content/uploads/2021/12/post.header.png 1280w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<h3 class="wp-block-heading" id="notebook-you-said-notebook">Notebook? You said notebook?</h3>



<p>A notebook is a document which contains code (e.g. Python code), text and images that can be read by us, humans, but also executed inside the notebook. With Jupyter app, it can be launched inside your web browser, allowing you to explore and experiment easily and share your work with many others.</p>



<p>Think of notebooks as cooking recipes that you can follow live, step-by-step and see the result directly. It&#8217;s truly wonderful.</p>



<p>Now imagine notebooks that can be linked to remote power and storage to perform your use cases at scale. That&#8217;s it 😀</p>



<p></p>



<figure class="wp-block-image aligncenter size-large"><img loading="lazy" decoding="async" width="1024" height="660" src="https://blog.ovhcloud.com/wp-content/uploads/2021/12/post.0-1024x660.png" alt="" class="wp-image-21432" srcset="https://blog.ovhcloud.com/wp-content/uploads/2021/12/post.0-1024x660.png 1024w, https://blog.ovhcloud.com/wp-content/uploads/2021/12/post.0-300x193.png 300w, https://blog.ovhcloud.com/wp-content/uploads/2021/12/post.0-768x495.png 768w, https://blog.ovhcloud.com/wp-content/uploads/2021/12/post.0.png 1466w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /><figcaption><em>Example of Jupyter notebook</em></figcaption></figure>



<h3 class="wp-block-heading" id="offers-like-google-colab-are-nice-but-limited">Solutions like Google Colab are nice, but limited</h3>



<p>There are plenty of managed notebook solutions on the market today. The market is split in two &#8211; complicated solutions inside cloud providers (AWS Sagemaker, Google AI Platform Notebooks, Azure ML Notebooks&#8230;) and pure players trying to bring notebooks to the masses. The main actor in this field is Google Colab.</p>



<p>Historically, Google Colab is based on Jupyterlab, and forked from this awesome open source project few years ago (source: <a href="https://research.google.com/colaboratory/faq.html" target="_blank" rel="noreferrer noopener nofollow external" data-wpel-link="external">their FAQ</a>).</p>



<p>Since mid-2021, they now provide 3 plans in 9 countries, from free to paid (Pro and Pro +).</p>



<p>After browsing their website and FAQ, I drafted this comparative table:</p>



<figure class="wp-block-image aligncenter size-large"><img loading="lazy" decoding="async" width="1024" height="578" src="https://blog.ovhcloud.com/wp-content/uploads/2021/12/post.1-1024x578.png" alt="" class="wp-image-21433" srcset="https://blog.ovhcloud.com/wp-content/uploads/2021/12/post.1-1024x578.png 1024w, https://blog.ovhcloud.com/wp-content/uploads/2021/12/post.1-300x169.png 300w, https://blog.ovhcloud.com/wp-content/uploads/2021/12/post.1-768x433.png 768w, https://blog.ovhcloud.com/wp-content/uploads/2021/12/post.1.png 1127w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /><figcaption><em>Comparative table between Google Colab </em>and OVHcloud AI Notebooks</figcaption></figure>



<p>If you are a student or an individual, Google Colab is ideal for you, as most pricing plans contain the basic features you need for exploring this magic world of data. That&#8217;s cool.</p>



<p><strong>But once you are working on more intensive projects</strong>, you may reach Colab limitations:</p>



<ul class="wp-block-list"><li><strong>Compute resources are not guaranteed</strong>: for example, you don&#8217;t know exactly how long and how much you will have GPU power or RAM memory. This is very critical when timing is important (and reproducibility)</li><li><strong>You cannot chose which GPU model will be used</strong>: it might be a good one, or an old one like K80</li><li><strong>No background execution except in Pro+</strong>: you cannot close your internet browser, or it will automatically stop your work</li><li><strong>Maximum 24 hours time of execution</strong>: if you&#8217;re running intensive trainings, it&#8217;s a serious limitation</li><li><strong>Not official JupyterLab version</strong>: the live code editor is based on Jupyterlab, but not the exact open source one. You have some features missing</li><li><strong>Unavailable in multiple countries</strong>: quoting their FAQ, <em>&#8220;For now, both Colab Pro and Pro+ are only available in the following countries: United States, Canada, Japan, Brazil, Germany, France, India, United Kingdom, and Thailand&#8221;</em></li><li><strong>Requires acceptance of Google ToS</strong>: when you use Google Colab, you need to fully accept the <a href="https://colab.research.google.com/pro/terms" target="_blank" rel="noreferrer noopener nofollow external" data-wpel-link="external">Google terms of services</a> and privacy policy. Read them carefully 😃</li></ul>



<p>Seeing their pricing, it&#8217;s fully understandable to put some limits.</p>



<p>But what can you do if you want more?</p>



<h3 class="wp-block-heading" id="good-news-everyone-you-have-some-simple-alternatives">Good news everyone! You have some (simple) alternatives</h3>



<p>We are a <strong>European company</strong>, and if I&#8217;m correct, <strong>the only one to provide managed notebooks in the cloud with GPU power at scale. </strong>We released OVHcloud AI Notebooks a few months ago and it&#8217;s really exciting to solve people&#8217;s challenges. Based on the current usage, it&#8217;s clearly a success (thumbs up to the team behind this new product!).</p>



<p><strong>AI Notebooks = European legislation, guaranteed resources, back-end execution, native Jupyterlab or VSCode editor, no maximum running time, available everywhere&#8230;</strong> <strong>and yet it&#8217;s also simple to use.</strong></p>



<p>Go back to the comparative table. You&#8217;ll see that we solve many blockers 😃.</p>



<p>To explain further, <strong>I&#8217;ve made a short video </strong>where I start in Google Colab and migrate my work in OVHcloud AI Notebooks. I took my time, explained everything and it lasts 8 minutes. If i wanted to automate it, it should take +-10 seconds.</p>



<figure class="wp-block-embed is-type-video is-provider-vimeo wp-block-embed-vimeo wp-embed-aspect-16-9 wp-has-aspect-ratio"><div class="wp-block-embed__wrapper">
<iframe loading="lazy" title="Alternative to Google Colab : learn how to move to OVHcloud  AI Notebooks" src="https://player.vimeo.com/video/651935109?h=cbc3d0ba32&amp;dnt=1&amp;app_id=122963" width="1200" height="675" frameborder="0" allow="autoplay; fullscreen; picture-in-picture" allowfullscreen></iframe>
</div><figcaption><em>Video tutorial to migrate from Google Colab to AI Notebooks</em></figcaption></figure>



<h3 class="wp-block-heading" id="want-to-give-a-try-fearing-it-s-too-expensive">Want to give it a try? Fearing it&#8217;s too expensive?</h3>



<p>O<a href="https://www.ovhcloud.com/fr/public-cloud/prices/#5260" target="_blank" rel="noreferrer noopener nofollow external" data-wpel-link="external">ur pricing is quite simple</a>: you don&#8217;t pay per month, you pay what you consume.</p>



<p>1 CPU is 0,03€ per hour, 1 NVIDIA V100S GPU is 1,75€ per hour.</p>



<p>If you use a notebook with 2 CPUs during 24 hours, it will cost 1,44 euro (0,03 x 2 x 24h).</p>



<p>It&#8217;s more expensive compared to Google Colab plans, however it&#8217;s not exactly the same product. OVHcloud AI Notebooks offers managed notebooks in the cloud, but with less limitations (our real competitors are AWS Sagemaker or Google AI Platforms).</p>



<p>And we support startups and research! If you are interested, <a href="https://startup.ovhcloud.com/" target="_blank" rel="noreferrer noopener nofollow external" data-wpel-link="external">reach our startup program</a> where the whole <strong>OVHcloud Public Cloud ecosystem is included (AI tools, K8s, storage, &#8230;) up to 100&#8217;000 euros.</strong></p>



<p>We also do some philanthropy for<strong> schools</strong>, <strong>open source projects</strong>&#8230; contact us!</p>



<p>Thanks for reading 😃</p>
<img loading="lazy" decoding="async" src="//blog.ovhcloud.com/wp-content/plugins/matomo/app/matomo.php?idsite=1&amp;rec=1&amp;url=https%3A%2F%2Fblog.ovhcloud.com%2Fovhcloud-ai-notebooks-the-power-of-jupyter-without-any-compromise%2F&amp;action_name=OVHcloud%20AI%20Notebooks%3A%20the%20power%20of%20Jupyter%20without%20any%20compromise&amp;urlref=https%3A%2F%2Fblog.ovhcloud.com%2Ffeed%2F" style="border:0;width:0;height:0" width="0" height="0" alt="" />]]></content:encoded>
					
		
		
			</item>
	</channel>
</rss>
