Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions avise/connectors/languagemodel/ollama.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@
import logging
from typing import List

import ollama

from .base import BaseLMConnector, Message
from ...registry import connector_registry
from ...utils import ansi_colors
Expand Down Expand Up @@ -32,6 +30,9 @@ def __init__(
config: Dictionary containing data from Connector configuration JSON.
evaluation: Boolean flag indicating whether initializing a connector for the target model or the evaluation model
"""
# Imported here so that importing AVISE does not load the Ollama SDK
import ollama

self.api_key = None
if evaluation:
self.model = config["eval_model"]["name"]
Expand Down
5 changes: 3 additions & 2 deletions avise/connectors/languagemodel/openai.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@
import logging
from typing import List

from openai import OpenAI

from .base import BaseLMConnector, Message
from ...registry import connector_registry
from ...utils import ansi_colors
Expand Down Expand Up @@ -133,6 +131,9 @@ def __init__(self, config: dict, evaluation: bool = False):
else:
self.max_tokens = 512

# Imported here so that importing AVISE does not load the OpenAI SDK
from openai import OpenAI

# Initialize OpenAI client
try:
client_kwargs = {"api_key": self.api_key}
Expand Down
23 changes: 20 additions & 3 deletions avise/engine.py
Original file line number Diff line number Diff line change
Expand Up @@ -255,11 +255,21 @@ def list_available(
listings = []
if sets:
listings.append(
(set_registry, "avise.sets", "Available Security Evaluation Tests", "--SET-list")
(
set_registry,
"avise.sets",
"Available Security Evaluation Tests",
"--SET-list",
)
)
if connectors:
listings.append(
(connector_registry, "avise.connectors", "Available Connectors", "--connector-list")
(
connector_registry,
"avise.connectors",
"Available Connectors",
"--connector-list",
)
)

found = True
Expand Down Expand Up @@ -296,7 +306,14 @@ def list_available(

if reportformats:
title = "Available Report Formats"
print("\n" + (f"{ansi_colors['bold']}{title}{ansi_colors['reset']}" if style.color else title))
print(
"\n"
+ (
f"{ansi_colors['bold']}{title}{ansi_colors['reset']}"
if style.color
else title
)
)
for format in ReportFormat:
print(f" {format.value}")
return found
Expand Down
29 changes: 18 additions & 11 deletions avise/models/adversarial_lm.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,6 @@
from typing import Optional
from importlib.resources import files

from transformers import (
Mistral3ForConditionalGeneration,
MistralCommonBackend,
AutoModelForCausalLM,
AutoTokenizer,
pipeline,
)
import torch
from huggingface_hub import snapshot_download
from mistral_common.exceptions import MistralCommonException

logger = logging.getLogger(__name__)


Expand All @@ -41,6 +30,17 @@ def __init__(
system_prompt: str = None,
use_device: Optional[str] = "auto",
):
# Heavy ML libraries are imported here, not at module level, so that
# importing AVISE (e.g. for `avise --SET-list`) stays fast.
import torch
from transformers import (
Mistral3ForConditionalGeneration,
MistralCommonBackend,
AutoModelForCausalLM,
AutoTokenizer,
)
from mistral_common.exceptions import MistralCommonException

logger.info("Loading Adversarial Language Model...")
torch.cuda.empty_cache()

Expand Down Expand Up @@ -190,6 +190,8 @@ def generate_response(self, prompt, reasoning: bool = True) -> list:
if "mistral" in self.model_name:
response = self._mistral_text_generation(messages)
else:
from transformers import pipeline

model_pipeline = pipeline(
task="text-generation",
model=self.model,
Expand Down Expand Up @@ -224,6 +226,8 @@ def generate_response(self, prompt, reasoning: bool = True) -> list:

def del_model(self):
"""Delete the model from GPU memory."""
import torch

self.model.cpu()
del self.model
del self.tokenizer
Expand Down Expand Up @@ -270,6 +274,9 @@ def _model_download(
model_path (str): Path where to save the model.
model_name (str): Name of the Hugging Face model.
"""
from huggingface_hub import snapshot_download
from transformers import AutoModelForCausalLM, AutoTokenizer

model_path = Path(files("avise").joinpath(model_path))

# Check if path exists
Expand Down
15 changes: 10 additions & 5 deletions avise/models/evaluation_lm.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,6 @@
import sys
from importlib.resources import files

import torch
from transformers import Mistral3ForConditionalGeneration, MistralCommonBackend
from huggingface_hub import snapshot_download
from mistral_common.exceptions import MistralCommonException

logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)

