# Entraînement ML avec Jupyter

Configurer JupyterLab avec prise en charge GPU pour des expériences d'apprentissage automatique et l'entraînement de modèles.

{% hint style="success" %}
Tous les exemples peuvent être exécutés sur des serveurs GPU loués via [CLORE.AI Marketplace](https://clore.ai/marketplace).
{% endhint %}

## Exigences du serveur

| Paramètre          | Minimum     | Recommandé |
| ------------------ | ----------- | ---------- |
| RAM                | 16Go        | 32 Go+     |
| VRAM               | 8 Go        | 16 Go+     |
| Réseau             | 200 Mbps    | 500 Mbps+  |
| Temps de démarrage | 2-3 minutes | -          |

{% hint style="info" %}
JupyterLab lui-même est léger. Choisissez le GPU et la RAM en fonction des exigences de votre charge de travail d'entraînement.
{% endhint %}

## Déploiement rapide

**Image Docker :**

```
pytorch/pytorch:2.5.1-cuda12.4-cudnn9-runtime
```

**Ports :**

```
22/tcp
8888/http
6006/http
```

**Environnement :**

```
JUPYTER_TOKEN=votre_token_sécurisé_ici
```

**Commande :**

```bash
pip install jupyterlab tensorboard && \
jupyter lab --ip=0.0.0.0 --port=8888 --allow-root --NotebookApp.token='votre_token_sécurisé_ici'
```

## Accéder à votre service

Après le déploiement, trouvez votre `http_pub` URL dans **Mes commandes**:

1. Aller à la **Mes commandes** page
2. Cliquez sur votre commande
3. Trouvez l' `http_pub` URL (par ex., `abc123.clorecloud.net`)

Utilisez `https://VOTRE_HTTP_PUB_URL` au lieu de `localhost` dans les exemples ci-dessous.

### Vérifiez que cela fonctionne

```bash
# Vérifier si JupyterLab est accessible
curl https://your-http-pub.clorecloud.net/

# Accéder avec le token
# https://your-http-pub.clorecloud.net/?token=votre_token_sécurisé_ici
```

{% hint style="warning" %}
Si vous obtenez HTTP 502, attendez 2-3 minutes - le service installe les dépendances.
{% endhint %}

## Location sur CLORE.AI

1. Visitez [CLORE.AI Marketplace](https://clore.ai/marketplace)
2. Filtrer par type de GPU, VRAM et prix
3. Choisir **À la demande** (tarif fixe) ou **Spot** (prix d'enchère)
4. Configurez votre commande :
   * Sélectionnez l'image Docker
   * Définissez les ports (TCP pour SSH, HTTP pour les interfaces web)
   * Ajoutez des variables d'environnement si nécessaire
   * Entrez la commande de démarrage
5. Sélectionnez le paiement : **CLORE**, **BTC**, ou **USDT/USDC**
6. Créez la commande et attendez le déploiement

### Accédez à votre serveur

* Trouvez les détails de connexion dans **Mes commandes**
* Interfaces Web : utilisez l'URL du port HTTP
* SSH : `ssh -p <port> root@<adresse-proxy>`

## Accéder à Jupyter

1. Attendre le déploiement
2. Trouver le mappage du port 8888
3. Ouvrir : `http://<proxy>:<port>?token=votre_token_sécurisé_ici`

## Image ML préconfigurée

Pour un environnement ML complet :

**Image :**

```
jupyter/pytorch-notebook:cuda12-pytorch-2.1.0
```

Ou construire personnalisé :

```dockerfile
FROM pytorch/pytorch:2.5.1-cuda12.4-cudnn9-runtime

RUN pip install --no-cache-dir \
    jupyterlab \
    numpy pandas matplotlib seaborn \
    scikit-learn \
    transformers datasets accelerate \
    tensorboard wandb \
    opencv-python pillow \
    tqdm rich

EXPOSE 8888 6006

CMD ["jupyter", "lab", "--ip=0.0.0.0", "--allow-root"]
```

## Bibliothèques essentielles

### Installer dans Jupyter

```python
!pip install transformers datasets accelerate bitsandbytes
!pip install wandb tensorboard
!pip install scikit-learn xgboost lightgbm
!pip install opencv-python albumentations
```

### Créer requirements.txt

```

# Frameworks ML
torch>=2.1.0
torchvision
torchaudio

# NLP
transformers>=4.36.0
datasets
tokenizers
sentencepiece

# Entraînement
accelerate
bitsandbytes
peft
trl

# Monitoring
wandb
tensorboard

# Données
numpy
pandas
matplotlib
seaborn
scikit-learn

# Vision par ordinateur
opencv-python
pillow
albumentations
```

## Exemples d'entraînement

### Classification d'images avec PyTorch

```python
import torch
import torch.nn as nn
import torchvision
from torchvision import transforms
from torch.utils.data import DataLoader

# Vérifier le GPU
print(f"GPU: {torch.cuda.get_device_name(0)}")
print(f"Mémoire: {torch.cuda.get_device_properties(0).total_memory / 1e9:.1f} GB")

# Charger les données
transform = transforms.Compose([
    transforms.Resize(224),
    transforms.ToTensor(),
    transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
])

train_data = torchvision.datasets.CIFAR10(
    root='./data', train=True, download=True, transform=transform
)
train_loader = DataLoader(train_data, batch_size=64, shuffle=True, num_workers=4)

# Modèle
model = torchvision.models.resnet18(pretrained=True)
model.fc = nn.Linear(512, 10)
model = model.cuda()

# Entraînement
optimizer = torch.optim.Adam(model.parameters(), lr=1e-4)
criterion = nn.CrossEntropyLoss()

for epoch in range(10):
    model.train()
    for images, labels in train_loader:
        images, labels = images.cuda(), labels.cuda()

        optimizer.zero_grad()
        outputs = model(images)
        loss = criterion(outputs, labels)
        loss.backward()
        optimizer.step()

    print(f"Époque {epoch+1}, Perte : {loss.item():.4f}")

# Sauvegarder le modèle
torch.save(model.state_dict(), 'model.pth')
```

### Classification de texte HuggingFace

```python
from transformers import AutoTokenizer, AutoModelForSequenceClassification
from transformers import TrainingArguments, Trainer
from datasets import load_dataset
import numpy as np

# Charger le jeu de données
dataset = load_dataset("imdb")

# Charger le modèle
model_name = "distilbert-base-uncased"
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModelForSequenceClassification.from_pretrained(model_name, num_labels=2)

# Tokeniser
def tokenize(examples):
    return tokenizer(examples["text"], padding="max_length", truncation=True)

tokenized = dataset.map(tokenize, batched=True)

# Entraînement
training_args = TrainingArguments(
    output_dir="./results",
    num_train_epochs=3,
    per_device_train_batch_size=16,
    per_device_eval_batch_size=64,
    warmup_steps=500,
    weight_decay=0.01,
    logging_dir="./logs",
    logging_steps=100,
    evaluation_strategy="epoch",
    save_strategy="epoch",
    load_best_model_at_end=True,
)

trainer = Trainer(
    model=model,
    args=training_args,
    train_dataset=tokenized["train"],
    eval_dataset=tokenized["test"],
)

trainer.train()
trainer.save_model("./best_model")
```

### Ajustement fin de LLM avec LoRA

```python
from transformers import AutoModelForCausalLM, AutoTokenizer, BitsAndBytesConfig
from peft import LoraConfig, get_peft_model, prepare_model_for_kbit_training
from datasets import load_dataset
from trl import SFTTrainer
import torch

# Charger le modèle avec quantification 4 bits
bnb_config = BitsAndBytesConfig(
    load_in_4bit=True,
    bnb_4bit_quant_type="nf4",
    bnb_4bit_compute_dtype=torch.float16,
)

model = AutoModelForCausalLM.from_pretrained(
    "mistralai/Mistral-7B-v0.1",
    quantization_config=bnb_config,
    device_map="auto",
)
tokenizer = AutoTokenizer.from_pretrained("mistralai/Mistral-7B-v0.1")
tokenizer.pad_token = tokenizer.eos_token

# Configurer LoRA
lora_config = LoraConfig(
    r=16,
    lora_alpha=32,
    target_modules=["q_proj", "v_proj"],
    lora_dropout=0.05,
    bias="none",
    task_type="CAUSAL_LM"
)

model = prepare_model_for_kbit_training(model)
model = get_peft_model(model, lora_config)

# Charger le jeu de données
dataset = load_dataset("timdettmers/openassistant-guanaco")

# Entraîner
trainer = SFTTrainer(
    model=model,
    train_dataset=dataset["train"],
    dataset_text_field="text",
    max_seq_length=512,
    tokenizer=tokenizer,
    args=TrainingArguments(
        output_dir="./lora_output",
        num_train_epochs=1,
        per_device_train_batch_size=4,
        gradient_accumulation_steps=4,
        learning_rate=2e-4,
        fp16=True,
        logging_steps=10,
        save_steps=100,
    ),
)

trainer.train()
trainer.save_model("./final_lora")
```

## Intégration TensorBoard

### Démarrer TensorBoard

```python
%load_ext tensorboard
%tensorboard --logdir ./logs --port 6006 --bind_all
```

Ou via le terminal :

```bash
tensorboard --logdir ./logs --port 6006 --bind_all &
```

### Enregistrer les métriques d'entraînement

```python
from torch.utils.tensorboard import SummaryWriter

writer = SummaryWriter('./logs')

for epoch in range(epochs):
    # ... boucle d'entraînement ...
    writer.add_scalar('Loss/train', train_loss, epoch)
    writer.add_scalar('Loss/val', val_loss, epoch)
    writer.add_scalar('Accuracy/val', accuracy, epoch)

writer.close()
```

## Intégration Weights & Biases

```python
import wandb

wandb.init(project="my-project", name="experiment-1")

# Enregistrer les métriques
wandb.log({"loss": loss, "accuracy": acc})

# Enregistrer le modèle
wandb.save("model.pth")

# Terminer
wandb.finish()
```

## Gestion des données

### Télécharger des jeux de données

```python

# jeux de données HuggingFace
from datasets import load_dataset
dataset = load_dataset("squad")

# jeux de données Kaggle
!pip install kaggle
!kaggle datasets download -d username/dataset-name

# Téléchargement direct
!wget https://example.com/data.zip
!unzip data.zip
```

### Monter le stockage cloud

```python

# S3
!pip install boto3
import boto3
s3 = boto3.client('s3')
s3.download_file('bucket', 'key', 'local_path')

# Google Cloud
!pip install google-cloud-storage
from google.cloud import storage
client = storage.Client()
bucket = client.bucket('my-bucket')
blob = bucket.blob('data.zip')
blob.download_to_filename('data.zip')
```

## Sauvegarder le travail

### Enregistrer sur un stockage externe

```python

# Sauvegarder le modèle sur S3
import boto3
s3 = boto3.client('s3',
    aws_access_key_id='VOTRE_CLE',
    aws_secret_access_key='VOTRE_SECRET'
)
s3.upload_file('model.pth', 'my-bucket', 'models/model.pth')
```

### Avant de terminer la session

```bash

# Télécharger les fichiers importants
scp -P <port> root@<host>:/workspace/model.pth ./
scp -P <port> -r root@<host>:/workspace/results/ ./results/
```

## Entraînement multi-GPU

```python
import torch.distributed as dist
from torch.nn.parallel import DistributedDataParallel

# Vérifier les GPUs
print(f"GPUs disponibles : {torch.cuda.device_count()}")

# DataParallel (simple)
model = nn.DataParallel(model)

# DistributedDataParallel (meilleur)

# Lancer avec : torchrun --nproc_per_node=4 train.py
dist.init_process_group("nccl")
model = DistributedDataParallel(model)
```

## Conseils de performance

### Optimisation de la mémoire

```python

# Checkpointing de gradient
model.gradient_checkpointing_enable()

# Précision mixte
from torch.cuda.amp import autocast, GradScaler
scaler = GradScaler()

with autocast():
    output = model(input)
    loss = criterion(output, target)

scaler.scale(loss).backward()
scaler.step(optimizer)
scaler.update()
```

### Chargement des données

```python

# Chargement plus rapide des données
loader = DataLoader(
    dataset,
    batch_size=64,
    num_workers=8,      # Utiliser plusieurs workers
    pin_memory=True,    # Transfert GPU plus rapide
    prefetch_factor=2   # Précharger les lots
)
```

## Dépannage

## Estimation des coûts

Tarifs typiques du marché CLORE.AI (à partir de 2024) :

| GPU       | Tarif horaire | Tarif journalier | Session de 4 heures |
| --------- | ------------- | ---------------- | ------------------- |
| RTX 3060  | \~$0.03       | \~$0.70          | \~$0.12             |
| RTX 3090  | \~$0.06       | \~$1.50          | \~$0.25             |
| RTX 4090  | \~$0.10       | \~$2.30          | \~$0.40             |
| A100 40GB | \~$0.17       | \~$4.00          | \~$0.70             |
| A100 80GB | \~$0.25       | \~$6.00          | \~$1.00             |

*Les prix varient selon le fournisseur et la demande. Vérifiez* [*CLORE.AI Marketplace*](https://clore.ai/marketplace) *pour les tarifs actuels.*

**Économisez de l'argent :**

* Utilisez **Spot** market pour les charges de travail flexibles (souvent 30-50 % moins cher)
* Payer avec **CLORE** jetons
* Comparer les prix entre différents fournisseurs


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.clore.ai/guides/guides_v2-fr/entrainement/jupyter-ml-training.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
