Comme l’monde de grandes bibliothèques, en R, verso le dessein liste, conséquemment seriez-vous intéressé par TensorFlow Probability (PTF, verso agir lapidaire)? Eh capital, regardons une référence de ses composants :

  • Distributions et bijecteurs (les bijecteurs sont des cartes réversibles et composables)
  • Modélisation aléatoire (Edward2 et naissance entrecroisement probabilistes)
  • Production aléatoire (via MCMC ou généralisation variationnelle)

Imaginez gardant que quelque ceci fonctionne de dévié transparente en tenant le framework TensorFlow – groupe, Keras, modules contribués – et puisque, fonctionnant de dévié distribuée et sur GPU. Le glèbe des applications possibles est étendu – et capital marre mélangé verso abstraction abrité parmi son rassemblement parmi un agence de blog d’réception.

Au recto de ceci, à nous équitable ici est de concéder une ouverture réception à PTF, en se concentrant sur l’adéquation cordiale et l’interopérabilité en tenant l’commencement en abîme. Quelques-uns allons activement poindre hein entamer en tenant l’un des éléments de armature : distributions. Ultérieurement, moi-même construirons un auto-encodeur variationnel proche à celui-ci de l’commencement des peintures en tenant MMD-VAE. Cette jour quoique, moi-même utiliserons PTF à échantillonner à éloigner des distributions a priori et a posteriori approchées.

Quelques-uns considérerons cet agence pendant une “confirmation de noumène” verso l’maniement PTF en tenant Keras – de R – et prévoyez de patronner en tenant des exemples puis élaborés parmi le possession de l’commencement de schéma semi-supervisé.

À mettre PTF en tenant TensorFlow, ajoutez réellement tensorflow-probability à la référence par pourriture des packages supplémentaires :

library(tensorflow)
install_tensorflow(
  extra_packages = c("keras", "tensorflow-hub", "tensorflow-probability"),
  type = "1.12"
)

À présent à tendre PTFquelque ce que moi-même avons à agir est de l’introduire et de enfanter des poignées utiles.

Et c’est excusé, numérisation à éloigner d’une répartition accoutumée normalisé.

n <- tfd$Connu(loc = 0, scale = 1)
n$sample(6L)
tf.Tensor(
"Normal_1/sample/Reshape:0", shape=(6,), dtype=float32
)

C’est capital, seulement moi-même sommeils en 2019, moi-même ne voulons puis diligent à enfanter une soirée verso calculer ces tenseurs. Dans lequel l’aperçu d’auto-encodeur variationnel plus loin, moi-même allons distinguer hein PTF et TF façon chagrinée sont le concours catégorique, pendant conséquemment ne pas débarquer à l’tendre gardant.

Avec tendre l’façon précoce, moi-même redevons accomplir les niveaux suivantes parmi une dépêche soirée (R) :

… et introduire PTFpendant plus avant.

tfp <- importation("tensorflow_probability")
tfd <- tfp$distributions

Voyons gardant activement PTF distributions.

Usage des distributions

Revoilà à coût cette analyse accoutumée.

n <- tfd$Connu(loc = 0, scale = 1)

Les choses fréquemment faites en tenant une répartition incluent l’numérisation :

# just as in low-level tensorflow, we need to append L to indicate integer arguments
n$sample(6L) 
tf.Tensor(
(-0.34403768 -0.14122334 -1.3832929   1.618252    1.364448   -1.1299014 ),
shape=(6,),
dtype=float32
)

En puis d’extorquer la vraisemblance du certificat. Ici, moi-même faisons ceci ensemble verso trio latitudes.

tf.Tensor(
(-1.4189385 -0.9189385 -1.4189385), shape=(3,), dtype=float32
)

Quelques-uns pouvons agir la même machin en tenant amplement d’discordantes distributions, par aperçu, le Bernoulli :

b <- tfd$Bernoulli(0.9)
b$sample(10L)
tf.Tensor(
(1 1 1 0 1 1 0 1 0 1), shape=(10,), dtype=int32
)
tf.Tensor(
(-1.2411538 -0.3411539 -1.2411538 -1.2411538), shape=(4,), dtype=float32
)

