<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Personal Webpage of Max Horn</title>
    <description>I work as a Applied Scientist for AWS AI where I explore the intersection of Machine Learning, Deep Learning and Causality. In particular, I am interested building models that understand notions of objects present in the real world.&lt;br /&gt;
Prior to my position at AWS I was a PhD Student in Machine Learning and Computational Biology at ETH Zürich and worked on the development of &lt;b&gt;deep learning methods for real world medical time series&lt;/b&gt;, &lt;b&gt;Dimensionality Reduction&lt;/b&gt; and &lt;b&gt;Topological Machine Learning&lt;/b&gt;.&lt;br /&gt;
My interests include but are not limited to: &lt;b&gt;Machine Learning for Healthcare&lt;/b&gt;, &lt;b&gt;Probabilistic Modelling&lt;/b&gt;, &lt;b&gt;Time Series Modelling&lt;/b&gt; and &lt;b&gt;Interpretable Machine Learning&lt;/b&gt;.&lt;br /&gt;
Here I write about stuff I care about in the realm of science, programming, technology and crypto.  All opinions expressed are solely my own and do not express the views or opinions of my employer.
</description>
    <link>https://ExpectationMax.github.io/</link>
    <atom:link href="https://ExpectationMax.github.io/feed.xml" rel="self" type="application/rss+xml" />
    <pubDate>Thu, 05 May 2022 10:28:36 +0000</pubDate>
    <lastBuildDate>Thu, 05 May 2022 10:28:36 +0000</lastBuildDate>
    <generator>Jekyll v3.9.2</generator>
    
      <item>
        <title>NeoVims built-in Language Server Client and why you should use it</title>
        <description>&lt;p&gt;As a fan of the &lt;a href=&quot;https://microsoft.github.io/language-server-protocol/&quot;&gt;Language Server
Protocol&lt;/a&gt; introduced by
Microsoft, I was very excited to hear, that &lt;a href=&quot;https://neovim.io/&quot;&gt;NeoVim&lt;/a&gt; (an
aggressive refactor of the Vim) will soon be shipping it’s own language server
client.&lt;/p&gt;

&lt;p&gt;Here I will show why I like the Language Server Protocol and how to configure
the built-in language server client to make it a bit more user friendly.&lt;/p&gt;

&lt;p&gt;When I first looked into using the NeoVims internal language server, &lt;a href=&quot;https://jdhao.github.io/2019/11/20/neovim_builtin_lsp_hands_on/&quot;&gt;jdhao’s
blog post&lt;/a&gt;
really helped me out – I invite you to check it out as an additional resource.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Table of Contents:&lt;/strong&gt;&lt;/p&gt;
&lt;ul id=&quot;markdown-toc&quot;&gt;
  &lt;li&gt;&lt;a href=&quot;#the-language-server-protocol--whats-all-the-fuss-about&quot; id=&quot;markdown-toc-the-language-server-protocol--whats-all-the-fuss-about&quot;&gt;The Language Server Protocol – What’s all the fuss about&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#neovims-internal-language-server-client&quot; id=&quot;markdown-toc-neovims-internal-language-server-client&quot;&gt;NeoVims internal Language Server Client&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#faster-completion&quot; id=&quot;markdown-toc-faster-completion&quot;&gt;Faster completion&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#getting-more-out-of-the-language-server---diagnostics-and-definitions&quot; id=&quot;markdown-toc-getting-more-out-of-the-language-server---diagnostics-and-definitions&quot;&gt;Getting more out of the language server - Diagnostics and Definitions&lt;/a&gt;    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;#diagnostics&quot; id=&quot;markdown-toc-diagnostics&quot;&gt;Diagnostics&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#definitions&quot; id=&quot;markdown-toc-definitions&quot;&gt;Definitions&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#additional-goodies&quot; id=&quot;markdown-toc-additional-goodies&quot;&gt;Additional goodies&lt;/a&gt;        &lt;ul&gt;
          &lt;li&gt;&lt;a href=&quot;#highlighting-references-to-variable-under-the-cursor&quot; id=&quot;markdown-toc-highlighting-references-to-variable-under-the-cursor&quot;&gt;Highlighting references to variable under the cursor&lt;/a&gt;&lt;/li&gt;
          &lt;li&gt;&lt;a href=&quot;#formatting&quot; id=&quot;markdown-toc-formatting&quot;&gt;Formatting&lt;/a&gt;&lt;/li&gt;
          &lt;li&gt;&lt;a href=&quot;#renaming-variables&quot; id=&quot;markdown-toc-renaming-variables&quot;&gt;Renaming variables&lt;/a&gt;&lt;/li&gt;
          &lt;li&gt;&lt;a href=&quot;#keybindings&quot; id=&quot;markdown-toc-keybindings&quot;&gt;Keybindings&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#summary&quot; id=&quot;markdown-toc-summary&quot;&gt;Summary&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;the-language-server-protocol--whats-all-the-fuss-about&quot;&gt;The Language Server Protocol – What’s all the fuss about&lt;/h2&gt;
&lt;p&gt;In essence the Language Server Protocol seeks to separate the functionality of
an IDE into two components:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;The Language Server, which is programming language specific. It analyzes the
code in the programming language you are using and implements the typical
set of functions an IDE provides such as looking up code completion, looking
up definitions, renaming variables, searching for symbols etc.&lt;/li&gt;
  &lt;li&gt;The Language Server Client, typically a plugin of the editor, which provides
the services of the Language Server to the user.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The Language Server Protocol defines a standardized way for these two
components to interact with each other.  An example of such a communication can
be seen below&lt;sup id=&quot;fnref:language-server-img-src&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:language-server-img-src&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://microsoft.github.io/language-server-protocol/overviews/lsp/img/language-server-sequence.png&quot; alt=&quot;Visualization of the communication between Language Server and Language
Server Client&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The benefit of splitting the services of an IDE into two components becomes
quite apparent: If every Language Server and Language Server Client follow
the specifications, it is only necessary to implement &lt;strong&gt;a single Language
Server per programming language&lt;/strong&gt; and a &lt;strong&gt;single Language Server Client for
each Editor&lt;/strong&gt;.  Thus all editors would benefit as soon as a language server
implements new functionality and the keybindings and additional functionalities
between different programming languages would be more consistent within
a single editor.&lt;/p&gt;

&lt;p&gt;Especially if you use Vim or NeoVim for programming this flexibility with
regard to the programming language is amazing and makes your editor setup more
lightweight (by only requiring the installation of a single plugin), consistent
and flexible with regard to new programming languages.  Simply setup the
language server in your editor and you are good to go!&lt;/p&gt;

&lt;h2 id=&quot;neovims-internal-language-server-client&quot;&gt;NeoVims internal Language Server Client&lt;/h2&gt;

&lt;p&gt;Due to these benefits, there were many implementations of language servers for
vim (such as &lt;a href=&quot;https://github.com/prabirshrestha/vim-lsp&quot;&gt;vim-lsp&lt;/a&gt;,
&lt;a href=&quot;https://github.com/autozimu/LanguageClient-neovim&quot;&gt;LanguageClient-neovim&lt;/a&gt;,
&lt;a href=&quot;https://github.com/natebosch/vim-lsc&quot;&gt;vim-lsc&lt;/a&gt;).  Nevertheless I often
experienced speed issues when using any of the plugins.  Thankfully, NeoVim
announced that they will be shipping a language server client built-in some
time ago.  It is not yet in the stable release but requires installing the
developer branch of NeoVim.  If you use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;brew&lt;/code&gt; this can for example be done
using the command &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;brew install neovim --HEAD&lt;/code&gt;, which will install the most
recent version of NeoVim directly from the git repository.&lt;/p&gt;

&lt;p&gt;Additionally, there is a lua-based plugin
&lt;a href=&quot;https://github.com/neovim/nvim-lspconfig&quot;&gt;nvim-lspconfig&lt;/a&gt; which provides
routines to integrate a diverse set of language servers.  It’s installation is
dependent on your plugin manager, for
&lt;a href=&quot;https://github.com/junegunn/vim-plug&quot;&gt;vim-plug&lt;/a&gt; it is installed by adding
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Plug 'neovim/nvim-lspconfig'&lt;/code&gt; to your NeoVim config.&lt;/p&gt;

&lt;p&gt;Afterwards, you can configure your language server using one of the
preconfigured profiles. For example, if you program in Python you first need to
install the python language server&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;pip &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'python-language-server[all]'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;and then add the configuration&lt;/p&gt;
&lt;div class=&quot;language-vimscript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;lua&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; EOF
require&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'nvim_lsp'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;pyls&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;setup&lt;span class=&quot;p&quot;&gt;({})&lt;/span&gt;
EOF
autocmd Filetype &lt;span class=&quot;k&quot;&gt;python&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;setlocal&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;omnifunc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;lua&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;vim&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;lsp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;omnifunc&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;which executes the line between the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;EOF&lt;/code&gt; statements as lua code. This is
required as we are configuring a plugin written in lua.  We need
to configure vim to actually use the Language Server Client for providing
completions. This is done in the last line of the snippet by setting
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;omnifunc&lt;/code&gt;, which allows us to trigger completion using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;C-x&amp;gt;&amp;lt;C-o&amp;gt;&lt;/code&gt;.  While
this works, it is by far not optimal, as the completion calls take place
synchronously, at the end of the article I will give some pointers on how to
improve the experience by using completion managers.&lt;/p&gt;

&lt;h2 id=&quot;faster-completion&quot;&gt;Faster completion&lt;/h2&gt;
&lt;p&gt;To my knowledge there are currently two completion managers which support the
NeoVims built-in Language Server Client: &lt;a href=&quot;https://github.com/ncm2/ncm2&quot;&gt;NCM2&lt;/a&gt;
and &lt;a href=&quot;https://github.com/nvim-lua/completion-nvim&quot;&gt;completion-nvim&lt;/a&gt; where the
first is written largely in python and the second is written in lua.  When
I first tested &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;completion-nvim&lt;/code&gt; I ran into some issues which was probably due
to the freshness of the project this can be a different story now.
Nevertheless, I will here show how to set up &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NCM2&lt;/code&gt; as this is what I went for
in the end.&lt;/p&gt;

&lt;p&gt;First you need to of course install and enable &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NCM2&lt;/code&gt; for Plug this can be done
using the following commands&lt;/p&gt;

&lt;div class=&quot;language-vimscript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;call&lt;/span&gt; plug#begin&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'~/.vim/plugged'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;&quot; Installing ncm2 with Plug&lt;/span&gt;
Plug &lt;span class=&quot;s1&quot;&gt;'ncm2/ncm2'&lt;/span&gt;
Plug &lt;span class=&quot;s1&quot;&gt;'roxma/nvim-yarp'&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;call&lt;/span&gt; plug#end&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

autocmd &lt;span class=&quot;nb&quot;&gt;BufEnter&lt;/span&gt; * &lt;span class=&quot;k&quot;&gt;call&lt;/span&gt; ncm2#enable_for_buffer&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;where the last line activates the completion manager for every buffer you
enter.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NCM2&lt;/code&gt; has support for the NeoVim built-in Language Server Client (see this
&lt;a href=&quot;https://github.com/ncm2/ncm2/pull/178&quot;&gt;pull request&lt;/a&gt;), but it does
not yet seem to be well documented.  The support can be activated by adding
a callback to the language server setup routine we called previously&lt;/p&gt;

&lt;div class=&quot;language-vimscript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;&quot; Setup language server client&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;lua&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; EOF
require&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'nvim_lsp'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;pyls&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;setup&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
    on_init &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; require&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'ncm2'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;register_lsp_source&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;;
EOF
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;getting-more-out-of-the-language-server---diagnostics-and-definitions&quot;&gt;Getting more out of the language server - Diagnostics and Definitions&lt;/h2&gt;
&lt;p&gt;While this gives us some basic functionality, the Language Server is capable of
doing much more! In the next section I will be concentrating on looking up
definitions of functions/variables and displaying diagnostics. In the end
I will give indications on some further useful functions. For a full list of
features and details on how to use them in NeoVim please consider the &lt;a href=&quot;https://neovim.io/doc/user/lsp.html&quot;&gt;NeoVim
Language Server Client documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;diagnostics&quot;&gt;Diagnostics&lt;/h3&gt;
&lt;p&gt;In particular I found the default setting of publishing diagnostic information
as virtual text at the end of the line rather annoying.  When I program
I prefer to only see the code and not some additional text indicating that this
function is missing a docstring etc. Changing the behaviour of NeoVims internal
Language Server Client can be done by modifying the callbacks it triggers when
it gets information from the Language Server.  The default callbacks are defined
&lt;a href=&quot;https://github.com/neovim/neovim/blob/master/runtime/lua/vim/lsp/callbacks.lua&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The callback of our interest is
&lt;a href=&quot;https://github.com/neovim/neovim/blob/ca7449db46062098cc9b0c84401655cba7d3a53f/runtime/lua/vim/lsp/callbacks.lua#L76&quot;&gt;“textDocument/publishDiagnostics”&lt;/a&gt;.
Here we simply want to remove the line
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;util.buf_diagnostics_virtual_text(bufnr, result.diagnostics)&lt;/code&gt; which adds the
virtual text annotations.  We can patch this by adding the following lua code
to our config (i.e. if you add this in your vim config you should surround it
with a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lua &amp;lt;&amp;lt; EOF&lt;/code&gt; / &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;EOF&lt;/code&gt; block, I left this out for the sake of correct
syntax highlighting)&lt;/p&gt;

&lt;div class=&quot;language-lua highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;--- Evtl. add `lua &amp;lt;&amp;lt; EOF` here&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;--- Define our own callbacks&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;local&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;util&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'vim.lsp.util'&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;local&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;vim&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;vim&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;local&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;api&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;vim&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;api&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;local&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'vim.lsp.buf'&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;vim&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lsp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;callbacks&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'textDocument/publishDiagnostics'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;local&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;uri&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;uri&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;local&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bufnr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;vim&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;uri_to_bufnr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;uri&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bufnr&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;err_message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;LSP.publishDiagnostics: Couldn't find buffer for &quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;uri&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;-- https://microsoft.github.io/language-server-protocol/specifications/specification-current/#diagnostic&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;-- The diagnostic's severity. Can be omitted. If omitted it is up to the&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;-- client to interpret diagnostics as error, warning, info or hint.&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;-- TODO: Replace this with server-specific heuristics to infer severity.&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;diagnostic&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;ipairs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;diagnostics&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;diagnostic&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;severity&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;diagnostic&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;severity&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;protocol&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;DiagnosticSeverity&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Error&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;util&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;buf_clear_diagnostics&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bufnr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;-- Always save the diagnostics, even if the buf is not loaded.&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;-- Language servers may report compile or build errors via diagnostics&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;-- Users should be able to find these, even if they're in files which&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;-- are not loaded.&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;util&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;buf_diagnostics_save_positions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bufnr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;diagnostics&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;-- Unloaded buffers should not handle diagnostics.&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;--    When the buffer is loaded, we'll call on_attach, which sends textDocument/didOpen.&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;--    This should trigger another publish of the diagnostics.&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;--&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;-- In particular, this stops a ton of spam when first starting a server for current&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;-- unloaded buffers.&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;api&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;nvim_buf_is_loaded&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bufnr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;util&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;buf_diagnostics_underline&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bufnr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;diagnostics&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;-- util.buf_diagnostics_virtual_text(bufnr, result.diagnostics)&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;util&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;buf_diagnostics_signs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bufnr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;diagnostics&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;vim&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;api&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;nvim_command&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;doautocmd User LspDiagnosticsChanged&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;--- Evtl. add `EOF` here&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Which does exactly the same as the original callback but comments out the line
(&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--&lt;/code&gt; is a comment in lua) that we mentioned before.&lt;/p&gt;

&lt;p&gt;In order to now see diagnostic information when placing the cursor on a line
with an error we can call the function &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;vim.lsp.util.show_line_diagnostics()&lt;/code&gt;
after some hover time using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;autocmd&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;language-vimscript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;autocmd &lt;span class=&quot;nb&quot;&gt;CursorHold&lt;/span&gt;  &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;buffer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;lua&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;vim&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;lsp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;util&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;show_line_diagnostics&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Additionally, we probably want to set the colors used to indicate a error or
warning to fit to the color scheme we using.  This can be done by defining the
appropriate highlight groups&lt;/p&gt;

&lt;div class=&quot;language-vimscript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;&quot; Highlighting applied to floating window&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;highlight&lt;/span&gt; LspDiagnosticsErrorFloating guifg&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;#fb4934&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;gui&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;NONE&lt;/span&gt; ctermfg&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;NONE&lt;/span&gt; ctermbg&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;NONE&lt;/span&gt; cterm&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;NONE&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;highlight&lt;/span&gt; LspDiagnosticsWarningFloating guifg&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;#fabd2f&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;gui&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;NONE&lt;/span&gt; ctermfg&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;NONE&lt;/span&gt; ctermbg&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;NONE&lt;/span&gt; cterm&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;NONE&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;highlight&lt;/span&gt; LspDiagnosticsInfoFloating guifg&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;#83a598&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;gui&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;NONE&lt;/span&gt; ctermfg&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;NONE&lt;/span&gt; ctermbg&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;NONE&lt;/span&gt; cterm&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;NONE&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;&quot; Highlighting applied to code&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;highlight&lt;/span&gt; LspDiagnosticsUnderlineError guifg&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;NONE&lt;/span&gt; guibg&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;NONE&lt;/span&gt; guisp&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;#fb4934&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;gui&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;undercurl ctermfg&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;NONE&lt;/span&gt; ctermbg&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;NONE&lt;/span&gt; cterm&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;undercurl
&lt;span class=&quot;nb&quot;&gt;highlight&lt;/span&gt; LspDiagnosticsUnderlineWarning guifg&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;NONE&lt;/span&gt; guibg&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;NONE&lt;/span&gt; guisp&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;#fabd2f&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;gui&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;undercurl ctermfg&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;NONE&lt;/span&gt; ctermbg&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;NONE&lt;/span&gt; cterm&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;undercurl
&lt;span class=&quot;nb&quot;&gt;highlight&lt;/span&gt; LspDiagnosticsUnderlineInfo guifg&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;NONE&lt;/span&gt; guibg&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;NONE&lt;/span&gt; guisp&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;#83a598&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;gui&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;undercurl ctermfg&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;NONE&lt;/span&gt; ctermbg&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;NONE&lt;/span&gt; cterm&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;undercurl
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The values above are set to match the &lt;a href=&quot;https://github.com/lifepillar/vim-gruvbox8&quot;&gt;gruvbox
8 color scheme&lt;/a&gt; and a terminal
supporting true color. They can be adapted to your personal
taste&lt;sup id=&quot;fnref:vim-highlighting&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:vim-highlighting&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;.  If you want them to change dependent on your
color scheme you should check out the vim predefines highlight groups (see
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;:help highligh-groups&lt;/code&gt;) and map accordingly using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;highlight link&lt;/code&gt;.  You
should keep in mind to set these after setting your color scheme though
otherwise you might run into problems.&lt;/p&gt;

&lt;h3 id=&quot;definitions&quot;&gt;Definitions&lt;/h3&gt;

&lt;p&gt;One of the best features of vim in my opinion is the tagstack (if you don’t
know about it, check out &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;:help tagstack&lt;/code&gt; and get your mind blown away ;) ).
The tagstack allows you to do what you need to do when doing programming:
&lt;em&gt;Understanding what the function you are calling does under the hood.&lt;/em&gt;  It
enables jumping to the definitions of functions, variables etc. and when you
got your information to jump back to where you came from.  The Language Server
Client allows you to jump to the definition of an object using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;:lua
vim.lsp.buf.definition()&lt;/code&gt; and we could just manually map this to the key
combination &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;C-]&amp;gt;&lt;/code&gt; which is used to jump to a tag.  Yet this would discard all
the other fancy combinations that are already defined for the tagstack such as
jump to definition in new window/in a preview window etc.  Thus the more
wholistic approach would be to override the tagstack functionality using
a custom &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tagfunc&lt;/code&gt;. I found a &lt;a href=&quot;https://daisuzu.hatenablog.com/entry/2019/12/06/005543&quot;&gt;single
reference&lt;/a&gt; on the
Japanese internet where somebody does exactly this. I adopted the code slightly
to work with the NeoVim internal Language Server Client&lt;sup id=&quot;fnref:additional-reference&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:additional-reference&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;3&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;div class=&quot;language-lua highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;local&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lsp&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'vim.lsp'&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;local&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;util&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'vim.lsp.util'&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;local&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;log&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'vim.lsp.log'&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;local&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;vim&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;vim&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;-- Ref (in Japanese): https://daisuzu.hatenablog.com/entry/2019/12/06/005543&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;-- Ref: https://qrunch.net/@igrep/entries/K6sUDofcmvtnRqzk&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;tagfunc_nvim_lsp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pattern&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;flags&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;info&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
 &lt;span class=&quot;kd&quot;&gt;local&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{}&lt;/span&gt;
 &lt;span class=&quot;kd&quot;&gt;local&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;isSearchingFromNormalMode&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;flags&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;c&quot;&lt;/span&gt;

 &lt;span class=&quot;kd&quot;&gt;local&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;method&lt;/span&gt;
 &lt;span class=&quot;kd&quot;&gt;local&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;params&lt;/span&gt;
 &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;isSearchingFromNormalMode&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then&lt;/span&gt;
   &lt;span class=&quot;c1&quot;&gt;-- Jump to the definition of the symbol under the cursor&lt;/span&gt;
   &lt;span class=&quot;c1&quot;&gt;-- when called by CTRL-]&lt;/span&gt;
   &lt;span class=&quot;n&quot;&gt;method&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'textDocument/definition'&lt;/span&gt;
   &lt;span class=&quot;n&quot;&gt;params&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;util&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;make_position_params&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
 &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
   &lt;span class=&quot;c1&quot;&gt;-- NOTE: Currently I'm not sure how this clause is tested&lt;/span&gt;
   &lt;span class=&quot;c1&quot;&gt;--       because `:tag` command doesn't seem to use `tagfunc`.&lt;/span&gt;

   &lt;span class=&quot;c1&quot;&gt;-- Search with `pattern` when called by ex command (e.g. `:tag`)&lt;/span&gt;
   &lt;span class=&quot;n&quot;&gt;method&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'workspace/symbol'&lt;/span&gt;

   &lt;span class=&quot;c1&quot;&gt;-- Delete &quot;\&amp;lt;&quot; from `pattern` when prepended.&lt;/span&gt;
   &lt;span class=&quot;c1&quot;&gt;-- Perhaps the server doesn't support regex in vim!&lt;/span&gt;
   &lt;span class=&quot;n&quot;&gt;params&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{}&lt;/span&gt;
   &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;string.find&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;flags&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'i'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then&lt;/span&gt;
     &lt;span class=&quot;n&quot;&gt;params&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;query&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;string.sub&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pattern&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'^\\&amp;lt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;''&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
   &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
     &lt;span class=&quot;n&quot;&gt;params&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;query&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pattern&lt;/span&gt;
   &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
 &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
 &lt;span class=&quot;kd&quot;&gt;local&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;client_id_to_results&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lsp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;buf_request_sync&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;method&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;params&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;800&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
 &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then&lt;/span&gt;
   &lt;span class=&quot;nb&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'Error when calling tagfunc: '&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;..&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
   &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;result&lt;/span&gt;
 &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

 &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_client_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;results&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;pairs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;client_id_to_results&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
   &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lsp_result&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;ipairs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;results&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
     &lt;span class=&quot;kd&quot;&gt;local&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;
     &lt;span class=&quot;kd&quot;&gt;local&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;location&lt;/span&gt;
     &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;isSearchingFromNormalMode&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then&lt;/span&gt;
       &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pattern&lt;/span&gt;
       &lt;span class=&quot;n&quot;&gt;location&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lsp_result&lt;/span&gt;
     &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
       &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lsp_result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;
       &lt;span class=&quot;n&quot;&gt;location&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lsp_result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;location&lt;/span&gt;
     &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
     &lt;span class=&quot;kd&quot;&gt;local&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;location_for_tagfunc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
       &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
       &lt;span class=&quot;n&quot;&gt;filename&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;vim&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;uri_to_fname&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;location&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;uri&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
       &lt;span class=&quot;n&quot;&gt;cmd&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;tostring&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;location&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;range&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;start&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;line&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
     &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
     &lt;span class=&quot;nb&quot;&gt;table.insert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;location_for_tagfunc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
 &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
 &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
 &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;result&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Be aware that &lt;strong&gt;the above code is written in lua&lt;/strong&gt; thus it must either be
