Intelligence Artificielle & ML

Progression
NB3BN Info - Centre de Formation Informatique au Maroc
Intelligence Artificielle & ML

Manuel de formation complet - 12 sections - Formation théorique et pratique

12
Sections
4
Niveau
50+
Pages
2024
Édition
Commencer la Formation
Section 1

Introduction à l'IA — Histoire, Concepts et Panorama

Qu'est-ce que l'Intelligence Artificielle ?

L'Intelligence Artificielle (IA) est la capacité d'une machine à imiter des fonctions cognitives humaines : raisonnement, apprentissage, résolution de problèmes, perception et compréhension du langage. Née en 1956 lors de la conférence de Dartmouth, l'IA a connu plusieurs "hivers" et renaissances avant d'exploser avec le Deep Learning à partir de 2012.

Les grandes branches de l'IA :
🤖 Machine Learning — Apprendre à partir de données sans programmation explicite
🧠 Deep Learning — Réseaux de neurones profonds, inspirés du cerveau humain
💬 NLP — Traitement du Langage Naturel (chatbots, traduction, résumé)
👁️ Computer Vision — Reconnaissance d'images et de vidéos
🎮 Reinforcement Learning — Apprentissage par récompenses (jeux, robotique)

Chronologie de l'IA

AnnéeÉvénement clé
1950Alan Turing publie "Computing Machinery and Intelligence" — Test de Turing
1956Conférence de Dartmouth — naissance officielle du terme "Intelligence Artificielle"
1997Deep Blue (IBM) bat le champion du monde d'échecs Garry Kasparov
2012AlexNet révolutionne la reconnaissance d'images — début de l'ère Deep Learning
2016AlphaGo (DeepMind) bat le champion mondial de Go — jeu jugé impossible pour l'IA
2017Transformer — architecture qui révolutionne le NLP (BERT, GPT)
2022ChatGPT (OpenAI) dépasse 100M d'utilisateurs en 2 mois
2024IA générative : GPT-4, Gemini, Claude, Midjourney — IA accessible à tous

Types d'IA selon le niveau de généralisation

IA Étroite (ANI) Performante dans un domaine précis : reconnaissance vocale, filtres anti-spam, recommandations Netflix. C'est l'IA d'aujourd'hui.
IA Générale (AGI) Capacités cognitives équivalentes à l'humain, dans tous les domaines. Objectif des chercheurs, pas encore atteint.
Super-IA (ASI) Surpasse l'intelligence humaine dans tous les domaines. Concept théorique et sujet de débat éthique.

Applications de l'IA dans le quotidien

SecteurApplicationExemple concret
SantéDiagnostic médicalDétection du cancer sur radios (précision 97%)
FinanceDétection de fraudeVisa bloque 4B$ de fraudes/an grâce à l'IA
TransportConduite autonomeTesla Autopilot, Waymo robotaxi
ÉducationTutorat personnaliséKhan Academy + GPT-4 Khanmigo
AgricultureAnalyse de culturesDrones IA détectent maladies des plantes
IndustrieMaintenance prédictivePrévision pannes machines avant qu'elles arrivent

Environnement de Travail IA

1
Python 3.10+ — Le langage de référence pour l'IA/ML
2
Jupyter Notebook — Environnement interactif pour explorer les données
3
Google Colab — GPU gratuit dans le cloud pour entraîner des modèles
4
Bibliothèques — NumPy, Pandas, Matplotlib, scikit-learn, TensorFlow, PyTorch

Question : Quelle architecture a révolutionné le NLP en 2017 ?

CNN (Convolutional Neural Network)
RNN (Recurrent Neural Network)
Transformer ✓
GAN (Generative Adversarial Network)
Section 2

Mathématiques pour l'IA — Algèbre, Statistiques et Calcul

Les Fondations Mathématiques de l'IA

L'IA repose sur des bases mathématiques solides. Comprendre ces concepts vous permettra de choisir les bons algorithmes, d'interpréter les résultats et de déboguer vos modèles.

Algèbre Linéaire — Vecteurs et Matrices

import numpy as np

# ── Vecteurs ──
v = np.array([1, 2, 3])       # Vecteur colonne
print(v.shape)                 # (3,)
print(np.dot(v, v))            # Produit scalaire = 14
print(np.linalg.norm(v))       # Norme = √14 ≈ 3.74

# ── Matrices ──
A = np.array([[1, 2], [3, 4], [5, 6]])   # Matrice 3×2
B = np.array([[7, 8], [9, 10]])           # Matrice 2×2

print(A.shape)       # (3, 2)
print(A @ B)         # Produit matriciel (3×2) × (2×2) = (3×2)
print(A.T)           # Transposée — (2×3)
print(np.linalg.det(B))  # Déterminant de B

# ── Décomposition en valeurs propres ──
valeurs, vecteurs = np.linalg.eig(B)
print("Valeurs propres :", valeurs)

# ── SVD (Singular Value Decomposition) — PCA, compression ──
U, S, Vt = np.linalg.svd(A)
print("Valeurs singulières :", S)

Statistiques Descriptives

import numpy as np
import pandas as pd

notes = np.array([12, 15, 8, 17, 10, 14, 18, 9, 16, 13])

# ── Mesures de tendance centrale ──
print(f"Moyenne  : {np.mean(notes):.2f}")    # 13.20
print(f"Médiane  : {np.median(notes):.2f}")  # 13.50
# Mode : valeur la plus fréquente
from scipy import stats
print(f"Mode     : {stats.mode(notes).mode}")

# ── Mesures de dispersion ──
print(f"Variance : {np.var(notes):.2f}")     # Dispersion carrée
print(f"Écart-type : {np.std(notes):.2f}")   # Dispersion linéaire
print(f"IQR      : {np.percentile(notes,75) - np.percentile(notes,25):.2f}")
print(f"Min/Max  : {np.min(notes)} / {np.max(notes)}")

# ── Distribution ──
percentile_25 = np.percentile(notes, 25)   # 1er quartile
percentile_75 = np.percentile(notes, 75)   # 3ème quartile

Probabilités — Base du Machine Learning

import numpy as np

# ── Probabilité conditionnelle : P(A|B) = P(A∩B) / P(B) ──
# Exemple : P(admis | a étudié) ?
# P(étudié) = 0.7, P(admis ∩ étudié) = 0.6
p_etudie = 0.7
p_admis_et_etudie = 0.6
p_admis_sachant_etudie = p_admis_et_etudie / p_etudie
print(f"P(admis|étudié) = {p_admis_sachant_etudie:.2f}")  # 0.857

# ── Théorème de Bayes ──
# P(H|E) = P(E|H) × P(H) / P(E)
# Exemple : test médical
p_maladie        = 0.01     # 1% de la population
p_positif_malade = 0.95     # 95% de vrais positifs
p_positif_sain   = 0.05     # 5% de faux positifs
p_positif        = p_positif_malade * p_maladie + p_positif_sain * (1 - p_maladie)
p_malade_positif = (p_positif_malade * p_maladie) / p_positif
print(f"P(malade|positif) = {p_malade_positif:.3f}")  # 0.161 !

Calcul Différentiel — Descente de Gradient

import numpy as np
import matplotlib.pyplot as plt

# ── Descente de gradient : minimiser une fonction coût ──
# Exemple : minimiser f(x) = x² - 4x + 5

def f(x):      return x**2 - 4*x + 5
def df_dx(x):  return 2*x - 4          # Dérivée de f

# Algorithme de descente de gradient
x = 0.0            # Point de départ
lr = 0.1           # Learning rate (taux d'apprentissage)
historique = []

for iteration in range(50):
    gradient = df_dx(x)
    x = x - lr * gradient             # Mise à jour : x ← x - α∇f(x)
    historique.append((x, f(x)))
    if abs(gradient) < 1e-6:           # Convergence
        print(f"Convergé en {iteration} itérations")
        break

print(f"Minimum trouvé : x = {x:.4f}, f(x) = {f(x):.4f}")
# Minimum à x=2, f(2)=1

Normalisation et Standardisation des Données

from sklearn.preprocessing import MinMaxScaler, StandardScaler
import numpy as np

X = np.array([[1000, 2], [1500, 5], [800, 1], [2000, 8]])

# ── Min-Max Scaling : valeurs dans [0, 1] ──
scaler_mm = MinMaxScaler()
X_mm = scaler_mm.fit_transform(X)
print("Min-Max:
", X_mm)

# ── Standardisation Z-score : moyenne=0, écart-type=1 ──
scaler_std = StandardScaler()
X_std = scaler_std.fit_transform(X)
print("Z-score:
", X_std)

# ── Quand utiliser quoi ? ──
# Min-Max : réseaux de neurones, k-NN, quand pas de valeurs aberrantes
# Z-score : régression linéaire, SVM, quand données gaussiennes
Important : Toujours normaliser/standardiser les données AVANT d'entraîner un modèle ML. Les algorithmes sont sensibles aux différences d'échelle entre variables.

Question : La descente de gradient minimise une fonction en se déplaçant dans quelle direction ?

Dans le sens du gradient (montée)
Dans le sens opposé au gradient (descente) ✓
Aléatoirement
Perpendiculairement au gradient
Section 3

Machine Learning — Algorithmes Supervisés

L'Apprentissage Supervisé

Dans l'apprentissage supervisé, le modèle apprend à partir d'exemples étiquetés (données + réponses connues). Il apprend à prédire la réponse pour de nouvelles données inconnues.

Deux types de problèmes :
📈 Régression — Prédire une valeur numérique continue (prix d'un appartement, température de demain)
🏷️ Classification — Prédire une catégorie (spam/non-spam, chien/chat/oiseau, admis/refusé)

Régression Linéaire

from sklearn.linear_model import LinearRegression
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error, r2_score
import numpy as np

# ── Données : surface (m²) → prix (MAD) ──
X = np.array([[50],[65],[80],[95],[110],[125],[140],[155]]).reshape(-1,1)
y = np.array([450000, 580000, 720000, 860000, 990000, 1100000, 1250000, 1380000])

# ── Diviser en train/test ──
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# ── Entraîner ──
model = LinearRegression()
model.fit(X_train, y_train)

# ── Prédire ──
y_pred = model.predict(X_test)

# ── Évaluer ──
mse = mean_squared_error(y_test, y_pred)
r2  = r2_score(y_test, y_pred)
print(f"Coefficient directeur : {model.coef_[0]:,.0f} MAD/m²")
print(f"Ordonnée à l'origine  : {model.intercept_:,.0f} MAD")
print(f"R² Score              : {r2:.3f}")  # 1.0 = parfait
print(f"RMSE                  : {np.sqrt(mse):,.0f} MAD")

# ── Prédiction ──
surface = np.array([[100]])
prix = model.predict(surface)
print(f"Appartement 100m² ≈ {prix[0]:,.0f} MAD")

Régression Logistique — Classification

from sklearn.linear_model import LogisticRegression
from sklearn.metrics import classification_report, confusion_matrix
import numpy as np

# ── Données : heures de travail + note → admis (0/1) ──
X = np.array([[2,8],[5,12],[8,15],[3,9],[7,14],[1,6],[9,17],[4,11]])
y = np.array([0, 1, 1, 0, 1, 0, 1, 1])  # 0=refusé, 1=admis

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.25)

# ── Entraîner ──
model = LogisticRegression()
model.fit(X_train, y_train)

# ── Évaluer ──
y_pred = model.predict(X_test)
print(classification_report(y_test, y_pred, target_names=['Refusé','Admis']))

# ── Matrice de confusion ──
cm = confusion_matrix(y_test, y_pred)
print("Vrais Positifs :", cm[1][1])
print("Faux Positifs  :", cm[0][1])

# ── Probabilité ──
proba = model.predict_proba([[6, 13]])
print(f"P(admis) = {proba[0][1]:.2%}")

Arbres de Décision et Random Forest

from sklearn.tree import DecisionTreeClassifier, export_text
from sklearn.ensemble import RandomForestClassifier
from sklearn.datasets import load_iris

# ── Arbre de Décision ──
iris = load_iris()
X, y = iris.data, iris.target

model_tree = DecisionTreeClassifier(max_depth=3, random_state=42)
model_tree.fit(X, y)
print(export_text(model_tree, feature_names=iris.feature_names))
print(f"Précision arbre : {model_tree.score(X, y):.3f}")

# ── Random Forest (ensemble d'arbres) ──
model_rf = RandomForestClassifier(
    n_estimators=100,    # 100 arbres
    max_depth=5,
    random_state=42,
    n_jobs=-1            # Utiliser tous les CPU
)
model_rf.fit(X, y)
print(f"Précision forêt : {model_rf.score(X, y):.3f}")

# ── Importance des variables ──
importances = model_rf.feature_importances_
for nom, imp in zip(iris.feature_names, importances):
    print(f"  {nom:25} : {imp:.3f}")

Support Vector Machine (SVM)

from sklearn.svm import SVC, SVR
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import Pipeline

# ── SVM Classification ──
pipeline = Pipeline([
    ('scaler', StandardScaler()),           # Normalisation obligatoire pour SVM
    ('svm', SVC(kernel='rbf', C=1.0, gamma='scale', probability=True))
])

pipeline.fit(X_train, y_train)
print(f"SVM Score : {pipeline.score(X_test, y_test):.3f}")

# ── Kernels disponibles ──
# 'linear'  : séparation linéaire
# 'rbf'     : Radial Basis Function — le plus courant pour données non-linéaires
# 'poly'    : polynomial — pour données avec frontières courbées
# 'sigmoid' : similaire aux réseaux de neurones

Validation Croisée et Métriques

from sklearn.model_selection import cross_val_score, GridSearchCV

# ── Cross-validation (K-Fold) ──
scores = cross_val_score(model_rf, X, y, cv=5, scoring='accuracy')
print(f"CV Scores : {scores}")
print(f"Moyenne   : {scores.mean():.3f} ± {scores.std():.3f}")

# ── GridSearchCV : trouver les meilleurs hyperparamètres ──
param_grid = {
    'n_estimators': [50, 100, 200],
    'max_depth': [3, 5, 10, None],
    'min_samples_split': [2, 5, 10]
}
grid = GridSearchCV(RandomForestClassifier(), param_grid, cv=5, n_jobs=-1)
grid.fit(X_train, y_train)
print("Meilleurs paramètres :", grid.best_params_)
print("Meilleur score       :", grid.best_score_)

Question : Quelle métrique mesure la proportion de prédictions correctes parmi toutes les prédictions ?

Recall (rappel)
Précision
Accuracy (exactitude) ✓
F1-Score
Section 4

Machine Learning Non Supervisé — Clustering et Réduction

L'Apprentissage Non Supervisé

Dans l'apprentissage non supervisé, il n'y a pas d'étiquettes. L'algorithme découvre lui-même la structure cachée dans les données. Utilisé pour : segmenter des clients, détecter des anomalies, compresser des données.

K-Means — Algorithme de Clustering

from sklearn.cluster import KMeans
from sklearn.preprocessing import StandardScaler
import numpy as np
import matplotlib.pyplot as plt

# ── Données : étudiants (heures de travail, note) ──
np.random.seed(42)
groupe_A = np.random.randn(50, 2) + [8, 17]   # Bons étudiants
groupe_B = np.random.randn(50, 2) + [4, 12]   # Étudiants moyens
groupe_C = np.random.randn(50, 2) + [2, 7]    # Étudiants en difficulté
X = np.vstack([groupe_A, groupe_B, groupe_C])

# ── Normaliser ──
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)

# ── K-Means ──
kmeans = KMeans(n_clusters=3, random_state=42, n_init=10)
kmeans.fit(X_scaled)
labels = kmeans.labels_

print("Répartition des clusters :")
for k in range(3):
    print(f"  Cluster {k} : {np.sum(labels == k)} étudiants")

# ── Méthode du coude : trouver le bon k ──
inertias = []
for k in range(1, 10):
    km = KMeans(n_clusters=k, random_state=42, n_init=10)
    km.fit(X_scaled)
    inertias.append(km.inertia_)
# Tracer inertias pour identifier le "coude"

DBSCAN — Clustering par Densité

from sklearn.cluster import DBSCAN

# DBSCAN détecte les formes non-sphériques et les anomalies
dbscan = DBSCAN(eps=0.5, min_samples=5)
labels = dbscan.fit_predict(X_scaled)

n_clusters = len(set(labels)) - (1 if -1 in labels else 0)
n_noise    = list(labels).count(-1)
print(f"Clusters trouvés  : {n_clusters}")
print(f"Points aberrants  : {n_noise}")

# ── Avantages DBSCAN vs K-Means ──
# ✅ Pas besoin de spécifier k
# ✅ Détecte les formes arbitraires
# ✅ Identifie les anomalies (label = -1)
# ❌ Sensible aux paramètres eps et min_samples

PCA — Réduction de Dimensionnalité

from sklearn.decomposition import PCA
from sklearn.datasets import load_digits
import numpy as np

# ── Données : chiffres manuscrits (1797 images 8×8 = 64 dimensions) ──
digits = load_digits()
X = digits.data      # shape: (1797, 64)
y = digits.target

# ── Réduire à 2 dimensions pour visualisation ──
pca_2d = PCA(n_components=2)
X_2d = pca_2d.fit_transform(X)
print(f"Variance expliquée (2D) : {pca_2d.explained_variance_ratio_.sum():.1%}")

# ── Réduire à 95% de variance conservée ──
pca_95 = PCA(n_components=0.95)
X_95 = pca_95.fit_transform(X)
print(f"Dimensions conservées (95% variance) : {X_95.shape[1]}")

# ── Variance expliquée par composante ──
for i, var in enumerate(pca_2d.explained_variance_ratio_):
    print(f"  PC{i+1} : {var:.1%} de la variance")

Détection d'Anomalies

from sklearn.ensemble import IsolationForest
from sklearn.svm import OneClassSVM
import numpy as np

# ── Données de transactions bancaires ──
np.random.seed(42)
normales   = np.random.randn(1000, 2)           # 1000 transactions normales
anomalies  = np.random.randn(20, 2) * 5 + 10   # 20 transactions frauduleuses
X = np.vstack([normales, anomalies])

# ── Isolation Forest ──
iso_forest = IsolationForest(
    contamination=0.02,    # 2% de données anormales estimées
    random_state=42
)
predictions = iso_forest.fit_predict(X)
# 1 = normal, -1 = anomalie

n_anomalies = np.sum(predictions == -1)
print(f"Anomalies détectées : {n_anomalies}")

# ── Cas d'usage ──
# Fraude bancaire       : transactions inhabituelles
# Cybersécurité         : comportements réseau anormaux
# Industrie             : pannes machines prédictives
# Qualité               : produits défectueux sur chaîne de fabrication

Association Rules — Market Basket Analysis

from mlxtend.frequent_patterns import apriori, association_rules
import pandas as pd

# ── Transactions d'une boutique ──
transactions = [
    ['pain', 'beurre', 'lait'],
    ['pain', 'lait'],
    ['beurre', 'oeufs', 'lait'],
    ['pain', 'beurre', 'oeufs', 'lait'],
    ['pain', 'oeufs'],
]

# ── Encoder en format binaire ──
from mlxtend.preprocessing import TransactionEncoder
te = TransactionEncoder()
te_arr = te.fit(transactions).transform(transactions)
df = pd.DataFrame(te_arr, columns=te.columns_)

# ── Trouver les itemsets fréquents ──
freq_items = apriori(df, min_support=0.6, use_colnames=True)
rules = association_rules(freq_items, metric='confidence', min_threshold=0.7)
print(rules[['antecedents','consequents','support','confidence','lift']])

Question : Quelle algorithme de clustering ne nécessite pas de spécifier le nombre de clusters k à l'avance ?

K-Means
DBSCAN ✓
K-Medoids
Hierarchical Clustering avec k fixé
Section 5

Deep Learning — Réseaux de Neurones avec TensorFlow/Keras

Comprendre les Réseaux de Neurones

Un réseau de neurones artificiel est inspiré du cerveau humain. Il est composé de couches de neurones connectés qui transforment progressivement les données d'entrée pour produire une sortie.

Architecture d'un neurone artificiel :
Entrées (x₁, x₂, ...) → Poids (w₁, w₂, ...) → Somme pondérée → Fonction d'activation → Sortie

Fonctions d'Activation

FonctionFormuleUsage
ReLUmax(0, x)Couches cachées — standard
Sigmoid1/(1+e⁻ˣ)Classification binaire (sortie)
Softmaxeˣⁱ/ΣeˣʲClassification multi-classes (sortie)
Tanh(eˣ-e⁻ˣ)/(eˣ+e⁻ˣ)RNN, LSTM
Leaky ReLUmax(0.01x, x)Évite le "dying ReLU"

Construire un Réseau de Neurones avec Keras

import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers
import numpy as np

# ── Données : classification de notes (admis/refusé) ──
X_train = np.random.rand(1000, 5)  # 5 features
y_train = (X_train[:, 0] + X_train[:, 1] > 1).astype(int)

# ── Construire le modèle ──
model = keras.Sequential([
    # Couche d'entrée + première couche cachée
    layers.Dense(64, activation='relu', input_shape=(5,)),
    layers.Dropout(0.3),        # Dropout : désactive 30% des neurones (régularisation)

    # Deuxième couche cachée
    layers.Dense(32, activation='relu'),
    layers.BatchNormalization(),  # Normalise les activations

    # Troisième couche cachée
    layers.Dense(16, activation='relu'),

    # Couche de sortie
    layers.Dense(1, activation='sigmoid')  # Sortie binaire [0, 1]
])

# ── Compiler ──
model.compile(
    optimizer=keras.optimizers.Adam(learning_rate=0.001),
    loss='binary_crossentropy',  # Pour classification binaire
    metrics=['accuracy']
)

model.summary()  # Affiche l'architecture

# ── Entraîner ──
history = model.fit(
    X_train, y_train,
    epochs=50,
    batch_size=32,
    validation_split=0.2,    # 20% pour validation
    callbacks=[
        keras.callbacks.EarlyStopping(patience=5, restore_best_weights=True),
        keras.callbacks.ReduceLROnPlateau(factor=0.5, patience=3)
    ],
    verbose=1
)

Réseau Multi-Classes (Softmax)

from tensorflow.keras.datasets import mnist

# ── Charger MNIST : chiffres manuscrits 28×28 ──
(X_train, y_train), (X_test, y_test) = mnist.load_data()

# ── Prétraitement ──
X_train = X_train.reshape(-1, 784).astype('float32') / 255.0
X_test  = X_test.reshape(-1, 784).astype('float32') / 255.0
y_train = keras.utils.to_categorical(y_train, 10)  # One-hot encoding
y_test  = keras.utils.to_categorical(y_test, 10)

# ── Modèle ──
model = keras.Sequential([
    layers.Dense(512, activation='relu', input_shape=(784,)),
    layers.Dropout(0.2),
    layers.Dense(256, activation='relu'),
    layers.Dropout(0.2),
    layers.Dense(10, activation='softmax')   # 10 classes (0-9)
])

model.compile(
    optimizer='adam',
    loss='categorical_crossentropy',
    metrics=['accuracy']
)

model.fit(X_train, y_train, epochs=10, batch_size=128, validation_split=0.1)
loss, acc = model.evaluate(X_test, y_test)
print(f"Test accuracy : {acc:.4f}")   # ~98%

Sauvegarder et Charger un Modèle

# ── Sauvegarder ──
model.save('mon_modele.keras')               # Format Keras natif
model.save_weights('poids_modele.weights.h5') # Seulement les poids

# ── Charger ──
model_charge = keras.models.load_model('mon_modele.keras')
predictions  = model_charge.predict(X_test[:5])

# ── Exporter pour production (TensorFlow Serving) ──
model.export('modele_prod/')
# Déploiement via TF Serving, FastAPI, ou TFLite (mobile)
Conseil : Utilisez Google Colab (colab.research.google.com) pour accéder gratuitement à des GPU T4 pour entraîner vos modèles. Les calculs sont jusqu'à 100× plus rapides qu'un CPU classique.

Question : Quelle fonction d'activation est recommandée pour la couche de sortie d'une classification multi-classes ?

ReLU
Sigmoid
Softmax ✓
Tanh
Section 6

CNN — Réseaux de Neurones Convolutifs et Vision par Ordinateur

Les CNN : Spécialistes de la Vision

Les Réseaux de Neurones Convolutifs (CNN) sont conçus spécifiquement pour traiter les images. Au lieu de connecter tous les neurones entre eux, ils utilisent des filtres qui glissent sur l'image pour détecter des motifs locaux : bords, textures, formes.

Architecture d'un CNN

from tensorflow import keras
from tensorflow.keras import layers

# ── CNN pour classification CIFAR-10 (10 catégories d'images) ──
model = keras.Sequential([

    # ── Bloc 1 : détecter les bords et textures ──
    layers.Conv2D(32, (3,3), activation='relu', padding='same', input_shape=(32,32,3)),
    layers.Conv2D(32, (3,3), activation='relu', padding='same'),
    layers.MaxPooling2D(2, 2),      # Réduire de 32×32 → 16×16
    layers.Dropout(0.25),

    # ── Bloc 2 : détecter formes plus complexes ──
    layers.Conv2D(64, (3,3), activation='relu', padding='same'),
    layers.Conv2D(64, (3,3), activation='relu', padding='same'),
    layers.MaxPooling2D(2, 2),      # Réduire de 16×16 → 8×8
    layers.Dropout(0.25),

    # ── Bloc 3 : détecter objets entiers ──
    layers.Conv2D(128, (3,3), activation='relu', padding='same'),
    layers.MaxPooling2D(2, 2),      # 8×8 → 4×4
    layers.Dropout(0.25),

    # ── Classificateur ──
    layers.Flatten(),               # Aplatir 4×4×128 = 2048 neurones
    layers.Dense(512, activation='relu'),
    layers.Dropout(0.5),
    layers.Dense(10, activation='softmax')  # 10 catégories CIFAR-10
])

model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])
model.summary()

