Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
tensorflow
GitHub Repository: tensorflow/docs-l10n
Path: blob/master/site/es-419/probability/examples/Fitting_DPMM_Using_pSGLD.ipynb
25118 views
Kernel: Python 3

Licensed under the Apache License, Version 2.0 (the "License");

#@title Licensed under the Apache License, Version 2.0 (the "License"); { display-mode: "form" } # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License.

Ajuste del modelo de mezcla del proceso de Dirichlet mediante la dinámica de Langevin con gradiente estocástico precondicionado

En este bloc de notas, demostraremos cómo agrupar una gran cantidad de muestras e inferir la cantidad de clústeres simultáneamente ajustando una mezcla del proceso Dirichlet de distribución gaussiana. Utilizamos la dinámica de Langevin de gradiente estocástico precondicionado (pSGLD) para la inferencia.

Índice

  1. Muestras

  2. Modelo

  3. Optimización

  4. Visualice el resultado

4.1. Resultado agrupado

4.2 Visualización de la incertidumbre

4.3. Media y escala del componente de mezcla seleccionado

4.4. Ponderación de cada componente de la mezcla

4.5. Convergencia de α\alpha

4.6. Número inferido de clústeres durante iteraciones

4.7. Ajuste del modelo mediante el uso de RMSProp

  1. Conclusión


1. Muestras

Primero, configuramos un conjunto de datos de juguetes. Generamos 50 000 muestras aleatorias a partir de tres distribuciones gaussianas bivariadas.

import time import numpy as np import matplotlib.pyplot as plt import tensorflow.compat.v1 as tf import tensorflow_probability as tfp
plt.style.use('ggplot') tfd = tfp.distributions
def session_options(enable_gpu_ram_resizing=True): """Convenience function which sets common `tf.Session` options.""" config = tf.ConfigProto() config.log_device_placement = True if enable_gpu_ram_resizing: # `allow_growth=True` makes it possible to connect multiple colabs to your # GPU. Otherwise the colab malloc's all GPU ram. config.gpu_options.allow_growth = True return config def reset_sess(config=None): """Convenience function to create the TF graph and session, or reset them.""" if config is None: config = session_options() tf.reset_default_graph() global sess try: sess.close() except: pass sess = tf.InteractiveSession(config=config)
# For reproducibility rng = np.random.RandomState(seed=45) tf.set_random_seed(76) # Precision dtype = np.float64 # Number of training samples num_samples = 50000 # Ground truth loc values which we will infer later on. The scale is 1. true_loc = np.array([[-4, -4], [0, 0], [4, 4]], dtype) true_components_num, dims = true_loc.shape # Generate training samples from ground truth loc true_hidden_component = rng.randint(0, true_components_num, num_samples) observations = (true_loc[true_hidden_component] + rng.randn(num_samples, dims).astype(dtype))
# Visualize samples plt.scatter(observations[:, 0], observations[:, 1], 1) plt.axis([-10, 10, -10, 10]) plt.show()
Image in a Jupyter notebook

2. Modelo

Aquí, definimos una mezcla de proceso de Dirichlet de distribución gaussiana con distribución simétrica previa de Dirichlet. En todo el bloc de notas, las cantidades vectoriales están escritas en negrita. Sobre i1,,Ni\in{1,\ldots,N} muestras, el modelo con una mezcla de j1,,Kj \in{1,\ldots,K} distribuciones gaussianas se formula de la siguiente manera:

