Alaya NeW Cloud

Run a PyTorch binary classifier on CCI

Train a binary classifier on CCI with Jupyter + PyTorch — from environment setup to result visualization

Prerequisites

  • You have an Alaya NeW enterprise account and password. If you need help or have not registered yet, follow Account setup to register.
  • Your enterprise account has sufficient balance for using the Cloud Container Instance (CCI) service. Refer to the console for the latest promotion details and pricing.

This document walks you through running a complete machine learning project in Alaya NeW's Cloud Container Instance (CCI) using Jupyter Notebook. Even with zero prior experience, you can follow the steps and succeed!

🎯 Project goal

Train an AI model to distinguish between two classes of data points (just like teaching a child to tell apples from bananas), aiming for an accuracy above 90%.

🔧 Part 1: Environment preparation

Step 1: Enter Cloud Container Instance

  1. Log in to the console: Use your registered enterprise account to log in to the Alaya NeW platform. Click "Products > Compute > Cloud Container Instance" to enter the CCI page.
  2. Create a new cloud container: Click "New cloud container" to enter the CCI provisioning page, where you configure parameters such as instance name, instance description, and data center. For this example, configure each parameter as follows:
    • Resource type: Select "Cloud Container Instance - GPU - H800A - 1 GPU".
    • For other parameters, refer to the table below.
ParameterDescriptionRequirementRequired
Instance nameIdentifier of the cloud container, used to uniquely identify it in the systemMust start with a letter; supports letters, digits, hyphens (-), and underscores (_); 4-20 charactersYes
Instance descriptionA short text description of the cloud container's purpose, function, or configurationNoneNo
Data centerThe data center providing CCI service resourcesChoose an available data center, e.g., Beijing Zone 3, Beijing Zone 5Yes
Billing modeBilling method for using data center resourcesChoose a supported billing mode (currently pay-as-you-go)Yes
Resource configurationDetailed resource specifications, including resource type, GPU model, compute spec, and disk configurationChoose resources that meet your needsYes
Storage configurationOptional NAS-type storage to mount into the CCIChoose the NAS storage to mountNo
ImagePublic images (base images and application images) and private images are supported. Choose the image type as neededYes
Other configurationConfigure environment-variable key-value pairs; optionally enable auto shutdown and auto release for the CCINo
  1. Confirm provisioning: Once parameters are set, click "Provision now". In the confirmation dialog, verify the parameters and click "OK" to complete CCI provisioning.

    You can check the created CCI on the Compute / Cloud Container Instance page. When the status shows "Running", the instance is ready to use.

  2. Open Jupyter: Click the access URL to enter the Jupyter UI.

Open Jupyter UI 1

  1. Jupyter home: You will see the screen below.

Open Jupyter UI 2

Step 2: Open a terminal

In the "Launcher" area on the right side of the Jupyter UI:

  1. Under "Other", click "Terminal".

Open terminal 1

  1. A command-line window opens.

Open terminal 2

Step 3: Install required packages

This document uses Ubuntu as the example OS.

# Install venv
apt update && apt install python3.12-venv -y

# Remove the old virtual environment (if any)
rm -rf ml_env

# Create a new virtual environment
python3 -m venv ml_env

# Activate the environment
source ml_env/bin/activate

# Install packages
pip install --upgrade pip
pip install numpy matplotlib torch torchvision jupyter ipykernel

# Register the Jupyter kernel
python -m ipykernel install --user --name=ml_env --display-name="Python (ml_env)"

# Verify
echo "Environment setup complete!"
python -c "import numpy; print('NumPy version:', numpy.__version__)"
python -c "import torch; print('PyTorch version:', torch.__version__)"

echo "Refresh the Jupyter page, then choose the 'Python (ml_env)' kernel when creating a Notebook"

Example 1

Installation in progress 👇

Example 2

Installation complete 👇

Example 3

Check the system version

If you are unsure about your OS version, run the following commands in the terminal to inspect system info:

# Method 1: View the OS release file
cat /etc/os-release

# Method 2: Print system info
uname -a