Transfer Learning — Réutiliser un Modèle Pré-entraîné

from tensorflow.keras.applications import VGG16, ResNet50, MobileNetV2

# ── Charger VGG16 pré-entraîné sur ImageNet (1.4M images, 1000 classes) ──
base_model = MobileNetV2(
    weights='imagenet',
    include_top=False,       # Supprimer la tête de classification
    input_shape=(224, 224, 3)
)
base_model.trainable = False   # Geler les poids de base

# ── Ajouter notre classificateur personnalisé ──
model = keras.Sequential([
    base_model,
    layers.GlobalAveragePooling2D(),
    layers.Dense(256, activation='relu'),
    layers.Dropout(0.5),
    layers.Dense(5, activation='softmax')   # 5 classes personnalisées
])

model.compile(optimizer=keras.optimizers.Adam(1e-4),
              loss='categorical_crossentropy', metrics=['accuracy'])

# ── Fine-tuning : dégeler les dernières couches ──
base_model.trainable = True
for layer in base_model.layers[:-20]:
    layer.trainable = False          # Garder les 20 dernières couches entraînables

model.compile(optimizer=keras.optimizers.Adam(1e-5), ...)  # LR plus faible

Augmentation de Données

from tensorflow.keras.preprocessing.image import ImageDataGenerator