p(x1,,xN)=i=1NGMM(xi),with  GMM(xi)=j=1KπjNormal(xiloc=μj,scale=σj)\begin{align*} p(\boldsymbol{x}_1,\cdots, \boldsymbol{x}_N) &=\prod_{i=1}^N \text{GMM}(x_i), \\ &\,\quad \text{with}\;\text{GMM}(x_i)=\sum_{j=1}^K\pi_j\text{Normal}(x_i\,|\,\text{loc}=\boldsymbol{\mu_{j}},\,\text{scale}=\boldsymbol{\sigma_{j}})\\ \end{align*}xiNormal(loc=μzi,scale=σzi)zi=Categorical(prob=π),with  π={π1,,πK}πDirichlet(concentration={αK,,αK})αInverseGamma(concentration=1,rate=1)μjNormal(loc=0,scale=1)σjInverseGamma(concentration=1,rate=1)\begin{align*} x_i&\sim \text{Normal}(\text{loc}=\boldsymbol{\mu}_{z_i},\,\text{scale}=\boldsymbol{\sigma}_{z_i}) \\ z_i &= \text{Categorical}(\text{prob}=\boldsymbol{\pi}),\\ &\,\quad \text{with}\;\boldsymbol{\pi}=\{\pi_1,\cdots,\pi_K\}\\ \boldsymbol{\pi}&\sim\text{Dirichlet}(\text{concentration}=\{\frac{\alpha}{K},\cdots,\frac{\alpha}{K}\})\\ \alpha&\sim \text{InverseGamma}(\text{concentration}=1,\,\text{rate}=1)\\ \boldsymbol{\mu_j} &\sim \text{Normal}(\text{loc}=\boldsymbol{0}, \,\text{scale}=\boldsymbol{1})\\ \boldsymbol{\sigma_j} &\sim \text{InverseGamma}(\text{concentration}=\boldsymbol{1},\,\text{rate}=\boldsymbol{1})\\ \end{align*}

Nuestro objetivo es asignar cada xix_i al jjésimo clúster a través de ziz_i que representa el índice inferido de un clúster.

Para un modelo de mezcla de Dirichlet ideal, KK se establece en \infty. Sin embargo, se sabe que se puede aproximar un modelo de mezcla de Dirichlet con un KK suficientemente grande. Tenga en cuenta que, aunque establecemos arbitrariamente un valor inicial de KK, también se infiere un número óptimo de clústeres mediante la optimización, a diferencia de un modelo de mezcla gaussiana simple.

En este bloc de notas, utilizamos una distribución gaussiana bivariada como componente de la mezcla y establecemos KK en 30.

reset_sess() # Upperbound on K max_cluster_num = 30 # Define trainable variables. mix_probs = tf.nn.softmax( tf.Variable( name='mix_probs', initial_value=np.ones([max_cluster_num], dtype) / max_cluster_num)) loc = tf.Variable( name='loc', initial_value=np.random.uniform( low=-9, #set around minimum value of sample value high=9, #set around maximum value of sample value size=[max_cluster_num, dims])) precision = tf.nn.softplus(tf.Variable( name='precision', initial_value= np.ones([max_cluster_num, dims], dtype=dtype))) alpha = tf.nn.softplus(tf.Variable( name='alpha', initial_value= np.ones([1], dtype=dtype))) training_vals = [mix_probs, alpha, loc, precision] # Prior distributions of the training variables #Use symmetric Dirichlet prior as finite approximation of Dirichlet process. rv_symmetric_dirichlet_process = tfd.Dirichlet( concentration=np.ones(max_cluster_num, dtype) * alpha / max_cluster_num, name='rv_sdp') rv_loc = tfd.Independent( tfd.Normal( loc=tf.zeros([max_cluster_num, dims], dtype=dtype), scale=tf.ones([max_cluster_num, dims], dtype=dtype)), reinterpreted_batch_ndims=1, name='rv_loc') rv_precision = tfd.Independent( tfd.InverseGamma( concentration=np.ones([max_cluster_num, dims], dtype), rate=np.ones([max_cluster_num, dims], dtype)), reinterpreted_batch_ndims=1, name='rv_precision') rv_alpha = tfd.InverseGamma( concentration=np.ones([1], dtype=dtype), rate=np.ones([1]), name='rv_alpha') # Define mixture model rv_observations = tfd.MixtureSameFamily( mixture_distribution=tfd.Categorical(probs=mix_probs), components_distribution=tfd.MultivariateNormalDiag( loc=loc, scale_diag=precision))

3. Optimización

Optimizamos el modelo con dinámica de Langevin de gradiente estocástico precondicionado (pSGLD), que nos permite optimizar un modelo en una gran cantidad de muestras en forma de descenso de gradiente de minilotes.

Para actualizar θ{π,α,μj,σj}\boldsymbol{\theta}\equiv\{\boldsymbol{\pi},\,\alpha,\, \boldsymbol{\mu_j},\,\boldsymbol{\sigma_j}\} en t,enlat, en la ésima iteración con un tamaño de minilote MM, la actualización se muestra como:

