Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
Returns
-------
Array with gradients.
"""
# map back to categories to make predictions
if self.is_cat:
X_pred = num_to_ord(X, self.d_abs)
if self.ohe:
X_pred = ord_to_ohe(X_pred, cat_vars_ord)[0]
else:
X_pred = X
# N = gradient batch size; F = nb of features; P = nb of prediction classes; B = instance batch size
# dL/dP -> BxP
preds = self.predict(X_pred) # NxP
preds_pert_pos, preds_pert_neg = perturb(preds, self.eps[0], proba=True) # (N*P)xP
def f(preds_pert):
return np.sum(Y * preds_pert, axis=1)
def g(preds_pert):
return np.max((1 - Y) * preds_pert, axis=1)
# find instances where the gradient is 0
idx_nograd = np.where(f(preds) - g(preds) <= - self.kappa)[0]
if len(idx_nograd) == X.shape[0]:
return np.zeros(X.shape)
dl_df = f(preds_pert_pos) - f(preds_pert_neg) # N*P
dl_dg = g(preds_pert_pos) - g(preds_pert_neg) # N*P
dl_dp = dl_df - dl_dg # N*P
dl_dp = np.reshape(dl_dp, (X.shape[0], -1)) / (2 * self.eps[0]) # NxP
def g(preds_pert):
return np.max((1 - Y) * preds_pert, axis=1)
# find instances where the gradient is 0
idx_nograd = np.where(f(preds) - g(preds) <= - self.kappa)[0]
if len(idx_nograd) == X.shape[0]:
return np.zeros(X.shape)
dl_df = f(preds_pert_pos) - f(preds_pert_neg) # N*P
dl_dg = g(preds_pert_pos) - g(preds_pert_neg) # N*P
dl_dp = dl_df - dl_dg # N*P
dl_dp = np.reshape(dl_dp, (X.shape[0], -1)) / (2 * self.eps[0]) # NxP
# dP/dx -> PxF
X_pert_pos, X_pert_neg = perturb(X, self.eps[1], proba=False) # (N*F)x(shape of X[0])
X_pert = np.concatenate([X_pert_pos, X_pert_neg], axis=0)
if self.is_cat:
X_pert = num_to_ord(X_pert, self.d_abs)
if self.ohe:
X_pert = ord_to_ohe(X_pert, cat_vars_ord)[0]
preds_concat = self.predict(X_pert)
n_pert = X_pert_pos.shape[0]
dp_dx = preds_concat[:n_pert] - preds_concat[n_pert:] # (N*F)*P
dp_dx = np.reshape(np.reshape(dp_dx, (X.shape[0], -1)),
(X.shape[0], preds.shape[1], -1), order='F') / (2 * self.eps[1]) # NxPxF
# dL/dx -> Bx(shape of X[0])
grads = np.einsum('ij,ijk->ik', dl_dp, dp_dx) # NxF
# set instances where gradient is 0 to 0
if len(idx_nograd) > 0:
grads[idx_nograd] = np.zeros(grads.shape[1:])