ClearML

Introduction

The integration of an AI/ML Framework within an O-RAN (Open Radio Access Network) setup serves as a pivotal enabler for realizing intelligent, adaptive, and efficient next-generation RAN operations. The primary objective is to harness data-driven learning to optimize network performance in real-time while ensuring openness and interoperability across RAN components.

Architecture

AI-ML Architecture

Figure: Integrated AI/ML (ClearML platform) with CCI-xG O-RAN Architecture.

This figure illustrates a ClearML-based AI/ML pipeline integrated with the CCI-xG Testbed O-RAN (Open Radio Access Network) architecture, specifically showing interactions between:

  • Non-Real-Time RIC (Non-RT RIC)

  • Near-Real-Time RIC (Near-RT RIC)

  • ClearML Training Framework

  • ML Designer

Key Components and Flow:

1. RAW data/telemetry sources:

  • UE (User Equipment)

  • O-CU/O-DU (Centralized and Distributed Units)

  • Near-RT RIC

  • Non-RT RIC

These components are configured to communicate over standard O-RAN interfaces like O1, A1, and E1.

2. Non-RT RIC:

  • VES Collector: Gathers telemetry/events from the RAN elements and stores them in InfluxDB, a time-series database.

  • AI/ML Inference Host: It hosts ML rApps (RIC applications) that perform AI/ML inferences, collects inference data, and communicates with the A1 adapter to push policies or models to the Near-RT RIC, ensuring seamless transfer of inference results.

3. ClearML Framework for AI/ML Training:

  • A cloud-based setup using ClearML to automate ML workflows.

  • Raw data from database extraction and storing for ML tasks.

  • Tasks like model training, data prep, etc., creation and make queue.

  • Models training execution on extracted and clean data.

  • Trained models storing and pushing to the AI/ML Inference Host.

  • Manages task tracking, logging, and coordination.

  • Perform training on distributed compute nodes using backend ClearML Agents.

  • ML Designer required configuring and monitoring AI/ML experiments via the ClearML Dashboard.

4. Near-RT RIC:

  • Receives inference results from the Non-RT RIC.

  • Executes xApps (Near-RT RIC applications) using ML-generated policies or decisions.

  • Monitored via the Near-RT RIC dashboard.

Setup