# ── Augmentation pour éviter le sur-apprentissage ──
datagen = ImageDataGenerator(
    rescale=1./255,
    rotation_range=20,          # Rotation ±20°
    width_shift_range=0.2,      # Décalage horizontal 20%
    height_shift_range=0.2,     # Décalage vertical 20%
    shear_range=0.2,             # Cisaillement
    zoom_range=0.2,              # Zoom ±20%
    horizontal_flip=True,        # Retournement horizontal
    fill_mode='nearest'
)

# ── Charger depuis dossiers ──
train_gen = datagen.flow_from_directory(
    'data/train/',
    target_size=(224, 224),
    batch_size=32,
    class_mode='categorical'
)

model.fit(train_gen, epochs=20, validation_data=val_gen)

OpenCV — Traitement d'Images

import cv2
import numpy as np

# ── Lire et afficher ──
img = cv2.imread('photo.jpg')
img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)  # OpenCV utilise BGR !

# ── Transformations ──
gris      = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
redim     = cv2.resize(img, (224, 224))
flou      = cv2.GaussianBlur(img, (5,5), 0)
bords     = cv2.Canny(gris, 100, 200)            # Détection de bords

# ── Détection de visages (Haar Cascade) ──
cascades = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_frontalface_default.xml')
visages  = cascades.detectMultiScale(gris, scaleFactor=1.1, minNeighbors=5)
for (x, y, w, h) in visages:
    cv2.rectangle(img, (x,y), (x+w, y+h), (0,255,0), 2)

# ── Préparer une image pour un modèle Keras ──
img_preprocessed = cv2.resize(img_rgb, (224, 224))
img_array = np.expand_dims(img_preprocessed / 255.0, axis=0)  # (1, 224, 224, 3)
prediction = model.predict(img_array)

Question : Qu'est-ce que le Transfer Learning en Deep Learning ?

Transférer des données entre GPU et CPU
Réutiliser un modèle pré-entraîné sur de nouvelles tâches ✓
Exporter un modèle vers un autre framework
Entraîner un modèle sur plusieurs machines
Section 7

NLP — Traitement du Langage Naturel et Transformers

Le Traitement du Langage Naturel

Le NLP (Natural Language Processing) permet aux machines de comprendre, générer et manipuler le langage humain. C'est la technologie derrière ChatGPT, Google Translate, Siri et les filtres anti-spam.

Prétraitement du Texte

