Skip to content

Feature/best of (dev)#453

Open
kkzxak47 wants to merge 32 commits into
devfrom
feature/best_of
Open

Feature/best of (dev)#453
kkzxak47 wants to merge 32 commits into
devfrom
feature/best_of

Conversation

@kkzxak47

@kkzxak47 kkzxak47 commented Mar 10, 2025

Copy link
Copy Markdown
Collaborator

Added a best_of setting, when it is larger than 1, # of completions will be generated and the best one will be returned (the one with the largest mean logprobs).

Implemented batched inference

Summary by Sourcery

Implements a 'best_of' setting to generate multiple completions and return the best one based on accumulated log probabilities. This enhances the quality of generated responses by allowing the model to explore multiple possibilities and select the most likely one.

New Features:

  • Introduces a 'best_of' setting to generate multiple completions and select the best one based on log probabilities.
  • Adds a new setting in the settings window to control the 'best_of' parameter.
  • Implements logic to generate multiple responses and select the best one based on accumulated log probabilities.

Tests:

  • Adds tests to verify that boolean and integer settings are saved and loaded correctly.
  • Adds tests to verify that string representations of integers and integer representations of booleans are converted correctly.
  • Adds tests for error handling and unexpected data in the settings file.

Summary by Sourcery

Implement a 'best_of' feature for generating multiple text completions and selecting the most probable one

New Features:

  • Add a 'best_of' parameter to generate multiple text completions and select the best one based on mean log probabilities
  • Implement batched inference to support parallel generation of multiple candidate completions

Enhancements:

  • Extend the Model class to support generating multiple candidate responses
  • Add a new method generate_best_of_response to handle multiple completion generation
  • Implement a token selection method based on log probabilities

Tests:

  • Add comprehensive tests for the new best_of functionality
  • Create test cases for batched inference and response selection
  • Verify handling of different best_of parameter values

Chores:

  • Add example scripts demonstrating advanced usage of the batched LLM generation
  • Create a new services module for batched LLM inference

@sourcery-ai

sourcery-ai Bot commented Mar 10, 2025

Copy link
Copy Markdown

Reviewer's Guide by Sourcery

This pull request introduces a 'best_of' setting to the Model class, enabling the generation of multiple completions and selection of the best one based on accumulated log probabilities. It also implements batched inference using a new BatchedLLM class to support parallel generation of multiple sequences. Additionally, it adds a setting in the settings window to control the 'best_of' parameter and includes comprehensive tests for the new functionality.

No diagrams generated as the changes look simple and do not need a visual representation.

File-Level Changes

Change Details Files
Introduced a best_of parameter to the Model class, enabling the generation of multiple completions and selection of the best one based on accumulated log probabilities.
  • Added best_of parameter to the Model class constructor.
  • Modified generate_response to call generate_best_of_response with best_of set to 1 to maintain original functionality.
  • Implemented generate_best_of_response to handle the best_of logic, generating multiple responses when best_of > 1.
  • Added a static method _select_best_result to select the best sequence based on mean log probabilities.
  • Utilized BatchedLLM for batched inference when best_of > 1.
  • Added logging for debugging best_of values.
  • Added logic to handle invalid best_of values, treating them as 1.
src/FreeScribe.client/Model.py
Implemented batched inference using a new BatchedLLM class to support parallel generation of multiple sequences.
  • Created a BatchedLLM class in services/batched_llm.py to manage batched inference using llama.cpp bindings.
  • Implemented methods for tokenization, batch management, sampling, and sequence generation within the BatchedLLM class.
  • Added cleanup methods to properly free allocated resources.
  • Implemented helper methods for converting logits to log probabilities and selecting the best result based on log probabilities.
src/FreeScribe.client/services/batched_llm.py
Added a setting in the settings window to control the best_of parameter.
  • Modified SettingsWindow.py to include old_best_of and new_best_of parameters in the load_or_unload_model method.
  • Modified SettingsWindowUI.py to save BEST_OF setting.
  • Modified SettingsConstant.py to include BEST_OF setting.
src/FreeScribe.client/UI/SettingsWindow.py
src/FreeScribe.client/UI/SettingsWindowUI.py
Added tests for the Model class, including tests for the best_of functionality.
  • Added tests for successful model setup and error handling.
  • Added tests for the generate_response and generate_best_of_response methods, including error handling and different best_of values.
  • Added tests for the get_gpu_info, close, and __del__ methods.
  • Added tests for the ModelManager class, including tests for model loading, unloading, and error handling.
tests/test_model.py
Added tests for the BatchedLLM class.
  • Added tests for initialization, cleanup, token conversion, batch operations, logit conversion, tokenization, sampler setup, and generation.
  • Added tests for helper methods such as _prepare_prompt_and_batch, _handle_encoder_decoder, _sample_token, and _finalize_results.
tests/services/test_batched_llm.py
Added examples for using the BatchedLLM class.
  • Added a simple example demonstrating how to use the BatchedLLM class for parallel text generation.
  • Added an advanced example demonstrating how to use the BatchedLLM class for practical applications, including generating multiple candidate continuations, scoring each continuation based on custom criteria, and selecting the best continuation based on the scores.
src/FreeScribe.client/examples/batched_llm_advanced.py
src/FreeScribe.client/examples/batched_llm_example.py

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!
  • Generate a plan of action for an issue: Comment @sourcery-ai plan on
    an issue to generate a plan of action for it.

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Hey @kkzxak47 - I've reviewed your changes - here's some feedback:

Overall Comments:

  • Consider adding a brief explanation of the best_of parameter in the class docstring.
  • The logic for choosing the best response could be extracted into a separate helper function for better readability.
