Skip to content

patch: fix EmptyLogits TypeError in pad_across_processes#6035

Open
MdHussain121 wants to merge 4 commits into
unslothai:mainfrom
MdHussain121:patch-accelerate-recursively-apply
Open

patch: fix EmptyLogits TypeError in pad_across_processes#6035
MdHussain121 wants to merge 4 commits into
unslothai:mainfrom
MdHussain121:patch-accelerate-recursively-apply

Conversation

@MdHussain121
Copy link
Copy Markdown

This PR fixes the TypeError raised during evaluation loops when using Hugging Face Trainer and accelerate.

Problem

During evaluation, Trainer gathers logits using \�ccelerate.utils.operations.pad_across_processes\ (or \gather), which traverses datasets using
ecursively_apply\ with \error_on_other_type=True. Because Unsloth's \EmptyLogits\ is not a standard PyTorch Tensor or container,
ecursively_apply\ fails with:
\TypeError: Unsupported types (<class 'unsloth.models._utils.EmptyLogits'>) passed to _pad_across_processes\

Solution

Added a monkeypatch \patch_accelerate_recursively_apply\ in \unsloth.import_fixes\ that intercepts
ecursively_apply\ for \EmptyLogits\ inputs and returns them unmodified.
A drift detector test has been added to \ ests/test_import_fixes_drift.py\ to verify this behavior.

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a patch patch_accelerate_recursively_apply to override accelerate.utils.operations.recursively_apply (and its re-export in accelerate.utils) to bypass Unsloth's EmptyLogits class, preventing potential TypeError exceptions. This patch is integrated into the GPU initialization process, and a corresponding unit test is added. The review feedback suggests refactoring the patch implementation to eliminate duplicated wrapper code and correcting a PEP 8 style violation regarding spaces around keyword arguments in the test file.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread unsloth/import_fixes.py
Comment on lines +2197 to +2229
def patch_accelerate_recursively_apply():
"""
Patch accelerate.utils.operations.recursively_apply to avoid raising
TypeError when encountering Unsloth's EmptyLogits class.
"""
try:
import accelerate.utils.operations as acc_ops

original_recursively_apply = acc_ops.recursively_apply

@functools.wraps(original_recursively_apply)
def _patched_recursively_apply(func, data, *args, **kwargs):
if type(data).__name__ == "EmptyLogits":
return data
return original_recursively_apply(func, data, *args, **kwargs)

acc_ops.recursively_apply = _patched_recursively_apply
except Exception:
pass

try:
import accelerate.utils as acc_utils

if hasattr(acc_utils, "recursively_apply"):
original_recursively_apply = acc_utils.recursively_apply

@functools.wraps(original_recursively_apply)
def _patched_recursively_apply(func, data, *args, **kwargs):
if type(data).__name__ == "EmptyLogits":
return data
return original_recursively_apply(func, data, *args, **kwargs)

acc_utils.recursively_apply = _patched_recursively_apply
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The implementation of patch_accelerate_recursively_apply contains duplicated code for defining and applying _patched_recursively_apply. Since accelerate.utils.recursively_apply is just a re-export of accelerate.utils.operations.recursively_apply, we can define the wrapper once and reuse it, which improves maintainability and readability.

def patch_accelerate_recursively_apply():
    """
    Patch accelerate.utils.operations.recursively_apply to avoid raising
    TypeError when encountering Unsloth's EmptyLogits class.
    """
    try:
        import accelerate.utils.operations as acc_ops
        original_recursively_apply = acc_ops.recursively_apply

        @functools.wraps(original_recursively_apply)
        def _patched_recursively_apply(func, data, *args, **kwargs):
            if type(data).__name__ == "EmptyLogits":
                return data
            return original_recursively_apply(func, data, *args, **kwargs)

        acc_ops.recursively_apply = _patched_recursively_apply

        try:
            import accelerate.utils as acc_utils
            if hasattr(acc_utils, "recursively_apply"):
                acc_utils.recursively_apply = _patched_recursively_apply
        except Exception:
            pass
    except Exception:
        pass

Comment thread tests/test_import_fixes_drift.py Outdated
e = EmptyLogits()
patch_accelerate_recursively_apply()

res = acc_ops.recursively_apply(lambda x: x, e, error_on_other_type = True)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

According to PEP 8, spaces should not be used around the = sign when used to indicate a keyword argument or a default parameter value. Please remove the spaces around = in error_on_other_type = True.

Suggested change
res = acc_ops.recursively_apply(lambda x: x, e, error_on_other_type = True)
res = acc_ops.recursively_apply(lambda x: x, e, error_on_other_type=True)
References
  1. PEP 8: Don't use spaces around the = sign when used to indicate a keyword argument or a default parameter value. (link)

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 769151b13f

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread unsloth/import_fixes.py
Comment on lines +2229 to +2230
if type(data).__name__ == "EmptyLogits":
return data
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Handle EmptyLogits before Accelerate debug verification

When Accelerate debug mode is enabled in distributed evaluation (ACCELERATE_DEBUG_MODE=1 / PartialState().debug), gather runs its verification wrapper before it reaches _gpu_gather and this patched recursively_apply; that wrapper calls find_device/get_shape on the logits structure, so a top-level EmptyLogits still raises before the bypass, and a nested one can make shape comparison fail across processes. This means the evaluation path this patch is meant to fix still breaks under Accelerate's debug mode unless the EmptyLogits case is handled at the operation/wrapper level as well.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant