def _update_H_coupled_kl(self, X, W, H, y, beta, mask=None): eps = 1e-12 if mask is None: return H * (W.T.dot(X / (W.dot(H) + eps)) + (H * y)) / ((np.sum(W, 0) + eps) + (_sigmoid(beta.dot(H)) * H).T).T else: return H * (W.T.dot(X / (W.dot(H) + eps)) + (H * y * mask)) / ( (np.sum(W, 0) + eps) + (_sigmoid(beta.dot(H)) * H * mask).T).T
def _update_H_coupled_euc(self, X, W, H, y, beta, phi=1., mask=None): eps = 1e-12 if mask is None: return H * ((1 / phi + eps) * W.T.dot(X) + (H * y)) / ((1 / phi + eps) * (W.T.dot(W).dot(H) + eps).T + (_sigmoid(beta.dot(H)) * H).T).T else: return H * ((1 / phi+eps) * W.T.dot(X) + (H * y)) / \ ( (1 / phi+eps) * (W.T.dot(W).dot(H) + eps).T + (_sigmoid(beta.dot(H)) * H).T ).T
def _update_H_coupled_euc(self, X, W, H, y, beta, phi=1., mask=None): eps = 1e-12 if mask is None: return H * ((1 / phi+eps) * W.T.dot(X) + (H * y)) / ( (1 / phi+eps) * (W.T.dot(W).dot(H) + eps).T + (_sigmoid(beta.dot(H)) * H).T ).T else: return H * ((1 / phi+eps) * W.T.dot(X) + (H * y)) / \ ( (1 / phi+eps) * (W.T.dot(W).dot(H) + eps).T + (_sigmoid(beta.dot(H)) * H).T ).T
def _update_param(self, w, y, X, mask=None, eta=0.01): """ :param w: the parameters at their current estimates of shape (n_features,) :param y: the response vector of shape (n_obs,) :param X: the design matrix of shape (n_features, n_obs) :param mask: the binary mask vector of shape (n_obs,). 1 if observed, 0 o/w :param eta: the batch gradient descent step size :returns: updated parameter vector of shape (n_features,) """ # if mask is not None: # X = X * mask # y = y * mask if mask is not None: return w + eta * X.dot(mask * (y - _sigmoid(w.dot(X)))) #? else: return w + eta * X.dot((y - _sigmoid(w.dot(X)))) #?
def _update_param(self, w, y, X, mask=None, eta=0.01): """ :param w: the parameters at their current estimates of shape (n_features,) :param y: the response vector of shape (n_obs,) :param X: the design matrix of shape (n_features, n_obs) :param mask: the binary mask vector of shape (n_obs,). 1 if observed, 0 o/w :param eta: the batch gradient descent step size :returns: updated parameter vector of shape (n_features,) """ # if mask is not None: # X = X * mask # y = y * mask if mask is not None: return w + eta * X.dot(mask* (y - _sigmoid(w.dot(X)))) #? else: return w + eta * X.dot((y - _sigmoid(w.dot(X)))) #?
def _update_H_coupled_kl_disp(self, X, W, H, y, beta, phi=0., mask=None): eps = 1e-12 WH = W.dot(H) if mask is None: mask = np.ones(len(y)) return H * (W.T.dot(X * (WH + phi) / (WH * (WH + phi * X) + eps)) + (H * y * mask)) / ((np.sum(W, 0) + eps) + (_sigmoid(beta.dot(H)) * H * mask).T).T
def _negative_log_likelihood(self, w, y, X, mask=None): """ Returns logistic regression negative log likelihood :param w: the parameters at their current estimates of shape (n_features,) :param y: the response vector of shape (n_obs,) :param X: the design matrix of shape (n_features, n_obs) :param mask: the binary mask vector of shape (n_obs,). 1 if observed, 0 o/w :returns: negative log likelihood value :rtype: float """ sigm = _sigmoid(w.dot(X)) if mask is not None: return -np.sum(np.log(bernoulli.pmf(y, sigm) * mask + 1e-5)) else: return -np.sum(np.log(bernoulli.pmf(y, sigm) + 1e-5))
def _update_param_mult(self, w, y, X, mask=None): """ Logistic regression, implemented with the multiplicative update rule. Note that the multiplicative update works quite poorly and only handles the case where a nonnegative coefficient vector is required. :param w: the parameters at their current estimates of shape (n_features,) :param y: the response vector of shape (n_obs,) :param X: the design matrix of shape (n_features, n_obs) :param mask: the binary mask vector of shape (n_obs,). 1 if observed, 0 o/w :returns: updated parameter vector of shape (n_features,) """ if mask is not None: X = X * mask y = y * mask return w * X.dot(y) / (X.dot(_sigmoid(w.dot(X))) + 1e-10)
def sigmoid(x, out=None): """ Logistic sigmoid function. Parameters ---------- x : numpy array Input data. out : numpy array, optional Array to hold the output data. Returns ------- numpy array Logistic sigmoid of input data. """ # Note: define a wrapper around _sigmoid so we just have the dependency on # madmom when pickling objects, not on scipy.special which may # contain the bug mentioned above return _sigmoid(x, out)
def _score(self, w, X): return _sigmoid(w.dot(X))
def _update_H_coupled_kl_disp(self, X, W, H, y, beta, phi=0., mask=None): eps = 1e-12 WH = W.dot(H) if mask is None: mask = np.ones(len(y)) return H * (W.T.dot(X * (WH + phi) / (WH * (WH + phi*X) + eps)) + (H * y * mask)) / ((np.sum(W,0) + eps) + (_sigmoid(beta.dot(H)) * H * mask).T ).T
def _update_H_coupled_kl(self, X, W, H, y, beta, mask=None): eps = 1e-12 if mask is None: return H * (W.T.dot(X / (W.dot(H) + eps)) + (H * y)) / ((np.sum(W,0) + eps) + (_sigmoid(beta.dot(H)) * H).T ).T else: return H * (W.T.dot(X / (W.dot(H) + eps)) + (H * y * mask)) / ((np.sum(W,0) + eps) + (_sigmoid(beta.dot(H)) * H * mask).T ).T