# Jupyter ML 训练

使用 GPU 支持设置 JupyterLab 以进行机器学习实验和模型训练。

{% hint style="success" %}
所有示例都可以在通过以下方式租用的 GPU 服务器上运行： [CLORE.AI 市场](https://clore.ai/marketplace).
{% endhint %}

## 服务器要求

| 参数   | 最低      | 推荐       |
| ---- | ------- | -------- |
| 内存   | 16GB    | 32GB 以上  |
| 显存   | 8GB     | 16GB+    |
| 网络   | 200Mbps | 500Mbps+ |
| 启动时间 | 2-3 分钟  | -        |

{% hint style="info" %}
JupyterLab 本身很轻量。根据您的训练工作负载需求选择 GPU 和内存。
{% endhint %}

## 快速部署

**Docker 镜像：**

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

**端口：**

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

**环境：**

```
JUPYTER_TOKEN=your_secure_token_here
```

**命令：**

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

## 访问您的服务

部署后，在以下位置查找您的 `http_pub` URL： **我的订单**:

1. 前往 **我的订单** 页面
2. 单击您的订单
3. 查找 `http_pub` URL（例如， `abc123.clorecloud.net`)

使用 `https://YOUR_HTTP_PUB_URL` 而不是 `localhost` 在下面的示例中。

### 验证是否正常运行

```bash
# 检查 JupyterLab 是否可访问
curl https://your-http-pub.clorecloud.net/

# 使用 token 访问
# https://your-http-pub.clorecloud.net/?token=your_secure_token_here
```

{% hint style="warning" %}
如果收到 HTTP 502，请等待 2-3 分钟 —— 服务正在安装依赖项。
{% endhint %}

## 在 CLORE.AI 上租用

1. 访问 [CLORE.AI 市场](https://clore.ai/marketplace)
2. 按 GPU 类型、显存和价格筛选
3. 选择 **按需** （固定费率）或 **竞价** （出价价格）
4. 配置您的订单：
   * 选择 Docker 镜像
   * 设置端口（用于 SSH 的 TCP，Web 界面的 HTTP）
   * 如有需要，添加环境变量
   * 输入启动命令
5. 选择支付方式： **CLORE**, **BTC**，或 **USDT/USDC**
6. 创建订单并等待部署

### 访问您的服务器

* 在以下位置查找连接详情： **我的订单**
* Web 界面：使用 HTTP 端口的 URL
* SSH： `ssh -p <port> root@<proxy-address>`

## 访问 Jupyter

1. 等待部署完成
2. 找到端口 8888 的映射
3. 打开： `http://<proxy>:<port>?token=your_secure_token_here`

## 预配置的 ML 镜像

用于完整的 ML 环境：

**镜像：**

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

或构建自定义镜像：

```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"]
```

## 常用库

### 在 Jupyter 中安装

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

### 创建 requirements.txt

```

# ML 框架
torch>=2.1.0
torchvision
torchaudio

# 自然语言处理 (NLP)
transformers>=4.36.0
datasets
tokenizers
sentencepiece

# 训练
accelerate
bitsandbytes
peft
trl

# 监控
wandb
tensorboard

# 数据
numpy
pandas
matplotlib
seaborn
scikit-learn

# 计算机视觉
opencv-python
pillow
albumentations
```

## 训练示例

### PyTorch 图像分类

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

# 检查 GPU
print(f"GPU: {torch.cuda.get_device_name(0)}")
print(f"Memory: {torch.cuda.get_device_properties(0).total_memory / 1e9:.1f} GB")

# 加载数据
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)

# 模型
model = torchvision.models.resnet18(pretrained=True)
model.fc = nn.Linear(512, 10)
model = model.cuda()

# 训练
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"Epoch {epoch+1}, Loss: {loss.item():.4f}")

# 保存模型
torch.save(model.state_dict(), 'model.pth')
```

### HuggingFace 文本分类

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

# 加载数据集
dataset = load_dataset("imdb")

# 加载模型
model_name = "distilbert-base-uncased"
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModelForSequenceClassification.from_pretrained(model_name, num_labels=2)

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

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

# 训练
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")
```

### 使用 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

# 使用 4 位量化加载模型
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

# 配置 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)

# 加载数据集
dataset = load_dataset("timdettmers/openassistant-guanaco")

# 训练
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")
```

## TensorBoard 集成

### 启动 TensorBoard

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

或通过终端：

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

### 记录训练指标

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

writer = SummaryWriter('./logs')

for epoch in range(epochs):
    # ... 训练循环 ...
    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()
```

## Weights & Biases 集成

```python
import wandb

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

# 记录指标
wandb.log({"loss": loss, "accuracy": acc})

# 记录模型
wandb.save("model.pth")

# 完成
wandb.finish()
```

## 数据管理

### 下载数据集

```python

# HuggingFace 数据集
from datasets import load_dataset
dataset = load_dataset("squad")

# Kaggle 数据集
!pip install kaggle
!kaggle datasets download -d username/dataset-name

# 直接下载
!wget https://example.com/data.zip
!unzip data.zip
```

### 挂载云存储

```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')
```

## 保存工作进度

### 保存到外部存储

```python

# 将模型保存到 S3
import boto3
s3 = boto3.client('s3',
    aws_access_key_id='YOUR_KEY',
    aws_secret_access_key='YOUR_SECRET'
)
s3.upload_file('model.pth', 'my-bucket', 'models/model.pth')
```

### 在结束会话之前

```bash

# 下载重要文件
scp -P <port> root@<host>:/workspace/model.pth ./
scp -P <port> -r root@<host>:/workspace/results/ ./results/
```

## 多 GPU 训练

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

# 检查 GPU
print(f"Available GPUs: {torch.cuda.device_count()}")

# DataParallel（简单）
model = nn.DataParallel(model)

# DistributedDataParallel（更好）

# 使用以下命令启动： torchrun --nproc_per_node=4 train.py
dist.init_process_group("nccl")
model = DistributedDataParallel(model)
```

## 性能优化建议

### 内存优化

```python

# 梯度检查点
model.gradient_checkpointing_enable()

# 混合精度
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()
```

### 数据加载

```python

# 更快的数据加载
loader = DataLoader(
    dataset,
    batch_size=64,
    num_workers=8,      # 使用多个工作进程
    pin_memory=True,    # 更快的 GPU 传输
    prefetch_factor=2   # 预取批次
)
```

## # 使用固定种子以获得一致结果

## 下载所有所需的检查点

检查文件完整性

| GPU     | 验证 CUDA 兼容性 | 费用估算    | CLORE.AI 市场的典型费率（截至 2024 年）： |
| ------- | ----------- | ------- | ---------------------------- |
| 按小时费率   | \~$0.03     | \~$0.70 | \~$0.12                      |
| 速度      | \~$0.06     | \~$1.50 | \~$0.25                      |
| 512x512 | \~$0.10     | \~$2.30 | \~$0.40                      |
| 按日费率    | \~$0.17     | \~$4.00 | \~$0.70                      |
| 4 小时会话  | \~$0.25     | \~$6.00 | \~$1.00                      |

*RTX 3060* [*CLORE.AI 市场*](https://clore.ai/marketplace) *A100 40GB*

**A100 80GB**

* 使用 **竞价** 价格随提供商和需求而异。请查看
* 以获取当前费率。 **CLORE** 节省费用：
* 市场用于灵活工作负载（通常便宜 30-50%）