ParseError: KaTeX parse error: Got function '\boldsymbol' with no arguments as subscript at position 300: …{ M } \nabla _ \̲b̲o̲l̲d̲s̲y̲m̲b̲o̲l̲ ̲{ \theta } \log…

En la ecuación anterior, ϵt\epsilon _ { t } es la tasa de aprendizaje en la t,t,ésima iteración y logp(θt)\log p(\theta_t) es una suma de distribuciones logarítmicas previas de θ\theta. G(θt)G ( \boldsymbol { \theta } _ { t }) es un precondicionador que ajusta la escala del gradiente de cada parámetro.

# Learning rates and decay starter_learning_rate = 1e-6 end_learning_rate = 1e-10 decay_steps = 1e4 # Number of training steps training_steps = 10000 # Mini-batch size batch_size = 20 # Sample size for parameter posteriors sample_size = 100

Usaremos la probabilidad logarítmica conjunta de la probabilidad GMM(xtk)\text{GMM}(x_{t_k}) y las probabilidades previas p(θt)p(\theta_t) como la función de pérdida para la pSGLD.

Tenga en cuenta que, como se especifica en la API de pSGLD, debemos dividir la suma de las probabilidades previas por el tamaño de la muestra NN.

# Placeholder for mini-batch observations_tensor = tf.compat.v1.placeholder(dtype, shape=[batch_size, dims]) # Define joint log probabilities # Notice that each prior probability should be divided by num_samples and # likelihood is divided by batch_size for pSGLD optimization. log_prob_parts = [ rv_loc.log_prob(loc) / num_samples, rv_precision.log_prob(precision) / num_samples, rv_alpha.log_prob(alpha) / num_samples, rv_symmetric_dirichlet_process.log_prob(mix_probs)[..., tf.newaxis] / num_samples, rv_observations.log_prob(observations_tensor) / batch_size ] joint_log_prob = tf.reduce_sum(tf.concat(log_prob_parts, axis=-1), axis=-1)
# Make mini-batch generator dx = tf.compat.v1.data.Dataset.from_tensor_slices(observations)\ .shuffle(500).repeat().batch(batch_size) iterator = tf.compat.v1.data.make_one_shot_iterator(dx) next_batch = iterator.get_next() # Define learning rate scheduling global_step = tf.Variable(0, trainable=False) learning_rate = tf.train.polynomial_decay( starter_learning_rate, global_step, decay_steps, end_learning_rate, power=1.) # Set up the optimizer. Don't forget to set data_size=num_samples. optimizer_kernel = tfp.optimizer.StochasticGradientLangevinDynamics( learning_rate=learning_rate, preconditioner_decay_rate=0.99, burnin=1500, data_size=num_samples) train_op = optimizer_kernel.minimize(-joint_log_prob) # Arrays to store samples mean_mix_probs_mtx = np.zeros([training_steps, max_cluster_num]) mean_alpha_mtx = np.zeros([training_steps, 1]) mean_loc_mtx = np.zeros([training_steps, max_cluster_num, dims]) mean_precision_mtx = np.zeros([training_steps, max_cluster_num, dims]) init = tf.global_variables_initializer() sess.run(init) start = time.time() for it in range(training_steps): [ mean_mix_probs_mtx[it, :], mean_alpha_mtx[it, 0], mean_loc_mtx[it, :, :], mean_precision_mtx[it, :, :], _ ] = sess.run([ *training_vals, train_op ], feed_dict={ observations_tensor: sess.run(next_batch)}) elapsed_time_psgld = time.time() - start print("Elapsed time: {} seconds".format(elapsed_time_psgld)) # Take mean over the last sample_size iterations mean_mix_probs_ = mean_mix_probs_mtx[-sample_size:, :].mean(axis=0) mean_alpha_ = mean_alpha_mtx[-sample_size:, :].mean(axis=0) mean_loc_ = mean_loc_mtx[-sample_size:, :].mean(axis=0) mean_precision_ = mean_precision_mtx[-sample_size:, :].mean(axis=0)
Elapsed time: 309.8013095855713 seconds

4. Visualización del resultado

4.1. Resultado agrupado

Primero, visualizamos el resultado de la agrupación.

Para asignar cada muestra xix_i a un clúster jj, calculamos la posterior de ziz_i como:

