Skip to content

Commit 308a9e6

Browse files
committed
Updated DeepDefend, version 0.1.1
1 parent 13d3bc9 commit 308a9e6

7 files changed

Lines changed: 273 additions & 11 deletions

File tree

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
name: Publish Python 🐍 distributions 📦 to PyPI
2+
3+
on:
4+
push:
5+
tags:
6+
- '*'
7+
8+
jobs:
9+
build-n-publish:
10+
name: Build and publish Python 🐍 distributions 📦 to PyPI
11+
runs-on: ubuntu-latest
12+
steps:
13+
- uses: actions/checkout@master
14+
- name: Set up Python 3.12
15+
uses: actions/setup-python@v3
16+
with:
17+
python-version: '3.12'
18+
- name: Install pypa/setuptools
19+
run: >-
20+
python -m
21+
pip install setuptools wheel
22+
- name: Extract tag name
23+
id: tag
24+
run: echo ::set-output name=TAG_NAME::$(echo $GITHUB_REF | cut -d / -f 3)
25+
- name: Update version in setup.py
26+
run: >-
27+
sed -i "s/{{VERSION_PLACEHOLDER}}/${{ steps.tag.outputs.TAG_NAME }}/g" setup.py
28+
- name: Build a binary wheel
29+
run: >-
30+
python setup.py sdist bdist_wheel
31+
- name: Publish distribution 📦 to PyPI
32+
uses: pypa/gh-action-pypi-publish@master
33+
with:
34+
password: ${{ secrets.PYPI_API_TOKEN }}

.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
__pycache__
2+
*.pyc
3+
dist/
4+
build/
5+
venv/

deepdefend/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
import deepdefend
2-
from .attacks import fgsm, pgd, bim
3-
from .defenses import adversarial_training, feature_squeezing
2+
from .attacks import fgsm, pgd, bim, cw, deepfool, jsma
3+
from .defenses import adversarial_training, feature_squeezing, gradient_masking, input_transformation, defensive_distillation

deepdefend/attacks.py

