<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Zounds</title>
    <description>Zounds is a blog about analyzing, synthesizing, and indexing audio.
</description>
    <link>http://johnvinyard.github.io/</link>
    <atom:link href="http://johnvinyard.github.io/feed.xml" rel="self" type="application/rss+xml"/>
    <pubDate>Sat, 07 Mar 2026 21:06:10 +0000</pubDate>
    <lastBuildDate>Sat, 07 Mar 2026 21:06:10 +0000</lastBuildDate>
    <generator>Jekyll v3.10.0</generator>
    
      <item>
        <title>Resonance Inference</title>
        <description>&lt;p&gt;In this mini-experiment, I further explore whether playable “instruments” can be 
extracted from a single audio recording by overfitting a simple model of resonating
objects and a sparse control signal.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/resonance-inference.html&quot;&gt;Read more: &lt;/a&gt;&lt;/p&gt;
</description>
        <pubDate>Thu, 21 Nov 2024 12:00:00 +0000</pubDate>
        <link>http://johnvinyard.github.io/machine-learning/2024/11/21/resonance-inference.html</link>
        <guid isPermaLink="true">http://johnvinyard.github.io/machine-learning/2024/11/21/resonance-inference.html</guid>
        
        
        <category>machine-learning</category>
        
      </item>
    
      <item>
        <title>Iterative Decomposition Model V3</title>
        <description>&lt;p&gt;There’s a new demo page for v3 of the iterative audio decomposition model I’ve been working on.&lt;br /&gt;
The model is small and hasn’t had much (less than 24-hours) of training time so far, but doubles the 
duration of audio segments from the &lt;a href=&quot;https://blog.cochlea.xyz/machine-learning/2024/02/29/siam.html&quot;&gt;prior model&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You can &lt;a href=&quot;/v3blogpost.html&quot;&gt;read more and listen to demos here&lt;/a&gt;&lt;/p&gt;
</description>
        <pubDate>Thu, 21 Nov 2024 12:00:00 +0000</pubDate>
        <link>http://johnvinyard.github.io/machine-learning/2024/11/21/iterative-decomposition-v3.html</link>
        <guid isPermaLink="true">http://johnvinyard.github.io/machine-learning/2024/11/21/iterative-decomposition-v3.html</guid>
        
        
        <category>machine-learning</category>
        
      </item>
    
      <item>
        <title>Playable State-Space Model From a Single Audio Sample</title>
        <description>&lt;p&gt;This work attempts to reproduce a short segment of “natural” (i.e., produced by acoustic
instruments or physical objects in the world) audio by decomposing it into two distinct pieces:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;A state-space model simulating the resonances of the system&lt;/li&gt;
  &lt;li&gt;a sparse control signal, representing energy injected into the system.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The control signal can be thought of as roughly corresponding to a musical score, and the state-space model
can be thought of as the dynamics/resonances of the musical instrument and the room in which it was played.&lt;/p&gt;

&lt;p&gt;You can &lt;a href=&quot;/ssm.html&quot;&gt;read more and listen to a demo here&lt;/a&gt;&lt;/p&gt;
</description>
        <pubDate>Mon, 23 Sep 2024 12:00:00 +0000</pubDate>
        <link>http://johnvinyard.github.io/machine-learning/2024/09/23/playable-state-space-model.html</link>
        <guid isPermaLink="true">http://johnvinyard.github.io/machine-learning/2024/09/23/playable-state-space-model.html</guid>
        
        
        <category>machine-learning</category>
        
      </item>
    
      <item>
        <title>Gaussian/Gamma Splatting for Music</title>
        <description>&lt;p&gt;In this work, we apply a Gaussian Splatting-like approach to audio to produce a lossy, sparse, interpretable, and manipulatable representation of audio. We use a source-excitation model for each audio “atom”, implemented by convolving a burst of band-limited noise with a variable-length “resonance”, which is built using a number of exponentially decaying harmonics, meant to mimic the resonance of physical objects. Envelopes are built in both the time and frequency domain using gamma and/or gaussian distributions. Sixty-four atoms are randomly initialized and then fitted (3000 iterations) to a short segment of audio via a loss using multiple STFT resolutions. A sparse solution, with few active atoms, is encouraged by a second, weighted loss term.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/gamma-audio-splat.html&quot;&gt;Read more, and listen to demos here!&lt;/a&gt;&lt;/p&gt;
</description>
        <pubDate>Thu, 01 Aug 2024 12:00:00 +0000</pubDate>
        <link>http://johnvinyard.github.io/machine-learning/2024/08/01/guassian-audio-splatting.html</link>
        <guid isPermaLink="true">http://johnvinyard.github.io/machine-learning/2024/08/01/guassian-audio-splatting.html</guid>
        
        
        <category>machine-learning</category>
        
      </item>
    
      <item>
        <title>Sparse Interpretable Audio Model V2</title>
        <description>&lt;p&gt;Happy Leap Day!  I’ve just &lt;a href=&quot;/siam.html&quot;&gt;published some high-level details and sound reconstructions&lt;/a&gt; from a newly-trained model that
decomposes musical audio into an easy-to-manipulate format:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://matching-pursuit-repo-media.s3.amazonaws.com/vector_siam.drawio2.png&quot; alt=&quot;Sparse Interpretable Audio Model Architecture&quot; title=&quot;Sparse Interpretable Audio Model&quot; /&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;event times and amplitudes&lt;/li&gt;
  &lt;li&gt;time and amplitude-agnostic event vectors that describe a musical event&lt;/li&gt;
  &lt;li&gt;A global context vector that determines room reverb&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Different “axes” of the sound can be manipulated independently, and indivdual events can be played in isolation.&lt;/p&gt;
</description>
        <pubDate>Thu, 29 Feb 2024 12:00:00 +0000</pubDate>
        <link>http://johnvinyard.github.io/machine-learning/2024/02/29/siam.html</link>
        <guid isPermaLink="true">http://johnvinyard.github.io/machine-learning/2024/02/29/siam.html</guid>
        
        
        <category>machine-learning</category>
        
      </item>
    
      <item>
        <title>Sparse Interpretable Audio Model</title>
        <description>&lt;p&gt;This post covers a model I’ve recently developed that encodes audio as a high-dimensional and sparse
tensor, inspired by algorithms such as matching pursuit and dictionary learning.&lt;/p&gt;

&lt;p&gt;Its decoder borrows techniques such as waveguide synthesis and convolution-based reverb to
pre-load inductive biases about the physics of sound into the model, hopefully allowing it to
spend capacity elsewhere.&lt;/p&gt;

&lt;p&gt;The goal is to arrive at a sparse, interpretable,
and hopefully easy-to-manipulate representation of musical sound. All of the model training and inference
code can be found in the &lt;a href=&quot;https://github.com/JohnVinyard/matching-pursuit&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;matching-pursuit&lt;/code&gt;&lt;/a&gt; github repository,
which has become my home-base for audio machine learning research.&lt;/p&gt;

&lt;p&gt;The current set of experiments is performed using the &lt;a href=&quot;https://zenodo.org/records/5120004#.Yhxr0-jMJBA&quot;&gt;MusicNet dataset&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;⚠️ This post contains sounds that may be loud. Please be sure to start your headphones or speakers at a lower volume to avoid
    unpleasant surprises!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&quot;motivations&quot;&gt;Motivations&lt;/h2&gt;

&lt;p&gt;I’ve formed several hunches/intuitions in my &lt;a href=&quot;https://github.com/JohnVinyard/matching-pursuit/tree/main/experiments&quot;&gt;recent years working on machine learning models for audio synthesis&lt;/a&gt; that all find expression in the work being covering today.&lt;/p&gt;

&lt;h3 id=&quot;frame-based-representations-are-limited&quot;&gt;Frame-Based Representations Are Limited&lt;/h3&gt;

&lt;p&gt;Almost all codecs and machine learning models that perform audio analysis and/or synthesis are frame-based; they chop audio up into
generally fixed-size frames, without much regard for the content, encode each framem and represent audio as a sequence of these encodings.&lt;/p&gt;

&lt;p&gt;The model discussed today takes some baby-steps away from a frame-based representation, and toward something that might be derived using &lt;a href=&quot;https://en.wikipedia.org/wiki/Matching_pursuit&quot;&gt;matching pursuit
or dictionary learning&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;While a sequence of encoded frames may reproduce sound very faithfully, it is not easily &lt;em&gt;interpretable&lt;/em&gt;; each frame
is a mixture of physical or musical events that have happened before that moment, and continue to reverberate.&lt;/p&gt;

&lt;p&gt;My sense is that a high-dimensional and &lt;em&gt;very&lt;/em&gt; sparse representation maps more closely onto the way we think about sound, especially musical audio.&lt;/p&gt;

&lt;h3 id=&quot;audio-synthesis-models-must-learn-physics&quot;&gt;Audio Synthesis Models Must Learn Physics&lt;/h3&gt;

&lt;p&gt;While there are certainly classes of audio where the laws of physics are unimportant (synthesized sounds/music), those laws
are integral to the sounds made by acoustic instruments, and even many synthesized instruments simply aim to mimic these sounds.&lt;/p&gt;

&lt;p&gt;Do audio models waste capacity learning some of the invariant laws of sound from scratch? Could it be advantageous to bake
some inductive biases around the physics of sound into the model from the outset, so that it can instead focus on understanding and extracting
higher-level “events” from a given piece of audio?&lt;/p&gt;

&lt;p&gt;Synthesis techniques such as &lt;a href=&quot;https://ccrma.stanford.edu/~jos/swgt/&quot;&gt;waveguide synthesis&lt;/a&gt; and the use of long convolution kernels
to model material transfer functions and room impulse responses suggest a different direction that might be fundamentally better (for audio) than the classic upsample-then-convolve-with-short-kernel approaches that have dominated both image and audio generation to-date.&lt;/p&gt;

&lt;h2 id=&quot;quick-tour&quot;&gt;Quick Tour&lt;/h2&gt;

&lt;p&gt;Before diving into the details, it might be good to get an intuitive feel for what the high-level components of the model
are doing. We grab a random segment of audio from the MusicNet dataset…&lt;/p&gt;

&lt;div class=&quot;language-python 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;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;conjure&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;audio_conjure&lt;/span&gt;

&lt;span class=&quot;o&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;audio_conjure&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;conjure_storage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;get_audio&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;identifier&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;data.audioiter&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;AudioIterator&lt;/span&gt;
    &lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;util&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;playable&lt;/span&gt;
    &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;zounds&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;stream&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;AudioIterator&lt;/span&gt;&lt;span class=&quot;p&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;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;15&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;zounds&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SR22050&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;normalize&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;overfit&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;False&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;step_size&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;n&quot;&gt;pattern&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;*.wav&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;chunk&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;next&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;iter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;stream&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;chunk&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;chunk&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;cpu&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;view&lt;/span&gt;&lt;span class=&quot;p&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;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;stream&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;n_samples&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;audio&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;playable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;chunk&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;stream&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;samplerate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;bio&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;audio&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;encode&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;bio&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;read&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;example_6&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;get_audio&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;example_7c&apos;&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;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;get_audio&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;meta&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;example_7c&apos;&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;div id=&quot;conjure-id-645cebe5670a6f4f96103cc2eea08cf8c67cbacf_407a73461e0352605bb6b0704c1a2a3d8f3645a5&quot; data-conjure=&quot;{&amp;quot;key&amp;quot;: &amp;quot;645cebe5670a6f4f96103cc2eea08cf8c67cbacf_407a73461e0352605bb6b0704c1a2a3d8f3645a5&amp;quot;, &amp;quot;public_uri&amp;quot;: &amp;quot;https://zounds-blog-media.s3.amazonaws.com/645cebe5670a6f4f96103cc2eea08cf8c67cbacf_407a73461e0352605bb6b0704c1a2a3d8f3645a5&amp;quot;, &amp;quot;content_type&amp;quot;: &amp;quot;audio/wav&amp;quot;, &amp;quot;feed_uri&amp;quot;: &amp;quot;/feed/645cebe5670a6f4f96103cc2eea08cf8c67cbacf&amp;quot;, &amp;quot;func_name&amp;quot;: &amp;quot;get_audio&amp;quot;, &amp;quot;func_identifier&amp;quot;: &amp;quot;645cebe5670a6f4f96103cc2eea08cf8c67cbacf&amp;quot;}&quot;&gt;&lt;/div&gt;

&lt;p&gt;You can click on the waveform to play the sound.&lt;/p&gt;

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

&lt;p&gt;The network encodes the audio, and we end up with something like this.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;⚠️ Because the representation is very high-dimensional, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(4096, 128)&lt;/code&gt; to be exact, we downsample for easier viewing&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class=&quot;language-python 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;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;conjure&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;numpy_conjure&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SupportedContentType&lt;/span&gt;

&lt;span class=&quot;o&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;numpy_conjure&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;conjure_storage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;content_type&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SupportedContentType&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Spectrogram&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;get_encoding&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;identifier&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;models.resonance&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;model&lt;/span&gt;
    &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;zounds&lt;/span&gt;
    &lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;io&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;BytesIO&lt;/span&gt;
    &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;torch&lt;/span&gt;
    &lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;torch.nn&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;functional&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;F&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;n_samples&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;15&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;bio&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;BytesIO&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get_audio&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;identifier&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;chunk&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;torch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;from_numpy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;zounds&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;AudioSamples&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;from_file&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bio&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)).&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;chunk&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;chunk&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[...,:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;n_samples&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;view&lt;/span&gt;&lt;span class=&quot;p&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;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n_samples&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;encoded&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sparse_encode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;chunk&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;# downsample for easier viewing
&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;encoded&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;encoded&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[:,&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;None&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;n&quot;&gt;encoded&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;F&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;max_pool2d&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;encoded&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;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8&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;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;encoded&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;encoded&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;view&lt;/span&gt;&lt;span class=&quot;p&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;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;encoded&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;shape&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:])&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;encoded&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;encoded&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;T&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;encoded&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cpu&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;numpy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;encoding_1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;get_encoding&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;example_7c&apos;&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;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;get_encoding&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;meta&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;example_7c&apos;&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;div id=&quot;conjure-id-d58810f9f504e43d753ec182ab3b6a94b20bc6ce_407a73461e0352605bb6b0704c1a2a3d8f3645a5&quot; data-conjure=&quot;{&amp;quot;key&amp;quot;: &amp;quot;d58810f9f504e43d753ec182ab3b6a94b20bc6ce_407a73461e0352605bb6b0704c1a2a3d8f3645a5&amp;quot;, &amp;quot;public_uri&amp;quot;: &amp;quot;https://zounds-blog-media.s3.amazonaws.com/d58810f9f504e43d753ec182ab3b6a94b20bc6ce_407a73461e0352605bb6b0704c1a2a3d8f3645a5&amp;quot;, &amp;quot;content_type&amp;quot;: &amp;quot;application/spectrogram+octet-stream&amp;quot;, &amp;quot;feed_uri&amp;quot;: &amp;quot;/feed/d58810f9f504e43d753ec182ab3b6a94b20bc6ce&amp;quot;, &amp;quot;func_name&amp;quot;: &amp;quot;get_encoding&amp;quot;, &amp;quot;func_identifier&amp;quot;: &amp;quot;d58810f9f504e43d753ec182ab3b6a94b20bc6ce&amp;quot;}&quot;&gt;&lt;/div&gt;

&lt;p&gt;The dark-blue portions represent zeros, and the yellow-orange portions represent events.&lt;/p&gt;

&lt;h2 id=&quot;reconstructed-audio&quot;&gt;Reconstructed Audio&lt;/h2&gt;

&lt;p&gt;We can also perform a full pass through the network, both encoding and decoding.  The reconstructions don’t sound amazing, but are clearly the same musical sequence as the original.&lt;/p&gt;

&lt;div class=&quot;language-python 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;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;conjure&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;audio_conjure&lt;/span&gt;

&lt;span class=&quot;o&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;audio_conjure&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;conjure_storage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;reconstruct_audio&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;identifier&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;models.resonance&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;model&lt;/span&gt;
    &lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;util&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;playable&lt;/span&gt;
    &lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;modules.normalization&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;max_norm&lt;/span&gt;
    &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;torch&lt;/span&gt;
    &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;zounds&lt;/span&gt;
    &lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;io&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;BytesIO&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;n_samples&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;15&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;bio&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;BytesIO&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get_audio&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;identifier&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;chunk&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;torch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;from_numpy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;zounds&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;AudioSamples&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;from_file&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bio&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)).&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;chunk&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;chunk&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[...,:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;n_samples&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;view&lt;/span&gt;&lt;span class=&quot;p&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;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n_samples&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;recon&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;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;forward&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;chunk&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;recon&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;torch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sum&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;recon&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dim&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;n&quot;&gt;keepdim&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;recon&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;max_norm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;recon&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;recon&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;playable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;recon&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;zounds&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SR22050&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;encoded&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;recon&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;encode&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;encoded&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;read&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;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;reconstruct_audio&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;example_7c&apos;&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;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;reconstruct_audio&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;meta&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;example_7c&apos;&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;div id=&quot;conjure-id-2576fa3cc62603e3c37a8961df8c2831bf879947_407a73461e0352605bb6b0704c1a2a3d8f3645a5&quot; data-conjure=&quot;{&amp;quot;key&amp;quot;: &amp;quot;2576fa3cc62603e3c37a8961df8c2831bf879947_407a73461e0352605bb6b0704c1a2a3d8f3645a5&amp;quot;, &amp;quot;public_uri&amp;quot;: &amp;quot;https://zounds-blog-media.s3.amazonaws.com/2576fa3cc62603e3c37a8961df8c2831bf879947_407a73461e0352605bb6b0704c1a2a3d8f3645a5&amp;quot;, &amp;quot;content_type&amp;quot;: &amp;quot;audio/wav&amp;quot;, &amp;quot;feed_uri&amp;quot;: &amp;quot;/feed/2576fa3cc62603e3c37a8961df8c2831bf879947&amp;quot;, &amp;quot;func_name&amp;quot;: &amp;quot;reconstruct_audio&amp;quot;, &amp;quot;func_identifier&amp;quot;: &amp;quot;2576fa3cc62603e3c37a8961df8c2831bf879947&amp;quot;}&quot;&gt;&lt;/div&gt;

&lt;h3 id=&quot;another-reconstruction-example&quot;&gt;Another Reconstruction Example&lt;/h3&gt;

&lt;p&gt;original:&lt;/p&gt;

&lt;div class=&quot;language-python 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;n&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;get_audio&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;example_8c&apos;&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;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;get_audio&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;meta&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;example_8c&apos;&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;div id=&quot;conjure-id-645cebe5670a6f4f96103cc2eea08cf8c67cbacf_66ca19b4a30fea0c7756c6d317899788024dcdb0&quot; data-conjure=&quot;{&amp;quot;key&amp;quot;: &amp;quot;645cebe5670a6f4f96103cc2eea08cf8c67cbacf_66ca19b4a30fea0c7756c6d317899788024dcdb0&amp;quot;, &amp;quot;public_uri&amp;quot;: &amp;quot;https://zounds-blog-media.s3.amazonaws.com/645cebe5670a6f4f96103cc2eea08cf8c67cbacf_66ca19b4a30fea0c7756c6d317899788024dcdb0&amp;quot;, &amp;quot;content_type&amp;quot;: &amp;quot;audio/wav&amp;quot;, &amp;quot;feed_uri&amp;quot;: &amp;quot;/feed/645cebe5670a6f4f96103cc2eea08cf8c67cbacf&amp;quot;, &amp;quot;func_name&amp;quot;: &amp;quot;get_audio&amp;quot;, &amp;quot;func_identifier&amp;quot;: &amp;quot;645cebe5670a6f4f96103cc2eea08cf8c67cbacf&amp;quot;}&quot;&gt;&lt;/div&gt;

&lt;p&gt;reconstruction:&lt;/p&gt;

&lt;div class=&quot;language-python 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;n&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;reconstruct_audio&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;example_8c&apos;&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;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;reconstruct_audio&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;meta&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;example_8c&apos;&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;div id=&quot;conjure-id-2576fa3cc62603e3c37a8961df8c2831bf879947_66ca19b4a30fea0c7756c6d317899788024dcdb0&quot; data-conjure=&quot;{&amp;quot;key&amp;quot;: &amp;quot;2576fa3cc62603e3c37a8961df8c2831bf879947_66ca19b4a30fea0c7756c6d317899788024dcdb0&amp;quot;, &amp;quot;public_uri&amp;quot;: &amp;quot;https://zounds-blog-media.s3.amazonaws.com/2576fa3cc62603e3c37a8961df8c2831bf879947_66ca19b4a30fea0c7756c6d317899788024dcdb0&amp;quot;, &amp;quot;content_type&amp;quot;: &amp;quot;audio/wav&amp;quot;, &amp;quot;feed_uri&amp;quot;: &amp;quot;/feed/2576fa3cc62603e3c37a8961df8c2831bf879947&amp;quot;, &amp;quot;func_name&amp;quot;: &amp;quot;reconstruct_audio&amp;quot;, &amp;quot;func_identifier&amp;quot;: &amp;quot;2576fa3cc62603e3c37a8961df8c2831bf879947&amp;quot;}&quot;&gt;&lt;/div&gt;

&lt;h2 id=&quot;model-and-training-details&quot;&gt;Model and Training Details&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;https://zounds-blog-media.s3.amazonaws.com/sparse-physical-model.jpg&quot; alt=&quot;model architecture&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The model’s encoder portion is fairly standard and uninteresting, while the decoder includes some novel features. Once again, code
for the experiment &lt;a href=&quot;https://github.com/JohnVinyard/matching-pursuit/blob/main/experiments/e_2023_10_2/experiment.py&quot;&gt;can be found on github&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;encoder&quot;&gt;Encoder&lt;/h3&gt;

&lt;p&gt;Starting with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;32768 samples&lt;/code&gt; at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;22050 hz&lt;/code&gt;, or about 1.5 seconds of audio, we first perform a short-time fourier transform
with a &lt;a href=&quot;https://github.com/JohnVinyard/matching-pursuit/blob/main/experiments/e_2023_10_2/experiment.py#L331&quot;&gt;window size of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;2048 samples&lt;/code&gt; and a step size of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;256 samples&lt;/code&gt;&lt;/a&gt;. This means that we begin with a representation of shape &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(batch, 1024, 128)&lt;/code&gt;, where &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;1024&lt;/code&gt;
is the number of FFT coefficients and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;128&lt;/code&gt; the number of frames.&lt;/p&gt;

&lt;p&gt;The spectrogram is then processed by a U-Net architecture with skip connections.&lt;/p&gt;

&lt;p&gt;Finally, the reprsentation is projected into a high-dimensional space and sparsified by choosing the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;N&lt;/code&gt; top-k elements in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(batch, 4096, 128)&lt;/code&gt; tensor.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;⚠️ The astute reader will notice that we’re working with the very frame-based representation we earlier warned against. There are still steps that need to be taken to fully free ourselves from the fixed-size grid.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3 id=&quot;decoder&quot;&gt;Decoder&lt;/h3&gt;

&lt;p&gt;Beginning with our highly-sparse &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(batch, 4096, 128)&lt;/code&gt; representation, we “break apart” this tensor into &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;N&lt;/code&gt; one-hot vectors. The current
experiment sets &lt;a href=&quot;https://github.com/JohnVinyard/matching-pursuit/blob/main/experiments/e_2023_10_2/experiment.py#L36&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;N = 64&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Put another way, we now have &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;N&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;64&lt;/code&gt; one-hot vectors, ideally representing “events” for each element in the batch of examples. Next, we embed these high-dimensional one-hot vectors into lower-dimensional, dense vectors, and generate the audio for each event
independently from there.&lt;/p&gt;

&lt;p&gt;First, we generate an impulse, which amounts to band-limited noise, representing the attack, breath, or some other injection of energy into a system.&lt;/p&gt;

&lt;p&gt;Next we create a linear combination of a number of pre-generated resonance patterns, which amount to four different waveforms (sine, square, sawtooth, triangle) sampled at many different frequencies within the range of fundamental frequencies for most acoustic instruments, in this case, from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;40 hz&lt;/code&gt; to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;4000 hz&lt;/code&gt;.  This represents the transfer function or impulse response of whatever system, or instrument, the impulse’s energy is injected into.&lt;/p&gt;

&lt;p&gt;We also choose a decay value, which determines the &lt;em&gt;envelope&lt;/em&gt; of the resonance and apply the envelope to the resonance we’ve generated.&lt;/p&gt;

&lt;p&gt;Each impulse and resonance are then convolved to produce a single event.&lt;/p&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(batch, 4096, 128)&lt;/code&gt; encoding is also summed along its time-axis, such that it becomes &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(batch, 4096)&lt;/code&gt;, and is then embedded into
a lower-dimensional, dense vector. This vector is passed to a sub-network which chooses a linear combination of impulse responses for
convolution-based reverb. Each event is also convolved with this room response kernel.&lt;/p&gt;

&lt;p&gt;We end with a tensor of shape &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(batch, n_events, 32768)&lt;/code&gt;, with each channel along the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;n_events&lt;/code&gt; dimension representing&lt;/p&gt;

&lt;h3 id=&quot;training&quot;&gt;Training&lt;/h3&gt;

&lt;p&gt;Instead of using MSE loss, each “event channel” loss is computed independently.  There’s much more work to do to both refine this approach and understand better why it helps, but it does seem to encourage events to cover independent/orthogonal parts of the time-frequency plane.  The model used to produce the encodings and audio in this post was trained for about 24 hours.&lt;/p&gt;

&lt;h2 id=&quot;random-generation&quot;&gt;Random Generation&lt;/h2&gt;

&lt;p&gt;Finally, we can understand the model a little better (and have some fun) by generating random sparse tensors and listening to the results.&lt;/p&gt;

&lt;div class=&quot;language-python 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;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;conjure&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;audio_conjure&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;encoding_1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;get_encoding&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;example_7c&apos;&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;n&quot;&gt;audio_conjure&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;conjure_storage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;random_generation&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;identifier&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;torch&lt;/span&gt;
    &lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;models.resonance&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;model&lt;/span&gt;
    &lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;modules&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sparsify2&lt;/span&gt;
    &lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;util&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;playable&lt;/span&gt;
    &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;zounds&lt;/span&gt;
    &lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;torch.nn&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;functional&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;F&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;n_samples&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;15&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;encoding&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;torch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;zeros&lt;/span&gt;&lt;span class=&quot;p&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;mi&quot;&gt;4096&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;128&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;normal_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;encoding_1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mean&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;encoding_1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;encoded&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;packed&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;one_hot&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sparsify2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;encoding&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n_to_keep&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;64&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;audio&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;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;generate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;encoded&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;one_hot&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;packed&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;audio&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;torch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sum&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;audio&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dim&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;n&quot;&gt;keepdim&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;audio&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;playable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;audio&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;zounds&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SR22050&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;n&quot;&gt;n_samples&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;bio&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;audio&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;encode&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;bio&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;read&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;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;random_generation&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;random_1d&apos;&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;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;random_generation&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;meta&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;random_1d&apos;&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;div id=&quot;conjure-id-bc0f0218f46ff1142c847996ef3df20907bdb6a2_d50e2d54a6b0aad028202560f97409989c1152c4&quot; data-conjure=&quot;{&amp;quot;key&amp;quot;: &amp;quot;bc0f0218f46ff1142c847996ef3df20907bdb6a2_d50e2d54a6b0aad028202560f97409989c1152c4&amp;quot;, &amp;quot;public_uri&amp;quot;: &amp;quot;https://zounds-blog-media.s3.amazonaws.com/bc0f0218f46ff1142c847996ef3df20907bdb6a2_d50e2d54a6b0aad028202560f97409989c1152c4&amp;quot;, &amp;quot;content_type&amp;quot;: &amp;quot;audio/wav&amp;quot;, &amp;quot;feed_uri&amp;quot;: &amp;quot;/feed/bc0f0218f46ff1142c847996ef3df20907bdb6a2&amp;quot;, &amp;quot;func_name&amp;quot;: &amp;quot;random_generation&amp;quot;, &amp;quot;func_identifier&amp;quot;: &amp;quot;bc0f0218f46ff1142c847996ef3df20907bdb6a2&amp;quot;}&quot;&gt;&lt;/div&gt;

&lt;p&gt;Another random generation result:&lt;/p&gt;

&lt;div class=&quot;language-python 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;n&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;random_generation&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;random_3d&apos;&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;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;random_generation&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;meta&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;random_3d&apos;&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;div id=&quot;conjure-id-bc0f0218f46ff1142c847996ef3df20907bdb6a2_062ba60acdabd9871ccc7e779df3d260932ecfcb&quot; data-conjure=&quot;{&amp;quot;key&amp;quot;: &amp;quot;bc0f0218f46ff1142c847996ef3df20907bdb6a2_062ba60acdabd9871ccc7e779df3d260932ecfcb&amp;quot;, &amp;quot;public_uri&amp;quot;: &amp;quot;https://zounds-blog-media.s3.amazonaws.com/bc0f0218f46ff1142c847996ef3df20907bdb6a2_062ba60acdabd9871ccc7e779df3d260932ecfcb&amp;quot;, &amp;quot;content_type&amp;quot;: &amp;quot;audio/wav&amp;quot;, &amp;quot;feed_uri&amp;quot;: &amp;quot;/feed/bc0f0218f46ff1142c847996ef3df20907bdb6a2&amp;quot;, &amp;quot;func_name&amp;quot;: &amp;quot;random_generation&amp;quot;, &amp;quot;func_identifier&amp;quot;: &amp;quot;bc0f0218f46ff1142c847996ef3df20907bdb6a2&amp;quot;}&quot;&gt;&lt;/div&gt;

&lt;h2 id=&quot;next-steps&quot;&gt;Next Steps&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;A single, low-dimensional and dense “context” vector for each audio segment might allow similar sparse vectors to represent related musical sequences played on different instruments, or in different rooms&lt;/li&gt;
  &lt;li&gt;The “physical model” I’ve developed is very rudimentary.  More study into existing physical modelling techniques might produce a far superior model&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;thanks-for-reading&quot;&gt;Thanks for Reading!&lt;/h2&gt;

&lt;p&gt;If you’d like to cite this article&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;@misc{vinyard2023audio,
  author = {Vinyard, John},
  title = {Sparse Interpetable Audio},
  url = {https://JohnVinyard.github.io/machine-learning/2023/11/15/sparse-physical-model.html},
  year = {2023}
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
</description>
        <pubDate>Wed, 15 Nov 2023 12:00:00 +0000</pubDate>
        <link>http://johnvinyard.github.io/machine-learning/2023/11/15/sparse-physical-model.html</link>
        <guid isPermaLink="true">http://johnvinyard.github.io/machine-learning/2023/11/15/sparse-physical-model.html</guid>
        
        
        <category>machine-learning</category>
        
      </item>
    
      <item>
        <title>A Music Vocoder Using Conditional Generative Adversarial Networks</title>
        <description>&lt;p&gt;The last couple of posts have been all about audio analysis and search but in
this one, I’ll return to some work that gets me a little closer to my ultimate 
goal, which is building synthesizers with high-level parameters, allowing the 
production of audio ranging from convincingly-real renderings of traditional 
acoustic instruments to novel synthetic textures and sounds.&lt;/p&gt;

&lt;p&gt;There’s clearly a lot of value in symbolic (usually MIDI-based) approaches to 
music generation but I feel there’s incredible promise and flexibility in 
producing audio directly.  Some incredibly moving sequences of sound are also 
very difficult to score, and not every valid or valuable piece of music can be 
expressed as a collection of discrete notes or events.&lt;/p&gt;

&lt;p&gt;All of the code for this, and future experiments involving music synthesis, can 
be found in &lt;a href=&quot;https://github.com/JohnVinyard/music-synthesis&quot;&gt;this GitHub repo&lt;/a&gt;.&lt;/p&gt;

&lt;h1 id=&quot;a-break-in-the-case&quot;&gt;A Break in the Case&lt;/h1&gt;

&lt;p&gt;I had already been exploring the use of generative adversarial networks to produce
very short and noisy snippets of Bach piano music when I read the 
&lt;a href=&quot;https://arxiv.org/abs/1802.04208&quot;&gt;WaveGAN&lt;/a&gt; paper, which was the first 
published application of GANs to raw audio that I’m aware of.  This was a very 
exciting and insightful paper, but I got &lt;em&gt;really&lt;/em&gt; excited last year when I 
read a pair of papers that had something very cool in common.&lt;/p&gt;

&lt;p&gt;Those were:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://arxiv.org/abs/1910.06711&quot;&gt;MelGAN: Generative Adversarial Networks for Conditional Waveform Synthesis&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://arxiv.org/abs/1909.11646&quot;&gt;High Fidelity Speech Synthesis with Adversarial Networks&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Both papers focused primarily on speech (the MelGAN paper included
piano samples as an aside) but the interesting feature they shared is that 
they were both training strongly-conditioned GANs using low-frequency audio 
features as input to the generator, which would then output high-frequency raw 
audio samples.&lt;/p&gt;

&lt;p&gt;What really excited me about these papers is that they seemed to lay the
foundation for a very flexible two-stage music synthesis pipeline.  At its
simplest, two trained networks would be required:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;A strongly-conditioned generator that can produce convincing audio from 
low-frequency features&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;Another network, unconditioned or perhaps conditioned on yet higher-level 
features, that could produce plausible sequences of these low-frequency 
features&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This post will focus on the first stage in that pipeline, with a subsequent post
covering the generation of novel musical sequences.&lt;/p&gt;

&lt;p&gt;Since my focus is music, I chose to use the 
&lt;a href=&quot;https://homes.cs.washington.edu/~thickstn/stats.html&quot;&gt;MusicNet dataset&lt;/a&gt;, 
which consists of around 34 hours of classical music recordings.  As my 
low-frequency conditioning feature, I chose to use 128-bin Mel-frequency 
spectrograms.  Here are a couple examples of audio from the dataset, alongside 
the accompanying low-frequency Mel spectrograms:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://generation-report-realmelganexperiment.s3-us-west-1.amazonaws.com/89855e_feature.png&quot; alt=&quot;spectrogram&quot; /&gt;&lt;/p&gt;
&lt;audio controls=&quot;&quot; src=&quot;https://generation-report-realmelganexperiment.s3-us-west-1.amazonaws.com/89855e_real_audio.ogg&quot;&gt;&lt;/audio&gt;

&lt;p&gt;&lt;img src=&quot;https://generation-report-onedimddspexperiment.s3-us-west-1.amazonaws.com/54a671_feature.png&quot; alt=&quot;spectrogram&quot; /&gt;&lt;/p&gt;
&lt;audio controls=&quot;&quot; src=&quot;https://generation-report-onedimddspexperiment.s3-us-west-1.amazonaws.com/54a671_real_audio.ogg&quot;&gt;&lt;/audio&gt;

&lt;h1 id=&quot;first-attempt-assessing-the-melgan-for-the-task&quot;&gt;First Attempt: Assessing the MelGAN for the Task&lt;/h1&gt;
&lt;p&gt;The first and most obvious approach would be to use the architecture described in 
the MelGAN paper, mostly as-is, and assess its performance on the task of 
producing musical signals.&lt;/p&gt;

&lt;p&gt;The MelGAN paper focuses primarily on speech but you can hear some examples of 
both speech and music generation from the model 
&lt;a href=&quot;https://melgan-neurips.github.io/&quot;&gt;on this page&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I had reason to be skeptical about the architecture’s performance on fairly 
diverse musical signals based on the piano examples included in that page, but 
decided starting with the MelGAN architecture would serve as a good baseline.&lt;/p&gt;

&lt;p&gt;The MelGAN paper uses a single generator that makes use of dilated convolutions
to greatly expand the receptive field of its layers, as well as &lt;em&gt;multiple&lt;/em&gt; 
discriminators that operate at a few different time scales/sampling rates. Notably, 
the discriminators don’t just produce a single judgement per input example; they 
produce multiple, overlapping judgements in the time domain.&lt;/p&gt;

&lt;p&gt;The generator is &lt;strong&gt;fully convolutional&lt;/strong&gt;, meaning that it makes no assumptions 
about the input or output time dimension.  This is a handy feature in a vocoder, 
since we can pass it a spectrogram of virtually any length at inference time.&lt;br /&gt;
During training, windows of 8192 samples at 22050hz (about a third of a second) 
are used.&lt;/p&gt;

&lt;p&gt;In the usual GAN setting, the generator is only trying to minimize or maximize 
some scalar value that the discriminator computes to indicate how close to the 
real training data the synthetic data lies.  The MelGAN paper adds to this a 
&lt;strong&gt;feature-matching loss&lt;/strong&gt;, in which the generator tries to minimize the L1 
distance between discriminator feature maps, or internal activations, for 
synthetic and real data.&lt;/p&gt;

&lt;p&gt;It’s interesting to note that the discriminator does not have access to the 
conditioning information in the original MelGAN formulation; it is purely 
computing the distance between real and fake examples.  When the generator loss 
is computed, discriminator feature maps are compared within the same batch, so 
that feature maps from real audio samples are being compared against feature maps 
from audio generated based on spectrograms derived from that same audio.&lt;/p&gt;

&lt;p&gt;As you can hear, the generator captured the overall structure of the audio 
fairly well after around 12 hours of training, but produced reproductions that 
were somewhat metallic and noisy:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://generation-report-realmelganexperiment.s3-us-west-1.amazonaws.com/89855e_feature.png&quot; alt=&quot;MelGAN spectrogram&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Real&lt;/p&gt;
&lt;audio controls=&quot;&quot; src=&quot;https://generation-report-realmelganexperiment.s3-us-west-1.amazonaws.com/89855e_real_audio.ogg&quot;&gt;&lt;/audio&gt;

&lt;p&gt;Generated&lt;/p&gt;
&lt;audio controls=&quot;&quot; src=&quot;https://generation-report-realmelganexperiment.s3-us-west-1.amazonaws.com/89855e_fake_audio.ogg&quot;&gt;&lt;/audio&gt;

&lt;p&gt;&lt;img src=&quot;https://generation-report-realmelganexperiment.s3-us-west-1.amazonaws.com/515e4a_feature.png&quot; alt=&quot;MelGAN spectrogram&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Real&lt;/p&gt;
&lt;audio controls=&quot;&quot; src=&quot;https://generation-report-realmelganexperiment.s3-us-west-1.amazonaws.com/515e4a_real_audio.ogg&quot;&gt;&lt;/audio&gt;

&lt;p&gt;Generated&lt;/p&gt;
&lt;audio controls=&quot;&quot; src=&quot;https://generation-report-realmelganexperiment.s3-us-west-1.amazonaws.com/515e4a_fake_audio.ogg&quot;&gt;&lt;/audio&gt;

&lt;p&gt;&lt;a href=&quot;https://generation-report-realmelganexperiment.s3-us-west-1.amazonaws.com/index.html&quot;&gt;More generated samples can be heard here.&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;an-alternate-architecture-geared-toward-music&quot;&gt;An Alternate Architecture Geared Toward Music&lt;/h2&gt;

&lt;p&gt;After evaluating the original MelGAN architecture’s performance on MusicNet, 
and &lt;a href=&quot;https://github.com/JohnVinyard/music-synthesis/tree/master/featuresynth/experiment&quot;&gt;trying quite a few alternative approaches&lt;/a&gt;,
I settled on the some modifications to the original experiment that resulted in 
more pleasing/musical audio.&lt;/p&gt;

&lt;p&gt;Over the course of several experiments, I found that giving the discriminator 
access to the conditioning data generally accelerated training and made for 
better end results.  I also found that building some strong priors into both the 
generator and discriminator architectures seemed to help with producing crisper 
and more pleasant audio.&lt;/p&gt;

&lt;p&gt;Before we dive in, code for the top-level parameters of this experiment can 
be found &lt;a href=&quot;https://github.com/JohnVinyard/music-synthesis/blob/master/featuresynth/experiment/multiscale.py#L24&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;a-conditioned-discriminator&quot;&gt;A Conditioned Discriminator&lt;/h3&gt;

&lt;p&gt;First, several experiments seemed to indicate that allowing the discriminator 
access to the conditioning spectrograms accelerated training and made for better 
end results.  It’d be worth an ablation study with my best-performing generator 
and discriminator to find out if this impression is true, but I haven’t yet 
performed one.&lt;/p&gt;

&lt;h3 id=&quot;strong-audio-priors&quot;&gt;Strong Audio Priors&lt;/h3&gt;

&lt;p&gt;While one of the promises of deep learning is models that learn from scratch, 
there may be cases where aspects of human perception are difficult or impossible 
to learn without some strong guidance.  With that in mind, and in hopes of 
accelerating training, my generator and discriminator architectures have in-built 
priors based on two facts:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Musical audio contains information at many different time-scales&lt;/li&gt;
  &lt;li&gt;Our perception of sound depends a great deal on a decomposition of audio into
many frequency bands by the cochlea&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;multi-scale-generator-and-discriminator&quot;&gt;Multi-Scale Generator and Discriminator&lt;/h4&gt;

&lt;p&gt;To address the problem of information at vastly different time scales, I saw an 
opportunity to try a multi-scale analysis and synthesis idea that mirrors 
multi-resolution wavelet transforms or the 
&lt;a href=&quot;https://grrrr.org/research/software/nsgt/&quot;&gt;Non-stationary Gabor Transform&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In most raw audio-producing neural network architectures I’ve encountered thus 
far, all audio and thus all frequency bands are produced at the same sampling 
rate.  I wanted to try an architecture where groups of frequency bands were 
produced at an &lt;em&gt;appropriate&lt;/em&gt; sampling rate, such that low frequency bands could be 
faithfully rendered with significantly fewer samples and only up-sampled at 
the last possible moment.  My hunch was that over-sampled filters producing lower 
frequencies were likely to produce a lot of artifacts.&lt;/p&gt;

&lt;p&gt;More concretely, at 22050hz, we might represent one second of audio with the 
following five bands or channels:&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th style=&quot;text-align: left&quot;&gt;N samples&lt;/th&gt;
      &lt;th style=&quot;text-align: left&quot;&gt;Start Hz&lt;/th&gt;
      &lt;th&gt;End Hz&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;1378&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;0&lt;/td&gt;
      &lt;td&gt;689&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;2756&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;689&lt;/td&gt;
      &lt;td&gt;1378&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;5512&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;1378&lt;/td&gt;
      &lt;td&gt;2756&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;11025&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;2756&lt;/td&gt;
      &lt;td&gt;5512&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;22050&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;5512&lt;/td&gt;
      &lt;td&gt;11025&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;So, we might decompose the following audio samples at 22050hz…&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://music-vocoder-blog-post.s3.amazonaws.com/audio_full.png&quot; alt=&quot;audio&quot; /&gt;&lt;/p&gt;

&lt;p&gt;…into the following five bands&lt;/p&gt;

&lt;p&gt;0hz - 689hz&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://music-vocoder-blog-post.s3.amazonaws.com/audio_band_0.png&quot; alt=&quot;band&quot; /&gt;&lt;/p&gt;
&lt;audio controls=&quot;&quot; src=&quot;https://music-vocoder-blog-post.s3.amazonaws.com/samples_band_0.wav&quot;&gt;&lt;/audio&gt;

&lt;p&gt;689hz - 1378hz&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://music-vocoder-blog-post.s3.amazonaws.com/audio_band_1.png&quot; alt=&quot;band&quot; /&gt;&lt;/p&gt;
&lt;audio controls=&quot;&quot; src=&quot;https://music-vocoder-blog-post.s3.amazonaws.com/samples_band_1.wav&quot;&gt;&lt;/audio&gt;

&lt;p&gt;1378hz - 2756hz&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://music-vocoder-blog-post.s3.amazonaws.com/audio_band_2.png&quot; alt=&quot;band&quot; /&gt;&lt;/p&gt;
&lt;audio controls=&quot;&quot; src=&quot;https://music-vocoder-blog-post.s3.amazonaws.com/samples_band_2.wav&quot;&gt;&lt;/audio&gt;

&lt;p&gt;2756hz - 5512hz&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://music-vocoder-blog-post.s3.amazonaws.com/audio_band_3.png&quot; alt=&quot;band&quot; /&gt;&lt;/p&gt;
&lt;audio controls=&quot;&quot; src=&quot;https://music-vocoder-blog-post.s3.amazonaws.com/samples_band_3.wav&quot;&gt;&lt;/audio&gt;

&lt;p&gt;5512hz - 11025hz&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://music-vocoder-blog-post.s3.amazonaws.com/audio_band_4.png&quot; alt=&quot;band&quot; /&gt;&lt;/p&gt;
&lt;audio controls=&quot;&quot; src=&quot;https://music-vocoder-blog-post.s3.amazonaws.com/samples_band_4.wav&quot;&gt;&lt;/audio&gt;

&lt;p&gt;For this experiment, the top-level generator was composed of five distinct 
frequency band generators that produced audio on each of the five time scales 
represented above.  Each sub-generator is conditioned on the same input 
spectrogram.&lt;/p&gt;

&lt;p&gt;Similarly, the discriminator is composed of five distinct frequency band 
discriminators that analyze audio on each of the five time scales represented 
above.  Each of these also have access to the conditioning spectrogram.&lt;/p&gt;

&lt;h4 id=&quot;frozen-filter-bank-layers&quot;&gt;Frozen Filter Bank Layers&lt;/h4&gt;

&lt;p&gt;To mimic the decomposition of audio into constituent frequency bands by the 
cochlea, each sub-generator and sub-discriminator includes a frozen layer 
(i.e., a layer with no learn-able parameters) 
representing a bank of finite impulse response filters.  This 
is similar to an approach used in the paper &lt;a href=&quot;https://arxiv.org/abs/1808.00158&quot;&gt;Speaker Recognition from Raw Waveform with SincNet&lt;/a&gt;
where the first layer of a speech recognition model is initialized as a bank of 
finite impulse response filters, parameterized by the filters’ center 
frequencies and bandwidths.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://music-vocoder-blog-post.s3.amazonaws.com/filters.png&quot; alt=&quot;filters&quot; /&gt;&lt;/p&gt;

&lt;p&gt;In this case, the discriminator for each time scale will have a frozen first 
layer initialized as a linear-spaced filter bank spanning the frequency interval 
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;[nyquist / 2, nyquist]&lt;/code&gt; except for the lowest-frequency time scale, whose 
filter bank will span &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;[0, nyquist]&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The generator for each time scale will also include one of these frozen filter 
bank layers, this time as its &lt;em&gt;last layer&lt;/em&gt;.  The generator will produce audio 
by performing a transposed convolution with this layer as its last step, 
essentially summing together the excitations from each filter bank channel.&lt;/p&gt;

&lt;p&gt;During training, the discriminator views audio as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;N&lt;/code&gt; distinct bands at different 
time scales and the generator produces this same representation.  Only 
during inference does each generated band need to be resampled to the desired 
sample rate (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;22050hz&lt;/code&gt; in our case) and summed together to produce the final 
output.&lt;/p&gt;

&lt;h3 id=&quot;conditioned-audio-examples&quot;&gt;Conditioned Audio Examples&lt;/h3&gt;
&lt;p&gt;Now that we’ve covered the modifications to the generator and discriminator 
architectures, let’s listen to some samples generated by the new model:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://generation-report-filterbankmultiscaleexperiment.s3.amazonaws.com/deb75f_feature.png&quot; alt=&quot;MelGAN spectrogram&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Real&lt;/p&gt;
&lt;audio controls=&quot;&quot; src=&quot;https://generation-report-filterbankmultiscaleexperiment.s3.amazonaws.com/deb75f_real_audio.ogg&quot;&gt;&lt;/audio&gt;

&lt;p&gt;Generated&lt;/p&gt;
&lt;audio controls=&quot;&quot; src=&quot;https://generation-report-filterbankmultiscaleexperiment.s3.amazonaws.com/deb75f_fake_audio.ogg&quot;&gt;&lt;/audio&gt;

&lt;p&gt;&lt;img src=&quot;https://generation-report-filterbankmultiscaleexperiment.s3.amazonaws.com/3370f6_feature.png&quot; alt=&quot;MelGAN spectrogram&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Real&lt;/p&gt;
&lt;audio controls=&quot;&quot; src=&quot;https://generation-report-filterbankmultiscaleexperiment.s3.amazonaws.com/3370f6_real_audio.ogg&quot;&gt;&lt;/audio&gt;

&lt;p&gt;Generated&lt;/p&gt;
&lt;audio controls=&quot;&quot; src=&quot;https://generation-report-filterbankmultiscaleexperiment.s3.amazonaws.com/3370f6_fake_audio.ogg&quot;&gt;&lt;/audio&gt;

&lt;p&gt;&lt;img src=&quot;https://generation-report-filterbankmultiscaleexperiment.s3.amazonaws.com/35f29c_feature.png&quot; alt=&quot;MelGAN spectrogram&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Real&lt;/p&gt;
&lt;audio controls=&quot;&quot; src=&quot;https://generation-report-filterbankmultiscaleexperiment.s3.amazonaws.com/35f29c_real_audio.ogg&quot;&gt;&lt;/audio&gt;

&lt;p&gt;Generated&lt;/p&gt;
&lt;audio controls=&quot;&quot; src=&quot;https://generation-report-filterbankmultiscaleexperiment.s3.amazonaws.com/35f29c_fake_audio.ogg&quot;&gt;&lt;/audio&gt;

&lt;p&gt;&lt;img src=&quot;https://generation-report-filterbankmultiscaleexperiment.s3.amazonaws.com/79c560_feature.png&quot; alt=&quot;MelGAN spectrogram&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Real&lt;/p&gt;
&lt;audio controls=&quot;&quot; src=&quot;https://generation-report-filterbankmultiscaleexperiment.s3.amazonaws.com/79c560_real_audio.ogg&quot;&gt;&lt;/audio&gt;

&lt;p&gt;Generated&lt;/p&gt;
&lt;audio controls=&quot;&quot; src=&quot;https://generation-report-filterbankmultiscaleexperiment.s3.amazonaws.com/79c560_fake_audio.ogg&quot;&gt;&lt;/audio&gt;

&lt;p&gt;&lt;img src=&quot;https://generation-report-filterbankmultiscaleexperiment.s3.amazonaws.com/b4cc04_feature.png&quot; alt=&quot;MelGAN spectrogram&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Real&lt;/p&gt;
&lt;audio controls=&quot;&quot; src=&quot;https://generation-report-filterbankmultiscaleexperiment.s3.amazonaws.com/b4cc04_real_audio.ogg&quot;&gt;&lt;/audio&gt;

&lt;p&gt;Generated&lt;/p&gt;
&lt;audio controls=&quot;&quot; src=&quot;https://generation-report-filterbankmultiscaleexperiment.s3.amazonaws.com/b4cc04_fake_audio.ogg&quot;&gt;&lt;/audio&gt;

&lt;p&gt;&lt;img src=&quot;https://generation-report-filterbankmultiscaleexperiment.s3.amazonaws.com/afbb72_feature.png&quot; alt=&quot;MelGAN spectrogram&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Real&lt;/p&gt;
&lt;audio controls=&quot;&quot; src=&quot;https://generation-report-filterbankmultiscaleexperiment.s3.amazonaws.com/afbb72_real_audio.ogg&quot;&gt;&lt;/audio&gt;

&lt;p&gt;Generated&lt;/p&gt;
&lt;audio controls=&quot;&quot; src=&quot;https://generation-report-filterbankmultiscaleexperiment.s3.amazonaws.com/afbb72_fake_audio.ogg&quot;&gt;&lt;/audio&gt;

&lt;p&gt;These samples tend to be less noisy and metallic-sounding than those produced 
with the baseline MelGAN architecture.  To my ear, they are more faithful to 
the originals, and more musically pleasant.  They aren’t without their problems, 
however.  There are some significant phase issues, possibly due to the fact that 
each generator band is produced independently.  The model also seems to have 
trouble faithfully reproducing lower frequencies which I find somewhat 
puzzling and surprising.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://generation-report-filterbankmultiscaleexperiment.s3.amazonaws.com/index.html&quot;&gt;You can hear more generated examples here.&lt;/a&gt;&lt;/p&gt;

&lt;h3 id=&quot;future-work&quot;&gt;Future Work&lt;/h3&gt;

&lt;p&gt;Overall, the results are promising and lay the groundwork for a first step in 
our two-stage music synthesis pipeline.  Next steps will include:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Beginning to work on contioned or unconditioned Mel spectrogram generation 
using this trained model as the spectrogram-to-audio vocoder&lt;/li&gt;
  &lt;li&gt;Exploring strategies for mitigating phase issues in this model&lt;/li&gt;
  &lt;li&gt;Exploring strategies for reproducing low frequencies more faithfully&lt;/li&gt;
  &lt;li&gt;Performing a more principled comparison of the original MelGAN model with 
this one, including analysis of parameter counts, audio generation performance 
and a more careful side-by-side analysis of generated samples&lt;/li&gt;
&lt;/ul&gt;
</description>
        <pubDate>Wed, 01 Apr 2020 12:00:00 +0000</pubDate>
        <link>http://johnvinyard.github.io/synthesis/2020/04/01/gan-vocoder.html</link>
        <guid isPermaLink="true">http://johnvinyard.github.io/synthesis/2020/04/01/gan-vocoder.html</guid>
        
        
        <category>synthesis</category>
        
      </item>
    
      <item>
        <title>Cochlea: A RESTful API for Annotating Audio</title>
        <description>&lt;p&gt;&lt;a href=&quot;https://github.com/JohnVinyard/annotate-api&quot;&gt;Cochlea&lt;/a&gt; is an early-stage, 
RESTful API that allows users to annotate audio files on the internet.&lt;br /&gt;
Segments or time intervals can be annotated with text tags or other arbitrary 
data.  This may not sound very exciting on its own, but I believe that these 
simple primitives make possible incredibly diverse applications tailored to 
the needs of electronic musicians, sound designers and other folks interested 
in playing with sound.&lt;/p&gt;

&lt;p&gt;Before starting to dream aloud about the endless possibilities, a little about 
how I arrived here…&lt;/p&gt;

&lt;h1 id=&quot;false-starts&quot;&gt;False Starts&lt;/h1&gt;

&lt;p&gt;I’m interested in building tools that allow musicians, sound designers 
and machine learning researchers to explore libraries of audio samples in new 
and intuitive ways that go far beyond traditional tag-based text searches.  Text 
can be a great starting point, but indexes based on perceptual audio similarity 
or other features such as pitch or timbre offer much more exciting possibilities.&lt;br /&gt;
Whereas text-based approaches require painstaking manual tagging of vast 
quantities of audio, indexes that organize sound based on features derived 
directly from audio samples make it feasible to imagine the entire internet as 
your sample library!&lt;/p&gt;

&lt;p&gt;With this ideal in mind, I’ve started and discarded several audio similarity 
search applications due to overly-rigid approaches.  I’ve often settled on a 
single feature or similarity metric I think will work well and based the 
entire application around it.  Inevitably, the search works well in some contexts 
and not so well in others.  In addition, I’ve failed time and again to make 
indexing &lt;em&gt;new&lt;/em&gt; sounds painless and I’ve eschewed more basic but necessary 
features, like allowing users to tag audio and search across those tags.&lt;/p&gt;

&lt;p&gt;The common theme in all these ventures has been a lack of flexibility due to 
assumptions I’ve baked in much too early in the process.  The RESTful API I 
introduced above is one possible answer to this problem, providing a simple 
platform on which all sorts of diverse applications might be built.&lt;/p&gt;

&lt;p&gt;Now, to dig into the details…&lt;/p&gt;

&lt;h1 id=&quot;api-resources&quot;&gt;API Resources&lt;/h1&gt;

&lt;p&gt;The experimental Cochlea API consists of just three simple resources:&lt;/p&gt;

&lt;h2 id=&quot;sounds&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/sounds&lt;/code&gt;&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;https://cochlea-example-app-images.s3.amazonaws.com/waveform.png&quot; alt=&quot;Sound&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sound&lt;/code&gt; resources are really just pointers to audio that’s hosted somewhere out 
there on the internet.  While it’s not totally necessary, ideally the servers 
hosting the audio content will conform to a basic interface:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;The servers should support 
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTTP/Range_requests&quot;&gt;byte-range requests&lt;/a&gt;, 
making partial downloads of the files possible&lt;/li&gt;
  &lt;li&gt;The servers should allow for cross-origin requests by setting appropriate 
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS&quot;&gt;CORS headers&lt;/a&gt;, making 
it possible for front-end applications to request the audio and play it using 
the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Web_Audio_API&quot;&gt;Web Audio API&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It’s also worth noting that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sound&lt;/code&gt; identifiers are ordered according to the 
time they were created, which will come in handy when we discuss &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;featurebot&lt;/code&gt; 
and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;aggregator&lt;/code&gt; users in a bit.&lt;/p&gt;

&lt;h2 id=&quot;annotations&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/annotations&lt;/code&gt;&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;https://cochlea-example-app-images.s3.amazonaws.com/annotation-tags.png&quot; alt=&quot;Annotations&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;annotations&lt;/code&gt; describe all or part of a sound using text tags or any other 
arbitrary piece of data.  The Cochlea API natively supports the creation 
and storage of text tags, but other arbitrary data describing sound segments can 
be hosted elsewhere.  We might create annotations tagging a segment of audio 
as containing female speech or create an annotation that highlights an 
interesting segment of a longer audio sequence.  We might also compute 
dense numerical features from the raw audio samples (such as short-time 
Fourier transform data, chroma, or MFCC data) and store them as NumPy arrays 
in an S3 bucket.&lt;/p&gt;

&lt;p&gt;Just as servers hosting audio data should conform to a particular interface, 
servers hosting dense features or other arbitrary annotation data should ideally 
support byte-range and CORS requests.&lt;/p&gt;

&lt;p&gt;Like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sound&lt;/code&gt; identifiers, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;annotation&lt;/code&gt; identifiers are ordered according to the 
time they were created, which will again come into play when we discuss 
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;featurebot&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;aggregator&lt;/code&gt; users a little later.&lt;/p&gt;

&lt;h2 id=&quot;users&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/users&lt;/code&gt;&lt;/h2&gt;

&lt;p&gt;The third and final resource type we’ll discuss is the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;user&lt;/code&gt; type.  There are 
a few different types to cover, and I think that this is where the platform 
&lt;em&gt;really&lt;/em&gt; starts to get interesting.&lt;/p&gt;

&lt;h3 id=&quot;humans&quot;&gt;Humans&lt;/h3&gt;

&lt;p&gt;Humans are the first and most obvious user type.  These users can read 
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sound&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;annotation&lt;/code&gt; resources and can create &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;annotation&lt;/code&gt; resources of 
their own, usually using textual tags added using some graphical user interface.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://cochlea-example-app-images.s3.amazonaws.com/create-annotation.png&quot; alt=&quot;Creating an Annotation&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;datasets&quot;&gt;Datasets&lt;/h3&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dataset&lt;/code&gt; users represent some sound collection or repository on the internet.&lt;br /&gt;
Some examples might include well-known audio datasets used by the machine 
learning community, such as 
&lt;a href=&quot;https://magenta.tensorflow.org/datasets/nsynth&quot;&gt;NSynth&lt;/a&gt; or 
&lt;a href=&quot;https://homes.cs.washington.edu/~thickstn/musicnet.html&quot;&gt;MusicNet&lt;/a&gt;.&lt;br /&gt;
Since these datasets often include structured data about their audio files, 
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dataset&lt;/code&gt; users will generally create both &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sounds&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;annotations&lt;/code&gt;.  For 
example, the MusicNet dataset includes detailed information about each note 
played in each piece, include onset time, duration, instrument and pitch.&lt;br /&gt;
The NSynth dataset tags each note with certain characteristics such as 
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;acoustic&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;percussive&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;electronic&lt;/code&gt;.&lt;/p&gt;

&lt;h3 id=&quot;featurebots&quot;&gt;Featurebots&lt;/h3&gt;

&lt;p&gt;&lt;img src=&quot;https://cochlea-example-app-images.s3.amazonaws.com/chroma_bot.png&quot; alt=&quot;Chroma&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;featurebot&lt;/code&gt; users listen to some or all &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sound&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;annotation&lt;/code&gt; resources, 
optionally filtering by the user that created the resource, and compute features, 
such as onset times, &lt;a href=&quot;https://en.wikipedia.org/wiki/Chroma_feature&quot;&gt;chroma&lt;/a&gt; or 
&lt;a href=&quot;https://en.wikipedia.org/wiki/Mel-frequency_cepstrum&quot;&gt;MFCC&lt;/a&gt; features and create 
pointers to the computed/derived data using new &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;annotation&lt;/code&gt; resources.  A few 
example applications might include:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;a bot that computes onset times using 
&lt;a href=&quot;https://librosa.github.io/librosa/generated/librosa.onset.onset_detect.html&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;librosa&lt;/code&gt;’s&lt;/a&gt; 
onset detection functionality&lt;/li&gt;
  &lt;li&gt;a bot that computes short-time Fourier transform data for each sound&lt;/li&gt;
  &lt;li&gt;a bot that listens for annotations from the short-time Fourier transform bot 
and computes &lt;a href=&quot;https://en.wikipedia.org/wiki/Chroma_feature&quot;&gt;chroma&lt;/a&gt; or 
&lt;a href=&quot;https://en.wikipedia.org/wiki/Mel-frequency_cepstrum&quot;&gt;MFCC&lt;/a&gt; data, 
thus beginning to form a distributed computation graph that transforms the raw
audio&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Since sounds and annotations have identifiers ordered according to the time 
they were created, bots need only remember the last id they processed and poll 
against &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sound&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;annotation&lt;/code&gt; resources to continually compute new features 
for incoming resources.&lt;/p&gt;

&lt;h3 id=&quot;aggregators&quot;&gt;Aggregators&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;https://s3-us-west-1.amazonaws.com/unsupervised-audio-embeddings-talk/tree.gv.svg&quot; alt=&quot;Hyperplane Tree&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;aggregator&lt;/code&gt; users are similar to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;featurebot&lt;/code&gt; users in that they listen to a 
stream of some or all &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sound&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;annotation&lt;/code&gt; resources, but these users 
only have read access and generally create alternative indexes over resources, 
making them searchable in novel ways.  A few example applications might include:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;a bot that listens for any &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;annotation&lt;/code&gt; with a tag and creates a more 
full-featured text search including fuzzy matching or using sound/music-related 
word embeddings for high-quality semantic searches&lt;/li&gt;
  &lt;li&gt;a bot that computes low-dimensional embeddings (using a technique 
&lt;a href=&quot;http://johnvinyard.github.io/zounds/search/embeddings/neural-networks/pytorch/2019/02/22/unsupervised-semantic-audio-embeddings.html&quot;&gt;similar to one I covered in an earlier post&lt;/a&gt;) 
from audio or other derived features, making visual exploration possible in a 
user interface&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These indexes might be published via a private or public REST API, allowing 
their consumers to navigate some or all of the audio available via the Cochlea 
API in interesting ways.&lt;/p&gt;

&lt;h1 id=&quot;an-example-user-interface&quot;&gt;An Example User Interface&lt;/h1&gt;

&lt;p&gt;&lt;img src=&quot;https://exampleapp.cochlea.xyz/visual_explorer.jpg&quot; alt=&quot;User Interface&quot; /&gt;&lt;/p&gt;

&lt;p&gt;An early, alpha-stage user interface built atop the Cochlea API and the concepts 
outlined above can be found &lt;a href=&quot;https://exampleapp.cochlea.xyz/&quot;&gt;here&lt;/a&gt;.  All the 
code for the example app can be found in the 
&lt;a href=&quot;https://github.com/JohnVinyard/annotate-api&quot;&gt;Github repo&lt;/a&gt;.  It pulls together 
data contributed by several &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;user&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;featurebot&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;aggregator&lt;/code&gt; users into 
an interface for sound discovery.  The users leveraged include:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dataset&lt;/code&gt; users that contribute sounds from several datasets, including 
&lt;a href=&quot;https://magenta.tensorflow.org/datasets/nsynth&quot;&gt;NSynth&lt;/a&gt; and &lt;a href=&quot;https://homes.cs.washington.edu/~thickstn/musicnet.html&quot;&gt;MusicNet&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;featurebot&lt;/code&gt; users that compute alternate visualizations of audio, 
including &lt;a href=&quot;https://en.wikipedia.org/wiki/Short-time_Fourier_transform&quot;&gt;short-time fourier transforms&lt;/a&gt;, 
&lt;a href=&quot;https://en.wikipedia.org/wiki/Chroma_feature&quot;&gt;chroma&lt;/a&gt; and 
&lt;a href=&quot;https://en.wikipedia.org/wiki/Mel-frequency_cepstrum&quot;&gt;MFCC&lt;/a&gt; features.&lt;/li&gt;
  &lt;li&gt;an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;aggregator&lt;/code&gt; user that embeds short segments of audio onto a 
three-dimensional sphere based on perceptual similarity, allowing users to 
navigate sound “space” using a Google Maps-like interface.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The user interface is a single-page Vue.js application hosted using Amazon S3 
and Cloudfront. It communicates with the Cochlea API as well as the search 
API hosted by the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;aggregator&lt;/code&gt; user.&lt;/p&gt;

&lt;p&gt;The API and web app are invite-only (for now), 
&lt;a href=&quot;mailto:john.vinyard@gmail.com&quot;&gt;but please reach out&lt;/a&gt; if you’re interested in 
giving them a spin (in exchange for some feedback, of course)!&lt;/p&gt;

</description>
        <pubDate>Tue, 22 Oct 2019 12:00:00 +0000</pubDate>
        <link>http://johnvinyard.github.io/api/search/annotation/2019/10/22/cochlea-api-and-example-application.html</link>
        <guid isPermaLink="true">http://johnvinyard.github.io/api/search/annotation/2019/10/22/cochlea-api-and-example-application.html</guid>
        
        
        <category>api</category>
        
        <category>search</category>
        
        <category>annotation</category>
        
      </item>
    
      <item>
        <title>Audio Query-By-Example via Unsupervised Embeddings</title>
        <description>&lt;p&gt;A couple of months ago, I gave a talk at the 
&lt;a href=&quot;https://www.meetup.com/Austin-Deep-Learning/events/256293686/&quot;&gt;Austin Deep Learning Meetup&lt;/a&gt; 
about building &lt;a href=&quot;https://cochlea.xyz/sounds?query=flute&quot;&gt;Cochlea&lt;/a&gt;, a prototype audio 
similarity search engine.  There was a lot to cover in an hour, some details 
were glossed over, and I’ve learned a few things since the talk, so I decided 
to write a blog post covering the process in a little more detail.&lt;/p&gt;

&lt;h2 id=&quot;motivations-and-first-steps&quot;&gt;Motivations and First Steps&lt;/h2&gt;
&lt;p&gt;There are countless hours of audio out there on the internet, and much of it is
either not indexed at all, or is searchable only via subjective, noisy and 
relatively low-bandwidth text descriptions and tags.  What if it was possible 
to index all this audio data by perceptual similarity, allowing musicians and 
sound designers to navigate the data in an intuitive way, without depending on 
manual tagging?&lt;/p&gt;

&lt;p&gt;The first challenge in building this kind of index is producing a 
representation of short audio segments that captures important perceptual 
qualities of the sound.  This is, of course, subjective, and somewhat 
task-dependent (e.g., am I searching for audio with a similar timbre, or just
the same pitch, or maybe a similar loudness envelope?), but in this case, we’d 
like to find some embedding space where elements are near one another if a 
human would likely assign the two sounds to the same class.  For example, two 
segments of classical solo piano music should fall closer together in the space 
than a segment of solo classical piano music and a segment of rock music.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://s3-us-west-1.amazonaws.com/unsupervised-audio-embeddings-talk/t-SNE.png&quot; alt=&quot;t-SNE&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Above, you can see a &lt;a href=&quot;https://lvdmaaten.github.io/tsne/&quot;&gt;t-SNE&lt;/a&gt; visualization 
of the 128-dimensional embeddings we end up learning in this experiment.  What’s 
interesting here is that we’re plotting by tags or labels, &lt;em&gt;but those won’t 
be used during training at all&lt;/em&gt;!  We’ll train a neural network that separates 
audio classes fairly well in an unsupervised manner.&lt;/p&gt;

&lt;h2 id=&quot;unsupervised-learning-of-semantic-audio-representations&quot;&gt;Unsupervised Learning of Semantic Audio Representations&lt;/h2&gt;
&lt;p&gt;There’s a great paper called 
&lt;a href=&quot;https://arxiv.org/abs/1711.02209&quot;&gt;Unsupervised Learning of Semantic Audio Representations&lt;/a&gt; 
from &lt;a href=&quot;https://ai.google/research/people/DanEllis&quot;&gt;Dan Ellis’&lt;/a&gt; research group at 
Google that develops the kind of representation we’re after by first noting a 
few things:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;certain types of transformations (e.g. pitch shifts and time 
dilation/compression) don’t typically change the general sound class&lt;/li&gt;
  &lt;li&gt;sounds that are temporally proximal (occur near in time) tend to be assigned
to the same sound class&lt;/li&gt;
  &lt;li&gt;mixtures of sounds inherit the sound classes of the constituent elements&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;They leverage these observations to train a neural network that produces dense, 
128-dimensional embeddings of short (approximately one second) spectrograms such that 
perceptually similar sounds have a low cosine distance, or small angle on the 
unit (hyper)sphere in an unsupervised fashion, without requiring a large, 
hand-labeled audio dataset to get started.&lt;/p&gt;

&lt;h2 id=&quot;deformations&quot;&gt;Deformations&lt;/h2&gt;

&lt;p&gt;First, to prove to ourselves that the observations are valid, we can apply the 
deformations to some audio and listen to ensure that some kind of perceptual 
similarity is maintained.&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Deformation&lt;/th&gt;
      &lt;th&gt;Audio&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;original&lt;/td&gt;
      &lt;td&gt;&lt;audio controls=&quot;&quot; src=&quot;https://s3-us-west-1.amazonaws.com/unsupervised-audio-embeddings-talk/original.ogg&quot;&gt;&lt;/audio&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;pitch shift up&lt;/td&gt;
      &lt;td&gt;&lt;audio controls=&quot;&quot; src=&quot;https://s3-us-west-1.amazonaws.com/unsupervised-audio-embeddings-talk/pitch-shift-up.ogg&quot;&gt;&lt;/audio&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;pitch shift down&lt;/td&gt;
      &lt;td&gt;&lt;audio controls=&quot;&quot; src=&quot;https://s3-us-west-1.amazonaws.com/unsupervised-audio-embeddings-talk/pitch-shift-down.ogg&quot;&gt;&lt;/audio&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;time dilation&lt;/td&gt;
      &lt;td&gt;&lt;audio controls=&quot;&quot; src=&quot;https://s3-us-west-1.amazonaws.com/unsupervised-audio-embeddings-talk/time-stretch-longer.ogg&quot;&gt;&lt;/audio&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;time compression&lt;/td&gt;
      &lt;td&gt;&lt;audio controls=&quot;&quot; src=&quot;https://s3-us-west-1.amazonaws.com/unsupervised-audio-embeddings-talk/time-stretch-faster.ogg&quot;&gt;&lt;/audio&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;additive noise&lt;/td&gt;
      &lt;td&gt;&lt;audio controls=&quot;&quot; src=&quot;https://s3-us-west-1.amazonaws.com/unsupervised-audio-embeddings-talk/additive-noise.ogg&quot;&gt;&lt;/audio&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;temporal proximity beginning&lt;/td&gt;
      &lt;td&gt;&lt;audio controls=&quot;&quot; src=&quot;https://s3-us-west-1.amazonaws.com/unsupervised-audio-embeddings-talk/original-beginning.ogg&quot;&gt;&lt;/audio&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;temporal proximity end&lt;/td&gt;
      &lt;td&gt;&lt;audio controls=&quot;&quot; src=&quot;https://s3-us-west-1.amazonaws.com/unsupervised-audio-embeddings-talk/original-end.ogg&quot;&gt;&lt;/audio&gt;&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;These all sound like they belong to the same, or a similar sound class, to my 
ears at least.&lt;/p&gt;

&lt;h2 id=&quot;triplet-loss&quot;&gt;Triplet Loss&lt;/h2&gt;

&lt;p&gt;Getting a little more formal, we’d like to learn a function or mapping such 
that simple cosine distance in the target or embedding space corresponds to some 
of the highly complex geometric relationships between the anchor and deformed 
sounds represented in the audio we’ve just listened to.&lt;/p&gt;

&lt;p&gt;For this experiment, that function, which we’ll call $g$, will take the form 
of a deep convolutional neural network with learn-able parameters:&lt;/p&gt;

\[g: \mathbb{R}^{F \times T} \rightarrow \mathbb{R}^{embedding\_dim}\]

&lt;p&gt;The original space is expressed as having dimensionality $F \times T$ because
the input representation used in the paper is a spectrogram, with the $^F$ and 
$^T$ representing the frequency and time dimensions, respectively.  We’ll go 
into more detail about how this representation will be computed in the next 
section.&lt;/p&gt;

&lt;p&gt;Our dataset will consist of $N$ “triplets” of data:&lt;/p&gt;

\[\tau  = \{ t_i\}_{i=1}^N\]

&lt;p&gt;Each triplet will look something like this:&lt;/p&gt;

\[t_i = (x_{a}^{(i)}, x_{p}^{(i)}, x_{n}^{(i)})\]

&lt;p&gt;and each member of the triplet will be a spectogram:&lt;/p&gt;

\[x_a^{(i)}, x_p^{(i)}, x_n^{(i)} \in \mathbb{R}^{F \times T}\]

&lt;p&gt;Each $x_a$ represents an &lt;em&gt;anchor&lt;/em&gt; audio segment, each $x_p$ represents a 
&lt;em&gt;positive&lt;/em&gt; example, i.e., the anchor with one of our audio deformations applied, 
or another audio segment that occurs near in time to the anchor, and each $x_n$ 
represents a &lt;em&gt;negative&lt;/em&gt; example, which we’ll choose by picking any other audio 
segment from our dataset at random.  Given a large enough  dataset, our 
random strategy for choosing the negative example is probably fairly safe, 
but we will take some care  to not accidentally choose negative examples that 
are actually more perceptually similar to the anchor than the positive example.&lt;/p&gt;

&lt;p&gt;We’ll minimize a loss with respect to our network parameters that will try to 
push the anchor and positive examples closer together in our embedding space, 
while it also pushes our anchor and negative examples further apart, given some 
distance function $d$:&lt;/p&gt;

\[\mathcal{L}(\tau ) = \sum_{i=1}^{N}\left [  d(g(x_a^{(i)}), g(x_p^{(i)})) - d(g(x_a^{(i)}), g(x_n^{(i)}))   + \delta \right]_+\]

&lt;p&gt;Our network’s job is to ensure that the distance $d$ from anchor to positive 
examples is less than the distance from anchor to negative examples by some 
positive margin $\delta$.  The paper’s authors used squared l2 distance as 
their $d$:&lt;/p&gt;

\[d(a, b) = \left \|  a - b \right \|_2^2\]

&lt;p&gt;While I used cosine distance:&lt;/p&gt;

\[d(a, b) = 1 - \frac{a \cdot b}{\left\| a \right\|_2 \left\| b \right\|_2}\]

&lt;p&gt;The $_+$ here indicates the &lt;a href=&quot;https://en.wikipedia.org/wiki/Hinge_loss&quot;&gt;hinge loss&lt;/a&gt;, 
which really just means that our loss goes to zero if it’s less than this 
margin $\delta$.  As usual, since we can’t optimize this term over all $N$ 
triplets, we’ll optimize the learn-able parameters using minibatches of data.&lt;br /&gt;
Additionally, we’ll see later that because of the way we’re sampling these 
triplets, our dataset is effectively unbounded.&lt;/p&gt;

&lt;h2 id=&quot;log-scaled-mel-spectrograms&quot;&gt;Log-Scaled Mel Spectrograms&lt;/h2&gt;

&lt;p&gt;The paper’s authors compute their input spectrograms by:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;using short-time Fourier transforms&lt;/li&gt;
  &lt;li&gt;discarding phase&lt;/li&gt;
  &lt;li&gt;mapping the resulting linear-spaced frequency bins onto an approximately 
log-spaced Mel scale&lt;/li&gt;
  &lt;li&gt;applying a logarithmic scaling to the magnitudes&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This is a fairly standard pipeline for computing a perceptually-motivated 
audio representation.  They go on to apply the various deformations mentioned 
above directly to this time-frequency representation.  I was a little uneasy 
with this approach because:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;mapping onto the Mel scale is done after the fact, from linear-spaced 
frequency bins that don’t have the frequency resolution we’d like in lower 
frequency ranges and are needlessly precise in higher frequency ranges&lt;/li&gt;
  &lt;li&gt;the representation isn’t invertible, as phase is discarded and many frequency
bins in the higher ranges are averaged together, meaning that it’s impossible to
know if the transformations actually &lt;em&gt;sound&lt;/em&gt; plausible.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For this project, I decided to perform all deformations in the time domain, 
mostly to convince myself that all of them continued to sound plausible.  I also 
opted to compute the time-frequency representation using a bank of log-spaced 
Morlet wavelets, so that perceptually-inspired frequency spacing and 
time/frequency resolution trade-offs could be accounted for from the outset, 
instead of being something of an afterthought.  A subset of our bank of filters 
will look something like this:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://s3-us-west-1.amazonaws.com/unsupervised-audio-embeddings-talk/filter_bank2.png&quot; alt=&quot;filter bank with log-space frequencies&quot; /&gt;&lt;/p&gt;

&lt;p&gt;This filter bank can be thought of as a 1D convolutional layer with frozen 
parameters.  Visualizing all the channels and weights of our convolutional filter
bank at once yields something like this:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://s3-us-west-1.amazonaws.com/unsupervised-audio-embeddings-talk/filter_bank.png&quot; alt=&quot;filter bank with log-space frequencies&quot; /&gt;&lt;/p&gt;

&lt;p&gt;One nice side effect of this decision is that now the computation of the 
time-frequency transform is performed as part of our neural network, or as 
part of our function $g$, by a convolutional layer with frozen parameters, 
meaning that our input representation is now just $\mathbb{R}^T$, with $^T$ 
being the number of audio samples in each segment.  While the filter bank is 
not included in the network’s learn-able parameters for this initial 
experiment, a learn-able time-frequency transform is an open possibility in 
future iterations of this work.&lt;/p&gt;

&lt;p&gt;The time-frequency representations we compute will look something like this:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://s3-us-west-1.amazonaws.com/unsupervised-audio-embeddings-talk/mel_scale_log_spectrogram.png&quot; alt=&quot;spectrogram&quot; /&gt;&lt;/p&gt;

&lt;p&gt;You can see the implementation of our 
&lt;a href=&quot;https://github.com/JohnVinyard/experiments/blob/master/unsupervised-semantic-audio-embeddings/network.py&quot;&gt;learn-able $g$ function here&lt;/a&gt;, 
which uses the &lt;a href=&quot;https://zounds.readthedocs.io/en/latest/learn.html#zounds.learn.FilterBank&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;zounds.learn.FilterBank&lt;/code&gt;&lt;/a&gt;
module to compute the time frequency-representation before passing it on to a 
stack of convolutional layers.  Also, &lt;a href=&quot;https://github.com/JohnVinyard/experiments/blob/master/unsupervised-semantic-audio-embeddings/mel-scale-log-spectrogram.ipynb&quot;&gt;this jupyter notebook&lt;/a&gt;
offers a more in-depth exploration of the motivations behind using a bank of 
log-spaced Morlet wavelets to compute our log-frequency representation.&lt;/p&gt;

&lt;h2 id=&quot;within-batch-semi-hard-negative-mining&quot;&gt;Within-Batch Semi-Hard Negative Mining&lt;/h2&gt;
&lt;p&gt;The paper’s authors also use a technique called 
“within-batch, semi-hard negative” mining to make training batches as difficult 
as possible for the network.  Since our loss encourages our learn-able function 
to widen the gap between the anchor-to-positive and anchor-to-negative 
embedding distances, we’d like to arrange our training data in such a way that 
that gap between embeddings is &lt;em&gt;narrowed&lt;/em&gt;, forcing our network to work harder 
to push anchor and negative embeddings further apart, and anchor and positive 
embeddings closer together.  Picking the hardest negative example for each 
anchor requires that we compute the distance from every anchor embedding to 
every negative embedding.  This is obviously prohibitively slow to do with our 
entire dataset, and again, isn’t really possible due to the fact that we’re 
building batches on the fly, so we’ll instead do it only &lt;em&gt;within&lt;/em&gt; each batch.&lt;/p&gt;

&lt;p&gt;You can see the results of this process on several batches of size eight in the
graph below.  After re-assigning the negative examples, the new 
anchor-to-negative distances (in red) for each example tend to be closer to the 
anchor-to-positive distances (in blue) than the original anchor-to-negative 
distances (in green), while still maintaining a positive margin.  It’s worth 
noting that the technique I’m using to re-assign the negative examples allows 
for the same negative example to be assigned to multiple triplets if it meets 
the criteria we set out above.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://s3-us-west-1.amazonaws.com/unsupervised-audio-embeddings-talk/negative_mining.png&quot; alt=&quot;negative mining results&quot; /&gt;&lt;/p&gt;

&lt;p&gt;There’s a little more detail about the algorithm I used to perform within-batch 
semi-hard negative mining in &lt;a href=&quot;https://github.com/JohnVinyard/experiments/blob/master/unsupervised-semantic-audio-embeddings/within-batch-semi-hard-negative-mining.ipynb&quot;&gt;this jupyter notebook&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;training-data&quot;&gt;Training Data&lt;/h2&gt;

&lt;p&gt;The paper’s authors used &lt;a href=&quot;https://research.google.com/audioset/&quot;&gt;Google’s AudioSet&lt;/a&gt;
for their training data, but I chose to pull together around 70 hours of sound 
and music from various sources on the internet, including:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://archive.org/details/audio&quot;&gt;Internet Archive&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://freesound.org/&quot;&gt;Freesound.org&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://homes.cs.washington.edu/~thickstn/musicnet.html&quot;&gt;MusicNet&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.phatdrumloops.com/beats.php&quot;&gt;Phat Drum Loops&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;While AudioSet is fantastic and enormous, my ultimate goal is to index audio on 
the internet in the same way Google that indexes documents, so I wanted to get 
some practice scraping audio and related metadata from  disparate sources on 
the internet as a part of this work.&lt;/p&gt;

&lt;h2 id=&quot;training&quot;&gt;Training&lt;/h2&gt;

&lt;p&gt;Now that all the details are ironed out, training the network is fairly 
straightforward and follows this procedure:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;choose a minibatch of &lt;strong&gt;anchor&lt;/strong&gt; examples at random&lt;/li&gt;
  &lt;li&gt;either apply a deformation (e.g., time stretch or pitch shift) or choose 
segments that occur within ten seconds of each anchor to produce &lt;strong&gt;positive&lt;/strong&gt; 
examples&lt;/li&gt;
  &lt;li&gt;choose &lt;strong&gt;negative&lt;/strong&gt; examples at random to complete the triplets&lt;/li&gt;
  &lt;li&gt;use our network $g$ in its current state to compute embeddings for the 
anchor, positive, and negative examples&lt;/li&gt;
  &lt;li&gt;perform within-batch semi-hard negative mining, re-assigning some or all of 
the negative embeddings to make each example in the batch “harder”, i.e., the 
loss greater&lt;/li&gt;
  &lt;li&gt;compute triplet loss, calculate gradients via backpropagation, and update 
our network’s weights&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;building-an-index-with-random-projections&quot;&gt;Building an Index with Random Projections&lt;/h2&gt;

&lt;p&gt;Naively, if we’d like to use our new embedding space to support query-by-example, 
it means computing the distance between a query embedding and &lt;em&gt;every other 
segment in our database!&lt;/em&gt;  A brute-force distance computation over every 
embedding obviously won’t scale well, but thankfully there are plenty of 
techniques available for performing approximate K-nearest neighbors search over 
high-dimensional data in sub-linear time.&lt;/p&gt;

&lt;p&gt;One such approach that gets us log-ish retrieval times builds a binary tree from 
every embedding in our dataset by choosing a random hyperplane for each node 
in the tree and bisecting that node’s data based on which side of the hyperplane 
each data point lies.  &lt;a href=&quot;https://github.com/erikbern&quot;&gt;Erik Bernhardsson&lt;/a&gt; took this 
basic approach while working on music recommendations at Spotify, along with 
some clever tricks to improve accuracy, and open-sourced his work as a library 
called &lt;a href=&quot;https://github.com/spotify/annoy&quot;&gt;Annoy (Approximate Nearest Neighbors Oh Yeah)&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Here’s a visualization of a single hyperplane tree built from our learned 
embeddings:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://s3-us-west-1.amazonaws.com/unsupervised-audio-embeddings-talk/tree.gv.svg&quot; alt=&quot;hyperplane tree&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The first trick introduced is simply to search both of a node’s subtrees 
when a query vector lies sufficiently close to that node’s hyperplane.  The 
intuition here is that good candidate vectors that lie just on the other side 
of the hyperplane “fence” would be missed, despite the fact that they’re nearby.&lt;/p&gt;

&lt;p&gt;The second trick is to build multiple trees.  All of the trees can be searched 
in parallel by building a priority queue of nodes to search, where node priority 
is determined by how far the query vector lies from that node’s hyperplane.  As 
we observed when discussing the first trick, hyperplanes that are far from the 
query vector are more likely to catch nearby candidates, so we’ll prefer those 
nodes, searching until we’ve reached some threshold of candidates we’d like to 
consider.&lt;/p&gt;

&lt;p&gt;Finally, we perform a brute-force distance search over our pool of narrowed 
candidates, which is typically orders of magnitude smaller than our total index 
size.&lt;/p&gt;

&lt;p&gt;In the graph below, you can look at the speed/accuracy tradeoffs we can make 
for our search using from one to 64 trees.  Accuracy here (ranging from 0-1) 
on the x-axis is defined as the overlap with results from our brute-force 
source-of-truth search.  There are other parameters that can be tweaked, such 
as our threshold for searching both paths for a given node, and the size of the 
candidate pool over which we’ll perform our final brute-force search, but this 
holds those parameters constant, only varying the number of trees we’re using.
These timings are for searches over around 60 hours of audio.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://s3-us-west-1.amazonaws.com/unsupervised-audio-embeddings-talk/search_times.png&quot; alt=&quot;search comparison&quot; /&gt;&lt;/p&gt;

&lt;p&gt;It’s worth noting that these timings are based on &lt;a href=&quot;https://github.com/JohnVinyard/experiments/blob/master/unsupervised-semantic-audio-embeddings/search.py#L108&quot;&gt;a pure-Python/Numpy implementation 
of the algorithm that I wrote for learning purposes&lt;/a&gt;; 
timings from Annoy’s C++ implementation would likely look better.&lt;/p&gt;

&lt;h2 id=&quot;conclusion-and-next-steps&quot;&gt;Conclusion and Next Steps&lt;/h2&gt;

&lt;p&gt;We’re off to a pretty good start.  We’ve now got:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;A way to learn a representation that captures perceptual similarity in an 
unsupervised way.  The more data we can feed it, the better!&lt;/li&gt;
  &lt;li&gt;A pretty fast way to search&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There are some interesting avenues to explore going forward, however:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Does vector arithmetic work for these embeddings just like it does for word 
embeddings (i.e., the classic &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;king - man + woman = queen&lt;/code&gt; example)?  Can we 
find a piano and violin duet by adding their “solo” embeddings together?&lt;/li&gt;
  &lt;li&gt;Could these embeddings be used in audio synthesis as conditioning vectors for 
a &lt;a href=&quot;https://arxiv.org/abs/1609.03499&quot;&gt;WaveNet&lt;/a&gt;-like model or a conditional 
&lt;a href=&quot;https://arxiv.org/abs/1802.04208&quot;&gt;WaveGAN&lt;/a&gt;?&lt;/li&gt;
  &lt;li&gt;Can we use these embeddings to predict tags for unlabelled audio for enhanced 
text search?&lt;/li&gt;
  &lt;li&gt;Is it possible to further embed our representations in a much lower two or 
three-dimensional space, making the navigation of audio segments visual and 
intuitive (our t-SNE visualization above points to “yes”)?&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;resources&quot;&gt;Resources&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://docs.google.com/presentation/d/1EB-B7WI42gOEKozXIkDvNUWaVjKQb_bqk5M_mUiueS0/edit?usp=sharing&quot;&gt;You can find slides from the original talk here&lt;/a&gt;, 
and watch a &lt;a href=&quot;https://www.youtube.com/watch?v=hKYuEZ0dEu0&amp;amp;feature=youtu.be&quot;&gt;video of it on YouTube&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/JohnVinyard/experiments/tree/master/unsupervised-semantic-audio-embeddings&quot;&gt;All the code for this experiment is on GitHub&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://arxiv.org/abs/1711.02209&quot;&gt;Unsupervised Learning of Semantic Audio Representations&lt;/a&gt; 
is the paper on which this experiment is based&lt;/li&gt;
  &lt;li&gt;There’s a &lt;a href=&quot;https://erikbern.com/2015/10/01/nearest-neighbors-and-vector-models-part-2-how-to-search-in-high-dimensional-spaces.html&quot;&gt;good blog post&lt;/a&gt; 
where Annoy’s author explains it in detail and an &lt;a href=&quot;https://www.youtube.com/watch?v=QkCCyLW0ehU&quot;&gt;talk that covers the same material on YouTube&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
</description>
        <pubDate>Fri, 22 Feb 2019 12:00:00 +0000</pubDate>
        <link>http://johnvinyard.github.io/zounds/search/embeddings/neural-networks/pytorch/2019/02/22/unsupervised-semantic-audio-embeddings.html</link>
        <guid isPermaLink="true">http://johnvinyard.github.io/zounds/search/embeddings/neural-networks/pytorch/2019/02/22/unsupervised-semantic-audio-embeddings.html</guid>
        
        
        <category>zounds</category>
        
        <category>search</category>
        
        <category>embeddings</category>
        
        <category>neural-networks</category>
        
        <category>pytorch</category>
        
      </item>
    
      <item>
        <title>Perceptual Audio Loss</title>
        <description>&lt;p&gt;Today, I perform a small experiment to investigate whether a carefully designed
loss function can help a very low-capacity neural network “spend” that capacity
only on perceptually relevant features.  If we can design audio codecs like
 &lt;a href=&quot;https://xiph.org/vorbis/doc/Vorbis_I_spec.html&quot;&gt;Ogg Vorbis&lt;/a&gt; that allocate bits
 according to perceptual relevance, then we should be able to design a loss
 function that penalizes perceptually relevant errors, and doesn’t bother much
 with those that fall near or below the threshold of human awareness.&lt;/p&gt;

&lt;p&gt;Given enough capacity, data, and time, a model trained using mean squared error
 will eventually produce pleasing samples, but can we produce those same samples
 with &lt;em&gt;less&lt;/em&gt; of all three?&lt;/p&gt;

&lt;p&gt;I used &lt;a href=&quot;https://github.com/JohnVinyard/zounds&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;zounds&lt;/code&gt;&lt;/a&gt; and
&lt;a href=&quot;https://pytorch.org/&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pytorch&lt;/code&gt;&lt;/a&gt; to build a small experiment where I dip the
first half of my pinkie toe into these waters.&lt;/p&gt;
&lt;h1 id=&quot;the-experiment&quot;&gt;The Experiment&lt;/h1&gt;

&lt;p&gt;In this experiment, I’ll train a “generator” network to transform a fixed noise
vector (128-dimensional, drawn from a gaussian distribution with zero mean,
unit variance, and a diagonal covariance matrix) into a &lt;em&gt;single&lt;/em&gt; fixed audio
sample of dimension 8192 (~.75 seconds at 11025hz sampling rate).  I’ll perform
this same experiment with five different audio samples, and two different loss
functions:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://pytorch.org/docs/stable/nn.html#torch.nn.MSELoss&quot;&gt;mean squared error&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/JohnVinyard/zounds/blob/master/zounds/learn/loss.py#L12&quot;&gt;a perceptually-inspired loss function&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;the-perceptually-inspired-loss&quot;&gt;The Perceptually-Inspired Loss&lt;/h2&gt;
&lt;p&gt;The &lt;a href=&quot;https://github.com/JohnVinyard/zounds/blob/master/zounds/learn/loss.py#L12&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PerceptualLoss&lt;/code&gt;&lt;/a&gt;
is very rudimentary, but hopefully captures some characteristics of early stages
in the human auditory processing pipeline, namely:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;an FIR filter bank, whose filters’ center frequencies lie along the &lt;a href=&quot;https://en.wikipedia.org/wiki/Bark_scale&quot;&gt;Bark scale&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;half-wave rectification (AKA ReLU)&lt;/li&gt;
  &lt;li&gt;a logarithmic, or &lt;a href=&quot;https://en.wikipedia.org/wiki/Decibel#Perception&quot;&gt;decibel&lt;/a&gt;-like amplitude scaling&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The network architecture, as well as the weight initialization &lt;em&gt;scheme&lt;/em&gt;
(but not the exact initialized weights) is held constant as we subjectively
evaluate the performance of our two loss functions on five different audio
files containing:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://archive.org/details/Greatest_Speeches_of_the_20th_Century&quot;&gt;Richard Nixon speaking&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://archive.org//details/AOC11B&quot;&gt;a Bach piano piece&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://archive.org/details/TopGunAnthem&quot;&gt;A song from the &lt;em&gt;Top Gun&lt;/em&gt; soundtrack&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://archive.org/details/TopGunAnthem&quot;&gt;A Kevin Gates song&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.phatdrumloops.com/beats.php&quot;&gt;A drumkit sample&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For each &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(audio sample, loss)&lt;/code&gt; pair, the generator network is given 1000
iterations to learn to transform the fixed noise vector into the given audio
sample, and “checkpoint” audio samples are recorded from the network every 250
iterations.&lt;/p&gt;

&lt;p&gt;Put another way, when over-fitting our low capacity network to a dataset of size
one, what does the loss emphasize?&lt;/p&gt;

&lt;h2 id=&quot;inspiration-and-previous-work&quot;&gt;Inspiration and Previous Work&lt;/h2&gt;
&lt;p&gt;This approach was inspired by the
&lt;a href=&quot;https://dmitryulyanov.github.io/deep_image_prior&quot;&gt;Deep Image Prior&lt;/a&gt; paper.
While that paper sought to understand biases inherent in neural network
&lt;em&gt;architectures&lt;/em&gt; by keeping the loss fixed, and varying network structure,
this experiment holds the architecture fixed, and tries to understand the
contribution of &lt;em&gt;different losses&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Both
&lt;a href=&quot;https://arxiv.org/abs/1512.09300&quot;&gt;Autoencoding beyond pixels using a learned similarity metric&lt;/a&gt;
and &lt;a href=&quot;https://arxiv.org/abs/1602.02644&quot;&gt;Generating Images with Perceptual Similarity Metrics based on Deep Networks&lt;/a&gt;
explore losses that go beyond simple per-pixel (or per-sample) metrics.&lt;/p&gt;

&lt;h2 id=&quot;the-code&quot;&gt;The Code&lt;/h2&gt;
&lt;p&gt;The &lt;a href=&quot;https://github.com/JohnVinyard/experiments/blob/master/audio-loss/audio_loss.py&quot;&gt;code for this experiment can be found on GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;h1 id=&quot;the-results&quot;&gt;The Results&lt;/h1&gt;

&lt;p&gt;In each section below, you can hear generations from the network every 250
iterations.&lt;/p&gt;

&lt;h2 id=&quot;richard-nixon-speaking&quot;&gt;Richard Nixon Speaking&lt;/h2&gt;

&lt;h3 id=&quot;original&quot;&gt;Original&lt;/h3&gt;
&lt;audio src=&quot;https://drive.google.com/uc?id=1A7R9W-UH9lDP1h9vl62ola52kz3TRBdv&amp;amp;authuser=0&amp;amp;export=download&quot; controls=&quot;&quot;&gt;&lt;/audio&gt;

&lt;h3 id=&quot;mean-squared-error&quot;&gt;Mean Squared Error&lt;/h3&gt;
&lt;h4 id=&quot;250-iterations&quot;&gt;250 Iterations&lt;/h4&gt;
&lt;audio src=&quot;https://drive.google.com/uc?id=1qwcY0SGKc8jQQGdWHp2snvDynRHL7FPo&amp;amp;authuser=0&amp;amp;export=download&quot; controls=&quot;&quot;&gt;&lt;/audio&gt;
&lt;h4 id=&quot;500-iterations&quot;&gt;500 Iterations&lt;/h4&gt;
&lt;audio src=&quot;https://drive.google.com/uc?id=1V6JFl4f1x1yHavO0gojaAntcJEZrbZwK&amp;amp;authuser=0&amp;amp;export=download&quot; controls=&quot;&quot;&gt;&lt;/audio&gt;
&lt;h4 id=&quot;750-iterations&quot;&gt;750 Iterations&lt;/h4&gt;
&lt;audio src=&quot;https://drive.google.com/uc?id=1T0W92I8HtvMTStBev8PJ6NIXz2arq8mI&amp;amp;authuser=0&amp;amp;export=download&quot; controls=&quot;&quot;&gt;&lt;/audio&gt;
&lt;h4 id=&quot;1000-iterations&quot;&gt;1000 Iterations&lt;/h4&gt;
&lt;audio src=&quot;https://drive.google.com/uc?id=1ntYaPth9mmTfpvYC44C6u84HDyDMCCCe&amp;amp;authuser=0&amp;amp;export=download&quot; controls=&quot;&quot;&gt;&lt;/audio&gt;

&lt;h3 id=&quot;perceptual-loss&quot;&gt;Perceptual Loss&lt;/h3&gt;
&lt;h4 id=&quot;250-iterations-1&quot;&gt;250 Iterations&lt;/h4&gt;
&lt;audio src=&quot;https://drive.google.com/uc?id=1NAi1MamTrVXCsaKZoWZ5SaVu1DGNBe46&amp;amp;authuser=0&amp;amp;export=download&quot; controls=&quot;&quot;&gt;&lt;/audio&gt;
&lt;h4 id=&quot;500-iterations-1&quot;&gt;500 Iterations&lt;/h4&gt;
&lt;audio src=&quot;https://drive.google.com/uc?id=1eBmyq-_KP9bGsbsfqxgtLSIosRGRpr7D&amp;amp;authuser=0&amp;amp;export=download&quot; controls=&quot;&quot;&gt;&lt;/audio&gt;
&lt;h4 id=&quot;750-iterations-1&quot;&gt;750 Iterations&lt;/h4&gt;
&lt;audio src=&quot;https://drive.google.com/uc?id=19A9stv_GK4XdnhZd5xdQniDhTygkyiV5&amp;amp;authuser=0&amp;amp;export=download&quot; controls=&quot;&quot;&gt;&lt;/audio&gt;
&lt;h4 id=&quot;1000-iterations-1&quot;&gt;1000 Iterations&lt;/h4&gt;
&lt;audio src=&quot;https://drive.google.com/uc?id=1nU6SBKGWlf8Q3QV06ZiM2CH1RPLuNX5R&amp;amp;authuser=0&amp;amp;export=download&quot; controls=&quot;&quot;&gt;&lt;/audio&gt;

&lt;h3 id=&quot;conclusions&quot;&gt;Conclusions&lt;/h3&gt;
&lt;p&gt;For this sample, MSE at 250 iterations is noisy and unintelligible, while the
perceptual loss is already &lt;em&gt;starting&lt;/em&gt; to be intelligible at the same point.  By
the end of the experiment, the samples generated by the network trained with MSE
are fairly intelligible, but completely missing the sibilant at the end of the
word “practice”.  The network trained with perceptual loss captures this
plainly and simply.&lt;/p&gt;

&lt;h2 id=&quot;bach-piano&quot;&gt;Bach Piano&lt;/h2&gt;

&lt;h3 id=&quot;original-1&quot;&gt;Original&lt;/h3&gt;
&lt;audio src=&quot;https://drive.google.com/uc?id=1E5MWSREqmDxCMCfG0P0GTaaeQLoQHftj&amp;amp;authuser=0&amp;amp;export=download&quot; controls=&quot;&quot;&gt;&lt;/audio&gt;

&lt;h3 id=&quot;mean-squared-error-1&quot;&gt;Mean Squared Error&lt;/h3&gt;
&lt;h4 id=&quot;250-iterations-2&quot;&gt;250 Iterations&lt;/h4&gt;
&lt;audio src=&quot;https://drive.google.com/uc?id=13Ny6OZc9t5cZlOwNquFhJbT5qQpdaBlZ&amp;amp;authuser=0&amp;amp;export=download&quot; controls=&quot;&quot;&gt;&lt;/audio&gt;
&lt;h4 id=&quot;500-iterations-2&quot;&gt;500 Iterations&lt;/h4&gt;
&lt;audio src=&quot;https://drive.google.com/uc?id=1IKUrYGvf4IBC2xYswG_WoaExCmRQGuFY&amp;amp;authuser=0&amp;amp;export=download&quot; controls=&quot;&quot;&gt;&lt;/audio&gt;
&lt;h4 id=&quot;750-iterations-2&quot;&gt;750 Iterations&lt;/h4&gt;
&lt;audio src=&quot;https://drive.google.com/uc?id=1DetNCEakbb1LG28DrfYLKG51K0d3wS9M&amp;amp;authuser=0&amp;amp;export=download&quot; controls=&quot;&quot;&gt;&lt;/audio&gt;
&lt;h4 id=&quot;1000-iterations-2&quot;&gt;1000 Iterations&lt;/h4&gt;
&lt;audio src=&quot;https://drive.google.com/uc?id=1QIzDeRo0fRawEvuL4D4Zv6xpYVLpmY5O&amp;amp;authuser=0&amp;amp;export=download&quot; controls=&quot;&quot;&gt;&lt;/audio&gt;

&lt;h3 id=&quot;perceptual-loss-1&quot;&gt;Perceptual Loss&lt;/h3&gt;
&lt;h4 id=&quot;250-iterations-3&quot;&gt;250 Iterations&lt;/h4&gt;
&lt;audio src=&quot;https://drive.google.com/uc?id=1ju4wLVD926QyOcX3Y0ycKMGTYHujvoqb&amp;amp;authuser=0&amp;amp;export=download&quot; controls=&quot;&quot;&gt;&lt;/audio&gt;
&lt;h4 id=&quot;500-iterations-3&quot;&gt;500 Iterations&lt;/h4&gt;
&lt;audio src=&quot;https://drive.google.com/uc?id=1k3w5sI5DV-89_j1RyRU9NDlxAF76CZeD&amp;amp;authuser=0&amp;amp;export=download&quot; controls=&quot;&quot;&gt;&lt;/audio&gt;
&lt;h4 id=&quot;750-iterations-3&quot;&gt;750 Iterations&lt;/h4&gt;
&lt;audio src=&quot;https://drive.google.com/uc?id=1-QphPZh7IQbeNWkQgDgLAyyNflwpD9hX&amp;amp;authuser=0&amp;amp;export=download&quot; controls=&quot;&quot;&gt;&lt;/audio&gt;
&lt;h4 id=&quot;1000-iterations-3&quot;&gt;1000 Iterations&lt;/h4&gt;
&lt;audio src=&quot;https://drive.google.com/uc?id=1gOppnGPpWuxzr0ffcx1UjMdhGBd0iEfC&amp;amp;authuser=0&amp;amp;export=download&quot; controls=&quot;&quot;&gt;&lt;/audio&gt;

&lt;h3 id=&quot;conclusions-1&quot;&gt;Conclusions&lt;/h3&gt;
&lt;p&gt;Even at the final iteration, generations from the network trained with MSE are
“blurry”, and noisy.  Generations from the network trained with perceptual loss
 are also a bit noisy, but overall, the final result is significantly clearer.&lt;/p&gt;

&lt;h2 id=&quot;top-gun-soundtrack&quot;&gt;Top Gun Soundtrack&lt;/h2&gt;

&lt;h3 id=&quot;original-2&quot;&gt;Original&lt;/h3&gt;
&lt;audio src=&quot;https://drive.google.com/uc?id=1s23PoeVHJD9hyxCLcCK1GAwzt0G9cYFP&amp;amp;authuser=0&amp;amp;export=download&quot; controls=&quot;&quot;&gt;&lt;/audio&gt;

&lt;h3 id=&quot;mean-squared-error-2&quot;&gt;Mean Squared Error&lt;/h3&gt;
&lt;h4 id=&quot;250-iterations-4&quot;&gt;250 Iterations&lt;/h4&gt;
&lt;audio src=&quot;https://drive.google.com/uc?id=11vHj4MeaAWuRw7sNg9KmbkK_ouYiKbpF&amp;amp;authuser=0&amp;amp;export=download&quot; controls=&quot;&quot;&gt;&lt;/audio&gt;
&lt;h4 id=&quot;500-iterations-4&quot;&gt;500 Iterations&lt;/h4&gt;
&lt;audio src=&quot;https://drive.google.com/uc?id=1VjrvvqhR53316iDjxH4emoIMzsEg_d4n&amp;amp;authuser=0&amp;amp;export=download&quot; controls=&quot;&quot;&gt;&lt;/audio&gt;
&lt;h4 id=&quot;750-iterations-4&quot;&gt;750 Iterations&lt;/h4&gt;
&lt;audio src=&quot;https://drive.google.com/uc?id=1p29_bagg5Opb5w2klTa2aAHH6hhmj8Y1&amp;amp;authuser=0&amp;amp;export=download&quot; controls=&quot;&quot;&gt;&lt;/audio&gt;
&lt;h4 id=&quot;1000-iterations-4&quot;&gt;1000 Iterations&lt;/h4&gt;
&lt;audio src=&quot;https://drive.google.com/uc?id=19oHd2JsFPatweJmmuukWCrdIBh0ciuBv&amp;amp;authuser=0&amp;amp;export=download&quot; controls=&quot;&quot;&gt;&lt;/audio&gt;

&lt;h3 id=&quot;perceptual-loss-2&quot;&gt;Perceptual Loss&lt;/h3&gt;
&lt;h4 id=&quot;250-iterations-5&quot;&gt;250 Iterations&lt;/h4&gt;
&lt;audio src=&quot;https://drive.google.com/uc?id=18ZLPitxQPMjgqHcXQ73tcRo5rTjtZ1uW&amp;amp;authuser=0&amp;amp;export=download&quot; controls=&quot;&quot;&gt;&lt;/audio&gt;
&lt;h4 id=&quot;500-iterations-5&quot;&gt;500 Iterations&lt;/h4&gt;
&lt;audio src=&quot;https://drive.google.com/uc?id=1A8xLjSvGpTvIB_JvqUyFSWywPcrCmAL1&amp;amp;authuser=0&amp;amp;export=download&quot; controls=&quot;&quot;&gt;&lt;/audio&gt;
&lt;h4 id=&quot;750-iterations-5&quot;&gt;750 Iterations&lt;/h4&gt;
&lt;audio src=&quot;https://drive.google.com/uc?id=1WNzy71oDgN7kMUCYFhOgbkbVWrauxLjl&amp;amp;authuser=0&amp;amp;export=download&quot; controls=&quot;&quot;&gt;&lt;/audio&gt;
&lt;h4 id=&quot;1000-iterations-5&quot;&gt;1000 Iterations&lt;/h4&gt;
&lt;audio src=&quot;https://drive.google.com/uc?id=1Uf9zbp-6t6hI2jGW0ltHRcu-uRQTCkVM&amp;amp;authuser=0&amp;amp;export=download&quot; controls=&quot;&quot;&gt;&lt;/audio&gt;

&lt;h3 id=&quot;conclusions-2&quot;&gt;Conclusions&lt;/h3&gt;

&lt;p&gt;This sample has a pretty broad frequency range, and a lot’s going on:
bass guitar, synth, female vocals, and a snare drum.  At 250 iterations,
generations from the network trained with MSE are a noisy, low frequency mess,
while generations from the network trained with perceptual loss are beginning to
be intelligible.&lt;/p&gt;

&lt;p&gt;The network trained with MSE does OK by the final iteration, but the network
trained with perceptual loss does a much better job of generating the crisp
high end, especially notable in the crack of the snare drum.&lt;/p&gt;

&lt;h2 id=&quot;kevin-gates&quot;&gt;Kevin Gates&lt;/h2&gt;

&lt;h3 id=&quot;original-3&quot;&gt;Original&lt;/h3&gt;
&lt;audio src=&quot;https://drive.google.com/uc?id=14ooyrEn0yWstLK4G-6I6zMTfuY6F3j3a&amp;amp;authuser=0&amp;amp;export=download&quot; controls=&quot;&quot;&gt;&lt;/audio&gt;

&lt;h3 id=&quot;mean-squared-error-3&quot;&gt;Mean Squared Error&lt;/h3&gt;
&lt;h4 id=&quot;250-iterations-6&quot;&gt;250 Iterations&lt;/h4&gt;
&lt;audio src=&quot;https://drive.google.com/uc?id=1eRIxPCYERS6yahhOgTQBcVoV4ufqLNyY&amp;amp;authuser=0&amp;amp;export=download&quot; controls=&quot;&quot;&gt;&lt;/audio&gt;
&lt;h4 id=&quot;500-iterations-6&quot;&gt;500 Iterations&lt;/h4&gt;
&lt;audio src=&quot;https://drive.google.com/uc?id=1FBX76pDL31QgoUwCD7xVUFaqKqB9Wqiy&amp;amp;authuser=0&amp;amp;export=download&quot; controls=&quot;&quot;&gt;&lt;/audio&gt;
&lt;h4 id=&quot;750-iterations-6&quot;&gt;750 Iterations&lt;/h4&gt;
&lt;audio src=&quot;https://drive.google.com/uc?id=1Ga3uk14qMgz2ZEmbR6R_hEBrr3-W1A9r&amp;amp;authuser=0&amp;amp;export=download&quot; controls=&quot;&quot;&gt;&lt;/audio&gt;
&lt;h4 id=&quot;1000-iterations-6&quot;&gt;1000 Iterations&lt;/h4&gt;
&lt;audio src=&quot;https://drive.google.com/uc?id=1-Na5cNgUP1ldyXyLEAc4ut-4_gR9lRx9&amp;amp;authuser=0&amp;amp;export=download&quot; controls=&quot;&quot;&gt;&lt;/audio&gt;

&lt;h3 id=&quot;perceptual-loss-3&quot;&gt;Perceptual Loss&lt;/h3&gt;
&lt;h4 id=&quot;250-iterations-7&quot;&gt;250 Iterations&lt;/h4&gt;
&lt;audio src=&quot;https://drive.google.com/uc?id=1-40tvz6kac8xP1g3SB335eBJ-q4_8yl8&amp;amp;authuser=0&amp;amp;export=download&quot; controls=&quot;&quot;&gt;&lt;/audio&gt;
&lt;h4 id=&quot;500-iterations-7&quot;&gt;500 Iterations&lt;/h4&gt;
&lt;audio src=&quot;https://drive.google.com/uc?id=1yiCnpd3krXL1L6LYDpam6ou__ICrkFPH&amp;amp;authuser=0&amp;amp;export=download&quot; controls=&quot;&quot;&gt;&lt;/audio&gt;
&lt;h4 id=&quot;750-iterations-7&quot;&gt;750 Iterations&lt;/h4&gt;
&lt;audio src=&quot;https://drive.google.com/uc?id=1fk-5wvkXPuen-DZA3ziLKMi1QE9-IrqR&amp;amp;authuser=0&amp;amp;export=download&quot; controls=&quot;&quot;&gt;&lt;/audio&gt;
&lt;h4 id=&quot;1000-iterations-7&quot;&gt;1000 Iterations&lt;/h4&gt;
&lt;audio src=&quot;https://drive.google.com/uc?id=1L5QkDHwzK8ZtfxLrmTPU9QTNkMQki9R3&amp;amp;authuser=0&amp;amp;export=download&quot; controls=&quot;&quot;&gt;&lt;/audio&gt;

&lt;h3 id=&quot;conclusions-3&quot;&gt;Conclusions&lt;/h3&gt;

&lt;p&gt;While this sample covers a frequencies similar to those from the “Top Gun”
soundtrack, both networks seem to struggle a bit more.  Unsurprisingly at this
point, the network trained with perceptual loss has managed to capture the
sharp attack of the snare drum, as well as make the words “I get…” at the end
 of the sample almost intelligibly.  Generations from both networks are noisy,
 but the MSE generations are much more so.&lt;/p&gt;

&lt;h2 id=&quot;drumkit&quot;&gt;Drumkit&lt;/h2&gt;

&lt;h3 id=&quot;original-4&quot;&gt;Original&lt;/h3&gt;
&lt;audio src=&quot;https://drive.google.com/uc?id=1APjAiOYRXeZ0imfduI6Wv0G2C5ODHrdK&amp;amp;authuser=0&amp;amp;export=download&quot; controls=&quot;&quot;&gt;&lt;/audio&gt;

&lt;h3 id=&quot;mean-squared-error-4&quot;&gt;Mean Squared Error&lt;/h3&gt;
&lt;h4 id=&quot;250-iterations-8&quot;&gt;250 Iterations&lt;/h4&gt;
&lt;audio src=&quot;https://drive.google.com/uc?id=1gbNem3ldRcwYEO6L-p7-S41y9KwvBBai&amp;amp;authuser=0&amp;amp;export=download&quot; controls=&quot;&quot;&gt;&lt;/audio&gt;
&lt;h4 id=&quot;500-iterations-8&quot;&gt;500 Iterations&lt;/h4&gt;
&lt;audio src=&quot;https://drive.google.com/uc?id=1bnWoGbWy1LYqs9WLY1bGreN6GwkS_Ri1&amp;amp;authuser=0&amp;amp;export=download&quot; controls=&quot;&quot;&gt;&lt;/audio&gt;
&lt;h4 id=&quot;750-iterations-8&quot;&gt;750 Iterations&lt;/h4&gt;
&lt;audio src=&quot;https://drive.google.com/uc?id=1-ksrFiSjZdMCZmTk9tPLQwllVFuooUX8&amp;amp;authuser=0&amp;amp;export=download&quot; controls=&quot;&quot;&gt;&lt;/audio&gt;
&lt;h4 id=&quot;1000-iterations-8&quot;&gt;1000 Iterations&lt;/h4&gt;
&lt;audio src=&quot;https://drive.google.com/uc?id=1MlIQpXZSa33YpcjiNpaItqBznYksup_z&amp;amp;authuser=0&amp;amp;export=download&quot; controls=&quot;&quot;&gt;&lt;/audio&gt;

&lt;h3 id=&quot;perceptual-loss-4&quot;&gt;Perceptual Loss&lt;/h3&gt;
&lt;h4 id=&quot;250-iterations-9&quot;&gt;250 Iterations&lt;/h4&gt;
&lt;audio src=&quot;https://drive.google.com/uc?id=1NAOlxyZ3x3yDMEWeO-z1VRcgw_7o-yt9&amp;amp;authuser=0&amp;amp;export=download&quot; controls=&quot;&quot;&gt;&lt;/audio&gt;
&lt;h4 id=&quot;500-iterations-9&quot;&gt;500 Iterations&lt;/h4&gt;
&lt;audio src=&quot;https://drive.google.com/uc?id=1N6rHaoq8GvyrX0r4Dvm2lNrsO1szEwPH&amp;amp;authuser=0&amp;amp;export=download&quot; controls=&quot;&quot;&gt;&lt;/audio&gt;
&lt;h4 id=&quot;750-iterations-9&quot;&gt;750 Iterations&lt;/h4&gt;
&lt;audio src=&quot;https://drive.google.com/uc?id=1cGa3rxRKarF_lOgVLJeVIoetL7dBTWWY&amp;amp;authuser=0&amp;amp;export=download&quot; controls=&quot;&quot;&gt;&lt;/audio&gt;
&lt;h4 id=&quot;1000-iterations-9&quot;&gt;1000 Iterations&lt;/h4&gt;
&lt;audio src=&quot;https://drive.google.com/uc?id=1IxT8uEzbbcnT-Uwc7dHl6WLrgIa8rlv2&amp;amp;authuser=0&amp;amp;export=download&quot; controls=&quot;&quot;&gt;&lt;/audio&gt;

&lt;h3 id=&quot;conclusions-4&quot;&gt;Conclusions&lt;/h3&gt;
&lt;p&gt;The difference between the two losses is not as apparent here, although there’s
certainly more definition in the mid range of the tom from the network trained
with perceptual loss.  Interestingly, the perceptual loss network seems to
plateau (or close to it) by iteration 250, while the MSE network starts pretty
terribly and makes its way slowly to the same point.&lt;/p&gt;

&lt;h1 id=&quot;final-thoughts&quot;&gt;Final Thoughts&lt;/h1&gt;

&lt;p&gt;While the results aren’t terribly dramatic, it does seem that the
perceptually-inspired loss function has helped to use network capacity on more
salient (from a human perspective) features of each sound.  In general, this
loss promoted:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;crisper mid and high frequencies&lt;/li&gt;
  &lt;li&gt;less noise&lt;/li&gt;
  &lt;li&gt;quicker convergence on something intelligible&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Obviously, my “perceptual model” is dead-simple, and certainly dead-wrong in
many cases.  Could we make even better use of model capacity by adding things
that perceptual audio codecs use to save bits, like tonal and temporal masking?
Our current model will penalize the generator for incorrectly producing a
frequency that may be inaudible to the listener!&lt;/p&gt;

&lt;h1 id=&quot;addendum&quot;&gt;Addendum&lt;/h1&gt;
&lt;p&gt;The most realistic audio generation models in the recent past, namely,
&lt;a href=&quot;https://arxiv.org/abs/1609.03499&quot;&gt;WaveNet&lt;/a&gt; and
&lt;a href=&quot;https://arxiv.org/abs/1612.07837&quot;&gt;SampleRNN&lt;/a&gt; have some interesting (and surprising)
properties:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;they model audio at the PCM sample level, and not at the FFT frame level,
which the vast majority of previous work has preferred&lt;/li&gt;
  &lt;li&gt;they are auto-regressive and recurrent models, respectively, ultimately
meaning that each successive sample is conditioned on all previous samples.
Sample generation is thus serial, and not parallelizeable (later work,
especially on WaveNet makes this not entirely true)&lt;/li&gt;
  &lt;li&gt;the problem is modelled in both cases as a &lt;em&gt;classification&lt;/em&gt; problem, and not
a regression problem.  Samples are modeled as discrete classes, and the
relationships between those classes must be learned, from scratch, by the model&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The question of whether it’s reasonable to expect to generate audio samples in
parallel, as if they were all independent of one another is an interesting one,
but isn’t really the topic of this post.&lt;/p&gt;

&lt;p&gt;What’s most interesting in this context is the re-framing of the problem as a
classification problem.  This apparently has a couple benefits:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;While using MSE to do regression assumes a gaussian probability distribution,
this approach allows us to learn any arbitratily complex distribution&lt;/li&gt;
  &lt;li&gt;With MSE and naive per-raw-sample regression, it’s possible to do pretty
well by modelling low frequencies (since that’s where most of the energy
lies), and making a lot of noise.  By framing the problem as classification, it
becomes a lot harder for the model to get “partial credit” and coast along
happily&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This approach is very clever, but doesn’t totally sit right with me, because
audio samples &lt;em&gt;are&lt;/em&gt; continuous, so why can’t we model them as such?  Is the
problem a missing perceptual model that maps groups of “raw” audio samples
into a more perceptually appropriate space?  Would regression in that space
work better?&lt;/p&gt;
</description>
        <pubDate>Thu, 07 Jun 2018 12:00:00 +0000</pubDate>
        <link>http://johnvinyard.github.io/zounds/synthesis/neural-networks/pytorch/2018/06/07/perceptual-audio-loss.html</link>
        <guid isPermaLink="true">http://johnvinyard.github.io/zounds/synthesis/neural-networks/pytorch/2018/06/07/perceptual-audio-loss.html</guid>
        
        
        <category>zounds</category>
        
        <category>synthesis</category>
        
        <category>neural-networks</category>
        
        <category>pytorch</category>
        
      </item>
    
  </channel>
</rss>
