[misc]: extend the comment sweep to every file
This commit is contained in:
committed by
fv-superagent
parent
74e3061646
commit
f496e4b838
@@ -77,9 +77,6 @@ if [[ "${1:-}" == "--stop" ]]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Args
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
usage() {
|
||||
cat <<USAGE
|
||||
@@ -168,9 +165,6 @@ esac
|
||||
REPO_ROOT="${DREAMVERSE_REPO_ROOT:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}"
|
||||
LOG_DIR="${DREAMVERSE_LOG_DIR:-/tmp/opencode/dreamverse-deploy}"
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Prereq checks
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
bail() { echo "error: $*" >&2; exit 3; }
|
||||
|
||||
@@ -234,9 +228,6 @@ echo " python: ${CONDA_ENV_PYTHON}"
|
||||
|
||||
mkdir -p "${LOG_DIR}"
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Teardown anything on target ports
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
echo "[1/8] killing any existing deploy on ports ${BACKEND_PORT}/${FRONTEND_PORT} and GPU ${GPU}..."
|
||||
|
||||
@@ -281,9 +272,6 @@ done
|
||||
gpu_mem="$(nvidia-smi --query-gpu=memory.used --format=csv,noheader,nounits 2>/dev/null | sed -n "$((GPU + 1))p" || echo 0)"
|
||||
echo " ports cleared; GPU${GPU} at ${gpu_mem} MiB"
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Launch backend
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
echo "[2/8] launching backend on GPU ${GPU} port ${BACKEND_PORT} (warmup=${WARMUP} torch_compile=${TORCH_COMPILE} nvenc=${NVENC})..."
|
||||
|
||||
@@ -367,9 +355,6 @@ fi
|
||||
|
||||
echo "[4/8] backend /readyz OK"
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Launch frontend
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
echo "[5/8] launching frontend on port ${FRONTEND_PORT}..."
|
||||
|
||||
@@ -403,7 +388,6 @@ fi
|
||||
|
||||
echo " frontend pid=${frontend_pid} log=${frontend_log}"
|
||||
|
||||
# Poll FE root
|
||||
echo "[6/8] polling http://127.0.0.1:${FRONTEND_PORT}/ ..."
|
||||
fe_ready=0
|
||||
for i in $(seq 1 30); do
|
||||
@@ -428,9 +412,6 @@ fi
|
||||
|
||||
echo "[7/8] frontend / OK"
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Print summary
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
cwd="$(readlink "/proc/${backend_pid}/cwd" 2>/dev/null || echo unknown)"
|
||||
gpu_mem_now="$(nvidia-smi --query-gpu=memory.used --format=csv,noheader,nounits 2>/dev/null | sed -n "$((GPU + 1))p" || echo 0)"
|
||||
|
||||
@@ -43,7 +43,6 @@ if ! python3 -m modal --version &> /dev/null; then
|
||||
# --break-system-packages preserves prior `pip install --user` semantics on PEP 668 agents.
|
||||
uv pip install --system --break-system-packages modal
|
||||
|
||||
# Verify installation
|
||||
if ! python3 -m modal --version &> /dev/null; then
|
||||
log "Error: Failed to install modal. Please install it manually."
|
||||
exit 1
|
||||
@@ -52,7 +51,6 @@ fi
|
||||
|
||||
log "modal version: $(python3 -m modal --version)"
|
||||
|
||||
# Set up Modal authentication using Buildkite secrets
|
||||
log "Setting up Modal authentication from Buildkite secrets..."
|
||||
MODAL_TOKEN_ID=$(buildkite-agent secret get modal_token_id)
|
||||
MODAL_TOKEN_SECRET=$(buildkite-agent secret get modal_token_secret)
|
||||
|
||||
@@ -33,9 +33,7 @@ merge_protections:
|
||||
|
||||
pull_request_rules:
|
||||
|
||||
# ============================================================
|
||||
# Type labels (from PR title prefix)
|
||||
# ============================================================
|
||||
|
||||
- name: "label type: feat"
|
||||
conditions:
|
||||
@@ -117,9 +115,7 @@ pull_request_rules:
|
||||
label:
|
||||
add: ["type: skill"]
|
||||
|
||||
# ============================================================
|
||||
# Scope labels (from changed files)
|
||||
# ============================================================
|
||||
|
||||
- name: "label scope: training"
|
||||
conditions:
|
||||
@@ -227,9 +223,7 @@ pull_request_rules:
|
||||
label:
|
||||
add: ["scope: model"]
|
||||
|
||||
# ============================================================
|
||||
# Merge conflict detection
|
||||
# ============================================================
|
||||
|
||||
- name: label conflicting PRs
|
||||
conditions:
|
||||
@@ -249,9 +243,7 @@ pull_request_rules:
|
||||
label:
|
||||
remove: [needs-rebase]
|
||||
|
||||
# ============================================================
|
||||
# Auto-merge
|
||||
# ============================================================
|
||||
|
||||
- name: auto-merge when ready and all checks pass
|
||||
conditions:
|
||||
|
||||
@@ -24,7 +24,7 @@ repos:
|
||||
require_serial: true
|
||||
args: [--in-place, --verbose]
|
||||
language_version: python3.12
|
||||
additional_dependencies: [toml] # TODO: Remove when yapf is upgraded
|
||||
additional_dependencies: [toml]
|
||||
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||
rev: v0.11.12
|
||||
hooks:
|
||||
@@ -36,10 +36,6 @@ repos:
|
||||
- id: codespell
|
||||
additional_dependencies: ['tomli']
|
||||
args: ['--toml', 'pyproject.toml']
|
||||
# - repo: https://github.com/PyCQA/isort
|
||||
# rev: 6.0.1
|
||||
# hooks:
|
||||
# - id: isort
|
||||
- repo: https://github.com/jackdewinter/pymarkdown
|
||||
rev: v0.9.30
|
||||
hooks:
|
||||
|
||||
@@ -307,7 +307,7 @@ def gpu_worker_process(
|
||||
message=str(e),
|
||||
))
|
||||
|
||||
return True # Continue loop
|
||||
return True
|
||||
|
||||
if first_cmd is not None:
|
||||
if first_cmd.type == CommandType.SHUTDOWN:
|
||||
|
||||
@@ -1704,7 +1704,6 @@ class SessionController:
|
||||
and slot.shared_stream_buffer is not None):
|
||||
start = chunk_offset
|
||||
end = start + chunk_length
|
||||
# Copy out of shared buffer for websocket send.
|
||||
chunk = bytes(slot.shared_stream_buffer[start:end])
|
||||
else:
|
||||
chunk = chunk_bytes or b""
|
||||
|
||||
@@ -49,7 +49,6 @@
|
||||
# toolchain.
|
||||
set -euo pipefail
|
||||
|
||||
# ─── Defaults (override via env) ──────────────────────────────────────────
|
||||
INSTALL_PREFIX="${INSTALL_PREFIX:-$HOME/opt/ffmpeg-native}"
|
||||
SOURCE_DIR="${SOURCE_DIR:-$HOME/src/ffmpeg-native}"
|
||||
X264_REF="${X264_REF:-stable}"
|
||||
@@ -137,7 +136,6 @@ export CC CXX
|
||||
[[ -n "${AS:-}" ]] && export AS
|
||||
echo "[install_native_ffmpeg] toolchain: CC=$CC CXX=$CXX AS=${AS:-<gnu-as>} (uname -m=$ARCH, source: $toolchain_source)"
|
||||
|
||||
# ─── Step 0: probe required tools ─────────────────────────────────────────
|
||||
required=("$CC" "$CXX" make pkg-config git)
|
||||
[[ "$(uname -m)" == "x86_64" ]] && required+=(nasm)
|
||||
missing=()
|
||||
@@ -155,7 +153,6 @@ if (( ${#missing[@]} > 0 )); then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# ─── Step 0.5: destructive-path guards ────────────────────────────────────
|
||||
guard_path() {
|
||||
local name="$1" value="$2"
|
||||
case "$value" in
|
||||
@@ -172,7 +169,6 @@ guard_path() {
|
||||
guard_path INSTALL_PREFIX "$INSTALL_PREFIX"
|
||||
guard_path SOURCE_DIR "$SOURCE_DIR"
|
||||
|
||||
# ─── Step 1: clean ────────────────────────────────────────────────────────
|
||||
echo "[install_native_ffmpeg] cleaning prior install + sources"
|
||||
rm -rf "$INSTALL_PREFIX" "$SOURCE_DIR/x264" "$SOURCE_DIR/ffmpeg" "$SOURCE_DIR/nv-codec-headers"
|
||||
mkdir -p "$SOURCE_DIR" "$INSTALL_PREFIX/lib"
|
||||
@@ -271,7 +267,6 @@ git clone --depth 1 --branch "$FFMPEG_REF" \
|
||||
make install
|
||||
)
|
||||
|
||||
# ─── Step 4: sanity check ──────────────────────────────────────────────────
|
||||
ffmpeg_bin="$INSTALL_PREFIX/bin/ffmpeg"
|
||||
echo "[install_native_ffmpeg] verifying $ffmpeg_bin"
|
||||
"$ffmpeg_bin" -hide_banner -buildconf | grep -i -E 'libx264|lto'
|
||||
|
||||
@@ -96,7 +96,6 @@ wait_for() {
|
||||
return 1
|
||||
}
|
||||
|
||||
# --- backend ---
|
||||
echo "[launch-demo] backend logs: ${BE_LOG}"
|
||||
( "${BE_SCRIPT}" "${BE_PORT_ARGS[@]}" >"${BE_LOG}" 2>&1 ) &
|
||||
BE_PID=$!
|
||||
@@ -117,7 +116,6 @@ if [[ "${HEALTH_PATH}" != "${READY_PATH}" ]]; then
|
||||
fi
|
||||
fi
|
||||
|
||||
# --- frontend ---
|
||||
if [[ "${NO_FRONTEND:-0}" != "1" ]]; then
|
||||
echo "[launch-demo] frontend logs: ${FE_LOG}"
|
||||
( "${SCRIPT_DIR}/launch_frontend.sh" >"${FE_LOG}" 2>&1 ) &
|
||||
|
||||
@@ -110,7 +110,6 @@
|
||||
--radius-xl: calc(var(--radius) + 4px);
|
||||
}
|
||||
|
||||
/* ——— Resets ——— */
|
||||
|
||||
*,
|
||||
*::before,
|
||||
@@ -194,7 +193,6 @@ summary::-webkit-details-marker {
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
/* ——— Base layer ——— */
|
||||
|
||||
@layer base {
|
||||
* {
|
||||
@@ -205,7 +203,6 @@ summary::-webkit-details-marker {
|
||||
}
|
||||
}
|
||||
|
||||
/* ——— Utilities ——— */
|
||||
|
||||
@layer utilities {
|
||||
.scrollbar-hidden {
|
||||
@@ -269,7 +266,6 @@ summary::-webkit-details-marker {
|
||||
animation: stt-pulse 1.4s ease-in-out infinite;
|
||||
}
|
||||
|
||||
/* ——— Theme transition ——— */
|
||||
|
||||
html.theme-transition,
|
||||
html.theme-transition *,
|
||||
@@ -284,7 +280,6 @@ html.theme-transition *::after {
|
||||
stroke 300ms ease !important;
|
||||
}
|
||||
|
||||
/* —————————————— CUSTOM TAILWIND —————————————— */
|
||||
|
||||
@layer components {
|
||||
.debug {
|
||||
|
||||
@@ -2853,7 +2853,6 @@ export default function Page() {
|
||||
onSelectCurrent={() => {
|
||||
const clips = completedClips as any[];
|
||||
if (sessionStarted && !sessionExpired) {
|
||||
// Return to live playback
|
||||
streamStore.patch({ activeClipId: "", activePlaybackStartTime: 0 });
|
||||
} else if (clips.length > 0) {
|
||||
selectClip(clips[clips.length - 1].id, 0);
|
||||
|
||||
@@ -219,15 +219,12 @@ describe('createAvPipeline', () => {
|
||||
updating = false;
|
||||
|
||||
addEventListener(): void {
|
||||
// noop for test
|
||||
}
|
||||
|
||||
removeEventListener(): void {
|
||||
// noop for test
|
||||
}
|
||||
|
||||
appendBuffer(): void {
|
||||
// noop for test
|
||||
}
|
||||
}
|
||||
|
||||
@@ -335,11 +332,9 @@ describe('createAvPipeline', () => {
|
||||
appendBuffer = vi.fn();
|
||||
|
||||
addEventListener(): void {
|
||||
// noop for test
|
||||
}
|
||||
|
||||
removeEventListener(): void {
|
||||
// noop for test
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -270,7 +270,6 @@ export function createAvPipeline({
|
||||
return;
|
||||
}
|
||||
stallRecoveryTimerId = setInterval(() => {
|
||||
// Stop polling once playback is running normally.
|
||||
if (initialPlaybackStarted && !playbackResumePending) {
|
||||
clearStallRecovery();
|
||||
return;
|
||||
|
||||
@@ -10,7 +10,6 @@ test.describe('datasets', () => {
|
||||
skipWithoutMock();
|
||||
|
||||
test('lists the seeded datasets', async ({ page, request }) => {
|
||||
// Read the seeded names from the mock so the assertion tracks the fixture.
|
||||
const res = await request.get(`${API_BASE}/datasets`);
|
||||
const datasets = (await res.json()) as Array<{ name: string }>;
|
||||
expect(datasets.length).toBeGreaterThan(0);
|
||||
|
||||
@@ -711,8 +711,8 @@ class JobRunner:
|
||||
job.finished_at = None
|
||||
job._stop_event.clear()
|
||||
job._log_buf = JobLogBuffer() # fresh log buffer
|
||||
job.log_file_handler = None # Reset file handler
|
||||
job._process = None # Reset subprocess handle
|
||||
job.log_file_handler = None
|
||||
job._process = None
|
||||
|
||||
# Wrap _run_job in an additional safety layer to catch any exceptions
|
||||
# that might escape (though they shouldn't with our comprehensive handling)
|
||||
|
||||
@@ -120,7 +120,6 @@
|
||||
--radius-xl: calc(var(--radius) + 4px);
|
||||
}
|
||||
|
||||
/* ——— Resets ——— */
|
||||
|
||||
html,
|
||||
body {
|
||||
@@ -211,7 +210,6 @@ html.theme-transition *::after {
|
||||
stroke 300ms ease !important;
|
||||
}
|
||||
|
||||
/* ——— Base layer ——— */
|
||||
|
||||
@layer base {
|
||||
button,
|
||||
|
||||
@@ -54,15 +54,12 @@ describe('DatasetSidebar', () => {
|
||||
it('lists dataset files after loading', async () => {
|
||||
render(<DatasetSidebar dataset={dataset} onClose={() => {}} />);
|
||||
|
||||
// The first file's caption is rendered once loading resolves.
|
||||
expect(await screen.findByDisplayValue('cap a')).toBeInTheDocument();
|
||||
expect(mockedApi.getDatasetFiles).toHaveBeenCalledWith('ds-1');
|
||||
|
||||
// One caption editor per returned file.
|
||||
const captionFields = screen.getAllByPlaceholderText('Caption');
|
||||
expect(captionFields).toHaveLength(2);
|
||||
|
||||
// Media URLs are requested per visible file.
|
||||
expect(mockedApi.getDatasetMediaUrl).toHaveBeenCalledWith('ds-1', 'a.mp4');
|
||||
expect(mockedApi.getDatasetMediaUrl).toHaveBeenCalledWith('ds-1', 'b.mp4');
|
||||
});
|
||||
|
||||
@@ -23,7 +23,6 @@ const MODELS = [
|
||||
];
|
||||
|
||||
beforeEach(() => {
|
||||
// Reset the shared options store to a known baseline for test isolation.
|
||||
defaultOptionsStore.set({ options: DEFAULT_OPTIONS });
|
||||
vi.mocked(getModels).mockResolvedValue(MODELS);
|
||||
vi.mocked(getDatasets).mockResolvedValue([]);
|
||||
|
||||
@@ -302,7 +302,6 @@ export default function CreateJobModal({
|
||||
}
|
||||
}, [isOpen, workloadType, inferenceWorkload, options, editingJobId]);
|
||||
|
||||
// Load the models available for this workload.
|
||||
React.useEffect(() => {
|
||||
if (!isOpen) return;
|
||||
// Ignore a superseded response so a slow fetch for a previous workload
|
||||
|
||||
@@ -81,7 +81,6 @@ describe('JobDetailsSidebar', () => {
|
||||
/>,
|
||||
);
|
||||
|
||||
// Flush the immediate poll fired on mount.
|
||||
await act(async () => {
|
||||
await vi.advanceTimersByTimeAsync(0);
|
||||
});
|
||||
|
||||
@@ -101,12 +101,10 @@ export default function JobQueue({ jobType, jobTypesForList }: JobQueueProps) {
|
||||
fetchJobsRef.current = fetchJobs;
|
||||
}, [fetchJobs]);
|
||||
|
||||
// Initial fetch + refetch whenever an external refresh is triggered.
|
||||
React.useEffect(() => {
|
||||
fetchJobs();
|
||||
}, [fetchJobs, nonce]);
|
||||
|
||||
// Poll every second while any job is running/pending; stop otherwise.
|
||||
const hasActive = jobs.some(
|
||||
(j) => j.status === 'running' || j.status === 'pending',
|
||||
);
|
||||
|
||||
@@ -68,7 +68,6 @@ function drawAutoAnnotated(ctx, node, widget_width, y, H) {
|
||||
ctx.fillStyle = litegraph_base.WIDGET_BGCOLOR;
|
||||
ctx.fill();
|
||||
|
||||
// Reset fill style for the teeth
|
||||
if (isAuto) {
|
||||
ctx.fillStyle = litegraph_base.WIDGET_TEXT_COLOR;
|
||||
} else {
|
||||
@@ -200,7 +199,6 @@ function mouseAutoAnnotated(event, [x, y], node) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Handle increment/decrement buttons if not in auto mode
|
||||
if (delta !== 0 && !this.isAuto) {
|
||||
if (this.config[0] === "FVAUTOCOMBO") {
|
||||
const options = this.options.values || [];
|
||||
@@ -241,7 +239,6 @@ function mouseAutoAnnotated(event, [x, y], node) {
|
||||
|
||||
v += increment;
|
||||
|
||||
// Apply min/max constraints
|
||||
if (this.options.min != null) {
|
||||
v = Math.max(this.options.min, v);
|
||||
}
|
||||
@@ -272,7 +269,6 @@ function mouseAutoAnnotated(event, [x, y], node) {
|
||||
if (this.config[0] === "FVAUTOCOMBO") {
|
||||
const options = this.options.values || [];
|
||||
|
||||
// Create menu items
|
||||
const menuItems = options.map(opt => {
|
||||
const value = typeof opt === 'object' ? opt.value : opt;
|
||||
const label = typeof opt === 'object' ? opt.label : opt.toString();
|
||||
@@ -323,7 +319,6 @@ function mouseAutoAnnotated(event, [x, y], node) {
|
||||
const d_callback = (v) => {
|
||||
this.value = this.parseValue?.(v) ?? Number(v);
|
||||
|
||||
// Apply min/max constraints
|
||||
if (this.options.min != null) {
|
||||
this.value = Math.max(this.options.min, this.value);
|
||||
}
|
||||
@@ -370,7 +365,6 @@ function makeAutoAnnotated(widget, inputData) {
|
||||
value: widget.value
|
||||
};
|
||||
|
||||
// Add AUTO properties to the widget
|
||||
Object.assign(widget, {
|
||||
type: "BOOLEAN",
|
||||
draw: drawAutoAnnotated,
|
||||
@@ -381,7 +375,7 @@ function makeAutoAnnotated(widget, inputData) {
|
||||
cachedValue: widget.value,
|
||||
config: inputData,
|
||||
options: Object.assign({}, inputData[1], widget.options),
|
||||
original: original, // Store original properties for reference
|
||||
original: original,
|
||||
|
||||
// Disable other potential mouse handlers with no-op functions
|
||||
onClick: function () {
|
||||
@@ -429,7 +423,6 @@ function makeAutoAnnotated(widget, inputData) {
|
||||
return v;
|
||||
},
|
||||
serializeValue: function () {
|
||||
// Return special value for AUTO mode
|
||||
return this.isAuto ? -99999 : this.value;
|
||||
},
|
||||
deserializeValue: function (data) {
|
||||
@@ -473,28 +466,22 @@ app.registerExtension({
|
||||
async beforeRegisterNodeDef(nodeType, nodeData, app) {
|
||||
if (nodeData?.name == "VideoGenerator" || nodeData?.name === "InferenceArgs" || nodeData?.name === "VAEConfig" ||
|
||||
nodeData?.name === "TextEncoderConfig" || nodeData?.name === "DITConfig") {
|
||||
// Add serialization support
|
||||
chainCallback(nodeType.prototype, "onSerialize", function (info) {
|
||||
if (!this.widgets) {
|
||||
return;
|
||||
}
|
||||
// Ensure widgets_values exists
|
||||
if (!info.widgets_values) {
|
||||
info.widgets_values = {};
|
||||
}
|
||||
|
||||
// Store AUTO widget states in a separate property
|
||||
if (!info.auto_widget_states) {
|
||||
info.auto_widget_states = {};
|
||||
}
|
||||
|
||||
// Handle AUTO widgets specially
|
||||
for (const w of this.widgets) {
|
||||
if (w.type === "BOOLEAN" && w.isAuto !== undefined) {
|
||||
// Store the serialized value (for Python node)
|
||||
info.widgets_values[w.name] = w.serializeValue();
|
||||
|
||||
// Store the full state (for UI restoration)
|
||||
info.auto_widget_states[w.name] = {
|
||||
isAuto: w.isAuto,
|
||||
value: w.value,
|
||||
@@ -504,7 +491,6 @@ app.registerExtension({
|
||||
}
|
||||
});
|
||||
|
||||
// Add deserialization support
|
||||
chainCallback(nodeType.prototype, "onConfigure", function (info) {
|
||||
if (!this.widgets) {
|
||||
return;
|
||||
@@ -522,7 +508,6 @@ app.registerExtension({
|
||||
}
|
||||
}
|
||||
|
||||
// Then, restore full state if available
|
||||
if (info.auto_widget_states) {
|
||||
for (const w of this.widgets) {
|
||||
if (w.type === "BOOLEAN" && w.isAuto !== undefined && w.name in info.auto_widget_states) {
|
||||
@@ -544,7 +529,6 @@ app.registerExtension({
|
||||
|
||||
// Override addInput to handle AUTO widgets
|
||||
chainCallback(nodeType.prototype, "onNodeCreated", function () {
|
||||
// Convert any existing widgets to AUTO widgets if needed
|
||||
let new_widgets = [];
|
||||
const intWidgetNames = ["sp_size", "tp_size", "height", "width", "num_frames", "num_inference_steps", "flow_shift", "seed", "fps", "scale_factor",
|
||||
"tile_sample_min_height", "tile_sample_min_width", "tile_sample_min_num_frames", "tile_sample_stride_height", "tile_sample_stride_width",
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
# TODO(cookbook-review): Design sample only. Before merge, double-check the
|
||||
# selected options, schema types/ranges, and baseline values for each deployment.
|
||||
# TODO: Recheck field paths and choices when the typed API in PR #1913 is finalized.
|
||||
title: FastWan2.1 1.3B
|
||||
summary: Distilled text-to-video serving with sparse attention.
|
||||
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
# TODO(cookbook-review): Design sample only. Before merge, double-check the
|
||||
# selected options, schema types/ranges, and baseline values for each deployment.
|
||||
# TODO: Recheck field paths and choices when the typed API in PR #1913 is finalized.
|
||||
title: Wan2.1 I2V 14B
|
||||
summary: Image-conditioned video generation from a source frame.
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ ROOT_DIR = Path(__file__).parent.parent.resolve()
|
||||
ROOT_DIR_RELATIVE = '../..'
|
||||
EXAMPLE_DIR = ROOT_DIR / "examples"
|
||||
EXAMPLE_DOC_DIR = ROOT_DIR / "docs/getting_started/examples"
|
||||
GITHUB_REPO = "hao-ai-lab/FastVideo" # Update this to your repo
|
||||
GITHUB_REPO = "hao-ai-lab/FastVideo"
|
||||
COOKBOOK_DATA = ROOT_DIR / "docs/assets/cookbook-recipes.json"
|
||||
COOKBOOK_CLIENTS = {
|
||||
"python": ("video.py", "python -m pip install openai==3.6.0"),
|
||||
@@ -364,11 +364,8 @@ class Index:
|
||||
content = f"# {self.title}\n\n{self.description}\n\n"
|
||||
if self.caption:
|
||||
content += f"## {self.caption}\n\n"
|
||||
# Generate a simple list of documentation links
|
||||
for doc in self.documents:
|
||||
# Convert document path to proper link
|
||||
doc_link = doc.replace("\\", "/")
|
||||
# Get just the filename for the link text
|
||||
doc_title = fix_case(Path(doc).stem.replace("_", " ").title())
|
||||
content += f"- [{doc_title}]({doc_link}.md)\n"
|
||||
content += "\n"
|
||||
@@ -459,12 +456,10 @@ class Example:
|
||||
return fix_case(self.path.stem.replace("_", " ").title())
|
||||
|
||||
def generate(self) -> str:
|
||||
# Create GitHub link to source
|
||||
github_path = str(self.path.relative_to(ROOT_DIR)).replace("\\", "/")
|
||||
github_url = f"https://github.com/{GITHUB_REPO}/blob/main/{github_path}"
|
||||
content = f"**Source:** [{github_path}]({github_url})\n\n"
|
||||
|
||||
# Add title for code files
|
||||
if self.main_file.suffix != ".md":
|
||||
content += f"# {self.title}\n\n"
|
||||
|
||||
@@ -484,19 +479,16 @@ class Example:
|
||||
return content
|
||||
|
||||
content += "## Additional Files\n\n"
|
||||
# Define binary/non-text file extensions to skip
|
||||
binary_extensions = {
|
||||
'.mp4', '.avi', '.mov', '.mkv', '.gif', '.jpg', '.jpeg', '.png', '.webp', '.bmp', '.pdf', '.zip', '.tar',
|
||||
'.gz', '.mp3', '.wav'
|
||||
}
|
||||
|
||||
for file in sorted(self.other_files):
|
||||
# Skip binary files
|
||||
if file.suffix.lower() in binary_extensions:
|
||||
continue
|
||||
|
||||
file_rel_path = file.relative_to(self.path)
|
||||
# Use collapsible admonitions, normalized by the site preparation
|
||||
content += f"??? note \"{file_rel_path}\"\n\n"
|
||||
|
||||
try:
|
||||
@@ -517,7 +509,6 @@ class Example:
|
||||
content += " ```\n"
|
||||
content += "\n"
|
||||
except UnicodeDecodeError:
|
||||
# Skip files that can't be decoded as UTF-8
|
||||
continue
|
||||
|
||||
return content
|
||||
@@ -580,7 +571,6 @@ def create_category_indices() -> dict[str, Index]:
|
||||
),
|
||||
}
|
||||
|
||||
# Ensure all category doc directories exist
|
||||
for index in category_indices.values():
|
||||
if not index.path.parent.exists():
|
||||
index.path.parent.mkdir(parents=True)
|
||||
@@ -604,7 +594,6 @@ def find_examples(category_indices: dict[str, Index], generate_main_index: bool)
|
||||
dir_name = category_dir_mapping.get(category, category)
|
||||
category_dir = EXAMPLE_DIR / dir_name
|
||||
|
||||
# Skip if directory doesn't exist
|
||||
if not category_dir.exists():
|
||||
continue
|
||||
|
||||
@@ -622,7 +611,6 @@ def find_examples(category_indices: dict[str, Index], generate_main_index: bool)
|
||||
examples.append(Example(path))
|
||||
# Find examples in subdirectories
|
||||
for path in EXAMPLE_DIR.glob("*/*.md"):
|
||||
# Skip categorised examples
|
||||
if path.parent.name in category_indices:
|
||||
continue
|
||||
examples.append(Example(path.parent))
|
||||
@@ -643,7 +631,6 @@ def create_nested_structures(examples: list[Example]) -> dict[str, dict[str, dic
|
||||
if example.category not in ["training", "distillation"]:
|
||||
continue
|
||||
|
||||
# Use mapped directory name if available
|
||||
dir_name = category_dir_mapping.get(example.category, example.category)
|
||||
category_dir = EXAMPLE_DIR / dir_name
|
||||
relative_path = example.path.relative_to(category_dir)
|
||||
@@ -656,7 +643,6 @@ def create_nested_structures(examples: list[Example]) -> dict[str, dict[str, dic
|
||||
model = path_parts[1] # e.g., "wan_i2v_14b_480p"
|
||||
dataset = path_parts[2] # e.g., "crush_smol"
|
||||
|
||||
# Initialize nested structure
|
||||
if example.category not in nested_structures:
|
||||
nested_structures[example.category] = {}
|
||||
if method not in nested_structures[example.category]:
|
||||
@@ -664,7 +650,6 @@ def create_nested_structures(examples: list[Example]) -> dict[str, dict[str, dic
|
||||
if model not in nested_structures[example.category][method]:
|
||||
nested_structures[example.category][method][model] = {}
|
||||
|
||||
# Store the nested structure
|
||||
nested_structures[example.category][method][model][dataset] = NestedStructure(category=example.category,
|
||||
method=method,
|
||||
model=model,
|
||||
@@ -677,7 +662,6 @@ def create_nested_structures(examples: list[Example]) -> dict[str, dict[str, dic
|
||||
dataset = path_parts[1] # e.g., "Wan-Syn-Data-480P"
|
||||
method = "DMD" # Default method for distillation
|
||||
|
||||
# Initialize nested structure
|
||||
if example.category not in nested_structures:
|
||||
nested_structures[example.category] = {}
|
||||
if method not in nested_structures[example.category]:
|
||||
@@ -685,7 +669,6 @@ def create_nested_structures(examples: list[Example]) -> dict[str, dict[str, dic
|
||||
if model not in nested_structures[example.category][method]:
|
||||
nested_structures[example.category][method][model] = {}
|
||||
|
||||
# Store the nested structure
|
||||
nested_structures[example.category][method][model][dataset] = NestedStructure(category=example.category,
|
||||
method=method,
|
||||
model=model,
|
||||
@@ -700,7 +683,7 @@ def generate_flat_examples(examples: list[Example], category_indices: dict[str,
|
||||
"""Generate documentation for flat structure examples (inference, etc.)."""
|
||||
for example in examples:
|
||||
if example.category in ["training", "distillation"]:
|
||||
continue # Skip nested structure examples
|
||||
continue
|
||||
|
||||
# Determine which index to use for this example
|
||||
if example.category is not None and example.category in category_indices:
|
||||
@@ -711,7 +694,6 @@ def generate_flat_examples(examples: list[Example], category_indices: dict[str,
|
||||
else:
|
||||
continue
|
||||
|
||||
# Generate the example documentation
|
||||
doc_path = index.path.parent / f"{example.path.stem}.md"
|
||||
with open(doc_path, "w+", encoding="utf-8") as f:
|
||||
f.write(example.generate())
|
||||
@@ -729,7 +711,6 @@ def generate_nested_examples(nested_structures: dict[str, dict[str, dict[str, di
|
||||
category_base_dir = category_index.path.parent
|
||||
|
||||
for method, models in nested_structures[category_name].items():
|
||||
# Create method-level index
|
||||
method_index = Index(path=category_base_dir / f"{method}.md",
|
||||
title=fix_case(method),
|
||||
description=f"Examples using {method}.",
|
||||
@@ -737,35 +718,28 @@ def generate_nested_examples(nested_structures: dict[str, dict[str, dict[str, di
|
||||
maxdepth=2)
|
||||
|
||||
for model, datasets in models.items():
|
||||
# Generate dataset examples using the Example class
|
||||
for dataset, nested_struct in datasets.items():
|
||||
doc_path = category_base_dir / f"{nested_struct.filename}.md"
|
||||
with open(doc_path, "w+", encoding="utf-8") as f:
|
||||
f.write(nested_struct.example.generate())
|
||||
|
||||
# Create model-level index
|
||||
model_index = Index(path=category_base_dir / f"{model}.md",
|
||||
title=fix_case(model.replace('_', ' ')),
|
||||
description=f"Examples for the {model} model.",
|
||||
caption=f"{fix_case(model.replace('_', ' '))} Datasets",
|
||||
maxdepth=1)
|
||||
|
||||
# Add dataset indices to model index
|
||||
for dataset, nested_struct in datasets.items():
|
||||
model_index.documents.append(nested_struct.filename)
|
||||
|
||||
# Write model index
|
||||
with open(model_index.path, "w+", encoding="utf-8") as f:
|
||||
f.write(model_index.generate())
|
||||
|
||||
# Add model to method index
|
||||
method_index.documents.append(model)
|
||||
|
||||
# Write method index
|
||||
with open(method_index.path, "w+", encoding="utf-8") as f:
|
||||
f.write(method_index.generate())
|
||||
|
||||
# Add method to main category index
|
||||
category_index.documents.append(method)
|
||||
|
||||
|
||||
@@ -777,7 +751,6 @@ def generate_examples(generate_main_index: bool = False) -> None:
|
||||
generate_main_index (bool): Whether to generate the main examples index.
|
||||
If False, only category-specific indices will be generated.
|
||||
"""
|
||||
# Create category indices
|
||||
category_indices = create_category_indices()
|
||||
|
||||
# Create the main examples index only if requested
|
||||
@@ -796,29 +769,22 @@ def generate_examples(generate_main_index: bool = False) -> None:
|
||||
# Find all examples
|
||||
examples = find_examples(category_indices, generate_main_index)
|
||||
|
||||
# Create nested structures for training and distillation
|
||||
nested_structures = create_nested_structures(examples)
|
||||
|
||||
# Generate flat structure examples (inference, etc.)
|
||||
generate_flat_examples(examples, category_indices, examples_index, generate_main_index)
|
||||
|
||||
# Generate nested structure examples (training, distillation)
|
||||
generate_nested_examples(nested_structures, category_indices)
|
||||
|
||||
# Generate the index files for categories
|
||||
for category_index in category_indices.values():
|
||||
if category_index.documents:
|
||||
# Add to main index if it exists
|
||||
if generate_main_index and examples_index:
|
||||
main_index_dir = examples_index.path.parent
|
||||
rel_path = os.path.relpath(category_index.path, start=main_index_dir)
|
||||
examples_index.documents.insert(0, str(rel_path).replace("\\", "/").replace(".md", ""))
|
||||
|
||||
# Write the category index file
|
||||
with open(category_index.path, "w+", encoding="utf-8") as f:
|
||||
f.write(category_index.generate())
|
||||
|
||||
# Write the main index file if requested
|
||||
if generate_main_index and examples_index:
|
||||
with open(examples_index.path, "w+", encoding="utf-8") as f:
|
||||
f.write(examples_index.generate())
|
||||
|
||||
@@ -7,7 +7,6 @@ export TOKENIZERS_PARALLELISM=false
|
||||
RUN_NAME=$(date +"%m%d_%H%M")
|
||||
echo "RUN_NAME: $RUN_NAME"
|
||||
|
||||
# Model paths for Self-Forcing DMD distillation.
|
||||
GENERATOR_MODEL_PATH="FastVideo/Matrix-Game-2.0-Base-Distilled-Diffusers"
|
||||
REAL_SCORE_MODEL_PATH="FastVideo/Matrix-Game-2.0-Base-Diffusers" # Teacher
|
||||
FAKE_SCORE_MODEL_PATH="FastVideo/Matrix-Game-2.0-Base-Diffusers" # Critic
|
||||
@@ -16,7 +15,6 @@ DATA_DIR="data/matrixgame2"
|
||||
VALIDATION_DATASET_FILE="examples/distill/MatrixGame2.0/validation.json"
|
||||
NUM_GPUS=1
|
||||
|
||||
# Training arguments
|
||||
training_args=(
|
||||
--tracker_project_name "matrixgame2_sf"
|
||||
--output_dir "checkpoints/matrixgame2_sf_${RUN_NAME}"
|
||||
@@ -32,12 +30,8 @@ training_args=(
|
||||
--simulate_generator_forward
|
||||
--num_frames 81
|
||||
--num_frame_per_block 3 # Frame generation block size for self-forcing
|
||||
# --enable_gradient_masking
|
||||
# --gradient_mask_last_n_frames 21
|
||||
# --init_weights_from_safetensors "path/to/generator_ema.safetensors"
|
||||
)
|
||||
|
||||
# Parallel arguments
|
||||
parallel_args=(
|
||||
--num_gpus $NUM_GPUS
|
||||
--sp_size 1
|
||||
@@ -47,7 +41,7 @@ parallel_args=(
|
||||
)
|
||||
|
||||
model_args=(
|
||||
--model_path $GENERATOR_MODEL_PATH # TODO: check if you can remove this in this script
|
||||
--model_path $GENERATOR_MODEL_PATH
|
||||
--pretrained_model_name_or_path $GENERATOR_MODEL_PATH
|
||||
--real_score_model_path $REAL_SCORE_MODEL_PATH
|
||||
--fake_score_model_path $FAKE_SCORE_MODEL_PATH
|
||||
@@ -58,7 +52,6 @@ dataset_args=(
|
||||
--dataloader_num_workers 4
|
||||
)
|
||||
|
||||
# Validation arguments
|
||||
validation_args=(
|
||||
--log_validation
|
||||
--log_visualization
|
||||
@@ -69,7 +62,6 @@ validation_args=(
|
||||
--validation_guidance_scale "6.0"
|
||||
)
|
||||
|
||||
# Optimizer arguments
|
||||
optimizer_args=(
|
||||
--learning_rate 3e-6
|
||||
--mixed_precision "bf16"
|
||||
@@ -80,7 +72,6 @@ optimizer_args=(
|
||||
--max_grad_norm 1.0
|
||||
)
|
||||
|
||||
# Miscellaneous arguments
|
||||
miscellaneous_args=(
|
||||
--inference_mode False
|
||||
--checkpoints_total_limit 3
|
||||
|
||||
@@ -77,7 +77,6 @@ training_args=(
|
||||
--simulate_generator_forward
|
||||
--num_frames 81
|
||||
--num_frame_per_block 3
|
||||
# --init_weights_from_safetensors "path/to/generator_ema.safetensors"
|
||||
)
|
||||
|
||||
parallel_args=(
|
||||
|
||||
@@ -33,8 +33,6 @@ FAKE_SCORE_MODEL_PATH="Wan-AI/Wan2.1-T2V-1.3B-Diffusers" # Critic model
|
||||
|
||||
DATA_DIR=your_data_dir
|
||||
VALIDATION_DATASET_FILE=your_validation_data_dir
|
||||
# export CUDA_VISIBLE_DEVICES=4,5
|
||||
# IP=[MASTER NODE IP]
|
||||
|
||||
training_args=(
|
||||
--tracker_project_name SFwan_t2v_distill_self_forcing_dmd
|
||||
@@ -64,7 +62,7 @@ parallel_args=(
|
||||
)
|
||||
|
||||
model_args=(
|
||||
--model_path $GENERATOR_MODEL_PATH # TODO: check if you can remove this in this script
|
||||
--model_path $GENERATOR_MODEL_PATH
|
||||
--pretrained_model_name_or_path $GENERATOR_MODEL_PATH
|
||||
--real_score_model_path $REAL_SCORE_MODEL_PATH
|
||||
--fake_score_model_path $FAKE_SCORE_MODEL_PATH
|
||||
|
||||
@@ -23,7 +23,6 @@ nodes=( $(scontrol show hostnames $SLURM_JOB_NODELIST) )
|
||||
export MASTER_ADDR=${nodes[0]}
|
||||
export TOKENIZERS_PARALLELISM=false
|
||||
export WANDB_API_KEY=YOUR_WANDB_API_KEY
|
||||
# export WANDB_API_KEY='your_wandb_api_key_here'
|
||||
export WANDB_BASE_URL="https://api.wandb.ai"
|
||||
export WANDB_MODE=online
|
||||
export FASTVIDEO_ATTENTION_BACKEND=FLASH_ATTN
|
||||
@@ -31,23 +30,13 @@ export FASTVIDEO_ATTENTION_BACKEND=FLASH_ATTN
|
||||
# Configs
|
||||
NUM_GPUS=8
|
||||
|
||||
# Model paths for Self-Forcing DMD distillation with Wan2.2:
|
||||
# GENERATOR_MODEL_PATH="Wan-AI/Wan2.2-T2V-A14B-Diffusers" # Updated to Wan2.2
|
||||
# REAL_SCORE_MODEL_PATH="Wan-AI/Wan2.2-T2V-A14B-Diffusers" # Teacher model
|
||||
# FAKE_SCORE_MODEL_PATH="Wan-AI/Wan2.2-T2V-A14B-Diffusers" # Critic model
|
||||
GENERATOR_MODEL_PATH="Wan-AI/Wan2.1-T2V-1.3B-Diffusers" # Updated to Wan2.2
|
||||
REAL_SCORE_MODEL_PATH="Wan-AI/Wan2.1-T2V-1.3B-Diffusers" # Teacher model
|
||||
FAKE_SCORE_MODEL_PATH="Wan-AI/Wan2.1-T2V-1.3B-Diffusers" # Critic model
|
||||
|
||||
# DATA_DIR="data/test-text-preprocessing/Node_0_GPU_1_File_1/combined_parquet_dataset/"
|
||||
DATA_DIR="/mnt/weka/home/hao.zhang/matthew/FastVideo/data/test-text-preprocessing"
|
||||
# DATA_DIR=data/crush-smol_processed_t2v/combined_parquet_dataset
|
||||
# DATA_DIR="/mnt/sharefs/users/hao.zhang/Vchitect-2M/Wan-Syn-upload/latents_i2v/train/"
|
||||
# VALIDATION_DATASET_FILE="data/crush-smol-single_processed_t2v/validation.json"
|
||||
VALIDATION_DATASET_FILE="/mnt/weka/home/hao.zhang/wl/FastVideo/examples/distill/Wan2.2-TI2V-5B-Diffusers/Data-free/validation_64.json"
|
||||
|
||||
# export CUDA_VISIBLE_DEVICES=4,5
|
||||
# IP=[MASTER NODE IP]
|
||||
|
||||
training_args=(
|
||||
--tracker_project_name SFwan2.2_t2v_distill_self_forcing_dmd # Updated for Wan2.2
|
||||
|
||||
@@ -31,7 +31,6 @@ export TOKENIZERS_PARALLELISM=false
|
||||
export WANDB_BASE_URL="https://api.wandb.ai"
|
||||
export WANDB_MODE=online
|
||||
export FASTVIDEO_ATTENTION_BACKEND=VIDEO_SPARSE_ATTN
|
||||
# export FASTVIDEO_ATTENTION_BACKEND=TORCH_SDPA
|
||||
|
||||
echo "MASTER_ADDR: $MASTER_ADDR"
|
||||
echo "NODE_RANK: $NODE_RANK"
|
||||
@@ -44,8 +43,6 @@ FAKE_SCORE_MODEL_PATH="Wan-AI/Wan2.1-T2V-1.3B-Diffusers"
|
||||
DATA_DIR=your_data_dir
|
||||
VALIDATION_DATASET_FILE=your_validation_dataset_file
|
||||
OUTPUT_DIR="checkpoints/wan_t2v_finetune"
|
||||
# export CUDA_VISIBLE_DEVICES=4,5
|
||||
# IP=[MASTER NODE IP]
|
||||
|
||||
# Training arguments
|
||||
training_args=(
|
||||
|
||||
@@ -31,7 +31,6 @@ export TOKENIZERS_PARALLELISM=false
|
||||
export WANDB_BASE_URL="https://api.wandb.ai"
|
||||
export WANDB_MODE=online
|
||||
export FASTVIDEO_ATTENTION_BACKEND=VIDEO_SPARSE_ATTN
|
||||
# export FASTVIDEO_ATTENTION_BACKEND=TORCH_SDPA
|
||||
|
||||
echo "MASTER_ADDR: $MASTER_ADDR"
|
||||
echo "NODE_RANK: $NODE_RANK"
|
||||
@@ -44,8 +43,6 @@ FAKE_SCORE_MODEL_PATH="Wan-AI/Wan2.1-T2V-14B-Diffusers"
|
||||
DATA_DIR=your_data_dir
|
||||
VALIDATION_DATASET_FILE=your_validation_dataset_file
|
||||
OUTPUT_DIR="checkpoints/wan_t2v_finetune"
|
||||
# export CUDA_VISIBLE_DEVICES=4,5
|
||||
# IP=[MASTER NODE IP]
|
||||
|
||||
# Training arguments
|
||||
training_args=(
|
||||
|
||||
@@ -31,7 +31,6 @@ export TOKENIZERS_PARALLELISM=false
|
||||
export WANDB_BASE_URL="https://api.wandb.ai"
|
||||
export WANDB_MODE=online
|
||||
export FASTVIDEO_ATTENTION_BACKEND=FLASH_ATTN
|
||||
# export FASTVIDEO_ATTENTION_BACKEND=TORCH_SDPA
|
||||
|
||||
echo "MASTER_ADDR: $MASTER_ADDR"
|
||||
echo "NODE_RANK: $NODE_RANK"
|
||||
@@ -44,8 +43,6 @@ FAKE_SCORE_MODEL_PATH="Wan-AI/Wan2.1-T2V-1.3B-Diffusers"
|
||||
DATA_DIR=your_data_dir
|
||||
VALIDATION_DATASET_FILE=your_validation_dataset_file
|
||||
OUTPUT_DIR="checkpoints/wan_t2v_finetune"
|
||||
# export CUDA_VISIBLE_DEVICES=4,5
|
||||
# IP=[MASTER NODE IP]
|
||||
|
||||
# Training arguments
|
||||
training_args=(
|
||||
|
||||
@@ -32,7 +32,6 @@ export WANDB_BASE_URL="https://api.wandb.ai"
|
||||
export WANDB_MODE=online
|
||||
export FASTVIDEO_ATTENTION_BACKEND=FLASH_ATTN
|
||||
export WANDB_API_KEY=your_wandb_api_key
|
||||
# export FASTVIDEO_ATTENTION_BACKEND=TORCH_SDPA
|
||||
|
||||
echo "MASTER_ADDR: $MASTER_ADDR"
|
||||
echo "NODE_RANK: $NODE_RANK"
|
||||
@@ -45,8 +44,6 @@ FAKE_SCORE_MODEL_PATH="Wan-AI/Wan2.2-TI2V-5B-Diffusers"
|
||||
DATA_DIR=your_data_dir
|
||||
VALIDATION_DIR=your_validation_path #(example:validation_64.json)
|
||||
OUTPUT_DIR="checkpoints/wan_t2v_finetune"
|
||||
# export CUDA_VISIBLE_DEVICES=4,5
|
||||
# IP=[MASTER NODE IP]
|
||||
|
||||
# Training arguments
|
||||
training_args=(
|
||||
|
||||
@@ -32,7 +32,6 @@ export WANDB_BASE_URL="https://api.wandb.ai"
|
||||
export WANDB_MODE=online
|
||||
export FASTVIDEO_ATTENTION_BACKEND=VIDEO_SPARSE_ATTN
|
||||
export WANDB_API_KEY=your_wandb_api_key
|
||||
# export FASTVIDEO_ATTENTION_BACKEND=TORCH_SDPA
|
||||
|
||||
echo "MASTER_ADDR: $MASTER_ADDR"
|
||||
echo "NODE_RANK: $NODE_RANK"
|
||||
@@ -44,8 +43,6 @@ REAL_SCORE_MODEL_PATH="Wan-AI/Wan2.2-TI2V-5B-Diffusers"
|
||||
FAKE_SCORE_MODEL_PATH="Wan-AI/Wan2.2-TI2V-5B-Diffusers"
|
||||
DATA_DIR=your_data_dir
|
||||
VALIDATION_DIR=your_validation_path #(example:validation_64.json)
|
||||
# export CUDA_VISIBLE_DEVICES=4,5
|
||||
# IP=[MASTER NODE IP]
|
||||
|
||||
# Training arguments
|
||||
training_args=(
|
||||
|
||||
@@ -9,7 +9,6 @@ export TOKENIZERS_PARALLELISM=false
|
||||
export WANDB_BASE_URL="https://api.wandb.ai"
|
||||
export WANDB_MODE=online
|
||||
export FASTVIDEO_ATTENTION_BACKEND=VIDEO_SPARSE_ATTN
|
||||
# export FASTVIDEO_ATTENTION_BACKEND=TORCH_SDPA
|
||||
|
||||
# Configs
|
||||
NUM_GPUS=1
|
||||
@@ -19,8 +18,6 @@ FAKE_SCORE_MODEL_PATH="Wan-AI/Wan2.2-TI2V-5B-Diffusers"
|
||||
DATA_DIR="data/crush-smol_processed_ti2v/combined_parquet_dataset/"
|
||||
VALIDATION_DATASET_FILE="examples/distill/Wan2.2-TI2V-5B-Diffusers/crush_smol/validation.json"
|
||||
OUTPUT_DIR="checkpoints/wan_t2v_finetune"
|
||||
# export CUDA_VISIBLE_DEVICES=4,5
|
||||
# IP=[MASTER NODE IP]
|
||||
|
||||
# Training arguments
|
||||
training_args=(
|
||||
|
||||
@@ -9,7 +9,6 @@ export TOKENIZERS_PARALLELISM=false
|
||||
export WANDB_BASE_URL="https://api.wandb.ai"
|
||||
export WANDB_MODE=online
|
||||
export FASTVIDEO_ATTENTION_BACKEND=VIDEO_SPARSE_ATTN
|
||||
# export FASTVIDEO_ATTENTION_BACKEND=TORCH_SDPA
|
||||
|
||||
# Configs
|
||||
NUM_GPUS=1
|
||||
@@ -18,8 +17,6 @@ REAL_SCORE_MODEL_PATH="Wan-AI/Wan2.2-TI2V-5B-Diffusers"
|
||||
FAKE_SCORE_MODEL_PATH="Wan-AI/Wan2.2-TI2V-5B-Diffusers"
|
||||
DATA_DIR="data/crush-smol_processed_ti2v/combined_parquet_dataset/"
|
||||
VALIDATION_DATASET_FILE="examples/distill/Wan2.2-TI2V-5B-Diffusers/crush_smol/validation.json"
|
||||
# export CUDA_VISIBLE_DEVICES=4,5
|
||||
# IP=[MASTER NODE IP]
|
||||
|
||||
# Training arguments
|
||||
training_args=(
|
||||
|
||||
@@ -63,7 +63,6 @@ async def main():
|
||||
dit_cpu_offload=True, # DiT need to be offloaded for MoE
|
||||
vae_cpu_offload=False,
|
||||
text_encoder_cpu_offload=True,
|
||||
# Set pin_cpu_memory to false if CPU RAM is limited and there're no frequent CPU-GPU transfer
|
||||
pin_cpu_memory=True,
|
||||
)
|
||||
|
||||
|
||||
@@ -17,7 +17,6 @@ def main():
|
||||
dit_cpu_offload=True, # DiT need to be offloaded for MoE
|
||||
vae_cpu_offload=False,
|
||||
text_encoder_cpu_offload=True,
|
||||
# Set pin_cpu_memory to false if CPU RAM is limited and there're no frequent CPU-GPU transfer
|
||||
pin_cpu_memory=True,
|
||||
)
|
||||
|
||||
|
||||
@@ -118,7 +118,7 @@ def score_all_metrics(video_path: str) -> None:
|
||||
for name in ev.metric_names:
|
||||
r = results[0].get(name)
|
||||
if r is None:
|
||||
continue # set metric, will show in corpus section
|
||||
continue
|
||||
if r.score is None:
|
||||
print(f" {name}: SKIPPED — {r.details.get('skipped', 'no score')}")
|
||||
else:
|
||||
|
||||
@@ -187,8 +187,8 @@ class BaseModelDeployment:
|
||||
num_gpus=1,
|
||||
use_fsdp_inference=True,
|
||||
text_encoder_cpu_offload=config["text_encoder_cpu_offload"],
|
||||
dmd_denoising_steps=[1000, 850, 700, 550, 350, 275, 200, 125], # TODO: hardocde for I2V
|
||||
dit_precision="fp32", # TODO: hardocde for I2V
|
||||
dmd_denoising_steps=[1000, 850, 700, 550, 350, 275, 200, 125],
|
||||
dit_precision="fp32",
|
||||
dit_cpu_offload=config["dit_cpu_offload"],
|
||||
vae_cpu_offload=config["vae_cpu_offload"],
|
||||
VSA_sparsity=config["VSA_sparsity"],
|
||||
|
||||
@@ -35,7 +35,6 @@ method:
|
||||
enable_gradient_in_rollout: true
|
||||
start_gradient_frame: 0
|
||||
|
||||
# Critic optimizer
|
||||
fake_score_learning_rate: 8.0e-6
|
||||
fake_score_betas: [0.0, 0.999]
|
||||
fake_score_lr_scheduler: constant
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
# ==============================================================================
|
||||
# Full configuration reference for fastvideo.train
|
||||
#
|
||||
# Legend:
|
||||
@@ -8,15 +7,12 @@
|
||||
# Keys depend on the _target_ class constructor / method_config.
|
||||
# [RESOLVED] — parsed by PipelineConfig.from_kwargs(); auto-populated from
|
||||
# the model's config files. Only scalar overrides are useful.
|
||||
# ==============================================================================
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# models: [FREE]
|
||||
#
|
||||
# Each role is instantiated via _target_(*, training_config=..., **kwargs).
|
||||
# Keys here are constructor kwargs of the _target_ class (e.g. WanModel).
|
||||
# You can define any role name (student, teacher, critic, etc.).
|
||||
# ------------------------------------------------------------------------------
|
||||
models:
|
||||
student:
|
||||
_target_: fastvideo.train.models.wan.WanModel # required
|
||||
@@ -39,13 +35,11 @@ models:
|
||||
trainable: true
|
||||
disable_custom_init_weights: true
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# method: [FREE]
|
||||
#
|
||||
# Instantiated via _target_(*, cfg=RunConfig, role_models=...).
|
||||
# All keys besides _target_ are available in self.method_config (a plain dict).
|
||||
# Keys depend entirely on the method class.
|
||||
# ------------------------------------------------------------------------------
|
||||
method:
|
||||
_target_: fastvideo.train.methods.distribution_matching.dmd2.DMD2Method # required
|
||||
|
||||
@@ -71,11 +65,9 @@ method:
|
||||
# --- FineTuneMethod keys (if using finetune instead) ---
|
||||
# _target_: fastvideo.train.methods.fine_tuning.finetune.FineTuneMethod
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# training: [TYPED] -> TrainingConfig
|
||||
#
|
||||
# Every field below has a typed default. Unknown keys are ignored.
|
||||
# ------------------------------------------------------------------------------
|
||||
training:
|
||||
|
||||
# --- training.distributed [TYPED] -> DistributedConfig ---
|
||||
@@ -166,13 +158,11 @@ training:
|
||||
dit_precision: fp32 # default: "fp32" (master weight precision)
|
||||
# model_path: ... # default: "" (auto-derived from models.student.init_from)
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# callbacks: [FREE]
|
||||
#
|
||||
# Each callback is instantiated via _target_(*, **kwargs).
|
||||
# The callback name (e.g. "grad_clip") is arbitrary — only _target_ matters.
|
||||
# training_config is injected automatically (not from YAML).
|
||||
# ------------------------------------------------------------------------------
|
||||
callbacks:
|
||||
|
||||
# --- GradNormClipCallback ---
|
||||
@@ -199,13 +189,11 @@ callbacks:
|
||||
output_dir: null # default: null (falls back to training.checkpoint.output_dir)
|
||||
sampling_timesteps: null # default: null (explicit timestep list for streaming)
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# pipeline: [RESOLVED] -> PipelineConfig
|
||||
#
|
||||
# Parsed by PipelineConfig.from_kwargs(). Most fields are auto-populated from
|
||||
# the model's config files (vae_config, dit_config, text_encoder_configs, etc.).
|
||||
# Only scalar overrides are typically needed here.
|
||||
# ------------------------------------------------------------------------------
|
||||
pipeline:
|
||||
flow_shift: 3 # default: null (model-specific)
|
||||
# LTX-2 linear QAT (SM100+ with FlashInfer); distinct from the role-local
|
||||
|
||||
@@ -24,7 +24,7 @@ models:
|
||||
_target_: fastvideo.train.models.wan.WanCausalModel
|
||||
init_from: wlsaidhi/SFWan2.1-T2V-1.3B-Diffusers
|
||||
trainable: true
|
||||
teacher: # remove once cache is complete
|
||||
teacher:
|
||||
_target_: fastvideo.train.models.wan.WanModel
|
||||
init_from: Wan-AI/Wan2.1-T2V-14B-Diffusers
|
||||
trainable: false
|
||||
|
||||
@@ -21,7 +21,7 @@ models:
|
||||
_target_: fastvideo.train.models.wan.WanModel
|
||||
init_from: Wan-AI/Wan2.1-T2V-1.3B-Diffusers
|
||||
trainable: true
|
||||
teacher: # remove once cache is complete
|
||||
teacher:
|
||||
_target_: fastvideo.train.models.wan.WanModel
|
||||
init_from: Wan-AI/Wan2.1-T2V-14B-Diffusers
|
||||
trainable: false
|
||||
|
||||
@@ -27,7 +27,6 @@ if [[ "${CONFIG}" != /* ]]; then
|
||||
CONFIG="$(pwd)/${CONFIG}"
|
||||
fi
|
||||
|
||||
# ── GPU / node settings ──────────────────────────────────────────
|
||||
NUM_GPUS="${NUM_GPUS:-$(nvidia-smi -L 2>/dev/null | wc -l)}"
|
||||
NUM_GPUS="${NUM_GPUS:-1}"
|
||||
NNODES="${NNODES:-1}"
|
||||
@@ -38,11 +37,9 @@ export TOKENIZERS_PARALLELISM=false
|
||||
export PYTHONPATH="${REPO_ROOT}${PYTHONPATH:+:${PYTHONPATH}}"
|
||||
|
||||
cd "${REPO_ROOT}"
|
||||
# ── W&B ──────────────────────────────────────────────────────────
|
||||
export WANDB_API_KEY="${WANDB_API_KEY:-}"
|
||||
export WANDB_MODE="${WANDB_MODE:-online}"
|
||||
|
||||
# ── Log file ─────────────────────────────────────────────────────
|
||||
CONFIG_NAME="$(basename "${CONFIG}" .yaml)"
|
||||
TIMESTAMP="$(date +%Y%m%d_%H%M%S)"
|
||||
LOG_DIR="${LOG_DIR:-examples/train}"
|
||||
|
||||
@@ -49,7 +49,6 @@ JOB_NAME="${JOB_NAME:-${CONFIG_NAME}}"
|
||||
OUTPUT_DIR="${OUTPUT_DIR:-logs/slurm}"
|
||||
mkdir -p "${OUTPUT_DIR}"
|
||||
|
||||
# ── Build sbatch args ─────────────────────────────────────────────
|
||||
# Forward the exported W&B API key through Slurm's environment so the generated
|
||||
# job script and its xtrace output do not contain the credential value.
|
||||
SBATCH_ARGS=(
|
||||
@@ -70,7 +69,6 @@ SBATCH_ARGS=(
|
||||
if [[ -n "${EXCLUDE}" ]]; then
|
||||
SBATCH_ARGS+=(--exclude="${EXCLUDE}")
|
||||
fi
|
||||
# Apply hardware and wall-clock requirements selected by an experiment launcher.
|
||||
if [[ -n "${SBATCH_CONSTRAINT}" ]]; then
|
||||
SBATCH_ARGS+=(--constraint="${SBATCH_CONSTRAINT}")
|
||||
fi
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#!/usr/bin/env bash
|
||||
# Run the modular Attn-QAT finetune recipe.
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
|
||||
@@ -45,9 +45,6 @@ training:
|
||||
checkpoints_total_limit: 3
|
||||
resume_from_checkpoint: latest
|
||||
|
||||
# tracker:
|
||||
# project_name: fastvideo
|
||||
# run_name: matrixgame2_i2v_finetune
|
||||
tracker:
|
||||
trackers: [none]
|
||||
project_name: ""
|
||||
|
||||
@@ -33,7 +33,6 @@ method:
|
||||
enable_gradient_in_rollout: true
|
||||
start_gradient_frame: 0
|
||||
|
||||
# Critic optimizer
|
||||
fake_score_learning_rate: 3.0e-7
|
||||
fake_score_betas: [0.9, 0.95]
|
||||
fake_score_lr_scheduler: constant
|
||||
|
||||
@@ -6,7 +6,6 @@ models:
|
||||
_target_: fastvideo.train.models.matrixgame2.matrixgame2_causal.MatrixGame2CausalModel
|
||||
init_from: mignonjia/mg_sf_distilled_zelda_1k_steps
|
||||
trainable: true
|
||||
# transformer_override_safetensor: outputs/matrixgame_dmd/checkpoints/mg_zelda_sf_m2/checkpoint-1000_weight_only/ema/generator_ema.safetensors
|
||||
teacher:
|
||||
_target_: fastvideo.train.models.matrixgame2.matrixgame2.MatrixGame2Model
|
||||
init_from: mignonjia/mg_bidirectional_zelda
|
||||
|
||||
@@ -8,7 +8,6 @@ MODEL_PATH="wlsaidhi/SFWan2.1-T2V-1.3B-Diffusers"
|
||||
DATA_DIR="data/crush-smol_processed_t2v_1_3b_ode_init/"
|
||||
VALIDATION_DATASET_FILE="$(dirname "$0")/validation.json"
|
||||
NUM_GPUS=1
|
||||
# IP=[MASTER NODE IP]
|
||||
|
||||
# Training arguments
|
||||
training_args=(
|
||||
|
||||
-1
@@ -29,7 +29,6 @@ export CUDA_VISIBLE_DEVICES=$SLURM_LOCALID
|
||||
export TOKENIZERS_PARALLELISM=false
|
||||
export WANDB_BASE_URL="https://api.wandb.ai"
|
||||
export WANDB_API_KEY=your-wandb-api-key
|
||||
# export FASTVIDEO_ATTENTION_BACKEND=TORCH_SDPA
|
||||
|
||||
echo "MASTER_ADDR: $MASTER_ADDR"
|
||||
echo "NODE_RANK: $NODE_RANK"
|
||||
|
||||
@@ -3,14 +3,11 @@
|
||||
export WANDB_BASE_URL="https://api.wandb.ai"
|
||||
export WANDB_MODE=online
|
||||
export TOKENIZERS_PARALLELISM=false
|
||||
# export FASTVIDEO_ATTENTION_BACKEND=TORCH_SDPA
|
||||
|
||||
MODEL_PATH="FastVideo/Matrix-Game-2.0-Base-Diffusers"
|
||||
DATA_DIR="footsies-dataset/preprocessed/combined_parquet_dataset"
|
||||
VALIDATION_DATASET_FILE="$(dirname "$0")/validation.json"
|
||||
NUM_GPUS=8
|
||||
# export CUDA_VISIBLE_DEVICES=4,5
|
||||
# IP=[MASTER NODE IP]
|
||||
|
||||
# Training arguments
|
||||
training_args=(
|
||||
@@ -80,7 +77,6 @@ miscellaneous_args=(
|
||||
--ema_start_step 0
|
||||
)
|
||||
|
||||
# If you do not have 32 GPUs and to fit in memory, you can: 1. increase sp_size. 2. reduce num_latent_t
|
||||
torchrun \
|
||||
--nnodes 1 \
|
||||
--nproc_per_node $NUM_GPUS \
|
||||
|
||||
@@ -3,14 +3,11 @@
|
||||
export WANDB_BASE_URL="https://api.wandb.ai"
|
||||
export WANDB_MODE=online
|
||||
export TOKENIZERS_PARALLELISM=false
|
||||
# export FASTVIDEO_ATTENTION_BACKEND=TORCH_SDPA
|
||||
|
||||
MODEL_PATH="FastVideo/Matrix-Game-2.0-Base-Diffusers"
|
||||
DATA_DIR="footsies-dataset/preprocessed/combined_parquet_dataset"
|
||||
VALIDATION_DATASET_FILE="$(dirname "$0")/validation.json"
|
||||
NUM_GPUS=8
|
||||
# export CUDA_VISIBLE_DEVICES=4,5
|
||||
# IP=[MASTER NODE IP]
|
||||
|
||||
# Training arguments
|
||||
training_args=(
|
||||
|
||||
@@ -5,7 +5,6 @@ MODEL_PATH="Matrix-Game-2.0-Base-Diffusers"
|
||||
DATA_MERGE_PATH="footsies-dataset/merge.txt"
|
||||
OUTPUT_DIR="footsies-dataset/preprocessed/"
|
||||
|
||||
# export CUDA_VISIBLE_DEVICES=0
|
||||
export MASTER_ADDR=localhost
|
||||
export MASTER_PORT=29500
|
||||
export RANK=0
|
||||
|
||||
@@ -3,14 +3,11 @@
|
||||
export WANDB_BASE_URL="https://api.wandb.ai"
|
||||
export WANDB_MODE=online
|
||||
export TOKENIZERS_PARALLELISM=false
|
||||
# export FASTVIDEO_ATTENTION_BACKEND=TORCH_SDPA
|
||||
|
||||
MODEL_PATH="weizhou03/Wan2.1-Fun-1.3B-InP-Diffusers"
|
||||
DATA_DIR="data/crush-smol_processed_i2v_1_3b_inp/combined_parquet_dataset/"
|
||||
VALIDATION_DATASET_FILE="examples/training/finetune/Wan2.1-Fun-1.3B-InP/crush_smol/validation.json"
|
||||
NUM_GPUS=8
|
||||
# export CUDA_VISIBLE_DEVICES=4,5
|
||||
# IP=[MASTER NODE IP]
|
||||
|
||||
# Training arguments
|
||||
training_args=(
|
||||
@@ -80,7 +77,6 @@ miscellaneous_args=(
|
||||
--enable_gradient_checkpointing_type "full"
|
||||
)
|
||||
|
||||
# If you do not have 32 GPUs and to fit in memory, you can: 1. increase sp_size. 2. reduce num_latent_t
|
||||
torchrun \
|
||||
--nnodes 1 \
|
||||
--nproc_per_node $NUM_GPUS \
|
||||
|
||||
@@ -30,7 +30,6 @@ export CUDA_VISIBLE_DEVICES=$SLURM_LOCALID
|
||||
export TOKENIZERS_PARALLELISM=false
|
||||
export WANDB_BASE_URL="https://api.wandb.ai"
|
||||
export WANDB_MODE=online
|
||||
# export FASTVIDEO_ATTENTION_BACKEND=TORCH_SDPA
|
||||
|
||||
echo "MASTER_ADDR: $MASTER_ADDR"
|
||||
echo "NODE_RANK: $NODE_RANK"
|
||||
@@ -41,8 +40,6 @@ NUM_GPUS=8
|
||||
MODEL_PATH="weizhou03/Wan2.1-Fun-1.3B-InP-Diffusers"
|
||||
DATA_DIR="data/crush-smol_processed_i2v_1_3b_inp/combined_parquet_dataset/"
|
||||
VALIDATION_DATASET_FILE="examples/training/finetune/Wan2.1-Fun-1.3B-InP/crush_smol/validation.json"
|
||||
# export CUDA_VISIBLE_DEVICES=4,5
|
||||
# IP=[MASTER NODE IP]
|
||||
|
||||
# If you do not have 32 GPUs and to fit in memory, you can: 1. increase sp_size. 2. reduce num_latent_t
|
||||
|
||||
|
||||
@@ -31,7 +31,6 @@ export TOKENIZERS_PARALLELISM=false
|
||||
export WANDB_BASE_URL="https://api.wandb.ai"
|
||||
export WANDB_MODE=online
|
||||
export FASTVIDEO_ATTENTION_BACKEND=VIDEO_SPARSE_ATTN
|
||||
# export FASTVIDEO_ATTENTION_BACKEND=TORCH_SDPA
|
||||
|
||||
echo "MASTER_ADDR: $MASTER_ADDR"
|
||||
echo "NODE_RANK: $NODE_RANK"
|
||||
@@ -41,8 +40,6 @@ NUM_GPUS=8
|
||||
MODEL_PATH="Wan-AI/Wan2.1-I2V-14B-720P-Diffusers"
|
||||
DATA_DIR=your_data_dir
|
||||
VALIDATION_DATASET_FILE=your_validation_dataset_file
|
||||
# export CUDA_VISIBLE_DEVICES=4,5
|
||||
# IP=[MASTER NODE IP]
|
||||
|
||||
# Core training arguments
|
||||
core_training_args=(
|
||||
|
||||
@@ -31,7 +31,6 @@ export TOKENIZERS_PARALLELISM=false
|
||||
export WANDB_BASE_URL="https://api.wandb.ai"
|
||||
export WANDB_MODE=online
|
||||
export FASTVIDEO_ATTENTION_BACKEND=VIDEO_SPARSE_ATTN
|
||||
# export FASTVIDEO_ATTENTION_BACKEND=TORCH_SDPA
|
||||
|
||||
echo "MASTER_ADDR: $MASTER_ADDR"
|
||||
echo "NODE_RANK: $NODE_RANK"
|
||||
@@ -41,8 +40,6 @@ NUM_GPUS=8
|
||||
MODEL_PATH="Wan-AI/Wan2.1-T2V-1.3B-Diffusers"
|
||||
DATA_DIR=your_data_dir
|
||||
VALIDATION_DATASET_FILE=your_validation_dataset_file
|
||||
# export CUDA_VISIBLE_DEVICES=4,5
|
||||
# IP=[MASTER NODE IP]
|
||||
|
||||
# Core training arguments
|
||||
core_training_args=(
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
|
||||
|
||||
# Basic info
|
||||
export WANDB_MODE="online"
|
||||
export NCCL_P2P_DISABLE=1
|
||||
export TORCH_NCCL_ENABLE_MONITORING=0
|
||||
@@ -11,15 +10,13 @@ export NODE_RANK=0
|
||||
export TOKENIZERS_PARALLELISM=false
|
||||
export WANDB_BASE_URL="https://api.wandb.ai"
|
||||
export FASTVIDEO_ATTENTION_BACKEND=VIDEO_SPARSE_ATTN
|
||||
export WANDB_API_KEY="your_wandb_api_key_here" # TODO: Replace with your actual key or load from a secure location
|
||||
export WANDB_API_KEY="your_wandb_api_key_here"
|
||||
|
||||
# Configs
|
||||
NUM_GPUS=4
|
||||
MODEL_PATH="Wan-AI/Wan2.1-T2V-1.3B-Diffusers"
|
||||
DATA_DIR=data/Wan-Syn_77x448x832_600k
|
||||
VALIDATION_DATASET_FILE=examples/training/finetune/Wan2.1-VSA/Wan-Syn-Data/validation_4.json
|
||||
|
||||
# Core training arguments
|
||||
core_training_args=(
|
||||
--tracker_project_name wan_t2v_VSA
|
||||
--output_dir "checkpoints/wan_t2v_finetune_VSA"
|
||||
@@ -31,14 +28,12 @@ core_training_args=(
|
||||
--enable_gradient_checkpointing_type "full" # if OOM enable this
|
||||
)
|
||||
|
||||
# Validation generation shape arguments (used during training validation)
|
||||
validation_generation_shape_args=(
|
||||
--num_height 448
|
||||
--num_width 832
|
||||
--num_frames 77
|
||||
)
|
||||
|
||||
# Parallel arguments
|
||||
parallel_args=(
|
||||
--num_gpus $NUM_GPUS
|
||||
--sp_size 1
|
||||
@@ -47,19 +42,16 @@ parallel_args=(
|
||||
--hsdp_shard_dim 1
|
||||
)
|
||||
|
||||
# Model arguments
|
||||
model_args=(
|
||||
--model_path "$MODEL_PATH"
|
||||
--pretrained_model_name_or_path "$MODEL_PATH"
|
||||
)
|
||||
|
||||
# Dataset arguments
|
||||
dataset_args=(
|
||||
--data_path "$DATA_DIR"
|
||||
--dataloader_num_workers 4
|
||||
)
|
||||
|
||||
# Validation arguments
|
||||
validation_args=(
|
||||
--log_validation
|
||||
--validation_dataset_file "$VALIDATION_DATASET_FILE"
|
||||
@@ -68,7 +60,6 @@ validation_args=(
|
||||
--validation_guidance_scale "5.0"
|
||||
)
|
||||
|
||||
# Optimizer arguments
|
||||
optimizer_args=(
|
||||
--learning_rate 1e-6
|
||||
--mixed_precision "bf16"
|
||||
@@ -78,7 +69,6 @@ optimizer_args=(
|
||||
--max_grad_norm 1.0
|
||||
)
|
||||
|
||||
# Miscellaneous arguments
|
||||
miscellaneous_args=(
|
||||
--inference_mode False
|
||||
--checkpoints_total_limit 3
|
||||
@@ -89,7 +79,6 @@ miscellaneous_args=(
|
||||
--seed 1000
|
||||
)
|
||||
|
||||
# VSA arguments
|
||||
vsa_args=(
|
||||
--VSA_decay_rate 0.03
|
||||
--VSA_decay_interval_steps 50
|
||||
|
||||
@@ -31,7 +31,6 @@ export TOKENIZERS_PARALLELISM=false
|
||||
export WANDB_BASE_URL="https://api.wandb.ai"
|
||||
export WANDB_MODE=online
|
||||
export FASTVIDEO_ATTENTION_BACKEND=VIDEO_SPARSE_ATTN
|
||||
# export FASTVIDEO_ATTENTION_BACKEND=TORCH_SDPA
|
||||
|
||||
echo "MASTER_ADDR: $MASTER_ADDR"
|
||||
echo "NODE_RANK: $NODE_RANK"
|
||||
@@ -41,8 +40,6 @@ NUM_GPUS=8
|
||||
MODEL_PATH="Wan-AI/Wan2.1-T2V-14B-Diffusers"
|
||||
DATA_DIR=your_data_dir
|
||||
VALIDATION_DATASET_FILE=your_validation_dataset_file
|
||||
# export CUDA_VISIBLE_DEVICES=4,5
|
||||
# IP=[MASTER NODE IP]
|
||||
|
||||
# Core training arguments
|
||||
core_training_args=(
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
export WANDB_BASE_URL="https://api.wandb.ai"
|
||||
export WANDB_MODE=online
|
||||
export TOKENIZERS_PARALLELISM=false
|
||||
# export FASTVIDEO_ATTENTION_BACKEND=TORCH_SDPA
|
||||
|
||||
MODEL_PATH="KyleShao/Cosmos-Predict2.5-2B-Diffusers"
|
||||
DATA_DIR="data/cosmos2_5_processed_t2w/combined_parquet_dataset/"
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
export WANDB_BASE_URL="https://api.wandb.ai"
|
||||
export WANDB_MODE=online
|
||||
export TOKENIZERS_PARALLELISM=false
|
||||
# export FASTVIDEO_ATTENTION_BACKEND=TORCH_SDPA
|
||||
|
||||
MODEL_PATH="KyleShao/Cosmos-Predict2.5-2B-Diffusers"
|
||||
DATA_DIR="data/cosmos2_5_processed_t2w/combined_parquet_dataset/"
|
||||
|
||||
@@ -7,9 +7,7 @@ set -euo pipefail
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
REPO_ROOT="$(cd "${SCRIPT_DIR}/../../../.." && pwd)"
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Edit the DDP run here. Do not launch while another job owns the same GPUs.
|
||||
# ---------------------------------------------------------------------------
|
||||
FEATURE_DIR="/mnt/lustre/vlm-kai/datasets/VGGSound/mmaudio_features_torio/train"
|
||||
VALIDATION_FEATURE_DIR="/mnt/lustre/vlm-kai/datasets/VGGSound/mmaudio_features_torio/val"
|
||||
EMPTY_STRING_FEATURES="${REPO_ROOT}/official_weights/mmaudio/raw/ext_weights/empty_string.pth"
|
||||
|
||||
@@ -6,9 +6,7 @@ set -euo pipefail
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
REPO_ROOT="$(cd "${SCRIPT_DIR}/../../../.." && pwd)"
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Edit the training run here. No environment variables are required.
|
||||
# ---------------------------------------------------------------------------
|
||||
VARIANT="small_44k"
|
||||
|
||||
FEATURE_DIR="/mnt/lustre/vlm-kai/datasets/VGGSound/mmaudio_features_torio/train"
|
||||
|
||||
@@ -3,14 +3,11 @@
|
||||
export WANDB_BASE_URL="https://api.wandb.ai"
|
||||
export WANDB_MODE=online
|
||||
export TOKENIZERS_PARALLELISM=false
|
||||
# export FASTVIDEO_ATTENTION_BACKEND=TORCH_SDPA
|
||||
|
||||
MODEL_PATH="Wan-AI/Wan2.1-I2V-14B-480P-Diffusers"
|
||||
DATA_DIR="data/crush-smol_processed_i2v/combined_parquet_dataset/"
|
||||
VALIDATION_DATASET_FILE="$(dirname "$0")/validation.json"
|
||||
NUM_GPUS=8
|
||||
# export CUDA_VISIBLE_DEVICES=4,5
|
||||
# IP=[MASTER NODE IP]
|
||||
|
||||
# Training arguments
|
||||
training_args=(
|
||||
@@ -80,7 +77,6 @@ miscellaneous_args=(
|
||||
--enable_gradient_checkpointing_type "full"
|
||||
)
|
||||
|
||||
# If you do not have 32 GPUs and to fit in memory, you can: 1. increase sp_size. 2. reduce num_latent_t
|
||||
torchrun \
|
||||
--nnodes 1 \
|
||||
--nproc_per_node $NUM_GPUS \
|
||||
|
||||
@@ -30,7 +30,6 @@ export CUDA_VISIBLE_DEVICES=$SLURM_LOCALID
|
||||
export TOKENIZERS_PARALLELISM=false
|
||||
export WANDB_BASE_URL="https://api.wandb.ai"
|
||||
export WANDB_MODE=online
|
||||
# export FASTVIDEO_ATTENTION_BACKEND=TORCH_SDPA
|
||||
|
||||
echo "MASTER_ADDR: $MASTER_ADDR"
|
||||
echo "NODE_RANK: $NODE_RANK"
|
||||
@@ -41,8 +40,6 @@ NUM_GPUS=8
|
||||
MODEL_PATH="Wan-AI/Wan2.1-I2V-14B-480P-Diffusers"
|
||||
DATA_DIR="data/crush-smol_processed_i2v/combined_parquet_dataset/"
|
||||
VALIDATION_DATASET_FILE="examples/training/finetune/wan_i2v_14b_480p/crush_smol/validation.json"
|
||||
# export CUDA_VISIBLE_DEVICES=4,5
|
||||
# IP=[MASTER NODE IP]
|
||||
|
||||
# If you do not have 32 GPUs and to fit in memory, you can: 1. increase sp_size. 2. reduce num_latent_t
|
||||
|
||||
|
||||
@@ -2,14 +2,11 @@
|
||||
|
||||
export WANDB_BASE_URL="https://api.wandb.ai"
|
||||
export WANDB_MODE=online
|
||||
# export FASTVIDEO_ATTENTION_BACKEND=TORCH_SDPA
|
||||
|
||||
MODEL_PATH="Wan-AI/Wan2.1-I2V-14B-480P-Diffusers"
|
||||
DATA_DIR="data/crush-smol_processed_i2v/combined_parquet_dataset/"
|
||||
VALIDATION_DIR="data/crush-smol_processed_i2v/validation_parquet_dataset/"
|
||||
NUM_GPUS=4
|
||||
# export CUDA_VISIBLE_DEVICES=4,5
|
||||
# IP=[MASTER NODE IP]
|
||||
|
||||
# Training arguments
|
||||
training_args=(
|
||||
@@ -79,7 +76,6 @@ miscellaneous_args=(
|
||||
--ema_start_step 0
|
||||
)
|
||||
|
||||
# If you do not have 32 GPUs and to fit in memory, you can: 1. increase sp_size. 2. reduce num_latent_t
|
||||
torchrun \
|
||||
--nnodes 1 \
|
||||
--nproc_per_node $NUM_GPUS \
|
||||
|
||||
@@ -3,13 +3,11 @@
|
||||
export WANDB_BASE_URL="https://api.wandb.ai"
|
||||
export WANDB_MODE=online
|
||||
export TOKENIZERS_PARALLELISM=false
|
||||
# export FASTVIDEO_ATTENTION_BACKEND=TORCH_SDPA
|
||||
|
||||
MODEL_PATH="Wan-AI/Wan2.1-T2V-1.3B-Diffusers"
|
||||
DATA_DIR="data/crush-smol_processed_t2v/combined_parquet_dataset/"
|
||||
VALIDATION_DATASET_FILE="$(dirname "$0")/validation.json"
|
||||
NUM_GPUS=4
|
||||
# export CUDA_VISIBLE_DEVICES=4,5
|
||||
|
||||
|
||||
# Training arguments
|
||||
|
||||
@@ -30,7 +30,6 @@ export CUDA_VISIBLE_DEVICES=$SLURM_LOCALID
|
||||
export TOKENIZERS_PARALLELISM=false
|
||||
export WANDB_BASE_URL="https://api.wandb.ai"
|
||||
export WANDB_MODE=online
|
||||
# export FASTVIDEO_ATTENTION_BACKEND=TORCH_SDPA
|
||||
|
||||
echo "MASTER_ADDR: $MASTER_ADDR"
|
||||
echo "NODE_RANK: $NODE_RANK"
|
||||
@@ -40,8 +39,6 @@ NUM_GPUS=8
|
||||
MODEL_PATH="Wan-AI/Wan2.1-T2V-1.3B-Diffusers"
|
||||
DATA_DIR="data/crush-smol_processed_t2v/combined_parquet_dataset/"
|
||||
VALIDATION_DATASET_FILE="examples/training/finetune/wan_t2v_1_3b/crush_smol/validation.json"
|
||||
# export CUDA_VISIBLE_DEVICES=4,5
|
||||
# IP=[MASTER NODE IP]
|
||||
|
||||
# Training arguments
|
||||
training_args=(
|
||||
|
||||
@@ -2,13 +2,11 @@
|
||||
|
||||
export WANDB_BASE_URL="https://api.wandb.ai"
|
||||
export WANDB_MODE=online
|
||||
# export FASTVIDEO_ATTENTION_BACKEND=TORCH_SDPA
|
||||
|
||||
MODEL_PATH="Wan-AI/Wan2.1-T2V-1.3B-Diffusers"
|
||||
DATA_DIR="data/crush-smol_processed_t2v/combined_parquet_dataset/"
|
||||
VALIDATION_DATASET_FILE="$(dirname "$0")/validation.json"
|
||||
NUM_GPUS=1
|
||||
# export CUDA_VISIBLE_DEVICES=4,5
|
||||
|
||||
|
||||
# Training arguments
|
||||
|
||||
@@ -3,13 +3,11 @@
|
||||
export WANDB_BASE_URL="https://api.wandb.ai"
|
||||
export WANDB_MODE=online
|
||||
export TOKENIZERS_PARALLELISM=false
|
||||
# export FASTVIDEO_ATTENTION_BACKEND=TORCH_SDPA
|
||||
|
||||
MODEL_PATH="Wan-AI/Wan2.1-T2V-1.3B-Diffusers"
|
||||
DATA_DIR="data/crush-smol_processed_t2v/combined_parquet_dataset/"
|
||||
VALIDATION_DATASET_FILE="$(dirname "$0")/validation.json"
|
||||
NUM_GPUS=4
|
||||
# export CUDA_VISIBLE_DEVICES=4,5
|
||||
|
||||
mkdir -p ../profiler_traces/wan_t2v_finetune/
|
||||
|
||||
|
||||
@@ -68,9 +68,7 @@ void set_params_fprop(Flash_fwd_params ¶ms,
|
||||
bool single_level_p_quant=false,
|
||||
bool seqlenq_ngroups_swapped=false) {
|
||||
|
||||
// Reset the parameters
|
||||
params = {};
|
||||
// Set the pointers and strides.
|
||||
params.q_ptr = q.data_ptr();
|
||||
params.k_ptr = k.data_ptr();
|
||||
params.v_ptr = v.data_ptr();
|
||||
@@ -119,13 +117,11 @@ void set_params_fprop(Flash_fwd_params ¶ms,
|
||||
params.cu_seqlens_k = static_cast<int *>(cu_seqlens_k_d);
|
||||
params.seqused_k = static_cast<int *>(seqused_k);
|
||||
|
||||
// P = softmax(QK^T)
|
||||
params.p_ptr = p_d;
|
||||
|
||||
// Softmax sum
|
||||
params.softmax_lse_ptr = softmax_lse_d;
|
||||
|
||||
// Set the dimensions.
|
||||
params.b = b;
|
||||
params.h = h;
|
||||
params.h_k = h_k;
|
||||
@@ -140,7 +136,6 @@ void set_params_fprop(Flash_fwd_params ¶ms,
|
||||
|
||||
params.head_divmod = cutlass::FastDivmod(int(h));
|
||||
|
||||
// Set the different scale values.
|
||||
params.scale_softmax = softmax_scale;
|
||||
params.scale_softmax_log2 = softmax_scale * M_LOG2E;
|
||||
__half scale_softmax_log2_half = __float2half(params.scale_softmax_log2);
|
||||
@@ -149,10 +144,6 @@ void set_params_fprop(Flash_fwd_params ¶ms,
|
||||
|
||||
// Set this to probability of keeping an element to simplify things.
|
||||
params.p_dropout = 1.f - p_dropout;
|
||||
// Convert p from float to int so we don't have to convert the random uint to float to compare.
|
||||
// [Minor] We want to round down since when we do the comparison we use <= instead of <
|
||||
// params.p_dropout_in_uint = uint32_t(std::floor(params.p_dropout * 4294967295.0));
|
||||
// params.p_dropout_in_uint16_t = uint16_t(std::floor(params.p_dropout * 65535.0));
|
||||
params.p_dropout_in_uint8_t = uint8_t(std::floor(params.p_dropout * 255.0));
|
||||
params.rp_dropout = 1.f / params.p_dropout;
|
||||
params.scale_softmax_rp_dropout = params.rp_dropout * params.scale_softmax;
|
||||
@@ -276,18 +267,12 @@ mha_fwd_impl(at::Tensor &q, // batch_size x seqlen_q x num_heads x (head
|
||||
CHECK_SHAPE(q, batch_size, num_heads, seqlen_q, head_size_og);
|
||||
CHECK_SHAPE(k, batch_size, num_heads_k, seqlen_k, head_size_og);
|
||||
CHECK_SHAPE(v, batch_size, num_heads_k, unpacked_head_size, seqlen_k/2);
|
||||
// CHECK_SHAPE(delta_s, batch_size, num_heads, seqlen_q / 128, seqlen_k);
|
||||
// CHECK_SHAPE(sfq, batch_size, seqlen_q, num_heads, unpacked_head_size);
|
||||
// CHECK_SHAPE(sfk, batch_size, seqlen_k, num_heads_k, unpacked_head_size);
|
||||
// CHECK_SHAPE(sfv, batch_size, unpacked_head_size, num_heads_k, seqlen_k);
|
||||
TORCH_CHECK(unpacked_head_size % 8 == 0, "head_size must be a multiple of 8");
|
||||
|
||||
auto dtype = is_bf16 ? at::ScalarType::BFloat16 : at::ScalarType::Half;
|
||||
at::Tensor out = torch::empty({batch_size, num_heads, seqlen_q, unpacked_head_size}, opts.dtype(dtype));
|
||||
|
||||
auto round_multiple = [](int x, int m) { return (x + m - 1) / m * m; };
|
||||
// const int head_size = round_multiple(head_size_og, 8);
|
||||
// const int head_size_rounded = round_multiple(head_size, 32);
|
||||
const int seqlen_q_rounded = round_multiple(seqlen_q, flash::BLOCK_M);
|
||||
const int seqlen_k_rounded = round_multiple(seqlen_k, flash::BLOCK_N);
|
||||
|
||||
@@ -348,10 +333,6 @@ mha_fwd_impl(at::Tensor &q, // batch_size x seqlen_q x num_heads x (head
|
||||
// if (out_.has_value()) { out_.value().copy_(out); }
|
||||
// }
|
||||
|
||||
// return {out, q_padded, k_padded, v_padded, out_padded, softmax_lse, p};
|
||||
// cudaDeviceSynchronize();
|
||||
// auto err = cudaGetLastError();
|
||||
// printf("%s\n", cudaGetErrorString(err));
|
||||
return {out, softmax_lse};
|
||||
}
|
||||
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
|
||||
namespace flash {
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template<bool Varlen=true>
|
||||
struct BlockInfo {
|
||||
@@ -55,6 +54,5 @@ struct BlockInfo {
|
||||
const int actual_seqlen_k;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
} // namespace flash
|
||||
|
||||
@@ -119,7 +119,6 @@ struct CollectiveEpilogueFwd{
|
||||
auto smem_thr_copy_O = smem_tiled_copy_O.get_thread_slice(thread_idx);
|
||||
constexpr int numel = decltype(size(tOrO))::value;
|
||||
cutlass::NumericArrayConverter<Element, float, numel> convert_op;
|
||||
// HACK: this requires tensor to be "contiguous"
|
||||
auto frag = convert_op(*reinterpret_cast<const cutlass::Array<float, numel> *>(tOrO.data()));
|
||||
auto tOrO_out = make_tensor(make_rmem_ptr<Element>(&frag), tOrO.layout());
|
||||
Tensor taccOrO = smem_thr_copy_O.retile_S(tOrO_out); // ((Atom,AtomNum), MMA_M, MMA_N)
|
||||
@@ -183,7 +182,6 @@ struct CollectiveEpilogueFwd{
|
||||
tma_store_wait<0>();
|
||||
}
|
||||
|
||||
// Write 0 to output and -inf to LSE
|
||||
CUTLASS_DEVICE void
|
||||
store_zero(
|
||||
Params const& epilogue_params,
|
||||
@@ -202,9 +200,7 @@ struct CollectiveEpilogueFwd{
|
||||
Tensor tOgO = gmem_thr_copy_O.partition_D(gO);
|
||||
Tensor tOrO = make_fragment_like(tOgO);
|
||||
clear(tOrO);
|
||||
// Construct identity layout for sO
|
||||
Tensor cO = cute::make_identity_tensor(select<0, 2>(TileShape_MNK{})); // (BLK_M,BLK_K) -> (blk_m,blk_k)
|
||||
// Repeat the partitioning with identity layouts
|
||||
Tensor tOcO = gmem_thr_copy_O.partition_D(cO);
|
||||
Tensor tOpO = make_tensor<bool>(make_shape(size<2>(tOgO)));
|
||||
#pragma unroll
|
||||
|
||||
@@ -97,7 +97,6 @@ __global__ void __launch_bounds__(Ktraits::kNWarps * cutlass::NumThreadsPerWarp,
|
||||
CollectiveEpilogue::prefetch_tma_descriptors(epilogue_params);
|
||||
}
|
||||
|
||||
// Obtain warp index
|
||||
|
||||
PipelineParams pipeline_params_v;
|
||||
pipeline_params_v.transaction_bytes = CollectiveMainloop::TmaTransactionBytesV;
|
||||
@@ -142,7 +141,7 @@ __global__ void __launch_bounds__(Ktraits::kNWarps * cutlass::NumThreadsPerWarp,
|
||||
cutlass::arch::warpgroup_reg_dealloc<24>();
|
||||
TileScheduler scheduler;
|
||||
|
||||
if (producer_warp_role == ProducerWarpRole::Mainloop) { // Load Q, K, V
|
||||
if (producer_warp_role == ProducerWarpRole::Mainloop) {
|
||||
PipelineStateQ smem_pipe_write_q = cutlass::make_producer_start_state<MainloopPipelineQ>();
|
||||
PipelineState smem_pipe_write_k = cutlass::make_producer_start_state<MainloopPipeline>();
|
||||
PipelineState smem_pipe_write_v = cutlass::make_producer_start_state<MainloopPipeline>();
|
||||
@@ -179,8 +178,6 @@ __global__ void __launch_bounds__(Ktraits::kNWarps * cutlass::NumThreadsPerWarp,
|
||||
for (auto work_tile_info = scheduler.get_initial_work(); work_tile_info.is_valid(scheduler_params); work_tile_info = scheduler.get_next_work(scheduler_params, work_tile_info)) {
|
||||
// Attention output (GEMM-II) accumulator.
|
||||
Tensor tOrO = partition_fragment_C(tiled_mma_pv, select<0, 2>(TileShape_MNK{}));
|
||||
// flash::Softmax<2 * (2 * kBlockM / NumMmaThreads)> softmax;
|
||||
// Pass single_level_p_quant flag to control P quantization mode
|
||||
flash::SoftmaxFused<2 * (2 * kBlockM / NumMmaThreads)> softmax_fused(params.single_level_p_quant);
|
||||
auto block_coord = work_tile_info.get_block_coord(scheduler_params);
|
||||
auto [m_block, bidh, bidb] = block_coord;
|
||||
|
||||
@@ -79,7 +79,6 @@ void run_flash_fwd(Flash_fwd_params ¶ms, cudaStream_t stream) {
|
||||
num_blocks_m = cutlass::ceil_div(num_blocks_m, size<0>(ClusterShape{})) * size<0>(ClusterShape{});
|
||||
typename Scheduler::Arguments scheduler_args = {num_blocks_m, params.h, params.b};
|
||||
typename Scheduler::Params scheduler_params = Scheduler::to_underlying_arguments(scheduler_args);
|
||||
// Get the ptr to kernel function.
|
||||
void *kernel;
|
||||
kernel = (void *)flash::compute_attn_ws<Kernel_traits, Is_causal, Scheduler>;
|
||||
int smem_size = sizeof(typename Kernel_traits::SharedStorage);
|
||||
|
||||
@@ -683,7 +683,6 @@ struct CollectiveMainloopFwd {
|
||||
Tensor tOrSFP = make_tensor<ElementSF>(LayoutSFP{});
|
||||
Tensor tOrSFP_flt = filter_zeros(tOrSFP);
|
||||
Tensor tSrDS = make_tensor<float>(make_shape(_8{}, _4{}), make_stride(_1{}, _8{}));
|
||||
// copy qk and sf from smem to rmem
|
||||
auto smem_tiled_copy_Q = make_tiled_copy_A(SmemCopyAtomQ{}, tiled_mma_qk);
|
||||
auto smem_thr_copy_Q = smem_tiled_copy_Q.get_thread_slice(thread_idx);
|
||||
Tensor tSsQ = smem_thr_copy_Q.partition_S(as_position_independent_swizzle_tensor(sQ));
|
||||
|
||||
@@ -65,7 +65,6 @@ public:
|
||||
// MSVC requires protecting use of CUDA-specific nonstandard syntax,
|
||||
// like blockIdx and gridDim, with __CUDA_ARCH__.
|
||||
#if defined(__CUDA_ARCH__)
|
||||
// current_work_linear_idx_ = blockIdx.x + blockIdx.y * gridDim.x + blockIdx.z * gridDim.x * gridDim.y;
|
||||
current_work_linear_idx_ = blockIdx.x;
|
||||
#else
|
||||
CUTLASS_ASSERT(false && "This line should never be reached");
|
||||
|
||||
@@ -136,7 +136,6 @@ __forceinline__ __device__ __half2 half_exp(__half2 x) {
|
||||
return out;
|
||||
}
|
||||
|
||||
// Apply the exp to all the elements.
|
||||
template <bool zero_init=false, typename Engine0, typename Layout0, typename Engine1, typename Layout1>
|
||||
__forceinline__ __device__ void max_scale_exp2_sum(Tensor<Engine0, Layout0> &tensor, Tensor<Engine1, Layout1> &max, Tensor<Engine1, Layout1> &sum, const float scale) {
|
||||
static_assert(Layout0::rank == 2, "Only support 2D Tensor"); static_assert(Layout1::rank == 1, "Only support 1D Tensor"); CUTE_STATIC_ASSERT_V(size<0>(max) == size<0>(tensor));
|
||||
@@ -164,7 +163,6 @@ __forceinline__ __device__ void max_scale_exp2_sum(Tensor<Engine0, Layout0> &ten
|
||||
}
|
||||
}
|
||||
|
||||
// Apply the exp to all the elements.
|
||||
template <bool Scale_max=true, bool Check_inf=true, typename Engine0, typename Layout0, typename Engine1, typename Layout1>
|
||||
__forceinline__ __device__ void scale_apply_exp2(Tensor<Engine0, Layout0> &tensor, Tensor<Engine1, Layout1> const &max, const float scale) {
|
||||
static_assert(Layout0::rank == 2, "Only support 2D Tensor");
|
||||
|
||||
@@ -79,7 +79,6 @@ if n % 128 != 0:
|
||||
else:
|
||||
q_padded = q
|
||||
|
||||
# use torch transpose + scaled_fp4_quant to get the ground truth
|
||||
q_padded = q_padded.transpose(2, 3).reshape(b, h, n_padded, d).contiguous()
|
||||
o_gt = torch.empty((b, h, n_padded, d // 2), dtype=torch.uint8, device='cuda')
|
||||
o_s_gt = torch.empty((b, h, n_padded, d // 16), dtype=torch.float8_e4m3fn, device='cuda')
|
||||
|
||||
@@ -127,11 +127,9 @@ def bench_kineto(fn,
|
||||
if not using_nsys:
|
||||
profiler.step()
|
||||
|
||||
# Return 1 if using Nsight Systems
|
||||
if using_nsys:
|
||||
return 1
|
||||
|
||||
# Parse the profiling table
|
||||
assert isinstance(kernel_names, str) or isinstance(kernel_names, tuple)
|
||||
is_tupled = isinstance(kernel_names, tuple)
|
||||
prof_lines = profiler.key_averages().table(sort_by='cuda_time_total', max_name_column_width=100).split('\n')
|
||||
@@ -140,11 +138,9 @@ def bench_kineto(fn,
|
||||
for name in kernel_names:
|
||||
assert sum([name in line for line in prof_lines]) == 1, f'Errors of the kernel {name} in the profiling table'
|
||||
|
||||
# Save chrome traces
|
||||
if trace_path is not None:
|
||||
profiler.export_chrome_trace(trace_path)
|
||||
|
||||
# Return average kernel times
|
||||
units = {'ms': 1e3, 'us': 1e6}
|
||||
kernel_times = []
|
||||
for name in kernel_names:
|
||||
|
||||
@@ -125,7 +125,6 @@
|
||||
using Type = __nv_bfloat162;
|
||||
};
|
||||
|
||||
// Define a 32 bytes packed data type.
|
||||
template <class Type>
|
||||
struct PackedVec {
|
||||
typename TypeConverter<Type>::Type elts[8];
|
||||
@@ -152,7 +151,6 @@
|
||||
|
||||
constexpr uint32_t NUM_THREADS_PER_TOKEN = head_dim / CVT_FP4_ELTS_PER_THREAD;
|
||||
|
||||
// load input
|
||||
const int token_id = token_block_id * BLOCK_SIZE + threadIdx.x / NUM_THREADS_PER_TOKEN;
|
||||
|
||||
int load_token_id;
|
||||
@@ -183,7 +181,6 @@
|
||||
(threadIdx.x % NUM_THREADS_PER_TOKEN) * CVT_FP4_ELTS_PER_THREAD)[0]; // feature dim
|
||||
}
|
||||
|
||||
// calculate max of every consecutive 16 elements
|
||||
auto localMax = __habs2(in_vec.elts[0]);
|
||||
#pragma unroll
|
||||
for (int i = 1; i < CVT_FP4_ELTS_PER_THREAD / 2; i++) { // local max
|
||||
@@ -204,7 +201,6 @@
|
||||
|
||||
float SFValueInv = (SFValue == 0.0f) ? 0.0f : 1.0f / SFValue;
|
||||
|
||||
// convert input to float2 and apply scale
|
||||
float2 fp2Vals[CVT_FP4_ELTS_PER_THREAD / 2];
|
||||
|
||||
#pragma unroll
|
||||
@@ -218,7 +214,6 @@
|
||||
fp2Vals[i].y = fp2Vals[i].y * SFValueInv;
|
||||
}
|
||||
|
||||
// convert to e2m1
|
||||
uint32_t e2m1Vals[CVT_FP4_ELTS_PER_THREAD / 8];
|
||||
#pragma unroll
|
||||
for (int i = 0; i < CVT_FP4_ELTS_PER_THREAD / 8; i++) {
|
||||
@@ -229,7 +224,6 @@
|
||||
// is not a multiple of BLOCK_SIZE (out-of-bounds write fix).
|
||||
if (token_id >= num_tokens) return;
|
||||
|
||||
// save
|
||||
if constexpr (CVT_FP4_ELTS_PER_THREAD == 8) {
|
||||
reinterpret_cast<uint32_t*>(output +
|
||||
batch_id * stride_bz_output +
|
||||
@@ -284,7 +278,6 @@
|
||||
constexpr uint32_t NUM_THREADS_PER_TOKEN = head_dim / CVT_FP4_ELTS_PER_THREAD;
|
||||
constexpr uint32_t NUM_THREADS_PER_SEQ = BLOCK_SIZE / CVT_FP4_ELTS_PER_THREAD;
|
||||
|
||||
// load input
|
||||
const int token_id = token_block_id * BLOCK_SIZE + threadIdx.x / NUM_THREADS_PER_TOKEN;
|
||||
|
||||
PackedVec in_vec;
|
||||
@@ -312,7 +305,6 @@
|
||||
in_vec.elts[i].y = shared_input[(threadIdx.x / NUM_THREADS_PER_SEQ) + ((threadIdx.x % NUM_THREADS_PER_SEQ) * CVT_FP4_ELTS_PER_THREAD + 2 * i + 1) * head_dim];
|
||||
}
|
||||
|
||||
// calculate max of every consecutive 16 elements
|
||||
auto localMax = __habs2(in_vec.elts[0]);
|
||||
#pragma unroll
|
||||
for (int i = 1; i < CVT_FP4_ELTS_PER_THREAD / 2; i++) { // local max
|
||||
@@ -333,7 +325,6 @@
|
||||
|
||||
float SFValueInv = (SFValue == 0.0f) ? 0.0f : 1.0f / SFValue;
|
||||
|
||||
// convert input to float2 and apply scale
|
||||
float2 fp2Vals[CVT_FP4_ELTS_PER_THREAD / 2];
|
||||
|
||||
#pragma unroll
|
||||
@@ -347,7 +338,6 @@
|
||||
fp2Vals[i].y = fp2Vals[i].y * SFValueInv;
|
||||
}
|
||||
|
||||
// convert to e2m1
|
||||
uint32_t e2m1Vals[CVT_FP4_ELTS_PER_THREAD / 8];
|
||||
#pragma unroll
|
||||
for (int i = 0; i < CVT_FP4_ELTS_PER_THREAD / 8; i++) {
|
||||
@@ -360,7 +350,6 @@
|
||||
(threadIdx.x % NUM_THREADS_PER_SEQ) * CVT_FP4_ELTS_PER_THREAD;
|
||||
if (write_token_id >= num_tokens) return;
|
||||
|
||||
// save
|
||||
if constexpr (CVT_FP4_ELTS_PER_THREAD == 8) {
|
||||
reinterpret_cast<uint32_t*>(output +
|
||||
batch_id * stride_bz_output +
|
||||
|
||||
@@ -224,8 +224,6 @@ export CMAKE_ARGS
|
||||
echo "TORCH_CUDA_ARCH_LIST: ${TORCH_CUDA_ARCH_LIST:-<unset>}"
|
||||
echo "CMAKE_ARGS: ${CMAKE_ARGS:-<unset>}"
|
||||
echo "GPU_BACKEND: ${GPU_BACKEND:-<unset>}"
|
||||
# Build and install
|
||||
# Use -v for verbose output
|
||||
if [ -n "${WHEEL_DIR}" ]; then
|
||||
mkdir -p "${WHEEL_DIR}"
|
||||
uv build --wheel -v --no-build-isolation --out-dir "${WHEEL_DIR}" .
|
||||
|
||||
@@ -65,7 +65,7 @@ template<int D> struct fwd_globals {
|
||||
|
||||
template<int D>
|
||||
__global__ __launch_bounds__(128, 4)
|
||||
void fwd_attend_ker(const __grid_constant__ fwd_globals<D> g) { // use block size of 64
|
||||
void fwd_attend_ker(const __grid_constant__ fwd_globals<D> g) {
|
||||
#if FASTVIDEO_TK_HOPPER
|
||||
extern __shared__ int __shm[];
|
||||
tma_swizzle_allocator al((int*)&__shm[0]);
|
||||
@@ -138,7 +138,6 @@ void fwd_attend_ker(const __grid_constant__ fwd_globals<D> g) { // use block siz
|
||||
// wait k
|
||||
wait(k_smem_arrived, kv_idx % 2);
|
||||
|
||||
// compute QK^T
|
||||
warpgroup::mm_ABt(att_block, q_smem[0], k_smem[0]);
|
||||
|
||||
copy(max_vec_last_scaled, max_vec);
|
||||
@@ -147,7 +146,6 @@ void fwd_attend_ker(const __grid_constant__ fwd_globals<D> g) { // use block siz
|
||||
|
||||
warpgroup::mma_async_wait();
|
||||
|
||||
// load K
|
||||
if (threadIdx.x == 0) {
|
||||
tma::expect_bytes(k_smem_arrived, sizeof(k_tile));
|
||||
coord<k_tile> k_tile_idx = {blockIdx.z, kv_head_idx, kv_block_index, 0};
|
||||
@@ -180,11 +178,9 @@ void fwd_attend_ker(const __grid_constant__ fwd_globals<D> g) { // use block siz
|
||||
// wait v
|
||||
wait(v_smem_arrived, kv_idx % 2);
|
||||
|
||||
// compute SV
|
||||
warpgroup::mma_AB(o_reg, att_block_mma, v_smem[0]);
|
||||
warpgroup::mma_async_wait();
|
||||
|
||||
// load V
|
||||
if (threadIdx.x == 0) {
|
||||
tma::expect_bytes(v_smem_arrived, sizeof(v_tile));
|
||||
coord<v_tile> v_tile_idx = {blockIdx.z, kv_head_idx, kv_block_index, 0};
|
||||
@@ -198,7 +194,6 @@ void fwd_attend_ker(const __grid_constant__ fwd_globals<D> g) { // use block siz
|
||||
// wait k
|
||||
wait(k_smem_arrived, kv_idx % 2);
|
||||
|
||||
// compute QK^T
|
||||
warpgroup::mm_ABt(att_block, q_smem[0], k_smem[0]);
|
||||
|
||||
copy(max_vec_last_scaled, max_vec);
|
||||
@@ -234,7 +229,6 @@ void fwd_attend_ker(const __grid_constant__ fwd_globals<D> g) { // use block siz
|
||||
// wait v
|
||||
wait(v_smem_arrived, kv_idx % 2);
|
||||
|
||||
// compute SV
|
||||
warpgroup::mma_AB(o_reg, att_block_mma, v_smem[0]);
|
||||
warpgroup::mma_async_wait();
|
||||
}
|
||||
@@ -550,7 +544,6 @@ void bwd_attend_ker(const __grid_constant__ bwd_globals<D> g) {
|
||||
if constexpr (D == 64) { mul(ds_block_t, ds_block_t, 0.125f); }
|
||||
else { mul(ds_block_t, ds_block_t, 0.08838834764f); }
|
||||
|
||||
// load vec
|
||||
if (threadIdx.x == 0) {
|
||||
coord<l_tile> vec_idx = {blockIdx.z, blockIdx.y, 0, load_q_block_index};
|
||||
tma::expect_bytes(vec_b[0], sizeof(l_smem[0]) + sizeof(d_smem[0]));
|
||||
@@ -564,7 +557,6 @@ void bwd_attend_ker(const __grid_constant__ bwd_globals<D> g) {
|
||||
warpgroup::store(ds_smem_t[0], ds_block_t);
|
||||
warpgroup::mma_async_wait();
|
||||
|
||||
// load og
|
||||
if (threadIdx.x == 0) {
|
||||
coord<q_tile> tile_idx = {blockIdx.z, blockIdx.y, load_q_block_index, 0};
|
||||
tma::expect_bytes(o_b[0], sizeof(og_smem[0]));
|
||||
@@ -575,7 +567,6 @@ void bwd_attend_ker(const __grid_constant__ bwd_globals<D> g) {
|
||||
warpgroup::mma_commit_group();
|
||||
warpgroup::mma_async_wait();
|
||||
|
||||
// load q
|
||||
if (threadIdx.x == 0) {
|
||||
coord<q_tile> q_tile_idx = {blockIdx.z, blockIdx.y, load_q_block_index, 0};
|
||||
tma::expect_bytes(q_b[0], sizeof(q_smem[0]));
|
||||
@@ -587,11 +578,9 @@ void bwd_attend_ker(const __grid_constant__ bwd_globals<D> g) {
|
||||
warpgroup::mm_AtB(qg_reg, ds_smem_t[0], k_smem[0]); //delat dQ = dSK
|
||||
warpgroup::mma_commit_group();
|
||||
warpgroup::mma_async_wait();
|
||||
// store qg to shared memory
|
||||
warpgroup::store(qg_smem, qg_reg);
|
||||
__syncthreads();
|
||||
|
||||
// store and add dQ to global memory
|
||||
if (threadIdx.x / 32 == 0) {
|
||||
coord<qg_tile> tile_idx = {blockIdx.z, blockIdx.y, store_qg_block_index, 0};
|
||||
tma::store_add_async(g.qg, qg_smem, tile_idx);
|
||||
@@ -643,11 +632,9 @@ void bwd_attend_ker(const __grid_constant__ bwd_globals<D> g) {
|
||||
warpgroup::mm_AtB(qg_reg, ds_smem_t[0], k_smem[0]); //delat dQ = dSK
|
||||
warpgroup::mma_commit_group();
|
||||
warpgroup::mma_async_wait();
|
||||
// store qg to shared memory
|
||||
warpgroup::store(qg_smem, qg_reg);
|
||||
__syncthreads();
|
||||
|
||||
// store and add dQ to global memory
|
||||
if (threadIdx.x / 32 == 0) {
|
||||
coord<qg_tile> tile_idx = {blockIdx.z, blockIdx.y, store_qg_block_index, 0};
|
||||
tma::store_add_async(g.qg, qg_smem, tile_idx);
|
||||
@@ -655,7 +642,6 @@ void bwd_attend_ker(const __grid_constant__ bwd_globals<D> g) {
|
||||
}
|
||||
}
|
||||
|
||||
// store kq and vq
|
||||
|
||||
// ! the following two line seems unnecessary.
|
||||
// tma::store_async_wait(); // ensure qg is finished
|
||||
@@ -768,7 +754,6 @@ block_sparse_attention_forward(
|
||||
float* l_ptr = reinterpret_cast<float*>(l_vec.data_ptr<float>());
|
||||
float* d_l = reinterpret_cast<float*>(l_ptr);
|
||||
|
||||
//cudadevicesynchronize();
|
||||
const c10::cuda::OptionalCUDAGuard device_guard(q.device());
|
||||
const cudaStream_t stream = at::cuda::getCurrentCUDAStream().stream();
|
||||
|
||||
@@ -820,7 +805,6 @@ block_sparse_attention_forward(
|
||||
fwd_attend_ker<64><<<grid, (128), mem_size, stream>>>(g);
|
||||
|
||||
CHECK_CUDA_ERROR(cudaGetLastError());
|
||||
// cudaStreamSynchronize(stream);
|
||||
}
|
||||
|
||||
if (head_dim == 128) {
|
||||
@@ -871,11 +855,9 @@ block_sparse_attention_forward(
|
||||
fwd_attend_ker<128><<<grid, (128), mem_size, stream>>>(g);
|
||||
|
||||
CHECK_CUDA_ERROR(cudaGetLastError());
|
||||
// cudaStreamSynchronize(stream);
|
||||
}
|
||||
|
||||
return {o, l_vec};
|
||||
//cudadevicesynchronize();
|
||||
}
|
||||
|
||||
std::vector<torch::Tensor>
|
||||
@@ -996,11 +978,9 @@ block_sparse_attention_backward(torch::Tensor q,
|
||||
constexpr int mem_size = kittens::MAX_SHARED_MEMORY;
|
||||
int threads = PREP_NUM_WARPS * kittens::WARP_THREADS;
|
||||
|
||||
//cudadevicesynchronize();
|
||||
const c10::cuda::OptionalCUDAGuard device_guard(q.device());
|
||||
const cudaStream_t stream = at::cuda::getCurrentCUDAStream().stream();
|
||||
|
||||
// cudaStreamSynchronize(stream);
|
||||
|
||||
// TORCH_CHECK(seq_len % (4*kittens::TILE_DIM*4) == 0, "sequence length must be divisible by 256");
|
||||
dim3 grid_bwd(q_seq_len/(PREP_NUM_WARPS*kittens::TILE_ROW_DIM<bf16>*4), qo_heads, batch);
|
||||
@@ -1084,7 +1064,6 @@ block_sparse_attention_backward(torch::Tensor q,
|
||||
dim3 grid_bwd_2(kv_seq_len/BLOCK_N, qo_heads, batch);
|
||||
threads = 128;
|
||||
|
||||
//cudadevicesynchronize();
|
||||
|
||||
{
|
||||
cudaFuncSetAttribute(
|
||||
@@ -1101,12 +1080,6 @@ block_sparse_attention_backward(torch::Tensor q,
|
||||
bwd_attend_ker<64><<<grid_bwd_2, threads, 72000, stream>>>(bwd_global);
|
||||
}
|
||||
|
||||
// CHECK_CUDA_ERROR(cudaGetLastError());
|
||||
// cudaStreamSynchronize(stream);
|
||||
//cudadevicesynchronize();
|
||||
// const auto kernel_end = std::chrono::high_resolution_clock::now();
|
||||
// std::cout << "Kernel Time: " << std::chrono::duration_cast<std::chrono::microseconds>(kernel_end - start).count() << "us" << std::endl;
|
||||
// std::cout << "---" << std::endl;
|
||||
}
|
||||
|
||||
if (head_dim == 128) {
|
||||
@@ -1188,7 +1161,6 @@ block_sparse_attention_backward(torch::Tensor q,
|
||||
dim3 grid_bwd_2(kv_seq_len/BLOCK_N, qo_heads, batch);
|
||||
threads = 128;
|
||||
|
||||
//cudadevicesynchronize();
|
||||
|
||||
{
|
||||
cudaFuncSetAttribute(
|
||||
@@ -1200,10 +1172,7 @@ block_sparse_attention_backward(torch::Tensor q,
|
||||
bwd_attend_ker<128><<<grid_bwd_2, threads, 113000, stream>>>(bwd_global);
|
||||
}
|
||||
|
||||
// cudaStreamSynchronize(stream);
|
||||
//cudadevicesynchronize();
|
||||
}
|
||||
|
||||
return {qg, kg, vg};
|
||||
//cudadevicesynchronize();
|
||||
}
|
||||
@@ -310,9 +310,7 @@ void fwd_attend_ker(const __grid_constant__ fwd_globals<D> g) {
|
||||
else { mul(max_vec_last_scaled, max_vec_last_scaled, 1.44269504089f*0.08838834764f); }
|
||||
|
||||
warpgroup::mma_async_wait();
|
||||
// apply non-pad mask
|
||||
int offset = g.text_L - (kv_idx - (kv_iters + 1)) * K::kv_height;
|
||||
// printf("k_idx_start: %d, k_idx_end: %d, text_end: %d, offset: %d\n", k_idx_start, k_idx_end, text_end, offset);
|
||||
right_fill(att_block, att_block, offset, base_types::constants<float>::neg_infty());
|
||||
|
||||
|
||||
@@ -437,7 +435,6 @@ sta_forward(torch::Tensor q, torch::Tensor k, torch::Tensor v, torch::Tensor o,
|
||||
float* l_ptr = reinterpret_cast<float*>(l_vec.data_ptr<float>());
|
||||
float* d_l = reinterpret_cast<float*>(l_ptr);
|
||||
|
||||
//cudadevicesynchronize();
|
||||
const c10::cuda::OptionalCUDAGuard device_guard(q.device());
|
||||
const cudaStream_t stream = at::cuda::getCurrentCUDAStream().stream();
|
||||
|
||||
@@ -578,10 +575,8 @@ sta_forward(torch::Tensor q, torch::Tensor k, torch::Tensor v, torch::Tensor o,
|
||||
|
||||
}
|
||||
CHECK_CUDA_ERROR(cudaGetLastError());
|
||||
// cudaStreamSynchronize(stream);
|
||||
}
|
||||
|
||||
return o;
|
||||
//cudadevicesynchronize();
|
||||
}
|
||||
|
||||
|
||||
@@ -267,7 +267,6 @@ void ulysses_a2a_tuned(int64_t handle, torch::Tensor inp, torch::Tensor out, int
|
||||
#undef LAUNCH_ULYSSES_A2A
|
||||
|
||||
TORCH_CHECK(cudaGetLastError() == cudaSuccess, "ulysses_a2a kernel launch failed");
|
||||
// Copy this rank's completed result out of the window.
|
||||
auto status = cudaMemcpyAsync(out.data_ptr(), ctx->buf, out_bytes, cudaMemcpyDeviceToDevice,
|
||||
stream);
|
||||
TORCH_CHECK(status == cudaSuccess, "ulysses_a2a copy-out failed: ", cudaGetErrorString(status));
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
#include <ATen/ATen.h>
|
||||
#include <vector>
|
||||
|
||||
// Forward declarations
|
||||
#ifdef TK_COMPILE_ST_ATTN
|
||||
extern torch::Tensor sta_forward(
|
||||
torch::Tensor q, torch::Tensor k, torch::Tensor v, torch::Tensor o,
|
||||
|
||||
@@ -295,7 +295,6 @@ struct GemmKernel {
|
||||
SmemLayoutB{}
|
||||
);
|
||||
|
||||
// register
|
||||
TiledMma tiled_mma;
|
||||
auto thr_mma = tiled_mma.get_slice(t_idx);
|
||||
auto tCrA = thr_mma.partition_fragment_A(gA(_, _, 0));
|
||||
@@ -314,7 +313,6 @@ struct GemmKernel {
|
||||
clear(tDrD);
|
||||
|
||||
|
||||
// global to shared copy
|
||||
G2STiledCopyA g2s_tiled_copy_a;
|
||||
auto g2s_thr_copy_a = g2s_tiled_copy_a.get_slice(t_idx);
|
||||
auto tAgA = g2s_thr_copy_a.partition_S(gA);
|
||||
@@ -371,7 +369,6 @@ struct GemmKernel {
|
||||
int32_t fallbackA_load = 0;
|
||||
int32_t fallbackA_mma = 0;
|
||||
|
||||
// copy first Stage - 1 tile
|
||||
CUTLASS_PRAGMA_UNROLL
|
||||
for (int i = 0, _i = min(Stage - 1, ntile); i < _i; ++i) {
|
||||
if (g2s_b_tile < ntile) {
|
||||
@@ -410,8 +407,6 @@ struct GemmKernel {
|
||||
// a s2r increase anyway
|
||||
s2r_a_smem = (s2r_a_smem + 1) % Stage;
|
||||
|
||||
// get next s2r b tile int64_t
|
||||
// end of a block
|
||||
|
||||
// dequant first
|
||||
dequant<AccumulatorDtype, TileM * TileN / ThreadNum, FastInt2Float>(
|
||||
@@ -425,7 +420,6 @@ struct GemmKernel {
|
||||
mma_block_a = mma_block_b;
|
||||
if (mma_block_a < size<1>(AS)) scale_a = AS(blk_m_coord, mma_block_a);
|
||||
|
||||
// load next stage
|
||||
if (g2s_b_tile < ntile) {
|
||||
g2s_tile_in_block = (g2s_tile_in_block + 1) % NumTilePerBlock;
|
||||
copy_AB<IsEvenM>(g2s_tiled_copy_a, tAgA, tAsA, tAcA, g2s_a_tile, g2s_a_smem, m_limit);
|
||||
|
||||
@@ -61,7 +61,6 @@ public:
|
||||
int tidx = threadIdx.x;
|
||||
float x[NumElementPerThread];
|
||||
|
||||
// load
|
||||
Loader<InputDtype, 1, MaxHiddenSize, NumThrPerCta, true, IsEven> loader;
|
||||
loader.load(params.Iptr, x, params.m, params.n, blk_m, 0, tidx);
|
||||
|
||||
@@ -86,7 +85,6 @@ public:
|
||||
}
|
||||
|
||||
__syncthreads();
|
||||
// var reduction
|
||||
float v = sqrtf(_reduce_square(x, shared_data) / params.n + params.eps);
|
||||
|
||||
CUTLASS_PRAGMA_UNROLL
|
||||
@@ -94,7 +92,6 @@ public:
|
||||
x[i] /= v;
|
||||
|
||||
if constexpr (Affine) {
|
||||
// load weight
|
||||
Loader<WeightDtype, 1, MaxHiddenSize, NumThrPerCta, true, IsEven> weight_loader;
|
||||
float w[NumElementPerThread];
|
||||
weight_loader.load(params.Wptr, w, 1, params.n, 0, 0, tidx);
|
||||
@@ -111,7 +108,6 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
// save y
|
||||
{
|
||||
Saver<OutputDtype, 1, MaxHiddenSize, NumThrPerCta, true, IsEven, false, false> saver;
|
||||
if constexpr (std::is_same_v<OutputDtype, float>) {
|
||||
|
||||
@@ -56,14 +56,12 @@ public:
|
||||
int tidx = threadIdx.x;
|
||||
float x[NumElementPerThread];
|
||||
|
||||
// load
|
||||
Loader<InputDtype, 1, MaxHiddenSize, NumThrPerCta, true, IsEven> loader;
|
||||
loader.load(params.Iptr, x, params.m, params.n, blk_m, 0, tidx);
|
||||
|
||||
// rms reduction
|
||||
float rms = sqrtf(_reduce_square(x, shared_data) / params.n + params.eps);
|
||||
|
||||
// load weight
|
||||
Loader<WeightDtype, 1, MaxHiddenSize, NumThrPerCta, true, IsEven> weight_loader;
|
||||
float w[NumElementPerThread];
|
||||
loader.load(params.Wptr, w, 1, params.n, 0, 0, tidx);
|
||||
@@ -73,7 +71,6 @@ public:
|
||||
for (int i = 0; i < NumElementPerThread; ++i)
|
||||
x[i] = w[i] * x[i] / rms ;
|
||||
|
||||
// save y
|
||||
OutputDtype *output_reg = (OutputDtype*)x;
|
||||
if constexpr (!std::is_same_v<OutputDtype, float>) {
|
||||
output_reg = (OutputDtype*)w;
|
||||
|
||||
@@ -109,7 +109,6 @@ public:
|
||||
|
||||
float float_reg[NumElementPerThread];
|
||||
|
||||
// load float32 data
|
||||
Loader<InputDtype, BlockSize, BlockSize, NumThrPerCta, IsEvenM, IsEvenN> loader;
|
||||
loader.load(params.Iptr, float_reg, params.m, params.n, blk_m, blk_n, tidx);
|
||||
quantization(
|
||||
|
||||
@@ -9,7 +9,6 @@ import triton.language as tl
|
||||
from triton.tools.tensor_descriptor import TensorDescriptor
|
||||
|
||||
from .quant_utils import fake_quantize_q, fake_quantize_kv, fake_quantize
|
||||
# from attn_qat_infer.api import triton_group_mean
|
||||
|
||||
|
||||
def is_cuda():
|
||||
@@ -141,7 +140,6 @@ def _attn_fwd_inner(acc,
|
||||
elif STAGE == 2:
|
||||
lo, hi = start_m * BLOCK_M, (start_m + 1) * BLOCK_M
|
||||
lo = tl.multiple_of(lo, BLOCK_M)
|
||||
# causal = False
|
||||
else:
|
||||
lo, hi = 0, N_CTX
|
||||
offsetk_y = offset_y + lo # offset from the start of the current batch-head combination
|
||||
@@ -149,7 +147,6 @@ def _attn_fwd_inner(acc,
|
||||
offsetv_y = offset_y * HEAD_DIM + lo
|
||||
else:
|
||||
offsetv_y = offset_y + lo
|
||||
# loop over k, v and update accumulator
|
||||
for start_n in tl.range(lo, hi, BLOCK_N, warp_specialize=warp_specialize):
|
||||
start_n = tl.multiple_of(start_n, BLOCK_N)
|
||||
kv_valid = (start_n + offs_n) < N_CTX
|
||||
@@ -191,7 +188,6 @@ def _attn_fwd_inner(acc,
|
||||
acc = acc * alpha[:, None]
|
||||
if IS_QAT:
|
||||
high_prec_acc = high_prec_acc * alpha[:, None]
|
||||
# prepare p and v for the dot
|
||||
if dtype == tl.float8e5:
|
||||
v = desc_v.load([0, offsetv_y]).T
|
||||
else:
|
||||
@@ -298,7 +294,6 @@ configs = [
|
||||
for s in NUM_STAGES_OPTIONS for w in [4, 8]
|
||||
]
|
||||
if "PYTEST_VERSION" in os.environ:
|
||||
# Use a single config in testing for reproducibility
|
||||
configs = [
|
||||
triton.Config(dict(BLOCK_M=128, BLOCK_N=64), num_stages=2, num_warps=4, pre_hook=_host_descriptor_pre_hook),
|
||||
]
|
||||
@@ -329,8 +324,6 @@ def _maybe_make_tensor_desc(desc_or_ptr, shape, strides, block_shape):
|
||||
return tl.make_tensor_descriptor(desc_or_ptr, shape, strides, block_shape)
|
||||
|
||||
|
||||
# @triton.autotune(configs=list(filter(keep, configs)), key=["N_CTX_Q", "N_CTX_KV", "HEAD_DIM", "FP8_OUTPUT", "warp_specialize"],
|
||||
# prune_configs_by={'early_config_prune': prune_invalid_configs}, cache_results=True)
|
||||
@triton.jit
|
||||
def _attn_fwd(
|
||||
sm_scale,
|
||||
@@ -398,11 +391,9 @@ def _attn_fwd(
|
||||
offset_y_q = off_z * (N_CTX_Q * H) + off_h * N_CTX_Q # offset for query tensor
|
||||
offset_y_kv = off_z * (N_CTX_KV * H) + off_h * N_CTX_KV # offset for key/value tensors
|
||||
qo_offset_y = offset_y_q + start_m * BLOCK_M
|
||||
# initialize offsets
|
||||
offs_m = start_m * BLOCK_M + tl.arange(0, BLOCK_M)
|
||||
offs_n = tl.arange(0, BLOCK_N) # for kv blocks
|
||||
q_valid = offs_m < N_CTX_Q
|
||||
# initialize pointer to m and l
|
||||
m_i = tl.zeros([BLOCK_M], dtype=tl.float32) - float("inf")
|
||||
l_i = tl.zeros([BLOCK_M], dtype=tl.float32) + 1.0
|
||||
acc = tl.zeros([BLOCK_M, HEAD_DIM], dtype=tl.float32)
|
||||
@@ -411,10 +402,8 @@ def _attn_fwd(
|
||||
else:
|
||||
# dummy value
|
||||
high_prec_acc = acc
|
||||
# load scales
|
||||
qk_scale = sm_scale
|
||||
qk_scale *= 1.44269504 # 1/log(2)
|
||||
# load q: it will stay in SRAM throughout
|
||||
q = desc_q.load([qo_offset_y, 0]) # load from start of q block and start of the entire head dimension
|
||||
q = tl.where(q_valid[:, None], q, 0.0)
|
||||
# stage 1: off-band
|
||||
@@ -434,7 +423,6 @@ def _attn_fwd(
|
||||
BLOCK_N, 4 - STAGE, offs_m, offs_n, N_CTX_KV,
|
||||
warp_specialize, IS_HOPPER, IS_QAT, fake_quant_P,
|
||||
two_level_quant_P, use_global_sf_P, JOIN_QAT_PV)
|
||||
# stage 2: on-band
|
||||
if STAGE & 2:
|
||||
acc, high_prec_acc, l_i, m_i = _attn_fwd_inner(acc, high_prec_acc, l_i, m_i, q, q_valid, desc_k, desc_v,
|
||||
offset_y_kv, dtype, start_m, qk_scale, BLOCK_M, HEAD_DIM,
|
||||
@@ -505,12 +493,10 @@ def _attn_bwd_preprocess(O, DO, Delta, Z, H, N_CTX, BLOCK_M: tl.constexpr, HEAD_
|
||||
off_hz = tl.program_id(1)
|
||||
off_n = tl.arange(0, HEAD_DIM)
|
||||
valid = off_m < N_CTX
|
||||
# load
|
||||
o = tl.load(O + off_hz * HEAD_DIM * N_CTX + off_m[:, None] * HEAD_DIM + off_n[None, :], mask=valid[:, None])
|
||||
do = tl.load(DO + off_hz * HEAD_DIM * N_CTX + off_m[:, None] * HEAD_DIM + off_n[None, :],
|
||||
mask=valid[:, None]).to(tl.float32)
|
||||
delta = tl.sum(o * do, axis=1)
|
||||
# write-back
|
||||
tl.store(Delta + off_hz * N_CTX + off_m, delta, mask=valid)
|
||||
|
||||
|
||||
@@ -573,7 +559,6 @@ def _attn_bwd_dkdv(
|
||||
qk = tl.where(mask, qk, -1.0e6)
|
||||
p = tl.math.exp2(qk - m[:, None])
|
||||
do = tl.load(do_ptrs, mask=q_valid[:, None])
|
||||
# Compute dV.
|
||||
p_quant = p
|
||||
if IS_QAT and fake_quant_P:
|
||||
p_quant, _ = fake_quantize(src_tensor=p,
|
||||
@@ -586,7 +571,6 @@ def _attn_bwd_dkdv(
|
||||
dv += tl.dot(tl.trans(p_quant.to(tl.bfloat16)), do)
|
||||
# D (= delta) is pre-divided by ds_scale.
|
||||
Di = tl.load(D + offs_m, mask=q_valid)
|
||||
# Compute dP and dS.
|
||||
dp = tl.dot(do, tl.trans(v))
|
||||
ds = p * (dp - Di[:, None])
|
||||
ds = ds.to(tl.bfloat16)
|
||||
@@ -659,7 +643,6 @@ def _attn_bwd_dq(
|
||||
mask = (offs_m[:, None] >= offs_n[None, :])
|
||||
qk = tl.where(mask, qk, -1.0e6)
|
||||
p = tl.math.exp2(qk - m)
|
||||
# Compute dP and dS.
|
||||
dp = tl.dot(do, tl.trans(v))
|
||||
ds = p * (dp - Di[:, None])
|
||||
# Compute dQ.
|
||||
@@ -1037,7 +1020,6 @@ def _attn_bwd(
|
||||
if SMOOTH_Q:
|
||||
Q_MEAN += adj
|
||||
|
||||
# load scales
|
||||
offs_k = tl.arange(0, HEAD_DIM)
|
||||
|
||||
start_n = pid * BLOCK_N1
|
||||
@@ -1050,7 +1032,6 @@ def _attn_bwd(
|
||||
dv = tl.zeros([BLOCK_N1, HEAD_DIM], dtype=tl.float32)
|
||||
dk = tl.zeros([BLOCK_N1, HEAD_DIM], dtype=tl.float32)
|
||||
|
||||
# load K and V: they stay in SRAM throughout the inner loop.
|
||||
k = tl.load(K + offs_n[:, None] * stride_tok + offs_k[None, :] * stride_d, mask=kv_valid[:, None])
|
||||
v = tl.load(V + offs_n[:, None] * stride_tok + offs_k[None, :] * stride_d, mask=kv_valid[:, None])
|
||||
|
||||
@@ -1101,7 +1082,6 @@ def _attn_bwd(
|
||||
start_m = 0
|
||||
num_steps = (N_CTX + BLOCK_M1 - 1) // BLOCK_M1
|
||||
|
||||
# Compute dK and dV for non-masked blocks.
|
||||
dk, dv = _attn_bwd_dkdv(dk,
|
||||
dv,
|
||||
Q,
|
||||
@@ -1133,7 +1113,6 @@ def _attn_bwd(
|
||||
dv_ptrs = DV + offs_n[:, None] * stride_tok + offs_k[None, :] * stride_d
|
||||
tl.store(dv_ptrs, dv, mask=kv_valid[:, None])
|
||||
|
||||
# Write back dK.
|
||||
dk *= sm_scale
|
||||
dk_ptrs = DK + offs_n[:, None] * stride_tok + offs_k[None, :] * stride_d
|
||||
tl.store(dk_ptrs, dk, mask=kv_valid[:, None])
|
||||
@@ -1185,14 +1164,12 @@ def _attn_bwd(
|
||||
warp_specialize=warp_specialize,
|
||||
)
|
||||
end_n -= num_steps * MASK_BLOCK_N2
|
||||
# stage 2: process KV blocks from 0 to end_n (before diagonal), ceiling division to include remainder
|
||||
num_steps = (end_n + BLOCK_N2 - 1) // BLOCK_N2
|
||||
start_n = 0
|
||||
else:
|
||||
# For non-causal, process all KV blocks from 0 to N_CTX (ceiling division to include remainder)
|
||||
num_steps = (N_CTX + BLOCK_N2 - 1) // BLOCK_N2
|
||||
start_n = 0
|
||||
# stage 2
|
||||
dq = _attn_bwd_dq(
|
||||
dq,
|
||||
q,
|
||||
@@ -1299,7 +1276,6 @@ class _attention(torch.autograd.Function):
|
||||
if IS_QAT:
|
||||
high_prec_o = torch.empty_like(q)
|
||||
else:
|
||||
# Initialize to a dummy value
|
||||
high_prec_o = o
|
||||
stage = 3 if causal else 1
|
||||
extra_kern_args = {}
|
||||
@@ -1442,7 +1418,6 @@ class _attention(torch.autograd.Function):
|
||||
use_global_sf=use_global_sf_QKV,
|
||||
)
|
||||
|
||||
# Apply pre-hook to set block shapes on tensor descriptors
|
||||
_host_descriptor_pre_hook({
|
||||
"BLOCK_M": fwd_block_m,
|
||||
"BLOCK_N": fwd_block_n,
|
||||
@@ -1647,7 +1622,6 @@ class _attention(torch.autograd.Function):
|
||||
num_stages=dkdv_launch[1],
|
||||
)
|
||||
elif N_CTX_Q == N_CTX_KV:
|
||||
# Use existing kernel for self-attention (same sequence lengths)
|
||||
grid = ((N_CTX_KV + BLOCK_N1 - 1) // BLOCK_N1, 1, BATCH * N_HEAD)
|
||||
_attn_bwd[grid](q,
|
||||
arg_k,
|
||||
@@ -1684,7 +1658,6 @@ class _attention(torch.autograd.Function):
|
||||
num_warps=NUM_WARPS,
|
||||
num_stages=NUM_STAGES)
|
||||
else:
|
||||
# Use separate kernels for cross-attention (different sequence lengths)
|
||||
grid_dq = ((N_CTX_Q + BLOCK_M2 - 1) // BLOCK_M2, 1, BATCH * N_HEAD)
|
||||
_attn_bwd_dq_cross[grid_dq](
|
||||
q,
|
||||
|
||||
@@ -183,11 +183,9 @@ def _attn_bwd_preprocess(
|
||||
off_m = tl.program_id(0) * BLOCK_M + tl.arange(0, BLOCK_M)
|
||||
off_hz = tl.program_id(1)
|
||||
off_n = tl.arange(0, HEAD_DIM)
|
||||
# load
|
||||
o = tl.load(O + off_hz * HEAD_DIM * N_CTX + off_m[:, None] * HEAD_DIM + off_n[None, :])
|
||||
do = tl.load(DO + off_hz * HEAD_DIM * N_CTX + off_m[:, None] * HEAD_DIM + off_n[None, :]).to(tl.float32)
|
||||
delta = tl.sum(o * do, axis=1)
|
||||
# write-back
|
||||
tl.store(Delta + off_hz * N_CTX + off_m, delta)
|
||||
|
||||
|
||||
@@ -255,13 +253,11 @@ def _attn_bwd_dkdv(
|
||||
pT = tl.where(mask[:, None], pT, 0.0)
|
||||
|
||||
do = tl.load(do_ptrs + block_sparse_offset * stride_tok)
|
||||
# Compute dV.
|
||||
ppT = pT
|
||||
ppT = ppT.to(tl.bfloat16)
|
||||
dv += tl.dot(ppT, do)
|
||||
# D (= delta) is pre-divided by ds_scale.
|
||||
Di = tl.load(D + offs_m)
|
||||
# Compute dP and dS.
|
||||
dpT = tl.dot(v, tl.trans(do)).to(tl.float32)
|
||||
dsT = pT * (dpT - Di[None, :])
|
||||
dsT = dsT.to(tl.bfloat16)
|
||||
@@ -333,7 +329,6 @@ def _attn_bwd_dq(
|
||||
offs_in_block = half * step_n + tl.arange(0, BLOCK_N2)
|
||||
mask = offs_in_block < block_size
|
||||
p = tl.where(mask[None, :], p, 0.0)
|
||||
# Compute dP and dS.
|
||||
dp = tl.dot(do, vT).to(tl.float32)
|
||||
ds = p * (dp - Di[:, None])
|
||||
ds = ds.to(tl.bfloat16)
|
||||
@@ -392,7 +387,6 @@ def _attn_bwd(
|
||||
M += off_chz
|
||||
D += off_chz
|
||||
|
||||
# load scales
|
||||
offs_k = tl.arange(0, HEAD_DIM)
|
||||
|
||||
start_n = pid * BLOCK_N1
|
||||
@@ -403,7 +397,6 @@ def _attn_bwd(
|
||||
dv = tl.zeros([BLOCK_N1, HEAD_DIM], dtype=tl.float32)
|
||||
dk = tl.zeros([BLOCK_N1, HEAD_DIM], dtype=tl.float32)
|
||||
|
||||
# load K and V: they stay in SRAM throughout the inner loop.
|
||||
k = tl.load(K + offs_n[:, None] * stride_tok + offs_k[None, :] * stride_d)
|
||||
v = tl.load(V + offs_n[:, None] * stride_tok + offs_k[None, :] * stride_d)
|
||||
|
||||
@@ -438,7 +431,6 @@ def _attn_bwd(
|
||||
dv_ptrs = DV + offs_n[:, None] * stride_tok + offs_k[None, :] * stride_d
|
||||
tl.store(dv_ptrs, dv)
|
||||
|
||||
# Write back dK.
|
||||
dk *= sm_scale
|
||||
dk_ptrs = DK + offs_n[:, None] * stride_tok + offs_k[None, :] * stride_d
|
||||
tl.store(dk_ptrs, dk)
|
||||
@@ -481,7 +473,6 @@ def _attn_bwd(
|
||||
end_n,
|
||||
num_steps #
|
||||
)
|
||||
# Write back dQ.
|
||||
dq_ptrs = DQ + offs_m[:, None] * stride_tok + offs_k[None, :] * stride_d
|
||||
dq *= sm_scale
|
||||
tl.store(dq_ptrs, dq)
|
||||
@@ -557,7 +548,6 @@ def _attn_bwd_dkdv_kernel(
|
||||
start_n = kv_blk * BLOCK_N1
|
||||
offs_n = start_n + tl.arange(0, BLOCK_N1)
|
||||
|
||||
# load K and V: they stay in SRAM throughout the inner loop.
|
||||
k = tl.load(K + offs_n[:, None] * stride_tok + offs_k[None, :] * stride_d)
|
||||
v = tl.load(V + offs_n[:, None] * stride_tok + offs_k[None, :] * stride_d)
|
||||
|
||||
|
||||
@@ -165,7 +165,6 @@ def _compute_dequant(
|
||||
if dst_dtype == tl.float16:
|
||||
dst_scale = dst_scale.to(tl.float16)
|
||||
|
||||
# Now upcast the tensor.
|
||||
intermediate_dtype: tl.constexpr = tl.bfloat16 if dst_dtype == tl.float32 else dst_dtype
|
||||
if cuda_capability_geq(10, 0):
|
||||
assert is_fp4
|
||||
@@ -215,7 +214,6 @@ def _compute_dequant(
|
||||
# 2) x is subnormal (x == 0bs001 where s is the sign): Map to +-0.5 in the dst type
|
||||
x0 = tl.where(em0 == 0x01, dst_0p5 | (x0 & 0x8000), x0)
|
||||
x1 = tl.where(em1 == 0x10, dst_0p5 | (x1 & 0x8000), x1)
|
||||
# 3) x is zero, do nothing
|
||||
dst_tensor = tl.interleave(x0, x1).to(intermediate_dtype, bitcast=True)
|
||||
|
||||
dst_tensor = dst_tensor.to(dst_dtype)
|
||||
|
||||
@@ -78,12 +78,10 @@ def _attn_fwd_loop(
|
||||
exp_scores = tl.math.exp2(scores - new_m[:, None])
|
||||
current_l = tl.sum(exp_scores, axis=1)
|
||||
|
||||
# Update L <- L * exp(M - M') + L1, M <- M'
|
||||
alpha = tl.math.exp2(m - new_m)
|
||||
l = l * alpha + current_l
|
||||
m = new_m
|
||||
|
||||
# Update O <- O * exp(M - M') + P @ V
|
||||
acc = (acc * alpha[:, None] + tl.dot(exp_scores.to(v.type.element_ty), v))
|
||||
|
||||
return m, l, acc
|
||||
@@ -286,8 +284,6 @@ def sliding_tile_attention_triton(q: torch.Tensor,
|
||||
|
||||
total_tile_size = tile_t * tile_h * tile_w
|
||||
|
||||
# BLOCK_Q=128
|
||||
# BLOCK_KV=128
|
||||
BLOCK_DIM = head_dim
|
||||
|
||||
output = torch.empty_like(q)
|
||||
@@ -329,8 +325,6 @@ def sliding_tile_attention_triton(q: torch.Tensor,
|
||||
scale=1.0 / (head_dim**0.5),
|
||||
has_text=has_text,
|
||||
text_q=False,
|
||||
# BLOCK_Q=BLOCK_Q,
|
||||
# BLOCK_KV=BLOCK_KV,
|
||||
BLOCK_DIM=BLOCK_DIM,
|
||||
)
|
||||
|
||||
@@ -363,8 +357,6 @@ def sliding_tile_attention_triton(q: torch.Tensor,
|
||||
scale=1.0 / (head_dim**0.5),
|
||||
has_text=has_text,
|
||||
text_q=True,
|
||||
# BLOCK_Q=BLOCK_Q,
|
||||
# BLOCK_KV=BLOCK_KV,
|
||||
BLOCK_DIM=BLOCK_DIM,
|
||||
)
|
||||
|
||||
|
||||
@@ -129,21 +129,17 @@ def _rms_norm_fwd_fused(
|
||||
|
||||
x = tl.load(x_ptr, mask=mask[None, :], other=0.0).to(tl.float32)
|
||||
|
||||
# Compute variance
|
||||
_var = x * x
|
||||
var = tl.sum(_var, axis=1) / N
|
||||
rstd = 1 / tl.sqrt(var + eps)
|
||||
|
||||
# Write mean / rstd
|
||||
tl.store(Rstd + rows, rstd)
|
||||
rstd = tl.reshape(rstd, (BLOCK_M, 1))
|
||||
|
||||
# Normalize and apply linear transformation
|
||||
w = tl.load(W + cols)
|
||||
x_hat = x * rstd
|
||||
y = x_hat * w
|
||||
|
||||
# Write output
|
||||
y = y.to(Y.type.element_ty)
|
||||
tl.store(y_ptr, y, mask=mask[None, :])
|
||||
|
||||
@@ -181,7 +177,6 @@ def rmsnorm(x, w, eps):
|
||||
else:
|
||||
BLOCK_M = 1
|
||||
|
||||
# Call the triton kernel
|
||||
_rms_norm_fwd_fused[(triton.cdiv(M, BLOCK_M), )]( #
|
||||
x,
|
||||
y,
|
||||
@@ -229,20 +224,16 @@ def _layer_norm_param_fwd_fused(
|
||||
|
||||
x = tl.load(x_ptr, mask=mask[None, :], other=0.0).to(tl.float32)
|
||||
|
||||
# Compute mean and Variance
|
||||
mean = tl.sum(x, axis=1, keep_dims=True) / N
|
||||
# Compute variance
|
||||
_var = (x - mean) * (x - mean)
|
||||
var = tl.sum(_var, axis=1, keep_dims=True) / N
|
||||
rstd = 1 / tl.sqrt(var + eps)
|
||||
|
||||
# Write mean / rstd
|
||||
_mean = tl.reshape(mean, (BLOCK_M))
|
||||
_rstd = tl.reshape(rstd, (BLOCK_M))
|
||||
tl.store(Mean + rows, _mean)
|
||||
tl.store(Rstd + rows, _rstd)
|
||||
|
||||
# Normalize and apply linear transformation
|
||||
x_hat = (x - mean) * rstd
|
||||
|
||||
w = tl.load(W + cols)
|
||||
@@ -250,7 +241,6 @@ def _layer_norm_param_fwd_fused(
|
||||
|
||||
x_hat = x_hat * w + b
|
||||
|
||||
# Write output
|
||||
x_hat = x_hat.to(Y.type.element_ty)
|
||||
tl.store(y_ptr, x_hat, mask=mask[None, :])
|
||||
|
||||
@@ -298,9 +288,6 @@ def layernorm_param(x, w, b, eps):
|
||||
return y, mean, rstd
|
||||
|
||||
|
||||
########################################################
|
||||
# Elementwise_affine=False
|
||||
########################################################
|
||||
|
||||
|
||||
@triton.jit
|
||||
@@ -327,23 +314,18 @@ def _layer_norm_noparam_fwd_fused(
|
||||
|
||||
x = tl.load(x_ptr, mask=mask[None, :], other=0.0).to(tl.float32)
|
||||
|
||||
# Compute mean and Variance
|
||||
mean = tl.sum(x, axis=1, keep_dims=True) / N
|
||||
# Compute variance
|
||||
_var = (x - mean) * (x - mean)
|
||||
var = tl.sum(_var, axis=1, keep_dims=True) / N
|
||||
rstd = 1 / tl.sqrt(var + eps)
|
||||
|
||||
# Write mean / rstd
|
||||
_mean = tl.reshape(mean, (BLOCK_M))
|
||||
_rstd = tl.reshape(rstd, (BLOCK_M))
|
||||
tl.store(Mean + rows, _mean)
|
||||
tl.store(Rstd + rows, _rstd)
|
||||
|
||||
# Normalize and apply linear transformation
|
||||
x_hat = (x - mean) * rstd
|
||||
|
||||
# Write output
|
||||
x_hat = x_hat.to(Y.type.element_ty)
|
||||
tl.store(y_ptr, x_hat, mask=mask[None, :])
|
||||
|
||||
@@ -440,7 +422,6 @@ class Int8LinearFunction(torch.autograd.Function):
|
||||
grad_bias = None
|
||||
|
||||
if ctx.needs_input_grad[0]:
|
||||
# grad_input = grad_output @ W
|
||||
w_float = dequantize_weight(w_q, w_s, grad_output.dtype)
|
||||
grad_input = torch.matmul(grad_output, w_float)
|
||||
|
||||
@@ -489,34 +470,15 @@ class RMSNormFunction(torch.autograd.Function):
|
||||
grad_output_flat = grad_output
|
||||
dx = dx
|
||||
|
||||
# Standard RMSNorm backward
|
||||
# dy = grad_output_flat
|
||||
# x_hat = x * rstd
|
||||
# w * dy
|
||||
# c1 = mean(dy * w * x) * rstd^2
|
||||
# dx = (dy * w - c1 * x) * rstd
|
||||
|
||||
# More precise:
|
||||
# y = x * rstd * w
|
||||
# dy = grad_output
|
||||
# dw = sum(dy * x * rstd, dim=0)
|
||||
|
||||
grad_w = None
|
||||
if ctx.needs_input_grad[1]: # w
|
||||
# grad_w = (grad_output_flat * x_flat * rstd).sum(dim=0)
|
||||
# More accurate gradient for weight when considering rstd was computed from x
|
||||
# Actually, for Affine part (w), it is just sum(dL/dy * x_hat).
|
||||
# y = x_hat * w
|
||||
# dL/dw = sum(dL/dy * x_hat)
|
||||
x_hat = x_flat * rstd
|
||||
grad_w = (grad_output_flat * x_hat).sum(dim=0)
|
||||
|
||||
grad_input = None
|
||||
if ctx.needs_input_grad[0]: # x
|
||||
# x_hat = x * rstd
|
||||
# dx = rstd * (w * dy - mean(w * dy * x_hat) * x_hat)
|
||||
# but for RMSNorm:
|
||||
# dx = rstd * (w * dy - (x * rstd^2) * mean(w * dy * x)) -> check formula
|
||||
|
||||
# Using PyTorch autograd for reference logic:
|
||||
# y = x / sqrt(mean(x^2) + eps) * w
|
||||
@@ -530,8 +492,6 @@ class RMSNormFunction(torch.autograd.Function):
|
||||
|
||||
# Let's compute:
|
||||
dy_w = grad_output_flat * w
|
||||
# term2 = (dy_w * x_flat).sum(dim=-1, keepdim=True) / N # mean(dy*w*x)
|
||||
# grad_input = rstd * (dy_w - x_flat * (rstd ** 2) * term2)
|
||||
|
||||
# Re-derivation:
|
||||
# x_hat = x * rstd
|
||||
@@ -586,10 +546,6 @@ class LayerNormFunction(torch.autograd.Function):
|
||||
else:
|
||||
w_eff = w
|
||||
|
||||
# dx calculation
|
||||
# x_hat = (x - mean) * rstd
|
||||
# y = x_hat * w + b
|
||||
# dL/dx_hat = dL/dy * w
|
||||
|
||||
dy = grad_output_flat
|
||||
dx_hat = dy * w_eff
|
||||
|
||||
@@ -5,7 +5,7 @@ import random
|
||||
import time
|
||||
import torch
|
||||
try:
|
||||
from flash_attn import flash_attn_varlen_func # Use the new flash attention function
|
||||
from flash_attn import flash_attn_varlen_func
|
||||
from flash_attn.flash_attn_interface import _flash_attn_varlen_forward, _flash_attn_varlen_backward
|
||||
except ImportError:
|
||||
|
||||
@@ -46,7 +46,6 @@ def calc_chunks(cu_seqlen, moba_chunk_size):
|
||||
chunk_to_batch[cu_num_chunk[1:-1]] = 1
|
||||
chunk_to_batch = chunk_to_batch.cumsum(dim=0, dtype=torch.int32)
|
||||
|
||||
# Do not filter out any chunk
|
||||
filtered_chunk_indices = torch.arange(num_chunk, device=cu_seqlen.device, dtype=torch.int32)
|
||||
num_filtered_chunk = num_chunk
|
||||
|
||||
@@ -66,7 +65,7 @@ def _select_threshold_query_head(gate: torch.Tensor, valid_gate_mask: torch.Tens
|
||||
eps = 1e-6
|
||||
|
||||
# LSE‐style normalization per <head, query> (across chunks)
|
||||
gate_masked = torch.where(valid_gate_mask, gate, -torch.inf) # Use -inf for max
|
||||
gate_masked = torch.where(valid_gate_mask, gate, -torch.inf)
|
||||
gate_min_val = torch.where(valid_gate_mask, gate, torch.inf) # Use +inf for min
|
||||
|
||||
row_min = gate_min_val.amin(dim=0) # (H, S)
|
||||
@@ -127,7 +126,7 @@ def _select_threshold_block(gate: torch.Tensor, valid_gate_mask: torch.Tensor, g
|
||||
eps = 1e-6
|
||||
|
||||
# LSE‐style normalization per block (across heads and queries)
|
||||
gate_masked = torch.where(valid_gate_mask, gate, -torch.inf) # Use -inf for max
|
||||
gate_masked = torch.where(valid_gate_mask, gate, -torch.inf)
|
||||
gate_min_val = torch.where(valid_gate_mask, gate, torch.inf) # Use +inf for min
|
||||
|
||||
block_max = gate_masked.amax(dim=(1, 2), keepdim=True) # (C, 1, 1)
|
||||
@@ -193,7 +192,7 @@ def _select_threshold_overall(gate: torch.Tensor, valid_gate_mask: torch.Tensor,
|
||||
eps = 1e-6
|
||||
|
||||
# LSE‐style normalization globally across all valid entries
|
||||
gate_masked = torch.where(valid_gate_mask, gate, -torch.inf) # Use -inf for max
|
||||
gate_masked = torch.where(valid_gate_mask, gate, -torch.inf)
|
||||
gate_min_val = torch.where(valid_gate_mask, gate, torch.inf) # Use +inf for min
|
||||
|
||||
overall_max = gate_masked.max() # scalar
|
||||
@@ -251,7 +250,7 @@ def _select_threshold_overall(gate: torch.Tensor, valid_gate_mask: torch.Tensor,
|
||||
|
||||
# 8) create the mask in the original flat shape
|
||||
others_mask_flat = torch.zeros_like(others_flat, dtype=torch.bool) # (C*H*S,)
|
||||
if selected_other_indices.numel() > 0: # Check if any 'other' indices were selected
|
||||
if selected_other_indices.numel() > 0:
|
||||
others_mask_flat[selected_other_indices] = True
|
||||
others_mask = others_mask_flat.view(C, H, S) # (C, H, S)
|
||||
|
||||
@@ -349,8 +348,6 @@ class MixedAttention(torch.autograd.Function):
|
||||
ctx.moba_chunk_size = moba_chunk_size
|
||||
ctx.softmax_scale = softmax_scale = q.shape[-1]**(-0.5)
|
||||
|
||||
# Non-causal self-attention branch
|
||||
# return out, softmax_lse, S_dmask, rng_state
|
||||
self_attn_out_sh, self_attn_lse_hs, _, _ = _flash_attn_varlen_forward(
|
||||
q=q,
|
||||
k=k,
|
||||
@@ -532,12 +529,10 @@ def moba_attn_varlen(
|
||||
kv = torch.stack((k, v), dim=1)
|
||||
seqlen, num_head, head_dim = q.shape
|
||||
|
||||
# Compute chunk boundaries.
|
||||
cu_chunk, filtered_chunk_indices, num_filtered_chunk, chunk_to_batch = calc_chunks(cu_seqlens, moba_chunk_size)
|
||||
|
||||
self_attn_cu_seqlen = cu_chunk
|
||||
|
||||
# Update top-k selection to include the self chunk.
|
||||
moba_topk = min(moba_topk, num_filtered_chunk)
|
||||
|
||||
# --- Build filtered KV from chunks ---
|
||||
@@ -553,16 +548,13 @@ def moba_attn_varlen(
|
||||
gathered = kv[indices.view(-1)].view(num_filtered_chunk, max_chunk_len, *kv.shape[1:])
|
||||
gathered = gathered * valid_mask.unsqueeze(-1).unsqueeze(-1).unsqueeze(-1).type_as(gathered)
|
||||
|
||||
# Compute key_gate_weight over valid tokens.
|
||||
key_values = gathered[:, :, 0].float() # [num_filtered_chunk, max_chunk_len, num_head, head_dim]
|
||||
valid_mask_exp = valid_mask.unsqueeze(-1).unsqueeze(-1)
|
||||
key_sum = (key_values * valid_mask_exp).sum(dim=1)
|
||||
divisor = valid_mask.sum(dim=1).unsqueeze(-1).unsqueeze(-1)
|
||||
key_gate_weight = key_sum / divisor # [num_filtered_chunk, num_head, head_dim]
|
||||
|
||||
# Compute gate logits between key_gate_weight and queries.
|
||||
q_float = q.float()
|
||||
# gate = torch.einsum("nhd,shd->nhs", key_gate_weight, q_float) # [num_filtered_chunk, num_head, seqlen]
|
||||
gate = torch.bmm(key_gate_weight.permute(1, 0, 2), q_float.permute(1, 0, 2).transpose(1, 2)).permute(1, 0, 2)
|
||||
|
||||
# Amplify the diagonal (self chunk) contributions.
|
||||
@@ -650,7 +642,6 @@ def moba_attn_varlen(
|
||||
moba_q_sh_indices = (moba_q_indices % seqlen) * num_head + (moba_q_indices // seqlen)
|
||||
moba_q = rearrange(q, "s h d -> (h s) d").index_select(0, moba_q_indices).unsqueeze(1)
|
||||
|
||||
# Build cumulative sequence lengths for the selected queries.
|
||||
moba_seqlen_q = gate_mask.sum(dim=-1).flatten()
|
||||
q_zero_mask = moba_seqlen_q == 0
|
||||
valid_expert_mask = ~q_zero_mask
|
||||
@@ -814,7 +805,6 @@ def test_attn_varlen_moba_speed(batch,
|
||||
simsum_threshold=0.25,
|
||||
threshold_type='query_head'):
|
||||
"""Speed test comparing flash_attn vs moba_attention"""
|
||||
# Get data
|
||||
q, k, v, cu_seqlen, max_seqlen = generate_data(batch, seqlen, head, head_dim, dtype)
|
||||
print(
|
||||
f"batch:{batch} head:{head} seqlen:{seqlen} chunk:{moba_chunk_size} topk:{moba_topk} select_mode: {select_mode} simsum_threshold:{simsum_threshold}"
|
||||
|
||||
@@ -53,15 +53,12 @@ def attn_qat_train_wrapper(q_BLHD, k_BLHD, v_BLHD, is_causal=False, sm_scale=Non
|
||||
if sm_scale is None:
|
||||
sm_scale = 1.0 / sqrt(q_BLHD.shape[-1])
|
||||
|
||||
# Convert from BLHD to BHLD format
|
||||
q_BHLD = q_BLHD.permute(0, 2, 1, 3).contiguous()
|
||||
k_BHLD = k_BLHD.permute(0, 2, 1, 3).contiguous()
|
||||
v_BHLD = v_BLHD.permute(0, 2, 1, 3).contiguous()
|
||||
|
||||
# Call attention with BHLD format
|
||||
o_BHLD = attention(q_BHLD, k_BHLD, v_BHLD, is_causal, sm_scale)
|
||||
|
||||
# Convert back from BHLD to BLHD format
|
||||
return o_BHLD.permute(0, 2, 1, 3).contiguous()
|
||||
|
||||
|
||||
@@ -84,7 +81,6 @@ def fused_attn_wrapper(q_BLHD, k_BLHD, v_BLHD, is_causal=False, sm_scale=None, w
|
||||
if sm_scale is None:
|
||||
sm_scale = 1.0 / sqrt(q_BLHD.shape[-1])
|
||||
|
||||
# Convert from BLHD to BHLD format
|
||||
q_BHLD = q_BLHD.permute(0, 2, 1, 3).contiguous()
|
||||
k_BHLD = k_BLHD.permute(0, 2, 1, 3).contiguous()
|
||||
v_BHLD = v_BLHD.permute(0, 2, 1, 3).contiguous()
|
||||
@@ -93,7 +89,6 @@ def fused_attn_wrapper(q_BLHD, k_BLHD, v_BLHD, is_causal=False, sm_scale=None, w
|
||||
# Note: fused_attention expects inputs in BHLD format and only supports same sequence lengths
|
||||
o_BHLD = fused_attention(q_BHLD, k_BHLD, v_BHLD, is_causal, sm_scale, warp_specialize)
|
||||
|
||||
# Convert back from BHLD to BLHD format
|
||||
return o_BHLD.permute(0, 2, 1, 3).contiguous()
|
||||
|
||||
|
||||
@@ -112,7 +107,6 @@ def cosine_similarity(tensor1, tensor2):
|
||||
t1_flat = tensor1.flatten().float()
|
||||
t2_flat = tensor2.flatten().float()
|
||||
|
||||
# Compute cosine similarity: (A · B) / (||A|| * ||B||)
|
||||
dot_product = torch.dot(t1_flat, t2_flat)
|
||||
norm1 = torch.norm(t1_flat)
|
||||
norm2 = torch.norm(t2_flat)
|
||||
@@ -139,7 +133,6 @@ def naive_attention(q, k, v, causal, sm_scale):
|
||||
Returns:
|
||||
Output tensor of shape (Z, H, N_CTX_Q, HEAD_DIM)
|
||||
"""
|
||||
# Compute attention scores: QK^T
|
||||
scores = torch.matmul(q, k.transpose(-2, -1)) * sm_scale
|
||||
|
||||
# Apply causal mask if needed
|
||||
@@ -156,10 +149,8 @@ def naive_attention(q, k, v, causal, sm_scale):
|
||||
# In cross-attention, typically no causal masking is applied
|
||||
pass
|
||||
|
||||
# Apply softmax
|
||||
attn_weights = torch.softmax(scores, dim=-1)
|
||||
|
||||
# Apply attention weights to values
|
||||
out = torch.matmul(attn_weights, v)
|
||||
|
||||
return out
|
||||
@@ -175,7 +166,6 @@ def test_qat_attention_forward():
|
||||
sm_scale = 1.0 / sqrt(HEAD_DIM)
|
||||
causal = False
|
||||
|
||||
# Create input tensors in BLHD format (B, L, H, D) = (Z, N_CTX, H, HEAD_DIM)
|
||||
q_BLHD = torch.randn((Z, N_CTX, H, HEAD_DIM), dtype=dtype, device=DEVICE, requires_grad=True)
|
||||
k_BLHD = torch.randn((Z, N_CTX, H, HEAD_DIM), dtype=dtype, device=DEVICE, requires_grad=True)
|
||||
v_BLHD = torch.randn((Z, N_CTX, H, HEAD_DIM), dtype=dtype, device=DEVICE, requires_grad=True)
|
||||
@@ -183,18 +173,15 @@ def test_qat_attention_forward():
|
||||
# Test with QAT (using wrapper that does permute/contiguous)
|
||||
out_qat_BLHD = attn_qat_train_wrapper(q_BLHD.clone(), k_BLHD.clone(), v_BLHD.clone(), causal, sm_scale)
|
||||
|
||||
# Convert to BHLD for naive attention comparison
|
||||
q_BHLD = q_BLHD.permute(0, 2, 1, 3).contiguous()
|
||||
k_BHLD = k_BLHD.permute(0, 2, 1, 3).contiguous()
|
||||
v_BHLD = v_BLHD.permute(0, 2, 1, 3).contiguous()
|
||||
out_naive_BHLD = naive_attention(q_BHLD.clone(), k_BHLD.clone(), v_BHLD.clone(), causal, sm_scale)
|
||||
out_naive_BLHD = out_naive_BHLD.permute(0, 2, 1, 3).contiguous()
|
||||
|
||||
# Check that outputs have correct shape
|
||||
assert out_qat_BLHD.shape == (Z, N_CTX, H, HEAD_DIM)
|
||||
assert out_naive_BLHD.shape == (Z, N_CTX, H, HEAD_DIM)
|
||||
|
||||
# Check that outputs are finite
|
||||
assert torch.isfinite(out_qat_BLHD).all()
|
||||
assert torch.isfinite(out_naive_BLHD).all()
|
||||
|
||||
@@ -206,9 +193,6 @@ def test_qat_attention_forward():
|
||||
f" QAT vs Naive Z={Z}, H={H}, N_CTX={N_CTX}, HEAD_DIM={HEAD_DIM} - Max diff: {max_diff.item():.6f}, Mean diff: {mean_diff.item():.6f}, Cosine sim: {cos_sim:.6f}"
|
||||
)
|
||||
|
||||
# QAT output should be reasonably close to naive (within tolerance due to quantization)
|
||||
# Using a reasonable tolerance for float16 and quantization effects
|
||||
# assert max_diff < 1.0, f"QAT and naive outputs should be reasonably close, got max_diff={max_diff.item():.6f}"
|
||||
|
||||
print("✓ Forward pass test passed.")
|
||||
|
||||
@@ -223,12 +207,10 @@ def test_qat_attention_backward():
|
||||
sm_scale = 1.0 / sqrt(HEAD_DIM)
|
||||
causal = True
|
||||
|
||||
# Create input tensors in BLHD format for QAT
|
||||
q_qat_BLHD = torch.randn((Z, N_CTX, H, HEAD_DIM), dtype=dtype, device=DEVICE, requires_grad=True)
|
||||
k_qat_BLHD = torch.randn((Z, N_CTX, H, HEAD_DIM), dtype=dtype, device=DEVICE, requires_grad=True)
|
||||
v_qat_BLHD = torch.randn((Z, N_CTX, H, HEAD_DIM), dtype=dtype, device=DEVICE, requires_grad=True)
|
||||
|
||||
# Create input tensors for naive (same values, convert to BHLD)
|
||||
q_naive_BHLD = q_qat_BLHD.clone().permute(0, 2, 1, 3).contiguous().detach().requires_grad_(True)
|
||||
k_naive_BHLD = k_qat_BLHD.clone().permute(0, 2, 1, 3).contiguous().detach().requires_grad_(True)
|
||||
v_naive_BHLD = v_qat_BLHD.clone().permute(0, 2, 1, 3).contiguous().detach().requires_grad_(True)
|
||||
@@ -250,7 +232,6 @@ def test_qat_attention_backward():
|
||||
# Backward pass for naive
|
||||
out_naive_BLHD.backward(dout)
|
||||
|
||||
# Check that gradients are computed
|
||||
assert q_qat_BLHD.grad is not None
|
||||
assert k_qat_BLHD.grad is not None
|
||||
assert v_qat_BLHD.grad is not None
|
||||
@@ -258,17 +239,14 @@ def test_qat_attention_backward():
|
||||
assert k_naive_BHLD.grad is not None
|
||||
assert v_naive_BHLD.grad is not None
|
||||
|
||||
# Check that gradients have correct shape
|
||||
assert q_qat_BLHD.grad.shape == q_qat_BLHD.shape
|
||||
assert k_qat_BLHD.grad.shape == k_qat_BLHD.shape
|
||||
assert v_qat_BLHD.grad.shape == v_qat_BLHD.shape
|
||||
|
||||
# Check that gradients are finite
|
||||
assert torch.isfinite(q_qat_BLHD.grad).all()
|
||||
assert torch.isfinite(k_qat_BLHD.grad).all()
|
||||
assert torch.isfinite(v_qat_BLHD.grad).all()
|
||||
|
||||
# Convert naive gradients to BLHD format for comparison
|
||||
q_naive_grad_BLHD = q_naive_BHLD.grad.permute(0, 2, 1, 3).contiguous()
|
||||
k_naive_grad_BLHD = k_naive_BHLD.grad.permute(0, 2, 1, 3).contiguous()
|
||||
v_naive_grad_BLHD = v_naive_BHLD.grad.permute(0, 2, 1, 3).contiguous()
|
||||
@@ -292,10 +270,6 @@ def test_qat_attention_backward():
|
||||
f" dV - Max diff: {dv_diff.max().item():.6f}, Mean diff: {dv_diff.mean().item():.6f}, Cosine sim: {dv_cos_sim:.6f}"
|
||||
)
|
||||
|
||||
# Gradients should be reasonably close (within tolerance due to quantization)
|
||||
# assert dq_diff.max() < 2.0, f"dQ gradients should be reasonably close, got max_diff={dq_diff.max().item():.6f}"
|
||||
# assert dk_diff.max() < 2.0, f"dK gradients should be reasonably close, got max_diff={dk_diff.max().item():.6f}"
|
||||
# assert dv_diff.max() < 2.0, f"dV gradients should be reasonably close, got max_diff={dv_diff.max().item():.6f}"
|
||||
|
||||
print("✓ Backward pass test passed.")
|
||||
|
||||
@@ -313,7 +287,6 @@ def test_qat_attention_different_shapes():
|
||||
causal = True
|
||||
|
||||
for Z, H, N_CTX, HEAD_DIM in test_configs:
|
||||
# Create input tensors in BLHD format
|
||||
q_BLHD = torch.randn((Z, N_CTX, H, HEAD_DIM), dtype=dtype, device=DEVICE)
|
||||
k_BLHD = torch.randn((Z, N_CTX, H, HEAD_DIM), dtype=dtype, device=DEVICE)
|
||||
v_BLHD = torch.randn((Z, N_CTX, H, HEAD_DIM), dtype=dtype, device=DEVICE)
|
||||
@@ -321,7 +294,6 @@ def test_qat_attention_different_shapes():
|
||||
sm_scale = 1.0 / sqrt(HEAD_DIM)
|
||||
out_qat_BLHD = attn_qat_train_wrapper(q_BLHD.clone(), k_BLHD.clone(), v_BLHD.clone(), causal, sm_scale)
|
||||
|
||||
# Convert to BHLD for naive attention
|
||||
q_BHLD = q_BLHD.permute(0, 2, 1, 3).contiguous()
|
||||
k_BHLD = k_BLHD.permute(0, 2, 1, 3).contiguous()
|
||||
v_BHLD = v_BLHD.permute(0, 2, 1, 3).contiguous()
|
||||
@@ -341,8 +313,6 @@ def test_qat_attention_different_shapes():
|
||||
f" (Z={Z}, H={H}, N_CTX={N_CTX}, HEAD_DIM={HEAD_DIM}) - Max diff: {max_diff.item():.6f}, Mean diff: {mean_diff.item():.6f}, Cosine sim: {cos_sim:.6f}"
|
||||
)
|
||||
|
||||
# Outputs should be reasonably close
|
||||
# assert max_diff < 1.0, f"QAT and naive outputs should be reasonably close for shape (Z={Z}, H={H}, N_CTX={N_CTX}, HEAD_DIM={HEAD_DIM}), got max_diff={max_diff.item():.6f}"
|
||||
|
||||
print(f"✓ Shape test passed for (Z={Z}, H={H}, N_CTX={N_CTX}, HEAD_DIM={HEAD_DIM})")
|
||||
|
||||
@@ -356,14 +326,12 @@ def test_qat_attention_non_causal():
|
||||
sm_scale = 1.0 / sqrt(HEAD_DIM)
|
||||
causal = False
|
||||
|
||||
# Create input tensors in BLHD format
|
||||
q_BLHD = torch.randn((Z, N_CTX, H, HEAD_DIM), dtype=dtype, device=DEVICE)
|
||||
k_BLHD = torch.randn((Z, N_CTX, H, HEAD_DIM), dtype=dtype, device=DEVICE)
|
||||
v_BLHD = torch.randn((Z, N_CTX, H, HEAD_DIM), dtype=dtype, device=DEVICE)
|
||||
|
||||
out_qat_BLHD = attn_qat_train_wrapper(q_BLHD.clone(), k_BLHD.clone(), v_BLHD.clone(), causal, sm_scale)
|
||||
|
||||
# Convert to BHLD for naive attention
|
||||
q_BHLD = q_BLHD.permute(0, 2, 1, 3).contiguous()
|
||||
k_BHLD = k_BLHD.permute(0, 2, 1, 3).contiguous()
|
||||
v_BHLD = v_BLHD.permute(0, 2, 1, 3).contiguous()
|
||||
@@ -383,8 +351,6 @@ def test_qat_attention_non_causal():
|
||||
f" QAT vs Naive (non-causal) - Max diff: {max_diff.item():.6f}, Mean diff: {mean_diff.item():.6f}, Cosine sim: {cos_sim:.6f}"
|
||||
)
|
||||
|
||||
# Outputs should be reasonably close
|
||||
# assert max_diff < 1.0, f"QAT and naive outputs should be reasonably close for non-causal, got max_diff={max_diff.item():.6f}"
|
||||
|
||||
print("✓ Non-causal test passed.")
|
||||
|
||||
@@ -398,14 +364,12 @@ def test_qat_attention_causal():
|
||||
sm_scale = 1.0 / sqrt(HEAD_DIM)
|
||||
causal = True
|
||||
|
||||
# Create input tensors in BLHD format
|
||||
q_BLHD = torch.randn((Z, N_CTX, H, HEAD_DIM), dtype=dtype, device=DEVICE)
|
||||
k_BLHD = torch.randn((Z, N_CTX, H, HEAD_DIM), dtype=dtype, device=DEVICE)
|
||||
v_BLHD = torch.randn((Z, N_CTX, H, HEAD_DIM), dtype=dtype, device=DEVICE)
|
||||
|
||||
out_qat_BLHD = attn_qat_train_wrapper(q_BLHD.clone(), k_BLHD.clone(), v_BLHD.clone(), causal, sm_scale)
|
||||
|
||||
# Convert to BHLD for naive attention
|
||||
q_BHLD = q_BLHD.permute(0, 2, 1, 3).contiguous()
|
||||
k_BHLD = k_BLHD.permute(0, 2, 1, 3).contiguous()
|
||||
v_BHLD = v_BLHD.permute(0, 2, 1, 3).contiguous()
|
||||
@@ -425,8 +389,6 @@ def test_qat_attention_causal():
|
||||
f" QAT vs Naive (causal) - Max diff: {max_diff.item():.6f}, Mean diff: {mean_diff.item():.6f}, Cosine sim: {cos_sim:.6f}"
|
||||
)
|
||||
|
||||
# Outputs should be reasonably close
|
||||
# assert max_diff < 1.0, f"QAT and naive outputs should be reasonably close for causal, got max_diff={max_diff.item():.6f}"
|
||||
|
||||
print("✓ Causal test passed.")
|
||||
|
||||
@@ -440,12 +402,10 @@ def test_qat_attention_causal_backward():
|
||||
sm_scale = 1.0 / sqrt(HEAD_DIM)
|
||||
causal = True
|
||||
|
||||
# Create input tensors in BLHD format for QAT
|
||||
q_qat_BLHD = torch.randn((Z, N_CTX, H, HEAD_DIM), dtype=dtype, device=DEVICE, requires_grad=True)
|
||||
k_qat_BLHD = torch.randn((Z, N_CTX, H, HEAD_DIM), dtype=dtype, device=DEVICE, requires_grad=True)
|
||||
v_qat_BLHD = torch.randn((Z, N_CTX, H, HEAD_DIM), dtype=dtype, device=DEVICE, requires_grad=True)
|
||||
|
||||
# Create input tensors for naive (same values, convert to BHLD)
|
||||
q_naive_BHLD = q_qat_BLHD.clone().permute(0, 2, 1, 3).contiguous().detach().requires_grad_(True)
|
||||
k_naive_BHLD = k_qat_BLHD.clone().permute(0, 2, 1, 3).contiguous().detach().requires_grad_(True)
|
||||
v_naive_BHLD = v_qat_BLHD.clone().permute(0, 2, 1, 3).contiguous().detach().requires_grad_(True)
|
||||
@@ -457,7 +417,6 @@ def test_qat_attention_causal_backward():
|
||||
out_naive_BHLD = naive_attention(q_naive_BHLD, k_naive_BHLD, v_naive_BHLD, causal, sm_scale)
|
||||
out_naive_BHLD = out_naive_BHLD.permute(0, 2, 1, 3).contiguous()
|
||||
|
||||
# Create dummy gradient
|
||||
dout = torch.randn_like(out_qat_BLHD).contiguous()
|
||||
|
||||
# Backward pass for QAT
|
||||
@@ -466,12 +425,10 @@ def test_qat_attention_causal_backward():
|
||||
# Backward pass for naive
|
||||
out_naive_BHLD.backward(dout)
|
||||
|
||||
# Check that gradients are computed
|
||||
assert q_qat_BLHD.grad is not None
|
||||
assert k_qat_BLHD.grad is not None
|
||||
assert v_qat_BLHD.grad is not None
|
||||
|
||||
# Convert naive gradients to BLHD format for comparison
|
||||
q_naive_grad_BLHD = q_naive_BHLD.grad.permute(0, 2, 1, 3).contiguous()
|
||||
k_naive_grad_BLHD = k_naive_BHLD.grad.permute(0, 2, 1, 3).contiguous()
|
||||
v_naive_grad_BLHD = v_naive_BHLD.grad.permute(0, 2, 1, 3).contiguous()
|
||||
@@ -513,7 +470,6 @@ def test_qat_attention_different_seq_lengths():
|
||||
for Z, H, N_CTX_Q, N_CTX_KV, HEAD_DIM, causal in test_configs:
|
||||
sm_scale = 1.0 / sqrt(HEAD_DIM)
|
||||
|
||||
# Create input tensors in BLHD format with different sequence lengths
|
||||
q_BLHD = torch.randn((Z, N_CTX_Q, H, HEAD_DIM), dtype=dtype, device=DEVICE)
|
||||
k_BLHD = torch.randn((Z, N_CTX_KV, H, HEAD_DIM), dtype=dtype, device=DEVICE)
|
||||
v_BLHD = torch.randn((Z, N_CTX_KV, H, HEAD_DIM), dtype=dtype, device=DEVICE)
|
||||
@@ -521,7 +477,6 @@ def test_qat_attention_different_seq_lengths():
|
||||
# Test with QAT (using wrapper that does permute/contiguous)
|
||||
out_qat_BLHD = attn_qat_train_wrapper(q_BLHD.clone(), k_BLHD.clone(), v_BLHD.clone(), causal, sm_scale)
|
||||
|
||||
# Convert to BHLD for naive attention comparison
|
||||
q_BHLD = q_BLHD.permute(0, 2, 1, 3).contiguous()
|
||||
k_BHLD = k_BLHD.permute(0, 2, 1, 3).contiguous()
|
||||
v_BHLD = v_BLHD.permute(0, 2, 1, 3).contiguous()
|
||||
@@ -532,7 +487,6 @@ def test_qat_attention_different_seq_lengths():
|
||||
assert out_qat_BLHD.shape == (Z, N_CTX_Q, H, HEAD_DIM)
|
||||
assert out_naive_BLHD.shape == (Z, N_CTX_Q, H, HEAD_DIM)
|
||||
|
||||
# Check that outputs are finite
|
||||
assert torch.isfinite(out_qat_BLHD).all()
|
||||
assert torch.isfinite(out_naive_BLHD).all()
|
||||
|
||||
@@ -544,8 +498,6 @@ def test_qat_attention_different_seq_lengths():
|
||||
f" (N_CTX_Q={N_CTX_Q}, N_CTX_KV={N_CTX_KV}, causal={causal}) - Max diff: {max_diff.item():.6f}, Mean diff: {mean_diff.item():.6f}, Cosine sim: {cos_sim:.6f}"
|
||||
)
|
||||
|
||||
# Outputs should be reasonably close
|
||||
# assert max_diff < 1.0, f"QAT and naive outputs should be reasonably close for (N_CTX_Q={N_CTX_Q}, N_CTX_KV={N_CTX_KV}), got max_diff={max_diff.item():.6f}"
|
||||
|
||||
print(f"✓ Different sequence lengths test passed for (N_CTX_Q={N_CTX_Q}, N_CTX_KV={N_CTX_KV})")
|
||||
|
||||
@@ -564,12 +516,10 @@ def test_qat_attention_different_seq_lengths_backward():
|
||||
for Z, H, N_CTX_Q, N_CTX_KV, HEAD_DIM, causal in test_configs:
|
||||
sm_scale = 1.0 / sqrt(HEAD_DIM)
|
||||
|
||||
# Create input tensors in BLHD format with different sequence lengths
|
||||
q_qat_BLHD = torch.randn((Z, N_CTX_Q, H, HEAD_DIM), dtype=dtype, device=DEVICE, requires_grad=True)
|
||||
k_qat_BLHD = torch.randn((Z, N_CTX_KV, H, HEAD_DIM), dtype=dtype, device=DEVICE, requires_grad=True)
|
||||
v_qat_BLHD = torch.randn((Z, N_CTX_KV, H, HEAD_DIM), dtype=dtype, device=DEVICE, requires_grad=True)
|
||||
|
||||
# Create input tensors for naive (same values, convert to BHLD)
|
||||
q_naive_BHLD = q_qat_BLHD.clone().permute(0, 2, 1, 3).contiguous().detach().requires_grad_(True)
|
||||
k_naive_BHLD = k_qat_BLHD.clone().permute(0, 2, 1, 3).contiguous().detach().requires_grad_(True)
|
||||
v_naive_BHLD = v_qat_BLHD.clone().permute(0, 2, 1, 3).contiguous().detach().requires_grad_(True)
|
||||
@@ -581,7 +531,6 @@ def test_qat_attention_different_seq_lengths_backward():
|
||||
out_naive_BHLD = naive_attention(q_naive_BHLD, k_naive_BHLD, v_naive_BHLD, causal, sm_scale)
|
||||
out_naive_BHLD = out_naive_BHLD.permute(0, 2, 1, 3).contiguous()
|
||||
|
||||
# Create dummy gradient
|
||||
dout = torch.randn_like(out_qat_BLHD).contiguous()
|
||||
|
||||
# Backward pass for QAT
|
||||
@@ -590,7 +539,6 @@ def test_qat_attention_different_seq_lengths_backward():
|
||||
# Backward pass for naive
|
||||
out_naive_BHLD.backward(dout)
|
||||
|
||||
# Check that gradients are computed
|
||||
assert q_qat_BLHD.grad is not None
|
||||
assert k_qat_BLHD.grad is not None
|
||||
assert v_qat_BLHD.grad is not None
|
||||
@@ -598,17 +546,14 @@ def test_qat_attention_different_seq_lengths_backward():
|
||||
assert k_naive_BHLD.grad is not None
|
||||
assert v_naive_BHLD.grad is not None
|
||||
|
||||
# Check that gradients have correct shape
|
||||
assert q_qat_BLHD.grad.shape == q_qat_BLHD.shape
|
||||
assert k_qat_BLHD.grad.shape == k_qat_BLHD.shape
|
||||
assert v_qat_BLHD.grad.shape == v_qat_BLHD.shape
|
||||
|
||||
# Check that gradients are finite
|
||||
assert torch.isfinite(q_qat_BLHD.grad).all()
|
||||
assert torch.isfinite(k_qat_BLHD.grad).all()
|
||||
assert torch.isfinite(v_qat_BLHD.grad).all()
|
||||
|
||||
# Convert naive gradients to BLHD format for comparison
|
||||
q_naive_grad_BLHD = q_naive_BHLD.grad.permute(0, 2, 1, 3).contiguous()
|
||||
k_naive_grad_BLHD = k_naive_BHLD.grad.permute(0, 2, 1, 3).contiguous()
|
||||
v_naive_grad_BLHD = v_naive_BHLD.grad.permute(0, 2, 1, 3).contiguous()
|
||||
@@ -632,10 +577,6 @@ def test_qat_attention_different_seq_lengths_backward():
|
||||
f" (N_CTX_Q={N_CTX_Q}, N_CTX_KV={N_CTX_KV}) - dV: Max diff: {dv_diff.max().item():.6f}, Mean diff: {dv_diff.mean().item():.6f}, Cosine sim: {dv_cos_sim:.6f}"
|
||||
)
|
||||
|
||||
# Gradients should be reasonably close (within tolerance due to quantization)
|
||||
# assert dq_diff.max() < 2.0, f"dQ gradients should be reasonably close, got max_diff={dq_diff.max().item():.6f}"
|
||||
# assert dk_diff.max() < 2.0, f"dK gradients should be reasonably close, got max_diff={dk_diff.max().item():.6f}"
|
||||
# assert dv_diff.max() < 2.0, f"dV gradients should be reasonably close, got max_diff={dv_diff.max().item():.6f}"
|
||||
|
||||
print(f"✓ Cross-attention backward test passed for (N_CTX_Q={N_CTX_Q}, N_CTX_KV={N_CTX_KV})")
|
||||
|
||||
@@ -650,7 +591,6 @@ def test_fused_attention_forward():
|
||||
sm_scale = 1.0 / sqrt(HEAD_DIM)
|
||||
causal = False
|
||||
|
||||
# Create input tensors in BLHD format (B, L, H, D) = (Z, N_CTX, H, HEAD_DIM)
|
||||
q_BLHD = torch.randn((Z, N_CTX, H, HEAD_DIM), dtype=dtype, device=DEVICE)
|
||||
k_BLHD = torch.randn((Z, N_CTX, H, HEAD_DIM), dtype=dtype, device=DEVICE)
|
||||
v_BLHD = torch.randn((Z, N_CTX, H, HEAD_DIM), dtype=dtype, device=DEVICE)
|
||||
@@ -658,18 +598,15 @@ def test_fused_attention_forward():
|
||||
# Test with fused attention (using wrapper that does permute/contiguous)
|
||||
out_fused_BLHD = fused_attn_wrapper(q_BLHD.clone(), k_BLHD.clone(), v_BLHD.clone(), causal, sm_scale)
|
||||
|
||||
# Convert to BHLD for naive attention comparison
|
||||
q_BHLD = q_BLHD.permute(0, 2, 1, 3).contiguous()
|
||||
k_BHLD = k_BLHD.permute(0, 2, 1, 3).contiguous()
|
||||
v_BHLD = v_BLHD.permute(0, 2, 1, 3).contiguous()
|
||||
out_naive_BHLD = naive_attention(q_BHLD.clone(), k_BHLD.clone(), v_BHLD.clone(), causal, sm_scale)
|
||||
out_naive_BLHD = out_naive_BHLD.permute(0, 2, 1, 3).contiguous()
|
||||
|
||||
# Check that outputs have correct shape
|
||||
assert out_fused_BLHD.shape == (Z, N_CTX, H, HEAD_DIM)
|
||||
assert out_naive_BLHD.shape == (Z, N_CTX, H, HEAD_DIM)
|
||||
|
||||
# Check that outputs are finite
|
||||
assert torch.isfinite(out_fused_BLHD).all()
|
||||
assert torch.isfinite(out_naive_BLHD).all()
|
||||
|
||||
@@ -681,8 +618,6 @@ def test_fused_attention_forward():
|
||||
f" Fused vs Naive - Max diff: {max_diff.item():.6f}, Mean diff: {mean_diff.item():.6f}, Cosine sim: {cos_sim:.6f}"
|
||||
)
|
||||
|
||||
# Fused attention should be reasonably close to naive (within tolerance for float16)
|
||||
# assert max_diff < 1e-1, f"Fused and naive outputs should be reasonably close, got max_diff={max_diff.item():.6f}"
|
||||
|
||||
print("✓ Fused attention forward pass test passed.")
|
||||
|
||||
@@ -697,12 +632,10 @@ def test_fused_attention_backward():
|
||||
sm_scale = 1.0 / sqrt(HEAD_DIM)
|
||||
causal = True
|
||||
|
||||
# Create input tensors in BLHD format for fused attention
|
||||
q_fused_BLHD = torch.randn((Z, N_CTX, H, HEAD_DIM), dtype=dtype, device=DEVICE, requires_grad=True)
|
||||
k_fused_BLHD = torch.randn((Z, N_CTX, H, HEAD_DIM), dtype=dtype, device=DEVICE, requires_grad=True)
|
||||
v_fused_BLHD = torch.randn((Z, N_CTX, H, HEAD_DIM), dtype=dtype, device=DEVICE, requires_grad=True)
|
||||
|
||||
# Create input tensors for naive (same values, convert to BHLD)
|
||||
q_naive_BHLD = q_fused_BLHD.clone().permute(0, 2, 1, 3).contiguous().detach().requires_grad_(True)
|
||||
k_naive_BHLD = k_fused_BLHD.clone().permute(0, 2, 1, 3).contiguous().detach().requires_grad_(True)
|
||||
v_naive_BHLD = v_fused_BLHD.clone().permute(0, 2, 1, 3).contiguous().detach().requires_grad_(True)
|
||||
@@ -714,7 +647,6 @@ def test_fused_attention_backward():
|
||||
out_naive_BHLD = naive_attention(q_naive_BHLD, k_naive_BHLD, v_naive_BHLD, causal, sm_scale)
|
||||
out_naive_BLHD = out_naive_BHLD.permute(0, 2, 1, 3).contiguous()
|
||||
|
||||
# Create dummy gradient (same for both, in BLHD format)
|
||||
dout = torch.randn_like(out_fused_BLHD).contiguous()
|
||||
|
||||
# Backward pass for fused attention
|
||||
@@ -723,7 +655,6 @@ def test_fused_attention_backward():
|
||||
# Backward pass for naive
|
||||
out_naive_BLHD.backward(dout)
|
||||
|
||||
# Check that gradients are computed
|
||||
assert q_fused_BLHD.grad is not None
|
||||
assert k_fused_BLHD.grad is not None
|
||||
assert v_fused_BLHD.grad is not None
|
||||
@@ -731,17 +662,14 @@ def test_fused_attention_backward():
|
||||
assert k_naive_BHLD.grad is not None
|
||||
assert v_naive_BHLD.grad is not None
|
||||
|
||||
# Check that gradients have correct shape
|
||||
assert q_fused_BLHD.grad.shape == q_fused_BLHD.shape
|
||||
assert k_fused_BLHD.grad.shape == k_fused_BLHD.shape
|
||||
assert v_fused_BLHD.grad.shape == v_fused_BLHD.shape
|
||||
|
||||
# Check that gradients are finite
|
||||
assert torch.isfinite(q_fused_BLHD.grad).all()
|
||||
assert torch.isfinite(k_fused_BLHD.grad).all()
|
||||
assert torch.isfinite(v_fused_BLHD.grad).all()
|
||||
|
||||
# Convert naive gradients to BLHD format for comparison
|
||||
q_naive_grad_BLHD = q_naive_BHLD.grad.permute(0, 2, 1, 3).contiguous()
|
||||
k_naive_grad_BLHD = k_naive_BHLD.grad.permute(0, 2, 1, 3).contiguous()
|
||||
v_naive_grad_BLHD = v_naive_BHLD.grad.permute(0, 2, 1, 3).contiguous()
|
||||
@@ -765,10 +693,6 @@ def test_fused_attention_backward():
|
||||
f" dV - Max diff: {dv_diff.max().item():.6f}, Mean diff: {dv_diff.mean().item():.6f}, Cosine sim: {dv_cos_sim:.6f}"
|
||||
)
|
||||
|
||||
# Gradients should be reasonably close (within tolerance for float16)
|
||||
# assert dq_diff.max() < 1e-1, f"dQ gradients should be reasonably close, got max_diff={dq_diff.max().item():.6f}"
|
||||
# assert dk_diff.max() < 1e-1, f"dK gradients should be reasonably close, got max_diff={dk_diff.max().item():.6f}"
|
||||
# assert dv_diff.max() < 1e-1, f"dV gradients should be reasonably close, got max_diff={dv_diff.max().item():.6f}"
|
||||
|
||||
print("✓ Fused attention backward pass test passed.")
|
||||
|
||||
@@ -787,7 +711,6 @@ def test_fused_attention_different_shapes():
|
||||
causal = True
|
||||
|
||||
for Z, H, N_CTX, HEAD_DIM in test_configs:
|
||||
# Create input tensors in BLHD format
|
||||
q_BLHD = torch.randn((Z, N_CTX, H, HEAD_DIM), dtype=dtype, device=DEVICE)
|
||||
k_BLHD = torch.randn((Z, N_CTX, H, HEAD_DIM), dtype=dtype, device=DEVICE)
|
||||
v_BLHD = torch.randn((Z, N_CTX, H, HEAD_DIM), dtype=dtype, device=DEVICE)
|
||||
@@ -795,7 +718,6 @@ def test_fused_attention_different_shapes():
|
||||
sm_scale = 1.0 / sqrt(HEAD_DIM)
|
||||
out_fused_BLHD = fused_attn_wrapper(q_BLHD.clone(), k_BLHD.clone(), v_BLHD.clone(), causal, sm_scale)
|
||||
|
||||
# Convert to BHLD for naive attention
|
||||
q_BHLD = q_BLHD.permute(0, 2, 1, 3).contiguous()
|
||||
k_BHLD = k_BLHD.permute(0, 2, 1, 3).contiguous()
|
||||
v_BHLD = v_BLHD.permute(0, 2, 1, 3).contiguous()
|
||||
@@ -815,8 +737,6 @@ def test_fused_attention_different_shapes():
|
||||
f" (Z={Z}, H={H}, N_CTX={N_CTX}, HEAD_DIM={HEAD_DIM}) - Max diff: {max_diff.item():.6f}, Mean diff: {mean_diff.item():.6f}, Cosine sim: {cos_sim:.6f}"
|
||||
)
|
||||
|
||||
# Outputs should be reasonably close
|
||||
# assert max_diff < 1e-1, f"Fused and naive outputs should be reasonably close for shape (Z={Z}, H={H}, N_CTX={N_CTX}, HEAD_DIM={HEAD_DIM}), got max_diff={max_diff.item():.6f}"
|
||||
|
||||
print(f"✓ Fused attention shape test passed for (Z={Z}, H={H}, N_CTX={N_CTX}, HEAD_DIM={HEAD_DIM})")
|
||||
|
||||
@@ -830,14 +750,12 @@ def test_fused_attention_non_causal():
|
||||
sm_scale = 1.0 / sqrt(HEAD_DIM)
|
||||
causal = False
|
||||
|
||||
# Create input tensors in BLHD format
|
||||
q_BLHD = torch.randn((Z, N_CTX, H, HEAD_DIM), dtype=dtype, device=DEVICE)
|
||||
k_BLHD = torch.randn((Z, N_CTX, H, HEAD_DIM), dtype=dtype, device=DEVICE)
|
||||
v_BLHD = torch.randn((Z, N_CTX, H, HEAD_DIM), dtype=dtype, device=DEVICE)
|
||||
|
||||
out_fused_BLHD = fused_attn_wrapper(q_BLHD.clone(), k_BLHD.clone(), v_BLHD.clone(), causal, sm_scale)
|
||||
|
||||
# Convert to BHLD for naive attention
|
||||
q_BHLD = q_BLHD.permute(0, 2, 1, 3).contiguous()
|
||||
k_BHLD = k_BLHD.permute(0, 2, 1, 3).contiguous()
|
||||
v_BHLD = v_BLHD.permute(0, 2, 1, 3).contiguous()
|
||||
@@ -857,8 +775,6 @@ def test_fused_attention_non_causal():
|
||||
f" Fused vs Naive (non-causal) - Max diff: {max_diff.item():.6f}, Mean diff: {mean_diff.item():.6f}, Cosine sim: {cos_sim:.6f}"
|
||||
)
|
||||
|
||||
# Outputs should be reasonably close
|
||||
# assert max_diff < 1e-1, f"Fused and naive outputs should be reasonably close for non-causal, got max_diff={max_diff.item():.6f}"
|
||||
|
||||
print("✓ Fused attention non-causal test passed.")
|
||||
|
||||
@@ -872,14 +788,12 @@ def test_fused_attention_causal():
|
||||
sm_scale = 1.0 / sqrt(HEAD_DIM)
|
||||
causal = True
|
||||
|
||||
# Create input tensors in BLHD format
|
||||
q_BLHD = torch.randn((Z, N_CTX, H, HEAD_DIM), dtype=dtype, device=DEVICE)
|
||||
k_BLHD = torch.randn((Z, N_CTX, H, HEAD_DIM), dtype=dtype, device=DEVICE)
|
||||
v_BLHD = torch.randn((Z, N_CTX, H, HEAD_DIM), dtype=dtype, device=DEVICE)
|
||||
|
||||
out_fused_BLHD = fused_attn_wrapper(q_BLHD.clone(), k_BLHD.clone(), v_BLHD.clone(), causal, sm_scale)
|
||||
|
||||
# Convert to BHLD for naive attention
|
||||
q_BHLD = q_BLHD.permute(0, 2, 1, 3).contiguous()
|
||||
k_BHLD = k_BLHD.permute(0, 2, 1, 3).contiguous()
|
||||
v_BHLD = v_BLHD.permute(0, 2, 1, 3).contiguous()
|
||||
@@ -899,8 +813,6 @@ def test_fused_attention_causal():
|
||||
f" Fused vs Naive (causal) - Max diff: {max_diff.item():.6f}, Mean diff: {mean_diff.item():.6f}, Cosine sim: {cos_sim:.6f}"
|
||||
)
|
||||
|
||||
# Outputs should be reasonably close
|
||||
# assert max_diff < 1e-1, f"Fused and naive outputs should be reasonably close for causal, got max_diff={max_diff.item():.6f}"
|
||||
|
||||
print("✓ Fused attention causal test passed.")
|
||||
|
||||
@@ -914,12 +826,10 @@ def test_fused_attention_causal_backward():
|
||||
sm_scale = 1.0 / sqrt(HEAD_DIM)
|
||||
causal = True
|
||||
|
||||
# Create input tensors in BLHD format for fused attention
|
||||
q_fused_BLHD = torch.randn((Z, N_CTX, H, HEAD_DIM), dtype=dtype, device=DEVICE, requires_grad=True)
|
||||
k_fused_BLHD = torch.randn((Z, N_CTX, H, HEAD_DIM), dtype=dtype, device=DEVICE, requires_grad=True)
|
||||
v_fused_BLHD = torch.randn((Z, N_CTX, H, HEAD_DIM), dtype=dtype, device=DEVICE, requires_grad=True)
|
||||
|
||||
# Create input tensors for naive (same values, convert to BHLD)
|
||||
q_naive_BHLD = q_fused_BLHD.clone().permute(0, 2, 1, 3).contiguous().detach().requires_grad_(True)
|
||||
k_naive_BHLD = k_fused_BLHD.clone().permute(0, 2, 1, 3).contiguous().detach().requires_grad_(True)
|
||||
v_naive_BHLD = v_fused_BLHD.clone().permute(0, 2, 1, 3).contiguous().detach().requires_grad_(True)
|
||||
@@ -931,7 +841,6 @@ def test_fused_attention_causal_backward():
|
||||
out_naive_BHLD = naive_attention(q_naive_BHLD, k_naive_BHLD, v_naive_BHLD, causal, sm_scale)
|
||||
out_naive_BHLD = out_naive_BHLD.permute(0, 2, 1, 3).contiguous()
|
||||
|
||||
# Create dummy gradient
|
||||
dout = torch.randn_like(out_fused_BLHD).contiguous()
|
||||
|
||||
# Backward pass for fused attention
|
||||
@@ -940,12 +849,10 @@ def test_fused_attention_causal_backward():
|
||||
# Backward pass for naive
|
||||
out_naive_BHLD.backward(dout)
|
||||
|
||||
# Check that gradients are computed
|
||||
assert q_fused_BLHD.grad is not None
|
||||
assert k_fused_BLHD.grad is not None
|
||||
assert v_fused_BLHD.grad is not None
|
||||
|
||||
# Convert naive gradients to BLHD format for comparison
|
||||
q_naive_grad_BLHD = q_naive_BHLD.grad.permute(0, 2, 1, 3).contiguous()
|
||||
k_naive_grad_BLHD = k_naive_BHLD.grad.permute(0, 2, 1, 3).contiguous()
|
||||
v_naive_grad_BLHD = v_naive_BHLD.grad.permute(0, 2, 1, 3).contiguous()
|
||||
@@ -996,14 +903,11 @@ def test_fused_vs_qat_attention_forward():
|
||||
v_qat_BLHD = v_BLHD.clone().to(torch.bfloat16)
|
||||
out_qat_BLHD = attn_qat_train_wrapper(q_qat_BLHD, k_qat_BLHD, v_qat_BLHD, causal, sm_scale)
|
||||
|
||||
# Convert QAT output back to float16 for comparison
|
||||
out_qat_BLHD = out_qat_BLHD.to(torch.bfloat16)
|
||||
|
||||
# Check that outputs have correct shape
|
||||
assert out_fused_BLHD.shape == (Z, N_CTX, H, HEAD_DIM)
|
||||
assert out_qat_BLHD.shape == (Z, N_CTX, H, HEAD_DIM)
|
||||
|
||||
# Check that outputs are finite
|
||||
assert torch.isfinite(out_fused_BLHD).all()
|
||||
assert torch.isfinite(out_qat_BLHD).all()
|
||||
|
||||
@@ -1015,8 +919,6 @@ def test_fused_vs_qat_attention_forward():
|
||||
f" Fused vs QAT - Max diff: {max_diff.item():.6f}, Mean diff: {mean_diff.item():.6f}, Cosine sim: {cos_sim:.6f}"
|
||||
)
|
||||
|
||||
# They may differ due to quantization in QAT and different implementations
|
||||
# assert max_diff < 1.0, f"Fused and QAT outputs should be reasonably close, got max_diff={max_diff.item():.6f}"
|
||||
|
||||
print("✓ Fused vs QAT forward pass test passed.")
|
||||
|
||||
@@ -1030,12 +932,10 @@ def test_fused_vs_qat_attention_backward():
|
||||
sm_scale = 1.0 / sqrt(HEAD_DIM)
|
||||
causal = True
|
||||
|
||||
# Create input tensors in BLHD format for fused attention (float16)
|
||||
q_fused_BLHD = torch.randn((Z, N_CTX, H, HEAD_DIM), dtype=torch.bfloat16, device=DEVICE, requires_grad=True)
|
||||
k_fused_BLHD = torch.randn((Z, N_CTX, H, HEAD_DIM), dtype=torch.bfloat16, device=DEVICE, requires_grad=True)
|
||||
v_fused_BLHD = torch.randn((Z, N_CTX, H, HEAD_DIM), dtype=torch.bfloat16, device=DEVICE, requires_grad=True)
|
||||
|
||||
# Create input tensors for QAT (float16, same values)
|
||||
q_qat_BLHD = q_fused_BLHD.clone().to(torch.bfloat16).detach().requires_grad_(True)
|
||||
k_qat_BLHD = k_fused_BLHD.clone().to(torch.bfloat16).detach().requires_grad_(True)
|
||||
v_qat_BLHD = v_fused_BLHD.clone().to(torch.bfloat16).detach().requires_grad_(True)
|
||||
@@ -1046,7 +946,6 @@ def test_fused_vs_qat_attention_backward():
|
||||
# Forward pass with QAT
|
||||
out_qat_BLHD = attn_qat_train_wrapper(q_qat_BLHD, k_qat_BLHD, v_qat_BLHD, causal, sm_scale)
|
||||
|
||||
# Create dummy gradient (same for both, in BLHD format)
|
||||
dout = torch.randn_like(out_fused_BLHD).contiguous()
|
||||
dout_qat = dout.to(torch.bfloat16)
|
||||
|
||||
@@ -1056,7 +955,6 @@ def test_fused_vs_qat_attention_backward():
|
||||
# Backward pass for QAT
|
||||
out_qat_BLHD.backward(dout_qat)
|
||||
|
||||
# Check that gradients are computed
|
||||
assert q_fused_BLHD.grad is not None
|
||||
assert k_fused_BLHD.grad is not None
|
||||
assert v_fused_BLHD.grad is not None
|
||||
@@ -1064,17 +962,14 @@ def test_fused_vs_qat_attention_backward():
|
||||
assert k_qat_BLHD.grad is not None
|
||||
assert v_qat_BLHD.grad is not None
|
||||
|
||||
# Check that gradients have correct shape
|
||||
assert q_fused_BLHD.grad.shape == q_fused_BLHD.shape
|
||||
assert k_fused_BLHD.grad.shape == k_fused_BLHD.shape
|
||||
assert v_fused_BLHD.grad.shape == v_fused_BLHD.shape
|
||||
|
||||
# Check that gradients are finite
|
||||
assert torch.isfinite(q_fused_BLHD.grad).all()
|
||||
assert torch.isfinite(k_fused_BLHD.grad).all()
|
||||
assert torch.isfinite(v_fused_BLHD.grad).all()
|
||||
|
||||
# Convert QAT gradients to float16 for comparison
|
||||
q_qat_grad_f16 = q_qat_BLHD.grad.to(torch.bfloat16)
|
||||
k_qat_grad_f16 = k_qat_BLHD.grad.to(torch.bfloat16)
|
||||
v_qat_grad_f16 = v_qat_BLHD.grad.to(torch.bfloat16)
|
||||
@@ -1098,10 +993,6 @@ def test_fused_vs_qat_attention_backward():
|
||||
f" dV - Max diff: {dv_diff.max().item():.6f}, Mean diff: {dv_diff.mean().item():.6f}, Cosine sim: {dv_cos_sim:.6f}"
|
||||
)
|
||||
|
||||
# Gradients may differ due to quantization in QAT and different implementations
|
||||
# assert dq_diff.max() < 2.0, f"dQ gradients should be reasonably close, got max_diff={dq_diff.max().item():.6f}"
|
||||
# assert dk_diff.max() < 2.0, f"dK gradients should be reasonably close, got max_diff={dk_diff.max().item():.6f}"
|
||||
# assert dv_diff.max() < 2.0, f"dV gradients should be reasonably close, got max_diff={dv_diff.max().item():.6f}"
|
||||
|
||||
print("✓ Fused vs QAT backward pass test passed.")
|
||||
|
||||
@@ -1120,7 +1011,6 @@ def test_fused_vs_qat_attention_different_shapes():
|
||||
for Z, H, N_CTX, HEAD_DIM in test_configs:
|
||||
sm_scale = 1.0 / sqrt(HEAD_DIM)
|
||||
|
||||
# Create input tensors in BLHD format (float16)
|
||||
q_BLHD = torch.randn((Z, N_CTX, H, HEAD_DIM), dtype=torch.bfloat16, device=DEVICE)
|
||||
k_BLHD = torch.randn((Z, N_CTX, H, HEAD_DIM), dtype=torch.bfloat16, device=DEVICE)
|
||||
v_BLHD = torch.randn((Z, N_CTX, H, HEAD_DIM), dtype=torch.bfloat16, device=DEVICE)
|
||||
@@ -1148,8 +1038,6 @@ def test_fused_vs_qat_attention_different_shapes():
|
||||
f" (Z={Z}, H={H}, N_CTX={N_CTX}, HEAD_DIM={HEAD_DIM}) - Max diff: {max_diff.item():.6f}, Mean diff: {mean_diff.item():.6f}, Cosine sim: {cos_sim:.6f}"
|
||||
)
|
||||
|
||||
# Outputs may differ due to quantization in QAT
|
||||
# assert max_diff < 1.0, f"Fused and QAT outputs should be reasonably close for shape (Z={Z}, H={H}, N_CTX={N_CTX}, HEAD_DIM={HEAD_DIM}), got max_diff={max_diff.item():.6f}"
|
||||
|
||||
print(f"✓ Fused vs QAT shape test passed for (Z={Z}, H={H}, N_CTX={N_CTX}, HEAD_DIM={HEAD_DIM})")
|
||||
|
||||
@@ -1162,7 +1050,6 @@ def test_fused_vs_qat_attention_non_causal():
|
||||
sm_scale = 1.0 / sqrt(HEAD_DIM)
|
||||
causal = False
|
||||
|
||||
# Create input tensors in BLHD format (float16)
|
||||
q_BLHD = torch.randn((Z, N_CTX, H, HEAD_DIM), dtype=torch.bfloat16, device=DEVICE)
|
||||
k_BLHD = torch.randn((Z, N_CTX, H, HEAD_DIM), dtype=torch.bfloat16, device=DEVICE)
|
||||
v_BLHD = torch.randn((Z, N_CTX, H, HEAD_DIM), dtype=torch.bfloat16, device=DEVICE)
|
||||
@@ -1190,8 +1077,6 @@ def test_fused_vs_qat_attention_non_causal():
|
||||
f" Fused vs QAT (non-causal) - Max diff: {max_diff.item():.6f}, Mean diff: {mean_diff.item():.6f}, Cosine sim: {cos_sim:.6f}"
|
||||
)
|
||||
|
||||
# Outputs may differ due to quantization in QAT
|
||||
# assert max_diff < 1.0, f"Fused and QAT outputs should be reasonably close for non-causal, got max_diff={max_diff.item():.6f}"
|
||||
|
||||
print("✓ Fused vs QAT non-causal test passed.")
|
||||
|
||||
@@ -1204,7 +1089,6 @@ def test_fused_vs_qat_attention_causal():
|
||||
sm_scale = 1.0 / sqrt(HEAD_DIM)
|
||||
causal = True
|
||||
|
||||
# Create input tensors in BLHD format (float16)
|
||||
q_BLHD = torch.randn((Z, N_CTX, H, HEAD_DIM), dtype=torch.bfloat16, device=DEVICE)
|
||||
k_BLHD = torch.randn((Z, N_CTX, H, HEAD_DIM), dtype=torch.bfloat16, device=DEVICE)
|
||||
v_BLHD = torch.randn((Z, N_CTX, H, HEAD_DIM), dtype=torch.bfloat16, device=DEVICE)
|
||||
@@ -1232,8 +1116,6 @@ def test_fused_vs_qat_attention_causal():
|
||||
f" Fused vs QAT (causal) - Max diff: {max_diff.item():.6f}, Mean diff: {mean_diff.item():.6f}, Cosine sim: {cos_sim:.6f}"
|
||||
)
|
||||
|
||||
# Outputs may differ due to quantization in QAT
|
||||
# assert max_diff < 1.0, f"Fused and QAT outputs should be reasonably close for causal, got max_diff={max_diff.item():.6f}"
|
||||
|
||||
print("✓ Fused vs QAT causal test passed.")
|
||||
|
||||
@@ -1246,12 +1128,10 @@ def test_fused_vs_qat_attention_causal_backward():
|
||||
sm_scale = 1.0 / sqrt(HEAD_DIM)
|
||||
causal = True
|
||||
|
||||
# Create input tensors in BLHD format for fused attention (float16)
|
||||
q_fused_BLHD = torch.randn((Z, N_CTX, H, HEAD_DIM), dtype=torch.bfloat16, device=DEVICE, requires_grad=True)
|
||||
k_fused_BLHD = torch.randn((Z, N_CTX, H, HEAD_DIM), dtype=torch.bfloat16, device=DEVICE, requires_grad=True)
|
||||
v_fused_BLHD = torch.randn((Z, N_CTX, H, HEAD_DIM), dtype=torch.bfloat16, device=DEVICE, requires_grad=True)
|
||||
|
||||
# Create input tensors for QAT (float16, same values)
|
||||
q_qat_BLHD = q_fused_BLHD.clone().to(torch.bfloat16).detach().requires_grad_(True)
|
||||
k_qat_BLHD = k_fused_BLHD.clone().to(torch.bfloat16).detach().requires_grad_(True)
|
||||
v_qat_BLHD = v_fused_BLHD.clone().to(torch.bfloat16).detach().requires_grad_(True)
|
||||
@@ -1262,7 +1142,6 @@ def test_fused_vs_qat_attention_causal_backward():
|
||||
# Forward pass with QAT
|
||||
out_qat_BLHD = attn_qat_train_wrapper(q_qat_BLHD, k_qat_BLHD, v_qat_BLHD, causal, sm_scale)
|
||||
|
||||
# Create dummy gradient
|
||||
dout = torch.randn_like(out_fused_BLHD).contiguous()
|
||||
dout_qat = dout.to(torch.bfloat16)
|
||||
|
||||
@@ -1272,7 +1151,6 @@ def test_fused_vs_qat_attention_causal_backward():
|
||||
# Backward pass for QAT
|
||||
out_qat_BLHD.backward(dout_qat)
|
||||
|
||||
# Check that gradients are computed
|
||||
assert q_fused_BLHD.grad is not None
|
||||
assert k_fused_BLHD.grad is not None
|
||||
assert v_fused_BLHD.grad is not None
|
||||
@@ -1280,7 +1158,6 @@ def test_fused_vs_qat_attention_causal_backward():
|
||||
assert k_qat_BLHD.grad is not None
|
||||
assert v_qat_BLHD.grad is not None
|
||||
|
||||
# Convert QAT gradients to float16 for comparison
|
||||
q_qat_grad_f16 = q_qat_BLHD.grad.to(torch.bfloat16)
|
||||
k_qat_grad_f16 = k_qat_BLHD.grad.to(torch.bfloat16)
|
||||
v_qat_grad_f16 = v_qat_BLHD.grad.to(torch.bfloat16)
|
||||
@@ -1319,7 +1196,6 @@ def test_qat_attention_wan_shape_forward():
|
||||
|
||||
print(f" Testing WAN shape: Z={Z}, H={H}, N_CTX={N_CTX}, HEAD_DIM={HEAD_DIM}")
|
||||
|
||||
# Create input tensors in BLHD format (B, L, H, D) = (Z, N_CTX, H, HEAD_DIM)
|
||||
q_BLHD = torch.randn((Z, N_CTX, H, HEAD_DIM), dtype=dtype, device=DEVICE)
|
||||
k_BLHD = torch.randn((Z, N_CTX, H, HEAD_DIM), dtype=dtype, device=DEVICE)
|
||||
v_BLHD = torch.randn((Z, N_CTX, H, HEAD_DIM), dtype=dtype, device=DEVICE)
|
||||
@@ -1327,7 +1203,6 @@ def test_qat_attention_wan_shape_forward():
|
||||
# Test with QAT (using wrapper that does permute/contiguous)
|
||||
out_qat_BLHD = attn_qat_train_wrapper(q_BLHD.clone(), k_BLHD.clone(), v_BLHD.clone(), causal, sm_scale)
|
||||
|
||||
# Convert to BHLD for naive attention comparison
|
||||
q_BHLD = q_BLHD.permute(0, 2, 1, 3).contiguous()
|
||||
k_BHLD = k_BLHD.permute(0, 2, 1, 3).contiguous()
|
||||
v_BHLD = v_BLHD.permute(0, 2, 1, 3).contiguous()
|
||||
@@ -1338,11 +1213,9 @@ def test_qat_attention_wan_shape_forward():
|
||||
print(f" Expected shape: {(Z, N_CTX, H, HEAD_DIM)}")
|
||||
print(f" out_qat_BLHD shape: {out_qat_BLHD.shape}")
|
||||
|
||||
# Check that outputs have correct shape
|
||||
assert out_qat_BLHD.shape == (Z, N_CTX, H, HEAD_DIM)
|
||||
assert out_naive_BLHD.shape == (Z, N_CTX, H, HEAD_DIM)
|
||||
|
||||
# Check that outputs are finite
|
||||
assert torch.isfinite(out_qat_BLHD).all()
|
||||
assert torch.isfinite(out_naive_BLHD).all()
|
||||
|
||||
@@ -1393,7 +1266,6 @@ def test_qat_attention_wan_shape_backward():
|
||||
# -----------------------------
|
||||
out_naive_BHLD = naive_attention(q_BHLD, k_BHLD, v_BHLD, causal, sm_scale)
|
||||
|
||||
# Convert naive output back to BLHD for comparing outputs
|
||||
out_naive_BLHD = out_naive_BHLD.permute(0, 2, 1, 3).contiguous()
|
||||
|
||||
# -----------------------------
|
||||
@@ -1597,23 +1469,8 @@ if __name__ == "__main__":
|
||||
print("Running Fused attention tests...")
|
||||
print()
|
||||
|
||||
# test_fused_attention_forward()
|
||||
# test_fused_attention_backward()
|
||||
# test_fused_attention_different_shapes()
|
||||
# test_fused_attention_non_causal()
|
||||
# test_fused_attention_causal()
|
||||
# test_fused_attention_causal_backward()
|
||||
|
||||
# print()
|
||||
# print("Running Fused vs QAT attention comparison tests...")
|
||||
# print()
|
||||
|
||||
# test_fused_vs_qat_attention_forward()
|
||||
# test_fused_vs_qat_attention_backward()
|
||||
# test_fused_vs_qat_attention_different_shapes()
|
||||
# test_fused_vs_qat_attention_non_causal()
|
||||
# test_fused_vs_qat_attention_causal()
|
||||
# test_fused_vs_qat_attention_causal_backward()
|
||||
|
||||
print()
|
||||
print("All tests passed! ✓")
|
||||
|
||||
@@ -2,7 +2,6 @@ import torch
|
||||
from .support_flex_sta import get_sliding_tile_attention_mask
|
||||
from fastvideo_kernel import sliding_tile_attention
|
||||
from torch.nn.attention.flex_attention import flex_attention
|
||||
# from flash_attn_interface import flash_attn_func
|
||||
from tqdm import tqdm
|
||||
|
||||
flex_attention = torch.compile(flex_attention, dynamic=False)
|
||||
@@ -83,7 +82,6 @@ def test_sliding_tile_attention():
|
||||
mean = 1e-1
|
||||
std = 10
|
||||
|
||||
# Run correctness check directly
|
||||
results = check_correctness(b, h, n, d, causal, mean, std, error_mode='output')
|
||||
assert results['TK vs FLEX'][
|
||||
'avg_diff'] < 3e-6, f"Average difference: {results['TK vs FLEX']['avg_diff']} is too large"
|
||||
|
||||
@@ -3,8 +3,6 @@ import pytest
|
||||
import sys
|
||||
import os
|
||||
|
||||
# Ensure local package is imported
|
||||
# sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "../python")))
|
||||
|
||||
try:
|
||||
from fastvideo_kernel._C import fastvideo_kernel_ops
|
||||
@@ -65,20 +63,13 @@ class TestTurboDiffusion:
|
||||
M, N, K = 32, 64, 128
|
||||
x = torch.randn(M, K, dtype=dtype, device="cuda")
|
||||
|
||||
# Create weights
|
||||
# For simplicity in testing, let's create random int8 weights and scales
|
||||
w_q = torch.randint(-127, 127, (N, K), dtype=torch.int8, device="cuda")
|
||||
|
||||
# Scale shape: The Int8Linear class uses:
|
||||
# row_blocks = cdiv(out_features, b=128)
|
||||
# col_blocks = cdiv(in_features, b=128)
|
||||
# scale shape: (row_blocks, col_blocks)
|
||||
|
||||
row_blocks = (N + 127) // 128
|
||||
col_blocks = (K + 127) // 128
|
||||
w_s = torch.randn(row_blocks, col_blocks, dtype=torch.float32, device="cuda").abs()
|
||||
|
||||
# Run int8_linear
|
||||
output = turbodiffusion_ops.int8_linear(x, w_q, w_s)
|
||||
|
||||
assert output.shape == (M, N)
|
||||
@@ -92,7 +83,6 @@ class TestTurboDiffusion:
|
||||
M, N, K = 32, 64, 128
|
||||
x = torch.randn(M, K, dtype=dtype, device="cuda", requires_grad=True)
|
||||
|
||||
# Weights (frozen)
|
||||
w_q = torch.randint(-127, 127, (N, K), dtype=torch.int8, device="cuda")
|
||||
row_blocks = (N + 127) // 128
|
||||
col_blocks = (K + 127) // 128
|
||||
@@ -100,7 +90,6 @@ class TestTurboDiffusion:
|
||||
|
||||
bias = torch.randn(N, dtype=dtype, device="cuda", requires_grad=True)
|
||||
|
||||
# Use Int8LinearFunction
|
||||
output = turbodiffusion_ops.Int8LinearFunction.apply(x, w_q, w_s, bias)
|
||||
loss = output.sum()
|
||||
loss.backward()
|
||||
@@ -109,7 +98,6 @@ class TestTurboDiffusion:
|
||||
assert bias.grad is not None
|
||||
assert x.grad.shape == (M, K)
|
||||
|
||||
# Check correctness against dequantized weight
|
||||
w_float = turbodiffusion_ops.dequantize_weight(w_q, w_s, dtype)
|
||||
|
||||
# Reference
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user