integrated using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lua &amp;lt;&amp;lt; EOF&lt;/code&gt; trick or saved in a separate file under
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/.config/nvim/lua&lt;/code&gt; and loaded prior to usage. In my case I save the above
code under &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/.config/nvim/lua/tagfunc_nvim_lsp.lua&lt;/code&gt; and load it in vim using&lt;/p&gt;
&lt;div class=&quot;language-vimscript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;lua&lt;/span&gt; require &lt;span class=&quot;s1&quot;&gt;'tagfunc_nvim_lsp'&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;setlocal&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;tagfunc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;lua&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;tagfunc_nvim_lsp
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;additional-goodies&quot;&gt;Additional goodies&lt;/h3&gt;

&lt;h4 id=&quot;highlighting-references-to-variable-under-the-cursor&quot;&gt;Highlighting references to variable under the cursor&lt;/h4&gt;
&lt;div class=&quot;language-vimscript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;autocmd &lt;span class=&quot;nb&quot;&gt;CursorHold&lt;/span&gt;  &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;buffer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;lua&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;vim&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;lsp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;buf&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;document_highlight&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
autocmd &lt;span class=&quot;nb&quot;&gt;CursorHoldI&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;buffer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;lua&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;vim&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;lsp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;buf&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;document_highlight&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
autocmd &lt;span class=&quot;nb&quot;&gt;CursorMoved&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;buffer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;lua&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;vim&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;lsp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;buf&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;clear_references&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;&quot; References to the same variable&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;highlight&lt;/span&gt; LspReference guifg&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;NONE&lt;/span&gt; guibg&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;#665c54&lt;/span&gt; guisp&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;NONE&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;gui&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;NONE&lt;/span&gt; cterm&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;NONE&lt;/span&gt; ctermfg&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;NONE&lt;/span&gt; ctermbg&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;59&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;highlight&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;!&lt;/span&gt; link LspReferenceText LspReference
&lt;span class=&quot;nb&quot;&gt;highlight&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;!&lt;/span&gt; link LspReferenceRead LspReference
&lt;span class=&quot;nb&quot;&gt;highlight&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;!&lt;/span&gt; link LspReferenceWrite LspReference
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 id=&quot;formatting&quot;&gt;Formatting&lt;/h4&gt;
&lt;p&gt;The below snippet implements formatting the file when triggering a write to
disk.  It needed some additional fixes to prevent the cursor position from
being lost after the reformat&lt;sup id=&quot;fnref:preserve-cursor-position&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:preserve-cursor-position&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;4&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;div class=&quot;language-vimscript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;!&lt;/span&gt; Preserve&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;command&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;try&lt;/span&gt;
        &lt;span class=&quot;c&quot;&gt;&quot; Preparation: save last search, and cursor position.&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;win_view &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;winsaveview&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;old_query &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;getreg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'/'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;silent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;!&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;execute&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'keepjumps '&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;a:command&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;finally&lt;/span&gt;
        &lt;span class=&quot;c&quot;&gt;&quot; try restore / reg and cursor position&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;call&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;winrestview&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;win_view&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;call&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;setreg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'/'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;old_query&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;endtry&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;endfunction&lt;/span&gt;

autocmd &lt;span class=&quot;nb&quot;&gt;BufWritePre&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;buffer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;call&lt;/span&gt; Preserve&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'lua vim.lsp.buf.formatting_sync(nil, 1000)'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 id=&quot;renaming-variables&quot;&gt;Renaming variables&lt;/h4&gt;
&lt;p&gt;The below snippet allows you to rename the variable under the cursor:&lt;/p&gt;
&lt;div class=&quot;language-vimscript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;!&lt;/span&gt; LspRename&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;call&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;inputsave&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;newname &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'Rename to: '&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;call&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;inputrestore&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;call&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;luaeval&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'vim.lsp.buf.rename(&quot;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;newname&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'&quot;)'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;endfunction&lt;/span&gt;

nnoremap &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;buffer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;leader&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;lr&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;cmd&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;call&lt;/span&gt; LspRename&lt;span class=&quot;p&quot;&gt;()&amp;lt;&lt;/span&gt;CR&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 id=&quot;keybindings&quot;&gt;Keybindings&lt;/h4&gt;
&lt;p&gt;In my vim config I wrapped a lot of the above functionality together into
a function called SetupLsp which I then call dependent on the input file type.&lt;/p&gt;
&lt;div class=&quot;language-vimscript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; SetupLsp&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    nnoremap &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;silent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;buffer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;gd&lt;/span&gt;    &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;cmd&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;lua&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;vim&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;lsp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;buf&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;declaration&lt;span class=&quot;p&quot;&gt;()&amp;lt;&lt;/span&gt;CR&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
    nnoremap &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;silent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;buffer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; K  &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;cmd&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;lua&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;vim&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;lsp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;buf&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;hover&lt;span class=&quot;p&quot;&gt;()&amp;lt;&lt;/span&gt;CR&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
    nnoremap &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;silent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;buffer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;cmd&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;lua&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;vim&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;lsp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;buf&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;signature_help&lt;span class=&quot;p&quot;&gt;()&amp;lt;&lt;/span&gt;CR&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
    inoremap &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;silent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;buffer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;cmd&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;lua&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;vim&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;lsp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;buf&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;signature_help&lt;span class=&quot;p&quot;&gt;()&amp;lt;&lt;/span&gt;CR&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
    nnoremap &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;silent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;buffer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;leader&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;ls&lt;/span&gt;    &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;cmd&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;lua&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;vim&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;lsp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;buf&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;document_symbol&lt;span class=&quot;p&quot;&gt;()&amp;lt;&lt;/span&gt;CR&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
    nnoremap &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;silent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;buffer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; gW    &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;cmd&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;lua&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;vim&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;lsp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;buf&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;workspace_symbol&lt;span class=&quot;p&quot;&gt;()&amp;lt;&lt;/span&gt;CR&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
    nnoremap &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;buffer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;leader&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;lr&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;cmd&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;call&lt;/span&gt; LspRename&lt;span class=&quot;p&quot;&gt;()&amp;lt;&lt;/span&gt;CR&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
    autocmd &lt;span class=&quot;nb&quot;&gt;CursorHold&lt;/span&gt;  &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;buffer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;lua&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;vim&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;lsp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;buf&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;document_highlight&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    autocmd &lt;span class=&quot;nb&quot;&gt;CursorHold&lt;/span&gt;  &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;buffer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;lua&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;vim&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;lsp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;util&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;show_line_diagnostics&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    autocmd &lt;span class=&quot;nb&quot;&gt;CursorHoldI&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;buffer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;lua&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;vim&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;lsp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;buf&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;document_highlight&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    autocmd &lt;span class=&quot;nb&quot;&gt;CursorMoved&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;buffer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;lua&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;vim&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;lsp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;buf&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;clear_references&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    autocmd &lt;span class=&quot;nb&quot;&gt;BufWritePre&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;buffer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;call&lt;/span&gt; Preserve&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'lua vim.lsp.buf.formatting_sync(nil, 1000)'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;lua&lt;/span&gt; require &lt;span class=&quot;s1&quot;&gt;'tagfunc_nvim_lsp'&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;setlocal&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;tagfunc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;lua&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;tagfunc_nvim_lsp
    &lt;span class=&quot;k&quot;&gt;setlocal&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;signcolumn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;yes
&lt;span class=&quot;k&quot;&gt;endfunction&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; SetupPython&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;setlocal&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;colorcolumn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;80&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;setlocal&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;tw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;79&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;setlocal&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;spell&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;setlocal&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;tabstop&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;4&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;shiftwidth&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;4&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;expandtab&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;call&lt;/span&gt; SetupLsp&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;endfunction&lt;/span&gt;

autocmd Filetype &lt;span class=&quot;k&quot;&gt;python&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;call&lt;/span&gt; SetupPython&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;/h2&gt;
&lt;p&gt;I hope you found the above pointers and snippets helpful.  For me switching to
the built-in language server client gave a huge jump in performance and
responsiveness of my favorite editor :).  Let me know if you have any comments,
suggestions or issues!&lt;/p&gt;

&lt;p&gt;See you next time!&lt;/p&gt;

&lt;div class=&quot;footnotes&quot; role=&quot;doc-endnotes&quot;&gt;
  &lt;ol&gt;
    &lt;li id=&quot;fn:language-server-img-src&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;The visualization is taken form the language server protocol documentation available &lt;a href=&quot;https://microsoft.github.io/language-server-protocol/overviews/lsp/overview/&quot;&gt;here&lt;/a&gt;. &lt;a href=&quot;#fnref:language-server-img-src&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:vim-highlighting&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;Check out &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;:help highlight-cterm&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;:help highlight-gui&lt;/code&gt; for the available settings. &lt;a href=&quot;#fnref:vim-highlighting&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:additional-reference&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;There was a further reference on the path to accomplishing this &lt;a href=&quot;https://daisuzu.hatenablog.com/entry/2019/12/06/005543&quot;&gt;here&lt;/a&gt; yet the webpage seems down now. &lt;a href=&quot;#fnref:additional-reference&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:preserve-cursor-position&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;For further information see &lt;a href=&quot;https://vi.stackexchange.com/questions/7761/how-to-restore-the-position-of-the-cursor-after-executing-a-normal-command&quot;&gt;this stackexchange discussion&lt;/a&gt;, from which the command originated. &lt;a href=&quot;#fnref:preserve-cursor-position&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;
</description>
        <pubDate>Sat, 31 Oct 2020 00:00:00 +0000</pubDate>
        <link>https://ExpectationMax.github.io/2020/NeoVims-Language-Server-Client/</link>
        <guid isPermaLink="true">https://ExpectationMax.github.io/2020/NeoVims-Language-Server-Client/</guid>
        
        <category>development</category>
        
        
        <category>development</category>
        
      </item>
    
      <item>
        <title>Two of our papers were accepted at ICML 2020</title>
        <description>&lt;p&gt;This week we presented two of our papers at ICML 2020, it was a great
experience to talk with others about our research and to think of future
directions and applications of our methods.  I want to use this page to point
out reference materials for these publications.&lt;/p&gt;

&lt;h2 id=&quot;set-functions-for-time-series&quot;&gt;Set Functions for Time Series&lt;/h2&gt;

&lt;p&gt;“Set Functions for Time Series” is work done together with &lt;a href=&quot;https://michaelmoor.ml/&quot;&gt;Michael
Moor&lt;/a&gt;, &lt;a href=&quot;https://christian.bock.ml&quot;&gt;Christian Bock&lt;/a&gt;, &lt;a href=&quot;https://bastian.rieck.me/&quot;&gt;Bastian
Rieck&lt;/a&gt; and my PhD Advisor Karsten Borgwardt.&lt;/p&gt;

&lt;p&gt;In the core we propose to rephrase learning on irregularly sampled time series
data as a set classification problem. This mitigates the necessity of imputing
time series prior to the application of Deep Learning models and allows their
direct application.  Michael Larionov wrote a nice summary of our paper
&lt;a href=&quot;https://towardsdatascience.com/set-attention-models-for-time-series-classification-c09360a60349&quot;&gt;on towards data science&lt;/a&gt;
where he explains the core components of the model.&lt;/p&gt;

&lt;p&gt;For further details please see the links below:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Paper:&lt;/strong&gt;
&lt;a href=&quot;https://proceedings.icml.cc/static/paper_files/icml/2020/4750-Paper.pdf&quot;&gt;ICML 2020&lt;/a&gt;,
&lt;a href=&quot;https://arxiv.org/abs/1909.12064&quot;&gt;arXiv&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Talk:&lt;/strong&gt;
&lt;a href=&quot;https://icml.cc/virtual/2020/poster/6545&quot;&gt;ICML 2020&lt;/a&gt;, &lt;a href=&quot;/assets/2020-07-16-ICML-SeFT-TopoAE/SeFT-slides.pdf&quot;&gt;Slides&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Code:&lt;/strong&gt;
&lt;a href=&quot;https://github.com/BorgwardtLab/Set_Functions_for_Time_Series&quot;&gt;Models&lt;/a&gt;, &lt;a href=&quot;https://github.com/ExpectationMax/medical_ts_datasets&quot;&gt;Datasets&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;topological-autoencoders&quot;&gt;Topological Autoencoders&lt;/h2&gt;
&lt;p&gt;The work “Topological Autoencoders” was joint work with my colleagues &lt;a href=&quot;https://michaelmoor.ml/&quot;&gt;Michael
Moor&lt;/a&gt; and &lt;a href=&quot;https://bastian.rieck.me/&quot;&gt;Bastian Rieck&lt;/a&gt;
and my PhD Advisor Karsten Borgwardt.&lt;/p&gt;

&lt;p&gt;&lt;img alt=&quot;Training visualization Topological Autoencoder&quot; src=&quot;/assets/2020-07-16-ICML-SeFT-TopoAE/topoae.gif&quot; width=&quot;49%&quot; /&gt;&lt;img alt=&quot;Training visualization Vanilla Autoencoder&quot; src=&quot;/assets/2020-07-16-ICML-SeFT-TopoAE/vanilla.gif&quot; width=&quot;49%&quot; /&gt;&lt;/p&gt;

&lt;p&gt;In this work we propose to constrain the topology of the  latent representation
of an autoencoder using methods from topological data analysis.
Michael wrote a wonderful blog post about the paper giving an intuitive
introduction &lt;a href=&quot;https://michaelmoor.ml/blog/topoae/main/&quot;&gt;here&lt;/a&gt;.
Below you can see our devised approach in
action compared to a vanilla autoencoder.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Paper:&lt;/strong&gt;
&lt;a href=&quot;https://proceedings.icml.cc/static/paper_files/icml/2020/613-Paper.pdf&quot;&gt;ICML 2020&lt;/a&gt;,
&lt;a href=&quot;https://arxiv.org/abs/1906.00722&quot;&gt;arXiv&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Talk:&lt;/strong&gt;
&lt;a href=&quot;https://icml.cc/virtual/2020/poster/5851&quot;&gt;ICML 2020&lt;/a&gt;, &lt;a href=&quot;/assets/2020-07-16-ICML-SeFT-TopoAE/TopoAE-slides.pdf&quot;&gt;Slides&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Code:&lt;/strong&gt; &lt;a href=&quot;https://github.com/BorgwardtLab/topological-autoencoders&quot;&gt;GitHub&lt;/a&gt;&lt;/p&gt;

</description>
        <pubDate>Fri, 17 Jul 2020 00:00:00 +0000</pubDate>
        <link>https://ExpectationMax.github.io/2020/ICML-Presentation/</link>
        <guid isPermaLink="true">https://ExpectationMax.github.io/2020/ICML-Presentation/</guid>
        
        <category>conferences</category>
        
        <category>publications</category>
        
        
        <category>summaries</category>
        
        <category>papers</category>
        
      </item>
    
      <item>
        <title>MLSS2020 Causality Lectures - a brief summary</title>
        <description>&lt;p&gt;The first week of the virtual Machine Learning Summer School in Tübingen is over
and it is time to take a brief look back at the lessons learned and the
experience made during this time. In the following I will briefly some of the
insights I made during the first week.&lt;/p&gt;

&lt;h2 id=&quot;causality-and-causal-inference-lectures&quot;&gt;Causality and Causal Inference lectures&lt;/h2&gt;
&lt;p&gt;The Causality lectures were held by &lt;a href=&quot;https://www.is.mpg.de/~bs&quot;&gt;Bernhard
Schölkopf&lt;/a&gt; and &lt;a href=&quot;https://www.is.mpg.de/person/sbauer&quot;&gt;Stefan
Bauer&lt;/a&gt;. As a heads up, I am most definitely
not an expert in this field and I am solely summarizing the most interesting
points according to my personal opinion :).&lt;/p&gt;

&lt;h3 id=&quot;causality-i&quot;&gt;Causality I&lt;/h3&gt;
&lt;p&gt;The first lecture by Prof. B. Schölkopf was a more general introduction to
causality, the required terms needed to understand the literature, how to
infer causal structure in smaller scale experiments with stochastic or
deterministic relationships between observations and finally the implications
of causality to semi-supervised learning.&lt;/p&gt;

