From e94daf652719cfab07776f4c506f3dbeda70d587 Mon Sep 17 00:00:00 2001 From: Wendy V Gaultier Date: Fri, 27 Oct 2023 17:54:39 +0000 Subject: [PATCH] Pipelines --- docs/en/3-Pipelines/Argo.md | 4 +- docs/en/3-Pipelines/PaaS.md | 18 - docs/fr/3-Pipelines/Argo.md | 383 ++++++++ docs/fr/3-Pipelines/Kubeflow-Pipelines.md | 256 ------ .../Machine-Learning-Model-Cloud-Storage.md | 61 -- .../Machine-Learning-Model-Serving.md | 39 - .../Machine-Learning-Training-Pipelines.md | 821 ------------------ docs/fr/3-Pipelines/Machine-Learning.md | 369 -------- docs/fr/3-Pipelines/Overview.md | 17 - docs/fr/3-Pipelines/PaaS-Integration.md | 52 -- docs/fr/3-Pipelines/PaaS.md | 12 - docs/fr/3-Pipelines/Serving.md | 18 - .../3-Pipelines/sklearn_iris_jsondata.ipynb | 524 ----------- docs/fr/images/argo-workflows.jpg | Bin 0 -> 60271 bytes docs/fr/images/argo.png | Bin 0 -> 87565 bytes mkdocs-fr.yml | 4 +- 16 files changed, 386 insertions(+), 2192 deletions(-) delete mode 100644 docs/en/3-Pipelines/PaaS.md create mode 100644 docs/fr/3-Pipelines/Argo.md delete mode 100644 docs/fr/3-Pipelines/Kubeflow-Pipelines.md delete mode 100644 docs/fr/3-Pipelines/Machine-Learning-Model-Cloud-Storage.md delete mode 100644 docs/fr/3-Pipelines/Machine-Learning-Model-Serving.md delete mode 100644 docs/fr/3-Pipelines/Machine-Learning-Training-Pipelines.md delete mode 100644 docs/fr/3-Pipelines/Machine-Learning.md delete mode 100644 docs/fr/3-Pipelines/Overview.md delete mode 100644 docs/fr/3-Pipelines/PaaS-Integration.md delete mode 100644 docs/fr/3-Pipelines/PaaS.md delete mode 100644 docs/fr/3-Pipelines/Serving.md delete mode 100644 docs/fr/3-Pipelines/sklearn_iris_jsondata.ipynb create mode 100644 docs/fr/images/argo-workflows.jpg create mode 100644 docs/fr/images/argo.png diff --git a/docs/en/3-Pipelines/Argo.md b/docs/en/3-Pipelines/Argo.md index 45ab86835..59fa75824 100644 --- a/docs/en/3-Pipelines/Argo.md +++ b/docs/en/3-Pipelines/Argo.md @@ -7,7 +7,7 @@ Full documentation can be found [here](https://argoproj.github.io/argo-workflows/walk-through/). -Argo Workflows allows you to +Argo Workflows have these advantages: - Workflow tasks can be defined as scripts (ex. python) or be containerized (ex. docker). - Complex workflows can be modeled using Directed Acyclic graphs (DAGs) to capture dependency chains. @@ -158,7 +158,7 @@ Use the following `Dockerfile` as a starting point for your `R` and `Python` pro #### 3. Write your workflow in YAML -YAML is Yet Another Markup Language and you'll need to write down the steps of your training pipeline in an Argo Workflows YAML file. This file should include reference to the Dockerfile you created in [Step 1](#2-write-a-dockerfile-to-run-your-code), as well as any input data and output data you'll be working with. +YAML is Yet Another Markup Language and you'll need to write down the steps of your training pipeline in an Argo Workflows YAML file. This file should include reference to the Dockerfile you created in [Step 2](#2-write-a-dockerfile-to-run-your-code), as well as any input data and output data you'll be working with. Here is an example YAML file for a simple machine learning pipeline that trains a logistic regression model on the iris dataset. The only real difference between the `Python` and `R` versions is the command `command: ["python", "train.py"]` vs `command: ["Rscript", "train.R"]` and the models are stored in different formats, `pkl` for `python` and `rds` for `R`. diff --git a/docs/en/3-Pipelines/PaaS.md b/docs/en/3-Pipelines/PaaS.md deleted file mode 100644 index 663e84195..000000000 --- a/docs/en/3-Pipelines/PaaS.md +++ /dev/null @@ -1,18 +0,0 @@ -# Overview - -## Integrate with Platforms like Databricks and AzureML - -The AAW platform is built around the idea of integrations, and so we can -integrate with many _Platform as a Service_ (PaaS) offerings, such as -[Azure ML](https://azure.microsoft.com/en-us/services/machine-learning/) and -[Databricks](https://azure.microsoft.com/en-ca/services/databricks/). - -See some examples on our -["MLOps" github Repo](https://github.com/StatCan/aaw-kubeflow-mlops). - -![PaaS](../images/PaaS.png) - -# Setup - -If you need help integrating with a platform as a service offering, we're happy -to help! diff --git a/docs/fr/3-Pipelines/Argo.md b/docs/fr/3-Pipelines/Argo.md new file mode 100644 index 000000000..f33060ea3 --- /dev/null +++ b/docs/fr/3-Pipelines/Argo.md @@ -0,0 +1,383 @@ + +## Flux de travail Argo + +![Logo calmar Argo Workflows](../images/argo.png) + +**[Flux de travail Argo](https://argoproj.github.io/argo-workflows/)** est un moteur de flux de travail open source natif de conteneur pour orchestrer des tâches parallèles sur Kubernetes. Les flux de travails Argo sont implémentés en tant que Kubernetes CRD (Custom Resource Definition). Il est particulièrement adapté aux flux de travail de science des données et aux flux de travail d’apprentissage automatique. + +La documentation complète peut être trouvée [ici](https://argoproj.github.io/argo-workflows/walk-through/). + +Les flux de travails Argo ont les avantages suivants: + +- Les tâches de workflow peuvent être définies sous forme de scripts (ex. Python) ou être conteneurisées (ex. Docker). +- Des flux de travail complexes peuvent être modélisés à l'aide de graphes acycliques dirigés (DAG) pour capturer les chaînes de dépendance. +- Les tâches indépendantes peuvent être exécutées en parallèle avec une granularité jusqu'au niveau de mise en œuvre, réduisant ainsi les charges de tâches chronophages. +- Agnositique de la plateforme Kubernetes, ce qui signifie que votre travail est très portable. + +Avec les flux de travails Argo, vous pouvez facilement créer des flux de travails qui intègrent des tâches telles que des constructions et des déploiements automatisés, le prétraitement des données, la formation de modèles et le déploiement de modèles, le tout dans un environnement Cloud Native Kubernetes. + + +!!! info "" +
+ [![Diagramme de flux de travail Argo](../images/argo-workflows.jpg)](https://argoproj.github.io/argo-workflows/) +

Flux de travail Argo

+
+ +Vous trouverez ci-dessous un exemple de cas d'utilisation de flux de travail Argo, dans lequel nous formons un modèle d'apprentissage automatique à l'aide des flux de travail Argo sur AAW. + +#### 1. Écrivez un script pour entraîner votre modèle + +Voici un exemple de script qui entraîne un modèle de régression logistique sur l'ensemble de données iris. N'oubliez pas de consulter le code de chaque langue ci-dessous. + +=== "Python" + + ``` python title="train.py" linenums="1" + #!/usr/bin/env python + + # Importer les bibliothèques nécessaires + import argparse + import pandas as pd + from sklearn.datasets import load_iris + from sklearn.linear_model import LogisticRegression + from sklearn.model_selection import train_test_split + from sklearn.metrics import accuracy_score + import joblib + + # Analyser les arguments d'entrée + parser = argparse.ArgumentParser(description="Train logistic regression model on iris dataset.") + parser.add_argument("--input", default="iris.csv", help="Path to input dataset file.") + parser.add_argument("--output", default="model.pkl", help="Path to output model file.") + args = parser.parse_args() + + # Charger l'ensemble de données d'iris + data = load_iris() + X, y = data.data, data.target + + # Divisez les données en ensembles d'entraînement et de test + X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42) + + # Entraîner un modèle de régression logistique + clf = LogisticRegression(random_state=42) + clf.fit(X_train, y_train) + + # Évaluer le modèle sur l'ensemble de test + y_pred = clf.predict(X_test) + accuracy = accuracy_score(y_test, y_pred) + print("Accuracy:", accuracy) + + # Enregistrer le modèle dans un fichier + joblib.dump(clf, args.output) + ``` + +=== "R" + + ``` r title="train.R" linenums="1" + #!/usr/bin/env Rscript + + # Importer les bibliothèques nécessaires + library(caret) + + # Copier les arguments d'entrée + args <- commandArgs(trailingOnly = TRUE) + input_file <- ifelse(length(args) > 0, args[1], "iris.csv") + output_file <- ifelse(length(args) > 1, args[2], "model.rds") + + # Charger l'ensemble de données d'iris + data(iris) + X <- iris[, 1:4] + y <- iris[, 5] + + # Divisez les données en ensembles d'entraînement et de test + set.seed(42) + train_index <- createDataPartition(y, p = 0.8, list = FALSE) + X_train <- X[train_index, ] + y_train <- y[train_index] + X_test <- X[-train_index, ] + y_test <- y[-train_index] + + # Entraîner un modèle de régression logistique + clf <- train(x = X_train, y = y_train, method = "glm") + + # Évaluer le modèle sur l'ensemble de test + y_pred <- predict(clf, newdata = X_test) + accuracy <- confusionMatrix(y_pred, y_test)$overall["Accuracy"] + print(paste0("Accuracy: ", accuracy)) + + # Enregistrer le modèle dans un fichier + saveRDS(clf, output_file) + ``` +#### 2. Écrivez un Dockerfile pour exécuter votre code + +Vous aurez besoin d'un Dockerfile qui inclut toutes les dépendances nécessaires pour entraîner votre modèle d'apprentissage automatique. Cela pourrait inclure: + +- des paquets comme + - `scikit-learn`, `pandas` ou `numpy` si vous utilisez `Python` + - `caret`, `janitor` et `tidyverse` si vous utilisez `R` +- vos propres bibliothèques ou scripts personnalisés +- le code de votre modèle d'apprentissage automatique sous la forme d'un script [comme dans l'exemple ci-dessus](#1-ecrivez-un-script-pour-entrainer-votre-modele). + +Utilisez le `Dockerfile` suivant comme point de départ pour vos projets `R` et `Python`. + +=== "Python" + + ``` docker title="Dockerfile" linenums="1" + FROM python:3.8-slim-buster + + # Installez toutes les dépendances nécessaires + RUN pip install --no-cache-dir scikit-learn pandas numpy + + # Définir le répertoire de travail + WORKDIR /app + + # Copier le code dans le conteneur + COPY train.py . + + # Définir le point d'entrée + ENTRYPOINT ["python", "train.py"] + ``` + +=== "R" + ``` docker title="Dockerfile" linenums="1" + FROM rocker/r-base:latest + + RUN apt-get update && apt-get install -y --no-install-recommends \ + libssl-dev \ + libcurl4-openssl-dev \ + libxml2-dev \ + && apt-get clean \ + && rm -rf /var/lib/apt/lists/* + + RUN R -e 'install.packages(c("caret", "janitor", "tidyverse"))' + + COPY train.R /app/train.R + + WORKDIR /app + + ENTRYPOINT ["Rscript", "train.R"] + ``` + +#### 3. Écrivez votre flux de travail en YAML + +YAML est encore un autre langage de balisage et vous devrez écrire les étapes de votre pipeline de formation dans un fichier YAML Argo Workflows. Ce fichier doit inclure une référence au Dockerfile que vous avez créé à l'[Étape 1](#2-ecrivez-un-dockerfile-pour-executer-votre-code), ainsi que toutes les données d'entrée et de sortie avec lesquelles vous travaillerez. + +Voici un exemple de fichier YAML pour un pipeline d'apprentissage automatique simple qui entraîne un modèle de régression logistique sur l'ensemble de données iris. La seule vraie différence entre les versions `Python` et `R` est la commande `command: ["python", "train.py"]` vs `command: ["Rscript", "train.R"]` et le les modèles sont stockés dans différents formats, `pkl` pour `python` et `rds` pour `R`. + +Le fichier YAML définit une seule étape appelée `train` qui exécute un script appelé `train.py` ou `train.R` dans l'image Docker `machine-learning:v1`. Le script prend un fichier d'ensemble de données d'entrée, spécifié par un paramètre appelé `dataset`, et génère un fichier de modèle entraîné vers un artefact de sortie appelé `model.pkl` ou `model.rds` selon le langage utilisé. + +=== "Python" + ``` yaml title="workflow.yaml" linenums="1" + apiVersion: argoproj.io/v1alpha1 + kind: Workflow + metadata: + generateName: ml-pipeline- + spec: + entrypoint: train + templates: + - name: train + container: + image: machine-learning:v1 + command: ["python", "train.py"] + args: ["--input", "{{inputs.parameters.dataset}}", "--output", "{{outputs.artifacts.model}}"] + inputs: + parameters: + - name: dataset + default: "iris.csv" + outputs: + artifacts: + - name: model + path: /output/model.pkl + ``` +=== "R" + ``` yaml title="workflow.yaml" linenums="1" + apiVersion: argoproj.io/v1alpha1 + kind: Workflow + metadata: + generateName: ml-pipeline- + spec: + entrypoint: train + templates: + - name: train + container: + image: machine-learning:v1 + command: ["Rscript", "train.R"] + args: ["--input", "{{inputs.parameters.dataset}}", "--output", "{{outputs.artifacts.model}}"] + inputs: + parameters: + - name: dataset + default: "iris.csv" + outputs: + artifacts: + - name: model + path: /output/model.rds + ``` + +#### 4. Soumettez le flux de travail à l'aide de l'entrée de ligne de commande(CLI) du flux de travail Argo + +Pour exécuter le flux de travail ci-dessus, vous devrez d'abord envoyer le Dockerfile vers notre registre de conteneurs, puis soumettre le fichier YAML à l'aide de la commande `argo submit`. Une fois le pipeline terminé, vous pouvez récupérer le fichier de modèle entraîné en téléchargeant l'artefact de sortie à partir de la commande `argo logs`. + +``` bash title="Terminal" +$ argo submit workflow.yaml # soumettre une spécification de flux de travail à Kubernetes +``` + +Il est également possible de soumettre des workflows argo à partir des workflows à l'aide de SDK et d'appels API (c'est juste un autre service Web !). Voir cette [section](#exemples-utilisant-des-sdk-bases-sur-flux-de-travail-argo). + +#### 5. Surveillez le pipeline à l'aide de la CLI du flux de travail Argo + +Pendant l'exécution du pipeline, vous pouvez surveiller sa progression à l'aide de la CLI Argo Workflows. Cela vous montrera quelles étapes se sont terminées avec succès et lesquelles sont toujours en cours. Vous trouverez ci-dessous quelques commandes utiles. Pour plus d'informations sur la CLI Argo Workflows, veuillez consulter [la documentation officielle de la CLI Argo Workflows](https://argoproj.github.io/argo-workflows/walk-through/argo-cli/) . + +``` bash title="Terminal" +$ argo list # lister les flux de travail actuels +$ argo get workflow-xxx # obtenir des informations sur un flux de travail spécifique +$ argo logs workflow-xxx # imprimer les journaux d'un flux de travail +$ argo delete workflow-xxx # suprimer un flux de travail + +``` + +#### 6. Récupérer le modèle entraîné + +Une fois la pipeline terminé, vous pouvez récupérer les données de sortie à l'aide de la commande argo logs ou en affichant les artefacts de sortie à l'aide de la CLI, c'est-à-dire accéder au répertoire que vous avez spécifié dans votre script et localiser le fichier `model.pkl` ou `model.rds`. L'extrait de code suivant, extrait du [script de formation ci-dessus](#1-ecrivez-un-script-pour-entrainer-votre-modele), indique au langage de programmation respectif où enregistrer le modèle entraîné. + +=== "Python" + + ``` python title="Saving Output Data" linenums="1" + #!/usr/bin/env python + + parser.add_argument("--output", default="model.pkl", help="Path to output model file.") + + # Enregistrer le modèle dans un fichier + joblib.dump(clf, args.output) + ``` + +=== "R" + + ``` r title="Saving Output Data" linenums="1" + #!/usr/bin/env Rscript + + output_file <- ifelse(length(args) > 1, args[2], "model.rds") + + # Enregistrer le modèle dans un fichier + saveRDS(clf, output_file) + ``` + +### Exemples utilisant des SDK basés sur flux de travail Argo + +Argo prend en charge les [bibliothèques client](https://argoproj.github.io/argo-workflows/client-libraries/), générées automatiquement et gérées par la communauté, qui incluent les SDK Java et Python. + +Si vous préférez utiliser un cadres de niveau supérieur, alors `Couler` et `Hera` sont des alternatives bien adaptées. Ces cadress rendent la création et la gestion de flux de travail complexes plus accessibles à un public plus large. + +#### Hera + +Hera vise à simplifier le processus de création et de soumission de flux de travail en éliminant de nombreux détails techniques via une interface de programmation d'application simple. Il utilise également un ensemble cohérent de terminologie et de concepts qui s'alignent sur les flux de travail Argo, permettant aux utilisateurs d'apprendre et d'utiliser plus facilement les deux outils ensemble. + +#### Couler + +Couler fournit une interface de programmation d'applications simple et unifiée pour définir des flux de travail à l'aide d'un style de programmation impératif. Il construit également automatiquement des graphiques acycliques dirigés (DAG) pour les flux de travail, ce qui peut contribuer à simplifier le processus de création et de gestion de ceux-ci. + +=== "Couler" + ``` py title="couler.py" linenums="1" + #!/usr/bin/env python + + # Préparez votre système + !pip config --user set global.index-url https://jfrog.aaw.cloud.statcan.ca/artifactory/api/pypi/pypi-remote/simple + !python3 -m pip install git+https://github.com/couler-proj/couler --ignore-installed + + # Définir une variable globale pour plus de commodité + NAMESPACE = "" + + # Importer les packages nécessaires + import json + import random + + import couler.argo as couler + from couler.argo_submitter import ArgoSubmitter + + + # Définir les étapes (fonctions) utilisées dans le workflow + def random_code(): + import random + res = "heads" if random.randint(0, 1) == 0 else "tails" + print(res) + + + def flip_coin(): + return couler.run_script( + image="k8scc01covidacr.azurecr.io/ubuntu", + source=random_code + ) + + + def heads(): + return couler.run_container( + image="k8scc01covidacr.azurecr.io/ubuntu", + command=["sh", "-c", 'echo "it was heads"'] + ) + + + def tails(): + return couler.run_container( + image="k8scc01covidacr.azurecr.io/ubuntu", + command=["sh", "-c", 'echo "it was tails"'] + ) + + + result = flip_coin() + + couler.when(couler.equal(result, "heads"), lambda: heads()) + couler.when(couler.equal(result, "tails"), lambda: tails()) + + submitter = ArgoSubmitter(namespace="NAMESPACE") + result = couler.run(submitter=submitter) + + print(json.dumps(result, indent=2)) + ``` +=== "Hera" + ``` py title="hera.py" linenums="1" + #!/usr/bin/env python + + # Préparez votre système + !pip config --user set global.index-url https://jfrog.aaw.cloud.statcan.ca/artifactory/api/pypi/pypi-remote/simple + !pip install hera-workflows + + # Importer les packages nécessaires + import hera + from hera import Task, Workflow + + # Configurer Hera + hera.global_config.GlobalConfig.token = "" + hera.global_config.GlobalConfig.host = "https://argo-workflows.aaw-dev.cloud.statcan.ca:443" + hera.global_config.GlobalConfig.namespace = "" + hera.global_config.GlobalConfig.service_account_name = "" + + + # Définir les étapes (fonctions) utilisées dans le workflow + def random_code(): + res = "heads" if random.randint(0, 1) == 0 else "tails" + print(res) + + + def heads(): + print("it was heads") + + + def tails(): + print("it was tails") + + # Définir le flux de travail + with Workflow("coin-flip") as w: + r = Task("r", random_code) + h = Task("h", heads) + t = Task("t", tails) + + h.on_other_result(r, "heads") + t.on_other_result(r, "tails") + + # Exécuter le flux de travail + w.create() + ``` + +### Ressources supplémentaires pour les flux de travail Argo + +Des exemples de flux de travail Argo peuvent être trouvés dans les référentiels Github suivants : + +- [Documentation des workflows Argo](https://argoproj.github.io/argo-workflows/) +- [Référence Argo CLI](https://argoproj.github.io/argo-workflows/walk-through/argo-cli/) diff --git a/docs/fr/3-Pipelines/Kubeflow-Pipelines.md b/docs/fr/3-Pipelines/Kubeflow-Pipelines.md deleted file mode 100644 index 31534fa06..000000000 --- a/docs/fr/3-Pipelines/Kubeflow-Pipelines.md +++ /dev/null @@ -1,256 +0,0 @@ -# Vue d'ensemble - -Kubeflow Pipelines est une plateforme de création de flux de production -d'apprentissage automatique pouvant être déployés dans un environnement -Kubernetes. Il permet de créer des pipelines qui encapsulent les flux de -production analytiques (transformation de données, modèles de formation, -construction d'éléments visuels, etc.). Ces pipelines peuvent être mis en -commun, réutilisés et programmés. Ils sont créés de façon à être exécutés avec -les calculs fournis par Kubernetes. - -Dans le contexte de l'espace de travail en analytique avancée, vous pouvez -interagir avec les pipelines Kubeflow par l'entremise : - -- de [l'interface utilisateur](../1-Experiences/Kubeflow.md) de Kubeflow, où, à - partir du menu Pipelines, vous pouvez télécharger des pipelines, visualiser - les pipelines que vous possédez et leurs résultats, etc. - -- de la trousse [SDK](https://www.kubeflow.org/docs/pipelines/sdk/sdk-overview/) - en Python de Kubeflow Pipelines, accessible dans les serveurs de bloc-notes - Jupyter, où vous pouvez définir vos composants et pipelines, les soumettre - pour les exécuter immédiatement, ou même les enregistrer pour plus tard. - - -??? exemple "Des exemples supplémentaires dans les bloc-notes" - Des exemples plus exhaustifs de pipelines produits expressément pour cette - plateforme sont accessibles dans - [GitHub](https://github.com/StatCan/aaw-contrib-jupyter-notebooks) (et dans chaque - serveur de bloc-notes à `/jupyter-notebooks`). Vous pouvez également - consulter des sources publiques. - -Voyez -[le documentation officiel de Kubeflow](https://www.kubeflow.org/docs/pipelines/overview/pipelines-overview/) -pour obtenir une explication générale détaillée de Kubeflow. - -![Un pipeline Kubeflow](../images/kf-pipeline_with_result.png) - -# Qu'est-ce qu'un pipeline et comment fonctionne-t-il? - -Dans Kubeflow Pipelines, un pipeline comprend un ou plusieurs composants de -pipeline enchaînés pour former un flux de production. Les composants sont comme -des fonctions que le pipeline connecte ensemble. - -Le _pipeline_ décrit l'ensemble du flux de production de ce que vous souhaitez -accomplir, tandis que les _composants de pipeline_ décrivent chacune des étapes -distinctes de ce processus (comme le fait d'extraire des colonnes d'un stock de -données, de transformer des données ou d'entraîner un modèle). Chaque -**composant** doit être **modulaire** et idéalement **réutilisable**. - -Essentiellement, chaque _composant_ a : - -- une application autonome, présentée sous forme d'image de menu fixe - (https://docs.docker.com/get-started/), pour effectuer le travail proprement - dit .le code dans l'image de menu fixe peut être une séquence de commandes en - langage naturel, un script Python ou tout autre code pouvant être exécuté à - partir d'un terminal Linux -- une description de la manière dont Kubeflow Pipelines exécute le code - (l'emplacement de l'image, les arguments de la ligne de commande qu'il - accepte, les résultats qu'il produit), sous forme de fichier YAML. - -Un _pipeline_ définit ensuite la logique de connexion des composants, par -exemple : - -1. Exécuter `ComposantA` -2. transmettre le résultat du `ComposantA` au `ComposantB` et au `ComposantC` -3. ... - - -!!! example "Exemple d'un pipeline" - Voici un exemple : - - #!/bin/python3 - dsl.pipeline(name="Estimer Pi", - description="Estimer Pi au moyen d'un modèle Map-Reduce") - def compute_pi(): - # Créer un "exemple" d'opération pour chaque valeur de départ - # transmise au pipeline - seeds = (1,2,3,4,5,6,7,8,9,10) - sample_ops = [sample_op(seed) for seed in seeds] - - # Obtenir les résultats avant de les transmettre à deux pipelines - # distincts. Les résultats sont extraits des fichiers - # `output_file.json` et sont disponibles à partir des instances - # `sample_op` par l'entremise de l'attribut `.outputs`. - outputs = [s.outputs['output'] for s in sample_ops] - - _generate_plot_op = generate_plot_op(outputs) - _average_op = average_op(outputs) - - Vous pouvez trouver le pipeline complet dans - [l'exemple `map-reduce-pipeline`](https://github.com/StatCan/aaw-contrib-jupyter-notebooks). - -# Définir et exécuter votre premier pipeline - -Bien que les _pipelines_ et les _composants_ soient définis par des fichiers -YAML, la trousse -[SDK](https://www.kubeflow.org/docs/pipelines/sdk/sdk-overview/) en Python vous -permet de les définir à partir du code Python. Voici un exemple de définition -d'un -[pipeline simple](https://github.com/StatCan/aaw-contrib-jupyter-notebooks/blob/master/kfp-basics/average_with_docker_components.ipynb) -en utilisant la trousse SDK en Python. - -L'objectif de notre pipeline est de calculer, au moyen de cinq nombres, les -valeurs suivantes : - -1. la moyenne des trois premiers nombres; -2. la moyenne des deux derniers nombres; -3. la moyenne des résultats de (1) et de (2). - -Pour ce faire, nous définissons un _pipeline_ qui utilise notre _composant_ -moyen pour effectuer les calculs. - -Le composant moyen est défini par une image de menu fixe au moyen d'un script -Python qui : - -- accepte un ou plusieurs nombres comme arguments de ligne de commande -- renvoie la moyenne de ces nombres, enregistrée dans le fichier `out.txt` dans - son conteneur. - -Pour indiquer à Kubeflow Pipelines comment utiliser cette image, nous -définissons notre _composant_ moyen par l'entremise d'un `ContainerOp`, qui -indique à Kubeflow l'interface API de notre image. L'instance `ContainerOp` -définit l'emplacement de l'image du menu fixe, la façon de lui transmettre des -arguments et les résultats à extraire du conteneur. Pour utiliser réellement ces -`ContainerOp` dans notre pipeline, nous créons des fonctions de fabrique comme -`average_op` (car nous voudrons probablement plus d'un _composant_ moyen). - -```python -from kfp import dsl - -def average_op(\*numbers): - """ Fabrique de ContainerOp moyen - - Accepte un nombre arbitraire de nombres d'entrée, en renvoyant un ContainerOp - qui transmet ces nombres à l'image du menu fixe sous-jacent pour faire la - moyenne - - Renvoie le résultat recueilli à partir du fichier ./out.txt à l'intérieur du - conteneur - - """ - - # Validation d'entrée - - if len(numbers) < 1: - raise ValueError("Doit préciser au moins un nombre à partir duquel calculer la moyenne") - - return dsl.ContainerOp( - name="averge", # Élément affiché dans la visionneuse de pipeline - image="k8scc01covidacr.azurecr.io/kfp-components/average:v1", # L'image - exécutée par Kubeflow Pipelines pour faire le travail arguments=numbers, - #transmet chaque nombre comme un argument de ligne de commande (chaîne) distinct - # Le script à l'intérieur du conteneur enregistre le résultat (sous forme de chaîne de caractères) dans le fichier out.txt, que - # Kubeflow Pipelines lit pour nous et récupère sous forme de chaîne. - file_outputs={'data': './out.txt'}, - ) -``` - -Nous définissons notre pipeline comme une fonction Python qui utilise les -fabriques de `ComponentOp` ci-dessus, décorées par l'élément décoratif -`@dsl.pipeline`. Notre pipeline utilise notre composant _moyen_ en lui -transmettant des nombres. Puis, nous utilisons les résultats _moyens_ en les -transmettant à des fonctions plus tard par l'accès à `avg\_\*.output`. - -```python -@dsl.pipeline( - name="nom de mon pipeline" -) -def my_pipeline(a, b, c, d, e): - """ - Calcul de moyenne de pipeline, qui accepte cinq nombres et effectue quelques calculs de moyenne sur ceux-ci - """ - - # Calculer les moyennes pour deux groupes - - avg_1 = average_op(a, b, c) - avg_2 = average_op(d, e) - - # Utiliser les résultats de \_1 et de \_2 pour calculer une moyenne globale - - average_result_overall = average_op(avg_1.output, avg_2.output) -``` - -Enfin, nous enregistrons une définition YAML de notre pipeline pour la -transmettre plus tard à Kubeflow Pipelines. Ce fichier YAML décrit à Kubeflow -Pipelines exactement comment exécuter notre pipeline. Décompressez-le et voyez -par vous-même! - -```python -from kfp import compiler -pipeline_yaml = 'pipeline.yaml.zip' -compiler.Compiler().compile( - my_pipeline, - pipeline_yaml -) print(f"Définition de pipeline exportée vers {pipeline_yaml}") -``` - - -??? avertissement "Kubeflow Pipelines est une bête paresseuse". - Il est utile de garder à l'esprit le calcul qui se produit lorsque vous - exécutez ce code Python par rapport à ce qui se passe lorsque vous soumettez - le pipeline à Kubeflow Pipelines. Bien que tout semble se produire - instantanément, essayez d'ajouter `print(avg_1.output)` au pipeline - ci-dessus et voyez ce qui se passe lorsque vous compilez votre pipeline. La - trousse SDK en Python que nous utilisons sert à créer des pipelines, et non - à les exécuter, de sorte que les résultats des composants ne seront jamais - disponibles lorsque vous exécuterez ce code Python. Ce point est abordé plus - en détail plus loin, dans la section _Comprendre l'ordre des calculs_. - -Pour exécuter notre pipeline, nous définissons une expérience : - -```python -experiment_name = "calcul de moyenne de pipeline" - -import kfp -client = kfp.Client() -exp = client.create_experiment(name=experiment_name) - -pl_params = { 'a': 5, 'b': 5, 'c': 8, 'd': 10, 'e': 18, } -``` - -Voici ce qui peut être observé dans -[l'interface utilisateur](../1-Experiences/Kubeflow.md) de Kubeflow Pipelines : - -![Expérience Kubeflow Pipelines](../images/kfp_experiment.png) - -Ensuite, nous exécutons une instance de notre pipeline en utilisant les -arguments souhaités : - -```python -import time - -run = client.run_pipeline( - exp.id, # Exécuter dans l'expérience ci-dessus - experiment_name + '-' + time.strftime("%Y%m%d-%H%M%S"), # Donner un nom et une - heure système à notre tâche unique pipeline_yaml, # Transmettre le .yaml.zip que - nous avons créé ci-dessus. Il définit le pipeline params=pl_params # Transmettre - les paramètres en fonction desquels nous souhaitons exécuter le pipeline -) -``` - -Voici ce que l'on peut également voir dans l'interface utilisateur : - -![Expérience Kubeflow Pipelines](../images/kfp_experiment.png) - -Plus tard, lorsque nous souhaiterons réutiliser le pipeline, nous pourrons -transmettre différents arguments et tout recommencer (et même le réutiliser à -partir de l'interface utilisateur de Kubeflow). Pour mieux comprendre cet -exemple, ouvrez-le dans Kubeflow et essayez-le vous-même. - -# Composants légers - -En construction, malheureusement! - -# Comprendre l'ordre des calculs - -En construction, malheureusement! diff --git a/docs/fr/3-Pipelines/Machine-Learning-Model-Cloud-Storage.md b/docs/fr/3-Pipelines/Machine-Learning-Model-Cloud-Storage.md deleted file mode 100644 index 3a271b7d4..000000000 --- a/docs/fr/3-Pipelines/Machine-Learning-Model-Cloud-Storage.md +++ /dev/null @@ -1,61 +0,0 @@ -# Données B protégées par Statcan - - -!!! info "Protégé B" - L'ETAA est certifié pour l'hébergement de données protégé B ! - -Afin de télécharger des données protégées B sur l'ETAA, les utilisateurs devront demander l'accès via l'Unité de Succès à la Clientèle (USC). Les utilisateurs d'ETAA devront également fournir un espace de noms, obtenir un sponsor et obtenir l'approbation d'OPMIC. Une fois le processus approuvé, notre équipe infrastructure de données F.A.I.R créera alors un dossier sur Net A qui à son tour donnera accès aux utilisateurs via le répertoire actif. Les données pourront alors être transférées de Net A vers le cloud ETAA. - -Le stockage des modèles d'apprentissage automatique dans un environnement de stockage cloud protégé est essentiel pour garantir la sécurité et la confidentialité des données sensibles. L'espace de travail d'analyse avancée (ETAA) fournit un environnement de stockage cloud sécuritaire et robuste qui peut être utilisé pour stocker des modèles d'apprentissage automatique et d'autres actifs de données. - -La plate-forme ETAA fournit un environnement de stockage cloud protégé conçu pour répondre aux exigences les plus strictes en matière de sécurité et de confidentialité des données. L'environnement de stockage est protégé par un cryptage et des contrôles d'accès conformes aux normes de l'industrie, ce qui garantit que seul le personnel autorisé peut accéder aux données sensibles. Cela protège contre les accès non autorisés, les violations de données et autres menaces de sécurité. - -En plus de ses fonctions de sécurité robustes, l'environnement de stockage en cloud ETAA est également hautement évolutif et flexible. Cela signifie que les data scientists et les ingénieurs en apprentissage automatique peuvent facilement faire évoluer leurs besoins de stockage à mesure que leurs ensembles de données et la taille de leurs modèles augmentent. Cela leur permet de stocker et de gérer de gros volumes de données et de modèles sans avoir à se soucier des limitations de stockage ou des goulots d'étranglement des performances. - -Le stockage des modèles d'apprentissage automatique dans un environnement de stockage cloud protégé sur l'espace de travail d'analyse avancée fournit une solution sécurisée, évolutive et flexible pour la gestion et la protection des données sensibles. En tirant parti des capacités de stockage dans le cloud fournies par la plate-forme ETAA, les data scientists et les ingénieurs en apprentissage automatique peuvent se concentrer sur la création et le déploiement de leurs modèles en toute confiance, sachant que leurs données sont protégées et sécurisées. - -## Stockage en ligne - - -!!! info "Avantages du stockage en cloud" - Le stockage en cloud offre plusieurs avantages pour la science des données et l'apprentissage automatique, notamment en termes d'évolutivité, d'accessibilité et de rentabilité. - -Premièrement, le stockage dans le cloud permet aux data scientists de stocker et de traiter de grandes quantités de données sans avoir à se soucier des limites du stockage local. Ceci est particulièrement important dans le contexte de l'apprentissage automatique, où de grands ensembles de données sont nécessaires pour la formation et le test des modèles. Le stockage dans le cloud permet aux data scientists d'augmenter leur capacité de stockage selon les besoins, sans avoir à investir dans du matériel coûteux. - -Deuxièmement, le stockage en cloud permet aux data scientists d'accéder aux données de n'importe où, en utilisant n'importe quel appareil doté d'une connexion Internet. Cela permet la collaboration entre des équipes géographiquement dispersées et permet aux data scientists de travailler à distance. De plus, le stockage dans le cloud facilite le partage de données avec d'autres parties prenantes, telles que des partenaires commerciaux ou des clients. Enfin, le stockage dans le cloud est généralement plus rentable que le stockage sur site, en particulier pour les petites entreprises ou celles dont les ressources informatiques sont limitées. - -Dans l'ensemble, le stockage en cloud est une solution fiable et pratique pour stocker et gérer vos données. Que vous ayez besoin de stocker de grandes quantités de données ou seulement quelques fichiers, le stockage en cloud facilite la gestion de vos besoins de stockage sans les tracas des solutions de stockage traditionnelles. - -La plateforme ETAA propose plusieurs types de stockage : - -- Disques (également appelés Volumes sur l'écran de création de Kubeflow Notebook Server) -- Buckets ("Blob" ou stockage S3, fournis via MinIO) -- Lacs de données (à venir) - -Selon votre cas d'utilisation, le disque ou le bucket peut être le plus approprié. Notre [aperçu du stockage](../5-Storage/Overview.md) vous aidera à les comparer. - -### Disques - -[![Disques](../images/Disks.PNG)](Storage.md/) - -**[Disks](../5-Storage/Disks.md)** sont ajoutés à votre serveur notebook en ajoutant des volumes de données. - -### Seaux - -MinIO est un système de stockage d'objets compatible S3-API qui fournit une alternative open source aux services de stockage cloud propriétaires. Bien que nous utilisions actuellement MinIO comme solution de stockage dans le cloud, nous prévoyons de le remplacer par s3-proxy dans un proche avenir. S3-proxy est un serveur proxy inverse léger et open source qui vous permet d'accéder à des services de stockage compatibles avec Amazon S3 avec vos applications existantes. En passant à s3-proxy, nous pourrons améliorer les performances, la sécurité et l'évolutivité de notre stockage dans le cloud, tout en maintenant la compatibilité avec l'API S3. - -[![MinIO](../images/Buckets.PNG)](AzureBlobStorage.md/) - -**[MinIO](../5-Storage/AzureBlobStorage.md)** est un magasin d'objets évolutif cloud natif. Nous l'utilisons pour les buckets (stockage blob ou S3). - -### Lacs de données (à venir) - -Un lac de données est un référentiel central qui vous permet de stocker toutes vos données structurées et non structurées à n'importe quelle échelle. C'est un moyen rentable de stocker et de gérer tous les types de données, des données brutes aux données traitées, et c'est un outil essentiel pour les data scientists. - -L'un des principaux avantages d'un lac de données est sa flexibilité. Il permet de stocker tous types de données sans avoir besoin de définir un schéma au préalable, ce qui est particulièrement utile lorsqu'il s'agit de données non structurées. Cette flexibilité permet aux data scientists d'explorer, d'expérimenter et d'extraire facilement des informations à partir de leurs données sans être contraints par les limites d'une base de données relationnelle traditionnelle. - -Les lacs de données permettent également aux data scientists de centraliser leurs données, ce qui facilite la gestion et l'analyse de gros volumes de données provenant de diverses sources. Avec un lac de données, les data scientists peuvent facilement ingérer et stocker des données provenant de diverses sources, telles que des bases de données, le stockage dans le cloud et des API tierces. De plus, les lacs de données fournissent souvent des fonctionnalités pour la gouvernance des données, la gestion des métadonnées et le contrôle d'accès, ce qui permet de garantir que les données sont de haute qualité et conformes aux réglementations en vigueur. - -De plus, les lacs de données basés sur le cloud offrent des solutions de stockage évolutives et économiques qui peuvent être facilement étendues en un clic. À mesure que les besoins de stockage de données d'un scientifique des données augmentent, il peut ajouter une capacité de stockage supplémentaire à son lac de données avec un minimum d'effort, sans se soucier de l'infrastructure sous-jacente ou de la maintenance. - -Dans l'ensemble, les lacs de données sont un outil essentiel pour les data scientists, car ils offrent la flexibilité, l'évolutivité et la facilité d'utilisation nécessaires pour stocker et gérer de gros volumes de données, permettant aux data scientists de se concentrer sur l'extraction d'informations et de valeur à partir des données. diff --git a/docs/fr/3-Pipelines/Machine-Learning-Model-Serving.md b/docs/fr/3-Pipelines/Machine-Learning-Model-Serving.md deleted file mode 100644 index 237deb56f..000000000 --- a/docs/fr/3-Pipelines/Machine-Learning-Model-Serving.md +++ /dev/null @@ -1,39 +0,0 @@ -# Introduction au modèle de service - -Dans le contexte des gouvernements, servir des modèles d'apprentissage automatique signifie rendre les modèles formés disponibles pour être utilisés par d'autres applications et systèmes. Cela peut inclure la réalisation de prédictions ou de classifications basées sur les données d'entrée, ou la fourniture d'informations et de recommandations basées sur les résultats de l'analyse des données. - -Servir des modèles d'apprentissage automatique dans un contexte gouvernemental soulève des questions importantes liées à la confidentialité des données. Les agences gouvernementales sont souvent responsables de la collecte et de la gestion des données personnelles sensibles, telles que les dossiers médicaux, les données financières et les casiers judiciaires. Lors de la diffusion de modèles d'apprentissage automatique, il est essentiel de s'assurer que ces données sont protégées et que leur accès est strictement contrôlé. - -Pour répondre à ces préoccupations, les agences gouvernementales doivent mettre en œuvre des mesures solides de confidentialité et de sécurité des données lorsqu'elles servent des modèles d'apprentissage automatique. Cela pourrait inclure le chiffrement des données au repos et en transit, la mise en œuvre de contrôles d'accès et d'authentification des utilisateurs, et la surveillance régulière des violations de données et des vulnérabilités. - -En plus de la confidentialité et de la sécurité des données, il est également important de prendre en compte les implications éthiques de servir des modèles d'apprentissage automatique dans un contexte gouvernemental. Les modèles d'apprentissage automatique peuvent être biaisés ou discriminatoires, entraînant un traitement injuste de certains groupes de personnes. Pour atténuer ces risques, les agences gouvernementales doivent soigneusement évaluer et surveiller leurs modèles d'apprentissage automatique, et prendre des mesures pour lutter contre les préjugés ou la discrimination qui pourraient survenir. - -Dans l'ensemble, servir des modèles d'apprentissage automatique dans un contexte gouvernemental nécessite un examen attentif de la confidentialité des données, de la sécurité et des préoccupations éthiques. En mettant en œuvre des mesures solides pour protéger les données personnelles et prévenir les préjugés, les agences gouvernementales peuvent tirer parti de la puissance de l'apprentissage automatique pour prendre de meilleures décisions et améliorer les résultats pour les citoyens tout en maintenant la confiance et la transparence. - -## Pourquoi servir avec nous ? - -Servir des modèles d'apprentissage automatique avec l'espace de travail d'analyse avancée (l'ETAA) présente plusieurs avantages. Premièrement, l'ETAA est une plate-forme d'analyse de données open source qui donne accès à une variété d'outils d'analyse avancés, notamment Python, R et SAS. Cela facilite le déploiement de modèles d'apprentissage automatique et leur intégration dans les flux de travail existants. - -Deuxièmement, l'ETAA prend en charge plusieurs frameworks MLOps, notamment Couler, Seldon et Argo Workflows. Ces frameworks fournissent une gamme de fonctionnalités, notamment la gestion des versions de modèle, le service de modèle et la surveillance de modèle, qui simplifient le processus de déploiement et de gestion des modèles d'apprentissage automatique en production. - -Troisièmement, l'ETAA fournit une plate-forme sécurisée et évolutive pour servir les modèles d'apprentissage automatique avec le statut protégé B. Les modèles peuvent être servis à l'aide d'environnements conteneurisés, tels que Docker, qui offrent un niveau élevé d'isolement et de sécurité. L'ETAA fournit également un accès aux ressources de cloud computing, permettant aux utilisateurs d'augmenter leur puissance de calcul selon les besoins pour gérer des volumes élevés de demandes. - -Enfin, l'ETAA est une plateforme collaborative qui permet aux utilisateurs de partager du code et des données avec d'autres chercheurs et analystes. Cela favorise une communauté d'utilisateurs qui peuvent apprendre du travail des autres et collaborer sur des projets qui nécessitent des capacités d'analyse avancées. - -En résumé, servir des modèles d'apprentissage automatique avec l'espace de travail d'analyse avancée donne accès à des outils d'analyse avancés, à plusieurs cadres MLOps, à une plate-forme protégé B sécurisée et évolutive et à une communauté collaborative d'utilisateurs, ce qui en fait une plate-forme idéale pour les scientifiques et les analystes de données qui veulent pour déployer et gérer des modèles d'apprentissage automatique en production. - -## Noyau de Seldon - -Seldon Core est une plate-forme open source pour le déploiement, la mise à l'échelle et la surveillance des modèles d'apprentissage automatique sur Kubernetes. Il fournit un moyen simple et efficace de déployer des modèles d'apprentissage automatique en tant que microservices dans un environnement de production. - -Servir des modèles d'apprentissage automatique à l'aide de Seldon Core implique les étapes suivantes : - -1. Conditionnement du modèle : la première étape consiste à conditionner le modèle d'apprentissage automatique formé dans une image de conteneur avec toutes les dépendances requises. Seldon Core prend en charge divers frameworks d'apprentissage automatique, notamment TensorFlow, PyTorch et Scikit-learn. - -2. Déploiement du modèle : une fois l'image du conteneur créée, l'étape suivante consiste à déployer le modèle sur Kubernetes à l'aide de Seldon Core. Cela implique de définir le fichier de configuration de déploiement, qui spécifie les ressources requises pour le déploiement, telles que le nombre de répliques et les ressources de calcul. - -3. Service de modèle : une fois le modèle déployé, Seldon Core expose un point de terminaison d'API REST qui peut être utilisé pour effectuer des prédictions. Les clients peuvent envoyer des requêtes au point de terminaison avec des données d'entrée, et le modèle renverra la sortie correspondante. Seldon Core prend également en charge divers modèles de déploiement, tels que le déploiement Canary et les tests A/B, pour permettre une expérimentation et des tests faciles de différents modèles. - -4. Surveillance des modèles : Seldon Core fournit diverses fonctionnalités de surveillance pour suivre les performances des modèles déployés. Cela inclut la surveillance en temps réel des métriques du modèle, telles que la latence et le débit, ainsi que la journalisation des données de demande et de réponse à des fins de débogage. - -Seldon Core facilite la mise à disposition de modèles d'apprentissage automatique à grande échelle, avec une prise en charge de la haute disponibilité, de l'évolutivité et de la tolérance aux pannes. Il fournit également une intégration avec divers outils natifs de Kubernetes, tels qu'Istio et Prometheus, pour permettre une surveillance et une observabilité avancées. diff --git a/docs/fr/3-Pipelines/Machine-Learning-Training-Pipelines.md b/docs/fr/3-Pipelines/Machine-Learning-Training-Pipelines.md deleted file mode 100644 index c15095c6e..000000000 --- a/docs/fr/3-Pipelines/Machine-Learning-Training-Pipelines.md +++ /dev/null @@ -1,821 +0,0 @@ -# Former des modèles d'apprentissage automatique sur l'ETAA - -
-![MLOps](../images/mlops.jpg) -
- - -!!! info - La formation de modèles d'apprentissage automatique implique l'utilisation d'algorithmes pour apprendre des modèles et des relations dans les données. Ce processus implique l'identification de caractéristiques ou de variables pertinentes pour le problème en question et l'utilisation de ces caractéristiques pour faire des prédictions ou des classifications. - -## Pourquoi s'entraîner avec nous ? - -_L'entraînement des modèles d'apprentissage automatique sur l'espace de travail d'analyse avancée (ETAA) présente plusieurs avantages._ - -1. **Open Source :** L'ETAA est une *plate-forme de données open source hébergée par Statistique Canada* qui fournit un accès sécurisé (protégé B) à une variété de sources de données, y compris des données de recensement, des enquêtes et des dossiers administratifs. Ces données peuvent être utilisées pour former des modèles d'apprentissage automatique et générer des informations qui peuvent éclairer les décisions politiques et améliorer les processus métier. - -2. **Polyvalent :** L'ETAA est *conçu pour gérer des ensembles de données volumineux et complexes*. Il donne accès à une gamme d'outils d'analyse avancés, dans le langage de votre choix, y compris *Python, R et SAS*, qui peuvent être utilisés pour prétraiter les données, former des modèles d'apprentissage automatique et générer des visualisations. *Parce que l'ETAA exploite les technologies cloud, *les utilisateurs peuvent augmenter leur puissance de calcul selon leurs besoins*. -* -3. **Sécurisé :** L'ETAA est une *plate-forme sécurisée (protégé B) qui respecte les normes les plus élevées en matière de confidentialité et de sécurité des données*. Les données peuvent être stockées et traitées sur la plateforme sans risque d'accès non autorisé ou de violation de données. - -## MLOps et pipelines de données - - -!!! info "Optimiser les workflows de données" - Les MLOps et les pipelines de données sont des outils importants utilisés dans le domaine de la science des données pour gérer et optimiser les workflows de données. - -### MLOps - -MLOps fait référence à l'ensemble des pratiques et des outils utilisés pour gérer l'ensemble du cycle de vie d'un modèle d'apprentissage automatique. Cela comprend tout, du développement et de la formation du modèle à son déploiement en production et à sa maintenance dans le temps. MLOps garantit que les modèles d'apprentissage automatique sont fiables, précis et évolutifs, et qu'ils peuvent être mis à jour et améliorés selon les besoins. - -### Pipelines de données - -Les pipelines de données sont une série d'étapes qui permettent de déplacer des données d'un système ou d'une application à un autre. Cela comprend la collecte, le nettoyage, la transformation et le stockage des données, ainsi que leur récupération en cas de besoin. Les pipelines de données sont importants pour garantir que les données sont exactes, fiables et accessibles à ceux qui en ont besoin. - - -!!! info "Automatisation et fiabilité" - Les MLOps et les pipelines de données aident les organisations à gérer le processus complexe consistant à travailler avec de grandes quantités de données et à développer des modèles d'apprentissage automatique. En automatisant ces processus et en s'assurant que les données sont exactes et fiables, les organisations peuvent économiser du temps et des ressources tout en prenant de meilleures décisions basées sur des informations basées sur les données. - -### Pourquoi des MLOps conteneurisés ? - -Les avantages de l'utilisation d'une approche conteneurisée pour la formation de modèles d'apprentissage automatique avec Argo Workflows incluent : - -1. **Reproductibilité :** La conteneurisation du modèle de l'apprentissage automatique et de ses dépendances garantit que l'environnement reste cohérent d'une exécution à l'autre, ce qui facilite la reproduction des résultats. - -2. **Évolutivité :** Argo Workflows peut orchestrer des tâches parallèles et des flux de travail complexes, ce qui facilite l'évolution du processus de formation selon les besoins. - -3. **Portabilité :** Les conteneurs peuvent être exécutés sur n'importe quelle plate-forme prenant en charge la conteneurisation, ce qui facilite le déplacement du processus de formation vers différents environnements ou fournisseurs de cloud. - -4. **Collaboration :** En transférant le conteneur vers un registre de conteneurs, les autres utilisateurs peuvent facilement télécharger et utiliser le conteneur à leurs propres fins, ce qui facilite la collaboration sur des projets de l'apprentissage automatique. - -Les flux de travail Argo et la conteneurisation offrent une approche puissante et flexible pour la formation de modèles d'apprentissage automatique. En tirant parti de ces outils, les data scientists et les ingénieurs en apprentissage automatique peuvent créer, déployer et gérer des workflows d'apprentissage automatique avec facilité et reproductibilité. - -## Comment former des modèles - -Il existe plusieurs façons de former des modèles d'apprentissage automatique et ce n'est pas à nous de dire à qui que ce soit comment le faire. Cela étant dit, nous avons fourni ci-dessous quelques guides sur la façon de former des modèles d'apprentissage automatique à l'aide des outils disponibles sur l'ETAA. Le premier tutoriel concerne la formation d'un modèle simple directement dans un notebook JupyterLab. Le deuxième tutoriel suppose que l'utilisateur est plus avancé et souhaite définir un pipeline MLOps pour former des modèles à l'aide d'Argo Workflows. - -### Créer un serveur de bloc-notes sur l'ETAA - - -!!! info "Serveurs portables" - Que vous envisagiez de travailler dans JupyterLab, R Studio ou quelque chose de plus avancé avec Argo Workflows, vous aurez besoin du serveur de bloc-notes approprié. [Suivez les instructions trouvées ici pour commencer.](https://docs.google.com/presentation/d/12yTDlbMCmbg0ccdea2h0vwhs5YTa_GHm_3DieG5A-k8/edit?usp=sharing) - -### Utilisation de JupyterLab - -![JupyterLab](../images/jupyterlab.jpg) - - -!!! info "JupyterLab est populaire" - La formation de modèles d'apprentissage automatique avec JupyterLab est une approche populaire parmi les data scientists et les ingénieurs en apprentissage automatique. - -Vous trouverez ici les étapes nécessaires pour former un modèle d'apprentissage automatique avec JupyterLab sur l'ETAA. Parce que nous sommes un environnement multilingue, nous avons fait de notre mieux pour fournir des exemples de code dans nos langages les plus populaires, `Python`, `R` et `SAS`. - -#### 1. Importez les bibliothèques requises - -Une fois qu'une session JupyterLab est en cours d'exécution, vous devez importer les bibliothèques requises pour votre modèle d'apprentissage automatique. Cela peut inclure des bibliothèques telles que `NumPy`, `Pandas`, `Scikit-learn`, `Tensorflow` ou `PyTorch`. Si vous utilisez `R`, vous aurez besoin de `tidyverse`, `caret` et `janitor`. - -=== "Python" - ``` py title="libraries.py" linenums="1" - #!/usr/bin/env python - - # tensorflow et keras pour la construction et la formation de modèles d'apprentissage en profondeur - import tensorflow as tf - from tensorflow import keras - - # numpy pour les calculs numériques - import numpy as np - - # pandas pour la manipulation et l'analyse des données - import pandas as pd - - # matplotlib pour la visualisation des données - import matplotlib.pyplot as plt - ``` -=== "R" - ``` r title="libraries.R" linenums="1" - #!/usr/bin/env Rscript - - # tidyverse pour des outils impressionnants d'analyse de données et de munging - library(tidyverse) - - # concierge pour nettoyer vos données - library(janitor) - - # caret pour un apprentissage automatique facile - library(caret) - ``` -=== "SASPy" - ``` py title="libraries.py" linenums="1" - #!/usr/bin/env python - - # la seule bibliothèque dont vous aurez besoin pour accéder à SAS depuis Python - import saspy - ``` -=== "SAS" - ``` sas title="libraries.sas" linenums="1" - - ``` - - -!!! note "À propos du code" - Les exemples de code que vous voyez dans ce document et tout au long de la documentation sont à titre indicatif pour vous aider à démarrer vos projets. Selon la tâche ou le projet spécifique, d'autres bibliothèques et étapes peuvent être nécessaires. - -#### 2. Charger et prétraiter les données - -Ensuite, vous devez charger et prétraiter les données que vous utiliserez pour entraîner votre modèle d'apprentissage automatique. Cela peut inclure le nettoyage des données, l'extraction de caractéristiques et la normalisation. Les étapes de prétraitement exactes que vous devrez effectuer dépendront de l'ensemble de données spécifique avec lequel vous travaillez, des exigences de votre modèle d'apprentissage automatique et du travail à effectuer. - -=== "Python" - ``` py title="load_data.py" linenums="1" - #!/usr/bin/env python - - # Importer les paquets nécessaires - import pandas as pd - from sklearn.preprocessing import StandardScaler - - # Charger des données à partir d'un fichier CSV - data = pd.read_csv('data.csv') - - # Nettoyage des données ! Beaucoup plus peut être fait, c'est un principe de base - data = data.dropna() # Drop rows with missing values - data = data.drop_duplicates() # Drop duplicate rows - - # Extraction de caractéristiques - X = data[['feature1', 'feature2', 'feature3']] # Sélectionnez les fonctionnalités pertinentes - - # Normalisation - scaler = StandardScaler() # Crée un objet scaler - X_norm = scaler.fit_transform(X) # Normaliser les valeurs des caractéristiques - ``` -=== "R" - ``` r title="load_data.R" linenums="1" - #!/usr/bin/env Rscript - - # Importer les paquets nécessaires - library(tidyverse) - library(janitor) - - # Charger des données à partir d'un fichier CSV - data <- read_csv("data.csv") - - # Nettoyer les données à l'aide d'un concierge - data_cleaned <- data %>% - # Supprimer les espaces blancs de début/fin dans les noms de colonne - clean_names() %>% - # Supprimer les lignes avec des valeurs manquantes - remove_empty() %>% - # Convertir la colonne de date au format Date - mutate(date = as.Date(date, format = "%m/%d/%Y")) %>% - # Supprimer les lignes en double - distinct() %>% - # Réorganiser les colonnes - select(date, column2, column1, column3) - ``` -=== "SASPy" - ``` py title="load_data.py" linenums="1" - #!/usr/bin/env python - - # Importer les paquets nécessaires - import saspy - - # Démarrez une session SAS et vérifiez les informations de configuration - sas = saspy.SASsession(cfgname='default') - - # Charger des données à partir d'un fichier CSV - data = sas.read_csv("./data.csv") - ``` -=== "SAS" - ``` sas title="load_data.sas" linenums="1" - /* Lecture d'un fichier délimité par des virgules avec une extension .csv */ - /* */ - /* Puisque la valeur DBMS= est CSV, vous n'avez pas besoin d'utiliser le DELIMITER= */ - /* déclaration.Par défaut, il est supposé que les noms de variables sont sur la première */ - /* ligne, l'instruction GETNAMES= n'est donc pas requise. */ - /* */ - /* Créer un fichier de test délimité par des virgules à lire en utilisant PROC IMPORT ci-dessous. */ - - /* Charger les données d'un fichier CSV */ - proc import - datafile='data.csv' - out=data - dbms=csv - replace; - run; - - /* Afficher les données */ - proc print ; - courir; - ``` - -#### 3. Divisez les données en ensembles d'entraînement et de test - - Une fois les données prétraitées, vous devez les diviser en ensembles d'apprentissage et de test. L'ensemble de formation sera utilisé pour former le modèle d'apprentissage automatique, tandis que l'ensemble de test sera utilisé pour évaluer ses performances. - -=== "Python" - ``` py title="train_test.py" linenums="1" - #!/usr/bin/env python - - # Importer les paquets nécessaires - import pandas as pd - from sklearn.model_selection import train_test_split - - # Diviser les données en ensembles d'entraînement et de test - X_train, X_test, y_train, y_test = train_test_split(X_norm, - data['target'], test_size=0.2, random_state=42) - ``` -=== "R" - ``` r title="train_test.R" linenums="1" - #!/usr/bin/env Rscript - - # Importer les paquets nécessaires - library(caret) - - # Charger le jeu de données - data <- read.csv("my-dataset.csv") - - # Définir la graine pour la reproductibilité - set.seed(123) - - # Diviser l'ensemble de données en train et tester à l'aide de la fonction createDataPartition de caret - train_index <- createDataPartition(data$target_variable, p = 0.7, list = FALSE) - train_data <- data[train_index, ] - test_data <- data[-train_index, ] - ``` -=== "SASPy" - ``` py title="train_test.py" linenums="1" - #!/usr/bin/env python - - ``` -=== "SAS" - ``` sas title="train_test.sas" linenums="1" - - ``` - - -!!! note - Nous divisons les données en ensembles d'apprentissage et de test à l'aide de la fonction "train_test_split" de "scikit-learn", qui divise de manière aléatoire les données en deux ensembles en fonction de la taille de test spécifiée et de la graine aléatoire. - - -#### 4. Définir et entraîner le modèle d'apprentissage automatique - -Avec la division des données, vous pouvez désormais définir et entraîner votre modèle d'apprentissage automatique à l'aide de l'ensemble d'entraînement. Cela pourrait impliquer la sélection de l'algorithme approprié, le réglage des hyperparamètres et la validation croisée. - -=== "Python" - ``` py title="train.py" linenums="1" - #!/usr/bin/env python - - # Importer les paquets nécessaires - from sklearn.ensemble import RandomForestClassifier - from sklearn.model_selection import train_test_split - - # Charger les ensembles de données - data = pd.read_csv("my-dataset.csv") - - # Diviser l'ensemble de données en train et tester - X_train, X_test, y_train, y_test = train_test_split(data.iloc[:, :-1], data.iloc[:, -1], test_size=0.3, random_state=123) - - # Former le modèle - model = RandomForestClassifier(n_estimators=100, random_state=123) - model.fit(X_train, y_train) - - # Imprimer le score de précision sur les données de test - print("Accuracy on test set: {:.3f}".format(model.score(X_test, y_test))) - ``` -=== "R" - ``` r title="train.R" linenums="1" - #!/usr/bin/env Rscript - - # Importer les paquets nécessaires - library(caret) - - # Charger l'ensembles de données - data <- read.csv("my-dataset.csv") - - # Définir la graine pour la reproductibilité - set.seed(123) - - # Diviser l'ensemble de données en train et tester à l'aide de la fonction createDataPartition de caret - train_index <- createDataPartition(data$target_variable, p = 0.7, list = FALSE) - train_data <- data[train_index, ] - test_data <- data[-train_index, ] - - # Définir le contrôle d'entraînement - train_control <- trainControl(method = "cv", number = 5) - - # Entraînez le modèle à l'aide de la fonction d'entraînement de caret, (method = "rf" est pour la forêt aléatoire) - model <- train(target_variable ~ ., data = train_data, method = "rf", trControl = train_control) - - # Imprimez l'objet modèle pour afficher les résultats - print(model) - ``` -=== "SASPy" - ``` py title="train.py" linenums="1" - #!/usr/bin/env python - - # Importer les paquets nécessaires - import saspy - import pandas as pd - - # Établir une connexion à une session SAS - sas = saspy.SASsession() - - # Charger l'ensembles de données - data = pd.read_csv("my-dataset.csv") - - # Télécharger l'ensemble de données sur SAS - sas_df = sas.df2sd(data, "mydata") - - # Diviser l'ensemble de données en train et tester - train, test = sas.surveyselect(data=sas_df, - method="SRS", - seed=123, - samprate=0.7, - outall=True, - strata="target_variable", - partind=True) - - # Former le modèle en utilisant la procédure HPFOREST - model = sas.hpforest(data=train, - target="target_variable", - input="input_variable_1-input_variable_n", - partition="rolevar", - rolevars={"test": "0", "train": "1"}, - nominals=["input_variable_1-input_variable_n"], - forestopts={"ntree": 100, "seed": 123}) - - # Noter le modèle sur les données de test - predictions = model.predict(newdata=test, out=pred_out) - - # Calculer le score de précision sur les données de test - accuracy = sas.freq(data=predictions, tables="target_variable*p_target_variable", nocum=True, nocol=True) - - # Imprimer le score de précision - print("Accuracy on test set: {:.3f}".format(accuracy.Frequency.iloc[0, 1] / accuracy.Frequency.iloc[:, 1].sum())) - - # Se déconnecter de la session SAS - sas.disconnect() - ``` -=== "SAS" - ``` sas title="train.sas" linenums="1" - /* Charger le jeu de données */ - proc import datafile="my-dataset.csv" out=mydata dbms=csv replace; - run; - - /* Divise le jeu de données en train et test */ - proc surveyselect data=mydata method=srs seed=123 out=selected outall - samprate=0.7; - strata target_variable; - run; - - /* Former le modèle */ - proc hpforest data=selected; - class _all_; - target target_variable / level=nominal; - partition rolevar=target_variable(test="0" train="1"); - input _all_; - forest ntree=100 seed=123; - run; - - /* Noter le modèle sur les données de test */ - proc hpforest predict testdata=selected out=testout; - run; - - /* Affiche le score de précision sur les données de test */ - proc freq data=testout; - tables target_variable*p_target_variable / nocum nocol; - run; - ``` - -#### 5. Évaluer le modèle - -Après avoir entraîné le modèle, vous devez évaluer ses performances sur l'ensemble de test. Cela vous donnera une idée de la performance du modèle sur de nouvelles données inédites. - -=== "Python" - ``` py title="evaluate.py" linenums="1" - - ``` -=== "R" - ``` r title="evaluate.R" linenums="1" - - ``` -=== "SASPy" - ``` py title="evaluate.py" linenums="1" - - ``` -=== "SAS" - ``` sas title="evaluate.sas" linenums="1" - - ``` - -#### 6. Déployer le modèle - -Enfin, vous pouvez déployer le modèle d'apprentissage automatique formé dans un environnement de production. - -=== "Python" - ``` py title="deploy.py" linenums="1" - - ``` -=== "R" - ``` r title="deploy.R" linenums="1" - - ``` -=== "SASPy" - ``` py title="deploy.py" linenums="1" - - ``` -=== "SAS" - ``` sas title="deploy.sas" linenums="1" - - ``` - -### Utilisation des workflows Argo - -![Argo Workflows](../images/argo-workflows-assembly-line.jpg) - - -!!! info "Bonnes pratiques MLOps" - Argo Workflows est un excellent outil pour tous ceux qui cherchent à mettre en œuvre des pratiques MLOps et à rationaliser le processus de formation et de déploiement de modèles d'apprentissage automatique ou d'autres tâches de science des données telles que ETL. - -**[Argo Workflows](https://argoproj.github.io/argo-workflows/)** est un engin de workflow open source natif de conteneur pour orchestrer des tâches parallèles sur Kubernetes. Argo Workflows est implémenté en tant que Kubernetes CRD (Custom Resource Definition). Il est particulièrement bien adapté pour une utilisation dans les flux de travail d'apprentissage automatique et de science des données. - -Argo Workflows vous permet de - -- Définissez des flux de travail où chaque étape du flux de travail est un conteneur. -- Modélisez les flux de travail en plusieurs étapes sous la forme d'une séquence de tâches ou capturez les dépendances entre les tâches à l'aide d'un graphe acyclique dirigé (DAG). -- Exécutez facilement des tâches de calcul intensives pour l'apprentissage automatique ou le traitement de données en une fraction du temps à l'aide des flux de travail Argo sur Kubernetes. -- Exécutez des pipelines CI/CD en mode natif sur Kubernetes sans configurer de produits de développement logiciel complexes. - -ce qui facilite la gestion de l'ensemble du pipeline d'apprentissage automatique de bout en bout. Avec Argo Workflows, vous pouvez facilement créer des workflows qui intègrent des tâches telles que le prétraitement des données, la formation de modèles et le déploiement de modèles, le tout dans un environnement Kubernetes. - - -!!! info "" -
- [![Flux de travail Argo](../images/argo-workflows.jpg)](https://argoproj.github.io/argo-workflows/) -

Flux de travail Argo

-
- -Vous trouverez ci-dessous les étapes pour former un modèle d'apprentissage automatique à l'aide d'Argo Workflows sur l'ETAA. - -#### 1. Écrivez un script pour entraîner votre modèle - -Voici un exemple de script qui entraîne un modèle de régression logistique sur l'ensemble de données iris. N'oubliez pas de consulter le code de chaque langue ci-dessous. - -=== "Python" - - ``` python title="train.py" linenums="1" - #!/usr/bin/env python - - # Importer les bibliothèques nécessaires - import argparse - import pandas as pd - from sklearn.datasets import load_iris - from sklearn.linear_model import LogisticRegression - from sklearn.model_selection import train_test_split - from sklearn.metrics import accuracy_score - import joblib - - # Analyser les arguments d'entrée - parser = argparse.ArgumentParser(description="Train logistic regression model on iris dataset.") - parser.add_argument("--input", default="iris.csv", help="Path to input dataset file.") - parser.add_argument("--output", default="model.pkl", help="Path to output model file.") - args = parser.parse_args() - - # Charger le jeu de données de l'iris - data = load_iris() - X, y = data.data, data.target - - # Diviser les données en ensembles d'entraînement et de test - X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42) - - # Former le modèle de régression logistique - clf = LogisticRegression(random_state=42) - clf.fit(X_train, y_train) - - # Évaluer le modèle sur l'ensemble de test - y_pred = clf.predict(X_test) - accuracy = accuracy_score(y_test, y_pred) - print("Accuracy:", accuracy) - - # Enregistrer le modèle dans un fichier - joblib.dump(clf, args.output) - ``` - -=== "R" - - ``` r title="train.R" linenums="1" - #!/usr/bin/env Rscript - - # Importer les bibliothèques nécessaires - library(caret) - - # Analyser les arguments d'entrée - args <- commandArgs(trailingOnly = TRUE) - input_file <- ifelse(length(args) > 0, args[1], "iris.csv") - output_file <- ifelse(length(args) > 1, args[2], "model.rds") - - # Charger le jeu de données de l'iris - data(iris) - X <- iris[, 1:4] - y <- iris[, 5] - - # Diviser les données en ensembles d'entraînement et de test - set.seed(42) - train_index <- createDataPartition(y, p = 0.8, list = FALSE) - X_train <- X[train_index, ] - y_train <- y[train_index] - X_test <- X[-train_index, ] - y_test <- y[-train_index] - - # Former le modèle de régression logistique - clf <- train(x = X_train, y = y_train, method = "glm") - - # Évaluer le modèle sur l'ensemble de test - y_pred <- predict(clf, newdata = X_test) - accuracy <- confusionMatrix(y_pred, y_test)$overall["Accuracy"] - print(paste0("Accuracy: ", accuracy)) - - # Enregistrer le modèle dans un fichier - saveRDS(clf, output_file) - ``` - -#### 2. Écrivez un Dockerfile pour exécuter votre code - -Vous aurez besoin d'un Dockerfile qui inclut toutes les dépendances nécessaires pour former votre modèle d'apprentissage automatique. Cela pourrait inclure - -- des forfaits comme - - `scikit-learn`, `pandas` ou `numpy` si vous utilisez `Python` - - `caret`, `janitor` et `tidyverse` si vous utilisez `R` -- vos propres bibliothèques ou scripts personnalisés -- le code de votre modèle de l'apprentissage automatique sous la forme d'un script [comme dans l'exemple ci-dessus](#1-write-a-script-to-train-your-model). - -Utilisez le `Dockerfile` suivant comme point de départ pour vos projets `R` et `Python`. - -=== "Python" - - ``` docker title="Dockerfile" linenums="1" - FROM python:3.8-slim-buster - - # Installez toutes les dépendances nécessaires - RUN pip install --no-cache-dir scikit-learn pandas numpy - - # Définir le répertoire de travail - WORKDIR /app - - # Copier le code dans le conteneur - COPY train.py . - - # Définir le point d'entrée - ENTRYPOINT ["python", "train.py"] - ``` - -=== "R" - ``` docker title="Dockerfile" linenums="1" - FROM rocker/r-base:latest - - RUN apt-get update && apt-get install -y --no-install-recommends \ - libssl-dev \ - libcurl4-openssl-dev \ - libxml2-dev \ - && apt-get clean \ - && rm -rf /var/lib/apt/lists/* - - RUN R -e 'install.packages(c("caret", "janitor", "tidyverse"))' - - COPY train.R /app/train.R - - WORKDIR /app - - ENTRYPOINT ["Rscript", "train.R"] - ``` - -#### 3. Écrivez votre workflow en YAML - -YAML est encore un autre langage de balisage et vous devrez écrire les étapes de votre pipeline de formation dans un fichier YAML Argo Workflows. Ce fichier doit inclure une référence au Dockerfile que vous avez créé à l'[Étape 1](#2-write-a-dockerfile-to-run-your-code), ainsi que toutes les données d'entrée et de sortie avec lesquelles vous travaillerez. - -Voici un exemple de fichier YAML pour un pipeline d'apprentissage automatique simple qui forme un modèle de régression logistique sur l'ensemble de données iris. La seule vraie différence entre les versions `Python` et `R` est la commande `command : ["python", "train.py"]` vs `command : ["Rscript", "train.R"]` et la les modèles sont stockés dans différents formats, `pkl` pour `python` et `rds` pour `R`. - -Le fichier YAML définit une seule étape appelée "train" qui exécute un script appelé "train.py" ou "train.R" dans l'image Docker "machine-learning:v1". Le script prend un fichier d'ensemble de données d'entrée, spécifié par un paramètre appelé `dataset`, et génère un fichier de modèle entraîné vers un artefact de sortie appelé `model.pkl` ou `model.rds` selon le langage utilisé. - -=== "Python" - ``` yaml title="workflow.yaml" linenums="1" - apiVersion: argoproj.io/v1alpha1 - kind: Workflow - metadata: - generateName: ml-pipeline- - spec: - entrypoint: train - templates: - - name: train - container: - image: machine-learning:v1 - command: ["python", "train.py"] - args: ["--input", "{{inputs.parameters.dataset}}", "--output", "{{outputs.artifacts.model}}"] - inputs: - parameters: - - name: dataset - default: "iris.csv" - outputs: - artifacts: - - name: model - path: /output/model.pkl - ``` -=== "R" - ``` yaml title="workflow.yaml" linenums="1" - apiVersion: argoproj.io/v1alpha1 - kind: Workflow - metadata: - generateName: ml-pipeline- - spec: - entrypoint: train - templates: - - name: train - container: - image: machine-learning:v1 - command: ["Rscript", "train.R"] - args: ["--input", "{{inputs.parameters.dataset}}", "--output", "{{outputs.artifacts.model}}"] - inputs: - parameters: - - name: dataset - default: "iris.csv" - outputs: - artifacts: - - name: model - path: /output/model.rds - ``` - - -#### 4. Soumettez le workflow à l'aide de la CLI Argo Workflows - -Pour exécuter le flux de travail ci-dessus, vous devez d'abord envoyer le fichier Dockerfile à notre registre de conteneurs, puis envoyer le fichier YAML à l'aide de la commande "argo submit". Une fois le pipeline terminé, vous pouvez récupérer le fichier de modèle formé en téléchargeant l'artefact de sortie à partir de la commande `argo logs`. - -``` bash title="Terminal" -$ argo submit workflow.yaml # soumettre une spécification de workflow à Kubernetes -``` - -#### 5. Surveiller le pipeline à l'aide de la CLI Argo Workflows - -Au fur et à mesure que le pipeline s'exécute, vous pouvez surveiller sa progression à l'aide de la CLI Argo Workflows. Cela vous montrera quelles étapes ont réussi et lesquelles sont toujours en cours. Vous trouverez ci-dessous quelques commandes utiles. Pour plus d'informations sur la CLI Argo Workflows, veuillez consulter [la documentation officielle de la CLI Argo Workflows](https://argoproj.github.io/argo-workflows/walk-through/argo-cli/) . - -``` bash title="Terminal" -$ argo list # liste les workflows actuels -$ argo get workflow-xxx # obtenir des informations sur un workflow spécifique -$ argo logs workflow-xxx # imprimer les logs d'un workflow -$ argo delete workflow-xxx # supprimer le workflow - -``` - -#### 6. Récupérer le modèle formé - -Une fois le pipeline terminé, vous pouvez récupérer les données de sortie à l'aide de la commande argo logs ou en affichant les artefacts de sortie à l'aide de la CLI, c'est-à-dire accéder au répertoire que vous avez spécifié dans votre script et localiser le fichier `model.pkl` ou `model. rds`. L'extrait de code suivant, tiré du [script de formation ci-dessus](#1-define-the-machine-learning-model-and-its-dependencies), indique au langage de programmation respectif où enregistrer le modèle formé. - -=== "Python" - - ``` python title="Enregistrement des données de sortie" linenums="1" - #!/usr/bin/env python - - parser.add_argument("--output", default="model.pkl", help="Path to output model file.") - - # Enregistrer le modèle dans un fichier - joblib.dump(clf, args.sortie) - ``` - -=== "R" - - ``` r title="Enregistrement des données de sortie" linenums="1" - #!/usr/bin/env Rscript - - output_file <- ifelse(length(args) > 1, args[2], "model.rds") - - # Enregistrer le modèle dans un fichier - saveRDS(clf, output_file) - ``` - -### Exemples d'utilisation de SDK basés sur Argo Workflows - -Si vous préférez utiliser un cadre de niveau supérieur, nous avons `Couler` et `Hera`. Ces cadres rendent la création et la gestion de flux de travail complexes plus accessibles à un public plus large. - -#### Hera - -Hera vise à simplifier le processus de création et de soumission des flux de travail en éliminant de nombreux détails techniques via une interface de programmation d'application simple. Il utilise également un ensemble cohérent de terminologie et de concepts qui s'alignent sur Argo Workflows, ce qui permet aux utilisateurs d'apprendre et d'utiliser plus facilement les deux outils ensemble. - -#### Couler - -Couler fournit une interface de programmation d'application simple et unifiée pour définir les flux de travail à l'aide d'un style de programmation impératif. Il construit également automatiquement des graphes acycliques dirigés (DAG) pour les flux de travail, ce qui peut aider à simplifier le processus de création et de gestion de ceux-ci. - -=== "Couler" - ``` py title="couler.py" linenums="1" - #!/usr/bin/env python - - # Préparez votre système - !pip config --user set global.index-url https://jfrog.ETAA.cloud.statcan.ca/artifactory/api/pypi/pypi-remote/simple - !python3 -m pip install git+https://github.com/couler-proj/couler --ignore-installed - - # Définir la variable globale pour plus de commodité - - NAMESPACE = "" - - # Importer les paquets nécessaires - import json - import random - - import couler.argo as couler - from couler.argo_submitter import ArgoSubmitter - - - # Définir les étapes (fonctions) utilisées dans le workflow - def random_code(): - import random - res = "heads" if random.randint(0, 1) == 0 else "tails" - print(res) - - - def flip_coin(): - return couler.run_script( - image="k8scc01covidacr.azurecr.io/ubuntu", - source=random_code - ) - - - def heads(): - return couler.run_container( - image="k8scc01covidacr.azurecr.io/ubuntu", - command=["sh", "-c", 'echo "it was heads"'] - ) - - - def tails(): - return couler.run_container( - image="k8scc01covidacr.azurecr.io/ubuntu", - command=["sh", "-c", 'echo "it was tails"'] - ) - - - result = flip_coin() - - couler.when(couler.equal(result, "heads"), lambda: heads()) - couler.when(couler.equal(result, "tails"), lambda: tails()) - - submitter = ArgoSubmitter(namespace="NAMESPACE") - result = couler.run(submitter=submitter) - - print(json.dumps(result, indent=2)) - ``` -=== "Hera" - ``` py title="hera.py" linenums="1" - #!/usr/bin/env python - - # Préparez votre système - !pip config --user set global.index-url https://jfrog.ETAA.cloud.statcan.ca/artifactory/api/pypi/pypi-remote/simple - !pip install hera-workflows - - # Importer les paquets nécessaires - import hera - from hera import Task, Workflow - - # Configurer Hera - hera.global_config.GlobalConfig.token = "" - hera.global_config.GlobalConfig.host = "https://argo-workflows.ETAA-dev.cloud.statcan.ca:443" - hera.global_config.GlobalConfig.namespace = "" - hera.global_config.GlobalConfig.service_account_name = "" - - - # Définir les étapes (fonctions) utilisées dans le workflow - def random_code(): - res = "heads" if random.randint(0, 1) == 0 else "tails" - print(res) - - - def heads(): - print("it was heads") - - - def tails(): - print("it was tails") - - - # Définir le flux de travail - with Workflow("coin-flip") as w: - r = Task("r", random_code) - h = Task("h", heads) - t = Task("t", tails) - - h.on_other_result(r, "heads") - t.on_other_result(r, "tails") - - # Exécuter le flux de travail - w.create() - ``` -=== "YAML" - ``` py title="workflow.yaml" linenums="1" - - ``` -=== "Seldon ?" - ``` py - - ``` - -### Ressources supplémentaires pour les workflows Argo - -Des exemples de workflows Argo Workflows peuvent être trouvés dans les répos Github suivants : - -- [Documentation Argo Workflows](https://argoproj.github.io/argo-workflows/) -- [Référence Argo CLI] (https://argoproj.github.io/argo-workflows/walk-through/argo-cli/) diff --git a/docs/fr/3-Pipelines/Machine-Learning.md b/docs/fr/3-Pipelines/Machine-Learning.md deleted file mode 100644 index 8f57449a5..000000000 --- a/docs/fr/3-Pipelines/Machine-Learning.md +++ /dev/null @@ -1,369 +0,0 @@ -# Modèles d'apprentissage automatique - -Les modèles d'apprentissage automatique sont des algorithmes de calcul conçus pour apprendre automatiquement des modèles et des relations à partir de données. Ces modèles sont entraînés sur un ensemble de données, qui est généralement une collection d'exemples ou d'instances, chacun d'entre eux se composant d'un ensemble de fonctionnalités ou de variables, ainsi que d'une variable cible ou d'une sortie. - -L'objectif d'un modèle d'apprentissage automatique est d'identifier des modèles et des relations au sein des données qui peuvent être utilisés pour faire des prédictions ou des décisions concernant de nouvelles données invisibles. Cela implique de développer une représentation mathématique de la relation entre les caractéristiques d'entrée et la variable de sortie, sur la base des modèles observés dans les données d'apprentissage. Une fois le modèle entraîné, il peut être utilisé pour faire des prédictions ou prendre des décisions concernant de nouvelles données inédites. - -Il existe plusieurs types de modèles d'apprentissage automatique, chacun étant conçu pour traiter différents types de problèmes ou de données. Certains des types les plus courants de modèles d'apprentissage automatique incluent : - -1. **Modèles de régression :** Les modèles de régression sont utilisés pour prédire des valeurs numériques continues, telles que les cours des actions ou les prix des logements. - -2. **Modèles de classification :** Les modèles de classification sont utilisés pour prédire des valeurs catégorielles discrètes, par exemple si un client achètera ou non un produit. - -3. **Modèles de clustering :** Les modèles de clustering sont utilisés pour identifier des groupes ou des clusters au sein d'un ensemble de données en fonction des similitudes entre les instances. - -4. **Modèles de recommandation :** Les modèles de recommandation sont utilisés pour recommander des produits ou des services aux utilisateurs en fonction de leur comportement ou de leurs préférences passés. - -5. **Réseaux de neurones :** Les réseaux de neurones sont un type de modèle d'apprentissage automatique conçu pour imiter la structure et la fonction du cerveau humain. Ils sont couramment utilisés dans les applications de reconnaissance d'images, de reconnaissance vocale et de traitement du langage naturel. - - -!!! info "Les modèles d'apprentissage automatique peuvent être biaisés" - Les modèles d'apprentissage automatique sont un outil puissant pour analyser et faire des prédictions sur les données, et ils ont un large éventail d'applications dans des domaines tels que la finance, la santé, le marketing, etc. Cependant, il est important de noter que les modèles d'apprentissage automatique ne sont pas parfaits et peuvent parfois faire des erreurs ou produire des résultats biaisés. Par conséquent, il est important d'évaluer et de tester soigneusement les modèles d'apprentissage automatique avant de les utiliser dans des applications réelles. - -## Exemples - -### Régression linéaire - -![Régression linéaire](../images/linear-regression.jpg) - - -!!! info "Régression linéaire" - $$ - \hat{Y}_i = \hat{\beta}_0 + \hat{\beta}_1 X_i + \hat{\epsilon}_i - $$ - - _Où $\hat{Y}_i$ désigne le $i$ième estimateur de la vraie valeur $Y$ en fonction de la $i$ième période d'apprentissage. Chaque $\hat{\beta}$ est un paramètre à apprendre. $\hat{\epsilon}_i$ est la quantité de bruit autorisée dans le modèle et peut varier en fonction du nombre d'époques d'entraînement indiqué par $i$. Chaque $X_i$ représente le $i$ième lot de données d'apprentissage._ - -Dans les modèles statistiques classiques comme la régression linéaire, l'objectif est de trouver une ligne qui correspond le mieux aux données, nous permettant de faire des prédictions sur de nouveaux points de données. - -À mesure que la complexité du problème augmente, des algorithmes plus sophistiqués sont nécessaires, tels que des arbres de décision, des machines à vecteurs de support et des forêts aléatoires. Cependant, ces méthodes ont des limites et peuvent ne pas être en mesure de capturer des modèles complexes dans de grands ensembles de données. - -#### Exemple de code - -=== "Python" - ``` py title="linear_regression.py" linenums="1" - #!/usr/bin/env python - - # Charger les bibliothèques requises - import pandas as pd - from sklearn.model_selection import train_test_split - from sklearn.linear_model import LinearRegression - from sklearn.metrics import mean_squared_error - - # Charger le jeu de données - data = pd.read_csv('path/to/dataset.csv') - - # Diviser les données en ensembles d'entraînement et de test - X_train, X_test, y_train, y_test = train_test_split(data.drop('target_variable', axis=1), data['target_variable'], test_size=0.2) - - # Former le modèle de régression linéaire - linear_model = LinearRegression() - linear_model.fit(X_train, y_train) - - # Faire des prédictions sur l'ensemble de test - y_pred = linear_model.predict(X_test) - - # Évaluer les performances du modèle - mse = mean_squared_error(y_test, y_pred) - rmse = mse ** 0.5 - print('Root Mean Squared Error:', rmse) - ``` - -=== "R" - ``` r title="linear_regression.r" linenums="1" - #!/usr/bin/env Rscript - - # Définir une graine aléatoire pour la reproductibilité - set.seed(123) - - # Charger le jeu de données - data <- read.csv('path/to/dataset.csv') - - # Diviser les données en ensembles d'entraînement et de test - train_index <- sample(1:nrow(data), size=0.8*nrow(data)) - train_data <- data[train_index,] - test_data <- data[-train_index,] - - # Former le modèle de régression linéaire - lm_model <- lm(target_variable ~ ., data=train_data) - - # Faire des prédictions sur l'ensemble de test - y_pred <- predict(lm_model, newdata=test_data[,-which(names(test_data)=='target_variable')]) - - # Évaluer les performances du modèle - mse <- mean((y_pred - test_data$target_variable)^2) - rmse <- sqrt(mse) - print(paste('Root Mean Squared Error:', rmse)) - ``` - -### Machine à vecteurs de support (SVM) - -![Supporter la machine vectorielle](../images/svm.jpg) - - -!!! note "SVM" - $$ - \underset{\mathbf{w},b,\boldsymbol{\xi}}{\operatorname{minimize}} \hspace{0.2cm} \frac{1}{2} ||\mathbf{w}||^2 + C \sum_{i=1}^{N} \xi_i - $$ - - $$ - \text{où} \hspace{0.2cm} y_i(\mathbf{w}^T\mathbf{x}_i + b) \geq 1-\xi_i \quad \text{and} \quad \hspace{0.2cm} \xi_i \geq 0 \hspace{0.2cm} \forall i \in {1,2,...,N} - $$ - - _Dans cette formule, nous utilisons la formulation SVM standard où $\mathbf{w}$ est le vecteur de poids, $b$ est le terme de biais et $\boldsymbol{\xi}$ est le vecteur variable d'écart. L'objectif est de minimiser la norme L2 du vecteur de poids $\mathbf{w}$, sous la contrainte que tous les exemples d'apprentissage sont classés correctement avec une marge d'au moins 1, plus une tolérance pour certaines violations de marge contrôlées par le paramètre de régularisation $C$. La variable cible $y_i$ prend les valeurs 1 ou -1, représentant les deux classes du problème de classification binaire, et $\mathbf{x}_i$ est le vecteur de caractéristiques pour le $i$ième exemple d'entraînement._ - -Une machine à vecteurs de support (SVM) est un algorithme d'apprentissage automatique supervisé qui peut être utilisé pour la classification, la régression et la détection des valeurs aberrantes. C'est un algorithme populaire dans le domaine de l'apprentissage automatique, en particulier pour résoudre les problèmes de classification. - -L'idée de base derrière SVM est de trouver un hyperplan qui sépare au mieux les données d'entrée en différentes classes. Dans un problème de classification à deux classes, l'hyperplan est une ligne qui sépare les points de données d'une classe des points de données de l'autre classe. SVM essaie de trouver l'hyperplan qui maximise la marge entre les deux classes, où la marge est la distance entre l'hyperplan et les points de données les plus proches de chaque classe. - -#### Exemple de code - -=== "Python" - ``` py title="svm.py" linenums="1" - #!/usr/bin/env python - - # Charger les bibliothèques requises - import pandas as pd - from sklearn.model_selection import train_test_split - from sklearn.svm import SVC - from sklearn.metrics import accuracy_score - - # Charger le jeu de données - data = pd.read_csv('path/to/dataset.csv') - - # Diviser les données en ensembles d'entraînement et de test - X_train, X_test, y_train, y_test = train_test_split(data.drop('target_variable', axis=1), data['target_variable'], test_size=0.2) - - # Former le modèle SVM - svm_model = SVC(kernel='linear', C=1.0, random_state=42) - svm_model.fit(X_train, y_train) - - # Faire des prédictions sur l'ensemble de test - y_pred = svm_model.predict(X_test) - - # Évaluer les performances du modèle - accuracy = accuracy_score(y_test, y_pred) - print('Accuracy:', accuracy) - ``` - -=== "R" - - ``` r title="svm.r" linenums="1" - #!/usr/bin/env Rscript - - # Charger les bibliothèques requises - library(e1071) - - # Charger le jeu de données - data <- read.csv('path/to/dataset.csv') - - # Diviser les données en ensembles d'entraînement et de test - set.seed(123) - train_index <- sample(1:nrow(data), size=0.8*nrow(data)) - train_data <- data[train_index,] - test_data <- data[-train_index,] - - # Former le modèle SVM - svm_model <- svm(target_variable ~ ., data=train_data, kernel='linear', cost=1) - - # Faire des prédictions sur l'ensemble de test - y_pred <- predict(svm_model, newdata=test_data[,-which(names(test_data)=='target_variable')]) - - # Évaluer les performances du modèle - accuracy <- mean(y_pred == test_data$target_variable) - print(paste('Accuracy:', accuracy)) - ``` - -### Forêt aléatoire - -![Forêt aléatoire](../images/random-forest.jpg) - - -!!! note "Forêt aléatoire" - $$ - \hat{y} = \frac{1}{T} \sum_{t=1}^{T} f_t(\mathbf{x}), - $$ - - _où $\hat{y}$ est la sortie prédite, $f_t(\mathbf{x})$ est la prédiction du $t$ième arbre de la forêt pour l'entrée $\mathbf{x}$, et $T $ est le nombre d'arbres dans la forêt._ - -Les forêts aléatoires sont une méthode d'apprentissage d'ensemble qui peut être utilisée pour les problèmes de classification et de régression. Ils sont souvent utilisés pour leur capacité à gérer des ensembles de données dimensionnelles à haute variation et des relations non linéaires entre les entités et les cibles. - -Chaque arbre est entraîné sur un sous-ensemble amorcé des données d'entraînement d'origine, et à chaque division, un sous-ensemble aléatoire de caractéristiques est pris en compte pour déterminer la division. La prédiction finale est obtenue en faisant la moyenne des prédictions de tous les arbres de la forêt. - -#### Exemple de code - -=== "Python" - - ``` py title="random_forest.py" linenums="1" - #!/usr/bin/env python - - # Charger les bibliothèques requises - import pandas as pd - from sklearn.model_selection import train_test_split - from sklearn.ensemble import RandomForestRegressor - from sklearn.metrics import mean_squared_error - - # Charger le jeu de données - data = pd.read_csv('path/to/dataset.csv') - - # Diviser les données en ensembles d'entraînement et de test - X_train, X_test, y_train, y_test = train_test_split(data.drop('target_variable', axis=1), data['target_variable'], test_size=0.2) - - # Former le modèle de forêt aléatoire - rf_model = RandomForestRegressor(n_estimators=100, random_state=42) - rf_model.fit(X_train, y_train) - - # Faire des prédictions sur l'ensemble de test - y_pred = rf_model.predict(X_test) - - # Évaluer les performances du modèle - mse = mean_squared_error(y_test, y_pred) - rmse = mse ** 0.5 - print('Root Mean Squared Error:', rmse) - ``` - -=== "R" - - ``` r title="random_forest.r" linenums="1" - #!/usr/bin/env Rscript - - # Charger les bibliothèques requises - library(randomForest) - - # Charger le jeu de données - data <- read.csv('path/to/dataset.csv') - - # Diviser les données en ensembles d'entraînement et de test - set.seed(123) - train_index <- sample(1:nrow(data), size=0.8*nrow(data)) - train_data <- data[train_index,] - test_data <- data[-train_index,] - - # Former le modèle de forêt aléatoire - rf_model <- randomForest(target_variable ~ ., data=train_data, ntree=100, importance=TRUE) - - # Faire des prédictions sur l'ensemble de test - y_pred <- predict(rf_model, newdata=test_data[,-which(names(test_data)=='target_variable')]) - - # Évaluer les performances du modèle - mse <- mean((y_pred - test_data$target_variable)^2) - rmse <- sqrt(mse) - print(paste('Root Mean Squared Error:', rmse)) - ``` - -### L'apprentissage en profondeur - -![Apprentissage en profondeur](../images/deep-learning.jpg) - - -!!! note "Apprentissage en profondeur" - $$ - \hat{y} = f(\mathbf{W}_L f(\mathbf{W}_{L-1} f(\dots f(\mathbf{W}_1\mathbf{x}+\mathbf{b} _1)\dots)+\mathbf{b}_{L-1})+\mathbf{b}_L) - $$ - - _où $\mathbf{x}$ est le vecteur d'entrée, $\mathbf{W}_i$ et $\mathbf{b}_i$ sont respectivement la matrice de pondération et le vecteur de biais pour la $i$ième couche, et $ f$ est la fonction d'activation._ - - _Cette formule représente un réseau de neurones à anticipation avec des couches $L$, où chaque couche applique une transformation linéaire à la sortie de la couche précédente, suivie d'une fonction d'activation non linéaire. La sortie de la couche finale, $\hat{y}$, représente la sortie prédite du réseau de neurones pour l'entrée donnée $\mathbf{x}$._ - -L'apprentissage en profondeur est un sous-ensemble de l'apprentissage automatique qui implique la formation de réseaux de neurones avec de nombreuses couches de nœuds interconnectés. Cette approche peut gérer des ensembles de données volumineux et complexes et est utilisée dans un large éventail d'applications, notamment la reconnaissance d'images, le traitement du langage naturel et la reconnaissance vocale. Le processus de formation consiste à alimenter le réseau de neurones avec un grand ensemble de données et à ajuster les poids des connexions entre les nœuds pour minimiser l'erreur entre les sorties prédites et les sorties réelles. Grâce à des itérations répétées, le réseau de neurones peut apprendre à reconnaître des modèles dans les données et à faire des prédictions précises sur de nouvelles données. - -#### Exemple de code - -=== "Python" - ``` py title="deep_learning.py" linenums="1" - #!/usr/bin/env python - - # Charger les bibliothèques requises - import pandas as pd - import numpy as np - import tensorflow as tf - from tensorflow import keras - from sklearn.model_selection import train_test_split - from sklearn.preprocessing import StandardScaler - from sklearn.metrics import accuracy_score - - # Charger le jeu de données - data = pd.read_csv('path/to/dataset.csv') - - # Diviser les données en ensembles d'entraînement et de test - X_train, X_test, y_train, y_test = train_test_split(data.drop('target_variable', axis=1), data['target_variable'], test_size=0.2) - - # Standardiser les caractéristiques d'entrée - scaler = StandardScaler() - X_train_scaled = scaler.fit_transform(X_train) - X_test_scaled = scaler.transform(X_test) - - # Définir le modèle de deep learning - model = keras.Sequential([ - keras.layers.Dense(64, activation='relu', input_shape=[X_train_scaled.shape[1]]), - keras.layers.Dropout(0.2), - keras.layers.Dense(1, activation='sigmoid') - ]) - - # Compiler le modèle - model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy']) - - # Former le modèle - history = model.fit(X_train_scaled, y_train, epochs=50, batch_size=32, validation_split=0.1) - - # Évaluer les performances du modèle - y_pred = model.predict_classes(X_test_scaled) - accuracy = accuracy_score(y_test, y_pred) - print('Accuracy:', accuracy) - ``` - -=== "R" - - ``` r title="deep_learning.r" linenums="1" - #!/usr/bin/env Rscript - - # Charger les bibliothèques requises - library(keras) - library(tensorflow) - - # Charger le jeu de données - data <- iris - x <- as.matrix(data[, 1:4]) - y <- to_categorical(as.numeric(data[, 5]) - 1) - - # Diviser les données en ensembles d'entraînement et de test - set.seed(123) - train_index <- sample(1:nrow(data), size=0.8*nrow(data)) - x_train <- x[train_index,] - y_train <- y[train_index,] - x_test <- x[-train_index,] - y_test <- y[-train_index,] - - # Définir l'architecture du réseau neuronal - model <- keras_model_sequential() %>% - layer_dense(units = 8, input_shape = c(4)) %>% - layer_activation('relu') %>% - layer_dense(units = 3) %>% - layer_activation('softmax') - - # Compiler le modèle - model %>% compile( - loss = 'categorical_crossentropy', - optimizer = 'adam', - metrics = c('accuracy') - ) - - # Former le modèle - history <- model %>% fit( - x_train, y_train, - epochs = 50, - batch_size = 10, - validation_split = 0.2, - verbose = 0 - ) - - # Évaluer les performances du modèle - metrics <- model %>% evaluate(x_test, y_test) - print(paste('Test Loss:', metrics[1])) - print(paste('Test Accuracy:', metrics[2])) - - # Tracez la précision de la formation et de la validation dans le temps - plot(history$metrics$accuracy, type='l', col='blue', ylim=c(0,1), ylab='Accuracy', xlab='Epoch') - lines(history$metrics$val_accuracy, type='l', col='red') - legend('bottomright', legend=c('Training', 'Validation'), col=c('blue', 'red'), lty=1) - ``` \ No newline at end of file diff --git a/docs/fr/3-Pipelines/Overview.md b/docs/fr/3-Pipelines/Overview.md deleted file mode 100644 index 4015d3035..000000000 --- a/docs/fr/3-Pipelines/Overview.md +++ /dev/null @@ -1,17 +0,0 @@ -MLOps, ou lopérations d'apprentissage automatique, fait référence à l'ensemble de pratiques et d'outils qui permettent aux organisations de développer, déployer et maintenir des modèles d'apprentissage automatique à grande échelle. MLOps vise à rationaliser le processus de bout en bout de création et de déploiement de modèles d'apprentissage automatique en intégrant les différentes étapes du cycle de vie de l'apprentissage automatique dans un flux de travail cohérent et automatisé. - -MLOps implique une gamme d'activités différentes, y compris la préparation et le prétraitement des données, la formation et l'optimisation des modèles, le déploiement et le service des modèles, la surveillance et la maintenance et l'amélioration continue. Certains des composants clés des MLOps incluent : - -1. **Gestion des données :** MLOps implique la gestion et le traitement de grandes quantités de données pour garantir la qualité et la précision des modèles d'apprentissage automatique. Cela implique des activités telles que le nettoyage, l'intégration et la transformation des données. - -2. **Entraînement et optimisation des modèles :** MLOps implique de développer et de tester des modèles d'apprentissage automatique, ainsi que de les optimiser en termes de performances et de précision. Cela peut impliquer d'expérimenter différents algorithmes, hyperparamètres et techniques de prétraitement des données. - -3. **Déploiement de modèles :** MLOps implique le déploiement de modèles d'apprentissage automatique dans des environnements de production, les rendant disponibles pour une utilisation dans des applications du monde réel. Cela peut impliquer la mise en conteneur de modèles pour un déploiement et une mise à l'échelle faciles, ainsi que la configuration d'API et d'autres interfaces pour la diffusion de modèles. - -4. **Surveillance et maintenance :** MLOps implique la surveillance des modèles d'apprentissage automatique en production pour s'assurer qu'ils fonctionnent comme prévu. Cela peut impliquer la configuration d'alertes et de notifications pour les défaillances du modèle, ainsi que la mise en œuvre de processus pour la maintenance et les mises à jour du modèle. - -5. **Amélioration continue :** MLOps implique l'amélioration continue des modèles d'apprentissage automatique au fil du temps, en fonction des commentaires des utilisateurs et de l'analyse continue des données de performance. Cela peut impliquer de recycler les modèles avec de nouvelles données ou d'intégrer les commentaires des utilisateurs pour affiner les modèles. - -Afin de mettre en œuvre efficacement les MLOps, les organisations doivent généralement adopter une gamme d'outils et de technologies différents, notamment des plates-formes de gestion de données, des cadres d'apprentissage automatique, des outils de conteneurisation et des outils de surveillance et de journalisation. Ils doivent également établir des flux de travail et des processus clairs pour gérer les différentes étapes du cycle de vie de l'apprentissage automatique, ainsi que mettre en œuvre des mesures de gouvernance et de conformité pour garantir la confidentialité et la sécurité des données. - -En résumé, MLOps est un composant essentiel du cycle de vie de l'apprentissage automatique, permettant aux organisations de développer, déployer et maintenir des modèles d'apprentissage automatique à grande échelle. En adoptant des pratiques et des outils MLOps, les organisations peuvent rationaliser leurs flux de travail d'apprentissage automatique, améliorer la précision et les performances des modèles et offrir plus de valeur aux utilisateurs et aux parties prenantes. diff --git a/docs/fr/3-Pipelines/PaaS-Integration.md b/docs/fr/3-Pipelines/PaaS-Integration.md deleted file mode 100644 index bf03427f1..000000000 --- a/docs/fr/3-Pipelines/PaaS-Integration.md +++ /dev/null @@ -1,52 +0,0 @@ -# Aperçu - -_L'un des principaux avantages de la plate-forme ETAA est sa capacité à s'intégrer aux plates-formes d'apprentissage automatique populaires telles que Databricks et AzureML._ - -Espace de travail d'analyse avancée (ETAA) est une plate-forme d'analyse de données open source conçue pour être hautement intégrable. Cela signifie qu'il peut être facilement intégré à d'autres plates-formes et outils pour étendre ses capacités et rationaliser les flux de travail. - -Un exemple de diagramme illustrant une stratégie de connexion PaaS possible : - -
- -
-![PaaS](../images/PaaS.png) -
- -**Configuration :** Si vous avez besoin d'aide pour intégrer une plate-forme en tant qu'offre de service, nous sommes heureux -aider! - -## Intégration avec les offres de plate-forme externe en tant que service (PaaS) - -_L'intégration est la clé du succès._ - -[![Intégration avec PaaS](../images/IntegratePaaS.PNG)]() - -Notre plate-forme open source offre une option inégalée à nos utilisateurs. En permettant aux utilisateurs d'utiliser des outils open source, nous leur donnons la possibilité d'utiliser leurs frameworks de science des données et d'apprentissage automatique préférés. Mais la véritable puissance de notre plateforme vient de sa capacité à s'intégrer à de nombreuses offres de plateforme en tant que service (PaaS), comme Databricks ou AzureML. Cela signifie que nos utilisateurs peuvent tirer parti de la puissance du cloud pour exécuter des pipelines complexes de traitement de données et d'apprentissage automatique à grande échelle. Avec la possibilité de s'intégrer aux offres PaaS, notre plate-forme permet à nos utilisateurs de faire passer leur travail au niveau supérieur, en leur donnant le pouvoir d'adapter facilement leurs charges de travail et de tirer parti des dernières innovations dans le domaine de la science des données et de la machine. apprentissage. En offrant ce niveau d'optionnalité, nous nous assurons que nos utilisateurs peuvent toujours choisir le bon outil pour le travail et garder une longueur d'avance dans un domaine en évolution constante. - -Nous pouvons nous intégrer à de nombreuses offres de plate-forme en tant que service (PaaS), comme Databricks ou AzureML. - -## Briques de données - -- [Databricks de Microsoft](https://azure.microsoft.com/en-ca/services/databricks/) - -Databricks est une plate-forme basée sur le cloud qui fournit une plate-forme d'analyse unifiée pour le traitement du Big Data et l'apprentissage automatique. Avec son puissant moteur de calcul distribué et ses outils de flux de travail rationalisés, Databricks est un choix populaire pour créer et déployer des modèles d'apprentissage automatique. En s'intégrant à Databricks, la plate-forme ETAA peut tirer parti de ses capacités informatiques distribuées pour former et déployer des modèles d'apprentissage automatique à grande échelle. - -## AzureML - -- [Azure ML de Microsoft](https://azure.microsoft.com/en-us/services/machine-learning/) - -AzureML est une autre plate-forme d'apprentissage automatique populaire qui fournit une large gamme d'outils pour créer, former et déployer des modèles d'apprentissage automatique. En s'intégrant à AzureML, la plateforme ETAA peut tirer parti de ses puissants outils de création et de formation de modèles, ainsi que de sa capacité à déployer des modèles dans le cloud. - -### Exemples - -_Des exemples d'intégration de la plate-forme ETAA avec ces plates-formes et d'autres peuvent être trouvés sur le référentiel MLOps Github._ - -- [Dépôt Github MLOps](https://github.com/StatCan/ETAA-kubeflow-mlops) - -Ce référentiel contient une gamme d'exemples et de didacticiels pour l'utilisation de la plate-forme ETAA dans divers flux de travail d'apprentissage automatique, y compris la préparation des données, la formation de modèles et le déploiement de modèles. - -## Conclusion - -En s'intégrant à des plates-formes d'apprentissage automatique populaires telles que Databricks et AzureML, la plate-forme ETAA fournit une solution puissante et flexible pour créer, déployer et gérer des workflows d'apprentissage automatique à grande échelle. - -En tirant parti des intégrations et des outils fournis par ces plates-formes, les scientifiques des données et les ingénieurs en apprentissage automatique peuvent accélérer leurs flux de travail et obtenir de meilleurs résultats avec moins d'effort. diff --git a/docs/fr/3-Pipelines/PaaS.md b/docs/fr/3-Pipelines/PaaS.md deleted file mode 100644 index f3b33a781..000000000 --- a/docs/fr/3-Pipelines/PaaS.md +++ /dev/null @@ -1,12 +0,0 @@ -# Intégrer avec des plateformes comme Databricks et AzureML - -La plateforme AAW est construite autour de l'idée d'intégrations, et nous -pouvons donc s'intégrer avec de nombreuses offres de "plateforme en tant que -service" (PaaS), telles que -[Azure ML](https://azure.microsoft.com/en-us/services/machine-learning/) et -[Databricks](https://azure.microsoft.com/en-ca/services/databricks/). - -Voir quelques exemples dans notre -[Dépôt Github "MLOps"](https://github.com/StatCan/aaw-kubeflow-mlops). - -![PaaS](../images/PaaS.png) diff --git a/docs/fr/3-Pipelines/Serving.md b/docs/fr/3-Pipelines/Serving.md deleted file mode 100644 index 02f5b7d94..000000000 --- a/docs/fr/3-Pipelines/Serving.md +++ /dev/null @@ -1,18 +0,0 @@ -# Service de modèle avec Seldon Core et KFServing - - -!!! warning "⚒ Cette page est en construction ⚒" - La personne qui écrit cette entrée n'en sait pas assez sur cette fonctionnalité pour écrire à son sujet, mais vous pouvez demander sur notre canal en Slack. - -## Sans-serveur avec KNative - -Kubernetes et [KNative] (https://knative.dev/) permettent à vos services de -monter ou descendre en puissance à la demande. Cela vous permet de créer des API -pour servir des modèles d'apprentissage automatique, sans avoir besoin de gérer -l'équilibrage de charge ou la montée en puissance. La plateforme peut gérer -toute votre mise à l'échelle pour vous, afin que vous puissiez vous concentrer -sur la logique du programme. - - -!!! warning "⚒ Cette page est en construction ⚒" - La personne qui rédige cette entrée ne connaît pas suffisamment cette fonctionnalité pour écrire à son sujet, mais vous pouvez demander sur notre canal en Slack. diff --git a/docs/fr/3-Pipelines/sklearn_iris_jsondata.ipynb b/docs/fr/3-Pipelines/sklearn_iris_jsondata.ipynb deleted file mode 100644 index c9256f0e0..000000000 --- a/docs/fr/3-Pipelines/sklearn_iris_jsondata.ipynb +++ /dev/null @@ -1,524 +0,0 @@ -{ - "cells": [ - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Servir un classificateur d'iris avec Seldon\n", - "\n", - "## Objectif du bloc-notes\n", - "\n", - "L'objectif de ce bloc-notes est d'encapsuler un modèle Python \"scikit-learn\" à utiliser comme microservice de prédiction avec Seldon Core." - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Configurer Python\n", - "\n", - "Écrivez requirements.txt et configurez notre environnement virtuel Python." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "execution": { - "iopub.execute_input": "2023-04-27T15:57:57.958799Z", - "iopub.status.busy": "2023-04-27T15:57:57.957866Z", - "iopub.status.idle": "2023-04-27T15:57:57.964285Z", - "shell.execute_reply": "2023-04-27T15:57:57.963484Z", - "shell.execute_reply.started": "2023-04-27T15:57:57.958767Z" - }, - "scrolled": true, - "tags": [] - }, - "outputs": [], - "source": [ - "%%writefile requirements.txt\n", - "scikit-learn\n", - "dill\n", - "pandas\n", - "sklearn\n", - "seldon-core\n", - "requests\n", - "matplotlib" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "execution": { - "iopub.execute_input": "2023-04-27T13:58:18.412667Z", - "iopub.status.busy": "2023-04-27T13:58:18.411840Z", - "iopub.status.idle": "2023-04-27T13:58:19.144219Z", - "shell.execute_reply": "2023-04-27T13:58:19.143136Z", - "shell.execute_reply.started": "2023-04-27T13:58:18.412630Z" - }, - "tags": [] - }, - "outputs": [], - "source": [ - "!if [ ! -d \"./venv\" ]; then python -m venv venv; fi" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "execution": { - "iopub.execute_input": "2023-04-27T13:58:19.302968Z", - "iopub.status.busy": "2023-04-27T13:58:19.302445Z", - "iopub.status.idle": "2023-04-27T13:58:20.355237Z", - "shell.execute_reply": "2023-04-27T13:58:20.353560Z", - "shell.execute_reply.started": "2023-04-27T13:58:19.302929Z" - }, - "tags": [] - }, - "outputs": [], - "source": [ - "!source ./venv/bin/activate" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "execution": { - "iopub.execute_input": "2023-04-27T13:58:20.713063Z", - "iopub.status.busy": "2023-04-27T13:58:20.712216Z", - "iopub.status.idle": "2023-04-27T13:58:21.461588Z", - "shell.execute_reply": "2023-04-27T13:58:21.460429Z", - "shell.execute_reply.started": "2023-04-27T13:58:20.713016Z" - }, - "tags": [] - }, - "outputs": [], - "source": [ - "!if [ ! -d \"/home/jovyan/.config/pip\" ]; then mkdir /home/jovyan/.config/pip; fi" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Seldon ne fonctionne que dans l'environnement de développement ETAA; modifiez `pip.conf` pour récupérer les packages sur internet." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "execution": { - "iopub.execute_input": "2023-04-27T13:58:21.463776Z", - "iopub.status.busy": "2023-04-27T13:58:21.463360Z", - "iopub.status.idle": "2023-04-27T13:58:21.469135Z", - "shell.execute_reply": "2023-04-27T13:58:21.468420Z", - "shell.execute_reply.started": "2023-04-27T13:58:21.463740Z" - }, - "tags": [] - }, - "outputs": [], - "source": [ - "%%writefile /home/jovyan/.config/pip/pip.conf\n", - "[global]\n", - "index-url = https://jfrog.aaw.cloud.statcan.ca/artifactory/api/pypi/pypi-remote/simple" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "execution": { - "iopub.execute_input": "2023-04-27T15:58:01.566928Z", - "iopub.status.busy": "2023-04-27T15:58:01.566106Z", - "iopub.status.idle": "2023-04-27T15:58:05.178871Z", - "shell.execute_reply": "2023-04-27T15:58:05.177536Z", - "shell.execute_reply.started": "2023-04-27T15:58:01.566896Z" - }, - "tags": [] - }, - "outputs": [], - "source": [ - "%%capture\n", - "%pip install -r requirements.txt" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Nous pouvons ajouter le noyau au lanceur JupyterLab pour une réutilisation facile." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "execution": { - "iopub.execute_input": "2023-04-27T13:58:48.714311Z", - "iopub.status.busy": "2023-04-27T13:58:48.713884Z", - "iopub.status.idle": "2023-04-27T13:58:50.178610Z", - "shell.execute_reply": "2023-04-27T13:58:50.177586Z", - "shell.execute_reply.started": "2023-04-27T13:58:48.714273Z" - }, - "tags": [] - }, - "outputs": [], - "source": [ - "!python -m ipykernel install --user --name=sklearn_iris_jsondata" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Déployer le modèle\n", - "\n", - "Écrivez un fichier YAML SeldonDeployment pour le modèle conteneurisé." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "execution": { - "iopub.execute_input": "2023-04-27T14:48:15.600923Z", - "iopub.status.busy": "2023-04-27T14:48:15.600036Z", - "iopub.status.idle": "2023-04-27T14:48:15.606528Z", - "shell.execute_reply": "2023-04-27T14:48:15.605436Z", - "shell.execute_reply.started": "2023-04-27T14:48:15.600890Z" - }, - "tags": [] - }, - "outputs": [], - "source": [ - "%%writefile sklearn_iris_jsondata_deployment.yaml\n", - "apiVersion: machinelearning.seldon.io/v1alpha2\n", - "kind: SeldonDeployment\n", - "metadata:\n", - " name: seldon-deployment-example\n", - " namespace: bryanpaget\n", - "spec:\n", - " name: sklearn-iris-deployment\n", - " annotations:\n", - " sidecar.istio.io/inject: \"false\"\n", - " predictors:\n", - " - componentSpecs:\n", - " - spec:\n", - " containers:\n", - " - image: seldonio/sklearn-iris:0.3\n", - " imagePullPolicy: IfNotPresent\n", - " name: sklearn-iris-classifier\n", - " graph:\n", - " children: []\n", - " endpoint:\n", - " type: REST\n", - " name: sklearn-iris-classifier\n", - " type: MODEL\n", - " name: sklearn-iris-predictor\n", - " replicas: 1" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Déployez SeldonDeployment." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "execution": { - "iopub.execute_input": "2023-04-27T13:58:50.189468Z", - "iopub.status.busy": "2023-04-27T13:58:50.188796Z", - "iopub.status.idle": "2023-04-27T13:58:53.893779Z", - "shell.execute_reply": "2023-04-27T13:58:53.892661Z", - "shell.execute_reply.started": "2023-04-27T13:58:50.189441Z" - }, - "tags": [] - }, - "outputs": [], - "source": [ - "!kubectl create -f sklearn_iris_jsondata_deployment.yaml" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "execution": { - "iopub.execute_input": "2023-04-27T13:58:53.896155Z", - "iopub.status.busy": "2023-04-27T13:58:53.895313Z", - "iopub.status.idle": "2023-04-27T13:58:55.209852Z", - "shell.execute_reply": "2023-04-27T13:58:55.208787Z", - "shell.execute_reply.started": "2023-04-27T13:58:53.896117Z" - }, - "tags": [] - }, - "outputs": [], - "source": [ - "!kubectl rollout status deploy \\\n", - " $(kubectl get deploy -l seldon-deployment-id=seldon-deployment-example \\\n", - " -o jsonpath='{.items[0].metadata.name}')" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Le service est-il disponible ?" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "execution": { - "iopub.execute_input": "2023-04-27T13:58:55.211582Z", - "iopub.status.busy": "2023-04-27T13:58:55.211279Z", - "iopub.status.idle": "2023-04-27T13:58:55.435452Z", - "shell.execute_reply": "2023-04-27T13:58:55.434211Z", - "shell.execute_reply.started": "2023-04-27T13:58:55.211552Z" - }, - "tags": [] - }, - "outputs": [], - "source": [ - "for i in range(60):\n", - " state = !kubectl get sdep seldon-deployment-example -o jsonpath='{.status.state}'\n", - " state = state[0]\n", - " print(state)\n", - " if state == \"Available\":\n", - " break\n", - " time.sleep(1)\n", - "assert state == \"Available\"" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Modèle de test\n", - "\n", - "Avec l'environnement virtuel configuré et activé, importez les bibliothèques Python nécessaires." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "execution": { - "iopub.execute_input": "2023-04-27T15:58:43.902715Z", - "iopub.status.busy": "2023-04-27T15:58:43.901670Z", - "iopub.status.idle": "2023-04-27T15:58:43.906588Z", - "shell.execute_reply": "2023-04-27T15:58:43.905572Z", - "shell.execute_reply.started": "2023-04-27T15:58:43.902678Z" - }, - "tags": [] - }, - "outputs": [], - "source": [ - "import json\n", - "import pandas as pd" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Le classificateur d'iris prend un ensemble de quatre mesures, dans ce cas `[5.964, 1.006, 2.081, 1.031]`, et il renvoie un ensemble de probabilités, une pour chacun des trois types de fleurs d'iris. [Vous pouvez en savoir plus sur les données d'iris ici.](https://archive.ics.uci.edu/ml/datasets/iris) Envoyons quelques données au modèle." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "execution": { - "iopub.execute_input": "2023-04-27T16:05:03.253143Z", - "iopub.status.busy": "2023-04-27T16:05:03.252208Z", - "iopub.status.idle": "2023-04-27T16:05:03.304174Z", - "shell.execute_reply": "2023-04-27T16:05:03.303066Z", - "shell.execute_reply.started": "2023-04-27T16:05:03.253106Z" - }, - "tags": [] - }, - "outputs": [], - "source": [ - "res = !curl -v seldon-deployment-example-sklearn-iris-predictor.bryanpaget.svc.cluster.local:8000/api/v0.1/predictions \\\n", - " -H 'Content-Type: application/json' \\\n", - " -d '{\"data\": {\"ndarray\": [[5.964, 1.006, 2.081, 1.031]]}}'" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Résultats\n", - "\n", - "Ce sont les résultats en JSON brut." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "execution": { - "iopub.execute_input": "2023-04-27T16:05:03.594132Z", - "iopub.status.busy": "2023-04-27T16:05:03.593539Z", - "iopub.status.idle": "2023-04-27T16:05:03.600395Z", - "shell.execute_reply": "2023-04-27T16:05:03.599596Z", - "shell.execute_reply.started": "2023-04-27T16:05:03.594090Z" - }, - "tags": [] - }, - "outputs": [], - "source": [ - "parsed = json.loads(res[-1])\n", - "print(json.dumps(parsed, indent=4, sort_keys=True))" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Cette fonction de traçage révèle un graphique à barres avec l'inférence du classificateur." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "execution": { - "iopub.execute_input": "2023-04-27T16:05:04.188096Z", - "iopub.status.busy": "2023-04-27T16:05:04.187614Z", - "iopub.status.idle": "2023-04-27T16:05:04.541870Z", - "shell.execute_reply": "2023-04-27T16:05:04.540936Z", - "shell.execute_reply.started": "2023-04-27T16:05:04.188045Z" - }, - "tags": [] - }, - "outputs": [], - "source": [ - "def display_iris_classifier_results(res):\n", - " \"\"\" Prend les résultats de classification du classificateur d'iris et les trace dans un graphique à barres pour une visualisation facile des probabilités de classe.\n", - "\n", - " Arguments :\n", - " res (string) : résultats du modèle d'iris servi par Seldon.\n", - " \"\"\"\n", - " results = res[-1]\n", - " results = json.loads(results)\n", - " names = results[\"data\"][\"names\"]\n", - " predictions = results[\"data\"][\"ndarray\"][0]\n", - " model = results[\"meta\"][\"requestPath\"]\n", - " model = model.popitem()\n", - " model, version = model[0], model[1]\n", - "\n", - " df = pd.DataFrame({\"Class\": names, \"Probability\": predictions})\n", - "\n", - " df.plot(\n", - " kind=\"bar\",\n", - " title=model.replace(\"-\", \" \").title(),\n", - " xlabel=\"Classification\",\n", - " ylabel=\"Probability\",\n", - " legend=False\n", - " )\n", - "\n", - "display_iris_classifier_results(res)" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Nettoyer\n", - "\n", - "Nettoyez en supprimant le déploiement." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "execution": { - "iopub.execute_input": "2023-04-27T16:05:04.750111Z", - "iopub.status.busy": "2023-04-27T16:05:04.749559Z", - "iopub.status.idle": "2023-04-27T16:05:07.723921Z", - "shell.execute_reply": "2023-04-27T16:05:07.722248Z", - "shell.execute_reply.started": "2023-04-27T16:05:04.750073Z" - }, - "tags": [] - }, - "outputs": [], - "source": [ - "!kubectl delete -f sklearn_iris_jsondata_deployment.yaml" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": ".venv", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.10.6" - }, - "varInspector": { - "cols": { - "lenName": 16, - "lenType": 16, - "lenVar": 40 - }, - "kernels_config": { - "python": { - "delete_cmd_postfix": "", - "delete_cmd_prefix": "del ", - "library": "var_list.py", - "varRefreshCmd": "print(var_dic_list())" - }, - "r": { - "delete_cmd_postfix": ") ", - "delete_cmd_prefix": "rm(", - "library": "var_list.r", - "varRefreshCmd": "cat(var_dic_list()) " - } - }, - "types_to_exclude": [ - "module", - "function", - "builtin_function_or_method", - "instance", - "_Feature" - ], - "window_display": false - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/docs/fr/images/argo-workflows.jpg b/docs/fr/images/argo-workflows.jpg new file mode 100644 index 0000000000000000000000000000000000000000..3042e54a18d149566187a6268b063878fbd019c1 GIT binary patch literal 60271 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

KCot?B1ha;*)zS0On}vuC*9JdoYlSX5lY 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]u`u1=r>CTcjz593?>xG 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

WhUxmNp;_61H2Zx6_<+p#vJ8h+ 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