fix: apply peft<->gptqmodel AWQ shim on the inference LoRA path too

Loading a trained LoRA at inference (e.g. a fighter LoRA on an image pipeline)
crashed with "cannot import name AwqGEMMQuantLinear" because peft dispatches AWQ
for any non-bnb target when gptqmodel is installed, and gptqmodel 7.1.0 renamed
that class to AwqGEMMLinear. The alias shim existed only in the training path.

Extract it to codai/models/peft_compat.ensure_peft_awq_compat() (cached) and call
it before load_lora_weights in codai/api/images._apply_loras and the acceleration
fuse path; the trainer now delegates to the shared shim.
Co-Authored-By: 's avatarClaude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RdMufYvtTbtGDWsiZVoXce
parent 2b6942d7
......@@ -16,7 +16,7 @@
# Canonical product version for CoderAI — single source of truth. Both the API
# metadata and the admin web UI read from here.
__version__ = "0.1.25"
__version__ = "0.1.26"
# Configure the CUDA caching allocator BEFORE torch is imported anywhere.
# expandable_segments lets the allocator return freed pages to the driver even
......
......@@ -676,6 +676,11 @@ def _ensure_ip_adapter_loaded(pipeline) -> bool:
def _apply_loras(pipeline, loras):
"""Load and activate LoRA weights on a diffusers pipeline."""
try:
# peft dispatches AWQ for any non-bnb target when gptqmodel is installed;
# gptqmodel 7.1.0 renamed the class peft imports, which would crash
# load_lora_weights below. Alias it before applying any adapter.
from codai.models.peft_compat import ensure_peft_awq_compat
ensure_peft_awq_compat()
names = []
weights = []
for i, lora in enumerate(loras):
......
......@@ -1443,13 +1443,11 @@ def _ensure_peft_awq_compat():
import AwqGEMMQuantLinear`, but gptqmodel 7.1.0 renamed that class to
AwqGEMMLinear. Since peft calls dispatch_awq for ANY non-bnb target whenever
gptqmodel is installed, the failed import crashes EVERY add_adapter() (SDXL, Wan
and Z-Image LoRA training alike). Alias the renamed class so the import succeeds;
no-op when the name already exists or gptqmodel isn't present."""
and Z-Image LoRA training alike). Delegates to the shared shim (also used by
the inference LoRA-apply path)."""
try:
import importlib
m = importlib.import_module("gptqmodel.nn_modules.qlinear.gemm_awq")
if not hasattr(m, "AwqGEMMQuantLinear") and hasattr(m, "AwqGEMMLinear"):
m.AwqGEMMQuantLinear = m.AwqGEMMLinear
from codai.models.peft_compat import ensure_peft_awq_compat
ensure_peft_awq_compat()
except Exception:
pass
......
......@@ -293,6 +293,14 @@ def apply_accel_to_pipeline(pipe, accel: Optional[dict]) -> None:
"acceleration LoRA", type(pipe).__name__)
return
# gptqmodel 7.1.0 renamed the AWQ class peft imports during dispatch; alias
# it before any load_lora_weights so the import doesn't crash the fuse.
try:
from codai.models.peft_compat import ensure_peft_awq_compat
ensure_peft_awq_compat()
except Exception:
pass
weight = float(accel.get("lora_weight") or 1.0)
def _load_one(ref, into_t2: bool, adapter: str) -> bool:
......
# CoderAI - OpenAI-compatible API server
# Copyright (C) 2026 Stefy Lanza <stefy@nexlab.net>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
"""Compatibility shims for peft <-> gptqmodel version skew."""
_awq_aliased = False
def ensure_peft_awq_compat():
"""peft's LoRA AWQ dispatcher does ``from gptqmodel.nn_modules.qlinear.gemm_awq
import AwqGEMMQuantLinear``, but gptqmodel 7.1.0 renamed that class to
AwqGEMMLinear. peft calls dispatch_awq for ANY non-bnb target whenever
gptqmodel is installed, so the failed import crashes EVERY add_adapter() /
load_lora_weights() — at LoRA *training* AND at *inference* when a trained
LoRA is applied to a pipeline. Alias the renamed class so the import succeeds;
no-op when the name already exists or gptqmodel isn't present. Cached so the
per-request inference path doesn't re-import gptqmodel every call."""
global _awq_aliased
if _awq_aliased:
return
try:
import importlib
m = importlib.import_module("gptqmodel.nn_modules.qlinear.gemm_awq")
if not hasattr(m, "AwqGEMMQuantLinear") and hasattr(m, "AwqGEMMLinear"):
m.AwqGEMMQuantLinear = m.AwqGEMMLinear
_awq_aliased = True
except Exception:
# gptqmodel not installed, or import failed — nothing to alias. Don't
# cache so a later call can retry once gptqmodel is importable.
pass
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment