Sketch-RNN with pytorch

alexis-jacq: <p>I am implementing the sequence-to-sequence model introduced by <a href="https://arxiv.org/abs/1704.03477">this paper</a> from Google Magenta:</p>
<p>My code is here:<br>
<aside class="onebox whitelistedgeneric">
  <header class="source">
      <img src="https://github.githubassets.com/favicons/favicon.svg" class="site-icon" width="32" height="32">
      <a href="https://github.com/alexis-jacq/Pytorch-Sketch-RNN" target="_blank">GitHub</a>
  </header>
  <article class="onebox-body">
    <img src="https://avatars1.githubusercontent.com/u/9195965?s=400&amp;v=4" class="thumbnail onebox-avatar" width="400" height="400">

<h3><a href="https://github.com/alexis-jacq/Pytorch-Sketch-RNN" target="_blank">alexis-jacq/Pytorch-Sketch-RNN</a></h3>

<p>a pytorch implementation of https://arxiv.org/abs/1704.03477 - alexis-jacq/Pytorch-Sketch-RNN</p>


  </article>
  <div class="onebox-metadata">
    
    
  </div>
  <div style="clear: both"></div>
</aside>
</p>
<p>As I don’t have Google’s power of computation, I changed a bit some hyperparameters of the papers (the number of nodes in the decoder LSTM and the learning rate) and it takes me half a day to run 10.000 epochs. However, according to the default hyperparameters suggested by the <a href="https://github.com/tensorflow/magenta/blob/master/magenta/models/sketch_rnn/model.py">autor’s TF implementation</a>, 512 neurons in decoder LSTM and lr = 0.0001 should be ok to get good results.</p>
<p>But, at least after 40.000 epochs, it still generates random straight strokes and even the reconstruction (giving true inputs from the training set to the decoder) is similar to the drawing but not satisfying. Something must be wrong somewhere… If any of you is interested by state-of-the-art seq2seq drawing generation, I would be glad to receive some help.</p>
<p>I really need to make it work, its for a robotic project (making collaborative child-robot hand-drawing)</p>

alexis-jacq: <p>Good niews !</p>
<p>My implementation was good since the beginning, but I had a terrible and invisible typo in the trajectory generation:</p>
<pre><code class="lang-auto">-        next_state[q_idx+1] = 1
+       next_state[q_idx+2] = 1 
</code></pre>
<p>Now it works properly, and I obtain nice samples of generated cats after short training (this one after 1900 epochs, ~3 epoch/s):<br>
<img src="https://discuss.pytorch.org/uploads/default/original/1X/670d6c2c8cff56c5b4f0325bca9d6cf473c41b12.jpg" width="640" height="480"></p>

smth: <p>man, one tiny typo can change the performance so much <img src="//discuss.pytorch.org/images/emoji/apple/slight_smile.png?v=5" title=":slight_smile:" class="emoji" alt=":slight_smile:"></p>

hardmaru: <p>This is great, I’m happy you were able to port sketch-rnn over to pytorch.</p>
<p>I’d also recommend using LSTM along with <a href="https://arxiv.org/abs/1603.05118" rel="nofollow noopener">Recurrent Dropout without Memory Loss</a>, which involves a one-line change of code in LSTM, and also <a href="https://arxiv.org/abs/1607.06450" rel="nofollow noopener">Layer Normalization</a>. I found these two tricks helped a lot for LSTMs.</p>

alexis-jacq: <p>Thanks a lot !</p>
<p>Yes, using recurrent dropout and layer normalization is on my TODO list. It seems to bet not yet implemented on Pytorch’s RNN modules, I will probably have to do my own.</p>
<p>Today I was busy finding a way to use the network to find and draw cats into clouds (with Canny edge detection):<br>
<img src="https://discuss.pytorch.org/uploads/default/original/1X/8a458a3ebfd835bcb3a4b05e1af95136d4cf8ded.png" width="304" height="222"><div class="lightbox-wrapper"><a class="lightbox" href="https://discuss.pytorch.org/uploads/default/original/1X/f3f09c35f24bcac8d7998616b615c502795b43e5.png" data-download-href="https://discuss.pytorch.org/uploads/default/f3f09c35f24bcac8d7998616b615c502795b43e5" title="chat2.svg.png"><img src="https://discuss.pytorch.org/uploads/default/optimized/1X/f3f09c35f24bcac8d7998616b615c502795b43e5_2_345x248.png" width="345" height="248" srcset="https://discuss.pytorch.org/uploads/default/optimized/1X/f3f09c35f24bcac8d7998616b615c502795b43e5_2_345x248.png, https://discuss.pytorch.org/uploads/default/optimized/1X/f3f09c35f24bcac8d7998616b615c502795b43e5_2_517x372.png 1.5x, https://discuss.pytorch.org/uploads/default/optimized/1X/f3f09c35f24bcac8d7998616b615c502795b43e5_2_690x496.png 2x" data-dominant-color="485793"><div class="meta"><svg class="fa d-icon d-icon-far-image svg-icon" aria-hidden="true"><use href="#far-image"></use></svg><span class="filename">chat2.svg.png</span><span class="informations">844×608 210 KB</span><svg class="fa d-icon d-icon-discourse-expand svg-icon" aria-hidden="true"><use href="#discourse-expand"></use></svg></div></a></div></p>
<p>Finaly, we used a <a href="http://www.rethinkrobotics.com/baxter/">Baxter</a> robot to draw a cat inferred from the head of a <a href="https://www.ald.softbankrobotics.com/en/cool-robots/nao">Nao</a> robot. And this led us to realize this creepy video:</p><div class="youtube-onebox lazy-video-container" data-video-id="KRq3V7Ck1aU" data-video-title="Baxter improvising from Nao's head" data-video-start-time="" data-provider-name="youtube">
  <a href="https://www.youtube.com/watch?v=KRq3V7Ck1aU" target="_blank" rel="noopener">
    <img class="youtube-thumbnail" src="https://img.youtube.com/vi/KRq3V7Ck1aU/maxresdefault.jpg" title="Baxter improvising from Nao's head" width="690" height="388">
  </a>
</div>


hardmaru: <p>These cloudy cats are great! It’s such a creative use of edge detection. I like the clouds more than nao’s head tbh.</p>
<p>Looking forward to see any gallery or work you end up producing!</p>

alexis-jacq: <p>Hahahaha yes, the result with Nao’s head is really ugly, that explains the style of the video!</p>
<p>But the project will be more serious, involving children with handwriting difficulties for creative activities with robots. We will probably obtain beautiful piece of child-robot collaborative arts!</p>

Kibum_Baek: <p>Hi I was looking at your code and I tried to run the cod on Jupyter notebook.</p>
<p>Still it seems to me that it doesn’t operate because at this part</p>
<pre><code class="lang-auto">if __name__=="__main__":
    model = Model()
    for epoch in range(50001):
        model.train(epoch)
</code></pre>
<p>I have an error saying</p>
<pre><code class="lang-auto">epoch 0 loss 2.6120107173919678 LR 2.6110057830810547 LKL 0.0010049500269815326
&lt;ipython-input-17-a948bd699ee2&gt;:36: UserWarning: Implicit dimension choice for softmax has been deprecated. Change the call to include dim=X as an argument.
  pi = F.softmax(pi.transpose(0,1).squeeze()).view(len_out,-1,hp.M)
&lt;ipython-input-17-a948bd699ee2&gt;:42: UserWarning: Implicit dimension choice for softmax has been deprecated. Change the call to include dim=X as an argument.
  q = F.softmax(params_pen).view(len_out,-1,3)
&lt;ipython-input-31-a793444e3f37&gt;:66: UserWarning: torch.nn.utils.clip_grad_norm is now deprecated in favor of torch.nn.utils.clip_grad_norm_.
  nn.utils.clip_grad_norm(self.encoder.parameters(), hp.grad_clip)
&lt;ipython-input-31-a793444e3f37&gt;:67: UserWarning: torch.nn.utils.clip_grad_norm is now deprecated in favor of torch.nn.utils.clip_grad_norm_.
  nn.utils.clip_grad_norm(self.decoder.parameters(), hp.grad_clip)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
&lt;ipython-input-33-1aab3c2e5ccc&gt; in &lt;module&gt;
      2     model = Model()
      3     for epoch in range(50001):
----&gt; 4         model.train(epoch)

&lt;ipython-input-31-a793444e3f37&gt; in train(self, epoch)
     78         if epoch%100==0:
     79             #self.save(epoch)
---&gt; 80             self.conditional_generation(epoch)
     81 
     82     def bivariate_normal_pdf(self, dx, dy):

&lt;ipython-input-31-a793444e3f37&gt; in conditional_generation(self, epoch)
    142             hidden_cell = (hidden, cell)
    143             # sample from parameters:
--&gt; 144             s, dx, dy, pen_down, eos = self.sample_next_state()
    145             #------
    146             seq_x.append(dx)

&lt;ipython-input-31-a793444e3f37&gt; in sample_next_state(self)
    180         sigma_y = self.sigma_y.data[0,0,pi_idx]
    181         rho_xy = self.rho_xy.data[0,0,pi_idx]
--&gt; 182         x,y = sample_bivariate_normal(mu_x,mu_y,sigma_x,sigma_y,rho_xy,greedy=False)
    183         next_state = torch.zeros(5)
    184         next_state[0] = x

&lt;ipython-input-32-7b287d68c95c&gt; in sample_bivariate_normal(mu_x, mu_y, sigma_x, sigma_y, rho_xy, greedy)
      8     cov = [[sigma_x * sigma_x, rho_xy * sigma_x * sigma_y],\
      9         [rho_xy * sigma_x * sigma_y, sigma_y * sigma_y]]
---&gt; 10     x = np.random.multivariate_normal(mean, cov, 1)
     11     return x[0][0], x[0][1]
     12 

mtrand.pyx in numpy.random.mtrand.RandomState.multivariate_normal()

TypeError: ufunc 'add' output (typecode 'O') could not be coerced to provided output parameter (typecode 'd') according to the casting rule ''same_kind''
</code></pre>
<p>Would you mind if you help me out with this?</p>