mirror of
https://github.com/ROCm/composable_kernel.git
synced 2026-07-15 11:34:54 +00:00
This commit is contained in:
265
test_data/generate_model_configs.py
Normal file
265
test_data/generate_model_configs.py
Normal file
@@ -0,0 +1,265 @@
|
||||
#!/usr/bin/env python3
|
||||
# Copyright (c) Advanced Micro Devices, Inc., or its affiliates.
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
"""
|
||||
Generate Model Configuration Combinations for MIOpen Testing
|
||||
|
||||
This script generates all possible combinations of model parameters
|
||||
and saves them as CSV files that can be read by the shell script.
|
||||
"""
|
||||
|
||||
import csv
|
||||
import argparse
|
||||
|
||||
|
||||
def generate_2d_configs(mode="full"):
|
||||
"""Generate all 2D model configuration combinations
|
||||
|
||||
Args:
|
||||
mode: 'small' for minimal set (~50 configs), 'half' for reduced set (~250 configs), 'full' for comprehensive set (~500 configs)
|
||||
"""
|
||||
|
||||
# Define parameter ranges
|
||||
models_2d = [
|
||||
"resnet18",
|
||||
"resnet34",
|
||||
"resnet50",
|
||||
"mobilenet_v2",
|
||||
"mobilenet_v3_large",
|
||||
"mobilenet_v3_small",
|
||||
"vgg11",
|
||||
"vgg16",
|
||||
"vgg19",
|
||||
"alexnet",
|
||||
"googlenet",
|
||||
"densenet121",
|
||||
"densenet161",
|
||||
"squeezenet1_0",
|
||||
"squeezenet1_1",
|
||||
"shufflenet_v2_x1_0",
|
||||
]
|
||||
|
||||
if mode == "small":
|
||||
# Minimal set for quick testing
|
||||
batch_sizes = [1, 8] # Just two batch sizes
|
||||
# Very limited input dimensions - only 2 key sizes
|
||||
input_dims = [
|
||||
(224, 224), # Standard (most common)
|
||||
(256, 256), # Medium
|
||||
]
|
||||
# Use only first 3 models for minimal testing
|
||||
models_2d = models_2d[:3] # Only resnet18, resnet34, resnet50
|
||||
elif mode == "half":
|
||||
# Reduced set for faster testing
|
||||
batch_sizes = [1, 8, 32] # Small, medium, large
|
||||
# Reduced input dimensions - 5 key sizes
|
||||
input_dims = [
|
||||
(64, 64), # Small
|
||||
(224, 224), # Standard (most common)
|
||||
(512, 512), # Large
|
||||
(224, 320), # Rectangular
|
||||
(227, 227), # AlexNet preferred
|
||||
]
|
||||
else: # full mode
|
||||
# More comprehensive but still limited
|
||||
batch_sizes = [1, 4, 8, 16, 32]
|
||||
# More dimensions but skip some redundant ones
|
||||
input_dims = [
|
||||
(64, 64),
|
||||
(128, 128),
|
||||
(224, 224),
|
||||
(256, 256),
|
||||
(512, 512), # Square
|
||||
(224, 320),
|
||||
(320, 224), # Rectangular (reduced from 4)
|
||||
(227, 227), # AlexNet preferred
|
||||
(299, 299), # Inception preferred
|
||||
]
|
||||
|
||||
precisions = ["fp32"] # , 'fp16', 'bf16']
|
||||
channels = [3] # Most models expect RGB
|
||||
|
||||
configs = []
|
||||
config_id = 1
|
||||
|
||||
# Generate all combinations (but limit to reasonable subset)
|
||||
for model in models_2d:
|
||||
for batch_size in batch_sizes:
|
||||
for height, width in input_dims:
|
||||
for precision in precisions:
|
||||
# Skip some combinations to keep dataset manageable
|
||||
if batch_size > 16 and height > 256:
|
||||
continue # Skip large batch + large image combinations
|
||||
if precision != "fp32" and batch_size < 8:
|
||||
continue # Skip mixed precision with tiny batches
|
||||
|
||||
config_name = f"{model}_b{batch_size}_{height}x{width}_{precision}"
|
||||
|
||||
config = {
|
||||
"config_name": config_name,
|
||||
"model": model,
|
||||
"batch_size": batch_size,
|
||||
"channels": channels[0],
|
||||
"height": height,
|
||||
"width": width,
|
||||
"precision": precision,
|
||||
}
|
||||
|
||||
configs.append(config)
|
||||
config_id += 1
|
||||
|
||||
return configs
|
||||
|
||||
|
||||
def generate_3d_configs(mode="full"):
|
||||
"""Generate all 3D model configuration combinations
|
||||
|
||||
Args:
|
||||
mode: 'small' for minimal set (~10 configs), 'half' for reduced set (~50 configs), 'full' for comprehensive set (~100 configs)
|
||||
"""
|
||||
|
||||
models_3d = ["r3d_18", "mc3_18", "r2plus1d_18"]
|
||||
|
||||
if mode == "small":
|
||||
# Minimal set for quick testing
|
||||
batch_sizes = [1, 4] # Just two batch sizes
|
||||
temporal_sizes = [8] # Only smallest temporal size
|
||||
# Very limited spatial dimensions
|
||||
input_dims = [
|
||||
(112, 112), # Standard for 3D
|
||||
]
|
||||
# Use only first model for minimal testing
|
||||
models_3d = models_3d[:1] # Only r3d_18
|
||||
elif mode == "half":
|
||||
# Reduced set for faster testing
|
||||
batch_sizes = [1, 4, 8] # Skip batch_size=2
|
||||
temporal_sizes = [8, 16] # Skip 32 (most expensive)
|
||||
# Reduced spatial dimensions
|
||||
input_dims = [
|
||||
(112, 112), # Small (common for video)
|
||||
(224, 224), # Standard
|
||||
(224, 320), # Rectangular
|
||||
]
|
||||
else: # full mode
|
||||
# More comprehensive but still reasonable
|
||||
batch_sizes = [1, 2, 4, 8] # 3D models are more memory intensive
|
||||
temporal_sizes = [8, 16, 32]
|
||||
# More dimensions
|
||||
input_dims = [
|
||||
(112, 112),
|
||||
(224, 224),
|
||||
(256, 256), # Standard sizes
|
||||
(224, 320),
|
||||
(320, 224), # Rectangular
|
||||
]
|
||||
|
||||
precisions = ["fp32"] # , 'fp16'] # Skip bf16 for 3D to reduce combinations
|
||||
channels = [3]
|
||||
|
||||
configs = []
|
||||
|
||||
for model in models_3d:
|
||||
for batch_size in batch_sizes:
|
||||
for temporal_size in temporal_sizes:
|
||||
for height, width in input_dims:
|
||||
for precision in precisions:
|
||||
# Skip very large combinations
|
||||
if batch_size > 4 and temporal_size > 16:
|
||||
continue
|
||||
if batch_size > 2 and height > 224:
|
||||
continue
|
||||
|
||||
config_name = f"{model}_b{batch_size}_t{temporal_size}_{height}x{width}_{precision}"
|
||||
|
||||
config = {
|
||||
"config_name": config_name,
|
||||
"model": model,
|
||||
"batch_size": batch_size,
|
||||
"channels": channels[0],
|
||||
"temporal_size": temporal_size,
|
||||
"height": height,
|
||||
"width": width,
|
||||
"precision": precision,
|
||||
}
|
||||
|
||||
configs.append(config)
|
||||
|
||||
return configs
|
||||
|
||||
|
||||
def save_configs_to_csv(configs, filename, config_type):
|
||||
"""Save configurations to CSV file"""
|
||||
|
||||
if not configs:
|
||||
print(f"No {config_type} configurations generated")
|
||||
return
|
||||
|
||||
fieldnames = list(configs[0].keys())
|
||||
|
||||
with open(filename, "w", newline="\n", encoding="utf-8") as csvfile:
|
||||
csvfile.write(f"# {config_type} Model Configurations\n")
|
||||
csvfile.write(f"# Generated {len(configs)} configurations\n")
|
||||
|
||||
writer = csv.DictWriter(csvfile, fieldnames=fieldnames, lineterminator="\n")
|
||||
writer.writeheader()
|
||||
|
||||
for config in configs:
|
||||
writer.writerow(config)
|
||||
|
||||
print(f"Generated {len(configs)} {config_type} configurations → {filename}")
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Generate model configuration combinations"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--output-2d",
|
||||
type=str,
|
||||
default="model_configs_2d.csv",
|
||||
help="Output file for 2D configurations",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--output-3d",
|
||||
type=str,
|
||||
default="model_configs_3d.csv",
|
||||
help="Output file for 3D configurations",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--mode",
|
||||
choices=["small", "half", "full"],
|
||||
default="full",
|
||||
help="Configuration mode: small (~60 total), half (~300 total) or full (~600 total) (default: half)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--limit",
|
||||
type=int,
|
||||
help="Limit number of configurations per type (for testing)",
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
print(f"Generating {args.mode} model configurations...")
|
||||
|
||||
print("Generating 2D model configurations...")
|
||||
configs_2d = generate_2d_configs(mode=args.mode)
|
||||
if args.limit:
|
||||
configs_2d = configs_2d[: args.limit]
|
||||
save_configs_to_csv(configs_2d, args.output_2d, "2D")
|
||||
|
||||
print("Generating 3D model configurations...")
|
||||
configs_3d = generate_3d_configs(mode=args.mode)
|
||||
if args.limit:
|
||||
configs_3d = configs_3d[: args.limit]
|
||||
save_configs_to_csv(configs_3d, args.output_3d, "3D")
|
||||
|
||||
print(
|
||||
f"\nTotal configurations: {len(configs_2d)} 2D + {len(configs_3d)} 3D = {len(configs_2d) + len(configs_3d)}"
|
||||
)
|
||||
print("\nTo use these configurations:")
|
||||
print(" Update generate_test_dataset.sh to read from these CSV files")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
473
test_data/generate_test_dataset.sh
Executable file
473
test_data/generate_test_dataset.sh
Executable file
@@ -0,0 +1,473 @@
|
||||
#!/bin/bash
|
||||
# Copyright (c) Advanced Micro Devices, Inc., or its affiliates.
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
# Generate Comprehensive Convolution Test Dataset for CK
|
||||
# This script captures MIOpen commands from PyTorch models and generates test cases
|
||||
|
||||
set -e # Exit on error
|
||||
set +x # Disable command echo (even if called with bash -x)
|
||||
|
||||
# Trap to kill all background jobs on script exit/interruption
|
||||
cleanup() {
|
||||
echo ""
|
||||
echo "Cleaning up background processes..."
|
||||
# Kill all jobs in the current process group
|
||||
jobs -p | xargs -r kill 2>/dev/null || true
|
||||
wait 2>/dev/null || true
|
||||
echo "Cleanup complete."
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Set up trap for common termination signals
|
||||
trap cleanup SIGINT SIGTERM EXIT
|
||||
|
||||
echo "=========================================="
|
||||
echo "CK Convolution Test Dataset Generator"
|
||||
echo "=========================================="
|
||||
|
||||
# Check if PyTorch is installed, if not create a virtual environment
|
||||
echo "Checking for PyTorch installation..."
|
||||
if ! python3 -c "import torch" 2>/dev/null; then
|
||||
echo "PyTorch not found. Creating virtual environment..."
|
||||
|
||||
# Create a virtual environment in the current directory
|
||||
VENV_DIR="./.venv"
|
||||
if [ ! -d "$VENV_DIR" ]; then
|
||||
python3 -m venv $VENV_DIR || {
|
||||
echo "ERROR: Failed to create virtual environment."
|
||||
echo "Creating empty CSV files as fallback..."
|
||||
echo "# 2D Convolution Test Cases" > conv_test_set_2d_dataset.csv
|
||||
echo "# Combined from multiple models" >> conv_test_set_2d_dataset.csv
|
||||
echo "# 3D Convolution Test Cases" > conv_test_set_3d_dataset.csv
|
||||
echo "# Combined from multiple models" >> conv_test_set_3d_dataset.csv
|
||||
exit 1
|
||||
}
|
||||
fi
|
||||
|
||||
# Activate virtual environment
|
||||
source $VENV_DIR/bin/activate
|
||||
|
||||
# Install PyTorch in virtual environment with ROCm support
|
||||
echo "Installing PyTorch and torchvision with ROCm support in virtual environment..."
|
||||
echo "Installing PyTorch with ROCm 7.1 support..."
|
||||
pip install -r requirements.txt || {
|
||||
echo "ERROR: Failed to install PyTorch with ROCm support."
|
||||
echo "Creating empty CSV files as fallback..."
|
||||
echo "# 2D Convolution Test Cases" > conv_test_set_2d_dataset.csv
|
||||
echo "# Combined from multiple models" >> conv_test_set_2d_dataset.csv
|
||||
echo "# 3D Convolution Test Cases" > conv_test_set_3d_dataset.csv
|
||||
echo "# Combined from multiple models" >> conv_test_set_3d_dataset.csv
|
||||
exit 1
|
||||
}
|
||||
echo "PyTorch installed successfully in virtual environment!"
|
||||
|
||||
# Use the virtual environment's Python for the rest of the script
|
||||
export PYTHON_CMD="$VENV_DIR/bin/python3"
|
||||
else
|
||||
echo "PyTorch is already installed."
|
||||
export PYTHON_CMD="python3"
|
||||
fi
|
||||
|
||||
# Verify PyTorch installation and GPU support
|
||||
$PYTHON_CMD -c "import torch; print(f'PyTorch version: {torch.__version__}')"
|
||||
$PYTHON_CMD -c "import torch; print(f'CUDA/ROCm available: {torch.cuda.is_available()}')"
|
||||
if ! $PYTHON_CMD -c "import torch; import sys; sys.exit(0 if torch.cuda.is_available() else 1)"; then
|
||||
echo "WARNING: PyTorch installed but GPU support not available!"
|
||||
echo "MIOpen commands will not be generated without GPU support."
|
||||
echo "Continuing anyway to generate placeholder data..."
|
||||
fi
|
||||
|
||||
# Parse command line arguments
|
||||
CONFIG_MODE="full" # Default configuration mode: 'small', 'half' or 'full'
|
||||
MAX_PARALLEL_JOBS=1 # Default number of parallel jobs
|
||||
NUM_GPUS=1 # Number of GPUs to use (0 means no GPU assignment)
|
||||
|
||||
# Process arguments
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case $1 in
|
||||
-j)
|
||||
MAX_PARALLEL_JOBS="$2"
|
||||
shift 2
|
||||
;;
|
||||
-j*)
|
||||
MAX_PARALLEL_JOBS="${1#-j}"
|
||||
shift
|
||||
;;
|
||||
--gpus)
|
||||
NUM_GPUS="$2"
|
||||
shift 2
|
||||
;;
|
||||
small|half|full)
|
||||
CONFIG_MODE="$1"
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
echo "Usage: $0 [small|half|full] [-j <num_jobs>] [--gpus <num_gpus>]"
|
||||
echo " Configuration modes: small, half, full (default: full)"
|
||||
echo " -j <num_jobs>: Number of parallel jobs (default: 1)"
|
||||
echo " --gpus <num_gpus>: Number of GPUs to use (e.g., 8 for GPUs 0-7)"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Setup GPU array if GPUs are requested
|
||||
if [ $NUM_GPUS -gt 0 ]; then
|
||||
# Auto-detect available GPUs
|
||||
AVAILABLE_GPUS_COUNT=$(rocm-smi --showid 2>/dev/null | grep -oP 'GPU\[\K[0-9]+' | wc -l)
|
||||
if [ "$AVAILABLE_GPUS_COUNT" -gt 0 ]; then
|
||||
MAX_AVAILABLE=$AVAILABLE_GPUS_COUNT
|
||||
else
|
||||
MAX_AVAILABLE=0
|
||||
fi
|
||||
|
||||
# Validate requested GPU count
|
||||
if [ $NUM_GPUS -gt $MAX_AVAILABLE ]; then
|
||||
echo "WARNING: Requested $NUM_GPUS GPUs but only $MAX_AVAILABLE available. Using $MAX_AVAILABLE GPUs."
|
||||
NUM_GPUS=$MAX_AVAILABLE
|
||||
fi
|
||||
|
||||
# Build GPU array (0 to NUM_GPUS-1)
|
||||
GPU_ARRAY=()
|
||||
for ((i=0; i<NUM_GPUS; i++)); do
|
||||
GPU_ARRAY+=($i)
|
||||
done
|
||||
|
||||
echo "Using $NUM_GPUS GPU(s): ${GPU_ARRAY[*]}"
|
||||
else
|
||||
echo "No GPU assignment specified, using default GPU behavior"
|
||||
GPU_ARRAY=()
|
||||
fi
|
||||
|
||||
# Configuration
|
||||
OUTPUT_DIR="generated_datasets"
|
||||
TIMESTAMP=$(date +"%Y%m%d_%H%M%S")
|
||||
|
||||
# Colors
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
PURPLE='\033[0;35m'
|
||||
CYAN='\033[0;36m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# Create output directory
|
||||
rm -rf "$OUTPUT_DIR"
|
||||
mkdir -p $OUTPUT_DIR
|
||||
|
||||
echo ""
|
||||
echo "Step 1: Generating model configurations"
|
||||
echo "-----------------------------------------"
|
||||
|
||||
# Generate model configuration files (with limit for testing)
|
||||
echo "Generating model configuration files (mode: $CONFIG_MODE)..."
|
||||
$PYTHON_CMD generate_model_configs.py \
|
||||
--mode $CONFIG_MODE \
|
||||
--output-2d $OUTPUT_DIR/model_configs_2d.csv \
|
||||
--output-3d $OUTPUT_DIR/model_configs_3d.csv
|
||||
|
||||
if [ ! -f "$OUTPUT_DIR/model_configs_2d.csv" ] || [ ! -f "$OUTPUT_DIR/model_configs_3d.csv" ]; then
|
||||
echo "ERROR: Failed to generate configuration files"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
# Check if running on GPU
|
||||
if ! command -v rocm-smi &> /dev/null; then
|
||||
echo "ERROR: ROCm not detected. Cannot generate MIOpen commands without GPU."
|
||||
echo "This script requires an AMD GPU with ROCm installed."
|
||||
echo "Creating empty CSV files as placeholder..."
|
||||
echo "# 2D Convolution Test Cases (No GPU available)" > conv_test_set_2d_dataset.csv
|
||||
echo "# 3D Convolution Test Cases (No GPU available)" > conv_test_set_3d_dataset.csv
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check if GPU is actually accessible
|
||||
if ! rocm-smi &> /dev/null; then
|
||||
echo "ERROR: rocm-smi failed. GPU may not be accessible."
|
||||
echo "Creating empty CSV files as placeholder..."
|
||||
echo "# 2D Convolution Test Cases (GPU not accessible)" > conv_test_set_2d_dataset.csv
|
||||
echo "# 3D Convolution Test Cases (GPU not accessible)" > conv_test_set_3d_dataset.csv
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "GPU detected. ROCm version:"
|
||||
rocm-smi --showdriverversion || true
|
||||
|
||||
|
||||
echo ""
|
||||
echo "Step 2: Running 2D/3D models and capturing MIOpen commands"
|
||||
echo "-----------------------------------------"
|
||||
echo "Using up to $MAX_PARALLEL_JOBS parallel jobs"
|
||||
echo ""
|
||||
|
||||
# Process 2D models from CSV configuration file
|
||||
echo "Processing 2D models from $OUTPUT_DIR/model_configs_2d.csv..."
|
||||
|
||||
# Count total configurations (excluding comments and header)
|
||||
TOTAL_CONFIGS=$(grep -v "^#" $OUTPUT_DIR/model_configs_2d.csv | tail -n +2 | wc -l)
|
||||
CURRENT_CONFIG=0
|
||||
|
||||
echo "Total configurations to process: $TOTAL_CONFIGS"
|
||||
echo ""
|
||||
|
||||
# Array to track background job PIDs
|
||||
declare -a job_pids=()
|
||||
# Counter for round-robin GPU assignment
|
||||
GPU_COUNTER=0
|
||||
|
||||
# Read 2D configurations from CSV (skip comments and header)
|
||||
while IFS=',' read -r config_name model batch_size channels height width precision; do
|
||||
# Skip comments and empty lines
|
||||
[[ "$config_name" =~ ^#.*$ ]] && continue
|
||||
[[ "$config_name" == "config_name" ]] && continue # Skip header
|
||||
[[ -z "$config_name" ]] && continue
|
||||
|
||||
# Increment counter
|
||||
CURRENT_CONFIG=$((CURRENT_CONFIG + 1))
|
||||
|
||||
# Build configuration command
|
||||
CONFIG="--model $model --batch-size $batch_size --channels $channels --height $height --width $width --precision $precision"
|
||||
CONFIG_NAME="$config_name"
|
||||
|
||||
# Assign GPU in round-robin fashion if GPUs are specified
|
||||
if [ $NUM_GPUS -gt 0 ]; then
|
||||
GPU_ID=${GPU_ARRAY[$((GPU_COUNTER % NUM_GPUS))]}
|
||||
GPU_COUNTER=$((GPU_COUNTER + 1))
|
||||
echo -e "${GREEN}[${CURRENT_CONFIG}/${TOTAL_CONFIGS}]${NC} ${CYAN}2D${NC} ${YELLOW}$CONFIG_NAME${NC} ${PURPLE}[GPU ${GPU_ID}]${NC} - Starting in background"
|
||||
else
|
||||
GPU_ID=""
|
||||
echo -e "${GREEN}[${CURRENT_CONFIG}/${TOTAL_CONFIGS}]${NC} ${CYAN}2D${NC} ${YELLOW}$CONFIG_NAME${NC} - Starting in background"
|
||||
fi
|
||||
|
||||
# Run in background
|
||||
(
|
||||
# Set HIP_VISIBLE_DEVICES if GPU was assigned
|
||||
if [ -n "$GPU_ID" ]; then
|
||||
export HIP_VISIBLE_DEVICES=$GPU_ID
|
||||
fi
|
||||
|
||||
MIOPEN_ENABLE_LOGGING_CMD=1 $PYTHON_CMD run_model_with_miopen.py \
|
||||
--model $model --batch-size $batch_size --channels $channels --height $height --width $width --precision $precision \
|
||||
> /dev/null 2>> $OUTPUT_DIR/${model}_miopen_log_2d.txt || true
|
||||
echo -e "${GREEN}[DONE]${NC} ${CYAN}2D${NC} ${YELLOW}$CONFIG_NAME${NC}"
|
||||
) &
|
||||
|
||||
job_pids+=($!)
|
||||
|
||||
# Limit number of parallel jobs
|
||||
if [ ${#job_pids[@]} -ge $MAX_PARALLEL_JOBS ]; then
|
||||
# Wait for any job to complete
|
||||
wait -n
|
||||
# Remove completed jobs from array
|
||||
for i in "${!job_pids[@]}"; do
|
||||
if ! kill -0 "${job_pids[$i]}" 2>/dev/null; then
|
||||
unset 'job_pids[$i]'
|
||||
fi
|
||||
done
|
||||
job_pids=("${job_pids[@]}") # Re-index array
|
||||
fi
|
||||
|
||||
done < $OUTPUT_DIR/model_configs_2d.csv
|
||||
|
||||
# Wait for all remaining 2D jobs to complete
|
||||
echo "Waiting for remaining 2D jobs to complete..."
|
||||
wait
|
||||
|
||||
echo "All 2D models processed!"
|
||||
echo ""
|
||||
|
||||
# Process 3D models from CSV configuration file
|
||||
echo "Processing 3D models from $OUTPUT_DIR/model_configs_3d.csv..."
|
||||
|
||||
# Count total 3D configurations (excluding comments and header)
|
||||
TOTAL_3D_CONFIGS=$(grep -v "^#" $OUTPUT_DIR/model_configs_3d.csv | tail -n +2 | wc -l)
|
||||
CURRENT_3D_CONFIG=0
|
||||
|
||||
echo "Total 3D configurations to process: $TOTAL_3D_CONFIGS"
|
||||
echo ""
|
||||
|
||||
# Reset job tracking array
|
||||
declare -a job_pids=()
|
||||
# GPU counter continues from 2D models for round-robin assignment
|
||||
|
||||
# Read 3D configurations from CSV (skip comments and header)
|
||||
while IFS=',' read -r config_name model batch_size channels temporal_size height width precision; do
|
||||
# Skip comments and empty lines
|
||||
[[ "$config_name" =~ ^#.*$ ]] && continue
|
||||
[[ "$config_name" == "config_name" ]] && continue # Skip header
|
||||
[[ -z "$config_name" ]] && continue
|
||||
|
||||
# Increment counter
|
||||
CURRENT_3D_CONFIG=$((CURRENT_3D_CONFIG + 1))
|
||||
|
||||
# Build configuration command for 3D models
|
||||
CONFIG="--model $model --batch-size $batch_size --channels $channels --temporal-size $temporal_size --height $height --width $width --precision $precision"
|
||||
CONFIG_NAME="$config_name"
|
||||
|
||||
# Assign GPU in round-robin fashion if GPUs are specified
|
||||
if [ $NUM_GPUS -gt 0 ]; then
|
||||
GPU_ID=${GPU_ARRAY[$((GPU_COUNTER % NUM_GPUS))]}
|
||||
GPU_COUNTER=$((GPU_COUNTER + 1))
|
||||
echo -e "${GREEN}[${CURRENT_3D_CONFIG}/${TOTAL_3D_CONFIGS}]${NC} ${CYAN}3D${NC} ${YELLOW}$CONFIG_NAME${NC} ${PURPLE}[GPU ${GPU_ID}]${NC} - Starting in background"
|
||||
else
|
||||
GPU_ID=""
|
||||
echo -e "${GREEN}[${CURRENT_3D_CONFIG}/${TOTAL_3D_CONFIGS}]${NC} ${CYAN}3D${NC} ${YELLOW}$CONFIG_NAME${NC} - Starting in background"
|
||||
fi
|
||||
|
||||
# Run in background
|
||||
(
|
||||
# Set HIP_VISIBLE_DEVICES if GPU was assigned
|
||||
if [ -n "$GPU_ID" ]; then
|
||||
export HIP_VISIBLE_DEVICES=$GPU_ID
|
||||
fi
|
||||
|
||||
MIOPEN_ENABLE_LOGGING_CMD=1 $PYTHON_CMD run_model_with_miopen.py \
|
||||
--model $model --batch-size $batch_size --channels $channels --temporal-size $temporal_size --height $height --width $width --precision $precision \
|
||||
> /dev/null 2>> $OUTPUT_DIR/${model}_miopen_log_3d.txt || true
|
||||
echo -e "${GREEN}[DONE]${NC} ${CYAN}3D${NC} ${YELLOW}$CONFIG_NAME${NC}"
|
||||
) &
|
||||
|
||||
job_pids+=($!)
|
||||
|
||||
# Limit number of parallel jobs
|
||||
if [ ${#job_pids[@]} -ge $MAX_PARALLEL_JOBS ]; then
|
||||
# Wait for any job to complete
|
||||
wait -n
|
||||
# Remove completed jobs from array
|
||||
for i in "${!job_pids[@]}"; do
|
||||
if ! kill -0 "${job_pids[$i]}" 2>/dev/null; then
|
||||
unset 'job_pids[$i]'
|
||||
fi
|
||||
done
|
||||
job_pids=("${job_pids[@]}") # Re-index array
|
||||
fi
|
||||
|
||||
done < $OUTPUT_DIR/model_configs_3d.csv
|
||||
|
||||
# Wait for all remaining 3D jobs to complete
|
||||
echo "Waiting for remaining 3D jobs to complete..."
|
||||
wait
|
||||
|
||||
echo "All 3D models processed!"
|
||||
echo ""
|
||||
|
||||
# Disable trap on successful completion
|
||||
trap - SIGINT SIGTERM EXIT
|
||||
|
||||
echo ""
|
||||
echo "Step 3: Converting MIOpen commands to CSV test cases"
|
||||
echo "-----------------------------------------"
|
||||
|
||||
# Convert 2D MIOpen logs to CSV
|
||||
echo "Converting 2D MIOpen logs to CSV..."
|
||||
for log_file in $OUTPUT_DIR/*_miopen_log_2d.txt; do
|
||||
if [ -f "$log_file" ]; then
|
||||
# Extract model name from filename (e.g., resnet_miopen_log_2d.txt -> resnet)
|
||||
base_name=$(basename "$log_file" _miopen_log_2d.txt)
|
||||
output_csv="$OUTPUT_DIR/${base_name}_cases_2d.csv"
|
||||
|
||||
echo " Converting $log_file -> $output_csv"
|
||||
$PYTHON_CMD miopen_to_csv.py \
|
||||
--input "$log_file" \
|
||||
--output-2d "$output_csv" \
|
||||
--model-name "$base_name" \
|
||||
--filter-duplicates || true
|
||||
fi
|
||||
done
|
||||
|
||||
# Convert 3D MIOpen logs to CSV
|
||||
echo "Converting 3D MIOpen logs to CSV..."
|
||||
for log_file in $OUTPUT_DIR/*_miopen_log_3d.txt; do
|
||||
if [ -f "$log_file" ]; then
|
||||
# Extract model name from filename (e.g., resnet3d_18_miopen_log_3d.txt -> resnet3d_18)
|
||||
base_name=$(basename "$log_file" _miopen_log_3d.txt)
|
||||
output_csv="$OUTPUT_DIR/${base_name}_cases_3d.csv"
|
||||
|
||||
echo " Converting $log_file -> $output_csv"
|
||||
$PYTHON_CMD miopen_to_csv.py \
|
||||
--input "$log_file" \
|
||||
--output-3d "$output_csv" \
|
||||
--model-name "$base_name" \
|
||||
--filter-duplicates || true
|
||||
fi
|
||||
done
|
||||
|
||||
echo ""
|
||||
echo "Step 4: Combining CSV files into final datasets"
|
||||
echo "-----------------------------------------"
|
||||
|
||||
# Combine all 2D CSV files into one
|
||||
echo "Combining all 2D test cases..."
|
||||
# First create empty file with comment headers
|
||||
echo "# 2D Convolution Test Cases" > conv_test_set_2d_dataset.csv
|
||||
echo "# Combined from multiple models" >> conv_test_set_2d_dataset.csv
|
||||
# Add header from first file as a comment
|
||||
first_2d_file=$(ls $OUTPUT_DIR/*_cases_2d.csv 2>/dev/null | head -1)
|
||||
if [ -f "$first_2d_file" ]; then
|
||||
# Get the CSV header line and prefix with #
|
||||
header_line=$(grep "^NDim," "$first_2d_file" | head -1)
|
||||
if [ ! -z "$header_line" ]; then
|
||||
echo "# $header_line" >> conv_test_set_2d_dataset.csv
|
||||
fi
|
||||
fi
|
||||
# Append all data rows (skip comment lines and CSV header) from all files
|
||||
for csv_file in $OUTPUT_DIR/*_cases_2d.csv; do
|
||||
if [ -f "$csv_file" ]; then
|
||||
# Skip lines starting with # and the NDim header line
|
||||
grep -v "^#" "$csv_file" | grep -v "^NDim," >> conv_test_set_2d_dataset.csv 2>/dev/null || true
|
||||
fi
|
||||
done
|
||||
|
||||
# Combine all 3D CSV files into one
|
||||
echo "Combining all 3D test cases..."
|
||||
# First create empty file with comment headers
|
||||
echo "# 3D Convolution Test Cases" > conv_test_set_3d_dataset.csv
|
||||
echo "# Combined from multiple models" >> conv_test_set_3d_dataset.csv
|
||||
# Add header from first file as a comment
|
||||
first_3d_file=$(ls $OUTPUT_DIR/*_cases_3d.csv 2>/dev/null | head -1)
|
||||
if [ -f "$first_3d_file" ]; then
|
||||
# Get the CSV header line and prefix with #
|
||||
header_line=$(grep "^NDim," "$first_3d_file" | head -1)
|
||||
if [ ! -z "$header_line" ]; then
|
||||
echo "# $header_line" >> conv_test_set_3d_dataset.csv
|
||||
fi
|
||||
fi
|
||||
# Append all data rows (skip comment lines and CSV header) from all files
|
||||
for csv_file in $OUTPUT_DIR/*_cases_3d.csv; do
|
||||
if [ -f "$csv_file" ]; then
|
||||
# Skip lines starting with # and the NDim header line
|
||||
grep -v "^#" "$csv_file" | grep -v "^NDim," >> conv_test_set_3d_dataset.csv 2>/dev/null || true
|
||||
fi
|
||||
done
|
||||
|
||||
# Count test cases
|
||||
COUNT_2D=0
|
||||
COUNT_3D=0
|
||||
if [ -f "conv_test_set_2d_dataset.csv" ]; then
|
||||
COUNT_2D=$(grep -v "^#" conv_test_set_2d_dataset.csv | tail -n +2 | wc -l)
|
||||
fi
|
||||
if [ -f "conv_test_set_3d_dataset.csv" ]; then
|
||||
COUNT_3D=$(grep -v "^#" conv_test_set_3d_dataset.csv | tail -n +2 | wc -l)
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "=========================================="
|
||||
echo "Dataset Generation Complete!"
|
||||
echo "=========================================="
|
||||
echo ""
|
||||
echo "Generated files:"
|
||||
if [ $COUNT_2D -gt 0 ]; then
|
||||
echo " - conv_test_set_2d_dataset.csv: $COUNT_2D test cases"
|
||||
fi
|
||||
if [ $COUNT_3D -gt 0 ]; then
|
||||
echo " - conv_test_set_3d_dataset.csv: $COUNT_3D test cases"
|
||||
fi
|
||||
echo " - Intermediate files in: $OUTPUT_DIR/"
|
||||
echo ""
|
||||
echo "To use these datasets for direction (bwd_data, bwd_weight, or fwd):"
|
||||
echo " 1. Build the test: cd ../script && make -j64 test_grouped_convnd_<direction>_dataset_xdl"
|
||||
echo " 2. Run the test: ./bin/test_grouped_convnd_<direction>_dataset_xdl"
|
||||
echo ""
|
||||
1187
test_data/gtest_parallel.py
Normal file
1187
test_data/gtest_parallel.py
Normal file
File diff suppressed because it is too large
Load Diff
518
test_data/miopen_to_csv.py
Normal file
518
test_data/miopen_to_csv.py
Normal file
@@ -0,0 +1,518 @@
|
||||
#!/usr/bin/env python3
|
||||
# Copyright (c) Advanced Micro Devices, Inc., or its affiliates.
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
"""
|
||||
Convert MIOpen Driver Commands to CSV Test Cases
|
||||
|
||||
Parses MIOpen driver commands from log files and converts them to CSV format
|
||||
for CK convolution testing.
|
||||
|
||||
Usage:
|
||||
python3 miopen_to_csv.py --input miopen_commands.txt --output conv_cases.csv
|
||||
python3 miopen_to_csv.py --input miopen_log.txt --output-2d conv_2d.csv --output-3d conv_3d.csv
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import csv
|
||||
import re
|
||||
import os
|
||||
|
||||
|
||||
def parse_miopen_command(command_line):
|
||||
"""
|
||||
Parse MIOpen driver command line into parameter dictionary
|
||||
|
||||
Example input:
|
||||
./bin/MIOpenDriver conv -n 4 -c 3 -H 224 -W 224 -k 64 -y 3 -x 3 -p 1 -q 1 -u 1 -v 1 -l 1 -j 1 -m conv -g 1 -F 1 -t 1
|
||||
|
||||
Returns dict with parsed parameters or None if parsing fails
|
||||
"""
|
||||
if not command_line.strip().startswith("./bin/MIOpenDriver conv"):
|
||||
return None
|
||||
|
||||
# Extract parameters using regex
|
||||
params = {}
|
||||
|
||||
# Parameter mapping: flag -> description
|
||||
# Support both short (-D) and long (--in_d) parameter formats
|
||||
param_patterns = {
|
||||
"n": r"-n\s+(\d+)", # batch size
|
||||
"c": r"-c\s+(\d+)", # input channels
|
||||
"k": r"-k\s+(\d+)", # output channels
|
||||
"H": r"-H\s+(\d+)", # input height
|
||||
"W": r"-W\s+(\d+)", # input width
|
||||
"D": r"(?:-D|--in_d)\s+(\d+)", # input depth (3D only) - supports both -D and --in_d
|
||||
"y": r"-y\s+(\d+)", # kernel height
|
||||
"x": r"-x\s+(\d+)", # kernel width
|
||||
"z": r"(?:-z|--fil_d)\s+(\d+)", # kernel depth (3D only) - supports both -z and --fil_d
|
||||
"u": r"-u\s+(\d+)", # stride height
|
||||
"v": r"-v\s+(\d+)", # stride width
|
||||
"w": r"(?:-w|--conv_stride_d)\s+(\d+)", # stride depth (3D only) - supports both -w and --conv_stride_d
|
||||
"p": r"-p\s+(\d+)", # pad height
|
||||
"q": r"-q\s+(\d+)", # pad width
|
||||
"s": r"(?:-s|--pad_d)\s+(\d+)", # pad depth (3D only) - supports both -s and --pad_d
|
||||
"l": r"-l\s+(\d+)", # dilation height
|
||||
"j": r"-j\s+(\d+)", # dilation width
|
||||
"r": r"(?:-r|--dilation_d)\s+(\d+)", # dilation depth (3D only) - supports both -r and --dilation_d
|
||||
"g": r"-g\s+(\d+)", # groups
|
||||
"F": r"-F\s+(\d+)", # direction (1=fwd, 2=bwd_weight, 4=bwd_data)
|
||||
}
|
||||
|
||||
for param, pattern in param_patterns.items():
|
||||
match = re.search(pattern, command_line)
|
||||
if match:
|
||||
params[param] = int(match.group(1))
|
||||
|
||||
return params if params else None
|
||||
|
||||
|
||||
def miopen_to_conv_param(miopen_params):
|
||||
"""
|
||||
Convert MIOpen parameters to CK ConvParam format
|
||||
|
||||
Returns dictionary in CSV format or None if conversion fails
|
||||
"""
|
||||
if not miopen_params:
|
||||
return None
|
||||
|
||||
# Determine if 2D or 3D convolution
|
||||
is_3d = (
|
||||
"D" in miopen_params
|
||||
or "z" in miopen_params
|
||||
or "w" in miopen_params
|
||||
or "r" in miopen_params
|
||||
or "s" in miopen_params
|
||||
)
|
||||
|
||||
# Extract basic parameters with defaults
|
||||
ndim = 3 if is_3d else 2
|
||||
groups = miopen_params.get("g", 1)
|
||||
batch_size = miopen_params.get("n", 1)
|
||||
# MIOpen uses total channels (C*G), CK uses channels per group
|
||||
out_channels_total = miopen_params.get("k", 64)
|
||||
in_channels_total = miopen_params.get("c", 3)
|
||||
out_channels = out_channels_total // groups # CK format: channels per group
|
||||
in_channels = in_channels_total // groups # CK format: channels per group
|
||||
|
||||
if is_3d:
|
||||
# 3D convolution
|
||||
kernel_d = miopen_params.get("z", 3)
|
||||
kernel_h = miopen_params.get("y", 3)
|
||||
kernel_w = miopen_params.get("x", 3)
|
||||
|
||||
input_d = miopen_params.get("D", 16)
|
||||
input_h = miopen_params.get("H", 32)
|
||||
input_w = miopen_params.get("W", 32)
|
||||
|
||||
stride_d = miopen_params.get("w", 1)
|
||||
stride_h = miopen_params.get("u", 1)
|
||||
stride_w = miopen_params.get("v", 1)
|
||||
|
||||
dilation_d = miopen_params.get("r", 1)
|
||||
dilation_h = miopen_params.get("l", 1)
|
||||
dilation_w = miopen_params.get("j", 1)
|
||||
|
||||
pad_d = miopen_params.get("s", 0)
|
||||
pad_h = miopen_params.get("p", 0)
|
||||
pad_w = miopen_params.get("q", 0)
|
||||
|
||||
# Calculate output dimensions
|
||||
output_d = (
|
||||
input_d + 2 * pad_d - dilation_d * (kernel_d - 1) - 1
|
||||
) // stride_d + 1
|
||||
output_h = (
|
||||
input_h + 2 * pad_h - dilation_h * (kernel_h - 1) - 1
|
||||
) // stride_h + 1
|
||||
output_w = (
|
||||
input_w + 2 * pad_w - dilation_w * (kernel_w - 1) - 1
|
||||
) // stride_w + 1
|
||||
|
||||
# Skip invalid configurations
|
||||
if output_d <= 0 or output_h <= 0 or output_w <= 0:
|
||||
return None
|
||||
|
||||
direction = miopen_params.get("F", 1) # 1=fwd, 2=bwd_weight, 4=bwd_data
|
||||
direction_name = {1: "fwd", 2: "bwd_weight", 4: "bwd_data"}.get(
|
||||
direction, "fwd"
|
||||
)
|
||||
|
||||
return {
|
||||
"NDim": ndim,
|
||||
"Groups": groups,
|
||||
"BatchSize": batch_size,
|
||||
"OutChannels": out_channels,
|
||||
"InChannels": in_channels,
|
||||
"KernelD": kernel_d,
|
||||
"KernelH": kernel_h,
|
||||
"KernelW": kernel_w,
|
||||
"InputD": input_d,
|
||||
"InputH": input_h,
|
||||
"InputW": input_w,
|
||||
"OutputD": output_d,
|
||||
"OutputH": output_h,
|
||||
"OutputW": output_w,
|
||||
"StrideD": stride_d,
|
||||
"StrideH": stride_h,
|
||||
"StrideW": stride_w,
|
||||
"DilationD": dilation_d,
|
||||
"DilationH": dilation_h,
|
||||
"DilationW": dilation_w,
|
||||
"LeftPadD": pad_d,
|
||||
"LeftPadH": pad_h,
|
||||
"LeftPadW": pad_w,
|
||||
"RightPadD": pad_d,
|
||||
"RightPadH": pad_h,
|
||||
"RightPadW": pad_w,
|
||||
"TestName": f"MIOpen_3D_{direction_name}",
|
||||
}
|
||||
|
||||
else:
|
||||
# 2D convolution
|
||||
kernel_h = miopen_params.get("y", 3)
|
||||
kernel_w = miopen_params.get("x", 3)
|
||||
|
||||
input_h = miopen_params.get("H", 32)
|
||||
input_w = miopen_params.get("W", 32)
|
||||
|
||||
stride_h = miopen_params.get("u", 1)
|
||||
stride_w = miopen_params.get("v", 1)
|
||||
|
||||
dilation_h = miopen_params.get("l", 1)
|
||||
dilation_w = miopen_params.get("j", 1)
|
||||
|
||||
pad_h = miopen_params.get("p", 0)
|
||||
pad_w = miopen_params.get("q", 0)
|
||||
|
||||
# Calculate output dimensions
|
||||
output_h = (
|
||||
input_h + 2 * pad_h - dilation_h * (kernel_h - 1) - 1
|
||||
) // stride_h + 1
|
||||
output_w = (
|
||||
input_w + 2 * pad_w - dilation_w * (kernel_w - 1) - 1
|
||||
) // stride_w + 1
|
||||
|
||||
# Skip invalid configurations
|
||||
if output_h <= 0 or output_w <= 0:
|
||||
return None
|
||||
|
||||
direction = miopen_params.get("F", 1)
|
||||
direction_name = {1: "fwd", 2: "bwd_weight", 4: "bwd_data"}.get(
|
||||
direction, "fwd"
|
||||
)
|
||||
|
||||
return {
|
||||
"NDim": ndim,
|
||||
"Groups": groups,
|
||||
"BatchSize": batch_size,
|
||||
"OutChannels": out_channels,
|
||||
"InChannels": in_channels,
|
||||
"KernelH": kernel_h,
|
||||
"KernelW": kernel_w,
|
||||
"InputH": input_h,
|
||||
"InputW": input_w,
|
||||
"OutputH": output_h,
|
||||
"OutputW": output_w,
|
||||
"StrideH": stride_h,
|
||||
"StrideW": stride_w,
|
||||
"DilationH": dilation_h,
|
||||
"DilationW": dilation_w,
|
||||
"LeftPadH": pad_h,
|
||||
"LeftPadW": pad_w,
|
||||
"RightPadH": pad_h,
|
||||
"RightPadW": pad_w,
|
||||
"TestName": f"MIOpen_2D_{direction_name}",
|
||||
}
|
||||
|
||||
|
||||
def write_csv_cases(test_cases, output_file, ndim):
|
||||
"""Write test cases to CSV file"""
|
||||
if not test_cases:
|
||||
print(f"No {ndim}D test cases to write")
|
||||
return
|
||||
|
||||
print(f"Writing {len(test_cases)} {ndim}D test cases to {output_file}")
|
||||
|
||||
# Define CSV headers based on dimension
|
||||
if ndim == 2:
|
||||
headers = [
|
||||
"NDim",
|
||||
"Groups",
|
||||
"BatchSize",
|
||||
"OutChannels",
|
||||
"InChannels",
|
||||
"KernelH",
|
||||
"KernelW",
|
||||
"InputH",
|
||||
"InputW",
|
||||
"OutputH",
|
||||
"OutputW",
|
||||
"StrideH",
|
||||
"StrideW",
|
||||
"DilationH",
|
||||
"DilationW",
|
||||
"LeftPadH",
|
||||
"LeftPadW",
|
||||
"RightPadH",
|
||||
"RightPadW",
|
||||
"TestName",
|
||||
]
|
||||
else: # 3D
|
||||
headers = [
|
||||
"NDim",
|
||||
"Groups",
|
||||
"BatchSize",
|
||||
"OutChannels",
|
||||
"InChannels",
|
||||
"KernelD",
|
||||
"KernelH",
|
||||
"KernelW",
|
||||
"InputD",
|
||||
"InputH",
|
||||
"InputW",
|
||||
"OutputD",
|
||||
"OutputH",
|
||||
"OutputW",
|
||||
"StrideD",
|
||||
"StrideH",
|
||||
"StrideW",
|
||||
"DilationD",
|
||||
"DilationH",
|
||||
"DilationW",
|
||||
"LeftPadD",
|
||||
"LeftPadH",
|
||||
"LeftPadW",
|
||||
"RightPadD",
|
||||
"RightPadH",
|
||||
"RightPadW",
|
||||
"TestName",
|
||||
]
|
||||
|
||||
with open(output_file, "w", newline="") as csvfile:
|
||||
# Write header comment
|
||||
csvfile.write(f"# {ndim}D Convolution Test Cases from MIOpen Commands\n")
|
||||
csvfile.write(f"# Generated {len(test_cases)} test cases\n")
|
||||
|
||||
writer = csv.DictWriter(csvfile, fieldnames=headers)
|
||||
writer.writeheader()
|
||||
|
||||
for test_case in test_cases:
|
||||
# Only write fields that exist in headers
|
||||
filtered_case = {k: v for k, v in test_case.items() if k in headers}
|
||||
writer.writerow(filtered_case)
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Convert MIOpen commands to CSV test cases"
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"--input",
|
||||
type=str,
|
||||
required=True,
|
||||
help="Input file with MIOpen driver commands",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--output", type=str, help="Output CSV file (for mixed 2D/3D cases)"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--output-2d",
|
||||
type=str,
|
||||
default="miopen_conv_2d.csv",
|
||||
help="Output CSV file for 2D cases",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--output-3d",
|
||||
type=str,
|
||||
default="miopen_conv_3d.csv",
|
||||
help="Output CSV file for 3D cases",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--filter-duplicates", action="store_true", help="Remove duplicate test cases"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--model-name",
|
||||
type=str,
|
||||
default="MIOpen",
|
||||
help="Model name to use in test case names (default: MIOpen)",
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
if not os.path.exists(args.input):
|
||||
print(f"ERROR: Input file not found: {args.input}")
|
||||
return 1
|
||||
|
||||
print(f"Parsing MIOpen commands from {args.input}...")
|
||||
|
||||
test_cases_2d = []
|
||||
test_cases_3d = []
|
||||
total_lines = 0
|
||||
parsed_lines = 0
|
||||
|
||||
with open(args.input, "r") as f:
|
||||
for line_num, line in enumerate(f, 1):
|
||||
total_lines += 1
|
||||
line = line.strip()
|
||||
|
||||
# Skip empty lines and non-MIOpen commands
|
||||
# Handle both direct commands and logged commands with MIOpen prefix
|
||||
if not line:
|
||||
continue
|
||||
|
||||
# Extract the actual MIOpenDriver command from logged format
|
||||
if "MIOpenDriver conv" in line:
|
||||
# Extract command after finding MIOpenDriver
|
||||
command_start = line.find("./bin/MIOpenDriver conv")
|
||||
if command_start != -1:
|
||||
line = line[command_start:]
|
||||
else:
|
||||
# Handle cases where path might be different - create standard format
|
||||
driver_start = line.find("MIOpenDriver conv")
|
||||
if driver_start != -1:
|
||||
line = "./bin/" + line[driver_start:]
|
||||
else:
|
||||
continue
|
||||
elif not line.startswith("./bin/MIOpenDriver conv"):
|
||||
continue
|
||||
|
||||
try:
|
||||
# Parse MIOpen command
|
||||
miopen_params = parse_miopen_command(line)
|
||||
if not miopen_params:
|
||||
continue
|
||||
|
||||
# Convert to ConvParam format
|
||||
conv_param = miopen_to_conv_param(miopen_params)
|
||||
if not conv_param:
|
||||
continue
|
||||
|
||||
# Add model name to test name
|
||||
conv_param["TestName"] = f"{args.model_name}_{conv_param['NDim']}D_fwd"
|
||||
|
||||
# Separate 2D and 3D cases
|
||||
if conv_param["NDim"] == 2:
|
||||
test_cases_2d.append(conv_param)
|
||||
else:
|
||||
test_cases_3d.append(conv_param)
|
||||
|
||||
parsed_lines += 1
|
||||
|
||||
except Exception as e:
|
||||
print(f"WARNING: Failed to parse line {line_num}: {e}")
|
||||
continue
|
||||
|
||||
print(f"Processed {total_lines} lines, parsed {parsed_lines} commands")
|
||||
print(f"Found {len(test_cases_2d)} 2D cases, {len(test_cases_3d)} 3D cases")
|
||||
|
||||
# Remove duplicates if requested
|
||||
if args.filter_duplicates:
|
||||
# Simple duplicate removal based on key parameters
|
||||
def make_key(case):
|
||||
if case["NDim"] == 2:
|
||||
return (
|
||||
case["Groups"],
|
||||
case["BatchSize"],
|
||||
case["OutChannels"],
|
||||
case["InChannels"],
|
||||
case["KernelH"],
|
||||
case["KernelW"],
|
||||
case["InputH"],
|
||||
case["InputW"],
|
||||
case["StrideH"],
|
||||
case["StrideW"],
|
||||
)
|
||||
else:
|
||||
return (
|
||||
case["Groups"],
|
||||
case["BatchSize"],
|
||||
case["OutChannels"],
|
||||
case["InChannels"],
|
||||
case["KernelD"],
|
||||
case["KernelH"],
|
||||
case["KernelW"],
|
||||
case["InputD"],
|
||||
case["InputH"],
|
||||
case["InputW"],
|
||||
case["StrideD"],
|
||||
case["StrideH"],
|
||||
case["StrideW"],
|
||||
)
|
||||
|
||||
seen_2d = set()
|
||||
unique_2d = []
|
||||
for case in test_cases_2d:
|
||||
key = make_key(case)
|
||||
if key not in seen_2d:
|
||||
seen_2d.add(key)
|
||||
unique_2d.append(case)
|
||||
|
||||
seen_3d = set()
|
||||
unique_3d = []
|
||||
for case in test_cases_3d:
|
||||
key = make_key(case)
|
||||
if key not in seen_3d:
|
||||
seen_3d.add(key)
|
||||
unique_3d.append(case)
|
||||
|
||||
print(
|
||||
f"After deduplication: {len(unique_2d)} 2D cases, {len(unique_3d)} 3D cases"
|
||||
)
|
||||
test_cases_2d = unique_2d
|
||||
test_cases_3d = unique_3d
|
||||
|
||||
# Write output files
|
||||
if args.output:
|
||||
# Write mixed cases to single file
|
||||
all_cases = test_cases_2d + test_cases_3d
|
||||
if all_cases:
|
||||
print(f"Writing {len(all_cases)} total cases to {args.output}")
|
||||
# Use 2D headers for mixed file, extend as needed
|
||||
mixed_headers = [
|
||||
"NDim",
|
||||
"Groups",
|
||||
"BatchSize",
|
||||
"OutChannels",
|
||||
"InChannels",
|
||||
"KernelH",
|
||||
"KernelW",
|
||||
"InputH",
|
||||
"InputW",
|
||||
"OutputH",
|
||||
"OutputW",
|
||||
"StrideH",
|
||||
"StrideW",
|
||||
"DilationH",
|
||||
"DilationW",
|
||||
"LeftPadH",
|
||||
"LeftPadW",
|
||||
"RightPadH",
|
||||
"RightPadW",
|
||||
"TestName",
|
||||
]
|
||||
|
||||
with open(args.output, "w", newline="") as csvfile:
|
||||
csvfile.write(
|
||||
"# Mixed 2D/3D Convolution Test Cases from MIOpen Commands\n"
|
||||
)
|
||||
writer = csv.DictWriter(
|
||||
csvfile, fieldnames=mixed_headers, extrasaction="ignore"
|
||||
)
|
||||
writer.writeheader()
|
||||
for case in all_cases:
|
||||
writer.writerow(case)
|
||||
else:
|
||||
# Write separate files for 2D and 3D
|
||||
if test_cases_2d:
|
||||
write_csv_cases(test_cases_2d, args.output_2d, 2)
|
||||
|
||||
if test_cases_3d:
|
||||
write_csv_cases(test_cases_3d, args.output_3d, 3)
|
||||
|
||||
print("Conversion completed!")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
exit(main())
|
||||
3
test_data/requirements.txt
Normal file
3
test_data/requirements.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
-i https://download.pytorch.org/whl/rocm7.1
|
||||
torch==2.10.*
|
||||
torchvision==0.25.*
|
||||
202
test_data/run_model_with_miopen.py
Normal file
202
test_data/run_model_with_miopen.py
Normal file
@@ -0,0 +1,202 @@
|
||||
#!/usr/bin/env python3
|
||||
# Copyright (c) Advanced Micro Devices, Inc., or its affiliates.
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
"""
|
||||
PyTorch Model Runner with MIOpen Command Logging using torchvision models
|
||||
|
||||
Usage:
|
||||
MIOPEN_ENABLE_LOGGING_CMD=1 python3 run_model_with_miopen.py --model resnet18 2> miopen_commands.txt
|
||||
|
||||
Available 2D models: alexnet, vgg11, vgg16, resnet18, resnet50, mobilenet_v2, etc.
|
||||
Available 3D models: r3d_18, mc3_18, r2plus1d_18
|
||||
"""
|
||||
|
||||
import torch
|
||||
import torchvision.models as models
|
||||
import torchvision.models.video as video_models
|
||||
import argparse
|
||||
import os
|
||||
|
||||
# Define available models
|
||||
MODELS_2D = [
|
||||
"alexnet",
|
||||
"vgg11",
|
||||
"vgg11_bn",
|
||||
"vgg13",
|
||||
"vgg13_bn",
|
||||
"vgg16",
|
||||
"vgg16_bn",
|
||||
"vgg19",
|
||||
"vgg19_bn",
|
||||
"resnet18",
|
||||
"resnet34",
|
||||
"resnet50",
|
||||
"resnet101",
|
||||
"resnet152",
|
||||
"resnext50_32x4d",
|
||||
"resnext101_32x8d",
|
||||
"resnext101_64x4d",
|
||||
"wide_resnet50_2",
|
||||
"wide_resnet101_2",
|
||||
"densenet121",
|
||||
"densenet161",
|
||||
"densenet169",
|
||||
"densenet201",
|
||||
"inception_v3",
|
||||
"googlenet",
|
||||
"shufflenet_v2_x0_5",
|
||||
"shufflenet_v2_x1_0",
|
||||
"shufflenet_v2_x1_5",
|
||||
"shufflenet_v2_x2_0",
|
||||
"mobilenet_v2",
|
||||
"mobilenet_v3_large",
|
||||
"mobilenet_v3_small",
|
||||
"mnasnet0_5",
|
||||
"mnasnet0_75",
|
||||
"mnasnet1_0",
|
||||
"mnasnet1_3",
|
||||
"squeezenet1_0",
|
||||
"squeezenet1_1",
|
||||
]
|
||||
|
||||
MODELS_3D = ["r3d_18", "mc3_18", "r2plus1d_18"]
|
||||
|
||||
ALL_MODELS = MODELS_2D + MODELS_3D
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(
|
||||
description="PyTorch Model Runner with MIOpen Command Logging"
|
||||
)
|
||||
|
||||
# Model selection
|
||||
parser.add_argument(
|
||||
"--model", choices=ALL_MODELS, default="resnet18", help="Model to run"
|
||||
)
|
||||
|
||||
# Input tensor dimensions
|
||||
parser.add_argument("--batch-size", type=int, default=4, help="Batch size")
|
||||
parser.add_argument(
|
||||
"--channels",
|
||||
type=int,
|
||||
default=3,
|
||||
help="Input channels (e.g., 3 for RGB, 1 for grayscale)",
|
||||
)
|
||||
parser.add_argument("--height", type=int, default=224, help="Input height")
|
||||
parser.add_argument("--width", type=int, default=224, help="Input width")
|
||||
parser.add_argument(
|
||||
"--input-size",
|
||||
type=int,
|
||||
help="Input size (sets both height and width to same value)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--temporal-size", type=int, default=16, help="Temporal dimension for 3D models"
|
||||
)
|
||||
|
||||
# Device and precision
|
||||
parser.add_argument(
|
||||
"--device",
|
||||
choices=["cuda", "cpu", "auto"],
|
||||
default="auto",
|
||||
help="Device to run on",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--precision",
|
||||
choices=["fp32", "fp16", "bf16"],
|
||||
default="fp32",
|
||||
help="Floating point precision",
|
||||
)
|
||||
|
||||
# Output control
|
||||
parser.add_argument(
|
||||
"--quiet", action="store_true", help="Suppress output except errors"
|
||||
)
|
||||
parser.add_argument("--verbose", action="store_true", help="Verbose output")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
# Handle input-size override
|
||||
if args.input_size:
|
||||
args.height = args.input_size
|
||||
args.width = args.input_size
|
||||
|
||||
# Check MIOpen logging
|
||||
if not os.environ.get("MIOPEN_ENABLE_LOGGING_CMD") and not args.quiet:
|
||||
print("WARNING: Set MIOPEN_ENABLE_LOGGING_CMD=1 to capture commands")
|
||||
|
||||
# Device selection
|
||||
if args.device == "auto":
|
||||
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
|
||||
else:
|
||||
device = torch.device(args.device)
|
||||
|
||||
# Check if actually running on GPU
|
||||
if device.type == "cpu":
|
||||
import sys
|
||||
|
||||
print(
|
||||
"WARNING: Running on CPU, MIOpen commands will not be generated!",
|
||||
file=sys.stderr,
|
||||
)
|
||||
print(f"CUDA/ROCm available: {torch.cuda.is_available()}", file=sys.stderr)
|
||||
if torch.cuda.is_available():
|
||||
print(f"GPU device count: {torch.cuda.device_count()}", file=sys.stderr)
|
||||
print(
|
||||
f"GPU name: {torch.cuda.get_device_name(0) if torch.cuda.device_count() > 0 else 'N/A'}",
|
||||
file=sys.stderr,
|
||||
)
|
||||
# Continue anyway for testing purposes
|
||||
|
||||
if not args.quiet:
|
||||
print(f"Using device: {device}")
|
||||
|
||||
# Create model using torchvision
|
||||
if args.model in MODELS_3D:
|
||||
# 3D Video models
|
||||
model = getattr(video_models, args.model)(weights=None)
|
||||
# 3D input: (batch, channels, temporal, height, width)
|
||||
input_tensor = torch.randn(
|
||||
args.batch_size, args.channels, args.temporal_size, args.height, args.width
|
||||
)
|
||||
if not args.quiet:
|
||||
print(f"3D model: {args.model}")
|
||||
print(f"Input shape: {input_tensor.shape} (B, C, T, H, W)")
|
||||
else:
|
||||
# 2D Image models
|
||||
model = getattr(models, args.model)(weights=None)
|
||||
# 2D input: (batch, channels, height, width)
|
||||
input_tensor = torch.randn(
|
||||
args.batch_size, args.channels, args.height, args.width
|
||||
)
|
||||
if not args.quiet:
|
||||
print(f"2D model: {args.model}")
|
||||
print(f"Input shape: {input_tensor.shape} (B, C, H, W)")
|
||||
|
||||
# Set precision
|
||||
if args.precision == "fp16":
|
||||
model = model.half()
|
||||
input_tensor = input_tensor.half()
|
||||
elif args.precision == "bf16":
|
||||
model = model.bfloat16()
|
||||
input_tensor = input_tensor.bfloat16()
|
||||
|
||||
model = model.to(device)
|
||||
input_tensor = input_tensor.to(device)
|
||||
|
||||
if not args.quiet:
|
||||
print(f"Running {args.model} model...")
|
||||
|
||||
# Run inference
|
||||
model.eval()
|
||||
with torch.no_grad():
|
||||
output = model(input_tensor)
|
||||
if not args.quiet:
|
||||
print(f"Output shape: {output.shape}")
|
||||
|
||||
if not args.quiet:
|
||||
print("Done! MIOpen commands logged to stderr")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user