def nn_interpolate_2D(X, x, y): """ Estimates of the pixel values at the coordinates (x, y) in `X` using a nearest neighbor interpolation strategy. Notes ----- Assumes the current entries in `X` reflect equally-spaced samples from a 2D integer grid. Parameters ---------- X : :py:class:`ndarray <numpy.ndarray>` of shape `(in_rows, in_cols, in_channels)` An input image sampled along a grid of `in_rows` by `in_cols`. x : list of length `k` A list of x-coordinates for the samples we wish to generate y : list of length `k` A list of y-coordinates for the samples we wish to generate Returns ------- samples : :py:class:`ndarray <numpy.ndarray>` of shape `(k, in_channels)` The samples for each (x,y) coordinate computed via nearest neighbor interpolation """ nx, ny = np.around(x), np.around(y) nx = np.clip(nx, 0, X.shape[1] - 1).astype(int) ny = np.clip(ny, 0, X.shape[0] - 1).astype(int) return X[ny, nx, :]
def _loss(self, X, target, neg_samples): """Actual computation of NCE loss""" fstr = "X must have shape (n_ex, n_c, n_in), but got {} dims instead" assert X.ndim == 3, fstr.format(X.ndim) W = self.parameters["W"] b = self.parameters["b"] # sample negative samples from the noise distribution if neg_samples is None: neg_samples = self.noise_sampler(self.num_negative_samples) assert len(neg_samples) == self.num_negative_samples # get the probability of the negative sample class and the target # class under the noise distribution p_neg_samples = self.noise_sampler.probs[neg_samples] p_target = np.atleast_2d(self.noise_sampler.probs[target]) # save the noise samples for debugging noise_samples = (neg_samples, p_target, p_neg_samples) # compute the logit for the negative samples and target Z_target = X @ W[target].T + b[0, target] Z_neg = X @ W[neg_samples].T + b[0, neg_samples] # subtract the log probability of each label under the noise dist if self.subtract_log_label_prob: n, m = Z_target.shape[0], Z_neg.shape[0] Z_target[range(n), ...] -= np.log(p_target) Z_neg[range(m), ...] -= np.log(p_neg_samples) # only retain the probability of the target under its associated # minibatch example aa, _, cc = Z_target.shape Z_target = Z_target[range(aa), :, range(cc)][..., None] # p_target = (n_ex, n_c, 1) # p_neg = (n_ex, n_c, n_samples) pred_p_target = self.act_fn(Z_target) pred_p_neg = self.act_fn(Z_neg) # if we're in evaluation mode, ignore the negative samples - just # return the binary cross entropy on the targets y_pred = pred_p_target if self.trainable: # (n_ex, n_c, 1 + n_samples) (target is first column) y_pred = np.concatenate((y_pred, pred_p_neg), axis=-1) n_targets = 1 y_true = np.zeros_like(y_pred) y_true[..., :n_targets] = 1 # binary cross entropy eps = 2.220446049250313e-16 np.clip(y_pred, eps, 1 - eps, y_pred) loss = -np.sum(y_true * np.log(y_pred) + (1 - y_true) * np.log(1 - y_pred)) return loss, Z_target, Z_neg, y_pred, y_true, noise_samples
def bilinear_interpolate(X, x, y): """ Estimates of the pixel values at the coordinates (x, y) in `X` via bilinear interpolation. Notes ----- Assumes the current entries in X reflect equally-spaced samples from a 2D integer grid. Modified from https://bit.ly/2NMb1Dr Parameters ---------- X : :py:class:`ndarray <numpy.ndarray>` of shape `(in_rows, in_cols, in_channels)` An input image sampled along a grid of `in_rows` by `in_cols`. x : list of length `k` A list of x-coordinates for the samples we wish to generate y : list of length `k` A list of y-coordinates for the samples we wish to generate Returns ------- samples : list of length `(k, in_channels)` The samples for each (x,y) coordinate computed via bilinear interpolation """ x0 = np.floor(x).astype(int) y0 = np.floor(y).astype(int) x1 = x0 + 1 y1 = y0 + 1 x0 = np.clip(x0, 0, X.shape[1] - 1) y0 = np.clip(y0, 0, X.shape[0] - 1) x1 = np.clip(x1, 0, X.shape[1] - 1) y1 = np.clip(y1, 0, X.shape[0] - 1) Ia = X[y0, x0, :].T Ib = X[y1, x0, :].T Ic = X[y0, x1, :].T Id = X[y1, x1, :].T wa = (x1 - x) * (y1 - y) wb = (x1 - x) * (y - y0) wc = (x - x0) * (y1 - y) wd = (x - x0) * (y - y0) return (Ia * wa).T + (Ib * wb).T + (Ic * wc).T + (Id * wd).T
def grad(y, y_pred, t_mean, t_log_var): """ Compute the gradient of the VLB with regard to the network parameters. Parameters ---------- y : :py:class:`ndarray <numpy.ndarray>` of shape `(n_ex, N)` The original images. y_pred : :py:class:`ndarray <numpy.ndarray>` of shape `(n_ex, N)` The VAE reconstruction of the images. t_mean: :py:class:`ndarray <numpy.ndarray>` of shape `(n_ex, T)` Mean of the variational distribution :math:`q(t | x)`. t_log_var: :py:class:`ndarray <numpy.ndarray>` of shape `(n_ex, T)` Log of the variance vector of the variational distribution :math:`q(t | x)`. Returns ------- dY_pred : :py:class:`ndarray <numpy.ndarray>` of shape `(n_ex, N)` The gradient of the VLB with regard to `y_pred`. dLogVar : :py:class:`ndarray <numpy.ndarray>` of shape `(n_ex, T)` The gradient of the VLB with regard to `t_log_var`. dMean : :py:class:`ndarray <numpy.ndarray>` of shape `(n_ex, T)` The gradient of the VLB with regard to `t_mean`. """ N = y.shape[0] eps = 2.220446049250313e-16 y_pred = np.clip(y_pred, eps, 1 - eps) dY_pred = -y / (N * y_pred) - (y - 1) / (N - N * y_pred) dLogVar = (np.exp(t_log_var) - 1) / (2 * N) dMean = t_mean / N return dY_pred, dLogVar, dMean
def loss(y, y_pred, t_mean, t_log_var): """ Variational lower bound for a Bernoulli VAE. Parameters ---------- y : :py:class:`ndarray <numpy.ndarray>` of shape `(n_ex, N)` The original images. y_pred : :py:class:`ndarray <numpy.ndarray>` of shape `(n_ex, N)` The VAE reconstruction of the images. t_mean: :py:class:`ndarray <numpy.ndarray>` of shape `(n_ex, T)` Mean of the variational distribution :math:`q(t \mid x)`. t_log_var: :py:class:`ndarray <numpy.ndarray>` of shape `(n_ex, T)` Log of the variance vector of the variational distribution :math:`q(t \mid x)`. Returns ------- loss : float The VLB, averaged across the batch. """ # prevent nan on log(0) eps = 2.220446049250313e-16 y_pred = np.clip(y_pred, eps, 1 - eps) # reconstruction loss: binary cross-entropy rec_loss = -np.sum(y * np.log(y_pred) + (1 - y) * np.log(1 - y_pred), axis=1) # KL divergence between the variational distribution q and the prior p, # a unit gaussian kl_loss = -0.5 * np.sum(1 + t_log_var - t_mean ** 2 - np.exp(t_log_var), axis=1) loss = np.mean(kl_loss + rec_loss) return loss
def fn(self, z): """ Evaluate the hard sigmoid activation on the elements of input `z`. .. math:: \\text{HardSigmoid}(z_i) &= 0 \\ \\ \\ \\ &&\\text{if }z_i < -2.5 \\\\ &= 0.2 z_i + 0.5 \\ \\ \\ \\ &&\\text{if }-2.5 \leq z_i \leq 2.5 \\\\ &= 1 \\ \\ \\ \\ &&\\text{if }z_i > 2.5 """ return np.clip((0.2 * z) + 0.5, 0.0, 1.0)
def nn_interpolate_1D(X, t): """ Estimates of the signal values at `X[t]` using a nearest neighbor interpolation strategy. Parameters ---------- X : :py:class:`ndarray <numpy.ndarray>` of shape `(in_length, in_channels)` An input image sampled along an integer `in_length` t : list of length `k` A list of coordinates for the samples we wish to generate Returns ------- samples : :py:class:`ndarray <numpy.ndarray>` of shape `(k, in_channels)` The samples for each (x,y) coordinate computed via nearest neighbor interpolation """ nt = np.clip(np.around(t), 0, X.shape[0] - 1).astype(int) return X[nt, :]
def clip(tensor, a_min=None, a_max=None): return np.clip(tensor, a_min, a_max)