import re
import nltk
from nltk.tokenize import word_tokenize, sent_tokenize
from nltk.corpus import stopwords
from nltk.stem import PorterStemmer, WordNetLemmatizer

nltk.download(['punkt','stopwords','wordnet'])

texte = "Les étudiants de NB3BN Info apprennent l'intelligence artificielle depuis 2020."

# ── Tokenisation ──
tokens_mots    = word_tokenize(texte, language='french')
tokens_phrases = sent_tokenize(texte, language='french')
print("Tokens :", tokens_mots)

# ── Suppression de la ponctuation et mise en minuscules ──
tokens_propres = [t.lower() for t in tokens_mots if t.isalpha()]

# ── Suppression des mots vides (stopwords) ──
stops = set(stopwords.words('french'))
tokens_utiles = [t for t in tokens_propres if t not in stops]
print("Tokens utiles :", tokens_utiles)

# ── Stemming (racine) ──
stemmer = PorterStemmer()
stems = [stemmer.stem(t) for t in tokens_utiles]

# ── Lemmatisation (forme canonique) ──
lemm = WordNetLemmatizer()
lemmes = [lemm.lemmatize(t) for t in tokens_utiles]

Vectorisation du Texte

from sklearn.feature_extraction.text import TfidfVectorizer, CountVectorizer

corpus = [
    "Python est un excellent langage de programmation",
    "L'IA avec Python est très puissante",
    "Le machine learning utilise Python et des maths",
    "JavaScript est utilisé pour le développement web",
]

# ── Bag of Words ──
cv = CountVectorizer()
X_bow = cv.fit_transform(corpus)
print("Vocabulaire :", cv.get_feature_names_out())

# ── TF-IDF (Term Frequency - Inverse Document Frequency) ──
# Donne plus de poids aux mots importants et rares
tfidf = TfidfVectorizer(max_features=100, ngram_range=(1,2))
X_tfidf = tfidf.fit_transform(corpus)
print("Forme TF-IDF :", X_tfidf.shape)

# ── Word Embeddings (Word2Vec) ──
from gensim.models import Word2Vec
phrases = [phrase.lower().split() for phrase in corpus]
w2v = Word2Vec(phrases, vector_size=100, window=5, min_count=1)
vecteur_python = w2v.wv['python']   # Vecteur de 100 dimensions
print("Mots similaires :", w2v.wv.most_similar('python'))

Transformers et Hugging Face

from transformers import pipeline, AutoTokenizer, AutoModelForSequenceClassification

# ── Pipelines prêts à l'emploi (zéro configuration) ──

# Analyse de sentiment
sentiment = pipeline("sentiment-analysis", model="nlptown/bert-base-multilingual-uncased-sentiment")
result = sentiment("NB3BN Info offre d'excellentes formations !")
print(result)  # [{'label': '5 stars', 'score': 0.89}]

# Génération de texte
generateur = pipeline("text-generation", model="gpt2")
texte = generateur("L'intelligence artificielle va", max_length=50)
print(texte[0]['generated_text'])

# Question-Réponse (extractif)
qa = pipeline("question-answering", model="distilbert-base-cased-distilled-squad")
contexte = "NB3BN Info est un centre de formation basé à Casablanca fondé en 2015."
question = "Où se trouve NB3BN Info ?"
reponse  = qa(question=question, context=contexte)
print("Réponse :", reponse['answer'])  # "Casablanca"

# Traduction
traducteur = pipeline("translation_fr_to_en", model="Helsinki-NLP/opus-mt-fr-en")
traduction = traducteur("Bonjour, je m'appelle Ali.")
print(traduction[0]['translation_text'])  # "Hello, my name is Ali."

# Résumé automatique
resumeur = pipeline("summarization", model="facebook/bart-large-cnn")
article = "..."   # Article long
resume = resumeur(article, max_length=130, min_length=30)
print(resume[0]['summary_text'])

Construire un Chatbot Simple

from transformers import AutoTokenizer, AutoModelForCausalLM
import torch

# ── Chatbot avec DialoGPT ──
tokenizer = AutoTokenizer.from_pretrained("microsoft/DialoGPT-medium")
model     = AutoModelForCausalLM.from_pretrained("microsoft/DialoGPT-medium")

historique = None

def chat(message):
    global historique
    # Encoder le message
    input_ids = tokenizer.encode(message + tokenizer.eos_token, return_tensors='pt')

    # Concaténer avec l'historique
    bot_input = torch.cat([historique, input_ids], dim=-1) if historique is not None else input_ids

    # Générer une réponse
    historique = model.generate(bot_input, max_length=1000, pad_token_id=tokenizer.eos_token_id)

    # Décoder la réponse
    reponse = tokenizer.decode(historique[:, bot_input.shape[-1]:][0], skip_special_tokens=True)
    return reponse

print(chat("Bonjour, comment ça va ?"))
print(chat("Parle-moi de l'IA"))

Question : Que représente "TF-IDF" en NLP ?

Text Format - Image Description Features
Term Frequency - Inverse Document Frequency ✓
Training Features - Input Data Format
Token Frequency - Index Data Field
Section 8

IA Générative — GANs, Diffusion et LLMs

L'IA Générative : Créer du Nouveau Contenu

L'IA générative crée du nouveau contenu — images, texte, musique, code, vidéo — à partir de données d'entraînement. C'est la révolution la plus visible de l'IA depuis 2022.

Types d'IA Générative :
🖼️ GAN — Génère des images réalistes (Midjourney, Stable Diffusion)
📝 LLM — Large Language Models : GPT-4, Claude, Gemini, LLaMA
🔊 Audio — Génère de la musique ou des voix (Suno, ElevenLabs)
🎬 Vidéo — Génère des vidéos (Sora, Runway, Kling)

GAN — Generative Adversarial Network

import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers
import numpy as np

# ── Architecture GAN ──
# Générateur (G) : bruit aléatoire → fausse image
# Discriminateur (D) : image → probabilité d'être réelle

# ── Générateur ──
def construire_generateur(latent_dim=100):
    model = keras.Sequential([
        layers.Dense(256, input_dim=latent_dim),
        layers.LeakyReLU(0.2),
        layers.BatchNormalization(),
        layers.Dense(512),
        layers.LeakyReLU(0.2),
        layers.BatchNormalization(),
        layers.Dense(1024),
        layers.LeakyReLU(0.2),
        layers.Dense(784, activation='tanh'),  # 28×28 pixels
        layers.Reshape((28, 28, 1))
    ])
    return model

# ── Discriminateur ──
def construire_discriminateur():
    model = keras.Sequential([
        layers.Flatten(input_shape=(28, 28, 1)),
        layers.Dense(512),
        layers.LeakyReLU(0.2),
        layers.Dropout(0.4),
        layers.Dense(256),
        layers.LeakyReLU(0.2),
        layers.Dropout(0.4),
        layers.Dense(1, activation='sigmoid')  # Réel=1, Faux=0
    ])
    return model

# ── Entraînement (simplifié) ──
G = construire_generateur()
D = construire_discriminateur()

D.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy'])
D.trainable = False

# GAN = G + D (D gelé)
z = keras.Input(shape=(100,))
img_gen = G(z)
validite = D(img_gen)
gan = keras.Model(z, validite)
gan.compile(optimizer='adam', loss='binary_crossentropy')

Utiliser des LLMs via API

import requests
import json

