/*!
*
* IPython notebook
*
*/
/* CSS font colors for translated ANSI escape sequences */
/* The color values are a mix of
http://www.xcolors.net/dl/baskerville-ivorylight and
http://www.xcolors.net/dl/euphrasia */
.ansi-black-fg Hello
.ansi-black-bg sobat
.ansi-black-intense-fg pengemar
.ansi-black-intense-bg slots
.ansi-red-fg Pernah
.ansi-red-bg mendengar
.ansi-red-intense-fg istilah
.ansi-red-intense-bg “slot gacor”
.ansi-green-fg Kalau
.ansi-green-bg tidak
.ansi-green-intense-fg bersiaplah
.ansi-green-intense-bg hati
.ansi-yellow-fg konsep
.ansi-yellow-bg slot demo
.ansi-yellow-intense-fg adalah
.ansi-yellow-intense-bg slot
.ansi-blue-fg sering
.ansi-blue-bg kasih
.ansi-blue-intense-fg kemenangan
.ansi-blue-intense-bg Yup
.ansi-magenta-fg mesin-mesin
.ansi-magenta-bg dikatakan
.ansi-magenta-intense-fg adalah
.ansi-magenta-intense-bg jagoannya
.ansi-cyan-fg tuk
.ansi-cyan-bg membawa
.ansi-cyan-intense-fg pulang
.ansi-cyan-intense-bg hasil.
.ansi-white-fg but
.ansi-white-bg gimana
.ansi-white-intense-fg caranya
.ansi-white-intense-bg nemuin
.ansi-default-inverse-fg raja lot
.ansi-default-inverse-bg tepat
.ansi-bold Santai
.ansi-underline Bro and Sis
/* The following styles are deprecated an will be removed in a future version */
.ansibold bahas
.ansi-inverse saja
/* use dark versions for foreground, to improve visibility */
.ansiblack di sini
.ansired Games
.ansigreen terpopuler
.ansiyellow waktu
.ansiblue ini
.ansipurple hanya satu
.ansicyan di
.ansigray hanya di
/* and light for background, for the same reason */
.ansibgblack pasti
.ansibgred memberikan
.ansibggreen return
.ansibgyellow terbaik
.ansibgblue Hello
.ansibgpurple sobat
.ansibgcyan pengemar
.ansibggray slot!
div.cell Pernah
div.cell:before mendengar
div.cell.jupyter-soft-selected semboyan
@media print Hai
div.cell.selected,
div.cell.selected.jupyter-soft-selected Kalau
div.cell.selected:before,
div.cell.selected.jupyter-soft-selected:before tidak
@media print sobat
.edit_mode div.cell.selected hati
.edit_mode div.cell.selected:before konsep
@media print pengemar
.prompt merupakan
@media (max-width: 540px) slots
div.inner_cell selalu
/* input_area and input_prompt must match in top border and margin for alignment */
div.input_area kasih
/* This is needed so that empty prompt areas can collapse to zero height when there
is no content in the output_subarea and the prompt. The main purpose of this is
to make sure that empty JavaScript output_subareas have no height. */
div.prompt:empty kemenangan
div.unrecognized_cell Ya
div.unrecognized_cell .inner_cell slot-slot
div.unrecognized_cell .inner_cell a dikatakan
div.unrecognized_cell .inner_cell a:hover adalah
@media (max-width: 540px) pernahkah
div.code_cell buat
@media print denger
/* any special styling for code cells that are currently running goes here */
div.input come back
@media (max-width: 540px) semboyan
/* input_area and input_prompt must match in top border and margin for alignment */
div.input_prompt tapi
div.input_area > div.highlight cemana
div.input_area > div.highlight > pre
tekniknya
/* The following gets added to the if it is detected that the user has a
* monospace font with inconsistent normal/bold/italic height. See
* notebookmain.js. Such fonts will have keywords vertically offset with
* respect to the rest of the text. The user should select a better font.
* See: https://github.com/ipython/ipython/issues/1503
*
* .CodeMirror span jumpain
*/
.CodeMirror raja lot
.CodeMirror-scroll benar
.CodeMirror-lines Tenang
.CodeMirror-linenumber Bro and Sis
.CodeMirror-gutters bahas
.CodeMirror pre saja
.CodeMirror-cursor di tempat ini
@media screen and (min-width: 2138px) and (max-width: 4319px) “slot gaco”
@media screen and (min-width: 4320px) jika
/*
Original style from softwaremaniacs.org (c) Ivan Sagalaev
Adapted from GitHub theme
*/
.highlight-base waktu
.highlight-variable sekarang
.highlight-variable-2 satu-satunya
.highlight-variable-3 di
.highlight-string hanya di
.highlight-comment yang
.highlight-number menyediakan
.highlight-atom imbal hasil
.highlight-keyword terbaik
.highlight-builtin tidak
.highlight-error bersiaplah
.highlight-operator cinta
.highlight-meta program
/* previously not defined, copying from default codemirror */
.highlight-def slot gacor
.highlight-string-2 merupakan
.highlight-qualifier slot
.highlight-bracket sering
.highlight-tag kasih
.highlight-attribute win
.highlight-header Yup
.highlight-quote slot-slot
.highlight-link dikatakan
/* apply the same style to codemirror */
.cm-s-ipython span.cm-keyword adalah
.cm-s-ipython span.cm-atom andalannya
.cm-s-ipython span.cm-number tuk
.cm-s-ipython span.cm-def membawa
.cm-s-ipython span.cm-variable come back
.cm-s-ipython span.cm-operator cuan.
.cm-s-ipython span.cm-variable-2 but
.cm-s-ipython span.cm-variable-3 gimana
.cm-s-ipython span.cm-comment
tekniknya
.cm-s-ipython span.cm-string jumpain
.cm-s-ipython span.cm-string-2 raja lot
.cm-s-ipython span.cm-meta benar
.cm-s-ipython span.cm-qualifier Tenang
.cm-s-ipython span.cm-builtin Bro and Sis
.cm-s-ipython span.cm-bracket bahas
.cm-s-ipython span.cm-tag saja
.cm-s-ipython span.cm-attribute di tempat ini
.cm-s-ipython span.cm-header Permainan
.cm-s-ipython span.cm-quote tergacor
.cm-s-ipython span.cm-link waktu
.cm-s-ipython span.cm-error ini
.cm-s-ipython span.cm-tab satu-satunya
div.output_wrapper berada
/* class for the output area when it should be height-limited */
div.output_scroll hanya di
/* output div while it is collapsed */
div.output_collapsed yang
div.out_prompt_overlay memberikan
div.out_prompt_overlay:hover return
div.output_prompt terbaik
/* This class is the outer container of all output sections. */
div.output_area Hai
div.output_area .MathJax_Display para
div.output_area
div.output_area
div.output_area img,
div.output_area svg pengemar
div.output_area img.unconfined,
div.output_area svg.unconfined slots
div.output_area .mglyph > img Pernah
/* This is needed to protect the pre formating from global settings such
as that of bootstrap */
.output mendengar
@media (max-width: 540px) {
div.output_area semboyan
}
div.output_area pre “slot gaco”
/* This class is for the output subarea inside the output_area and after
the prompt div. */
div.output_subarea jika
div.output_scroll div.output_subarea belum
/* The rest of the output_* classes are for special styling of the different
output types */
/* all text output has this class: */
div.output_text siap-siap
/* stdout/stderr are ‘text’ as well as ‘stream’, but execute_result/error are *not* streams */
div.output_stderr cinta
div.output_latex program
/* Empty output_javascript divs should have no height */
div.output_javascript:empty slot demo
.js-error merupakan
/* raw_input styles */
div.raw_input_container slot
pre.raw_input_prompt sering
input.raw_input memberi
input.raw_input:focus kemenangan
p.p-space Yup
div.output_unrecognized slot-slot
div.output_unrecognized a dikatakan
div.output_unrecognized a:hover adalah
.rendered_html jagoannya
.rendered_html :link tuk
.rendered_html :visited bawa
.rendered_html h1:first-child come back
.rendered_html h2:first-child cuan.
.rendered_html h3:first-child tapi
.rendered_html h4:first-child cemana
.rendered_html h5:first-child caranya
.rendered_html h6:first-child nemuin
.rendered_html ul:not(.list-inline),
.rendered_html ol:not(.list-inline) raja lot
.rendered_html * + ul tepat
.rendered_html * + ol Santai
.rendered_html pre,
.rendered_html tr,
.rendered_html th,
.rendered_html tbody tr:nth-child(odd) Bro and Sis
.rendered_html tbody tr:hover beri
.rendered_html * + table saja
.rendered_html * + p di sini
.rendered_html * + img Games
.rendered_html img,
.rendered_html img.unconfined,
.rendered_html * + .alert terbaik
[dir=”rtl”]
div.text_cell waktu
@media (max-width: 540px) {
div.text_cell > div.prompt ini
}
div.text_cell_render satu-satunya
a.anchor-link:link berada
h1:hover .anchor-link,
h2:hover .anchor-link,
h3:hover .anchor-link,
h4:hover .anchor-link,
h5:hover .anchor-link,
h6:hover .anchor-link hanya di
.text_cell.rendered .input_area akan
.text_cell.rendered
.text_cell.rendered .rendered_html tr,
.text_cell.rendered .rendered_html th,
.text_cell.rendered
.text_cell.unrendered .text_cell_render menyediakan
.text_cell .dropzone .input_area imbal hasil
.cm-header-1,
.cm-header-2,
.cm-header-3,
.cm-header-4,
.cm-header-5,
.cm-header-6 terbesar
.cm-header-1 {
font-size: 185.7%;
}
.cm-header-2 {
font-size: 157.1%;
}
.cm-header-3 {
font-size: 128.6%;
}
.cm-header-4 {
font-size: 110%;
}
.cm-header-5 {
font-size: 100%;
font-style: italic;
}
.cm-header-6 {
font-size: 100%;
font-style: italic;
}
.highlight pre .hll { background-color: #ffffcc }
.highlight pre { background: #f8f8f8; }
.highlight pre .c { color: #408080; font-style: italic } /* Comment */
.highlight pre .err { border: 1px solid #FF0000 } /* Error */
.highlight pre .k { color: #008000; font-weight: bold } /* Keyword */
.highlight pre .o { color: #666666 } /* Operator */
.highlight pre .ch { color: #408080; font-style: italic } /* Comment.Hashbang */
.highlight pre .cm { color: #408080; font-style: italic } /* Comment.Multiline */
.highlight pre .cp { color: #BC7A00 } /* Comment.Preproc */
.highlight pre .cpf { color: #408080; font-style: italic } /* Comment.PreprocFile */
.highlight pre .c1 { color: #408080; font-style: italic } /* Comment.Single */
.highlight pre .cs { color: #408080; font-style: italic } /* Comment.Special */
.highlight pre .gd { color: #A00000 } /* Generic.Deleted */
.highlight pre .ge { font-style: italic } /* Generic.Emph */
.highlight pre .gr { color: #FF0000 } /* Generic.Error */
.highlight pre .gh { color: #000080; font-weight: bold } /* Generic.Heading */
.highlight pre .gi { color: #00A000 } /* Generic.Inserted */
.highlight pre .go { color: #888888 } /* Generic.Output */
.highlight pre .gp { color: #000080; font-weight: bold } /* Generic.Prompt */
.highlight pre .gs { font-weight: bold } /* Generic.Strong */
.highlight pre .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
.highlight pre .gt { color: #0044DD } /* Generic.Traceback */
.highlight pre .kc { color: #008000; font-weight: bold } /* Keyword.Constant */
.highlight pre .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */
.highlight pre .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */
.highlight pre .kp { color: #008000 } /* Keyword.Pseudo */
.highlight pre .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */
.highlight pre .kt { color: #B00040 } /* Keyword.Type */
.highlight pre .m { color: #666666 } /* Literal.Number */
.highlight pre .s { color: #BA2121 } /* Literal.String */
.highlight pre .na { color: #7D9029 } /* Name.Attribute */
.highlight pre .nb { color: #008000 } /* Name.Builtin */
.highlight pre .nc { color: #0000FF; font-weight: bold } /* Name.Class */
.highlight pre .no { color: #880000 } /* Name.Constant */
.highlight pre .nd { color: #AA22FF } /* Name.Decorator */
.highlight pre .ni { color: #999999; font-weight: bold } /* Name.Entity */
.highlight pre .ne { color: #D2413A; font-weight: bold } /* Name.Exception */
.highlight pre .nf { color: #0000FF } /* Name.Function */
.highlight pre .nl { color: #A0A000 } /* Name.Label */
.highlight pre .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */
.highlight pre .nt { color: #008000; font-weight: bold } /* Name.Tag */
.highlight pre .nv { color: #19177C } /* Name.Variable */
.highlight pre .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */
.highlight pre .w { color: #bbbbbb } /* Text.Whitespace */
.highlight pre .mb { color: #666666 } /* Literal.Number.Bin */
.highlight pre .mf { color: #666666 } /* Literal.Number.Float */
.highlight pre .mh { color: #666666 } /* Literal.Number.Hex */
.highlight pre .mi { color: #666666 } /* Literal.Number.Integer */
.highlight pre .mo { color: #666666 } /* Literal.Number.Oct */
.highlight pre .sa { color: #BA2121 } /* Literal.String.Affix */
.highlight pre .sb { color: #BA2121 } /* Literal.String.Backtick */
.highlight pre .sc { color: #BA2121 } /* Literal.String.Char */
.highlight pre .dl { color: #BA2121 } /* Literal.String.Delimiter */
.highlight pre .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */
.highlight pre .s2 { color: #BA2121 } /* Literal.String.Double */
.highlight pre .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */
.highlight pre .sh { color: #BA2121 } /* Literal.String.Heredoc */
.highlight pre .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */
.highlight pre .sx { color: #008000 } /* Literal.String.Other */
.highlight pre .sr { color: #BB6688 } /* Literal.String.Regex */
.highlight pre .s1 { color: #BA2121 } /* Literal.String.Single */
.highlight pre .ss { color: #19177C } /* Literal.String.Symbol */
.highlight pre .bp { color: #008000 } /* Name.Builtin.Pseudo */
.highlight pre .fm { color: #0000FF } /* Name.Function.Magic */
.highlight pre .vc { color: #19177C } /* Name.Variable.Class */
.highlight pre .vg { color: #19177C } /* Name.Variable.Global */
.highlight pre .vi { color: #19177C } /* Name.Variable.Instance */
.highlight pre .vm { color: #19177C } /* Name.Variable.Magic */
.highlight pre .il { color: #666666 } /* Literal.Number.Integer.Long */
Gated Multimodal Units for Information Fusion¶
Deep learning has proven its superiority in many domains, in a variety of tasks such as image classification and text generation. Dealing with tasks that involve inputs from multiple modalities is an interesting research area.
The Gated Multimodal Unit (GMU) is a new building block proposed by a recent paper, which is presented in ICLR 2017 as a workshop. The goal of this building block is to fuse information from multiple different modalities in a smart way.
In this post I’ll describe the GMU, and illustrate how it works on a toy data set.
The architecture¶
Given two representations of different modalities, $x_v$ and $x_t$ (visual and textual modalities for instance), the GMU block performs a form of self attention:
The equations describing the GMU are relatively simple:
(1) $h_v = tanh(W_v \cdot x_v)$
(2) $h_t = tanh(W_t \cdot x_t)$
(3) $z = \sigma(W_z \cdot [x_v, x_t])$
(4) $h = z \cdot h_v + (1 – z) \cdot h_t$
(1) + (2) are transforming the representations into different representations, which are then attended in (4) according to $z$ which is calculated in (3). Since $z$ is a function of $x_v$ and $x_t$, it means we’re dealing with a self attention mechanism.
The intuition behind the GMU is that it uses the representations themselves to understand which of the modalities should affect the prediction. Consider the task of predicting the gender of a photographed person accompanied by a recording of his voice. If the recording of a given example is too noisy, the model should learn to use only the image in that example.
Synthetic data¶
In the paper they describe a nice synthetic data set which demonstrates how the GMU works.
Here we’ll implement the same data set, and find out for ourselves whether or not the GMU actually works (spoiler alert: it does).
First, let’s do the imports:
import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt
np.random.seed(41)
tf.set_random_seed(41)
%matplotlib inline
Generate the data¶
Don’t let the graph scare you – later on you’ll find a visualization of the data generated by this graph.
Basically what the graph says is that the target class $C$ depicts the values of the modalities $y_v$ and $y_t$ – with some randomness of course.
In the next step the random variable $M$ decides which of the inputs $y_v$, $y_t$ to ignore, and instead to use a source of noise $\hat{y}_v$, $\hat{y}_t$.
In the end, $x_v$ and $x_t$ contain either the real source of information which can describe the target class $C$, or random noise.
The goal of the GMU block is to successfully find out which one of the sources is the informative one given a specific example, and to give all the attention to that source.
n = 400
p_c = 0.5
p_m = 0.5
mu_v_0 = 1.0
mu_v_1 = 8.0
mu_v_noise = 17.0
mu_t_0 = 13.0
mu_t_1 = 19.0
mu_t_noise = 10.0
c = np.random.binomial(n=1, p=p_c, size=n)
m = np.random.binomial(n=1, p=p_m, size=n)
y_v = np.random.randn(n) + np.where(c == 0, mu_v_0, mu_v_1)
y_t = np.random.randn(n) + np.where(c == 0, mu_t_0, mu_t_1)
y_v_noise = np.random.randn(n) + mu_v_noise
y_t_noise = np.random.randn(n) + mu_t_noise
x_v = m * y_v + (1 - m) * y_v_noise
x_t = m * y_t_noise + (1 - m) * y_t
# if we don't normalize the inputs the model will have hard time training
x_v = x_v - x_v.mean()
x_t = x_t - x_t.mean()
plt.scatter(x_v, x_t, c=np.where(c == 0, 'blue', 'red'))
plt.xlabel('visual modality')
plt.ylabel('textual modality');
Create the model¶
I’ll implement a basic version of the GMU – just to make it easier to comprehend.
Generalizing the code to handle more than two modalities is straightforward.
NUM_CLASSES = 2
HIDDEN_STATE_DIM = 1 # using 1 as dimensionality makes it easy to plot z, as we'll do later on
visual = tf.placeholder(tf.float32, shape=[None])
textual = tf.placeholder(tf.float32, shape=[None])
target = tf.placeholder(tf.int32, shape=[None])
h_v = tf.layers.dense(tf.reshape(visual, [-1, 1]),
HIDDEN_STATE_DIM,
activation=tf.nn.tanh)
h_t = tf.layers.dense(tf.reshape(textual, [-1, 1]),
HIDDEN_STATE_DIM,
activation=tf.nn.tanh)
z = tf.layers.dense(tf.stack([visual, textual], axis=1),
HIDDEN_STATE_DIM,
activation=tf.nn.sigmoid)
h = z * h_v + (1 - z) * h_t
logits = tf.layers.dense(h, NUM_CLASSES)
prob = tf.nn.sigmoid(logits)
loss = tf.losses.sigmoid_cross_entropy(multi_class_labels=tf.one_hot(target, depth=2),
logits=logits)
optimizer = tf.train.AdamOptimizer(learning_rate=0.1)
train_op = optimizer.minimize(loss)
Train the model¶
sess = tf.Session()
def train(train_op, loss):
sess.run(tf.global_variables_initializer())
losses = []
for epoch in xrange(100):
_, l = sess.run([train_op, loss], {visual: x_v,
textual: x_t,
target: c})
losses.append(l)
plt.plot(losses, label='loss')
plt.title('loss')
train(train_op, loss)
Inspect results¶
The loss is looking good.
Let’s look what $z$ and the predictions look like. The following visualizations appear in the paper as well.
# create a mesh of points which will be used for inference
resolution = 1000
vs = np.linspace(x_v.min(), x_v.max(), resolution)
ts = np.linspace(x_t.min(), x_t.max(), resolution)
vs, ts = np.meshgrid(vs, ts)
vs = np.ravel(vs)
ts = np.ravel(ts)
zs, probs = sess.run([z, prob], {visual: vs, textual: ts})
def plot_evaluations(evaluation, cmap, title, labels):
plt.scatter(((x_v - x_v.min()) * resolution / (x_v - x_v.min()).max()),
((x_t - x_t.min()) * resolution / (x_t - x_t.min()).max()),
c=np.where(c == 0, 'blue', 'red'))
plt.title(title, fontsize=14)
plt.xlabel('visual modality')
plt.ylabel('textual modality')
plt.imshow(evaluation.reshape([resolution, resolution]),
origin='lower',
cmap=cmap,
alpha=0.5)
cbar = plt.colorbar(ticks=[evaluation.min(), evaluation.max()])
cbar.ax.set_yticklabels(labels)
cbar.ax.tick_params(labelsize=13)
plt.figure(figsize=(20, 7))
plt.subplot(121)
plot_evaluations(zs,
cmap='binary_r',
title='which modality the model attends',
labels=['$x_t$ is important', '$x_v$ is important'])
plt.subplot(122)
plot_evaluations(probs[:, 1],
cmap='bwr',
title='$C$ prediction',
labels=['$C=0$', '$C=1$'])
We can see $z$ behaves exactly as we want (left figure). What’s nice about it is that the class of points that reside far from the boundary line are predicted using practically only one of the modalities. It means the model learned when to ignore the modality that contains pure unpredictive noise.
Why not to use simple FF (Feed Forward)?¶
If we ignore the data generating process and just look at the data points, clearly there are 4 distinct clusters.
These clusters aren’t linearly separable. While the GMU gives capacity to the model in order to explain this non-linear behaviour, one could just throw another layer to the mixture instead, thus solving the problem with plain feed-forward (FF) network.
The universal approximation theorem states that a feed-forward network with a single hidden layer containing a finite number of neurons, can approximate continuous functions… (Wikipedia)
So indeed, for this contrived example a simple FF will do the job. However, the point in introducing new architectures (GMU in this case) is to introduce inductive bias that allows the training process to take advantage of prior knowledge we have about the problem.
Conclusion¶
For real world problems involving multiple modalities, the authors claim the GMU achieves superior performance. They show cased their approach using the task of identifying a movie genre based on its plot and its poster.
GMU is easy to implement, and it may be worthwhile to keep it in your tool belt in case you need to train a model to use multiple modalities as input. To this end, you can create a sub network for each modality. The sub networks need not be the same – you can for instance use a CNN for a visual modality and LSTM for a textual one. What matters is that each sub network outputs a dense representation of its modality. Then, feed these representations into a GMU block in order to fuse the information into one representation. The fused representation will be fed into another sub network whose output will be the final prediction.
if (!document.getElementById(‘mathjaxscript_pelican_#%@#$@#’)) {
var mathjaxscript = document.createElement(‘script’);
mathjaxscript.id = ‘mathjaxscript_pelican_#%@#$@#’;
mathjaxscript.type=”text/javascript”;
mathjaxscript.src=”//cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS-MML_HTMLorMML”;
mathjaxscript[(window.opera ? “innerHTML” : “text”)] =
“MathJax.Hub.Config({” +
” config: [‘MMLorHTML.js’],” +
” TeX: { extensions: [‘AMSmath.js’,’AMSsymbols.js’,’noErrors.js’,’noUndefined.js’], equationNumbers: { autoNumber: ‘AMS’ } },” +
” jax: [‘input/TeX’,’input/MathML’,’output/HTML-CSS’],” +
” extensions: [‘tex2jax.js’,’mml2jax.js’,’MathMenu.js’,’MathZoom.js’],” +
” displayAlign: ‘center’,” +
” displayIndent: ‘0em’,” +
” showMathMenu: true,” +
” tex2jax: { ” +
” inlineMath: [ [‘$’,’$’] ], ” +
” displayMath: [ [‘$$’,’$$’] ],” +
” processEscapes: true,” +
” preview: ‘TeX’,” +
” }, ” +
” ‘HTML-CSS’: { ” +
” linebreaks: { automatic: true, width: ‘95% container’ }, ” +
” styles: { ‘.MathJax_Display, .MathJax .mo, .MathJax .mi, .MathJax .mn’: {color: ‘black ! important’} }” +
” } ” +
“}); “;
(document.body || document.getElementsByTagName(‘head’)[0]).appendChild(mathjaxscript);
}
{Halo|Hello|Hai}, {para|sobat} {pengemar|pencinta} {slots|slot!} {Pernah|pernahkah} {denger|mendengar} {istilah|semboyan} {“slot gacor”|”slot gaco”|”slot demo”|”raja slot}? {Kalau|jika} {belum|tidak}, {bersiaplah|siap-siap} jatuh {cinta|hati} sama {konsep|program} ini. {slot gacor|slot gaco|slot demo|raja slot} {adalah|merupakan} mesin {slot|slots} yang {sering|selalu} {memberi|kasih} {kemenangan|win}. {Ya|Yup}, {mesin-mesin|slot-slot} ini bisa {dibilang|dikatakan|disebut} {adalah|sebagai} {jagoannya|andalannya} {buat|tuk} {bawa|membawa} {pulang|come back} {hasil.|cuan.} {tapi|any way|but}, {gimana|cemana} sih {caranya|
tekniknya} {jumpain|nemuin} {slot gacor|slot gaco|slot demo|raja lot} yang {tepat|benar}? {Tenang|Santai} {Bro|Bro and Sis}, kita {bahas|beri} {santai|tenang] {aja|saja} {di sini|di tempat ini}
{Permainan|Game|Gaming|Games} {terbaik|terpercaya|tergacor|tergaco|terpopuler} {saat|waktu} {ini|sekarang} {hanya satu|satu-satunya} {berada|di} Indonesia {yaitu|hanya di} {yang|pasti|akan} {memberikan|menyediakan} {imbal hasil|return|ROI|return on Investment} {terbaik|tertinggi|terbesar}