Lines changed: 121 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@
55
- `fgsm(model, x, y, epsilon=0.01)`: Fast Gradient Sign Method (FGSM) attack.
66
- `pgd(model, x, y, epsilon=0.01, alpha=0.01, num_steps=10)`: Projected Gradient Descent (PGD) attack.
77
- `bim(model, x, y, epsilon=0.01, alpha=0.01, num_steps=10)`: Basic Iterative Method (BIM) attack.
8-
8+
- `cw(model, x, y, epsilon=0.01, c=1, kappa=0, num_steps=10, alpha=0.01)`: Carlini & Wagner (C&W) attack.
9+
- `deepfool(model, x, y, num_steps=10)`: DeepFool attack.
10+
- `jsma(model, x, y, theta=0.1, gamma=0.1, num_steps=10)`: Jacobian-based Saliency Map Attack (JSMA).
911
"""
1012

1113
import numpy as np
@@ -100,4 +102,122 @@ def bim(model, x, y, epsilon=0.01, alpha=0.01, num_steps=10):
100102
adversarial_example = tf.clip_by_value(adversarial_example + perturbation, 0, 1)
101103
adversarial_example = tf.clip_by_value(adversarial_example, x - epsilon, x + epsilon)
102104

105+
return adversarial_example.numpy()
106+
107+
def cw(model, x, y, epsilon=0.01, c=1, kappa=0, num_steps=10, alpha=0.01):
108+
"""
109+
Carlini & Wagner (C&W) attack.
110+
111+
Parameters:
112+
model (tensorflow.keras.Model): The target model to attack.
113+
x (numpy.ndarray): The input example to attack.
114+
y (numpy.ndarray): The true labels of the input example.
115+
epsilon (float): The maximum magnitude of the perturbation (default: 0.01).
116+
c (float): The weight of the L2 norm of the perturbation (default: 1).
117+
kappa (float): The confidence parameter (default: 0).
118+
num_steps (int): The number of C&W iterations (default: 10).
119+
alpha (float): The step size for each iteration (default: 0.01).
120+
121+
Returns:
122+
adversarial_example (numpy.ndarray): The perturbed input example.
123+
"""
124+
# Define the loss function
125+
def loss_function(x, y, model, c, kappa):
126+
prediction = model(x)
127+
loss = tf.keras.losses.CategoricalCrossentropy()(y, prediction)
128+
return loss + c * tf.norm(x - tf.clip_by_value(x, 0, 1)) ** 2 - kappa
129+
130+
# Initialize the adversarial example
131+
adversarial_example = tf.identity(x)
132+
133+
# Perform the C&W attack
134+
for _ in range(num_steps):
135+
with tf.GradientTape() as tape:
136+
tape.watch(adversarial_example)
137+
loss = loss_function(adversarial_example, y, model, c, kappa)
138+
139+
gradient = tape.gradient(loss, adversarial_example)
140+
perturbation = alpha * tf.sign(gradient)
141+
adversarial_example = tf.clip_by_value(adversarial_example + perturbation, 0, 1)
142+
adversarial_example = tf.clip_by_value(adversarial_example, x - epsilon, x + epsilon)
143+
144+
return adversarial_example.numpy()
145+
146+
def deepfool(model, x, y, num_steps=10):
147+
"""
148+
DeepFool attack.
149+
150+
Parameters:
151+
model (tensorflow.keras.Model): The target model to attack.
152+
x (numpy.ndarray): The input example to attack.
153+
y (numpy.ndarray): The true labels of the input example.
154+
num_steps (int): The number of DeepFool iterations (default: 10).
155+
156+
Returns:
157+
adversarial_example (numpy.ndarray): The perturbed input example.
158+
"""
159+
# Initialize the adversarial example
160+
adversarial_example = tf.identity(x)
161+
162+
# Perform the DeepFool attack
163+
for _ in range(num_steps):
164+
with tf.GradientTape() as tape:
165+
tape.watch(adversarial_example)
166+
prediction = model(adversarial_example)
167+
loss = tf.keras.losses.CategoricalCrossentropy()(y, prediction)
168+
169+
gradient = tape.gradient(loss, adversarial_example)
170+
perturbation = gradient / tf.norm(gradient)
171+
adversarial_example = adversarial_example + perturbation
172+
173+
return adversarial_example.numpy()
174+
175+
def jsma(model, x, y, theta=0.1, gamma=0.1, num_steps=10):
176+
"""
177+
Jacobian-based Saliency Map Attack (JSMA) attack.
178+
179+
Parameters:
180+
model (tensorflow.keras.Model): The target model to attack.
181+
x (numpy.ndarray): The input example to attack.
182+
y (numpy.ndarray): The true labels of the input example.
183+
theta (float): The threshold for selecting pixels (default: 0.1).
184+
gamma (float): The step size for each iteration (default: 0.1).
185+
num_steps (int): The number of JSMA iterations (default: 10).
186+
187+
Returns:
188+
adversarial_example (numpy.ndarray): The perturbed input example.
189+
"""
190+
# Initialize the adversarial example
191+
adversarial_example = tf.identity(x)
192+
193+
# Get the input shape
194+
input_shape = x.shape
195+
196+
# Perform the JSMA attack
197+
for _ in range(num_steps):
198+
# Calculate the Jacobian matrix
199+
with tf.GradientTape() as tape:
200+
tape.watch(adversarial_example)
201+
prediction = model(adversarial_example)
202+
loss = tf.keras.losses.CategoricalCrossentropy()(y, prediction)
203+
204+
jacobian = tape.jacobian(loss, adversarial_example)
205+
206+
# Calculate the saliency map
207+
saliency_map = np.zeros(input_shape)
208+
for i in range(input_shape[1]):
209+
for j in range(input_shape[2]):
210+
for k in range(input_shape[3]):
211+
saliency_map[0, i, j, k] = np.sum(jacobian[0, i, j, k, :])
212+
213+
# Select the pixels to perturb
214+
perturbed_pixels = np.where(saliency_map > theta)
215+
216+
# Perturb the selected pixels
217+
for i in range(len(perturbed_pixels[0])):
218+
if adversarial_example[0, perturbed_pixels[0][i], perturbed_pixels[1][i], perturbed_pixels[2][i]] < 1:
219+
adversarial_example[0, perturbed_pixels[0][i], perturbed_pixels[1][i], perturbed_pixels[2][i]] += gamma
220+
else:
221+
adversarial_example[0, perturbed_pixels[0][i], perturbed_pixels[1][i], perturbed_pixels[2][i]] -= gamma
222+
103223
return adversarial_example.numpy()

deepdefend/defenses.py

Lines changed: 82 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
1+
# defenses.py
12
"""
23
Functions to apply adversarial defense mechanisms to deep learning models.
34
45
Available functions:
56
- `adversarial_training(model, x, y, epsilon=0.01)`: Adversarial Training defense.
67
- `feature_squeezing(model, bit_depth=4)`: Feature Squeezing defense.
7-
8+
- `gradient_masking(model, mask_threshold=0.1)`: Gradient Masking defense.
9+
- `input_transformation(model, transformation_function=None)`: Input Transformation defense.
10+
- `defensive_distillation(model, teacher_model, temperature=2)`: Defensive Distillation defense.
811
"""
912

1013
import numpy as np
@@ -68,4 +71,82 @@ def feature_squeezing(model, bit_depth=4):
6871
squeezed_weights = [np.clip(np.round(w * (2**bit_depth) / np.max(np.abs(w))), -2**(bit_depth - 1), 2**(bit_depth - 1) - 1) / (2**(bit_depth) / np.max(np.abs(w))) for w in layer_weights]
6972
layer.set_weights(squeezed_weights)
7073

74+
return defended_model
75+
76+
def gradient_masking(model, mask_threshold=0.1):
77+
"""
78+
Gradient Masking defense.
79+
80+
Gradient masking modifies the gradients during training to make them less informative
81+
for adversarial attackers.
82+
83+
Parameters:
84+
model (tensorflow.keras.Model): The model to defend.
85+
mask_threshold (float): The threshold for masking gradients (default: 0.1).
86+
87+
Returns:
88+
defended_model (tensorflow.keras.Model): The model with gradient masking defense.
89+
"""
90+
defended_model = tf.keras.models.clone_model(model)
91+
defended_model.set_weights(model.get_weights())
92+
93+
def masked_loss(y_true, y_pred):
94+
loss = tf.keras.losses.CategoricalCrossentropy()(y_true, y_pred)
95+
gradients = tf.gradients(loss, defended_model.trainable_variables)
96+
masked_gradients = [tf.where(tf.abs(g) > mask_threshold, g, tf.zeros_like(g)) for g in gradients]
97+
return loss, masked_gradients
98+
99+
defended_model.compile(optimizer='adam', loss=masked_loss, metrics=['accuracy'])
100+
return defended_model
101+
102+
def input_transformation(model, transformation_function=None):
103+
"""
104+
Input Transformation defense.
105+
106+
Input transformation applies a transformation to the input data before feeding it
107+
to the model, aiming to remove adversarial perturbations.
108+
109+
Parameters:
110+
model (tensorflow.keras.Model): The model to defend.
111+
transformation_function (function): The transformation function to apply (default: None).
112+
113+
Returns:
114+
defended_model (tensorflow.keras.Model): The model with input transformation defense.
115+
"""
116+
defended_model = tf.keras.models.clone_model(model)
117+
defended_model.set_weights(model.get_weights())
118+
119+
def transformed_input(x):
120+
if transformation_function is not None:
121+
return transformation_function(x)
122+
else:
123+
return x
124+
125+
defended_model.layers[0].input = tf.keras.Input(shape=model.input_shape[1:])
126+
defended_model.layers[0].input = transformed_input(defended_model.layers[0].input)
127+
return defended_model
128+
129+
def defensive_distillation(model, teacher_model, temperature=2):
130+
"""
131+
Defensive Distillation defense.
132+
133+
Defensive distillation trains a student model to mimic the predictions of a
134+
teacher model, which is often a more robust model.
135+
136+
Parameters:
137+
model (tensorflow.keras.Model): The student model to defend.
138+
teacher_model (tensorflow.keras.Model): The teacher model.
139+
temperature (float): The temperature parameter for distillation (default: 2).
140+
141+
Returns:
142+
defended_model (tensorflow.keras.Model): The distilled student model.
143+
"""
144+
defended_model = tf.keras.models.clone_model(model)
145+
defended_model.set_weights(model.get_weights())
146+
147+
def distilled_loss(y_true, y_pred):
148+
teacher_predictions = teacher_model(y_true)
149+
return tf.keras.losses.CategoricalCrossentropy()(y_true, y_pred) + temperature**2 * tf.keras.losses.CategoricalCrossentropy()(teacher_predictions, y_pred)
150+
151+
defended_model.compile(optimizer='adam', loss=distilled_loss, metrics=['accuracy'])
71152
return defended_model

readme.md

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
# DeepDefend 0.1.0
2-
![Python Version](https://img.shields.io/badge/python-3.11-blue.svg)
1+
# DeepDefend 0.1.1
2+
![Python Version](https://img.shields.io/badge/python-3.12-blue.svg)
33
![Code Size](https://img.shields.io/github/languages/code-size/infinitode/deepdefend)
44
![Downloads](https://pepy.tech/badge/deepdefend)
55
![License Compliance](https://img.shields.io/badge/license-compliance-brightgreen.svg)
@@ -28,7 +28,7 @@ DeepDefend supports the following Python versions:
2828
- Python 3.8
2929
- Python 3.9
3030
- Python 3.10
31-
- Python 3.11
31+
- Python 3.11 or later
3232

3333
Please ensure that you have one of these Python versions installed before using DeepDefend. DeepDefend may not work as expected on lower versions of Python than the supported.
3434

@@ -43,7 +43,7 @@ Please ensure that you have one of these Python versions installed before using
4343

4444
```python
4545
import tensorflow as tf
46-
from deepdefend.attacks import fgsm, pgd, bim
46+
from deepdefend.attacks import fgsm, pgd, bim, cw, deepfool, jsma
4747

4848
# Load a pre-trained TensorFlow model
4949
model = ...
@@ -58,19 +58,31 @@ adversarial_example_fgsm = fgsm(model, x_example, y_example, epsilon=0.01)
5858
# Perform PGD attack on the example data
5959
adversarial_example_pgd = pgd(model, x_example, y_example, epsilon=0.01, alpha=0.01, num_steps=10)
6060

61-
# Perfrom BIM attack on the example data
61+
# Perform BIM attack on the example data
6262
adversarial_example_bim = bim(model, x_example, y_example, epsilon=0.01, alpha=0.01, num_steps=10)
63+
64+
# Perform CW attack on the example data
65+
adversarial_example_cw = cw(model, x_example, y_example, epsilon=0.01, c=1, kappa=0, num_steps=10, alpha=0.01)
66+
67+
# Perform Deepfool attack on the example data
68+
adversarial_example_deepfool = deepfool(model, x_example, y_example, num_steps=10)
69+
70+
# Perform JSMA attack on the example data
71+
adversarial_example_jsma(model, x_example, y_example, theta=0.1, gamma=0.1, num_steps=10)
6372
```
6473

6574
### Adversarial Defenses
6675

6776
```python
6877
import tensorflow as tf
69-
from deepdefend.defenses import adversarial_training, feature_squeezing
78+
from deepdefend.defenses import adversarial_training, feature_squeezing, gradient_masking, input_transformation, defensive_distillation
7079

7180
# Load a pre-trained TensorFlow model
7281
model = ...
7382

83+
# Teacher model for distillation
84+
teacher_model = ...
85+
7486
# Load training data
7587
x_train, y_train = ... # training data and labels
7688

@@ -79,6 +91,15 @@ defended_model = adversarial_training(model, x_train, y_train, epsilon=0.01)
7991

8092
# Feature squeezing defense
8193
defended_model_squeezed = feature_squeezing(model, bit_depth=4)
94+
95+
# Gradient masking defense
96+
defended_model_masking = gradient_masking(model, mask_threshold=0.1)
97+
98+
# Input transformation defense
99+
defended_model_transformation = input_transformation(model, transformation_function=None)
100+
101+
# Defensive distillation defense
102+
defended_model_distillation = defensive_distillation(model, teacher_model, temperature=2)
82103
```
83104

84105
## Contributing

setup.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
setup(
44
name='deepdefend',
5-
version='0.1.0',
5+
version='{{VERSION_PLACEHOLDER}}',
66
author='Infinitode Pty Ltd',
77
author_email='infinitode.ltd@gmail.com',
88
description='An open-source Python library for adversarial attacks and defenses in deep learning models.',
@@ -25,6 +25,7 @@
2525
'Programming Language :: Python :: 3.9',
2626
'Programming Language :: Python :: 3.10',
2727
'Programming Language :: Python :: 3.11',
28+
'Programming Language :: Python :: 3.12',
2829
],
2930
python_requires='>=3.6',
3031
)

0 commit comments

Comments
 (0)