# Method 3: View Linux release info
cat /etc/*release*

You will see output similar to the following:

  • Ubuntu / Debian: shows ID=ubuntu or ID=debian
  • CentOS / RHEL: shows ID="centos" or ID="rhel"
  • Alpine: shows ID=alpine

Example 4

Install commands differ across operating systems.

Step 4: Verify the installation

Continue in the terminal:

# Check NumPy installation
python -c "import numpy; print('NumPy version:', numpy.__version__)"

# Check PyTorch installation
python -c "import torch; print('PyTorch version:', torch.__version__)"

Example 5

📝 Part 2: Create and run the machine learning code

Step 1: Refresh the Jupyter page

Refresh your browser so the newly installed environment takes effect.

Step 2: Create a new Notebook

  1. Close the Terminal window and return to the Launcher page. The UI looks like the screenshot below.

Part 2-1

  1. In the Notebook section, locate "Python (ml_env)" (the environment we just created) and click it.

Part 2-2 Part 2-3

Step 3: Paste in the code

Copy the code below into your Notebook in chunks. We recommend using 6 cells for easier reading and debugging.

Cell 1: Import the required libraries

Copy the code below into a cell and press Shift + Enter to run it.

import math
import time
import random
import numpy as np
import matplotlib.pyplot as plt
import torch
import torch.nn as nn
from torch.utils.data import TensorDataset, DataLoader
from pathlib import Path

# Set random seeds (for reproducible results across runs)
def set_seed(seed=42):
    random.seed(seed)
    np.random.seed(seed)
    torch.manual_seed(seed)
    if torch.cuda.is_available():
        torch.cuda.manual_seed_all(seed)
        torch.backends.cudnn.deterministic = True

set_seed(42)
print("✅ Imports successful!")

Part 2-4

Successful output 👇

Part 2-5

Cell 2: Build the dataset

Copy the code below into a cell and press Shift + Enter to run it.

def make_moons(n_samples=1000, noise=0.2):
    """Generate a two-moons dataset"""
    n_samples_out = n_samples // 2
    n_samples_in = n_samples - n_samples_out
    outer_circ_x = np.cos(np.linspace(0, math.pi, n_samples_out))
    outer_circ_y = np.sin(np.linspace(0, math.pi, n_samples_out))
    inner_circ_x = 1 - np.cos(np.linspace(0, math.pi, n_samples_in))
    inner_circ_y = 1 - np.sin(np.linspace(0, math.pi, n_samples_in)) - .5
    X = np.vstack([np.append(outer_circ_x, inner_circ_x),
                    np.append(outer_circ_y, inner_circ_y)]).T.astype(np.float32)
    y = np.hstack([np.zeros(n_samples_out, dtype=np.float32),
                    np.ones(n_samples_in,  dtype=np.float32)])
    if noise > 0:
        X += np.random.normal(0, noise, X.shape)
    return X, y

# Build a dataset of 1200 samples
X, y = make_moons(1200, noise=0.25)

# Split into training (80%) and validation (20%) sets
perm = np.random.permutation(len(X))
train_size = int(0.8 * len(X))
X_train, y_train = X[perm[:train_size]], y[perm[:train_size]]
X_val, y_val = X[perm[train_size:]], y[perm[train_size:]]

# Build the data loaders (for mini-batch training)
train_ds = TensorDataset(torch.from_numpy(X_train), torch.from_numpy(y_train))
val_ds = TensorDataset(torch.from_numpy(X_val), torch.from_numpy(y_val))
train_loader = DataLoader(train_ds, batch_size=64, shuffle=True)
val_loader = DataLoader(val_ds, batch_size=256, shuffle=False)

print(f"Training samples: {len(train_ds)}")
print(f"Validation samples: {len(val_ds)}")

Part 2-6

Cell 3: Define the neural network model

Copy the code below into a cell and press Shift + Enter to run it.

class MLP(nn.Module):
    """A simple neural network"""
    def __init__(self, in_dim=2, hidden=128, dropout_rate=0.2):
        super().__init__()
        self.net = nn.Sequential(
            nn.Linear(in_dim, hidden),      # Input layer → hidden layer 1
            nn.ReLU(),                       # Activation function
            nn.Dropout(dropout_rate),        # Prevent overfitting
            nn.Linear(hidden, hidden//2),    # Hidden layer 1 → hidden layer 2
            nn.ReLU(),
            nn.Dropout(dropout_rate),
            nn.Linear(hidden//2, 1)          # Hidden layer 2 → output layer
        )

    def forward(self, x):
        return self.net(x).squeeze(1)

# Check whether a GPU is available
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
print(f"Using device: {device}")

# Initialize the model
model = MLP(hidden=128, dropout_rate=0.2).to(device)
criterion = nn.BCEWithLogitsLoss()  # Loss function
optimizer = torch.optim.Adam(model.parameters(), lr=1e-2, weight_decay=1e-4)  # Optimizer

# Training hyperparameters
EPOCHS = 200        # Train for at most 200 epochs
patience = 20       # Early-stopping patience (stop if no improvement for 20 epochs)

# Create a folder to save model checkpoints
Path("checkpoints").mkdir(exist_ok=True)

print("✅ Model initialized")

Part 2-7 Part 2-8

Cell 4: Define helper functions

Copy the code below into a cell and press Shift + Enter to run it.

# Set up live plotting
plt.ion()
fig = plt.figure(figsize=(15, 6))
ax_loss = fig.add_subplot(1, 2, 1)      # Left: loss curves
ax_boundary = fig.add_subplot(1, 2, 2)  # Right: decision boundary

train_losses, val_losses = [], []  # Track losses
train_accs, val_accs = [], []      # Track accuracy

def calculate_accuracy(model, data_loader):
    """Compute the model's accuracy"""
    model.eval()
    correct = 0
    total = 0
    with torch.no_grad():
        for xb, yb in data_loader:
            xb, yb = xb.to(device), yb.to(device)
            outputs = torch.sigmoid(model(xb))
            predicted = (outputs > 0.5).float()
            total += yb.size(0)
            correct += (predicted == yb).sum().item()
    return correct / total

def plot_boundary(ax, epoch):
    """Plot the decision boundary"""
    ax.clear()
    h = 0.02
    x_min, x_max = X[:, 0].min() - .5, X[:, 0].max() + .5
    y_min, y_max = X[:, 1].min() - .5, X[:, 1].max() + .5
    xx, yy = np.meshgrid(np.arange(x_min, x_max, h),
                            np.arange(y_min, y_max, h))

    grid = torch.from_numpy(np.c_[xx.ravel(), yy.ravel()]).float().to(device)
    with torch.no_grad():
        Z = torch.sigmoid(model(grid)).cpu().numpy().reshape(xx.shape)

    ax.contourf(xx, yy, Z, levels=50, cmap='RdBu', alpha=0.7)

    ax.scatter(X_train[:, 0], X_train[:, 1], c=y_train, cmap='bwr',
                edgecolors='k', marker='o', label='Training set', alpha=0.7)
    ax.scatter(X_val[:, 0], X_val[:, 1], c=y_val, cmap='bwr',
                edgecolors='k', marker='x', label='Validation set', alpha=0.7)

    ax.set_xlim(xx.min(), xx.max())
    ax.set_ylim(yy.min(), yy.max())
    ax.set_title(f'Decision boundary (epoch {epoch})')
    ax.legend()

def plot_metrics(ax):
    """Plot loss and accuracy curves"""
    ax.clear()
    ax.plot(train_losses, label='Training loss', color='blue', linestyle='-')
    ax.plot(val_losses, label='Validation loss', color='red', linestyle='-')
    ax.set_xlabel('Epoch')
    ax.set_ylabel('Loss', color='black')
    ax.legend(loc='upper left')
    ax.grid(True)

    ax2 = ax.twinx()
    ax2.plot(train_accs, label='Training accuracy', color='blue', linestyle='--')
    ax2.plot(val_accs, label='Validation accuracy', color='red', linestyle='--')
    ax2.set_ylabel('Accuracy', color='black')
    ax2.legend(loc='upper right')

    ax.set_title('Training progress')

print("✅ Helper functions defined")

Part 2-9 Part 2-10

Cell 5: Run training (the core)

Copy the code below into a cell and press Shift + Enter to run it.

print("🚀 Starting training...")
start_time = time.time()
best_val_loss = float('inf')
patience_counter = 0

for epoch in range(1, EPOCHS + 1):
    # ----- Training phase -----
    model.train()
    epoch_loss = 0.
    for xb, yb in train_loader:
        xb, yb = xb.to(device), yb.to(device)
        optimizer.zero_grad()
        logits = model(xb)
        loss = criterion(logits, yb)
        loss.backward()
        optimizer.step()
        epoch_loss += loss.item() * xb.size(0)

    train_loss = epoch_loss / len(train_loader.dataset)
    train_losses.append(train_loss)

    # ----- Validation phase -----
    model.eval()
    epoch_loss = 0.
    with torch.no_grad():
        for xb, yb in val_loader:
            xb, yb = xb.to(device), yb.to(device)
            logits = model(xb)
            loss = criterion(logits, yb)
            epoch_loss += loss.item() * xb.size(0)

    val_loss = epoch_loss / len(val_loader.dataset)
    val_losses.append(val_loss)

    # Compute accuracy
    train_acc = calculate_accuracy(model, train_loader)
    val_acc = calculate_accuracy(model, val_loader)
    train_accs.append(train_acc)
    val_accs.append(val_acc)

    # Print progress every 10 epochs
    if epoch % 10 == 0 or epoch == 1:
        print(f'Epoch {epoch:03d}/200 | '
                f'Train loss: {train_loss:.4f} | Val loss: {val_loss:.4f} | '
                f'Train acc: {train_acc:.3f} | Val acc: {val_acc:.3f}')

    # Save the best model
    if val_loss < best_val_loss:
        best_val_loss = val_loss
        patience_counter = 0
        torch.save({
            'epoch': epoch,
            'model_state_dict': model.state_dict(),
            'loss': val_loss,
        }, 'checkpoints/best_model.pth')
    else:
        patience_counter += 1

    # Early stopping (stop if no improvement for 20 epochs)
    if patience_counter >= patience:
        print(f"⏹️ Early stopping triggered at epoch {epoch}")
        break

    # Refresh the plots every 5 epochs
    if epoch % 5 == 0 or epoch == 1:
        plot_metrics(ax_loss)
        plot_boundary(ax_boundary, epoch)
        fig.tight_layout()
        plt.pause(0.01)

end_time = time.time()
print(f"✅ Training complete! Elapsed: {end_time - start_time:.2f}s")

Part 2-11 Part 2-12 Part 2-13

Cell 6: Final evaluation and visualization

Copy the code below into a cell and press Shift + Enter to run it.

# Load the best model
checkpoint = torch.load('checkpoints/best_model.pth')
model.load_state_dict(checkpoint['model_state_dict'])
print(f"📥 Loaded best model (epoch {checkpoint['epoch']}, val loss: {checkpoint['loss']:.4f})")

# Final evaluation
model.eval()
with torch.no_grad():
    X_tensor = torch.from_numpy(X).to(device)
    y_pred_proba = torch.sigmoid(model(X_tensor)).cpu().numpy()
    y_pred = (y_pred_proba > 0.5).astype(int)
    accuracy = (y_pred == y).mean()
    print(f'🎯 Final accuracy: {accuracy:.3f} ({accuracy*100:.1f}%)')

# Render the final plots
plt.figure(figsize=(15, 6))

# Left: loss and accuracy curves
plt.subplot(1, 2, 1)
plt.plot(train_losses, label='Training loss', color='blue', linestyle='-')
plt.plot(val_losses, label='Validation loss', color='red', linestyle='-')
plt.xlabel('Epoch')
plt.ylabel('Loss')
plt.legend(loc='upper left')
plt.twinx()
plt.plot(train_accs, label='Training accuracy', color='blue', linestyle='--')
plt.plot(val_accs, label='Validation accuracy', color='red', linestyle='--')
plt.ylabel('Accuracy')
plt.legend(loc='upper right')
plt.title('Training progress')
plt.grid(True)

# Right: decision boundary
plt.subplot(1, 2, 2)
h = 0.02
x_min, x_max = X[:, 0].min() - .5, X[:, 0].max() + .5
y_min, y_max = X[:, 1].min() - .5, X[:, 1].max() + .5
xx, yy = np.meshgrid(np.arange(x_min, x_max, h),
                        np.arange(y_min, y_max, h))

grid = torch.from_numpy(np.c_[xx.ravel(), yy.ravel()]).float().to(device)
with torch.no_grad():
    Z = torch.sigmoid(model(grid)).cpu().numpy().reshape(xx.shape)

plt.contourf(xx, yy, Z, levels=50, cmap='RdBu', alpha=0.7)
plt.scatter(X_train[:, 0], X_train[:, 1], c=y_train, cmap='bwr',
            edgecolors='k', marker='o', label='Training set', alpha=0.7)
plt.scatter(X_val[:, 0], X_val[:, 1], c=y_val, cmap='bwr',
            edgecolors='k', marker='x', label='Validation set', alpha=0.7)
plt.colorbar()
plt.xlim(xx.min(), xx.max())
plt.ylim(yy.min(), yy.max())
plt.title('Final decision boundary')
plt.legend()

plt.tight_layout()
plt.show()

print("✨ Congratulations! The full machine learning workflow is complete!")

Part 2-14 Part 2-15

📊 Part 3: Interpreting the results

Reading the training output

Epoch 001/200 | Train loss: 0.3820 | Val loss: 0.3491 | Train acc: 0.899 | Val acc: 0.842
Epoch 010/200 | Train loss: 0.1523 | Val loss: 0.2195 | Train acc: 0.942 | Val acc: 0.942
  • Loss: lower is better; indicates fewer prediction errors.
  • Accuracy: higher is better; the fraction of correct predictions.
  • Final accuracy: e.g., 0.942 means 94.2% accuracy.

Reading the plots

  • Left plot: blue line = training set, red line = validation set
    • Solid lines are loss values (lower is better)
    • Dashed lines are accuracy values (higher is better)
  • Right plot:
    • Colored background: the model's predicted regions
    • Red/blue points: ground-truth data (circles = training set, crosses = validation set)

🎉 Summary

In this exercise you have:

  1. ✅ Configured a Python environment in a cloud container
  2. ✅ Built a neural network model
  3. ✅ Trained the model to distinguish two classes of data
  4. ✅ Reached over 90% accuracy
  5. ✅ Visualized the model's decision process

This is just like teaching an AI "kid" to recognize two kinds of objects — once trained, it can classify new ones. The core of machine learning is the loop: "feed data → let the model learn → use the model to predict".

Last updated on

Was this page helpful?

On this page