-
Notifications
You must be signed in to change notification settings - Fork 0
SDK-43: Add LLM unlearning models support #187
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
benglewis
merged 28 commits into
main
from
codex/2026-01-13/linear-mention-sdk-43-add-support-for-unlearning-for-llm
Jan 25, 2026
Merged
Changes from all commits
Commits
Show all changes
28 commits
Select commit
Hold shift + click to select a range
28b6c1c
Refine LLM unlearning models
benglewis 96e8137
Move `get_unique_id` to a new `testing_utils` file
benglewis ea21669
Add small / Smol test
benglewis a3737df
Switch to `nvidia/Nemotron-Flash-1B` since it turns out that SmolLM2-…
benglewis 4c968f0
Fix unlearning LLM run typing
benglewis 493191e
Refine LLM run list typing
benglewis 32c2096
Type unlearning run list responses
benglewis 0349fae
Handle empty target utilities explicitly
benglewis 418b923
Merge remote-tracking branch 'origin/codex/2026-01-13/linear-mention-…
benglewis 8fcbda0
Merge remote-tracking branch 'origin/codex/2026-01-13/linear-mention-…
benglewis b062346
Merge branch 'main' into codex/2026-01-13/linear-mention-sdk-43-add-s…
benglewis b1b1823
Fix Ruff lint errors and basedpyright errors
benglewis ec89380
Add `check_run` and `acheck_run` (and `check_run_by_id` and `acheck_r…
benglewis be58f5d
Reduce duplicate code
benglewis 17f756e
LLM behavior unlearning test and loading of transformers Pipeline
benglewis fb991d6
Fix `numpy` version error
benglewis 5eea81a
Fix requirements files
benglewis e10613e
Fix retries when HTTP SSE request fails
benglewis 898c7f8
Fix Misha's PR comment
benglewis 9b42aa5
Fix ChatGPT PR review comments
benglewis 785155b
Fix Gemini's PR comment
benglewis d02a588
Fix bug in `deleted_at` field for `OutputUnlearningLlmRun`
benglewis 73d8597
Rename `get_pipeline_for_run` to `get_hf_pipeline_for_run`
benglewis 1bd8c92
Fix `MODEL_FOR_IMAGE_TEXT_TO_TEXT_MAPPING_NAMES` being used instead o…
benglewis efa2e01
Fix pydantic error due to class not really being imported at runtime
benglewis 47c7acf
Fix `deleted_at` being missing crashing the tests
benglewis 3eabf6c
Switch to `API_HOST2` and `API_KEY2` for now until `test` contains LL…
benglewis 60ebe02
Fix unlearning LLM behavior test running on every platform
benglewis File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,153 @@ | ||
| import importlib.util | ||
| import tempfile | ||
| import zipfile | ||
| from pathlib import Path | ||
| from typing import TYPE_CHECKING, cast | ||
|
|
||
| from hirundo import HirundoError | ||
| from hirundo._http import requests | ||
| from hirundo._timeouts import DOWNLOAD_READ_TIMEOUT | ||
| from hirundo.logger import get_logger | ||
|
|
||
| if TYPE_CHECKING: | ||
| from torch import device as torch_device | ||
| from transformers.configuration_utils import PretrainedConfig | ||
| from transformers.modeling_utils import PreTrainedModel | ||
| from transformers.pipelines.base import Pipeline | ||
|
|
||
| from hirundo.unlearning_llm import LlmModel, LlmModelOut | ||
|
|
||
| logger = get_logger(__name__) | ||
|
|
||
|
|
||
| ZIP_FILE_CHUNK_SIZE = 50 * 1024 * 1024 # 50 MB | ||
| REQUIRED_PACKAGES_FOR_PIPELINE = ["peft", "transformers", "accelerate"] | ||
|
|
||
|
|
||
| def get_hf_pipeline_for_run_given_model( | ||
| llm: "LlmModel | LlmModelOut", | ||
| run_id: str, | ||
| config: "PretrainedConfig | None" = None, | ||
| device: "str | int | torch_device | None" = None, | ||
| device_map: str | dict[str, int | str] | None = None, | ||
| trust_remote_code: bool = False, | ||
| token: str | None = None, | ||
| ) -> "Pipeline": | ||
| for package in REQUIRED_PACKAGES_FOR_PIPELINE: | ||
| if importlib.util.find_spec(package) is None: | ||
| raise HirundoError( | ||
| f'{package} is not installed. Please install transformers extra with pip install "hirundo[transformers]"' | ||
| ) | ||
| from peft import PeftModel | ||
| from transformers.models.auto.configuration_auto import AutoConfig | ||
| from transformers.models.auto.modeling_auto import ( | ||
| MODEL_FOR_IMAGE_TEXT_TO_TEXT_MAPPING_NAMES, | ||
| AutoModelForCausalLM, | ||
| AutoModelForImageTextToText, | ||
| ) | ||
| from transformers.models.auto.tokenization_auto import AutoTokenizer | ||
| from transformers.pipelines import pipeline | ||
|
|
||
| from hirundo.unlearning_llm import ( | ||
| HuggingFaceTransformersModel, | ||
| HuggingFaceTransformersModelOutput, | ||
| LlmUnlearningRun, | ||
| ) | ||
|
|
||
| run_results = LlmUnlearningRun.check_run_by_id(run_id) | ||
| if run_results is None: | ||
| raise HirundoError("No run results found") | ||
| result_payload = ( | ||
| run_results.get("result", run_results) | ||
| if isinstance(run_results, dict) | ||
| else run_results | ||
| ) | ||
| if isinstance(result_payload, dict): | ||
| result_url = result_payload.get("result") | ||
| else: | ||
| result_url = result_payload | ||
| if not isinstance(result_url, str): | ||
| raise HirundoError("Run results did not include a download URL") | ||
| # Stream the zip file download | ||
|
|
||
| zip_file_path = tempfile.NamedTemporaryFile(delete=False).name | ||
| with requests.get( | ||
| result_url, | ||
| timeout=DOWNLOAD_READ_TIMEOUT, | ||
| stream=True, | ||
| ) as r: | ||
| r.raise_for_status() | ||
| with open(zip_file_path, "wb") as zip_file: | ||
| for chunk in r.iter_content(chunk_size=ZIP_FILE_CHUNK_SIZE): | ||
| zip_file.write(chunk) | ||
| logger.info( | ||
| "Successfully downloaded the result zip file for run ID %s to %s", | ||
| run_id, | ||
| zip_file_path, | ||
| ) | ||
|
|
||
| with tempfile.TemporaryDirectory() as temp_dir: | ||
| temp_dir_path = Path(temp_dir) | ||
| with zipfile.ZipFile(zip_file_path, "r") as zip_file: | ||
| zip_file.extractall(temp_dir_path) | ||
| # Attempt to load the tokenizer normally | ||
| base_model_name = ( | ||
| llm.model_source.model_name | ||
| if isinstance( | ||
| llm.model_source, | ||
| HuggingFaceTransformersModel | HuggingFaceTransformersModelOutput, | ||
| ) | ||
| else llm.model_source.local_path | ||
| ) | ||
| token = ( | ||
| llm.model_source.token | ||
| if isinstance( | ||
| llm.model_source, | ||
| HuggingFaceTransformersModel, | ||
| ) | ||
| else token | ||
| ) | ||
| tokenizer = AutoTokenizer.from_pretrained( | ||
| base_model_name, | ||
| token=token, | ||
| trust_remote_code=trust_remote_code, | ||
| ) | ||
| if tokenizer.pad_token is None: | ||
| tokenizer.pad_token = tokenizer.eos_token | ||
| config = AutoConfig.from_pretrained( | ||
| base_model_name, | ||
| token=token, | ||
| trust_remote_code=trust_remote_code, | ||
| ) | ||
| config_dict = config.to_dict() if hasattr(config, "to_dict") else config | ||
| is_multimodal = ( | ||
| config_dict.get("model_type") | ||
| in MODEL_FOR_IMAGE_TEXT_TO_TEXT_MAPPING_NAMES.keys() | ||
| ) | ||
| if is_multimodal: | ||
| base_model = AutoModelForImageTextToText.from_pretrained( | ||
| base_model_name, | ||
| token=token, | ||
| trust_remote_code=trust_remote_code, | ||
| ) | ||
| else: | ||
| base_model = AutoModelForCausalLM.from_pretrained( | ||
| base_model_name, | ||
| token=token, | ||
| trust_remote_code=trust_remote_code, | ||
| ) | ||
| model = cast( | ||
| "PreTrainedModel", | ||
| PeftModel.from_pretrained( | ||
| base_model, str(temp_dir_path / "unlearned_model_folder") | ||
| ), | ||
| ) | ||
|
|
||
| return pipeline( | ||
| task="text-generation", | ||
| model=model, | ||
| tokenizer=tokenizer, | ||
| config=config, | ||
| device=device, | ||
| device_map=device_map, | ||
| ) |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.