Notez que parmi le final segment, moi-même demandons les log-probabilités de quatre tirages indépendants.

Formes de lot et formes d’événement

Dans lequel PTFmoi-même pouvons agir ce qui suit.

ns <- tfd$Connu(
  loc = c(1, 10, -200),
  scale = c(0.1, 0.1, 1)
)
ns
tfp.distributions.Connu(
"Connu/", batch_shape=(3,), event_shape=(), dtype=float32
)

Haineusement à ce à duquel ceci pourrait apparenter, il ne s’agit pas d’une accoutumée multivariée. Dans prouvé par batch_shape=(3,), il s’agit d’un « lot » de distributions univariées indépendantes. Le incident qu’elles-mêmes soient univariées se voit parmi event_shape=(): Chaque homme d’eux vit parmi une hauteur distant conjoncturel.

Si à la ardeur moi-même créons une autonome accoutumée multivariée bidimensionnelle :

n <- tfd$MultivariateNormalDiag(loc = c(0, 10), scale_diag = c(1, 4))
n
tfp.distributions.MultivariateNormalDiag(
"MultivariateNormalDiag/", batch_shape=(), event_shape=(2,), dtype=float32
)

moi-même voyons batch_shape=(), event_shape=(2,)pendant examiné.

Ressources sûr, moi-même pouvons relier les couple, organisant des lots de distributions multivariées :

nd_batch <- tfd$MultivariateNormalFullCovariance(
  loc = list(c(0., 0.), c(1., 1.), c(2., 2.)),
  covariance_matrix = list(
    matrix(c(1, .1, .1, 1), ncol = 2),
    matrix(c(1, .3, .3, 1), ncol = 2),
    matrix(c(1, .5, .5, 1), ncol = 2))
)

Cet aperçu définit un lot de trio distributions normales multivariées bidimensionnelles.

Ralliement imprégné les formes de lot et les formes d’événement

Quant à anormal que ceci puisse réapparaître, des situations surviennent où moi-même voulons rénover les formes de répartition imprégné ces bonshommes – en incident, moi-même verrons un tel cas vigoureusement récemment.

tfd$Independent est appliqué verso métamorphoser les dimensions en batch_shape aux dimensions parmi event_shape.

Revoilà un lot de trio distributions de Bernoulli indépendantes.

bs <- tfd$Bernoulli(probs=c(.3,.5,.7))
bs
tfp.distributions.Bernoulli(
"Bernoulli/", batch_shape=(3,), event_shape=(), dtype=int32
)

Quelques-uns pouvons métamorphoser ceci en un Bernoulli « tridimensionnel » possible pendant cela :

b <- tfd$Independent(bs, reinterpreted_batch_ndims = 1L)
b
tfp.distributions.Independent(
"IndependentBernoulli/", batch_shape=(), event_shape=(3,), dtype=int32
)

Ici reinterpreted_batch_ndims raconte PTF quel nombre de dimensions de lot sont utilisées verso l’distant conjoncturel, en originel à numéroter à éloigner de la déclarée de la référence des formes.

Comme cette sentiment de armature de PTF distributions, moi-même sommeils prêts à les distinguer utilisées parmi un VAE.

Quelques-uns prendrons l’châssis convolutive (pas si) profonde de l’commencement de la schéma en tenant MMD-VAE et utiliserons distributions verso l’numérisation et le dessein des probabilités. En favoritisme, à nous coût VAE pourra informer la répartition a priori.

Matériellement, l’relation second comprendra trio parties. Dans lequel un préliminaire moment, moi-même présentons un acte bref exécutoire à la jour à un VAE à a priori stable et à un VAE apprenant les paramètres de la répartition a priori. Ultérieurement, moi-même avons la détour d’modèle verso la ouverture VAE (statique-a priori). Finalement, moi-même discutons de la détour de brigade et du modèle annexe impliqués parmi la second VAE (commencement précurseur).

La prodrome des couple versions l’une subséquemment l’divergent entraîne des duplications de acte, seulement évite de répandre des branches if-else déroutantes parmi le acte.

Le second VAE est libre parmi le baguette des exemples Keras vers que vous-même n’ayez pas à imiter des chrestomathie de acte. Le acte contient puisque des fonctionnalités supplémentaires non décrites et reproduites ici, analogues que la garantie des surcharge du modèle.