# ── OpenAI API (ChatGPT, GPT-4) ──
def appeler_gpt(message, model="gpt-4o-mini"):
    response = requests.post(
        "https://api.openai.com/v1/chat/completions",
        headers={
            "Authorization": f"Bearer {CLE_API_OPENAI}",
            "Content-Type": "application/json"
        },
        json={
            "model": model,
            "messages": [{"role": "user", "content": message}],
            "temperature": 0.7,
            "max_tokens": 1000
        }
    )
    return response.json()['choices'][0]['message']['content']

# ── Ollama : LLM local (gratuit, privé) ──
def appeler_llama(message):
    response = requests.post(
        "http://localhost:11434/api/generate",
        json={"model": "llama3", "prompt": message, "stream": False}
    )
    return response.json()['response']

# ── RAG : Retrieval-Augmented Generation ──
# 1. Indexer les documents dans une base vectorielle (Chroma, Pinecone)
# 2. Pour chaque question : récupérer les documents pertinents
# 3. Construire un prompt contextualisé avec les documents
# 4. Envoyer au LLM pour générer une réponse précise

Stable Diffusion — Génération d'Images

from diffusers import StableDiffusionPipeline
import torch

# ── Charger le modèle ──
pipe = StableDiffusionPipeline.from_pretrained(
    "runwayml/stable-diffusion-v1-5",
    torch_dtype=torch.float16
).to("cuda")  # GPU requis

# ── Générer une image ──
prompt = "A beautiful Moroccan riad courtyard with blue tiles, sunset lighting, photorealistic"
negative_prompt = "blurry, low quality, distorted, ugly"

image = pipe(
    prompt=prompt,
    negative_prompt=negative_prompt,
    num_inference_steps=50,    # Qualité vs vitesse
    guidance_scale=7.5,        # Adhérence au prompt
    width=512, height=512
).images[0]

image.save("riad.png")
print("Image générée !")

Ingénierie de Prompts (Prompt Engineering)

TechniqueDescriptionExemple
Zero-shotInstruction directe sans exemple"Traduis en français : Hello"
Few-shotDonner quelques exemples avant la tâche"Positif:✓ Négatif:✗ Neutre:? → 'Super !':"
Chain of ThoughtDemander de raisonner étape par étape"Réfléchis étape par étape..."
Role PromptingAssigner un rôle à l'IA"Tu es un expert en Python. Explique..."
Structured OutputDemander un format précis"Réponds en JSON : {clé: valeur}"

Question : Dans un GAN, quel composant génère de fausses données ?

Le Discriminateur
Le Générateur ✓
Le Classificateur
L'Encodeur
Section 9

Déploiement de Modèles ML — APIs, Cloud et Edge

Du Notebook à la Production

Un modèle de machine learning n'a de valeur que s'il est accessible aux utilisateurs. Le déploiement consiste à exposer le modèle via une API, une application web ou mobile.

Créer une API ML avec FastAPI

from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
import joblib
import numpy as np

# ── Charger le modèle sauvegardé ──
model = joblib.load('model_formations.pkl')
scaler = joblib.load('scaler.pkl')

app = FastAPI(title="NB3BN IA API", version="1.0")

# ── Schéma de données ──
class EtudiantInput(BaseModel):
    heures_travail: float
    note_prec:      float
    age:            int
    niveau:         int   # 1=débutant, 2=intermédiaire, 3=avancé

class Prediction(BaseModel):
    admis:        bool
    probabilite:  float
    conseil:      str

# ── Endpoint de prédiction ──
@app.post("/predict", response_model=Prediction)
async def predire(etudiant: EtudiantInput):
    try:
        X = np.array([[
            etudiant.heures_travail,
            etudiant.note_prec,
            etudiant.age,
            etudiant.niveau
        ]])
        X_scaled = scaler.transform(X)
        proba    = model.predict_proba(X_scaled)[0][1]
        admis    = proba >= 0.5

        conseil = (
            "Continuez ainsi, vous êtes sur la bonne voie !" if admis
            else "Augmentez vos heures de travail et revoyez les bases."
        )
        return Prediction(admis=admis, probabilite=round(proba, 3), conseil=conseil)

    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

@app.get("/health")
async def health():
    return {"status": "ok", "model_loaded": model is not None}

# Lancer : uvicorn api:app --reload --port 8000

MLflow — Suivi des Expériences

import mlflow
import mlflow.sklearn
from sklearn.ensemble import RandomForestClassifier

mlflow.set_experiment("NB3BN-Formation-Admis")

with mlflow.start_run(run_name="RF-100-trees"):
    # ── Paramètres ──
    n_estimators = 100
    max_depth    = 5
    mlflow.log_param("n_estimators", n_estimators)
    mlflow.log_param("max_depth", max_depth)

    # ── Entraînement ──
    model = RandomForestClassifier(n_estimators=n_estimators, max_depth=max_depth)
    model.fit(X_train, y_train)

    # ── Métriques ──
    accuracy = model.score(X_test, y_test)
    mlflow.log_metric("accuracy", accuracy)
    mlflow.log_metric("f1_score", f1)

    # ── Sauvegarder le modèle ──
    mlflow.sklearn.log_model(model, "model")
    print(f"Run terminé. Accuracy: {accuracy:.3f}")

Déploiement sur le Cloud

OptionPlateformeUsageCoût
ServerlessAWS Lambda, Cloud FunctionsInférence ponctuellePay-per-call
ContainerDocker + KubernetesProduction scalableVariable
Managed MLAWS SageMaker, Vertex AIMLOps completÉlevé
SimpleHeroku, Render, RailwayPrototypageFaible/gratuit
Hugging FaceHF SpacesDémos IAGratuit/Pro
# ── Dockerfile pour une API ML ──
# FROM python:3.11-slim
# WORKDIR /app
# COPY requirements.txt .
# RUN pip install -r requirements.txt
# COPY . .
# CMD ["uvicorn", "api:app", "--host", "0.0.0.0", "--port", "8000"]

# ── Construire et lancer ──
# docker build -t nb3bn-ml-api .
# docker run -p 8000:8000 nb3bn-ml-api

Question : Quelle bibliothèque Python facilite la création d'APIs REST pour servir des modèles ML ?

Django
Flask uniquement
FastAPI ✓
Tornado
Section 10

Éthique, Biais et Réglementation de l'IA

L'IA Éthique : Un Enjeu Mondial

L'IA prend des décisions qui impactent la vie des gens : attribution de crédits, recrutement, justice pénale, diagnostic médical. Il est crucial que ces systèmes soient justes, transparents et responsables.

Les Biais Algorithmiques

Un modèle IA reproduit, voire amplifie, les biais présents dans ses données d'entraînement :

BiaisExemple réelConséquence
Biais de sélectionDataset médical avec peu de femmesMauvais diagnostic chez les femmes
Biais de confirmationAlgorithme de recrutement formé sur CV historiquesDiscrimine les femmes dans la tech
Biais de mesureCapteurs de qualité de l'air dans quartiers richesSous-estime la pollution dans quartiers pauvres
Biais culturelTraducteur formé sur textes anglophonesMauvaise traduction pour langues minoritaires

Détecter et Corriger les Biais

from sklearn.metrics import classification_report
import pandas as pd

# ── Vérifier les métriques par groupe ──
y_test = pd.Series([0,1,1,0,1,0,1,1,0,1])
y_pred = pd.Series([0,1,0,0,1,0,1,0,0,1])
groupes = pd.Series(['H','F','F','H','F','H','H','F','H','F'])  # H=Homme, F=Femme