&lt;p&gt;Here I found the work on deriving causality for deterministic cases of
particular interest (see &lt;a href=&quot;https://arxiv.org/abs/1203.3475&quot;&gt;this&lt;/a&gt; paper).  In
this work, the authors use an assumption termed the &lt;em&gt;independence of input and
mechanism&lt;/em&gt; to derive a causal inference rule which does not require any
assumptions on noise. The assumption states, that $ p(C) $ (the probability
distribution of the cause) and $p(E|C)$ (the probability distribution of the
effect conditional on the cause) should be independent. This implies, that the
distribution of the effect would then in some way be dependent on the function
$f$ mapping from cause to effect and thus $Cov(log f’, p_C) = 0$ (encoding
the independence assumption) and $Cov(log f^{-1’}, p_E) &amp;gt; 0$ (encoding the
dependence between the function mapping from cause to effect and the
distribution of the effect). This leads to the inference rule that
$X \rightarrow Y$ if  $\int \log | f’(x) | p(x) dx \leq \int \log | f^{-1}(y)|
p(y) dy $. This can also be computed using empirical estimators for the
slope of the function mapping between X and Y.&lt;/p&gt;

&lt;p&gt;Finally, B. Schölkopf presented implications of causality in the domain of
semi-supervised learning. In particular, if &lt;em&gt;independence of input and
mechanism&lt;/em&gt; is true, he shows that semi-supervised learning can theoretically not
benefit learning in the causal direction. In other words when a model is trying
to infer effect from cause (thus $p(E|C)$), additional data from the cause
distribution $p(C)$ will not help the model learn due to $ p(C) $ being
independent of $ p(E|C) $. In contrast, if learning is in the anti-causal
direction, semi-supervised learning can be beneficial.&lt;/p&gt;

&lt;h3 id=&quot;causality-ii&quot;&gt;Causality II&lt;/h3&gt;
&lt;p&gt;The second talk by Stefan Bauer focused on how to infer Structural Causal
Models and how causality can be integrated with Deep Learning approaches.&lt;/p&gt;

&lt;p&gt;In the first part of his talk, Stefan showed bridges between causal inference
and non-linear ICA and further shows that there will always be both a causal as
well as anti-causal linear model if additive Gaussian noise is assumed.
Afterwards, Stefan talks about time series models and how ODEs are perfect
models for causal structure in the presence of time.&lt;/p&gt;

&lt;p&gt;In the second half, the topic switches to describing a causal perspective on
representation learning. Here the bridges between disentangles representations
and causality become evident. This is due to the assumption, that a change in
distribution of the data would arise from a sparse change in causal
conditionals or causal mechanisms, thus leading to similar properties as
desired in disentangled representations.  Nevertheless, recent research shows
that disentangled representations cannot be learned in a completely
unsupervised way (see &lt;a href=&quot;https://arxiv.org/abs/1811.12359&quot;&gt;Locatello et al, ICML
2019&lt;/a&gt;), also leading to potential issues with
the discovery of causal mechanisms.  There is some hope though, as few labels
seem to help with determining correct disentangled representations (see
&lt;a href=&quot;https://arxiv.org/abs/2002.02886&quot;&gt;Locatello et al., ICML 2020&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Finally, Stefan talks about some exciting work on encoding causal structure
into machine learning architectures.  Here a decoder is designed to resemble
the structure of a general Structural Causal Model and trained to match the
observations of the training data.  These &lt;em&gt;Structural Causal Autoencoders&lt;/em&gt; (see
&lt;a href=&quot;https://arxiv.org/abs/2006.07796&quot;&gt;Leeb et al., under review NeurIPS 2020&lt;/a&gt;)
were shown to yield good performance in learning representations for generating
images and transferring between similar tasks.&lt;/p&gt;

&lt;p&gt;All in all some very exciting directions. I am looking forward to seeing the
future development of Causality and Machine Learning.&lt;/p&gt;
</description>
        <pubDate>Fri, 05 Jun 2020 00:00:00 +0000</pubDate>
        <link>https://ExpectationMax.github.io/2020/First-week-MLSS/</link>
        <guid isPermaLink="true">https://ExpectationMax.github.io/2020/First-week-MLSS/</guid>
        
        <category>conferences</category>
        
        
        <category>summaries</category>
        
        <category>MLSS2020</category>
        
      </item>
    
      <item>
        <title>Summary of Talks and Posters from ICLR 2020</title>
        <description>&lt;p&gt;This years ICLR was was special for me (and for many others as well) as it was
the first virtual conference I have ever attended to (and will given the
current situation with COVID-19 surely not be the last). At the virtual ICLR,
posters were replaced with short prerecorded videos of 5 minutes where the
authors briefly present their work.  These videos can be accessed at any time
independent of the “poster session” in which was possible to talk to one or
more authors of the paper.  One benefit of the conference being completely
virtual is definitely that it allows to spread out looking at the “posters”
over a longer time (if willing to sacrifice the possibility to talk with the
author in a virtual poster session).&lt;/p&gt;

&lt;p&gt;Overall, I found this format very appealing, as it allows to get a quick
perspective into the work and also allows to look at many works without getting
overwhelmed as the presentations are usually kept at a high level. For more
detailed information it is always possible to pull up the paper.&lt;/p&gt;

&lt;p&gt;A few weeks after the virtual conference is over I finally managed to summarize
some of the papers and posters I looked at, and thought I might as well share
it with the people who could be interested. You can find a subset of the papers
I selected for reading accompanied with a sometimes more, sometimes less
detailed summary below.  I must say that I am still not completely finished
with all the papers I marked and thus might update this page at a later time.&lt;/p&gt;

&lt;h2 id=&quot;table-of-contents&quot;&gt;Table of Contents&lt;/h2&gt;
&lt;ul id=&quot;markdown-toc&quot;&gt;
  &lt;li&gt;&lt;a href=&quot;#table-of-contents&quot; id=&quot;markdown-toc-table-of-contents&quot;&gt;Table of Contents&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#anomaly-detection&quot; id=&quot;markdown-toc-anomaly-detection&quot;&gt;Anomaly Detection&lt;/a&gt;    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;#deep-semi-supervised-anomaly-detection&quot; id=&quot;markdown-toc-deep-semi-supervised-anomaly-detection&quot;&gt;Deep Semi-Supervised Anomaly Detection&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#input-complexity-and-out-of-distribution-detection-with-likelihood-based-generative-models&quot; id=&quot;markdown-toc-input-complexity-and-out-of-distribution-detection-with-likelihood-based-generative-models&quot;&gt;Input Complexity and Out-of-distribution Detection with Likelihood-based Generative Models&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#generative-models&quot; id=&quot;markdown-toc-generative-models&quot;&gt;Generative Models&lt;/a&gt;    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;#understanding-the-limitations-of-conditional-generative-models&quot; id=&quot;markdown-toc-understanding-the-limitations-of-conditional-generative-models&quot;&gt;Understanding the Limitations of Conditional Generative Models&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#your-classifier-is-secretly-an-energy-based-model-and-you-should-treat-it-like-one&quot; id=&quot;markdown-toc-your-classifier-is-secretly-an-energy-based-model-and-you-should-treat-it-like-one&quot;&gt;Your classifier is secretly an energy based model and you should treat it like one&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#gradient-estimation&quot; id=&quot;markdown-toc-gradient-estimation&quot;&gt;Gradient Estimation&lt;/a&gt;    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;#estimating-gradients-for-discrete-random-variables-by-sampling-without-replacement&quot; id=&quot;markdown-toc-estimating-gradients-for-discrete-random-variables-by-sampling-without-replacement&quot;&gt;Estimating Gradients for Discrete Random Variables by Sampling without Replacement&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#sumo-unbiased-estimation-of-log-marginal-probability-for-latent-variable-models&quot; id=&quot;markdown-toc-sumo-unbiased-estimation-of-log-marginal-probability-for-latent-variable-models&quot;&gt;SUMO: Unbiased Estimation of Log Marginal Probability for Latent Variable Models&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#pooling-and-set-functions&quot; id=&quot;markdown-toc-pooling-and-set-functions&quot;&gt;Pooling and Set Functions&lt;/a&gt;    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;#fspool-learning-set-representations-with-featurewise-sort-pooling&quot; id=&quot;markdown-toc-fspool-learning-set-representations-with-featurewise-sort-pooling&quot;&gt;FSPool: Learning Set Representations with Featurewise Sort Pooling&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#on-universal-equivariant-set-networks&quot; id=&quot;markdown-toc-on-universal-equivariant-set-networks&quot;&gt;On Universal Equivariant Set Networks&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#structpool-structured-graph-pooling-via-conditional-random-fields&quot; id=&quot;markdown-toc-structpool-structured-graph-pooling-via-conditional-random-fields&quot;&gt;StructPool: Structured Graph Pooling via Conditional Random Fields&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#representation-learning&quot; id=&quot;markdown-toc-representation-learning&quot;&gt;Representation Learning&lt;/a&gt;    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;#disentanglement-by-nonlinear-ica-with-general-incompressible-flow-networks-gin&quot; id=&quot;markdown-toc-disentanglement-by-nonlinear-ica-with-general-incompressible-flow-networks-gin&quot;&gt;Disentanglement by Nonlinear ICA with General Incompressible-flow Networks (GIN)&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#infograph-unsupervised-and-semi-supervised-graph-level-representation-learning-via-mutual-information-maximization&quot; id=&quot;markdown-toc-infograph-unsupervised-and-semi-supervised-graph-level-representation-learning-via-mutual-information-maximization&quot;&gt;InfoGraph: Unsupervised and Semi-supervised Graph-Level Representation Learning via Mutual Information Maximization&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#mutual-information-gradient-estimation-for-representation-learning&quot; id=&quot;markdown-toc-mutual-information-gradient-estimation-for-representation-learning&quot;&gt;Mutual Information Gradient Estimation for Representation Learning&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#on-mutual-information-maximization-for-representation-learning&quot; id=&quot;markdown-toc-on-mutual-information-maximization-for-representation-learning&quot;&gt;On Mutual Information Maximization for Representation Learning&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#seq2seq-models&quot; id=&quot;markdown-toc-seq2seq-models&quot;&gt;Seq2Seq models&lt;/a&gt;    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;#are-transformers-universal-approximators-of-sequence-to-sequence-functions&quot; id=&quot;markdown-toc-are-transformers-universal-approximators-of-sequence-to-sequence-functions&quot;&gt;Are Transformers universal approximators of sequence-to-sequence functions?&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#mogrifier-lstm&quot; id=&quot;markdown-toc-mogrifier-lstm&quot;&gt;Mogrifier LSTM&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#reformer-the-efficient-transformer&quot; id=&quot;markdown-toc-reformer-the-efficient-transformer&quot;&gt;Reformer: The Efficient Transformer&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#understanding-deep-learning&quot; id=&quot;markdown-toc-understanding-deep-learning&quot;&gt;Understanding Deep Learning&lt;/a&gt;    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;#four-things-everyone-should-know-to-improve-batch-normalization&quot; id=&quot;markdown-toc-four-things-everyone-should-know-to-improve-batch-normalization&quot;&gt;Four Things Everyone Should Know to Improve Batch Normalization&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#on-the-variance-of-the-adaptive-learning-rate-and-beyond&quot; id=&quot;markdown-toc-on-the-variance-of-the-adaptive-learning-rate-and-beyond&quot;&gt;On the Variance of the Adaptive Learning Rate and Beyond&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#the-implicit-bias-of-depth-how-incremental-learning-drives-generalization&quot; id=&quot;markdown-toc-the-implicit-bias-of-depth-how-incremental-learning-drives-generalization&quot;&gt;The Implicit Bias of Depth: How Incremental Learning Drives Generalization&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#towards-neural-networks-that-provably-know-when-they-dont-know&quot; id=&quot;markdown-toc-towards-neural-networks-that-provably-know-when-they-dont-know&quot;&gt;Towards neural networks that provably know when they don’t know&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#truth-or-backpropaganda-an-empirical-investigation-of-deep-learning-theory&quot; id=&quot;markdown-toc-truth-or-backpropaganda-an-empirical-investigation-of-deep-learning-theory&quot;&gt;Truth or backpropaganda? An empirical investigation of deep learning theory&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#what-graph-neural-networks-cannot-learn-depth-vs-width&quot; id=&quot;markdown-toc-what-graph-neural-networks-cannot-learn-depth-vs-width&quot;&gt;What graph neural networks cannot learn: depth vs width&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#why-gradient-clipping-accelerates-training-a-theoretical-justification-for-adaptivity&quot; id=&quot;markdown-toc-why-gradient-clipping-accelerates-training-a-theoretical-justification-for-adaptivity&quot;&gt;Why Gradient Clipping Accelerates Training: A Theoretical Justification for Adaptivity&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#other---normalizing-flows-robustness-meta-learning-probabilistic-modelling&quot; id=&quot;markdown-toc-other---normalizing-flows-robustness-meta-learning-probabilistic-modelling&quot;&gt;Other - Normalizing Flows, Robustness, Meta-Learning, Probabilistic Modelling&lt;/a&gt;    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;#invertible-models-and-normalizing-flows&quot; id=&quot;markdown-toc-invertible-models-and-normalizing-flows&quot;&gt;Invertible Models and Normalizing Flows&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#learning-to-balance-bayesian-meta-learning-for-imbalanced-and-out-of-distribution-tasks&quot; id=&quot;markdown-toc-learning-to-balance-bayesian-meta-learning-for-imbalanced-and-out-of-distribution-tasks&quot;&gt;Learning to Balance: Bayesian Meta-Learning for Imbalanced and Out-of-distribution Tasks&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#meta-dropout-learning-to-perturb-latent-features-for-generalization&quot; id=&quot;markdown-toc-meta-dropout-learning-to-perturb-latent-features-for-generalization&quot;&gt;Meta Dropout: Learning to Perturb Latent Features for Generalization&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#on-robustness-of-neural-ordinary-differential-equations&quot; id=&quot;markdown-toc-on-robustness-of-neural-ordinary-differential-equations&quot;&gt;On Robustness of Neural Ordinary Differential Equations&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#why-not-to-use-zero-imputation-correcting-sparsity-bias-in-training-neural-networks&quot; id=&quot;markdown-toc-why-not-to-use-zero-imputation-correcting-sparsity-bias-in-training-neural-networks&quot;&gt;Why Not to Use Zero Imputation? Correcting Sparsity Bias in Training Neural Networks&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;anomaly-detection&quot;&gt;Anomaly Detection&lt;/h2&gt;
&lt;h3 id=&quot;deep-semi-supervised-anomaly-detection&quot;&gt;&lt;a href=&quot;https://iclr.cc/virtual/poster_HkgH0TEYwH.html&quot;&gt;Deep Semi-Supervised Anomaly Detection&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Anomaly detection in the Semi-supervised setting: Additional labels samples
to leverage expert knowledge&lt;/p&gt;

&lt;p&gt;Goal: Improve decision boundary using the labeled data.&lt;/p&gt;

&lt;p&gt;A supervised classifier usually performs bad on unseen samples. Unsupervised
approaches cannot use the labels examples to improve.&lt;/p&gt;

&lt;p&gt;Suggest the Deep SAD method with is an extension of the Deep SVDD method.
The SAD method is unsupervised and tries to map examples (non-anomalies)
into a as compact as possible hypersphere.&lt;/p&gt;

&lt;p&gt;(I wonder how this is different to maximum
likelihood training of a simple generative models such as a flow? In the end
we simply penalize the distance from the mode. Of course this approach does
not penalize contraction / stretching of the space such that it can map all
examples to a very small volume).&lt;/p&gt;

&lt;p&gt;The SVDD approach tries to minimize the following objective:&lt;/p&gt;

\[\frac{1}{n} \sum_{i=1}^n || \phi(X_i; \theta) - c ||^2\]

&lt;p&gt;and the authors of this paper suggest including an additional term which
penalizes anomalous samples from being close to the center of the sphere.
The objective then becomes:&lt;/p&gt;

\[\frac{1}{n+m} \sum_{i=1}^n || \phi(X_i; \theta) - c ||^2 + \frac{\eta}{n+m} \sum_{j=1}^m(|| \phi(X_i; \theta) - c ||^2 )^{y_j}; \eta &amp;gt; 0\]

&lt;p&gt;where $y_j=1$ for normal samples and $y_j=-1$ for anomalies.&lt;/p&gt;

&lt;p&gt;Makes perfect sense. Additionally, the authors benchmark their method and
present an information-theoretic framework for deep anomaly detection in
their paper.&lt;/p&gt;

&lt;h3 id=&quot;input-complexity-and-out-of-distribution-detection-with-likelihood-based-generative-models&quot;&gt;&lt;a href=&quot;https://iclr.cc/virtual/poster_SyxIWpVYvr.html&quot;&gt;Input Complexity and Out-of-distribution Detection with Likelihood-based Generative Models&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Obvious strategy of generative models for detecting OOD samples (train model
on data, label low likelihood samples as OOD) does not work. Often the out
of distribution samples actually have significantly higher likelihood than
the training distribution.&lt;/p&gt;

&lt;p&gt;Intuition of paper: The input complexity of the dataset images influences
the likelihood.&lt;/p&gt;

&lt;p&gt;Analyse normalized size of image after being compressed with lossless
compression which serves as a proxy for the Kolmogorov complexity.
&lt;em&gt;Complexity of image seems to correlate with the likelihood (more complex,
less likely).&lt;/em&gt; Most variance is explained by this.&lt;/p&gt;

&lt;p&gt;Suggest to correct the likelihood by subtracting the complexity estimate of
the image, and show that this can be interpreted as a likelihood ratio test
statistic giving links to Bayesian model comparison, minimum description
length and Occams razor.&lt;/p&gt;

&lt;p&gt;Results indicate higher performance compared to many out of distribution
detection methods. The only method based on generative modelling which out
performs the approach is WAIC which relies on ensembles of generative models
and thus is sufficiently more costly to optimize.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Input complexity is the main culprit for out of distribution detection and
proxies of input complexity can be used to to design corrected scores.&lt;/em&gt;&lt;/p&gt;

&lt;h2 id=&quot;generative-models&quot;&gt;Generative Models&lt;/h2&gt;
&lt;h3 id=&quot;understanding-the-limitations-of-conditional-generative-models&quot;&gt;&lt;a href=&quot;https://iclr.cc/virtual/poster_r1lPleBFvH.html&quot;&gt;Understanding the Limitations of Conditional Generative Models&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Main problem of conditional generative models: &lt;em&gt;Not robust&lt;/em&gt;, do not
recognise out of distribution samples.&lt;/p&gt;

&lt;p&gt;Ideally, in a good generative model undetected (high density) adversarial
attacks should have a low volume.
Problem: Even if adversarial attacks are close to this low volume set the
close area itself would again be large due to the curse of dimensionality.
The theory of the paper suggests that one can always construct such
a adversarial attack such that it would not be detected (?, have to check on
this in the paper).&lt;/p&gt;

&lt;p&gt;Results: MNIST model is robust, CIFAR model to detect.
–&amp;gt; Interpolated examples (in data space) on CIFAR have higher likelihood
    than the samples themselves
Explanation: Classification and Generation are very different things.
Classification only cares for very few aspects of the data, while generation
tries to model every single aspect of the data.&lt;/p&gt;

&lt;p&gt;The authors suggest that the class-unrelated entropy (background, nascence
variables) in CIFAR is the reason for these models failing. Demonstrate this
with new dataset where MNIST digits are on CIFAR background and thus
increasing the class-unrelated entropy. Then MNIST also fails similarly to
CIFAR in the previous example.&lt;/p&gt;

&lt;p&gt;Authors argue that much of the problem comes from the standard likelihood
objective which tries to model everything, while for classification one only
cares about selected bits of the data.&lt;/p&gt;

&lt;h3 id=&quot;your-classifier-is-secretly-an-energy-based-model-and-you-should-treat-it-like-one&quot;&gt;&lt;a href=&quot;https://iclr.cc/virtual/poster_Hkxzx0NtDB.html&quot;&gt;Your classifier is secretly an energy based model and you should treat it like one&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Criticism: Progress in generative models driven by Likelihood and sample
quality. Not by downstream tasks such as:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Out of Distribution detection&lt;/li&gt;
  &lt;li&gt;Robust classifications&lt;/li&gt;
  &lt;li&gt;semi-supervised learning
In practice, the generative model based solutions on these tasks usually lag
behind compared to engineered solutions. &lt;em&gt;Why?&lt;/em&gt;&lt;/li&gt;
  &lt;li&gt;Not flexible enough?&lt;/li&gt;
  &lt;li&gt;Architecture only good for generation not classification etc.&lt;/li&gt;
  &lt;li&gt;Additional modelling constraints are making models worse for
discrimination (such as invertibility for flows)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Alternative: Use energy based models!&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Very flexible! We only need a energy function&lt;/li&gt;
  &lt;li&gt;But we cannot easily compute the normalizing constant which leads to
some problems with regard to sampling and training&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;How to train?&lt;/em&gt;
While log likelihood does not have a nice form, the gradient of log p can be
written quite simply:&lt;/p&gt;

\[\frac{\partial p_{\theta}(x)}{\partial \theta} =
     E_{p_{\theta}(x')} [ \partial E_{\theta}(x) / \partial \theta ]
     -  \partial E_{\theta}(x) / \partial \theta\]

&lt;p&gt;where the last term is evaluated on the data and the first uses samples from
the model (which is also tricky, usually done using MCMC).&lt;/p&gt;

&lt;p&gt;Contribution:&lt;br /&gt;
Take classifier models and instead of using softmax define
a energy based model using the inputs before the softmax. Where the energy
is the negative output of the class indexed preactivations:
$E_{\theta}(x, y) = -f_{\theta}(x)[y]$
This EBM can be trained and later used to predict the class using basic
rules of probability, which simply results in a softmax. Further we can sum
$y$ out to which also results in a EBM of the form:
$E_{\theta}(x) = - LogSumExp_y(f(x)[y])$, which is a purely generative model.
&lt;img src=&quot;/assets/2020-05-19-ICLR-2020/clf_is_ebm_summary.png&quot; alt=&quot;Overview figure&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;What to do with this insight? - Experiments&lt;/em&gt;&lt;br /&gt;
Train factorized distribution to ensure unbiased training of classifier:
$p(x) + p(y|z)$ as it does not require sampling from the joint distribution
which could be biased. (This is actually reflected in the results, which
show poor performance when the distribution is factored). Nevertheless, this
hybrid model is the only one which yields comparable classification
performance to STOA. Further, JEM improves calibration of the models
significantly compared to baseline approaches. Also the JEM model is
better at recognizing out of distribution samples and adversarial examples.
This is done using a trick where they seed the MCMC chain at the position of
the adversarial sample and execute a few MCMC steps with respect to the learned
data distribution, further improving adversarial robustness significantly.&lt;/p&gt;

&lt;p&gt;Nevertheless, training is still very unstable due to MCMC sampling. Learning
is also hard to diagnose as there is no clear loss definition.&lt;/p&gt;

&lt;h2 id=&quot;gradient-estimation&quot;&gt;Gradient Estimation&lt;/h2&gt;
&lt;h3 id=&quot;estimating-gradients-for-discrete-random-variables-by-sampling-without-replacement&quot;&gt;&lt;a href=&quot;https://iclr.cc/virtual/poster_rklEj2EFvB.html&quot;&gt;Estimating Gradients for Discrete Random Variables by Sampling without Replacement&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Discrete variables do not allow the computation of a gradient which is
needed for gradient based optimization. This problem is usually mitigated by
one of two approaches:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Relaxation of the discrete distribution to a continuous distribution (+
evtl. sampling) such as Gumbel-Softmax or Concrete methods. These
unfortunately usually have a high bias.&lt;/li&gt;
  &lt;li&gt;Sampling and deriving stochastic gradients usually based on REINFORCE.
REINFORCE gradients usually have high variance.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Authors say that REINFORCE is basically a “trick” for pulling the gradient
operation inside the expectation:&lt;/p&gt;

\[\begin{aligned}
\nabla_\theta E_{p_\theta(x)}[f(x)] &amp;amp;= E_{p_\theta(x)} [ \nabla_\theta \log p_\theta(x) f(x) ] \\\\
&amp;amp;\approx \nabla_\theta p_\theta (x) f(x) \\\\
&amp;amp;\approx \frac{1}{k} \sum_{i=1}^k  \nabla_\theta p_\theta (x_i) f(x_i)
\end{aligned}\]

&lt;p&gt;Further, one can use the average of the other samples in order to reduce the
variance of the estimate (REINFORCE with baseline, Mnih &amp;amp; Rezende 2016):&lt;/p&gt;

\[\nabla_\theta E_{p_\theta(x)}[f(x)] \approx \frac{1}{k} \sum_{i=1}^k  \nabla_\theta p_\theta (x_i)
\left( f(x_i) - \frac{\sum_{j \neq i} f(x_j)}{k - 1} \right)\]

&lt;p&gt;In contrast to previous work the authors &lt;em&gt;suggest to sample without
replacement&lt;/em&gt;, as duplicate samples are uninformative in a deterministic
setting. This leads to a sequence of ordered samples drawn from the distribution
such that&lt;/p&gt;

\[p(B) = p(b_1) \times \frac{p(b_2)}{1-p(b_1)} \times \frac{p(b_3)}{1 - p(b_2) - p(b_3)}\]

&lt;p&gt;In their paper, they derive a generic estimator for $E[f(x)]$ by
Rao-Blackwellizing the crude single sample estimator (which is based on
a single Monte Carlo sample). They call this estimator the unordered set
estimator:&lt;/p&gt;

\[E_{p_\theta(x)}[f(x)] = E_{p_\theta(S^k)}[e^{US}(S^k)] = E_{p_\theta(S^k)} \left[\sum_{s \in S^k} p(s) R(S^k, s) f(s)\right]\]

&lt;p&gt;where $R(S^l, s) = \frac{p^{D \setminus { s } } (S^k \setminus { s } )}{p(S^k)}$
is the &lt;em&gt;leave-one-out ratio&lt;/em&gt; and $S^k$ is an unordered sample without replacement.
They then apply REINFORCE to the derived estimator for the computation of
gradients which gives rise to the unordered set policy gradient estimator:&lt;/p&gt;

\[\begin{aligned}
&amp;amp; E_{p_\theta(x) [ \nabla_\theta \log p_\theta (s) f(x) ] \\\\
&amp;amp;= E_{p_\theta(S) [ e^{USPG}(S^k)] \\\\
&amp;amp;= E_{p_\theta(S) \[ \sum_{s \in S^k} p_\theta(s) R(S^l, s) \nabla_\theta \log p_\theta(s) f(s) \] \\\\
&amp;amp;= E_{p_\theta(S) \[ \sum_{s \in S^k} R(S^l, s) \nabla_\theta p_\theta(s) f(s)\]
\end{aligned}\]

&lt;p&gt;where the last step can be derived using the log derivative trick.&lt;/p&gt;

&lt;p&gt;Further, the authors use an approach similar to Mnih &amp;amp; Rezende (2016) in
order to reduce the variance by subtracting a baseline based on the other
samples. This is not entirely trivial though, as the samples are not
independent and thus a correction needs to be applied.&lt;/p&gt;

&lt;p&gt;Experiments:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Synthetic example: Shows lowest gradient variance compared to all other
methods&lt;/li&gt;
  &lt;li&gt;Policy for travelling salesman problem: Comparable to biased approaches
and out-performs all unbiased approaches&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The devised estimator is a low variance unbiased estimator which can be used
as a replacement to Gumbel-Softmax.&lt;/p&gt;

&lt;h3 id=&quot;sumo-unbiased-estimation-of-log-marginal-probability-for-latent-variable-models&quot;&gt;&lt;a href=&quot;https://iclr.cc/virtual/poster_SylkYeHtwr.html&quot;&gt;SUMO: Unbiased Estimation of Log Marginal Probability for Latent Variable Models&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Suggest a new gradient estimator for marginal probabilities.&lt;/p&gt;

&lt;p&gt;Maximum likelihood estimation for Latent Variable Models (LVM) requires
unbiased estimates of $\nabla_\theta \log p_\theta(x)$ which are not
directly available. Instead research has focused on developing lower bounds
for the log marginal probability $\log p_\theta(x)$ such as the ELBO or IWAE
and to optimize the model parameters with respect to this lower bound.&lt;/p&gt;

&lt;p&gt;The approach devised in this paper is composed of two components:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;Importance weighted bounds (IWAE): Here the idea is to use multiple
samples, instead of a single sample as suggested with the ELBO. This
results in an increasing tighter bound on the true marginal
log-likelihood, such that&lt;/p&gt;

\[\begin{gather}
ELBO \leq E[IWAE_1(x)] \leq E[IWAE_2(x)] \leq \dots \leq \log p_\theta(x) \\\\
\log p_\theta(x) = \lim_{K \rightarrow \inf} E[IWAE_K(x)]
\end{gather}\]

    &lt;p&gt;where $K$ denotes the number of samples used to compute the lower bound.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Russian roulette estimators: Estimator used to compute the value of an
infinite series&lt;/p&gt;

\[\sum^\inf_{k=1} \Delta_k = E_{K \sim p(K)} \left[ \sum^K_{k=1} \frac{\Delta_k}{P(\mathcal{K} \geq k)} \right]\]

    &lt;p&gt;which basically weighs each term in by the probability of sampling
a larger k. This is true is the series converges absolutely s.th.
$\sum_{k=1}^\inf |\Delta_k| \lt \inf$.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The authors suggest SUMO (Stochastically Unbiased Marginalization
Objective), by combining the IWAE lower bound with the Russian Roulette
estimator:&lt;/p&gt;

\[\begin{gather}
\Delta_k (x) = IWAE_{k+1}(x) - IWAE_k(x) \\\\
SUMO(x) = IWAE_1(x) + \sum^K_{k=1} \frac{\Delta_k (x)}{P(\mathcal{K} \leq k)}
\end{gather}\]

&lt;p&gt;where $K \sim p(K)$. This objective is unbiased, such that
$E[SUMO(X)] = \log p_\theta(x)$, and under some conditions (that the
gradient of SUMO is bounded and differentiable everywhere) that
$E[\nabla_\theta SUMO(x)] = \nabla_\theta E[SUMO(x)] = \log p_\theta (x)$.
Deciding on $p(K)$ determines the variance of the estimator and the compute
cost.&lt;/p&gt;

&lt;p&gt;Applications:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Minimizing $\log p_\theta (x)$, which occurs in reverse-KL objectives&lt;/li&gt;
  &lt;li&gt;As an unbiased score function for examples in HMC and REINFORCE gradient
estimation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Results: Better test NLL, more stable in entropy maximization&lt;/p&gt;

&lt;h2 id=&quot;pooling-and-set-functions&quot;&gt;Pooling and Set Functions&lt;/h2&gt;
&lt;h3 id=&quot;fspool-learning-set-representations-with-featurewise-sort-pooling&quot;&gt;&lt;a href=&quot;https://iclr.cc/virtual/poster_HJgBA2VYwH.html&quot;&gt;FSPool: Learning Set Representations with Featurewise Sort Pooling&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Discuss architectures for computing deep set representations.&lt;/p&gt;

&lt;p&gt;Issue of &lt;em&gt;Jump discontinuity&lt;/em&gt;: When we are rotating the input set elements
and compute the representation of a set and decode it into a set again,
there comes a point where the decoded set element jumps back by one
position, such that it is again in the same position (the visualization in
their talk is quite good and easier to understand than my explanation here).&lt;/p&gt;

&lt;p&gt;With very many points the network would simply give up and just predict
a constant output although the input is being rotated.&lt;/p&gt;

&lt;p&gt;Suggest FSPool:&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;Sort inputs (which is ok as it is a set)&lt;/li&gt;
  &lt;li&gt;Multiply with a set of learned weights. As these are not always the same
size, the weights are interpreted as a piecewise linear function between
0 and 1, and the values used for the dot product are evaluated on an
evenly spaced grid between 0 and 1 such that the correct number of
weights for any size of input can be obtained.&lt;/li&gt;
  &lt;li&gt;This is done for each feature individually. (Which seems to result in
loss of information regarding the joint distribution?)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This helps to mitigate the issue with jump discontinuity for set
autoencoders as the learnt permutation can simply be inverted in the decoder
such that no jumpy needs to occur and the output would always correspond to
the matching input. This then also removes the necessity of matching input
and output elements.&lt;/p&gt;

&lt;h3 id=&quot;on-universal-equivariant-set-networks&quot;&gt;&lt;a href=&quot;https://iclr.cc/virtual/poster_HkxTwkrKDB.html&quot;&gt;On Universal Equivariant Set Networks&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Regarding approximation power of deep equivariant networks.&lt;/p&gt;

&lt;p&gt;DeepSets:&lt;/p&gt;

\[X \mapsto XA + \mathbf{1}\mathbf{1}^\top XB + 1 c^\top\]

&lt;p&gt;Authors call $X \mapsto \mathbf{1}\mathbf{1}^\top XB$ a linear transmitting
layer. Further they note that setting $B=0$ for all layers results in
a model which simply applies an MLP on each row of X, and refer to it as
PointNet.&lt;/p&gt;

&lt;p&gt;Authors derive the requirements for universal approximation of equivariant
functions on the unit cube. This is not the case for PointNet, as it cannot approximate the simple function $x \mapsto 1^\top x 1$.&lt;/p&gt;

&lt;p&gt;Main theorem: PointNet is not equivariant universal, but PointNet with
single linear transmitting layer is. In particular the DeepSets model is
equivariant universal.&lt;/p&gt;

&lt;p&gt;Proof:&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;Stone-Weierstrass, any continuous equivariant function can be
approximated by equivariant polynomial on the unit cube&lt;/li&gt;
  &lt;li&gt;Construct model with linear transmitting layer that approximates any
permutation equivariant polynomial&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The suggested model consists of two PointNets, and a single linear
transmitting layer.&lt;/p&gt;

&lt;h3 id=&quot;structpool-structured-graph-pooling-via-conditional-random-fields&quot;&gt;&lt;a href=&quot;https://iclr.cc/virtual/poster_BJxg_hVtwH.html&quot;&gt;StructPool: Structured Graph Pooling via Conditional Random Fields&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Why is graph pooling challenging? This is no locality information in a graph
as the number of neighboring nodes is not fixed. (slightly confused by this
statement, are neighbors not the definition of locality ?)&lt;/p&gt;

&lt;p&gt;Until now there are two pooling approaches:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Selection of important nodes via node sampling, could loose node
information if a node is not selected.&lt;/li&gt;
  &lt;li&gt;Graph pooling via clustering, cluster nodes together which represent then
represent a new node in the next iteration&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Other work DiffPool: Suggests to use a GCN to predict an assignment matrix
which defines which nodes are merged. This only uses the node features and
does not incorporate structural information.&lt;/p&gt;

&lt;p&gt;The authors suggest StructPool: Where the pooling depends on the node
features and the high-order structural relationship in the graph. They
formulate the assignment problem as a conditional random field where the
goal is to minimize the Gibbs Energy. Basically, they add another pairwise
energy term (derived from an attention mechanism) which looks at pairs of
nodes which are within l-hop distance from each other which create an
additional pairwise energy to the unary energy of the conditional random
field. The two energies are combined and then used the compute the
assignment matrix using the softmax operation.&lt;/p&gt;

&lt;p&gt;The proposed method shows improvement over other pooling techniques on D&amp;amp;D,
COLLAB Proteins IMDB-B and IMDB-M whereas it has slightly lower performance
on Enzymes.&lt;/p&gt;

&lt;h2 id=&quot;representation-learning&quot;&gt;Representation Learning&lt;/h2&gt;
&lt;h3 id=&quot;disentanglement-by-nonlinear-ica-with-general-incompressible-flow-networks-gin&quot;&gt;&lt;a href=&quot;https://iclr.cc/virtual/poster_rygeHgSFDH.html&quot;&gt;Disentanglement by Nonlinear ICA with General Incompressible-flow Networks (GIN)&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Non-linear ICA theory: Can recover non-linear projections of conditionally
independent distributions (in latent space) in the data space. This requires
the conditionally independent distributions to belong to the exponential
family. Given some additional requirements, the theory implies that the
sufficient statistics of the true generating latent space are a linear
transformation of the recovered sufficient statistics in the latent space.&lt;/p&gt;

&lt;p&gt;For disentanglement exactly one variable of the reconstructed latent space
should be associated with one in the true latent space. This is equivalent
to requiring sparsity in the transformation matrix.&lt;/p&gt;

&lt;p&gt;Authors show that this is given for Gaussian latent spaces and claim that
additional latent dimensions in the recovered latent space will solely
encode noise. This gives rise to simultaneous disentanglement and
dimensionality discovery mechanism.&lt;/p&gt;

&lt;p&gt;They suggest a method based on volume preserving flows (which are thus
incompressible). This is implemented based on RealNVP, where the
(pre-exponentiated) scale of the last component is set to the negative of
the sum of all previous components, enforcing the same volume. The authors
argue, that this constraint makes the standard deviation in the latent space
remain meaningful, as variability can only be shifted between dimensions but
not increased.&lt;/p&gt;

&lt;p&gt;They show that the spectrum of standard deviations shows multiple regimes
corresponding to global, local and noise on EMNIST to support this claim.&lt;/p&gt;

&lt;p&gt;Experiments on artificial data show that the proposed approach recovers the
true latent space if distributions sufficiently overlap. Further they find
very convincing latent dimensions for EMNIST (more realistic that anything
I have seem to date).&lt;/p&gt;

&lt;h3 id=&quot;infograph-unsupervised-and-semi-supervised-graph-level-representation-learning-via-mutual-information-maximization&quot;&gt;&lt;a href=&quot;https://iclr.cc/virtual/poster_r1lfF2NYvH.html&quot;&gt;InfoGraph: Unsupervised and Semi-supervised Graph-Level Representation Learning via Mutual Information Maximization&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Prior work: Graph kernel, Graph2vec requires manual construction of features
of importance. Aim of work: Automated discovery of these features.&lt;/p&gt;

&lt;p&gt;InfoGraph: Model which tries to maximize the MI between patch
representations (subgraphs) and global representations (hole graph). This
should create a global representation of the graph which preserves aspects
of all pathces and all scales. Approach is competitive in classification.&lt;/p&gt;

&lt;p&gt;Extension to semi-supervised scenarios:
Use student-teacher like architecture: Student model learns in a supervised
manner, whereas the teacher learns on all unlabeled data using the
previously devised InfoGraph approach. In order for the student model to
learn from the teacher model, they propose to maximize the mutual
information of intermediate layers of the GNN and the final representation.
Thus the student is slightly biased to exploit similar structures as the
unsupervised teacher. This leads to better performance than simply combining
supervised and unsupervised loss for a single model.&lt;/p&gt;

&lt;h3 id=&quot;mutual-information-gradient-estimation-for-representation-learning&quot;&gt;&lt;a href=&quot;https://iclr.cc/virtual/poster_ByxaUgrFvH.html&quot;&gt;Mutual Information Gradient Estimation for Representation Learning&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Problem: High bias or high variance in existing approaches for MI.&lt;/p&gt;

&lt;p&gt;Hypothesis of work is that while the approximated loss landscape could
potentially be very noisy deriving only the gradient without prior
computation of the loss could lead to much lower noise and variance.&lt;/p&gt;

&lt;p&gt;Derive gradient of MI and use reparameterization trick in order to make the
computation tractable and obtain $\nabla_z \log q(E_{\phi}(x))$ and
$\nabla_{x,z} log q(x, E_{\phi}(x))$ via score estimation.&lt;/p&gt;

&lt;p&gt;Use Spectral Stein Gradient estimator for score estimation of implicit
distributions. Reduce the complexity of the estimation by applying a &lt;em&gt;random
projection&lt;/em&gt; into a lower dimensional space. This reduces the computational
complexity of computing the RBF kernel of the Spectral Stein Gradient
Estimator.&lt;/p&gt;

&lt;p&gt;The devised approach outperforms other mutual information maximization
techniques.&lt;/p&gt;

&lt;h3 id=&quot;on-mutual-information-maximization-for-representation-learning&quot;&gt;&lt;a href=&quot;https://iclr.cc/virtual/poster_rkxoh24FPH.html&quot;&gt;On Mutual Information Maximization for Representation Learning&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Many representation learning approaches are based on the InfoMax principle,
where a good representation should maximize the mutual information between
the data and the learnt representation (Linsker 1988).&lt;/p&gt;

&lt;p&gt;Recently, novel approaches for new lower bounds on the MI and modern CNN
architectures have resurged the approach. However:&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;MI is hard to estimate&lt;/li&gt;
  &lt;li&gt;Invariant under bijections&lt;/li&gt;
  &lt;li&gt;Does not yield good clustering representations&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;em&gt;So why doe these approaches work so well?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Modern approaches do not maximize MI between data and representation, but
between different views of the same input (higher level aggregation and
lower level aggregation) which is a lower bound on the original InfoMax
objective. Thus if these views encode low level information, such as pixel
noise, they would not yield high mutual information, whereas if high level
features such as “catness” would yield high mutual information on different
crops of a cat image.&lt;/p&gt;

&lt;p&gt;Experiments: Maximize MI between bottom and top half of image and evaluate
performance using linear classifier.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Usage of bijective encoders: &lt;em&gt;These preserve mutual information
completely!&lt;/em&gt; Thus &lt;em&gt;the true MI between the segments is actually remains
the same during training.&lt;/em&gt; Nevertheless, the lower bounds of the
estimators increases slightly during training and the classification
accuracy of the derived representations increases strongly. Thus the
&lt;em&gt;estimator favors “good representations”&lt;/em&gt; despite any solution maximizing
the MI!&lt;/li&gt;
  &lt;li&gt;Encoders which could be injective or monojective: MLPs with skip
connections initialized to the identity mapping. Here the estimators
favor hard to invert mappings even though the initialization (identity)
maximizes the mutual information. The estimators thus bias towards good
representations for classification, but tend towards hard to invert
mappings which reduce the true mutual information!&lt;/li&gt;
  &lt;li&gt;Impact of encoder architecture: &lt;em&gt;Different architecture with same MI
estimator values lead to very different performance in terms of
classification.&lt;/em&gt; Thus the value of the estimator is insufficient to
explain performance. Inductive bias of architecture responsible for good
performance?&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;seq2seq-models&quot;&gt;Seq2Seq models&lt;/h2&gt;
&lt;h3 id=&quot;are-transformers-universal-approximators-of-sequence-to-sequence-functions&quot;&gt;&lt;a href=&quot;https://iclr.cc/virtual/poster_ByxRM0Ntvr.html&quot;&gt;Are Transformers universal approximators of sequence-to-sequence functions?&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;TLDR: Yes.&lt;/p&gt;

&lt;p&gt;Maybe not as there are quite some structures which could potentially limit
expressive power: All tokens experience the same transformation. Only
pairwise interactions between tokens are possible.&lt;/p&gt;

&lt;p&gt;Paper shows that there always exists a transformer network with small width
and unlimited depth that can approximate any equivariant function
arbitrarily accurately.&lt;/p&gt;

&lt;p&gt;What about positional encodings? These remove the restriction of permutation
equivariance and allow a transformer to approximate any continuous seq-2-seq
function.&lt;/p&gt;

&lt;p&gt;Further, the authors show that inclusion hybrid architectures which for
example include convolutional layers in between attention layers actually
can improve performance.&lt;/p&gt;

&lt;h3 id=&quot;mogrifier-lstm&quot;&gt;&lt;a href=&quot;https://iclr.cc/virtual/poster_SJe5P6EYvS.html&quot;&gt;Mogrifier LSTM&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Core modification to LSTM: Gate the hidden state using input, and gate the
input using the hidden state in an alternating fashion. The input and hidden
state are then fed into the LSTM which then gives rise to a new hidden
state. This leads to better performance than the baseline LSTM model and
pushes the new LSTM closer to transformer networks in terms of performance.&lt;/p&gt;

&lt;p&gt;Why does it work though? Potential explanations&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Contextualized embeddings: The procedure could lead to an embedding which 
accounts for the actual context of the work and not only its mean context
such as in word embeddings. Experiments indicate that this is not
sufficient for explaining the performance on character level tasks and
synthetics datasets.&lt;/li&gt;
  &lt;li&gt;Multiplicative interactions: Not really clear how this would improve
performance.&lt;/li&gt;
  &lt;li&gt;Many more&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of them really explain the Mogrifier LSTM. The authors performed
several experiments and none of them was really conclusive. There are solely
indications. For example the Mogrifier performs better on a copy task if the
sequences are long. Further, it this performance gap becomes larger as the
vocabulary size of the input sequences increases.&lt;/p&gt;

&lt;h3 id=&quot;reformer-the-efficient-transformer&quot;&gt;&lt;a href=&quot;https://iclr.cc/virtual/poster_rkgNKkHtvB.html&quot;&gt;Reformer: The Efficient Transformer&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Combine two techniques to make Transformers more memory efficient and
scalable with respect to training time:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;RevNets (Invertable version of ResNet): As the computation can be
inverted, it is not necessary to store all downstream activations for
a back-propagation pass. They can be dynamically recomputed when needed.
The reversibility of the connections is enabled by only applying the layer
to half of the input and adding its output to the other half. This is
a bit similar to the strategy of RealNVP. Interestingly, this does not
reduce the performance.&lt;/li&gt;
  &lt;li&gt;Chunking of computations through the FeedForward NNs: Prevents having to
store all intermediate activations at once.&lt;/li&gt;
  &lt;li&gt;While one could in theory also chunk the computation of the attention
mechanism, the quadratic scaling of attention will lead to severe issues
with respect to speed&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Tackling the attention computation and making it scalable:
Main issue: while we compute all values in the preattention matrix, the
softmax converts these into a matrix of the same size, where many values are
very close to zero. &lt;em&gt;The attention matrix is sparse.&lt;/em&gt; How can we use the
sparsity? &lt;strong&gt;Use variant of locality sensitive hashing:&lt;/strong&gt; Allows sorting
vectors with a high dot product into buckets. Thus one can simply compute
the attention within each bucket and already cover most of the variance.
Use shared QK attention (where the query and key are the same, which
apparently seems to be as powerful as regular attention). Then bucket QK via
LSH and sort according to the bucket. In order to exploit parallelism chunk
the sorted array into fixed sizes and allow attention to attend within the
chunk and the previous chunk in if the bucket ids match in order to cover
case when chunking slitted buckets. In order to avoid problems with the
probabilistic nature of LHS the process is repeated with multiple hash
functions.&lt;/p&gt;

&lt;p&gt;The results indicate that with more hash functions, the model converges to
the performance of a full attention model.&lt;/p&gt;

&lt;h2 id=&quot;understanding-deep-learning&quot;&gt;Understanding Deep Learning&lt;/h2&gt;
&lt;h3 id=&quot;four-things-everyone-should-know-to-improve-batch-normalization&quot;&gt;&lt;a href=&quot;https://iclr.cc/virtual/poster_HJx8HANFDH.html&quot;&gt;Four Things Everyone Should Know to Improve Batch Normalization&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Things that are wrong with BatchNorm:&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;Inference Example Weighing:
During training, the influence of the current instance on the batch
statistics is still $\frac{1}{B}$, whereas during testing the instance
does not contribute at all as only the moving averages are used for
computing the normalization. The authors suggest to reparametrize the
mean and std-deviation of batch norm during test time to reintroduce the
dependency on the instance:&lt;/p&gt;

\[\begin{aligned}
\mu_i &amp;amp;= \alpha E[x_i] + (1-\alpha) m_x\\\\
\sigma_i^2 &amp;amp;= (\alpha E[x_i^2] + (1-\alpha)m_x) - \mu_i^2
\end{aligned}\]

    &lt;p&gt;where, $\alpha$ is a hyperparameter which can be tuned after training on
the validation data. This can also be done after a model has already been
trained with regular batch norm and was shown to improve performance at
test time.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;Ghost Batch Norm:
Originally developed for multi GPU  and large batch training scenarios,
Ghost Batch norm normalized across subsets of each batch instead of the
complete batch. The authors show that this increases performance even for
single GPU medium batch size training (by inducing additional noise
during training?)&lt;/li&gt;
  &lt;li&gt;Batch Normalization and Weight decay: Applying weight decay on the shift
and scale parameters of batch norm is unstudied. Authors show a slight
improvement of performance. Yet, for this to be the case it is necessary
that the path from BN to output does not pass through additional BN
layers as it would amplify the effect with increasing depth.&lt;/li&gt;
  &lt;li&gt;Generalizing Batch and Group Norm:
For small batch regime when the application of vanilla batch norm is not
possible, suggest to normalize over both channel groups and examples.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The authors show that combining all the above proposed techniques can lead
to an improvement of up to 6% in some scenarios. In general, I think the
first approach is the most relevant and interesting.&lt;/p&gt;

&lt;h3 id=&quot;on-the-variance-of-the-adaptive-learning-rate-and-beyond&quot;&gt;&lt;a href=&quot;https://iclr.cc/virtual/poster_rkgz2aEKDr.html&quot;&gt;On the Variance of the Adaptive Learning Rate and Beyond&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Warmup: Linear increase on learning rate, seems to be critical for some
learning tasks (such as in the case of Transformer models).&lt;/p&gt;

&lt;p&gt;Experiments showed that &lt;em&gt;without warmup, the gradient distribution gets
distorted towards small values&lt;/em&gt;. This happens in the very beginning of
training withing the first 10 updates. With warmup this distortion doesn’t
occur and the gradient distributions remains largely the same compared to
the vary beginning of training.&lt;/p&gt;

&lt;p&gt;Why does warmup improve the convergence and mitigate this effect? Authors
suggest that the adaptive learning rate is of very high variance in the
beginning of training, due to the lack of samples used for computing the
moving averages.&lt;/p&gt;

&lt;p&gt;Set up two control experiments to verify if this is actually the cause of
problems:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Adam-2k, which provides Adam with additional 2k samples for estimating
the variance of the gradient (without any updates to the weights!). This
leads to a learning curve which is extremely similar to using warmup.&lt;/li&gt;
  &lt;li&gt;Adam-eps: Increase the value of epsilon in the Adam implementation. This
term is usually added to the square root of the variance estimate. By
increasing eps the influence of the estimated variance becomes lower.
This leads to better convergence than without warmup, but still shows
some difficulties during training.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The authors suggest a rectification term to mitigate the issue of high
variance in the adaptive learning rate, which basically deactivates adaptive
learning rates when the variance estimate would diverge.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Experiments:&lt;/em&gt; Astonishingly, the results indicate that this corrected Adam
implementation RAdam, is significantly more robust to the selection of the
learning rate. Further, in contrast to warmup, it is not required to tune
any parameter to reach optimal performance (which is the case for the length
of warmup. Depending on the initial learning rate, longer or shorter warmup
could be required). Cool.&lt;/p&gt;

&lt;h3 id=&quot;the-implicit-bias-of-depth-how-incremental-learning-drives-generalization&quot;&gt;&lt;a href=&quot;https://iclr.cc/virtual/poster_H1lj0nNFwB.html&quot;&gt;The Implicit Bias of Depth: How Incremental Learning Drives Generalization&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Set up linear model $f_{\sigma}(x) = &amp;lt;\sigma, x&amp;gt;$ with reparameterizing
using auxiliary variables: $\sigma = w_1 \cdot w_2 \cdot w_3 \dots$ and
train via gradient descent.&lt;/p&gt;

&lt;p&gt;Analyse the gradient flow and show that the learning dynamics are different
between using only $\sigma$ and the formulation using auxiliary variables.
In the not deep model, all values are learned at the same time, whereas with
increasing depth the values are learnt incrementally. The authors conjecture
that this is the cause of sparsity in these type of models. Parameters that
most decrease the loss, are decreased first, if there is a solution which
has few non-zero values, this approach will most likely find it.&lt;/p&gt;

&lt;p&gt;The authors formalize the notation of incremental learning, and derive
conditions where it would occur. These conditions become much less strict as
the model becomes more deep. Thus, &lt;em&gt;deeper models allow for incremental
learning to occur more easily&lt;/em&gt; and deeper models are more biased towards
obtaining sparse solutions.&lt;/p&gt;

&lt;p&gt;Empirical results show that incremental learning occurs also under relaxed
assumptions.&lt;/p&gt;

&lt;h3 id=&quot;towards-neural-networks-that-provably-know-when-they-dont-know&quot;&gt;&lt;a href=&quot;https://iclr.cc/virtual/poster_ByxGkySKwH.html&quot;&gt;Towards neural networks that provably know when they don’t know&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Probabilistic model: Decompose $p(y|x)$ into in and out of distribution part.&lt;/p&gt;

\[p(y|x) = \frac{p(y|x,i) p(x|i) p(i) + p(y|x,o) p(x|o) p(o)}
         {p(x|i) p(i) + p(x|o) p(o)}\]

&lt;p&gt;Gives rise to generative models of in distribution data $p(x|i)$, out of
distribution data $p(x|o)$ and probability of the label given data is out of
distribution $p(y|x,o) = 1/M$. Requires a out of distribution data!
By using Gaussian Mixture Models as generative models, the authors can prove
that the model would be not-confident for areas which differ significantly
from the training data. Further they show that with their approach they can
guarantee that entire volumes would be assigned low confidence.&lt;/p&gt;

&lt;p&gt;Experimental results indicate state of the art out of distribution detection
without reducing classification performance.&lt;/p&gt;

&lt;h3 id=&quot;truth-or-backpropaganda-an-empirical-investigation-of-deep-learning-theory&quot;&gt;&lt;a href=&quot;https://iclr.cc/virtual/poster_HyxyIgHFvr.html&quot;&gt;Truth or backpropaganda? An empirical investigation of deep learning theory&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;em&gt;Suboptimal local minima DO exist in the loss landscape:&lt;/em&gt;
Constructed proof based on high bias neurons which force ReLU units to
function as the identity map. These neurons can then kill other ReLU
neurons, constructing a smaller NN embedded inside the NN. Experiments show
than when initializing with high bias or high variance of bias the test
networks converge to suboptimal local minima.
&lt;em&gt;Suboptimal local minimal do exist, but are avoided by careful initialization.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Low l2 norm parameters are not better:&lt;/em&gt;
Low l2 norm motivated from many directions: SVMs, generalization theory,
Induced development of weight decay.&lt;/p&gt;

&lt;p&gt;Empirical test: Use weight decay with norm bias, such that it increases the
norm relative to weight decay. This improved performance across
architectures and datasets and even improved performance without batch
normalization.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Neural Tangent Kernel patterns:&lt;/em&gt;
While the tangent kernel was confirmed to become constant in convnets, the
tangent kernel does not become constant in more involved architectures such
as resnet and others with skip connections.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Low rank layers:&lt;/em&gt;
Experiments show that theoretical results do not hold in real world.
Maximizing the rank outperforms rank minimization. Rank minimization also
produces less robust networks.&lt;/p&gt;

&lt;h3 id=&quot;what-graph-neural-networks-cannot-learn-depth-vs-width&quot;&gt;&lt;a href=&quot;https://iclr.cc/virtual/poster_B1l2bp4YwS.html&quot;&gt;What graph neural networks cannot learn: depth vs width&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Previous results indicate that the GNN message passing model is equivalent
to a 1WL-test and thus not universal.&lt;/p&gt;

&lt;p&gt;These results have been shown on anonymous graphs (where the nodes have no
features). The first result of paper indicates that GNNs with message
passing are universal if they have “powerful layers”, are sufficiently deep
and wide and &lt;em&gt;if the nodes are given unique features&lt;/em&gt;. If these do not exist
in the graph, then they can in theory be randomly assigned, but this would
probably lead to issues with generalization. Experiments confirm this:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;On the detection of a 4-cycle task a GNN without node labels can only
reach very poor performance (provably).&lt;/li&gt;
  &lt;li&gt;Degree features slightly improve performance a lot but don’t lead to
optimal performance&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;Assigning unique features based on a canonical ordering leads to perfect
performance on train and test&lt;/em&gt;&lt;/li&gt;
  &lt;li&gt;Random features leads to optimal performance on train but not on test and
thus generalize very badly&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Second result focuses on what cannot be learnt by GNNs with message passing.
Suggests that the GNN size should depend on the number of nodes $n$:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;Cannot solve many decision, optimization, verification and estimation
problems unless:&lt;/p&gt;

\[depth \times width = \Omega(n^d) \text{ for } d \in [0.5, 2]\]
  &lt;/li&gt;
  &lt;li&gt;&lt;em&gt;Dependence on n even if task appears local $\Omega(n)$!&lt;/em&gt;&lt;/li&gt;
  &lt;li&gt;Hard problems (maximum independent set, minimum vertex cover, coloring)
require $\Omega(n^2)$&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All in all a very good study on which can be helpful when picking
hyperparameters for GNNs.&lt;/p&gt;

&lt;h3 id=&quot;why-gradient-clipping-accelerates-training-a-theoretical-justification-for-adaptivity&quot;&gt;&lt;a href=&quot;https://iclr.cc/virtual/poster_BJgnXpVYwS.html&quot;&gt;Why Gradient Clipping Accelerates Training: A Theoretical Justification for Adaptivity&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;While Vanilla SGD is theoretically optimal it is in practice worse than
extensions such as SGD with momentum and Adam. Where does this gap come
from?&lt;/p&gt;

&lt;p&gt;Start insight: Proof of SGD optimality relies on three assumptions:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Differentiability&lt;/li&gt;
  &lt;li&gt;Bounded second moments&lt;/li&gt;
  &lt;li&gt;L-smoothness which is the focus of this talk&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;L-smoothness is actually a very strict criterion. Empirical evaluation shows
that smoothness of a NN changes dramatically and that it correlates with the
gradient norm.&lt;/p&gt;

&lt;p&gt;Authors suggest a relaxed smoothness criterion (l0, l1 smoothness), which
would account for the empirical observations better then the strict
criterion.&lt;/p&gt;

&lt;p&gt;Show with the relaxed smoothness criterion, there is a dependency of SGD
convergence on the maximal norm of the gradient. This means Vanilla SGD
would not converge if the gradient is not upper bounded.
Further, the paper shows that clipped gradient descent does not have
a dependence on the maximal norm of the gradient.&lt;/p&gt;

&lt;p&gt;High level intuition: With clipping the SGD can traverse non-smooth areas,
without clipping this would lead to divergences. This is especially the case
when training with high learning rate.&lt;/p&gt;

&lt;h2 id=&quot;other---normalizing-flows-robustness-meta-learning-probabilistic-modelling&quot;&gt;Other - Normalizing Flows, Robustness, Meta-Learning, Probabilistic Modelling&lt;/h2&gt;
&lt;h3 id=&quot;invertible-models-and-normalizing-flows&quot;&gt;&lt;a href=&quot;https://iclr.cc/virtual/speaker_4.html&quot;&gt;Invertible Models and Normalizing Flows&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Reference: https://arxiv.org/pdf/1908.09257&lt;/p&gt;

&lt;p&gt;Generative networks paradigm:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Variational Autoencoder (previously called Helmholz machine)&lt;/li&gt;
  &lt;li&gt;Generative Adversarial Networks using Noise Contrastive Estimation (the discriminator)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Two parts of determine the likelihood of a normalizing flow:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;likelihood of transformed variable in latent space given prior (push
everything to zero if we assume N(0,1))&lt;/li&gt;
  &lt;li&gt;determinant of the jacobian penalizing strong compression (similar an
entropy regularization term)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Sampling:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Sample from prior&lt;/li&gt;
  &lt;li&gt;pass through flow and you are done&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;History of flows:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;First:
    &lt;ul&gt;
      &lt;li&gt;Require square weight matrices&lt;/li&gt;
      &lt;li&gt;strictly increasing activation functions&lt;/li&gt;
      &lt;li&gt;Should make whole network invertable
 Issue: Computing the determinant of the jacobian is problematic!
 Space: $\mathcal{O}(d^2)$, runtime from $\mathcal{O}(d!)$ to $\mathcal{O}(d^3)$&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Autoregressive models: Have triangular jacobian!&lt;/li&gt;
  &lt;li&gt;Using LU decomposition to enforce triangular jacobian: Works really bad.&lt;/li&gt;
  &lt;li&gt;Coupling layers (NICE): Use function on fraction of the inputs to scale
and shift the other fraction. Is invertable and has a very easy to
compute jacobian! Actually got rejected twice during the process!&lt;/li&gt;
  &lt;li&gt;Real NVP: Batch normalization, Convolutional NN, small extensions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Relevance of log-likelihood:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Sample quality vs. log-likelihood:
Log-likelihhod and sample quality do not have to be aligned. But it seems
that (until now at least) that there at least seems to be a very strong
correlation (Evtl. look at Theis &amp;amp; van den Oord et al. 2015).&lt;/li&gt;
  &lt;li&gt;Density as a measure of typicality (for anomaly detection):
Role in typicality is questionable. Until now it does not seem to be
aligned.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Future directions:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Learning flows on manifolds&lt;/li&gt;
  &lt;li&gt;Add in prior knowledge into the flow, such as symmetries&lt;/li&gt;
  &lt;li&gt;Discrete change of variables, requires tricks (such as continuous
relaxation) for backprop&lt;/li&gt;
  &lt;li&gt;Variational approximations, mapping discrete variables to continuous
distributions, using dequantization&lt;/li&gt;
  &lt;li&gt;Adaptive sparsity patterns&lt;/li&gt;
  &lt;li&gt;Non-invertible models (Dinh 2019)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;learning-to-balance-bayesian-meta-learning-for-imbalanced-and-out-of-distribution-tasks&quot;&gt;&lt;a href=&quot;https://iclr.cc/virtual/poster_rkeZIJBYvr.html&quot;&gt;Learning to Balance: Bayesian Meta-Learning for Imbalanced and Out-of-distribution Tasks&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Focuses on extending MAML to unbalanced test datasets and out of
distribution tasks. This is mostly implemented by adapting the inner
gradient update according to the following formula:&lt;/p&gt;

\[\begin{aligned}
\theta_0 = \theta * z^\tau \\
\theta_k = \theta_{k-1} - \gamma^\tau \circ \alpha \circ \sum_{c=1}^C \omega^\tau_c \nabla_\theta \mathcal{L}_c
\end{aligned}\]

&lt;p&gt;where $*$ is abused in notation to “multiply if component in $\theta$ is
a weight and add if component in $\theta$ is a bias” and $\circ$ represents
element wise multiplication.&lt;/p&gt;

&lt;p&gt;The components have the following roles:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;$\omega^\tau_c$ scales the gradient of all instances with class c. Allows
to take larger gradient steps for classes with more examples &lt;em&gt;in order to
tackle class imbalance&lt;/em&gt; (Is this equivalent to computing a weighted loss?)&lt;/li&gt;
  &lt;li&gt;$\gamma^\tau$ scales the size of gradient steps on a per task basis &lt;em&gt;in
order to tackle task imbalance&lt;/em&gt;. Reasoning: Larger tasks should have
larger $\gamma$ because they can rely more on task-specific updates,
while smaller tasks should have small $\gamma$ because they should rely
more on meta-knowledge.&lt;/li&gt;
  &lt;li&gt;$z^\tau$ relocates the initial weights for each task. This allows tasks
which dissimilar (out of distribution) to the original meta-learnt tasks
to be shifted further away in weight space, while task which are closes
the meta-learnt tasks to remain closer. &lt;em&gt;Tackles out-of-distribution
tasks&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The parameters are inferred using amortized variational inference, where the
inference network is shared across all tasks and the parameters are computed
conditionally on summary statistics derived from the task instances (see
below).&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/2020-05-19-ICLR-2020/learning-to-balance-figure.png&quot; alt=&quot;Inference network&quot; /&gt;&lt;/p&gt;

&lt;p&gt;In general, I find it very interesting how the authors incorporate additional
terms into the inner gradient computation loop and how the inference of the
associated parameters is implemented using variational inference on the
summary statistics.&lt;/p&gt;

&lt;h3 id=&quot;meta-dropout-learning-to-perturb-latent-features-for-generalization&quot;&gt;&lt;a href=&quot;https://iclr.cc/virtual/poster_BJgd81SYwr.html&quot;&gt;Meta Dropout: Learning to Perturb Latent Features for Generalization&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Suggest to additionally learn how to perturb intermediate representation
during meta learning using input dependent Dropout. This is done by
computing parameters of the noise distribution dependent on the output of
the previous layer. This results in the following preactivation:&lt;/p&gt;

\[\begin{aligned}
a^{(l)} &amp;amp;\sim \mathcal{N}(\mu^{(l)}(h^{(l-1)}), I) \\\\
z^{(l)} &amp;amp;= Softplus(a^{(l)}) \\\\
h^{(l)} &amp;amp;= ReLU(W^{(l)} h^{(l-1)} \cdot z^{(l)})
\end{aligned}\]

&lt;p&gt;The parameters of the function $ \mu $ and the weights of the layer $W$ are
trained using the meta learning objects of MAML. Yet importantly, the
weights of $\mu$ are not fitted in the inner training loop of MAML as this
would allow the algorithm to “optimize away” the perturbation. Interestingly
they use a lower bound to optimize the inner loop. This is not really
motivated, but the authors draw a connection to variational inference, where
q and p are from the same family and thus the KL would equal 0. The results
look very good actually.&lt;/p&gt;

&lt;h3 id=&quot;on-robustness-of-neural-ordinary-differential-equations&quot;&gt;&lt;a href=&quot;https://iclr.cc/virtual/poster_B1e9Y2NYvS.html&quot;&gt;On Robustness of Neural Ordinary Differential Equations&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Empirical study of Neural ODEs compared to ResNets. Show that they are more
robust to random noise and to adversarial attacks. Further suggest
Time-invariant steady state ODE (TisODE), to additionally improve
robustness. This adds time invariance in the ODE function and a specific
steady state condition.&lt;/p&gt;

&lt;p&gt;They argue that the NeuralODE is more robust to perturbations as the ODE
integral curves do not intersect (See Theorem 1).  The argument is that due
to the non intersecting property, each perturbation of less than $\epsilon$
would remain sandwiched within the $\epsilon$ ball and its distance from the
unperturbed final position would remain upper bounded.  Quite a cool insight.
The extensions of the authors in TisODE aim at controlling the differences
between neighboring integral curves to enhance NeuralODE robustness.&lt;/p&gt;

&lt;h3 id=&quot;why-not-to-use-zero-imputation-correcting-sparsity-bias-in-training-neural-networks&quot;&gt;&lt;a href=&quot;https://iclr.cc/virtual/poster_BylsKkHYvH.html&quot;&gt;Why Not to Use Zero Imputation? Correcting Sparsity Bias in Training Neural Networks&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Using Zero imputation induces a bias in the network! Often the prediction
correlates with the fraction of imputed values more than with respect to the
similarity of the instances! This effect is present across a large variety
of datasets including medical data.&lt;/p&gt;

&lt;p&gt;Authors coin term “Variable sparsity problem”, where the expected value of
the output layer of a NN depends on the sparsity of the input data. The
existence of this problem is derived theoretically based on a few
assumptions.&lt;/p&gt;

&lt;p&gt;Paper suggest that imputation with non zero values is helpful, by
stabilizing the number of known entities. Phrase imputation as injecting
plausible noise. Still it should be considered as injecting noise into the
network!&lt;/p&gt;

&lt;p&gt;Authors suggest to use sparsity normalization:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Divide the input data by the L1 norm&lt;/li&gt;
  &lt;li&gt;Then the average activation of the subsequent layer would be independent
of data sparsity&lt;/li&gt;
  &lt;li&gt;This is a simple preprocessing scheme of the input data!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Authors show theoretically that this preprocessing step can fix the variable
sparsity problem. Empirical results are also in line with the theory.&lt;/p&gt;
</description>
        <pubDate>Sat, 23 May 2020 00:00:00 +0000</pubDate>
        <link>https://ExpectationMax.github.io/2020/ICLR-2020/</link>
        <guid isPermaLink="true">https://ExpectationMax.github.io/2020/ICLR-2020/</guid>
        
        <category>conferences</category>
        
        <category>papers</category>
        
        
        <category>papers</category>
        
      </item>
    
      <item>
        <title>Project: simple-gpu-scheduler - easy scheduling of jobs on multiple GPUs</title>
        <description>&lt;p&gt;Our research group has multiple servers each equipped with multiple GPUs.
Unfortunately, these are not connected together in a cluster infrastructure,
but instead, GPUs are assigned to individuals or on a per-project basis. This
makes the execution of many jobs using multiple GPUs difficult.&lt;/p&gt;

&lt;p&gt;While it would be possible to connect the servers to a small cluster with
a scheduling system (we are working on it!), this can take a long time until it
is set up. Especially in academia where the maintenance and setup of servers is
often delegated to the departments IT-team, the path to implementing a small
scale cluster is littered with bureaucracy. Questions like: &lt;em&gt;Who is
responsible for xyz?&lt;/em&gt;, &lt;em&gt;How are the software installations managed?&lt;/em&gt;,
&lt;em&gt;Which alterations should be done to have the correct network infrastructure?&lt;/em&gt;
can take ages before they are answered and appropriately implemented. In our
particular case we had the idea of refurbishing the cluster more than a year
ago and are still no where close to having it up and running.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://imgs.xkcd.com/comics/networking_problems.png&quot; alt=&quot;XKCD comic about networking problems&quot; title=&quot;LOOK, THE LATENCY FALLS EVERY TIME YOU CLAP YOUR HANDS AND SAY YOU BELIEVE&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;the-alternative---simple-gpu-scheduler&quot;&gt;The Alternative - &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;simple-gpu-scheduler&lt;/code&gt;&lt;/h2&gt;

&lt;p&gt;Driven by the need of having something as a bridge between our current server
setup and the to be beautiful world of our personal cluster I decided to write
a small Python package to do the job. This is how
&lt;a href=&quot;https://github.com/ExpectationMax/simple_gpu_scheduler&quot;&gt;simple-gpu-scheduler&lt;/a&gt;
was born.&lt;/p&gt;

&lt;h3 id=&quot;how-it-works&quot;&gt;How it works&lt;/h3&gt;

&lt;p&gt;Software based on the CUDA library (such as most deep learning frameworks and
many others), can be constrained to only seeing certain GPUs using the
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CUDA_VISIBLE_DEVICES&lt;/code&gt; environment variable. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;simple-gpu-scheduler&lt;/code&gt; accepts
commands and executes them while setting the environment variable to
a currently free GPU. As soon as the job finishes, the GPU is released and the
next job is allocated to it. This allows to always utilize all of the GPUs to
the maximally possible extent &lt;sup id=&quot;fnref:gnu-parallel&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:gnu-parallel&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;

&lt;h3 id=&quot;usage&quot;&gt;Usage&lt;/h3&gt;

&lt;p&gt;I wanted to make &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;simple-gpu-scheduler&lt;/code&gt; as simple and flexible as possible and
thus tried to adhere to the &lt;a href=&quot;https://en.wikipedia.org/wiki/KISS_principle&quot;&gt;KISS
principle&lt;/a&gt;. Like many UNIX tools
it thus takes it’s input from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;stdin&lt;/code&gt; such that it can be combined with other
tools. This allows reading commands from a list, or even from a fifo (first in
first out), such we can build a fully functioning queuing system. For further
reference please consult the &lt;a href=&quot;https://github.com/ExpectationMax/simple_gpu_scheduler&quot;&gt;GitHub
page&lt;/a&gt; of the project.&lt;/p&gt;

&lt;h3 id=&quot;simple-example&quot;&gt;Simple example&lt;/h3&gt;

&lt;p&gt;Suppose you have a file &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gpu_commands.txt&lt;/code&gt; with commands that you would like to
execute on the GPUs 0, 1 and 2 in parallel:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;cat &lt;/span&gt;gpu_commands.txt
python train_model.py &lt;span class=&quot;nt&quot;&gt;--lr&lt;/span&gt; 0.001 &lt;span class=&quot;nt&quot;&gt;--output&lt;/span&gt; run_1
python train_model.py &lt;span class=&quot;nt&quot;&gt;--lr&lt;/span&gt; 0.0005 &lt;span class=&quot;nt&quot;&gt;--output&lt;/span&gt; run_2
python train_model.py &lt;span class=&quot;nt&quot;&gt;--lr&lt;/span&gt; 0.0001 &lt;span class=&quot;nt&quot;&gt;--output&lt;/span&gt; run_3
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Then you can do so by simply piping the command into the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;simple_gpu_scheduler&lt;/code&gt;
script&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;simple_gpu_scheduler &lt;span class=&quot;nt&quot;&gt;--gpus&lt;/span&gt; 0 1 2 &amp;lt; gpu_commands.txt
Processing &lt;span class=&quot;nb&quot;&gt;command&lt;/span&gt; &lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;python train_model.py &lt;span class=&quot;nt&quot;&gt;--lr&lt;/span&gt; 0.001 &lt;span class=&quot;nt&quot;&gt;--output&lt;/span&gt; run_1&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt; on gpu 2
Processing &lt;span class=&quot;nb&quot;&gt;command&lt;/span&gt; &lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;python train_model.py &lt;span class=&quot;nt&quot;&gt;--lr&lt;/span&gt; 0.0005 &lt;span class=&quot;nt&quot;&gt;--output&lt;/span&gt; run_2&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt; on gpu 1
Processing &lt;span class=&quot;nb&quot;&gt;command&lt;/span&gt; &lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;python train_model.py &lt;span class=&quot;nt&quot;&gt;--lr&lt;/span&gt; 0.0001 &lt;span class=&quot;nt&quot;&gt;--output&lt;/span&gt; run_3&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt; on gpu 0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;hyperparameter-search&quot;&gt;Hyperparameter search&lt;/h3&gt;

&lt;p&gt;One of the most common use cases for running many jobs in parallel is
hyperparameter search. For convenience I added a small script
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;simple_hypersearch&lt;/code&gt; which generates commands to evaluate a hyperparameter
grid. Here is a small example of how to generate all possible configurations
and execute them in random order:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;simple_hypersearch &lt;span class=&quot;s2&quot;&gt;&quot;python3 train_dnn.py --lr {lr} --batch_size {bs}&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; lr 0.001 0.0005 0.0001 &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; bs 32 64 128 | simple_gpu_scheduler &lt;span class=&quot;nt&quot;&gt;--gpus&lt;/span&gt; 0,1,2
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;final-words&quot;&gt;Final words&lt;/h3&gt;

&lt;p&gt;I hope some of you find the software useful. Feel free to open issues and
feature requests if you need any further features. See you next time!&lt;/p&gt;

&lt;div class=&quot;footnotes&quot; role=&quot;doc-endnotes&quot;&gt;
  &lt;ol&gt;
    &lt;li id=&quot;fn:gnu-parallel&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;&lt;a href=&quot;https://www.gnu.org/software/parallel/&quot;&gt;GNU parallel&lt;/a&gt;
can be used to do something similar (see the
&lt;a href=&quot;https://news.ycombinator.com/item?id=21269950&quot;&gt;HN discussion&lt;/a&gt;). It is
significantly more flexible, which IMHO comes at the cost of ease of use. &lt;a href=&quot;#fnref:gnu-parallel&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;
</description>
        <pubDate>Fri, 25 Oct 2019 00:00:00 +0000</pubDate>
        <link>https://ExpectationMax.github.io/2019/simple-gpu-scheduler/</link>
        <guid isPermaLink="true">https://ExpectationMax.github.io/2019/simple-gpu-scheduler/</guid>
        
        <category>development</category>
        
        
        <category>development</category>
        
      </item>
    
      <item>
        <title>Organizing projects and notes with vimwiki and VimR</title>
        <description>&lt;p&gt;After a long time of absence I decided to reactivate my blog! So here comes
another post related to optimizing the workflow of a PhD student in Computer
Science.&lt;/p&gt;

&lt;h2 id=&quot;the-problem&quot;&gt;The problem&lt;/h2&gt;

&lt;p&gt;If there is one thing you should do a lot in your PhD studies it is reading.
Papers, course materials, books, blog articles. Over time it becomes hard to
keep track of everything read and the thoughts one had while reading. While it
is possible to track this kind of information (especially for papers) in
reference management software, it is usually not desired/possible to store
information from heterogeneous sources in such a format.&lt;/p&gt;

&lt;h2 id=&quot;a-potential-solution&quot;&gt;A potential solution&lt;/h2&gt;

&lt;p&gt;As I have developed a strong resistance against using practically any other
editor besides (Neo)vim &lt;sup id=&quot;fnref:1&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:1&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;, I searched for a solution within this framework. The
most lucrative solution for my taste was &lt;a href=&quot;https://github.com/vimwiki/vimwiki&quot;&gt;vimwiki&lt;/a&gt;.
It allows to:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Organize notes from multiple projects in a hierarchy&lt;/li&gt;
  &lt;li&gt;Supports navigating between these in a flawless fashion&lt;/li&gt;
  &lt;li&gt;It is very easy to create new pages&lt;/li&gt;
  &lt;li&gt;Can be configured to use a markdown compatible syntax&lt;/li&gt;
  &lt;li&gt;As everything is text, changes can also easily be synchronized git and even
be hosted in a personal wiki on github&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;configuration&quot;&gt;Configuration&lt;/h2&gt;

&lt;p&gt;I configured vimwiki such that it saves all my notes in a folder &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PhDWiki&lt;/code&gt; in
my home directory, uses the markdown syntax and only gets activated when files
inside this notes folder are being edited (I want to have the possibility to
configure my general markdown integration independently of vimwiki). This can
be achieved by adding the following settings to your &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.vimrc&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;init.vim&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-vimscript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;g:vimwiki_list&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[{&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'path'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'~/PhDwiki/'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'syntax'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'markdown'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'ext'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'.md'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'index'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'Home'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}]&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;g:vimwiki_global_ext&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;&quot; Install the plugin, this uses vim-plug anything else should also do&lt;/span&gt;
Plug &lt;span class=&quot;s1&quot;&gt;'vimwiki/vimwiki'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;working-with-equations-in-the-vimr-preview&quot;&gt;Working with equations in the VimR preview&lt;/h2&gt;

&lt;p&gt;While it is possible to configure vim such that some symbols in equations are
replaced, this usually does not really improve the readability of the
equations. This is especially due to very limited support of most operation
such as sub- and superscripts. For revising my writing, I rely on the preview
provided by &lt;a href=&quot;https://github.com/qvacua/vimr&quot;&gt;VimR&lt;/a&gt;. While I deactivated all
additional features of the GUI such as file browser, buffer view etc.,
features such as the markdown and html preview are the most beneficial
components of a GUI-interface compared to running NeoVim in the terminal.&lt;/p&gt;

&lt;p&gt;Unfortunately, this preview does not support equations which are
omnipresent in courses and papers out of the box. Yet not all hope is lost, as
thanks to a nifty javascript tool &lt;a href=&quot;https://www.mathjax.org/&quot;&gt;MathJax&lt;/a&gt; it can be
made to do so. VimR uses a tiny browser with full javascript support
to render markdown and html pages, thus by modifying the markdown template to
include MathJax we can patch in the support of equations.&lt;/p&gt;

&lt;p&gt;For this we need to edit the template file
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;VimR.app/Contents/Resources/markdown/template.html&lt;/code&gt;, by adding the following
lines just before the html tag &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;/head&amp;gt;&lt;/code&gt;. The relevant region of the edited
file should look as follows:&lt;/p&gt;

&lt;div class=&quot;language-html highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  &lt;span class=&quot;nt&quot;&gt;&amp;lt;title&amp;gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;script &lt;/span&gt;&lt;span class=&quot;na&quot;&gt;type=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;text/javascript&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;window&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;MathJax&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;extensions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;tex2jax.js&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;jax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;input/TeX&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;output/HTML-CSS&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;tex2jax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;inlineMath&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\\&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\\&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;displayMath&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;$$&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;$$&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\\&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\\&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;processEscapes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
      &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;HTML-CSS&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;na&quot;&gt;availableFonts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;STIX&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
          &lt;span class=&quot;na&quot;&gt;preferredFont&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;STIX&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;na&quot;&gt;webFont&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;STIX-Web&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;na&quot;&gt;imageFont&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;script &lt;/span&gt;&lt;span class=&quot;na&quot;&gt;type=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;text/javascript&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;src=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/MathJax.js&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;async&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This adds MathJax in the most light configuration to the markdown template,
allowing it to render math equations. Below you can see how the result looks:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/2019-04-12_VimR_equations.jpg&quot; alt=&quot;Vimr with markdown preview&quot; /&gt;&lt;/p&gt;

&lt;p&gt;While this works well in practice, it is still a rather hacky solution. For
example sometimes it is necessary to wrap the equation into a set of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;p&amp;gt;&amp;lt;/p&amp;gt;&lt;/code&gt;
tags to prevent the markdown renderer from destroying the equations. To make
the approach more integrated and robust to updates of the software, I opened an
issue &lt;a href=&quot;https://github.com/qvacua/vimr/issues/718&quot;&gt;here&lt;/a&gt;. I will edit this post
if there is any follow up development.&lt;/p&gt;

&lt;div class=&quot;footnotes&quot; role=&quot;doc-endnotes&quot;&gt;
  &lt;ol&gt;
    &lt;li id=&quot;fn:1&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;I am planning to do a separate blog post on the benefits and disadvantages of using an editor like Vim for most of your work. &lt;a href=&quot;#fnref:1&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;
</description>
        <pubDate>Fri, 12 Apr 2019 00:00:00 +0000</pubDate>
        <link>https://ExpectationMax.github.io/2019/organizing-projects-with-vimwiki-and-VimR/</link>
        <guid isPermaLink="true">https://ExpectationMax.github.io/2019/organizing-projects-with-vimwiki-and-VimR/</guid>
        
        <category>development</category>
        
        
        <category>development</category>
        
      </item>
    
      <item>
        <title>Setting up a Neovim and pipenv based Python development environment</title>
        <description>&lt;p&gt;I think everybody has been there after some time:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;multiple python venvs for dozens of projects&lt;/li&gt;
  &lt;li&gt;huge &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;requirements.txt&lt;/code&gt; files containing all dependencies of dependencies&lt;/li&gt;
  &lt;li&gt;JuPyter notebooks everywhere, including their dependencies&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For the start of my PhD I decided to try to bring some order in the chaos of environments and dependencies by switching to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pipenv&lt;/code&gt;. Furthermore, I show how to implement &lt;strong&gt;jupyter notebook&lt;/strong&gt; style programming in a Neovim()/Oni() development environment.&lt;/p&gt;

&lt;h2 id=&quot;pipenv&quot;&gt;pipenv&lt;/h2&gt;

&lt;p&gt;Pipenv is a tool that allows to manage project dependent virtual environments, while additionally enhancing reproducibility by using checksums of installed packages (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Pipfile.lock&lt;/code&gt;).
It is the recommended package manager by http://www.python.org, is straightforward to install and also supports loading project specific environment variables using an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.env&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;Virtual environments in pipenv are not stored in the repository of the project, also there are no additional files besides the Pipfile and the Pipfile.lock (these are actually good to have to ensure reproducibility).
The strategy is to avoid installing packages outside of pipenv (for example using pip), which automatically ensures that all project dependencies are tracked and up to date. Overall pretty neat in my opinion.&lt;/p&gt;

&lt;p&gt;On macOS with &lt;a href=&quot;https://brew.sh/&quot;&gt;brew&lt;/a&gt; you can be up an running with Python 3 and pipenv using the following commands:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;brew &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;python3
brew &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;pipenv
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Afterwards, we can install JuPyter in the global Python3 environment (or the users Python3 environment by adding the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--user&lt;/code&gt; flag) using:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;pip3 &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;--user&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; jupyter
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;avoiding-reinstalling-jupyter-for-all-venvs&quot;&gt;Avoiding reinstalling JuPyter for all venvs&lt;/h3&gt;

&lt;p&gt;Now that we have the JuPyter installed in the global environment we don’t want to have to reinstall all the dependencies for each virtual environment/project we work on.
The trick is, that we only need to install the JuPyter kernel in the individual virtual environments, and register these kernels in the global installation.&lt;/p&gt;

&lt;p&gt;The kernel package that is required for a jupyter/IPython interface (notebook, QT Console, console) to communicate with an environment is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ipykernel&lt;/code&gt;, which can be installed as an development dependency in pipenv (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pipenv install --dev ipykernel&lt;/code&gt;).
Afterwards, the new kernel needs to be registered with the global JuPyter installation.
In order to make the whole process easier, I wrote added a small bash function to my &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/.bashrc&lt;/code&gt; to create a Python 3 environment, install &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ipykernel&lt;/code&gt; as a development dependency and register the new kernel for usage in the global JuPyter installation.&lt;/p&gt;

&lt;p&gt;To get the same functionality, add the following lines to your &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/.bashrc&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;init_python3_pipenv &lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
   &lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Setting up pipenv environment&quot;&lt;/span&gt;
   pipenv &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--three&lt;/span&gt;
   &lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Installing ipython kernel&quot;&lt;/span&gt;
   pipenv &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--dev&lt;/span&gt; ipykernel
   &lt;span class=&quot;c&quot;&gt;# get name of environment and remove checksum for pretty name&lt;/span&gt;
   &lt;span class=&quot;nv&quot;&gt;venv_name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;basename&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--&lt;/span&gt; &lt;span class=&quot;si&quot;&gt;$(&lt;/span&gt;pipenv &lt;span class=&quot;nt&quot;&gt;--venv&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;))&lt;/span&gt;
   &lt;span class=&quot;nv&quot;&gt;venv_prettyname&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$venv_name&lt;/span&gt; | &lt;span class=&quot;nb&quot;&gt;cut&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'-'&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-f&lt;/span&gt; 1&lt;span class=&quot;si&quot;&gt;)&lt;/span&gt;
   &lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Adding ipython kernel to list of jupyter kernels&quot;&lt;/span&gt;
   &lt;span class=&quot;si&quot;&gt;$(&lt;/span&gt;pipenv &lt;span class=&quot;nt&quot;&gt;--py&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-m&lt;/span&gt; ipykernel &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--user&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--name&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$venv_name&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
   &lt;span class=&quot;nt&quot;&gt;--display-name&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Python3 (&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$venv_prettyname&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;)&quot;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;A new project can now easily be set up using:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;mkdir&lt;/span&gt; ~/Projects/MyAwesomeProject
&lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; ~/Projects/MyAwesomeProject
init_python3_pipenv
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;jupyter-notebook-style-programming-in-onineovim&quot;&gt;JuPyter notebook style programming in Oni/Neovim&lt;/h2&gt;

&lt;p&gt;For the vim users out there, I will explain how you can convert vim into an interactive developing environment similar to working in a jupyter notebook or using an ide like spyder.
This setup involves launching an IPython kernel in a QTConsole, establishing a remote connection to the kernel using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nvim-ipy&lt;/code&gt; plugin and configuring the QTConsole such that it outputs the results of remote commands.
IMHO the result look quite acceptable:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/2018-04-10_Oni-and-QtConsole.png&quot; alt=&quot;Screenshot of working environment&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;running-qtconsole-from-vim-using-correct-kernel&quot;&gt;Running QtConsole from vim using correct kernel&lt;/h3&gt;
&lt;p&gt;The benefit of the QT Console is that the output of a command is directly visible, allowing interactive programming with intermediate plots and variable inspection.&lt;/p&gt;

&lt;p&gt;On macOS, the dependencies (mainly QT) of the QT Console can be installed via brew.
For other operating systems please refer to the &lt;a href=&quot;https://qtconsole.readthedocs.io/en/stable/index.html&quot;&gt;QT console documentation&lt;/a&gt;.
As I only use Python 3 for development on an macOS operating system, I got the QT Console up and running using the following commands:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;brew &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;sip &lt;span class=&quot;nt&quot;&gt;--without-python&lt;/span&gt;@2
brew &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;pyqt &lt;span class=&quot;nt&quot;&gt;--with-python3&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--without-python&lt;/span&gt;@2
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;For integration with vim I use the &lt;a href=&quot;https://github.com/bfredl/nvim-ipy&quot;&gt;nvim-ipy&lt;/a&gt; vim plugin, which can be installed using your favorite vim plugin manager (I personally use &lt;a href=&quot;https://github.com/junegunn/vim-plug&quot;&gt;vim-plug&lt;/a&gt;).
The following command rely on the installation of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nvim-ipy&lt;/code&gt;.
To allow the QT Console to easily be launched using the correct kernel and from within vim, I defined the following vim functions in my &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;init.vim&lt;/code&gt;&lt;/p&gt;

&lt;div class=&quot;language-vimscript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;!&lt;/span&gt; GetKernelFromPipenv&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;a:kernel&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;tolower&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;system&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'basename $(pipenv --venv)'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;&quot; Remove control characters (most importantly newline)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;substitute&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;a:kernel&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'[[:cntrl:]]'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;''&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'g'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;endfunction&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;!&lt;/span&gt; ConnectToPipenvKernel&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;a:kernel&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; GetKernelFromPipenv&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;call&lt;/span&gt; IPyConnect&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'--kernel'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;a:kernel&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'--no-window'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;endfunction&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;!&lt;/span&gt; AddFilepathToSyspath&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;a:filepath&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;expand&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'%:p:h'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;call&lt;/span&gt; IPyRun&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'import sys; sys.path.append(&quot;'&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;a:filepath&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'&quot;)'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    echo &lt;span class=&quot;s1&quot;&gt;'Added '&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;a:filepath&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;' to pythons sys.path'&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;endfunction&lt;/span&gt;

command&lt;span class=&quot;p&quot;&gt;!&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;-&lt;/span&gt;nargs&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;0&lt;/span&gt; ConnectToPipenvKernel &lt;span class=&quot;k&quot;&gt;call&lt;/span&gt; ConnectToPipenvKernel&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
command&lt;span class=&quot;p&quot;&gt;!&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;-&lt;/span&gt;nargs&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;0&lt;/span&gt; RunQtConsole &lt;span class=&quot;k&quot;&gt;call&lt;/span&gt; jobstart&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;jupyter qtconsole --existing&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
command&lt;span class=&quot;p&quot;&gt;!&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;-&lt;/span&gt;nargs&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;0&lt;/span&gt; AddFilepathToSyspath &lt;span class=&quot;k&quot;&gt;call&lt;/span&gt; AddFilepathToSyspath&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

</description>
        <pubDate>Tue, 10 Apr 2018 17:00:00 +0000</pubDate>
        <link>https://ExpectationMax.github.io/2018/Neovim-pipenv-based-development-environment/</link>
        <guid isPermaLink="true">https://ExpectationMax.github.io/2018/Neovim-pipenv-based-development-environment/</guid>
        
        <category>development</category>
        
        
        <category>development</category>
        
      </item>
    
  </channel>
</rss>