Ensuite, commençons par la rivalité paroisse.

Au chanceux de moi-même garantir, revoilà à coût les étapes préparatoires (laquelle maints chargements de meuble supplémentaires).

Treillis de conditions

Avec modifier de MNIST et Chic-MNIST, moi-même utiliserons le quelque coût Kuzushiji-MNIST(Clanuwat et al. 2018).

Tiré de : Deep Learning for Classical Japanese Literature (Clanuwat et al. 2018)
np <- importation("numpy")

kuzushiji <- np$load("kmnist-train-imgs.npz")
kuzushiji <- kuzushiji$get("arr_0")
 
train_images <- kuzushiji %>%
  k_expand_dims() %>%
  k_cast(dtype = "float32")

train_images <- train_images %>% `/`(255)

Dans parmi cet divergent agence, moi-même diffusons les conditions via tfdatasets :

buffer_size <- 60000
batch_size <- 256
batches_per_epoch <- buffer_size / batch_size

train_dataset <- tensor_slices_dataset(train_images) %>%
  dataset_shuffle(buffer_size) %>%
  dataset_batch(batch_size)

Voyons gardant ce qui détruit parmi les modèles d’encodeur et de décodeur.

Encodeur

L’encodeur diffère de ce qu’on avait sinon PTF en ce qu’ il ne renvoie pas les moyennes postérieures approximatives et les variances ouvertement dessous tournure de tenseurs. Au recto de ceci, il renvoie un lot de distributions normales multivariées :

# you might want to détruit this depending on the dataset
latent_dim <- 2

encoder_model <- function(name = NULL) {

  keras_model_custom(name = name, function(self) {
  
    self$conv1 <-
      layer_conv_2d(
        filters = 32,
        kernel_size = 3,
        strides = 2,
        poussée = "dévoré"
      )
    self$conv2 <-
      layer_conv_2d(
        filters = 64,
        kernel_size = 3,
        strides = 2,
        poussée = "dévoré"
      )
    self$flatten <- layer_flatten()
    self$serré <- layer_dense(units = 2 * latent_dim)
    
    function (x, mask = NULL) {
      x <- x %>%
        self$conv1() %>%
        self$conv2() %>%
        self$flatten() %>%
        self$serré()
        
      tfd$MultivariateNormalDiag(
        loc = x(, 1:latent_dim),
        scale_diag = tf$nn$softplus(x(, (latent_dim + 1):(2 * latent_dim)) + 1e-5)
      )
    }
  })
}

Essayons ça.

régler <- encoder_model()

iter <- make_iterator_one_shot(train_dataset)
x <-  iterator_get_next(iter)

approx_posterior <- régler(x)
approx_posterior
tfp.distributions.MultivariateNormalDiag(
"MultivariateNormalDiag/", batch_shape=(256,), event_shape=(2,), dtype=float32
)
approx_posterior$sample()
tf.Tensor(
(( 5.77791929e-01 -1.64988488e-02)
 ( 7.93901443e-01 -1.00042784e+00)
 (-1.56279251e-01 -4.06365871e-01)
 ...
 ...
 (-6.47531569e-01  2.10889503e-02)), shape=(256, 2), dtype=float32)

Quelques-uns ne savons pas verso vous-même, seulement moi-même apprécions sans cesse la cliché d’surveiller les latitudes en tenant façon chagrinée – amplement.

Passons gardant au décodeur, qui renvoie puisque une répartition au recto d’un tenseur.

Décodeur

Dans lequel le décodeur, moi-même voyons conséquemment les transformations imprégné la tournure du lot et la tournure de l’événement sont utiles. La scène de self$deconv3 est à quatre dimensions. Ce laquelle moi-même avons faim, c’est d’une vraisemblance on-off verso tout point. Avant, ceci existait aguerri en introduisant le tenseur parmi une vautré serré et en appliquant une poussée sigmoïde. Ici, on utilise tfd$Independent verso rénover avantageusement le tenseur en une répartition de vraisemblance sur des images tridimensionnelles (taille, mont, fossé(s)).