for groupe in ['H', 'F']:
    mask = groupes == groupe
    print(f"
=== Groupe {groupe} ===")
    print(classification_report(y_test[mask], y_pred[mask]))
    # Un bon modèle doit avoir des métriques similaires pour tous les groupes

# ── Fairness Indicators (Google) ──
# pip install fairness-indicators tensorflow-model-analysis

# ── IBM AI Fairness 360 ──
# from aif360.datasets import BinaryLabelDataset
# from aif360.metrics import BinaryLabelDatasetMetric

IA Explicable (XAI)

import shap

# ── SHAP : expliquer les prédictions individuelles ──
explainer = shap.TreeExplainer(model_rf)
shap_values = explainer.shap_values(X_test)

# ── Afficher l'importance des features pour UNE prédiction ──
shap.force_plot(
    explainer.expected_value[1],
    shap_values[1][0],
    X_test[0],
    feature_names=['heures', 'note', 'age', 'niveau']
)

# ── Importance globale des features ──
shap.summary_plot(shap_values[1], X_test, feature_names=['heures','note','age','niveau'])

# ── LIME : Local Interpretable Model-agnostic Explanations ──
from lime.lime_tabular import LimeTabularExplainer
explainer_lime = LimeTabularExplainer(X_train, feature_names=['h','n','a','nv'])
exp = explainer_lime.explain_instance(X_test[0], model.predict_proba, num_features=4)
exp.show_in_notebook()

Réglementations IA dans le Monde

RégionRéglementationPrincipales obligations
Union EuropéenneAI Act (2024)Classification par risque, interdiction IA à haut risque non expliquée
États-UnisExecutive Order on AI (2023)Standards de sécurité, déclaration des IA puissantes
ChineRéglementation IA générative (2023)Contenu conforme aux valeurs socialistes, traçabilité
MarocStratégie Maroc Digital 2030Développement IA responsable, formation aux métiers IA

Checklist Éthique IA

1
Données : Dataset représentatif de tous les groupes — vérifier les biais dès la collecte
2
Transparence : Documenter les choix algorithmiques, publier les limitations du modèle
3
Responsabilité : Identifier qui est responsable des décisions prises par l'IA
4
Vie privée : Minimiser les données collectées, respecter le RGPD/loi 09-08 au Maroc
5
Supervision humaine : Toujours prévoir un contrôle humain pour les décisions importantes

Question : Qu'est-ce que l'IA Explicable (XAI) ?

Une IA qui parle aux humains
Des méthodes pour comprendre et interpréter les décisions d'un modèle IA ✓
Un modèle IA codé en langage naturel
Une IA sans paramètres cachés
Section 11

Outils IA Populaires — AutoML, Langchain et Outils No-Code

AutoML — Machine Learning Automatisé

L'AutoML automatise les étapes fastidieuses du ML : sélection du modèle, réglage des hyperparamètres, ingénierie des features. Il permet à des non-experts de créer des modèles performants.

from autosklearn.classification import AutoSklearnClassifier
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split

# ── Auto-sklearn ──
X, y = load_breast_cancer(return_X_y=True)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)

automl = AutoSklearnClassifier(
    time_left_for_this_task=120,  # 2 minutes d'optimisation
    per_run_time_limit=30,
    n_jobs=-1
)
automl.fit(X_train, y_train)

print("Meilleur modèle :", automl.show_models())
print("Score :", automl.score(X_test, y_test))
from flaml import AutoML
import pandas as pd

# ── FLAML (Microsoft) — plus léger, plus rapide ──
automl = AutoML()
automl.fit(
    X_train, y_train,
    task="classification",       # ou "regression", "ts_forecast"
    time_budget=60,              # 60 secondes
    metric='accuracy',
    early_stop=True
)
print(f"Meilleur algorithme : {automl.best_estimator}")
print(f"Meilleurs params    : {automl.best_config}")

LangChain — Orchestrer des LLMs

from langchain_openai import ChatOpenAI
from langchain.prompts import ChatPromptTemplate
from langchain.schema.output_parser import StrOutputParser
from langchain.schema.runnable import RunnablePassthrough

# ── Chatbot avec mémoire ──
from langchain.memory import ConversationBufferMemory
from langchain.chains import ConversationChain

llm = ChatOpenAI(model="gpt-4o-mini", temperature=0.7)
memory = ConversationBufferMemory()
chatbot = ConversationChain(llm=llm, memory=memory, verbose=True)

print(chatbot.predict(input="Bonjour, je veux apprendre Python"))
print(chatbot.predict(input="Par où commencer ?"))
print(chatbot.predict(input="Quel livre recommandes-tu ?"))

# ── RAG : Chatbot sur vos documents ──
from langchain_community.vectorstores import Chroma
from langchain_openai import OpenAIEmbeddings
from langchain_community.document_loaders import PyPDFLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter

# 1. Charger et découper le document
loader = PyPDFLoader("manuel_nb3bn.pdf")
docs = loader.load()
splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=200)
chunks = splitter.split_documents(docs)

# 2. Créer la base vectorielle
embeddings = OpenAIEmbeddings()
vectordb = Chroma.from_documents(chunks, embeddings)
retriever = vectordb.as_retriever(search_kwargs={"k": 4})

# 3. Chaîne RAG
template = """Réponds à la question en te basant sur le contexte :
Contexte : {context}
Question : {question}
Réponse :"""
prompt = ChatPromptTemplate.from_template(template)

rag_chain = (
    {"context": retriever, "question": RunnablePassthrough()}
    | prompt | llm | StrOutputParser()
)

print(rag_chain.invoke("Qu'est-ce que Python ?"))

Outils IA No-Code et Low-Code

OutilSpécialitéLien
Google AutoMLVision, NLP, tabularcloud.google.com/automl
Azure ML StudioML visuel drag-and-dropml.azure.com
Teachable MachineClassif. images/sonsteachablemachine.withgoogle.com
RoboflowDétection d'objetsroboflow.com
Obviously.aiPrédictions businessobviously.ai
StreamlitDémo rapide MLstreamlit.io

Créer une Démo Streamlit

import streamlit as st
import joblib
import numpy as np

# ── Interface utilisateur en quelques lignes ──
st.title("🎓 Prédiction d'Admission NB3BN Info")
st.subheader("Entrez les informations de l'étudiant")

heures = st.slider("Heures de travail/semaine", 0, 40, 10)
note   = st.number_input("Note précédente /20", 0.0, 20.0, 10.0)
age    = st.selectbox("Âge", range(16, 60))
niveau = st.radio("Niveau actuel", ["Débutant", "Intermédiaire", "Avancé"])

niveau_num = ["Débutant","Intermédiaire","Avancé"].index(niveau) + 1

if st.button("🔮 Prédire"):
    model = joblib.load('model.pkl')
    X = np.array([[heures, note, age, niveau_num]])
    proba = model.predict_proba(X)[0][1]
    admis = proba >= 0.5

    if admis:
        st.success(f"✅ Admis — Probabilité : {proba:.1%}")
        st.balloons()
    else:
        st.error(f"❌ Non admis — Probabilité : {proba:.1%}")
        st.info("Conseil : Augmentez vos heures de travail !")

# Lancer : streamlit run app.py

Question : Que signifie RAG dans le contexte des LLMs ?

Recurrent AI Generation
Retrieval-Augmented Generation ✓
Random Attention Grouping
Rapid API Gateway
Section 12

Projet Final IA — Système de Recommandation de Formations

Projet : Moteur de Recommandation NB3BN Info

Nous allons construire un système de recommandation qui suggère des formations personnalisées à chaque étudiant en fonction de son profil, ses notes et ses préférences. Ce projet combine ML supervisé, clustering et NLP.

Architecture du Système


