def test_get_set_state(self): """Test for `.get_state` and `.set_state` methods.""" x = self.ds.X[0, :] self.norm.out_layer = None out_norm = self.norm.transform(x) self.logger.info( "Normalized sample before restoring state:\n{:}".format(out_norm)) state = self.norm.get_state(return_optimizer=False) model = mlp(input_dims=20, hidden_dims=(40,), output_dims=3) net = CClassifierPyTorch(model=model, pretrained=True) norm_new = CNormalizerDNN(net) # Restore state norm_new.set_state(state) post_out_norm = self.norm.transform(x) self.logger.info( "Normalized sample after restoring state:\n{:}".format(post_out_norm)) self.assert_array_equal(out_norm, post_out_norm)
def setUpClass(cls): cls.ds = CDLRandom(n_samples=40, n_classes=3, n_features=20, n_informative=15, random_state=0).load() model = mlp(input_dims=20, hidden_dims=(40,), output_dims=3) loss = nn.CrossEntropyLoss() optimizer = optim.SGD(model.parameters(), lr=1e-1) cls.net = CClassifierPyTorch(model=model, loss=loss, optimizer=optimizer, random_state=0, epochs=10, pretrained=True) cls.net.fit(cls.ds.X, cls.ds.Y) cls.norm = CNormalizerDNN(net=cls.net) CPreProcessTestCases.setUpClass()
def test_preprocess_dnn(self): """Test using a `CNormalizerDNN` as preprocessor.""" # Create a new clf which will have the unittest's Net as preprocessor # We use 3 as the number of features as it is the output size of # the standard Net used in this unittest new_clf = self._create_clf(3, self.n_classes, self.batch_size) new_clf.preprocess = CNormalizerDNN(self.clf) # Train the new classifier new_clf.fit(self.tr.X, self.tr.Y) # Test forward and backward self._test_predict(new_clf, self.ts) self._test_accuracy(new_clf, self.ts) self._test_gradient_numerical(new_clf, self.ts.X[0, :], th=1e-2, epsilon=1e-3)
def __init__(self, combiner, layer_clf, dnn, layers, threshold, n_jobs=1): self.n_jobs = n_jobs super(CClassifierDNR, self).__init__(combiner, threshold) if not isinstance(dnn, CClassifierDNN): raise TypeError("`dnn` must be an instance of `CClassifierDNN`") if not isinstance(layers, list): raise TypeError("`layers` must be a list") if isinstance(layer_clf, dict): if not sorted(layers) == sorted(layer_clf.keys()): raise ValueError("`layer_clf` dict must contain `layers` " "values as keys") if not all(isinstance(c, CClassifier) for c in layer_clf.values()): raise TypeError("`layer_clf` dict must contain `CClassifier` " "instances as values") elif not isinstance(layer_clf, CClassifier): raise TypeError("`layer_clf` must be an instance of either" "`CClassifier` or `dict`") self._layers = layers self._layer_clfs = {} for layer in self._layers: if isinstance(layer_clf, dict): self._layer_clfs[layer] = layer_clf[layer] else: self._layer_clfs[layer] = layer_clf.deepcopy() # search for nested preprocess modules until the inner is reached module = self._layer_clfs[layer] while module.preprocess is not None: module = module.preprocess # once the inner preprocess is found, append the dnn to it module.preprocess = CNormalizerDNN(net=dnn, out_layer=layer) # this allows to access inner classifiers using the # respective layer name add_readwrite(self, layer, self._layer_clfs[layer])
def test_chain(self): """Test for preprocessors chain.""" # Inner preprocessors should be passed to the pytorch clf with self.assertRaises(ValueError): CNormalizerDNN(net=self.net, preprocess='min-max')
def test_aspreprocess(self): """Test for normalizer used as preprocess.""" from secml.ml.classifiers import CClassifierSVM from secml.ml.classifiers.multiclass import CClassifierMulticlassOVA model = mlp(input_dims=20, hidden_dims=(40,), output_dims=3) loss = nn.CrossEntropyLoss() optimizer = optim.SGD(model.parameters(), lr=1e-1) net = CClassifierPyTorch(model=model, loss=loss, optimizer=optimizer, random_state=0, epochs=10, preprocess='min-max') net.fit(self.ds.X, self.ds.Y) norm = CNormalizerDNN(net=net) clf = CClassifierMulticlassOVA( classifier=CClassifierSVM, preprocess=norm) self.logger.info("Testing last layer") clf.fit(self.ds.X, self.ds.Y) y_pred, scores = clf.predict( self.ds.X, return_decision_function=True) self.logger.info("TRUE:\n{:}".format(self.ds.Y.tolist())) self.logger.info("Predictions:\n{:}".format(y_pred.tolist())) self.logger.info("Scores:\n{:}".format(scores)) x = self.ds.X[0, :] self.logger.info("Testing last layer gradient") for c in self.ds.classes: self.logger.info("Gradient w.r.t. class {:}".format(c)) grad = clf.grad_f_x(x, y=c) self.logger.info("Output of grad_f_x:\n{:}".format(grad)) check_grad_val = CFunction( clf.decision_function, clf.grad_f_x).check_grad( x, y=c, epsilon=1e-1) self.logger.info( "norm(grad - num_grad): %s", str(check_grad_val)) self.assertLess(check_grad_val, 1e-3) self.assertTrue(grad.is_vector_like) self.assertEqual(x.size, grad.size) layer = 'linear1' norm.out_layer = layer self.logger.info("Testing layer {:}".format(norm.out_layer)) clf.fit(self.ds.X, self.ds.Y) y_pred, scores = clf.predict( self.ds.X, return_decision_function=True) self.logger.info("TRUE:\n{:}".format(self.ds.Y.tolist())) self.logger.info("Predictions:\n{:}".format(y_pred.tolist())) self.logger.info("Scores:\n{:}".format(scores)) self.logger.info("Testing 'linear1' layer gradient") grad = clf.grad_f_x(x, y=0) # y is required for multiclassova self.logger.info("Output of grad_f_x:\n{:}".format(grad)) self.assertTrue(grad.is_vector_like) self.assertEqual(x.size, grad.size)