decoder_model <- function(name = NULL) {
  
  keras_model_custom(name = name, function(self) {
    
    self$serré <- layer_dense(units = 7 * 7 * 32, poussée = "dévoré")
    self$reshape <- layer_reshape(target_shape = c(7, 7, 32))
    self$deconv1 <-
      layer_conv_2d_transpose(
        filters = 64,
        kernel_size = 3,
        strides = 2,
        padding = "same",
        poussée = "dévoré"
      )
    self$deconv2 <-
      layer_conv_2d_transpose(
        filters = 32,
        kernel_size = 3,
        strides = 2,
        padding = "same",
        poussée = "dévoré"
      )
    self$deconv3 <-
      layer_conv_2d_transpose(
        filters = 1,
        kernel_size = 3,
        strides = 1,
        padding = "same"
      )
    
    function (x, mask = NULL) {
      x <- x %>%
        self$serré() %>%
        self$reshape() %>%
        self$deconv1() %>%
        self$deconv2() %>%
        self$deconv3()
      
      tfd$Independent(tfd$Bernoulli(logits = x),
                      reinterpreted_batch_ndims = 3L)
      
    }
  })
}

Essayons ceci en conséquence.

decoder <- decoder_model()
decoder_likelihood <- decoder(approx_posterior_sample)
tfp.distributions.Independent(
"IndependentBernoulli/", batch_shape=(256,), event_shape=(28, 28, 1), dtype=int32
)

Cette répartition sera utilisée verso fabriquer les « reconstructions », conséquemment que verso estimer la log-vraisemblance des échantillons authentiques.

Gaspillage KL et optimiseur

Les couple VAE évoqués plus loin auront faim d’un optimiseur…

optimizer <- tf$colis$AdamOptimizer(1e-4)

… et les couple délégueront à compute_kl_loss verso allier la rivalité KL de la dissipation.

Cette ardeur d’renommée soustrait réellement la log-vraisemblance des échantillons dessous la loi a priori de à elles log-vraisemblance dessous la loi a posteriori approchante.

compute_kl_loss <- function(
  latent_prior,
  approx_posterior,
  approx_posterior_sample) {
  
  kl_div <- approx_posterior$log_prob(approx_posterior_sample) -
    latent_prior$log_prob(approx_posterior_sample)
  avg_kl_div <- tf$reduce_mean(kl_div)
  avg_kl_div
}

À présent que moi-même avons vu les parties communes, moi-même abordons d’alentours hein éduquer un VAE en tenant un a priori stable.

Dans lequel ce VAE, moi-même utilisons PTF verso enfanter le prior gaussien isotrope habitué. Quelques-uns échantillonnons subséquemment ouvertement à éloigner de cette répartition parmi la détour d’commencement.

latent_prior <- tfd$MultivariateNormalDiag(
  loc  = tf$zeros(list(latent_dim)),
  scale_identity_multiplier = 1
)

Et revoilà la détour d’modèle intacte. Quelques-uns soulignerons l’construisant PTF-étapes liées plus loin.

for (epoch in seq_len(num_epochs)) {
  iter <- make_iterator_one_shot(train_dataset)
  
  total_loss <- 0
  total_loss_nll <- 0
  total_loss_kl <- 0
  
  until_out_of_range({
    x <-  iterator_get_next(iter)
    
    with(tf$GradientTape(persistent = TRUE) %as% heurt, {
      approx_posterior <- régler(x)
      approx_posterior_sample <- approx_posterior$sample()
      decoder_likelihood <- decoder(approx_posterior_sample)
      
      nll <- -decoder_likelihood$log_prob(x)
      avg_nll <- tf$reduce_mean(nll)
      
      kl_loss <- compute_kl_loss(
        latent_prior,
        approx_posterior,
        approx_posterior_sample
      )

      loss <- kl_loss + avg_nll
    })
    
    total_loss <- total_loss + loss
    total_loss_nll <- total_loss_nll + avg_nll
    total_loss_kl <- total_loss_kl + kl_loss
    
    encoder_gradients <- heurt$gradient(loss, régler$variables)
    decoder_gradients <- heurt$gradient(loss, decoder$variables)
    
    optimizer$apply_gradients(purrr::transpose(list(
      encoder_gradients, régler$variables
    )),
    global_step = tf$colis$get_or_create_global_step())
    optimizer$apply_gradients(purrr::transpose(list(
      decoder_gradients, decoder$variables
    )),
    global_step = tf$colis$get_or_create_global_step())
 
  })
  
  cat(
    glue(
      "Losses (epoch): {epoch}:",
      "  {(as.numeric(total_loss_nll)/batches_per_epoch) %>% reprise(4)} nll",
      "  {(as.numeric(total_loss_kl)/batches_per_epoch) %>% reprise(4)} kl",
      "  {(as.numeric(total_loss)/batches_per_epoch) %>% reprise(4)} intact"
    ),
    "n"
  )
}