Étudiant ──► Profil + historique ──► Moteur de Recommandation ──► Top 5 Formations

Moteur de Recommandation :
  1. Filtrage collaboratif    : "Les étudiants similaires ont aimé..."
  2. Filtrage basé contenu    : "Basé sur vos notes, vous aimeriez..."
  3. Modèle hybride           : Combinaison des deux approches
  4. Score de confiance       : Probabilité d'appréciation

Étape 1 : Données et Feature Engineering

import pandas as pd
import numpy as np
from sklearn.preprocessing import LabelEncoder, StandardScaler

# ── Données simulées ──
np.random.seed(42)
n = 500

data = pd.DataFrame({
    'etudiant_id':   range(n),
    'age':           np.random.randint(18, 45, n),
    'niveau':        np.random.choice(['débutant','inter','avancé'], n),
    'note_maths':    np.random.uniform(5, 20, n),
    'note_info':     np.random.uniform(5, 20, n),
    'heures_semaine':np.random.randint(2, 30, n),
    'formation_id':  np.random.randint(0, 10, n),
    'rating':        np.random.randint(1, 6, n),  # Note 1-5
})

# ── Encoder les variables catégorielles ──
le = LabelEncoder()
data['niveau_enc'] = le.fit_transform(data['niveau'])

# ── Features pour le modèle ──
features = ['age', 'niveau_enc', 'note_maths', 'note_info', 'heures_semaine']
X = data[features].values
y = data['rating'].values

print(f"Dataset : {data.shape[0]} interactions")

Étape 2 : Filtrage Collaboratif (SVD)

from sklearn.decomposition import TruncatedSVD
from sklearn.metrics.pairwise import cosine_similarity
import numpy as np

# ── Matrice utilisateur-formation ──
n_etudiants  = 100
n_formations = 10
matrice = np.random.randint(0, 6, (n_etudiants, n_formations)).astype(float)
matrice[matrice == 0] = np.nan  # 0 = pas encore noté

# Remplir les NaN par la moyenne de la formation
col_means = np.nanmean(matrice, axis=0)
matrice_remplie = np.where(np.isnan(matrice), col_means, matrice)

# ── Décomposition SVD ──
svd = TruncatedSVD(n_components=5)
svd.fit(matrice_remplie)
matrice_svd = svd.inverse_transform(svd.transform(matrice_remplie))

# ── Recommander pour un étudiant ──
def recommander_pour_etudiant(etudiant_id, n_reco=5):
    scores = matrice_svd[etudiant_id]
    deja_vu = ~np.isnan(matrice[etudiant_id])
    scores[deja_vu] = -1  # Exclure déjà notés
    top = np.argsort(scores)[::-1][:n_reco]
    return [(f"Formation {i}", round(scores[i], 2)) for i in top]

reco = recommander_pour_etudiant(42)
print(f"Recommandations pour l'étudiant 42 :")
for f, score in reco:
    print(f"  {f} — Score prédit : {score}")

Étape 3 : Filtrage par Contenu (Similarité NLP)

from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.metrics.pairwise import cosine_similarity

# ── Descriptions des formations ──
formations = {
    'Python':        "Programmation Python, data science, automatisation, scripts",
    'JavaScript':    "Développement web frontend, React, DOM, APIs REST",
    'Machine Learning': "Scikit-learn, TensorFlow, modèles prédictifs, données",
    'Excel':         "Bureautique, tableur, formules, tableaux croisés dynamiques",
    'SQL':           "Bases de données, MySQL, requêtes, jointures, administration",
    'Marketing':     "SEO, réseaux sociaux, Google Ads, email marketing, analytics",
    'Design':        "Photoshop, Illustrator, UI/UX, maquettes, typographie",
    'Réseau':        "TCP/IP, routeurs, sécurité, pare-feu, administration Linux",
    'Comptabilité':  "Sage, TVA, bilan, CPC, fiscalité marocaine, plan comptable",
    'Vidéo':         "Premiere Pro, montage, colorimétrie, YouTube, diffusion",
}

# ── Vecteuriser les descriptions ──
noms = list(formations.keys())
desc = list(formations.values())
tfidf = TfidfVectorizer()
X_tfidf = tfidf.fit_transform(desc)

# ── Trouver les formations similaires ──
sim = cosine_similarity(X_tfidf)

def formations_similaires(formation, n=3):
    idx = noms.index(formation)
    scores = list(enumerate(sim[idx]))
    scores.sort(key=lambda x: x[1], reverse=True)
    return [(noms[i], round(s, 3)) for i, s in scores[1:n+1]]

print("Similaires à Python :", formations_similaires('Python'))

Étape 4 : Modèle Hybride Final

def systeme_recommandation(etudiant_id, profil, n_reco=5):
    """
    Système hybride : combine filtrage collaboratif + contenu + ML
    
    profil = {'niveau': 'inter', 'note_info': 16, 'formations_vues': ['Python', 'SQL']}
    """
    scores = {}

    # ── Score 1 : Filtrage collaboratif ──
    collab_reco = recommander_pour_etudiant(etudiant_id, n_reco=10)
    for nom, score in collab_reco:
        scores[nom] = scores.get(nom, 0) + score * 0.4  # Poids 40%

    # ── Score 2 : Contenu (based on formations vues) ──
    for formation_vue in profil.get('formations_vues', []):
        similaires = formations_similaires(formation_vue, n=5)
        for sim_nom, sim_score in similaires:
            scores[sim_nom] = scores.get(sim_nom, 0) + sim_score * 0.4  # Poids 40%

    # ── Score 3 : Bonus selon niveau ──
    bonus_niveau = {
        'débutant':  ['Excel', 'Bureautique', 'HTML'],
        'inter':     ['Python', 'JavaScript', 'SQL'],
        'avancé':    ['Machine Learning', 'Réseau', 'Design'],
    }
    for f in bonus_niveau.get(profil.get('niveau', 'inter'), []):
        scores[f] = scores.get(f, 0) + 0.2  # Poids 20%

    # ── Retourner le top N ──
    top = sorted(scores.items(), key=lambda x: x[1], reverse=True)
    return top[:n_reco]

# ── Test ──
profil_etudiant = {'niveau': 'inter', 'note_info': 15, 'formations_vues': ['Python']}
reco = systeme_recommandation(42, profil_etudiant)
print("
🎯 Formations recommandées :")
for nom, score in reco:
    print(f"  ⭐ {nom:20} — Score : {score:.3f}")

Récapitulatif des Compétences IA Acquises

DomaineCompétences
MathématiquesAlgèbre linéaire, probabilités, gradient
ML SuperviséRégression, classification, évaluation
ML Non superviséClustering, PCA, anomalie
Deep LearningKeras/TensorFlow, CNN, Transfer Learning
NLPPrétraitement, TF-IDF, Transformers, Chatbot
IA GénérativeGANs, LLMs, Diffusion, Prompt Engineering
DéploiementFastAPI, MLflow, Docker, Cloud
ÉthiqueBiais, XAI, RGPD, AI Act
Prochaines étapes : Participez à des compétitions Kaggle pour pratiquer, suivez les papers ArXiv en IA, et construisez des projets concrets pour votre portfolio.

Question finale : Un système de recommandation hybride combine quelles deux approches ?

Supervisé et non supervisé
Filtrage collaboratif et filtrage basé sur le contenu ✓
Deep Learning et statistiques classiques
NLP et Computer Vision

Félicitations !

Vous avez terminé ce manuel de formation. Passez maintenant votre test de niveau sur NB3BN Info.

Passer le Test de Niveau