Before Getting Started

  1. Check the Deployment: Ensure that the ClearML server and ClearML agent are deployed in virtual machines (VMs) within the OpenStack project.

    If any of the components are missing, please contact the administrator.

    • ClearML Server: The backend service infrastructure for ClearML. It allows multiple users to collaborate and manage their experiments by working seamlessly with the ClearML Python package and ClearML Agent.

      Components:

      • Web Server: Includes the ClearML Web UI, which is the user interface for tracking, comparing, and managing experiments.

      • API Server: A RESTful API for: - Documenting and logging experiments, including information, statistics, and results. - Querying experiment history, logs, and results.

      • File Server: Stores media and models, making them easily accessible via the ClearML Web UI.

  2. Communicate with the ClearML Server:

    • Create a VM in the OpenStack Project:

      Requirements:

      • Ubuntu 20.04

      • Flavor: 8 CPU, 8 GB RAM, 128 GB Disk

    • Create a Virtual Environment:

      sudo apt-get update
      sudo apt-get install python3-venv
      python3 -m venv myenv
      
    • Activate the Virtual Environment:

      source myenv/bin/activate
      
    • Install the ClearML Python Package:

      pip install clearml
      
    • Connect the ClearML SDK to the Server:

      • Run the ClearML setup wizard:

        clearml-init
        
      • The setup wizard will prompt for ClearML credentials:

        “Please create new ClearML credentials through the settings page in your `clearml-server` web app (e.g., http://localhost:8080/settings/workspace-configuration), or create a free account at https://app.clear.ml/settings/workspace-configuration. In the settings page, press ‘Create new credentials’, then press ‘Copy to clipboard’. Paste the copied configuration here:”

        • Note: To get credentials, please contact the administrator.

        • At the command prompt, paste the copied ClearML credentials. The setup wizard will verify the credentials.

      • Sample Output:

        Detected credentials key="********************" secret="*******"
        CLEARML Hosts configuration:
            Web App: https://app.<your-domain>
            API: https://api.<your-domain>
            File Store: https://files.<your-domain>
        Verifying credentials ...
        Credentials verified!
        New configuration stored in /home/<username>/clearml.conf
        CLEARML setup completed successfully.
        
      • You are now ready to use ClearML in your code!

ClearML Dashboard

The project dashboard provides a summary of users most recent projects, reports, and tasks. Click a project, report or task to quickly access it.

To access the dashboard:

AI-ML Architecture


After logging in you can see the project pages, dataset pages, and access various experiment management features from the dashboard.



AI-ML Architecture


On the Datasets page, you can view, manage, and create datasets, as well as track their versions and storage usage



AI-ML Architecture

Data Collection, Processing or Management examples

Check InfluxDB Credentials

Ensure you have the following InfluxDB credentials:

INFLUXDB_URL = "..."  # InfluxDB URL
TOKEN = "..."         # Your token
ORG = "..."           # Your organization name
BUCKET = "..."        # Your bucket name

Upload a Dataset from InfluxDB to ClearML Server Storage

Use the ClearML Data Management tool to upload datasets. The following Python code serves as a template:

from clearml import Dataset
from influxdb import InfluxDBClient
import pandas as pd
import time
import io

# InfluxDB credentials and configurations
INFLUXDB_URL = "..."  # Replace with your InfluxDB URL
TOKEN = "..."         # Your token
ORG = "..."           # Your organization name
BUCKET = "..."        # Your bucket name

# Create InfluxDB client
client = InfluxDBClient(url=INFLUXDB_URL, token=TOKEN)

# Define the number of days you want to retrieve data from
X_days = 30  # Change this to the number of days you need

# Calculate the timestamp X days ago from the current time
end_time = int(time.time() * 1e9)  # Current time in nanoseconds
start_time = end_time - (X_days * 24 * 3600 * 1e9)  # X days ago in nanoseconds

# Query data from InfluxDB
query = f'SELECT * FROM "randata" WHERE time >= {start_time} AND time <= {end_time}'
result = client.query(query)

# Convert the result to a Pandas DataFrame
df = pd.DataFrame(result.get_points())

# Convert the DataFrame to a CSV-like string in memory
csv_buffer = io.StringIO()
df.to_csv(csv_buffer, index=False)
csv_buffer.seek(0)  # Reset the buffer to the beginning


print(f"Dataset uploaded to ClearML with ID: {dataset.id}")

Upload your own dataset to ClearML Server Storage

  # Upload the in-memory CSV data to ClearML
dataset = Dataset.create(dataset_name="rapp_data", dataset_project="rapp_examples")
dataset.add_object(csv_buffer, "randata.csv")  # Add the in-memory CSV as an object with a filename
dataset.upload()
dataset.finalize()


print(f"Dataset uploaded to ClearML with ID: {dataset.id}")

Accessing the Uploaded Data and Preparing It

from clearml import Dataset
import os
import pandas as pd
from pathlib import Path
from clearml import Task

# Initialize ClearML Task
task = Task.init(project_name="Your-Project", task_name="Data Preparation", output_uri=True)

# Load dataset from ClearML
dataset_name = "your-dataset-name"
dataset_project = "your-dataset-project"
local_dataset_path = Path(Dataset.get(
    dataset_project=dataset_project,
    dataset_name=dataset_name,
    alias="dataset-alias"
).get_local_copy())

# List all files in the dataset directory
data_files = [data_path for data_path in os.listdir(local_dataset_path) if data_path.endswith(".csv")]
print("Data files:", data_files)

# Function to preprocess a single CSV file
def process_file(file_path):
    df = pd.read_csv(file_path)
    # ... code for preparing the data ...
    return df

# Process all data files
dataframes = [process_file(os.path.join(local_dataset_path, file)) for file in data_files]

# Combine into a single DataFrame
combined_data = pd.concat(dataframes, axis=0).reset_index(drop=True)

# Display basic statistics
print(combined_data.describe())

Preprocessing and Normalization

import pandas as pd
from sklearn.preprocessing import StandardScaler, MinMaxScaler

def preprocess_data(df, numeric_cols=None, fill_strategy="mean", drop_cols=None):
    """
    Preprocess the dataset:
    - Fill missing values
    - Drop unnecessary columns
    - Ensure consistent data types
    """
    # Drop unnecessary columns if specified
    if drop_cols:
        df = df.drop(columns=drop_cols, errors="ignore")

    # Fill missing values
    if fill_strategy == "mean":
        df = df.fillna(df.mean(numeric_only=True))
    elif fill_strategy == "median":
        df = df.fillna(df.median(numeric_only=True))
    elif fill_strategy == "zero":
        df = df.fillna(0)
    elif fill_strategy == "ffill":
        df = df.fillna(method="ffill")
    elif fill_strategy == "bfill":
        df = df.fillna(method="bfill")
    else:
        raise ValueError("Unsupported fill strategy. Use 'mean', 'median', 'zero', 'ffill', or 'bfill'.")

    # Ensure numeric columns are of proper type
    if numeric_cols:
        df[numeric_cols] = df[numeric_cols].apply(pd.to_numeric, errors="coerce")

    return df

def normalize_data(df, cols_to_normalize, method="standard"):
    """
    Normalize the specified columns using the given method:
    - 'standard': StandardScaler (z-score normalization)
    - 'minmax': MinMaxScaler (scale to [0, 1])
    """
    if method == "standard":
        scaler = StandardScaler()
    elif method == "minmax":
        scaler = MinMaxScaler()
    else:
        raise ValueError("Unsupported normalization method. Use 'standard' or 'minmax'.")

    df[cols_to_normalize] = scaler.fit_transform(df[cols_to_normalize])

    return df

Model Training

Creating and Training the Model

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

# Assuming 'combined_data' is your preprocessed dataset
data = combined_data.to_numpy()

# Split into training, validation, and test sets
train_size = int(0.7 * len(data))
val_size = int(0.15 * len(data))
test_size = len(data) - train_size - val_size

train_data = data[:train_size]
val_data = data[train_size:train_size+val_size]
test_data = data[train_size+val_size:]

train_input, train_labels = train_data[:, :-1], train_data[:, -1]
val_input, val_labels = val_data[:, :-1], val_data[:, -1]
test_input, test_labels = test_data[:, :-1], test_data[:, -1]

# Create the model
model = tf.keras.Sequential([
    layers.Dense(32, activation='relu', input_shape=(train_input.shape[1],)),
    layers.Dense(16, activation='relu'),
    layers.Dense(8, activation='relu'),
    layers.Dense(3, activation='softmax')  # Adjust '3' to the number of classes in your dataset
])

model.compile(optimizer='adam',
              loss=tf.keras.losses.SparseCategoricalCrossentropy(),
              metrics=['accuracy'])

# Train the model
history = model.fit(
    train_input, train_labels,
    validation_data=(val_input, val_labels),
    batch_size=64,
    epochs=15,
    callbacks=[
        tf.keras.callbacks.EarlyStopping(monitor='val_loss', patience=5),
        tf.keras.callbacks.ReduceLROnPlateau(monitor='val_loss', factor=0.1, patience=3)
    ]
)

print("Training complete!")

Evaluation and Logging

import matplotlib.pyplot as plt

# Evaluate the model
test_loss, test_accuracy = model.evaluate(test_input, test_labels)
print(f"Test Loss: {test_loss}, Test Accuracy: {test_accuracy}")

# Log metrics to ClearML
task.get_logger().report_single_value("Test Loss", test_loss)
task.get_logger().report_single_value("Test Accuracy", test_accuracy)

# Log training history
def plot_training(history):
    plt.figure()
    plt.plot(history.history['loss'], label='Train Loss')
    plt.plot(history.history['val_loss'], label='Validation Loss')
    plt.title('Loss Curve')
    plt.legend()
    plt.savefig('loss_curve.png')
    plt.show()

plot_training(history)

# Save the model
model.save("trained_model.keras")
task.upload_artifact("Trained Model", artifact_object="trained_model.keras")

For a step-by-step walkthrough and practical usage, see the ClearML Experiment in the Sample Experiments section.