j=argmaxzip(zixi,θ)\begin{align*} j = \underset{z_i}{\arg\max}\,p(z_i\,|\,x_i,\,\boldsymbol{\theta}) \end{align*}
loc_for_posterior = tf.compat.v1.placeholder( dtype, [None, max_cluster_num, dims], name='loc_for_posterior') precision_for_posterior = tf.compat.v1.placeholder( dtype, [None, max_cluster_num, dims], name='precision_for_posterior') mix_probs_for_posterior = tf.compat.v1.placeholder( dtype, [None, max_cluster_num], name='mix_probs_for_posterior') # Posterior of z (unnormalized) unnomarlized_posterior = tfd.MultivariateNormalDiag( loc=loc_for_posterior, scale_diag=precision_for_posterior)\ .log_prob(tf.expand_dims(tf.expand_dims(observations, axis=1), axis=1))\ + tf.log(mix_probs_for_posterior[tf.newaxis, ...]) # Posterior of z (normarizad over latent states) posterior = unnomarlized_posterior\ - tf.reduce_logsumexp(unnomarlized_posterior, axis=-1)[..., tf.newaxis] cluster_asgmt = sess.run(tf.argmax( tf.reduce_mean(posterior, axis=1), axis=1), feed_dict={ loc_for_posterior: mean_loc_mtx[-sample_size:, :], precision_for_posterior: mean_precision_mtx[-sample_size:, :], mix_probs_for_posterior: mean_mix_probs_mtx[-sample_size:, :]}) idxs, count = np.unique(cluster_asgmt, return_counts=True) print('Number of inferred clusters = {}\n'.format(len(count))) np.set_printoptions(formatter={'float': '{: 0.3f}'.format}) print('Number of elements in each cluster = {}\n'.format(count)) def convert_int_elements_to_consecutive_numbers_in(array): unique_int_elements = np.unique(array) for consecutive_number, unique_int_element in enumerate(unique_int_elements): array[array == unique_int_element] = consecutive_number return array cmap = plt.get_cmap('tab10') plt.scatter( observations[:, 0], observations[:, 1], 1, c=cmap(convert_int_elements_to_consecutive_numbers_in(cluster_asgmt))) plt.axis([-10, 10, -10, 10]) plt.show()
Number of inferred clusters = 3 Number of elements in each cluster = [16911 16645 16444]
Image in a Jupyter notebook

Podemos ver que se asigna un número casi igual de muestras a los clústeres apropiados y que el modelo también ha inferido con éxito el número correcto de clústeres.

4.2 Visualización de la incertidumbre

Aquí, analizamos la incertidumbre del resultado del agrupamiento al visualizarlo para cada muestra.

Calculamos la incertidumbre mediante el uso de entropía:

Uncertaintyentropy=1Kzi=1Kl=1Op(zixi,θl)logp(zixi,θl)\begin{align*} \text{Uncertainty}_\text{entropy} = -\frac{1}{K}\sum^{K}_{z_i=1}\sum^{O}_{l=1}p(z_i\,|\,x_i,\,\boldsymbol{\theta}_l)\log p(z_i\,|\,x_i,\,\boldsymbol{\theta}_l) \end{align*}

En pSGLD, tratamos el valor de un parámetro de entrenamiento en cada iteración como una muestra de su distribución posterior. Por lo tanto, calculamos la entropía sobre los valores de OO iteraciones para cada parámetro. El valor final de entropía se calcula al promediar las entropías de todas las asignaciones de clústeres.

# Calculate entropy posterior_in_exponential = tf.exp(posterior) uncertainty_in_entropy = tf.reduce_mean(-tf.reduce_sum( posterior_in_exponential * posterior, axis=1), axis=1) uncertainty_in_entropy_ = sess.run(uncertainty_in_entropy, feed_dict={ loc_for_posterior: mean_loc_mtx[-sample_size:, :], precision_for_posterior: mean_precision_mtx[-sample_size:, :], mix_probs_for_posterior: mean_mix_probs_mtx[-sample_size:, :] })
plt.title('Entropy') sc = plt.scatter(observations[:, 0], observations[:, 1], 1, c=uncertainty_in_entropy_, cmap=plt.cm.viridis_r) cbar = plt.colorbar(sc, fraction=0.046, pad=0.04, ticks=[uncertainty_in_entropy_.min(), uncertainty_in_entropy_.max()]) cbar.ax.set_yticklabels(['low', 'high']) cbar.set_label('Uncertainty', rotation=270) plt.show()
Image in a Jupyter notebook

