Add files via upload
This commit is contained in:
parent
0978bb2f1d
commit
1284bb346b
238 changed files with 13931 additions and 3 deletions
93
easyjailbreak/mutation/rule/Crossover.py
Normal file
93
easyjailbreak/mutation/rule/Crossover.py
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
import importlib.resources
|
||||
import random
|
||||
import re
|
||||
from easyjailbreak.mutation import MutationBase
|
||||
from easyjailbreak.datasets import JailbreakDataset, Instance
|
||||
from easyjailbreak.seed import SeedTemplate
|
||||
|
||||
|
||||
class CrossOver(MutationBase):
|
||||
r"""
|
||||
The 'CrossOver' class serves to interlace sentences from two distinct texts.
|
||||
"""
|
||||
def __init__(self, attr_name='jailbreak_prompt', num_points=5,
|
||||
seed_pool:JailbreakDataset=None):
|
||||
r"""
|
||||
Initializes the CrossOver instance.
|
||||
:param ~str attr_name: The attribute name in the instance that contains the text to be mutated.
|
||||
:param ~int num_points: The number of break points when crossover.
|
||||
:param ~JailbreakDataset seed_pool: The default cross-over seed pool.
|
||||
"""
|
||||
self.attr_name = attr_name
|
||||
self.num_points = num_points
|
||||
self.seed_pool = seed_pool
|
||||
if seed_pool is None:
|
||||
seed_path = importlib.resources.files("easyjailbreak.seed") / "seed_template.json"
|
||||
self.seed_pool = SeedTemplate().new_seeds(
|
||||
seeds_num=10,
|
||||
prompt_usage='attack',
|
||||
method_list=["AutoDAN-a"],
|
||||
template_file=seed_path
|
||||
)
|
||||
self.seed_pool = JailbreakDataset([Instance(jailbreak_prompt=prompt) for prompt in self.seed_pool])
|
||||
|
||||
def _get_mutated_instance(self, instance, **kwargs):
|
||||
r"""
|
||||
Generates a mutated instance of the given object.
|
||||
:param instance: The instance to be mutated.
|
||||
:param kwargs: Additional keyword arguments.
|
||||
:return: A list containing the mutated instance.
|
||||
"""
|
||||
mutated_instances = []
|
||||
seed = getattr(instance, self.attr_name)
|
||||
if 'other_instance' in kwargs:
|
||||
other_instance = kwargs['other_instance']
|
||||
other_seed = getattr(other_instance, self.attr_name)
|
||||
else:
|
||||
other_instance = random.choice(self.seed_pool._dataset)
|
||||
other_seed = getattr(other_instance, self.attr_name)
|
||||
child1, child2 = self.crossover(seed, other_seed, self.num_points)
|
||||
|
||||
new_instance1 = instance.copy()
|
||||
setattr(new_instance1, self.attr_name, child1)
|
||||
new_instance2 = other_instance.copy()
|
||||
setattr(new_instance2, self.attr_name, child2)
|
||||
mutated_instances.append(new_instance1)
|
||||
mutated_instances.append(new_instance2)
|
||||
return mutated_instances
|
||||
|
||||
def crossover(self, str1, str2, num_points):
|
||||
r"""
|
||||
The function determines the feasible points for intertwining or crossing over.
|
||||
:return: two sentences after crossover
|
||||
"""
|
||||
sentences1 = [s for s in re.split('(?<=[.!?])\s+', str1) if s]
|
||||
sentences2 = [s for s in re.split('(?<=[.!?])\s+', str2) if s]
|
||||
|
||||
max_swaps = min(len(sentences1), len(sentences2)) - 1
|
||||
num_swaps = min(num_points, max_swaps)
|
||||
|
||||
if num_swaps >= max_swaps:
|
||||
return str1, str2
|
||||
|
||||
swap_indices = sorted(random.sample(range(1, max_swaps), num_swaps))
|
||||
|
||||
new_str1, new_str2 = [], []
|
||||
last_swap = 0
|
||||
for swap in swap_indices:
|
||||
if random.choice([True, False]):
|
||||
new_str1.extend(sentences1[last_swap:swap])
|
||||
new_str2.extend(sentences2[last_swap:swap])
|
||||
else:
|
||||
new_str1.extend(sentences2[last_swap:swap])
|
||||
new_str2.extend(sentences1[last_swap:swap])
|
||||
last_swap = swap
|
||||
|
||||
if random.choice([True, False]):
|
||||
new_str1.extend(sentences1[last_swap:])
|
||||
new_str2.extend(sentences2[last_swap:])
|
||||
else:
|
||||
new_str1.extend(sentences2[last_swap:])
|
||||
new_str2.extend(sentences1[last_swap:])
|
||||
|
||||
return ' '.join(new_str1), ' '.join(new_str2)
|
||||
Loading…
Add table
Add a link
Reference in a new issue