Plus haut, en amusant en tenant l’encodeur et le décodeur, on a déjà vu hein

approx_posterior <- régler(x)

moi-même convenu une répartition à éloigner lesquelles moi-même pouvons échantillonner. Quelques-uns l’utilisons verso extorquer des échantillons à éloigner du croupe voisin :

approx_posterior_sample <- approx_posterior$sample()

Ces échantillons, moi-même les prenons et les transmettons au décodeur, qui moi-même convenu des probabilités on-off verso les pixels de l’beau.

decoder_likelihood <- decoder(approx_posterior_sample)

À présent, la dissipation se compose des composants ELBO collectifs : dissipation de rétablissement et différence KL. La dissipation de rétablissement que moi-même obtenons ouvertement de PTFen utilisant la répartition de décodeur apprise verso calculer la faculté de l’admission d’racine.

nll <- -decoder_likelihood$log_prob(x)
avg_nll <- tf$reduce_mean(nll)

La dissipation de KL que moi-même obtenons de compute_kl_lossla ardeur d’renommée que moi-même avons vue plus avant :

kl_loss <- compute_kl_loss(
        latent_prior,
        approx_posterior,
        approx_posterior_sample
      )

On rassemblé les couple et on arrive à la dissipation globale de VAE :

loss <- kl_loss + avg_nll

En oust de ces modifications dues à l’maniement PTFle marche de brigade n’est qu’un backprop habituel, à duquel il ressemble en utilisant façon chagrinée.

Voyons gardant hein, au recto d’tendre la gaussienne isotrope normalisé, moi-même pourrions informer un rapprochement de gaussiennes. Le alignement du abondance de distributions ici est relativement subreptice. Totalité pendant en tenant latent_dimvous-même voudrez probablement risquer et dénuder ce qui fonctionne le principalement sur votre rassemblement de conditions.

mixture_components <- 16

learnable_prior_model <- function(name = NULL, latent_dim, mixture_components) {
  
  keras_model_custom(name = name, function(self) {
    
    self$loc <-
      tf$get_variable(
        name = "loc",
        shape = list(mixture_components, latent_dim),
        dtype = tf$float32
      )
    self$raw_scale_diag <- tf$get_variable(
      name = "raw_scale_diag",
      shape = c(mixture_components, latent_dim),
      dtype = tf$float32
    )
    self$mixture_logits <-
      tf$get_variable(
        name = "mixture_logits",
        shape = c(mixture_components),
        dtype = tf$float32
      )
      
    function (x, mask = NULL) {
        tfd$MixtureSameFamily(
          components_distribution = tfd$MultivariateNormalDiag(
            loc = self$loc,
            scale_diag = tf$nn$softplus(self$raw_scale_diag)
          ),
          mixture_distribution = tfd$Categorical(logits = self$mixture_logits)
        )
      }
    })
  }

Dans lequel PTF taxinomie, components_distribution est le exemple de répartition subjacent, et mixture_distribution détient les probabilités que les composants individuels soient choisis.

Notez hein self$loc, self$raw_scale_diag et self$mixture_logits sont TensorFlow Variables et de ce fait, existant et pouvant abstraction mis à sabord par backprop.

Quelques-uns créons gardant le modèle.

latent_prior_model <- learnable_prior_model(
  latent_dim = latent_dim,
  mixture_components = mixture_components
)

Comme obtient-on une répartition a priori latente à éloigner lesquelles on peut échantillonner ? De dévié un peu extraordinaire, ce modèle sera indispensable sinon admission :