En el grafo anterior, menos luminancia representa más incertidumbre. Podemos ver que las muestras cercanas a los límites de los clústeres tienen una incertidumbre especialmente mayor. Esto es intuitivamente cierto: esas muestras son difíciles de agrupar.

4.3. Media y escala del componente de mezcla seleccionado

A continuación, analizamos los clústeres seleccionados μj\mu_j y σj\sigma_j.

for idx, numbe_of_samples in zip(idxs, count): print( 'Component id = {}, Number of elements = {}' .format(idx, numbe_of_samples)) print( 'Mean loc = {}, Mean scale = {}\n' .format(mean_loc_[idx, :], mean_precision_[idx, :]))
Component id = 0, Number of elements = 16911 Mean loc = [-4.030 -4.113], Mean scale = [ 0.994 0.972] Component id = 4, Number of elements = 16645 Mean loc = [ 3.999 4.069], Mean scale = [ 1.038 1.046] Component id = 5, Number of elements = 16444 Mean loc = [-0.005 -0.023], Mean scale = [ 0.967 1.025]

Nuevamente, μj\boldsymbol{\mu_j} y σj\boldsymbol{\sigma_j} se acercan a la verdad fundamental.

4.4 Ponderación de cada componente de la mezcla

También analizamos las ponderaciones inferidas de la mezcla.

plt.ylabel('Mean posterior of mixture weight') plt.xlabel('Component') plt.bar(range(0, max_cluster_num), mean_mix_probs_) plt.show()
Image in a Jupyter notebook

Vemos que solo unos pocos (tres) componentes de la mezcla tienen ponderaciones significativas y que el resto de las ponderaciones tienen valores próximos a cero. Esto también muestra que el modelo infirió con éxito el número correcto de componentes de la mezcla que constituye la distribución de las muestras.

4.5. Convergencia de α\alpha

Observamos la convergencia del parámetro de concentración α\alpha de la distribución de Dirichlet.

print('Value of inferred alpha = {0:.3f}\n'.format(mean_alpha_[0])) plt.ylabel('Sample value of alpha') plt.xlabel('Iteration') plt.plot(mean_alpha_mtx) plt.show()
Value of inferred alpha = 0.679
Image in a Jupyter notebook

Teniendo en cuenta el hecho de que α\alpha más pequeños da como resultado un menor número esperado de clústeres en un modelo de mezcla de Dirichlet, el modelo parece estar aprendiendo el número óptimo de clústeres a lo largo de iteraciones.

4.6. Número inferido de clústeres durante iteraciones

Visualizamos cómo el número inferido de clústeres cambia a lo largo de las iteraciones.

Para hacerlo, inferimos el número de clústeres a lo largo de las iteraciones.

step = sample_size num_of_iterations = 50 estimated_num_of_clusters = [] interval = (training_steps - step) // (num_of_iterations - 1) iterations = np.asarray(range(step, training_steps+1, interval)) for iteration in iterations: start_position = iteration-step end_position = iteration result = sess.run(tf.argmax( tf.reduce_mean(posterior, axis=1), axis=1), feed_dict={ loc_for_posterior: mean_loc_mtx[start_position:end_position, :], precision_for_posterior: mean_precision_mtx[start_position:end_position, :], mix_probs_for_posterior: mean_mix_probs_mtx[start_position:end_position, :]}) idxs, count = np.unique(result, return_counts=True) estimated_num_of_clusters.append(len(count))
plt.ylabel('Number of inferred clusters') plt.xlabel('Iteration') plt.yticks(np.arange(1, max(estimated_num_of_clusters) + 1, 1)) plt.plot(iterations - 1, estimated_num_of_clusters) plt.show()
Image in a Jupyter notebook

A lo largo de las iteraciones, el número de clústeres se acerca a tres. Con el resultado de la convergencia de α\alpha a un valor más pequeño a lo largo de iteraciones, podemos ver que el modelo está aprendiendo con éxito los parámetros para inferir un número óptimo de clústeres.

Curiosamente, podemos ver que la inferencia ya ha convergido al número correcto de clústeres en las primeras iteraciones, a diferencia de α\alpha que convergió en iteraciones mucho más posteriores.

4.7. Ajuste del modelo mediante el uso de RMSProp

En esta sección, para ver la efectividad del esquema de muestreo Monte Carlo de pSGLD, utilizamos RMSProp para ajustar el modelo. Elegimos RMSProp para comparar porque viene sin el esquema de muestreo y pSGLD se basa en RMSProp.

# Learning rates and decay starter_learning_rate_rmsprop = 1e-2 end_learning_rate_rmsprop = 1e-4 decay_steps_rmsprop = 1e4 # Number of training steps training_steps_rmsprop = 50000 # Mini-batch size batch_size_rmsprop = 20
# Define trainable variables. mix_probs_rmsprop = tf.nn.softmax( tf.Variable( name='mix_probs_rmsprop', initial_value=np.ones([max_cluster_num], dtype) / max_cluster_num)) loc_rmsprop = tf.Variable( name='loc_rmsprop', initial_value=np.zeros([max_cluster_num, dims], dtype) + np.random.uniform( low=-9, #set around minimum value of sample value high=9, #set around maximum value of sample value size=[max_cluster_num, dims])) precision_rmsprop = tf.nn.softplus(tf.Variable( name='precision_rmsprop', initial_value= np.ones([max_cluster_num, dims], dtype=dtype))) alpha_rmsprop = tf.nn.softplus(tf.Variable( name='alpha_rmsprop', initial_value= np.ones([1], dtype=dtype))) training_vals_rmsprop =\ [mix_probs_rmsprop, alpha_rmsprop, loc_rmsprop, precision_rmsprop] # Prior distributions of the training variables #Use symmetric Dirichlet prior as finite approximation of Dirichlet process. rv_symmetric_dirichlet_process_rmsprop = tfd.Dirichlet( concentration=np.ones(max_cluster_num, dtype) * alpha_rmsprop / max_cluster_num, name='rv_sdp_rmsprop') rv_loc_rmsprop = tfd.Independent( tfd.Normal( loc=tf.zeros([max_cluster_num, dims], dtype=dtype), scale=tf.ones([max_cluster_num, dims], dtype=dtype)), reinterpreted_batch_ndims=1, name='rv_loc_rmsprop') rv_precision_rmsprop = tfd.Independent( tfd.InverseGamma( concentration=np.ones([max_cluster_num, dims], dtype), rate=np.ones([max_cluster_num, dims], dtype)), reinterpreted_batch_ndims=1, name='rv_precision_rmsprop') rv_alpha_rmsprop = tfd.InverseGamma( concentration=np.ones([1], dtype=dtype), rate=np.ones([1]), name='rv_alpha_rmsprop') # Define mixture model rv_observations_rmsprop = tfd.MixtureSameFamily( mixture_distribution=tfd.Categorical(probs=mix_probs_rmsprop), components_distribution=tfd.MultivariateNormalDiag( loc=loc_rmsprop, scale_diag=precision_rmsprop))
og_prob_parts_rmsprop = [ rv_loc_rmsprop.log_prob(loc_rmsprop), rv_precision_rmsprop.log_prob(precision_rmsprop), rv_alpha_rmsprop.log_prob(alpha_rmsprop), rv_symmetric_dirichlet_process_rmsprop .log_prob(mix_probs_rmsprop)[..., tf.newaxis], rv_observations_rmsprop.log_prob(observations_tensor) * num_samples / batch_size ] joint_log_prob_rmsprop = tf.reduce_sum( tf.concat(log_prob_parts_rmsprop, axis=-1), axis=-1)
# Define learning rate scheduling global_step_rmsprop = tf.Variable(0, trainable=False) learning_rate = tf.train.polynomial_decay( starter_learning_rate_rmsprop, global_step_rmsprop, decay_steps_rmsprop, end_learning_rate_rmsprop, power=1.) # Set up the optimizer. Don't forget to set data_size=num_samples. optimizer_kernel_rmsprop = tf.train.RMSPropOptimizer( learning_rate=learning_rate, decay=0.99) train_op_rmsprop = optimizer_kernel_rmsprop.minimize(-joint_log_prob_rmsprop) init_rmsprop = tf.global_variables_initializer() sess.run(init_rmsprop) start = time.time() for it in range(training_steps_rmsprop): [ _ ] = sess.run([ train_op_rmsprop ], feed_dict={ observations_tensor: sess.run(next_batch)}) elapsed_time_rmsprop = time.time() - start print("RMSProp elapsed_time: {} seconds ({} iterations)" .format(elapsed_time_rmsprop, training_steps_rmsprop)) print("pSGLD elapsed_time: {} seconds ({} iterations)" .format(elapsed_time_psgld, training_steps)) mix_probs_rmsprop_, alpha_rmsprop_, loc_rmsprop_, precision_rmsprop_ =\ sess.run(training_vals_rmsprop)
RMSProp elapsed_time: 53.7574200630188 seconds (50000 iterations) pSGLD elapsed_time: 309.8013095855713 seconds (10000 iterations)