Expand All @@ -34,6 +29,12 @@ def __init__(
system_prompt: str = None,
use_device: str = "auto",
):
# Heavy ML libraries are imported here, not at module level, so that
# importing AVISE (e.g. for `avise --SET-list`) stays fast.
import torch
from transformers import Mistral3ForConditionalGeneration, MistralCommonBackend
from mistral_common.exceptions import MistralCommonException

logger.info("Loading Evaluation Language Model...")
torch.cuda.empty_cache()
self.model = None
Expand Down Expand Up @@ -195,6 +196,8 @@ def _mistral_text_generation(self, messages: list) -> str:
def del_model(self):
"""Delete the model from GPU memory."""
if self.model:
import torch

self.model.cpu()
del self.model
del self.tokenizer
Expand All @@ -213,6 +216,8 @@ def _model_download(
model_path (str): Path where to save the model.
model_name (str): Name of the Hugging Face model.
"""
from huggingface_hub import snapshot_download

model_path = Path(files("avise").joinpath(model_path))
# Check if path exists
if not os.path.exists(model_path):
Expand Down
8 changes: 6 additions & 2 deletions avise/pipelines/continuallearning/pipeline.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
from typing import List, Dict, Any, Optional
from datetime import datetime
from math import sqrt
from statistics import NormalDist

from .schema import (
ContinualLearningSETCase,
Expand All @@ -26,7 +27,6 @@
)
from ...connectors.continuallearning.base import BaseCLConnector

from scipy.special import erfinv

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -372,7 +372,11 @@ def _calculate_confidence_interval(
return (0, 0.0, 0.0)

p = passed / n
z = 1.96 if confidence_level == 0.95 else sqrt(2) * erfinv(confidence_level)
z = (
1.96
if confidence_level == 0.95
else NormalDist().inv_cdf((1 + confidence_level) / 2)
)

denominator = 1 + (z**2 / n)
center = (p + (z**2 / (2 * n))) / denominator
Expand Down
8 changes: 6 additions & 2 deletions avise/pipelines/languagemodel/pipeline.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@
from typing import List, Dict, Any, Optional
from datetime import datetime
from math import sqrt
from statistics import NormalDist

from .schema import LanguageModelSETCase, OutputData, EvaluationResult, ReportData
from ...connectors.languagemodel.base import BaseLMConnector
from ...models import EvaluationLanguageModel

from scipy.special import erfinv

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -339,7 +339,11 @@ def _calculate_confidence_interval(
p = passed / n

# Z-score for confidence level (1.96 for 95% CI)
z = 1.96 if confidence_level == 0.95 else sqrt(2) * erfinv(confidence_level)
z = (
1.96
if confidence_level == 0.95
else NormalDist().inv_cdf((1 + confidence_level) / 2)
)

# Wilson score interval
denominator = 1 + (z**2 / n)
Expand Down
4 changes: 2 additions & 2 deletions avise/sets/continuallearning/backdoor.py
Original file line number Diff line number Diff line change
Expand Up @@ -242,8 +242,8 @@ class Backdoor(BaseSETPipeline):

name = "Backdoor"
description = (
"Injects a backdoor trigger into a Continual Learning model's training data and "
"evaluates whether the model learns to associate the trigger with a target label."
"Tests whether poisoning a continual learning model's training data with a "
"backdoor trigger makes it classify triggered inputs as an attacker-chosen label."
)

def __init__(self):
Expand Down
5 changes: 4 additions & 1 deletion avise/sets/languagemodel/multi_turn/context_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,10 @@ class ContextTest(BaseSETPipeline):
"""Context Test SET."""

name = "Context test"
description = "A simple test for multi-turn conversations where the conversation history is passed to the target"
description = (
"Tests whether the target model keeps track of the conversation context "
"across multiple turns, with the full history sent in every request."
)

def __init__(self):
super().__init__()
Expand Down
Loading
Loading