Here's what I looked at during the review
  • 🟢 General issues: all looks good
  • 🟢 Security: all looks good
  • 🟡 Testing: 1 issue found
  • 🟡 Complexity: 2 issues found
  • 🟢 Documentation: all looks good

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment thread tests/test_model.py Outdated
top_p: float = 0.95,
repeat_penalty: float = 1.1,
# you can override the best_of setting here
best_of: int | None = None,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

issue (complexity): Consider extracting the best-of evaluation logic and logging into separate helper functions to reduce nesting and improve readability of the generate_best_of_response function, such as creating a function to compute the logprob sum and content from the response dicts, and using it in the main function to simplify the logic there .

Consider extracting separate helper functions to encapsulate the best‐of evaluation logic and logging. For example, you can split out the token logprob summing and sorting logic into a dedicated function, which will reduce nesting in generate_best_of_response.

Suggested changes:

  1. Extract a helper to compute the logprob sum and content:
def _extract_result(response: dict) -> tuple:
    """Extract the sum of token logprobs and the generated content."""
    token_logprobs = response["choices"][0]["logprobs"]["token_logprobs"]
    content = response["choices"][0]["message"]["content"]
    return (sum(token_logprobs), content)
  1. Refactor generate_best_of_response to use the helper:
def generate_best_of_response(
    self,
    prompt: str,
    max_tokens: int = 50,
    temperature: float = 0.1,
    top_p: float = 0.95,
    repeat_penalty: float = 1.1,
    best_of: int | None = None,
) -> str:
    try:
        messages = [{"role": "user", "content": prompt}]
        _best_of = best_of or self.config.get("best_of") or 1

        logprob_args = {}
        if _best_of > 1:
            logprob_args = {"logprobs": True, "top_logprobs": 1}

        responses = [
            self.model.create_chat_completion(
                messages,
                max_tokens=max_tokens,
                temperature=temperature,
                top_p=top_p,
                repeat_penalty=repeat_penalty,
                **logprob_args
            )
            for _ in range(_best_of)
        ]
        logger.debug(f"Responses: {responses}")

        if _best_of > 1:
            results = [_extract_result(response) for response in responses]
            logger.debug(f"Results: {results}")
            results.sort(key=lambda x: x[0])
        else:
            results = [(0, responses[0]["choices"][0]["message"]["content"])]

        best_response = results[-1]
        self.model.reset()
        logger.debug(f"Selected Response: {best_response}")
        return best_response[1]

    except Exception as e:
        print(f"GPU inference error ({e.__class__.__name__}): {str(e)}")
        return f"({e.__class__.__name__}): {str(e)}"

This refactor maintains functionality while reducing nesting and increasing readability.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

done

Comment thread src/FreeScribe.client/UI/SettingsWindow.py
@kkzxak47 kkzxak47 changed the title Feature/best of Feature/best of (dev) Mar 12, 2025
@yingbull

yingbull commented Apr 7, 2025

Copy link
Copy Markdown

With recent work do we still want to merge this @kkzxak47 ?

@kkzxak47 kkzxak47 marked this pull request as draft April 7, 2025 16:38
@kkzxak47

kkzxak47 commented Apr 7, 2025

Copy link
Copy Markdown
Collaborator Author

With recent work do we still want to merge this @kkzxak47 ?

The current implementation is relatively slow, so I'm exploring an optimization. We don't need to merge it right away. It can be merged later.

@kkzxak47 kkzxak47 marked this pull request as ready for review April 10, 2025 15:51

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Hey @kkzxak47 - I've reviewed your changes - here's some feedback:

Overall Comments:

  • Consider adding a brief explanation of the batched inference approach in the description.
  • The new BatchedLLM class introduces a lot of complexity; ensure it's thoroughly tested, especially edge cases and error handling.
Here's what I looked at during the review
  • 🟡 General issues: 1 issue found
  • 🟢 Security: all looks good
  • 🟢 Testing: all looks good
  • 🟡 Complexity: 1 issue found
  • 🟢 Documentation: all looks good

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment thread src/FreeScribe.client/services/batched_llm.py Outdated
Comment thread src/FreeScribe.client/services/batched_llm.py
Comment thread src/FreeScribe.client/examples/batched_llm_advanced.py Outdated
Comment thread src/FreeScribe.client/services/batched_llm.py Outdated
@kkzxak47 kkzxak47 marked this pull request as draft April 10, 2025 17:09
@kkzxak47 kkzxak47 marked this pull request as ready for review April 10, 2025 17:30

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Hey @kkzxak47 - I've reviewed your changes - here's some feedback:

Overall Comments:

  • Consider adding a brief description of the new BatchedLLM class to the docstring.
  • The _select_best_result method could be a standalone function instead of a static method.
Here's what I looked at during the review
  • 🟡 General issues: 3 issues found
  • 🟢 Security: all looks good
  • 🟢 Testing: all looks good
  • 🟡 Complexity: 1 issue found
  • 🟢 Documentation: all looks good

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment thread src/FreeScribe.client/services/batched_llm.py Outdated
Comment thread src/FreeScribe.client/services/batched_llm.py
Comment thread client_requirements.txt
Comment thread src/FreeScribe.client/Model.py
Comment thread tests/services/test_batched_llm.py Outdated
Comment thread tests/services/test_batched_llm.py Outdated
Comment thread src/FreeScribe.client/examples/batched_llm_advanced.py
Comment thread tests/services/test_batched_llm.py Outdated
Comment thread tests/services/test_batched_llm.py Outdated
Comment on lines +262 to +263
if 0 <= index < 5:
return index + 1

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

issue (code-quality): We've found these issues:

Comment thread tests/services/test_batched_llm.py Outdated
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.

2 participants