En comparación con pSGLD, aunque el número de iteraciones de RMSProp es mayor, la optimización de RMSProp es mucho más rápida.

A continuación, observamos el resultado de la agrupación.

cluster_asgmt_rmsprop = sess.run(tf.argmax( tf.reduce_mean(posterior, axis=1), axis=1), feed_dict={ loc_for_posterior: loc_rmsprop_[tf.newaxis, :], precision_for_posterior: precision_rmsprop_[tf.newaxis, :], mix_probs_for_posterior: mix_probs_rmsprop_[tf.newaxis, :]}) idxs, count = np.unique(cluster_asgmt_rmsprop, return_counts=True) print('Number of inferred clusters = {}\n'.format(len(count))) np.set_printoptions(formatter={'float': '{: 0.3f}'.format}) print('Number of elements in each cluster = {}\n'.format(count)) cmap = plt.get_cmap('tab10') plt.scatter( observations[:, 0], observations[:, 1], 1, c=cmap(convert_int_elements_to_consecutive_numbers_in( cluster_asgmt_rmsprop))) plt.axis([-10, 10, -10, 10]) plt.show()
Number of inferred clusters = 4 Number of elements in each cluster = [ 1644 15267 16647 16442]
Image in a Jupyter notebook

La optimización RMSProp no dedujo correctamente el número de clústeres en nuestro experimento. También nos fijamos en la ponderación de la mezcla.

plt.ylabel('MAP inferece of mixture weight') plt.xlabel('Component') plt.bar(range(0, max_cluster_num), mix_probs_rmsprop_) plt.show()
Image in a Jupyter notebook

Podemos ver que la cantidad incorrecta de componentes tiene ponderaciones de mezcla significativas.

Aunque la optimización lleva más tiempo, pSGLD, que tiene un esquema de muestreo de Monte Carlo, tuvo un mejor desempeño en nuestro experimento.

5. Conclusión

En este bloc de notas, hemos descrito cómo agrupar una gran cantidad de muestras, así como inferir la cantidad de clústeres simultáneamente al ajustar una mezcla del proceso Dirichlet de distribución gaussiana mediante el uso de la pSGLD.

El experimento demostró que el modelo agrupó muestras con éxito e infirió el número correcto de clústeres. Además, hemos demostrado que el esquema de muestreo de Monte Carlo de la pSGLD nos permite visualizar la incertidumbre en el resultado. No solo agrupando las muestras, sino que también hemos visto que el modelo podría inferir los parámetros correctos de los componentes de la mezcla. Sobre la relación entre los parámetros y el número de conglomerados inferidos, hemos investigado cómo el modelo aprende el parámetro para controlar el número de clústeres efectivos visualizando la correlación entre la convergencia de 𝛼 y el número de clústeres inferidos. Por último, hemos analizado los resultados del ajuste del modelo mediante el uso de RMSProp. Hemos visto que RMSProp, que es el optimizador sin esquema de muestreo de Monte Carlo, funciona considerablemente más rápido que la pSGLD, pero ha producido menos precisión en la agrupación.

Aunque el conjunto de datos de juguetes solo tenía 50 000 muestras con solo dos dimensiones, la optimización en forma de minilotes que se usa aquí se puede escalar en conjuntos de datos mucho más grandes.