latent_prior <- latent_prior_model(NULL)
latent_prior
tfp.distributions.MixtureSameFamily(
"MixtureSameFamily/", batch_shape=(), event_shape=(2,), dtype=float32
)

Revoilà gardant la détour d’modèle intacte. Notez hein moi-même avons un tiers modèle à attester.

for (epoch in seq_len(num_epochs)) {
  iter <- make_iterator_one_shot(train_dataset)
  
  total_loss <- 0
  total_loss_nll <- 0
  total_loss_kl <- 0
  
  until_out_of_range({
    x <-  iterator_get_next(iter)
    
    with(tf$GradientTape(persistent = TRUE) %as% heurt, {
      approx_posterior <- régler(x)
      
      approx_posterior_sample <- approx_posterior$sample()
      decoder_likelihood <- decoder(approx_posterior_sample)
      
      nll <- -decoder_likelihood$log_prob(x)
      avg_nll <- tf$reduce_mean(nll)
      
      latent_prior <- latent_prior_model(NULL)
      
      kl_loss <- compute_kl_loss(
        latent_prior,
        approx_posterior,
        approx_posterior_sample
      )

      loss <- kl_loss + avg_nll
    })
    
    total_loss <- total_loss + loss
    total_loss_nll <- total_loss_nll + avg_nll
    total_loss_kl <- total_loss_kl + kl_loss
    
    encoder_gradients <- heurt$gradient(loss, régler$variables)
    decoder_gradients <- heurt$gradient(loss, decoder$variables)
    prior_gradients <-
      heurt$gradient(loss, latent_prior_model$variables)
    
    optimizer$apply_gradients(purrr::transpose(list(
      encoder_gradients, régler$variables
    )),
    global_step = tf$colis$get_or_create_global_step())
    optimizer$apply_gradients(purrr::transpose(list(
      decoder_gradients, decoder$variables
    )),
    global_step = tf$colis$get_or_create_global_step())
    optimizer$apply_gradients(purrr::transpose(list(
      prior_gradients, latent_prior_model$variables
    )),
    global_step = tf$colis$get_or_create_global_step())
    
  })
  
  checkpoint$save(file_prefix = checkpoint_prefix)
  
  cat(
    glue(
      "Losses (epoch): {epoch}:",
      "  {(as.numeric(total_loss_nll)/batches_per_epoch) %>% reprise(4)} nll",
      "  {(as.numeric(total_loss_kl)/batches_per_epoch) %>% reprise(4)} kl",
      "  {(as.numeric(total_loss)/batches_per_epoch) %>% reprise(4)} intact"
    ),
    "n"
  )
}  

Et c’est quelque! Avec moi-même, les couple VAE ont donné des résultats conformes, et moi-même n’avons pas évident de grandes différences en désagréable la dimensionnalité latente et le abondance de distributions de rapprochement. Exclusivement davantage une jour, moi-même ne voudrions pas disséminer à d’discordantes ensembles de conditions, architectures, etc.

En vigoureux de résultats, à duquel ressemblent-ils ? Ici, moi-même voyons des lecture générées subséquemment 40 époques de brigade. A rustaud, des lecture aléatoires, à déclarée, la fossé ordinaire VAE d’présentation de l’distant anormal.

À condition que moi-même ayons conquis à poindre que la vraisemblance TensorFlow, l’façon chagrinée et Keras forment une arrangement attrayante ! Si vous-même associez la déluge pleine de acte requise à la empêchement de la tâche, conséquemment qu’à la abîme des concepts impliqués, ceci devrait manifester pendant une réalisation relativement concise.

Dans lequel un filiation puis attenant, moi-même prévoyons de briguer en tenant des applications puis complexes de TensorFlow Probability, spécialement parmi le possession de l’commencement des peintures. Restez à l’examen!

Clanuwat, Blase, Mikel Bober-Irizar, Asanobu Kitamoto, Alex Lamb, Kazuaki Yamamoto et David Ha. 2018. “Commencement en abîme verso la théâtre japonaise impeccable.” 3 décembre 2018. https://arxiv.org/abs/cs.CV/1812.01718.

By nsmaat