def test(trans_configs, model_configs, data_configs, save=False, output_dir=None): """ Apply transformation(s) on images. :param trans_configs: dictionary. The collection of the parameterized transformations to test. in the form of { configsx: { param: value, } } The key of a configuration is 'configs'x, where 'x' is the id of corresponding weak defense. :param model_configs: dictionary. Defines model related information. Such as, location, the undefended model, the file format, etc. :param data_configs: dictionary. Defines data related information. Such as, location, the file for the true labels, the file for the benign samples, the files for the adversarial examples, etc. :param save: boolean. Save the transformed sample or not. :param output_dir: path or str. The location to store the transformed samples. It cannot be None when save is True. :return: """ # load weak defenses into a pool pool, _ = load_pool(trans_configs=trans_configs, model_configs=model_configs) # load the benign samples data_file = os.path.join(data_configs.get('dir'), data_configs.get('bs_file')) data_bs = np.load(data_file) img_rows, img_cols = data_bs.shape[1], data_bs.shape[2] # load the corresponding true labels label_file = os.path.join(data_configs.get('dir'), data_configs.get('label_file')) labels = np.load(label_file) print('SHAPES:', data_bs.shape, labels.shape) # test the loaded weak defenses one by one for id, model in pool.items(): if id == 0: # skip the undefended model, which does not transform the image continue key = 'configs{}'.format(id) trans_args = trans_configs.get(key) print('TRANS CONFIG:', trans_args) # transform a small subset data_trans = transform(data_bs[:50], trans_args) # predict the transformed images by the corresponding model (weak defense) pred = model.predict(data_trans) # plotting a sample img_idx = 30 img = data_trans[img_idx].reshape((img_rows, img_cols)) plt.imshow(img, cmap='gray') title = '{}, {}'.format(trans_args.get('description'), np.argmax(pred[img_idx])) plt.title(title) plt.show() plt.close() # save the transformed sample as required if save: if output_dir is None: raise ValueError("Cannot save images to a none path.") file = os.path.join(output_dir, "{}.png".format(time.monotonic())) image.imsave(file, img)
def random_rotations(X, num_samples, minval, maxval): samples = [] num_images = X.shape[0] pool = np.asarray([i for i in range(minval, maxval + 1)]) angles = np.random.choice(pool, size=num_samples, replace=False) trans_params = { 'type': TRANSFORMATION.ROTATE.value, 'subtype': '', } print('Random angles:', angles) rotated = [] for angle in angles: trans_params['description'] = 'rotate{}'.format(angle) trans_params['angle'] = angle X_rot = transform(X, attack_args=trans_params) rotated.append(X_rot) rotated = np.asarray(rotated) print('ROTATED SHAPE:', rotated.shape) for i in range(num_images): for j in range(num_samples): samples.append(rotated[j][i]) samples = np.asarray(samples) print('SAMPLE SHAPES:', samples.shape) return samples
def predict(self, x, batch_size=128, **kwargs): """ Perform prediction for a batch of inputs. :param x: Test set. :type x: `np.ndarray` :param batch_size: Size of batches. :type batch_size: `int` :return: Array of predictions of shape `(nb_inputs, nb_classes)`. :rtype: `np.ndarray` """ from art.config import ART_NUMPY_DTYPE # Apply transformation x_preprocessed = transform(x, self._trans_configs) # Apply preprocessing x_preprocessed, _ = self._apply_preprocessing(x_preprocessed, y=None, fit=False) # Run predictions with batching predictions = np.zeros((x_preprocessed.shape[0], self.nb_classes()), dtype=ART_NUMPY_DTYPE) for batch_index in range( int(np.ceil(x_preprocessed.shape[0] / float(batch_size)))): begin, end = batch_index * batch_size, min( (batch_index + 1) * batch_size, x_preprocessed.shape[0]) predictions[begin:end] = self._model.predict( [x_preprocessed[begin:end]]) # Apply postprocessing predictions = self._apply_postprocessing(preds=predictions, fit=False) return predictions
def predict(self, x, batch_size=128, **kwargs): """ Perform prediction for a batch of inputs. :param x: Test set. :type x: `np.ndarray` :param batch_size: Size of batches. :type batch_size: `int` :return: Array of predictions of shape `(nb_inputs, nb_classes)`. :rtype: `np.ndarray` """ import torch # Apply transformation x_preprocessed = transform(set_channels_last(x), self._trans_configs) x_preprocessed = set_channels_first(x_preprocessed) # Apply preprocessing x_preprocessed, _ = self._apply_preprocessing(x_preprocessed, y=None, fit=False) # Run prediction with batch processing results = np.zeros((x_preprocessed.shape[0], self.nb_classes()), dtype=np.float32) num_batch = int(np.ceil(len(x_preprocessed) / float(batch_size))) for m in range(num_batch): # Batch indexes begin, end = m * batch_size, min((m + 1) * batch_size, x_preprocessed.shape[0]) model_outputs = self._model(torch.from_numpy(x_preprocessed[begin:end]).to(self._device)) output = model_outputs[-1] results[begin:end] = output.detach().cpu().numpy() # Apply postprocessing predictions = self._apply_postprocessing(preds=results, fit=False) return predictions
def get_augmented_aeloaders(dataset, batch, dataroot, ae_file, trans_type=TRANSFORMATION.clean): train_sampler, trainloader, validloader, _ = get_dataloaders(dataset, batch, dataroot, trans_type) _, test_aug = get_augmentation(dataset) _, (_, y_test) = load_data(dataset) x_ae = load_model(ae_file) x_ae = transform(x_ae, trans_type) x_ae = data_utils.rescale(x_ae) x_ae = data_utils.set_channels_first(x_ae) testset = MyDataset(x_ae, y_test, aug=test_aug) testloader = torch.utils.data.DataLoader( testset, batch_size=batch, shuffle=False, num_workers=32, pin_memory=torch.cuda.is_available(), drop_last=False) return train_sampler, trainloader, validloader, testloader
def train(trainset, testset, processor=None, **kwargs): # get network model = cnn() X_train, Y_train = trainset X_test, Y_test = testset # apply transformation X_train = transform(X_train, processor) learning_rate = 0.001 validation_rate = 0.2 optimizer = kwargs.get('optimizer', keras.optimizers.Adam(lr=learning_rate)) loss_func = kwargs.get('loss', keras.losses.categorical_crossentropy) metrics = kwargs.get('metrics', 'default') print('Training weak defense [{}]...'.format(processor.description)) print('>>> optimizer: {}'.format(optimizer)) print('>>> loss function: {}'.format(loss_func)) print('>>> metrics: {}'.format(metrics)) nb_examples, img_rows, img_cols, nb_channels = X_train.shape nb_training = int(nb_examples * (1. - validation_rate)) train_examples = X_train[:nb_training] train_labels = Y_train[:nb_training] val_examples = X_train[nb_training:] val_labels = Y_train[nb_training:] """ compile data """ if ('default' == metrics): model.compile(optimizer=optimizer, loss=loss_func, metrics=['accuracy']) else: model.compile(optimizer=optimizer, loss=loss_func, metrics=['accuracy', metrics]) # train the model history = model.fit(train_examples, train_labels, batch_size=64, epochs=20, verbose=2, validation_data=(val_examples, val_labels)) model_dir = kwargs.get('model_dir', 'models') save_file = kwargs.get('model_name', 'demo') postfix = kwargs.get('model_format', '.h5') model.save(os.path.join(model_dir, save_file + postfix)) print('Saved the model to file [{}]'.format( os.path.join(model_dir, save_file + postfix))) # evaluate the model scores_train = model.evaluate(train_examples, train_labels, batch_size=128, verbose=0) scores_val = model.evaluate(val_examples, val_labels, batch_size=128, verbose=0) X_test = transform(X_test, processor) scores_test = model.evaluate(X_test, Y_test, batch_size=128, verbose=0) """ report """ print('\t\t\t loss, \t acc (BS/AE)') print('training set: {}'.format(scores_train)) print('validation set: {}'.format(scores_val)) print('test set: {}'.format(scores_test)) print('') log_dir = kwargs.get('checkpoint_folder', 'checkpoints') save_file = save_file.replace(postfix, '') file.dict2csv(history.history, '{}/checkpoint-{}.csv'.format(log_dir, save_file))
def load_data(dataset, trans_type=TRANSFORMATION.clean, channel_first=False, trans_set='both'): assert dataset in DATA.get_supported_datasets() assert trans_set is None or trans_set in ['none', 'train', 'test', 'both'] X_train = None Y_train = None X_test = None Y_test = None img_rows = 0 img_cols = 0 nb_channels = 0 nb_classes = 0 if DATA.mnist == dataset: """ Dataset of 60,000 28x28 grayscale images of the 10 digits, along with a test set of 10,000 images. """ (X_train, Y_train), (X_test, Y_test) = mnist.load_data() nb_examples, img_rows, img_cols = X_test.shape nb_channels = 1 nb_classes = 10 elif DATA.fation_mnist == dataset: """ Dataset of 60,000 28x28 grayscale images of 10 fashion categories, along with a test set of 10,000 images. The class labels are: Label Description 0 T-shirt/top 1 Trouser 2 Pullover 3 Dress 4 Coat 5 Sandal 6 Shirt 7 Sneaker 8 Bag 9 Ankle boot """ (X_train, Y_train), (X_test, Y_test) = fashion_mnist.load_data() nb_examples, img_rows, img_cols = X_test.shape nb_channels = 1 nb_classes = 10 elif DATA.cifar_10 == dataset: """ Dataset of 50,000 32x32 color training images, labeled over 10 categories, and 10,000 test images. """ (X_train, Y_train), (X_test, Y_test) = cifar10.load_data() nb_examples, img_rows, img_cols, nb_channels = X_test.shape nb_classes = 10 elif DATA.cifar_100 == dataset: (X_train, Y_train), (X_test, Y_test) = cifar100.load_data(label_mode='fine') nb_examples, img_rows, img_cols, nb_channels = X_test.shape nb_classes = 100 X_train = X_train.reshape(-1, img_rows, img_cols, nb_channels) X_test = X_test.reshape(-1, img_rows, img_cols, nb_channels) """ cast pixels to floats, normalize to [0, 1] range """ X_train = X_train.astype(np.float32) X_test = X_test.astype(np.float32) X_train = data_utils.rescale(X_train, range=(0., 1.)) X_test = data_utils.rescale(X_test, range=(0., 1.)) """ one-hot-encode the labels """ Y_train = keras.utils.to_categorical(Y_train, nb_classes) Y_test = keras.utils.to_categorical(Y_test, nb_classes) """ transform images """ if trans_set is not None: if trans_set in ['train', 'both']: X_train = transform(X_train, trans_type) X_train = data_utils.rescale(X_train, range=(0., 1.)) if trans_set in ['test', 'both']: X_test = transform(X_test, trans_type) X_test = data_utils.rescale(X_test, range=(0., 1.)) if channel_first: X_train = data_utils.set_channels_first(X_train) X_test = data_utils.set_channels_first(X_test) """ summarize data set """ print('Dataset({}) Summary:'.format(dataset.upper())) print('Train set: {}, {}'.format(X_train.shape, Y_train.shape)) print('Test set: {}, {}'.format(X_test.shape, Y_test.shape)) return (X_train, Y_train), (X_test, Y_test)
def sample_from_distribution(x, distribution_args): """ Apply transformations from the specific distributions on given input x. :param x: the legitimate sample. :param distribution_args: dictionary. configuration of the distribution. :return: """ if len(x.shape) == 4 and x.shape[0] > 1: raise ValueError( "This method does not support sampling for a batch. Function `batch_sample_from_distribution` is for batch sampling." ) transformation = distribution_args.get( "transformation", TRANSFORMATION_DISTRIBUTION.RANDOM.value) # channel_index = distribution_args.get("channel_index", 3) # if channel_index not in [1, 3]: # raise ValueError("`channel_index` must be 1 or 3, but found {}.".format(channel_index)) # if channel_index == 1: x = set_channels_last(x) x = x.astype(np.float32) if transformation == TRANSFORMATION_DISTRIBUTION.RANDOM.value: # select a random transformation distribution = TRANSFORMATION_DISTRIBUTION.distributions()[1:] transformation = random.choice(distribution) if transformation == TRANSFORMATION_DISTRIBUTION.ROTATION.value: # randomly rotate the input x trans_args = { "type": "rotate", "subtype": "", "id": -1, } # the interval of rotation angle min_angle = distribution_args.get("min_angle", -15) max_angle = distribution_args.get("max_angle", 15) # rotate the x by a random angle angle = random.randint(min_angle, max_angle) trans_args["angle"] = angle trans_args["description"] = "rotate[{}]".format(angle) x_trans = transform(x, trans_args)[0] elif transformation == TRANSFORMATION_DISTRIBUTION.GAUSSIAN_NOISE.value: # add random gaussian noise to the input # magnitude of noise eta = distribution_args.get("eta", 0.03) clip_min = distribution_args.get("clip_min", 0.) clip_max = distribution_args.get("clip_max", 1.) # add noise noise = np.random.normal(loc=0, scale=1, size=x.shape) noisy_x = np.clip((x + noise * eta), clip_min, clip_max) x_trans = noisy_x.reshape(x.shape) elif transformation == TRANSFORMATION_DISTRIBUTION.TRANSLATION.value: # randomly translate the input trans_args = { "type": "shift", "subtype": "", "id": -1, } # interval of translation offsets min_offset = distribution_args.get("min_offset", -0.20) max_offset = distribution_args.get("max_offset", 0.20) # random offsets in x- and y-axis x_offset = random.uniform(min_offset, max_offset) y_offset = random.uniform(min_offset, max_offset) trans_args["x_offset"] = x_offset trans_args["y_offset"] = y_offset trans_args["description"] = "shift[{},{}]".format(x_offset, y_offset) x_trans = transform(x, trans_args)[0] elif transformation == TRANSFORMATION_DISTRIBUTION.AFFINE.value: # apply random affine transformation trans_args = { "type": "affine", "subtype": "", "id": -1, } # interval of transformation offsets min_offset = distribution_args.get("min_offset", 0.1) max_offset = distribution_args.get("max_offset", 0.5) if min_offset <= 0 or max_offset <= 0: raise ValueError( "`min_offset` and `max_offset` must be positive, but found {} and {}." .format(min_offset, max_offset)) if min_offset >= max_offset: raise ValueError( "`min_offset` must be less than `max_offset`, but found {} and {}." .format(min_offset, max_offset)) # apply random affine transformation op1 = random.uniform(min_offset, max_offset) op2 = random.uniform(min_offset, max_offset) origin_point1 = distribution_args.get("origin_point1", (op1, op1)) origin_point2 = distribution_args.get("origin_point2", (op1, op2)) origin_point3 = distribution_args.get("origin_point3", (op2, op1)) np1 = random.uniform(min_offset, max_offset) np2 = random.uniform(min_offset, max_offset) np3 = random.uniform(min_offset, max_offset) np4 = random.uniform(min_offset, max_offset) new_point1 = distribution_args.get("new_point1", (np1, np2)) new_point2 = distribution_args.get("new_point2", (np1, np3)) new_point3 = distribution_args.get("new_point3", (np4, np2)) trans_args["origin_point1"] = origin_point1 trans_args["origin_point2"] = origin_point2 trans_args["origin_point3"] = origin_point3 trans_args["new_point1"] = new_point1 trans_args["new_point2"] = new_point2 trans_args["new_point3"] = new_point3 trans_args["description"] = "affine[{},{},{};{},{},{}]".format( origin_point1, origin_point2, origin_point3, new_point1, new_point2, new_point3) x_trans = transform(x, trans_args)[0] else: raise ValueError( "Distribution {} is not supported.".format(transformation)) # if channel_index == 1: # x_trans = set_channels_first(x_trans) return x_trans.astype(np.float32)