<h2>Why such design decision was made?</h2>

<p>It is indeed a very interesting question. Let's see how this is described in Keras documentation:</p>

<blockquote>
  <p>In the original version of Adadelta you don't have to set an initial learning rate. In this version, initial learning rate and decay factor can be set, as in most other Keras optimizers.</p>
</blockquote>

<p>So the documentations itself admits that this method doesn't need a learning rate. I believe this design decision was made because of some other templates, dependencies, or codes in the project.</p>

<p>More specifically, the philosophy of keras is <strong>you can combine any building blocks you want</strong> (i.e. a unified API). If you remove the parameter <code>lr</code> from this, I believe you won't be able to use some of the <strong>callbacks</strong>.</p>

<hr>

<h2>Comparison</h2>

<p>Now, let's compare the <a href="https://github.com/keras-team/keras/blob/master/keras/optimizers.py#L350" rel="noreferrer">Adadelta implementation</a> of Keras to the <a href="https://arxiv.org/pdf/1212.5701.pdf" rel="noreferrer">original paper</a>:</p>

<ul>
<li><p><a href="https://github.com/keras-team/keras/blob/master/keras/optimizers.py#L406" rel="noreferrer">Line 406:</a> here the gradients are accumulated into a moving average (<code>a</code> is the moving average, <code>rho</code> is decay rate as in the paper, <code>g</code> is computed gradients for parameter <code>p</code>):</p>

<pre class="lang-python prettyprint-override"><code>new_a = self.rho * a + (1. - self.rho) * K.square(g)
self.updates.append(K.update(a, new_a))
</code></pre>

<p>This perfectly corresponds to the following line in the algorithm:</p>

<p><a href="https://i.stack.imgur.com/Qyft7.png" rel="noreferrer"><img src="https://i.stack.imgur.com/Qyft7.png" alt="enter image description here"></a></p></li>
<li><p><a href="https://github.com/keras-team/keras/blob/master/keras/optimizers.py#L410" rel="noreferrer">Line 410:</a> delta calculation (here, <code>d_a</code> is delta accumulator, also in the form of moving average):</p>

<pre class="lang-python prettyprint-override"><code>update = g * K.sqrt(d_a + self.epsilon) / K.sqrt(new_a + self.epsilon)
</code></pre>

<p>This perfectly corresponds to</p>

<p><a href="https://i.stack.imgur.com/5Y8bU.png" rel="noreferrer"><img src="https://i.stack.imgur.com/5Y8bU.png" alt="enter image description here"></a></p></li>
<li><p><a href="https://github.com/keras-team/keras/blob/master/keras/optimizers.py#L411" rel="noreferrer">Line 411:</a> now <strong>here is the tricky part.</strong> The code looks as follows:</p>

<pre class="lang-python prettyprint-override"><code>new_p = p - lr * update
</code></pre>

<p>Which doesn't follows the original algorithm in the paper:</p>

<p><a href="https://i.stack.imgur.com/Rkpo8.png" rel="noreferrer"><img src="https://i.stack.imgur.com/Rkpo8.png" alt="enter image description here"></a></p>

<p>Furthermore, such learning rate admits changes through the learning rate decay parameter. However, the default value of <code>lr</code> in Keras is <code>1.0</code>, and <code>decay</code> is <code>0.0</code> so by default it shouldn't affect the outcome.</p></li>
</ul>
What Is the Learning Rate Parameter in Adadelta Optimiser for in Keras?
<p>In Keras, there is an Adadelta optimiser for SGD as follows:</p>

<pre class="lang-py prettyprint-override"><code>optimizer = optimizers.Adadelta(lr=1.0, rho=0.95, epsilon=None, decay=0.0)
</code></pre>

<p>Here is the doc.: <a href="https://keras.io/optimizers/#adadelta" rel="nofollow noreferrer">https://keras.io/optimizers/#adadelta</a>
But as we know, Adadelta does not use any learning rate. So what is lr for?</p>