<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Dragan Djuric</title>
    <description>Dragan Djuric&apos;s Clojure Blog, Artificial Intelligence, Deep Learning, Bayesian Data Analysis, CUDA, GPU, OpenCL, Functional Programming, Probabilistic Programming, Data Science.</description>
    <link>http://dragan.rocks/</link>
    <atom:link href="http://dragan.rocks/feed.xml" rel="self" type="application/rss+xml"/>
    <pubDate>Fri, 02 Jan 2026 18:42:04 +0100</pubDate>
    <lastBuildDate>Fri, 02 Jan 2026 18:42:04 +0100</lastBuildDate>
    <generator>Jekyll v3.10.0</generator>
    
      <item>
        <title>Gemma 3 AI model in Clojure</title>
        <description>&lt;p&gt;
Recently I&apos;ve been working on the ONNX runtime integration into Deep Diamond, backed by the grant sponsored by the &lt;a href=&quot;https://www.clojuriststogether.org/news/clojurists-together-2025-long-term-funding-announcement/&quot;&gt;Clojurists Together&lt;/a&gt; Foundation.
In the past few articles, we&apos;ve seen how ONNX models are integrated into Deep Diamond, using only a single
function &lt;code&gt;onnx&lt;/code&gt;, with almost no need for additional configuration (which is available).
I used a simple MNIST model in the demonstration. But, can we now load and run the inference on
the real deal models, such as the open LLMs from the Hugging Face, for example? Let&apos;s see!
&lt;/p&gt;

&lt;p&gt;
The Hugging Face model card has this to say about Gemma 3: &quot;Gemma is a family of lightweight, state-of-the-art open models from Google, built from the same research and technology used to create the Gemini models.&quot; (etc., etc.)
So, it seems to be something worth trying.
&lt;/p&gt;

&lt;p&gt;
I&apos;ll try to be brief, and skip the unnecessary talk. Let&apos;s just show the code,
which I&apos;ve just lifted up and adapted from the Diamond&apos;s midje tests.
&lt;/p&gt;

&lt;p&gt;
What we need for this? First, decide on the backend engine; this time we&apos;ll use tensors in main memory
backed up by the oneDNN engine (DNNL).
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-clojure&quot;&gt;&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #A52A2A; font-weight: bold;&quot;&gt;def&lt;/span&gt; &lt;span style=&quot;color: #0084C8; font-weight: bold;&quot;&gt;fact&lt;/span&gt; &lt;span style=&quot;color: #7388d6;&quot;&gt;(&lt;/span&gt;dnnl-factory&lt;span style=&quot;color: #7388d6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;
&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #A52A2A; font-weight: bold;&quot;&gt;def&lt;/span&gt; &lt;span style=&quot;color: #0084C8; font-weight: bold;&quot;&gt;neand-fact&lt;/span&gt; &lt;span style=&quot;color: #7388d6;&quot;&gt;(&lt;/span&gt;neanderthal-factory fact&lt;span style=&quot;color: #7388d6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
Next, load and configure a particular flavor of Gemma 3 (a smaller one, only 1 billion parameters).
The &lt;code&gt;onnx&lt;/code&gt; function creates a generalized blueprint, which can create the actual functions when
evaluated with the specific input tensors.
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-clojure&quot;&gt;&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #A52A2A; font-weight: bold;&quot;&gt;def&lt;/span&gt; &lt;span style=&quot;color: #0084C8; font-weight: bold;&quot;&gt;onnx-bp&lt;/span&gt; &lt;span style=&quot;color: #7388d6;&quot;&gt;(&lt;/span&gt;onnx fact &lt;span style=&quot;color: #4E9A06;&quot;&gt;&quot;data/gemma-3-1b-it-ONNX-GQA/onnx/model.onnx&quot;&lt;/span&gt;
                   &lt;span style=&quot;color: #909183;&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color: #F5666D;&quot;&gt;:options&lt;/span&gt; &lt;span style=&quot;color: #709870;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #A52A2A; font-weight: bold;&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&quot;color: #907373;&quot;&gt;(&lt;/span&gt;options&lt;span style=&quot;color: #907373;&quot;&gt;)&lt;/span&gt;
                           &lt;span style=&quot;color: #907373;&quot;&gt;(&lt;/span&gt;override-dimension! &lt;span style=&quot;color: #4E9A06;&quot;&gt;&quot;batch_size&quot;&lt;/span&gt; 1&lt;span style=&quot;color: #907373;&quot;&gt;)&lt;/span&gt;
                           &lt;span style=&quot;color: #907373;&quot;&gt;(&lt;/span&gt;override-dimension! &lt;span style=&quot;color: #4E9A06;&quot;&gt;&quot;sequence_length&quot;&lt;/span&gt; 1&lt;span style=&quot;color: #907373;&quot;&gt;)&lt;/span&gt;
                           &lt;span style=&quot;color: #907373;&quot;&gt;(&lt;/span&gt;override-dimension! &lt;span style=&quot;color: #4E9A06;&quot;&gt;&quot;past_sequence_length&quot;&lt;/span&gt; 1&lt;span style=&quot;color: #907373;&quot;&gt;)&lt;/span&gt;
                           &lt;span style=&quot;color: #907373;&quot;&gt;(&lt;/span&gt;override-dimension! &lt;span style=&quot;color: #4E9A06;&quot;&gt;&quot;total_sequence_length&quot;&lt;/span&gt; 1&lt;span style=&quot;color: #907373;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #709870;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #909183;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #7388d6;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
Gemma 3 has 63 inputs and 61 outputs. We&apos;ll need to provide these, but even here we can automate some parts
with Clojure, since past-key values are pretty uniform. We only need to provide inputs, while the engine
can create the outputs for us.
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-clojure&quot;&gt;&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #A52A2A; font-weight: bold;&quot;&gt;def&lt;/span&gt; &lt;span style=&quot;color: #0084C8; font-weight: bold;&quot;&gt;src-tz&lt;/span&gt; &lt;span style=&quot;color: #7388d6;&quot;&gt;(&lt;/span&gt;tensor fact &lt;span style=&quot;color: #909183;&quot;&gt;[&lt;/span&gt;1 1 28 28&lt;span style=&quot;color: #909183;&quot;&gt;]&lt;/span&gt; &lt;span style=&quot;color: #F5666D;&quot;&gt;:float&lt;/span&gt; &lt;span style=&quot;color: #F5666D;&quot;&gt;:nchw&lt;/span&gt;&lt;span style=&quot;color: #7388d6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;
&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #A52A2A; font-weight: bold;&quot;&gt;def&lt;/span&gt; &lt;span style=&quot;color: #0084C8; font-weight: bold;&quot;&gt;input-ids&lt;/span&gt; &lt;span style=&quot;color: #7388d6;&quot;&gt;(&lt;/span&gt;tensor neand-fact &lt;span style=&quot;color: #909183;&quot;&gt;[&lt;/span&gt;1 1&lt;span style=&quot;color: #909183;&quot;&gt;]&lt;/span&gt; &lt;span style=&quot;color: #F5666D;&quot;&gt;:long&lt;/span&gt; &lt;span style=&quot;color: #F5666D;&quot;&gt;:nc&lt;/span&gt;&lt;span style=&quot;color: #7388d6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;
&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #A52A2A; font-weight: bold;&quot;&gt;def&lt;/span&gt; &lt;span style=&quot;color: #0084C8; font-weight: bold;&quot;&gt;position-ids&lt;/span&gt; &lt;span style=&quot;color: #7388d6;&quot;&gt;(&lt;/span&gt;tensor neand-fact &lt;span style=&quot;color: #909183;&quot;&gt;[&lt;/span&gt;1 1&lt;span style=&quot;color: #909183;&quot;&gt;]&lt;/span&gt; &lt;span style=&quot;color: #F5666D;&quot;&gt;:long&lt;/span&gt; &lt;span style=&quot;color: #F5666D;&quot;&gt;:nc&lt;/span&gt;&lt;span style=&quot;color: #7388d6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;
&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #A52A2A; font-weight: bold;&quot;&gt;def&lt;/span&gt; &lt;span style=&quot;color: #0084C8; font-weight: bold;&quot;&gt;attention-mask&lt;/span&gt; &lt;span style=&quot;color: #7388d6;&quot;&gt;(&lt;/span&gt;tensor neand-fact &lt;span style=&quot;color: #909183;&quot;&gt;[&lt;/span&gt;1 1&lt;span style=&quot;color: #909183;&quot;&gt;]&lt;/span&gt; &lt;span style=&quot;color: #F5666D;&quot;&gt;:long&lt;/span&gt; &lt;span style=&quot;color: #F5666D;&quot;&gt;:nc&lt;/span&gt;&lt;span style=&quot;color: #7388d6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;
&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #A52A2A; font-weight: bold;&quot;&gt;def&lt;/span&gt; &lt;span style=&quot;color: #0084C8; font-weight: bold;&quot;&gt;past-key-values&lt;/span&gt; &lt;span style=&quot;color: #7388d6;&quot;&gt;(&lt;/span&gt;repeatedly 60 #&lt;span style=&quot;color: #909183;&quot;&gt;(&lt;/span&gt;tensor fact &lt;span style=&quot;color: #709870;&quot;&gt;[&lt;/span&gt;1 3 1 64&lt;span style=&quot;color: #709870;&quot;&gt;]&lt;/span&gt; &lt;span style=&quot;color: #F5666D;&quot;&gt;:float&lt;/span&gt; &lt;span style=&quot;color: #F5666D;&quot;&gt;:nchw&lt;/span&gt;&lt;span style=&quot;color: #909183;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #7388d6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
Next, create the executable instance model. Nothing too fancy here.
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-clojure&quot;&gt;&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #A52A2A; font-weight: bold;&quot;&gt;def&lt;/span&gt; &lt;span style=&quot;color: #0084C8; font-weight: bold;&quot;&gt;gemma-next!&lt;/span&gt; &lt;span style=&quot;color: #7388d6;&quot;&gt;(&lt;/span&gt;onnx-bp &lt;span style=&quot;color: #909183;&quot;&gt;(&lt;/span&gt;into &lt;span style=&quot;color: #709870;&quot;&gt;[&lt;/span&gt;input-ids attention-mask position-ids&lt;span style=&quot;color: #709870;&quot;&gt;]&lt;/span&gt; past-key-values&lt;span style=&quot;color: #909183;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #7388d6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
Now, these inputs need to be initialized. Normally, that would be done inside an LLM generation loop, but
here we only demonstrate one step, and we transfer some mock data.
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-clojure&quot;&gt;&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;transfer! &lt;span style=&quot;color: #7388d6;&quot;&gt;[&lt;/span&gt;2&lt;span style=&quot;color: #7388d6;&quot;&gt;]&lt;/span&gt; input-ids&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;
&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;transfer! &lt;span style=&quot;color: #7388d6;&quot;&gt;[&lt;/span&gt;0&lt;span style=&quot;color: #7388d6;&quot;&gt;]&lt;/span&gt; position-ids&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;
&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;transfer! &lt;span style=&quot;color: #7388d6;&quot;&gt;[&lt;/span&gt;1&lt;span style=&quot;color: #7388d6;&quot;&gt;]&lt;/span&gt; attention-mask&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;
&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #A52A2A; font-weight: bold;&quot;&gt;doseq&lt;/span&gt; &lt;span style=&quot;color: #7388d6;&quot;&gt;[&lt;/span&gt;pkv past-key-values&lt;span style=&quot;color: #7388d6;&quot;&gt;]&lt;/span&gt;
  &lt;span style=&quot;color: #7388d6;&quot;&gt;(&lt;/span&gt;transfer! &lt;span style=&quot;color: #909183;&quot;&gt;(&lt;/span&gt;repeat 0&lt;span style=&quot;color: #909183;&quot;&gt;)&lt;/span&gt; pkv&lt;span style=&quot;color: #7388d6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
Aaaaand, we actually run the model by calling our gemma function, which provides the next token.
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-clojure&quot;&gt;&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;gemma-next!&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
Now, hold on with the celebration. This does not actually return a full answer from the LLM.
This only returns the next token, but in the form of large tensor full of numbers. The information
is there, but needs to be extracted from these numbers to the form of string. Also, this is only one step;
a LLM would typically run this in a loop and spew tokens after tokens. There&apos;s some more work to do
until we get a ready made, hands-off chatty LLM. But the main work has been done, and now it&apos;s the matter
of setting it up properly, tokenizing the inputs, and calling it in a useful way! Still lots of work,
but not the hardest parts :)
&lt;/p&gt;

&lt;p&gt;
I&apos;ve applied for Clojurists Together yearly funding in 2026. If you are a Clojurists Together member,
and would like to see continued development in this area, &lt;a href=&quot;https://www.clojuriststogether.org/news/vote-on-2026-annual-funding/&quot;&gt;your vote can help me keep working on this&lt;/a&gt; :)
&lt;/p&gt;

&lt;p&gt;
My goal with this funding in 2026 is to continuously develop Clojure AI, ML, and high-performance
ecosystem of Uncomplicate libraries (Neanderhal and many more), on Nvidia GPUs, Apple Silicon, and traditional PC.
In this year, I will also focus on writing tutorals on my blog and creating websites for the projects involved,
which is something that I wanted for years, but didn&apos;t have time to do because I spent all time on
programming.
&lt;/p&gt;
</description>
        <pubDate>Tue, 09 Dec 2025 23:35:00 +0100</pubDate>
        <link>http://dragan.rocks/articles/25/Gemma-3-AI-model-in-Clojure</link>
        <guid isPermaLink="true">http://dragan.rocks/articles/25/Gemma-3-AI-model-in-Clojure</guid>
        
        
        <category>Clojure,</category>
        
        <category>AI,</category>
        
        <category>Deep</category>
        
        <category>Diamond,</category>
        
        <category>Gemma</category>
        
        <category>3</category>
        
        <category>3</category>
        
      </item>
    
      <item>
        <title>Plan for Clojure AI, ML, and high-performance Uncomplicate ecosystem in 2026</title>
        <description>&lt;p&gt;
I&apos;ve applied for Clojurists Together yearly funding in 2026. Here&apos;s my application. If you are a Clojurists Together member,
and would like to see continued development in this area, your vote can help me keep working on this :)
&lt;/p&gt;

&lt;p&gt;
My goal with this funding in 2026 is to continuously develop Clojure AI, ML, and high-performance
ecosystem of Uncomplicate libraries (Neanderhal and many more), on Nvidia GPUs, Apple Silicon, and traditional PC.
In this year, I will also focus on writing tutorals on my blog and creating websites for the projects involved,
which is something that I wanted for years, but didn&apos;t have time to do because I spent all time on
programming.
&lt;/p&gt;
&lt;div id=&quot;outline-container-orgcdb087b&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;orgcdb087b&quot;&gt;How that work will benefit the Clojure community&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-orgcdb087b&quot;&gt;
&lt;p&gt;
This will highly benefit the Clojure community as this is THE AI ecosystem for Clojure,
and supporting AI is arguably the main focus on probably all software platforms.
Clojure has something to offer on that front, beyond just calling OpenAI API as a web service!
&lt;/p&gt;

&lt;p&gt;
Uncomplicate grew to quite a few libraries (of which some are quite big; just Neanderthal is 28,000 lines of
highly-condensed, aggresively macroized, and reusable code): Diamond ONNX Runtime, Neanderthal, Deep Diamond,
ClojureCUDA, ClojureCPP, Apple Presets, ClojureCL, Fluokitten, Bayadera, Clojure Sound, and Commons.
&lt;/p&gt;

&lt;p&gt;
Here&apos;s a word or two of how I hope to improve each of these libraries with Clojurists Together funding in 2026.
&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-orge748947&quot; class=&quot;outline-3&quot;&gt;
&lt;h3 id=&quot;orge748947&quot;&gt;Neanderthal (Clojure&apos;s alternative to NumPy, on steroids)&lt;/h3&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-orge748947&quot;&gt;
&lt;p&gt;
In 2025, Neanderthal celebrated its 10th birthday. It started as a humble but fast matrix and vector library
for Clojure, but after 10 years of relentless improvements, now it boasts a general matrix/vector/linear algebra API
implemented by no less than 5(!) engines for CPUs, GPU (Nvidia CUDA), GPU (OpenCL: AMD, Intel, Nvidia), Apple Silicon (Accelerate),
and general CPU (OpenBLAS). And this is not a superficial support for the sake of ticking a check box; each of these
engines support much more operations on exotic structures, and configuration options, than I&apos;ve seen elsewhere.
It has almost everything, but it doesn&apos;t (YET!) have a METAL-based engine for Apple GPUs. Let&apos;s work on that!
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-org451c97f&quot; class=&quot;outline-3&quot;&gt;
&lt;h3 id=&quot;org451c97f&quot;&gt;Deep Diamond (the Clojure Tensor and Deep Learning library, not quite unlike PyTorch, but of different philosophy)&lt;/h3&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-org451c97f&quot;&gt;
&lt;p&gt;
In 2019, I started Deep Diamond as a demo showcase for Neanderthal&apos;s capabilities as the foundation
for high-performance number-crunching software. It quickly outgrew that, and became a general Tensor/Deep Learning
API, implemented by several fast, native optimized, backends, that run on both CPUs and GPUs, across
hardware platforms (x86_64, GPUs, arm64, Apple Silicon, you name it) and operating systems (Linux, MasOS, Windows).
Of course, it does not clash with Neanderthal, but complements it, in the best manner of highly focused
Clojure libraries that do one job and do it well.
&lt;/p&gt;

&lt;p&gt;
Deep Diamond is quite capable, but it cries for a METAL-based engine for Apple GPUs, too.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-org3470569&quot; class=&quot;outline-3&quot;&gt;
&lt;h3 id=&quot;org3470569&quot;&gt;Diamond ONNX Runtime (the Clojure library for executing AI models)&lt;/h3&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-org3470569&quot;&gt;
&lt;p&gt;
This is the latest gem in Uncomplicate&apos;s store, and I developed it thanks to Clojurists Together
funding in Q3 2025. Similarly to how I started Deep Diamond mainly as a teaching showcase for Neanderthal,
I started this to show Clojure programmers how close we, Clojurists, are to the latest and shiniest AI stuff
that everyone&apos;s raving about. But of course, being close does not mean that we can close the gap
to the multi-billion funded Python ecosystem in a few afternoons. It needs laser-focused development
and knowing what to do, when, and where. Nevertheless, Clojure &lt;b&gt;is there&lt;/b&gt;. Now we can run inference on the trained models
from Hugging Face and other vibrant AI communities directly in Clojure&apos;s REPL. Does this make an effortless billion-dollar
AI startup? NO. Does it bring Clojurians to the party? YES! And there&apos;s more to come.
&lt;/p&gt;

&lt;p&gt;
Not only that this library is new, but the whole wider ecosystem exploded in the last year
with the wide availability of open-weights model that you can run at home. So, lots of functionality
is added upstream all the time, and I hope to be able to stay current and have the best and newest stuff in Clojure..
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-orgb9763c1&quot; class=&quot;outline-3&quot;&gt;
&lt;h3 id=&quot;orgb9763c1&quot;&gt;ClojureCUDA (REPL-based low-level CUDA development)&lt;/h3&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-orgb9763c1&quot;&gt;
&lt;p&gt;
Not many Clojurians may prefer to work with GPU directly, or to write their own kernels. Neither do I.
But, this library is one of the un-celebrated workhorses that enables me to implement whatever I want
in Neanderthal, Deep Diamond, and Diamond ONNX Runtime, instead of just trying to wrap whatever there
is in upstream C++ libraies. ClojureCUDA gives us the superpower of choice: wrap whatever works,
but then implement the missing parts yourself!
&lt;/p&gt;

&lt;p&gt;
As CUDA is receiving a steady stream of changes and improvements, I&apos;d like to improve and extend
ClojureCUDA to always be in top shape! It is not as easy as it seems to the casual onlooker.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-org3444432&quot; class=&quot;outline-3&quot;&gt;
&lt;h3 id=&quot;org3444432&quot;&gt;ClojureCPP (the gateway to native C++ libraries)&lt;/h3&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-org3444432&quot;&gt;
&lt;p&gt;
From 20,000 feet, integrating a native library to JVM and Clojure may look straightforward.
Oh, how wrong they are. Virtually every C++ library is a special kind of jungle, with its
own structures, patterns and inventions. What might seems a minor technical detail might
require special acrobatics to support it on the JVM. Masking that mess under the hood
so that a Clojurian do not need to care might be insanely brittle if it weren&apos;t for
ClojureCPP! It is not as large as Neanderthal or Deep Diamond, but it is one of the reasons
that enables these upper level libraries stay on the 25,000 or 3,000 lines of code mark,
instead of being 500,000 or 50,000, as many of their counterparts in other languages.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-org5d60bff&quot; class=&quot;outline-3&quot;&gt;
&lt;h3 id=&quot;org5d60bff&quot;&gt;Apple Presets (native JNI bindings for various Apple libraries)&lt;/h3&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-org5d60bff&quot;&gt;
&lt;p&gt;
Yup. To support Apple Silicon in Neanderthal and Deep Diamond I had to make these bindings,
since there weren&apos;t any to &quot;just&quot; wrap. And to support more Apple high performance computing apis,
I&apos;ll have to create additional bindings (for example, for METAL) and only then
develop the Clojure part.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-orgfabadd5&quot; class=&quot;outline-3&quot;&gt;
&lt;h3 id=&quot;orgfabadd5&quot;&gt;Fluokitten, Bayadera, ClojureCL, Commons, Clojure Sound, etc.&lt;/h3&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-orgfabadd5&quot;&gt;
&lt;p&gt;
These libraries will not be in focus in 2026., but will probably need some care and
assorted improvements here and there.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-org1a2368e&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;org1a2368e&quot;&gt;Summary:&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-org1a2368e&quot;&gt;
&lt;p&gt;
In short, my focus with this funding with Clojurists Together will have two main branches:
&lt;/p&gt;
&lt;ol class=&quot;org-ol&quot;&gt;
&lt;li&gt;Development of new functionalities, supporting more hardware and platforms for existing functionality,
and fixing issues for a dozen Uncomplicate libraries that already exist. This is what is described
in the text you&apos;ve just read.&lt;/li&gt;
&lt;li&gt;Develop an unified website for Uncomplicate and stuff it with useful information in one place.
Currently, some libraries have websites that I wrote many years ago, while some rely
on GitHub Clojure tests, in-code documentation, tutorials on dragan.rocks and my books.
There are many resources, some of which are quite detailed (2 full books!), but people
without experience (which is the majority of Clojure programmers) have a hard time using all these in organized way.
I hope to solve this with the unified website!&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-org5983ef7&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;org5983ef7&quot;&gt;Projects directly involved:&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-org5983ef7&quot;&gt;
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/uncomplicate/diamond-onnxrt&quot;&gt;https://github.com/uncomplicate/diamond-onnxrt&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/uncomplicate/neanderthal&quot;&gt;https://github.com/uncomplicate/neanderthal&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/uncomplicate/deep-diamond&quot;&gt;https://github.com/uncomplicate/deep-diamond&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/uncomplicate/clojurecuda&quot;&gt;https://github.com/uncomplicate/clojurecuda&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/uncomplicate/clojure-cpp&quot;&gt;https://github.com/uncomplicate/clojure-cpp&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/uncomplicate/clojurecl&quot;&gt;https://github.com/uncomplicate/clojurecl&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/uncomplicate/apple-presets&quot;&gt;https://github.com/uncomplicate/apple-presets&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/uncomplicate/fluokitten&quot;&gt;https://github.com/uncomplicate/fluokitten&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
</description>
        <pubDate>Sat, 29 Nov 2025 01:41:00 +0100</pubDate>
        <link>http://dragan.rocks/articles/25/Clojure-AI-ML-high-performance-Uncomplicate</link>
        <guid isPermaLink="true">http://dragan.rocks/articles/25/Clojure-AI-ML-high-performance-Uncomplicate</guid>
        
        
        <category>Clojure,</category>
        
        <category>AI,</category>
        
        <category>Matrices,</category>
        
        <category>Neanderthal,</category>
        
        <category>Vectors,</category>
        
        <category>Linear</category>
        
        <category>Algebra,</category>
        
        <category>Apple</category>
        
      </item>
    
      <item>
        <title>Not One, Not Two, Not Even Three, but Four Ways to Run an ONNX AI Model on GPU with CUDA</title>
        <description>&lt;p&gt;
Two weeks ago, &lt;a href=&quot;./Clojure-Runs-ONNX-AI-Models-Now&quot;&gt;I announced a new Clojure ML library, Diamond ONNX RT&lt;/a&gt;, which integrates ONNX Runtime into Deep Diamond.
In that post, we explored the classic Hello World example of Neural Networks, MNIST handwritten image recognition, step-by-step.
We run that example on the CPU, from main memory. The next logical step is to execute this stuff on the GPU.
&lt;/p&gt;

&lt;p&gt;
You&apos;ll see that with a little help of &lt;a href=&quot;https://github.com/uncomplicate/clojurecuda&quot;&gt;ClojureCUDA&lt;/a&gt;&lt;iframe class=&quot;github-btn&quot; src=&quot;https://ghbtns.com/github-btn.html?user=uncomplicate&amp;amp;repo=clojurecuda&amp;amp;type=watch&quot; width=&quot;100&quot; height=&quot;20&quot; title=&quot;Star on GitHub&quot; frameBorder=&quot;0&quot;&gt;&lt;/iframe&gt; and &lt;a href=&quot;https://github.com/uncomplicate/clojurecl&quot;&gt;Deep Diamond&lt;/a&gt;&lt;iframe class=&quot;github-btn&quot; src=&quot;https://ghbtns.com/github-btn.html?user=uncomplicate&amp;amp;repo=deep-diamond&amp;amp;type=watch&quot; width=&quot;100&quot; height=&quot;20&quot; title=&quot;Star on GitHub&quot; frameBorder=&quot;0&quot;&gt;&lt;/iframe&gt;
built-in CUDA machinery, this is both easy and simple, requiring almost no effort from
a curious Clojure programmer. But don&apos;t just trust me; let&apos;s fire up your REPL, and we can continue together.
&lt;/p&gt;

&lt;p&gt;
Here&apos;s how you can evaluate this directly in your REPL (you can use the Hello World that is provided in the &lt;a href=&quot;https://github.com/uncomplicate/diamond-onnxrt/tree/main/examples/hello-world&quot;&gt;&lt;code&gt;./examples&lt;/code&gt;&lt;/a&gt;
sub-folder of Diamond ONNX RT as a springboard).
&lt;/p&gt;
&lt;div id=&quot;outline-container-org7278bfb&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;org7278bfb&quot;&gt;Require Diamond&apos;s namespaces&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-org7278bfb&quot;&gt;
&lt;p&gt;
First things first, we refer functions that we&apos;re going to use.
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-clojure&quot;&gt;&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;require &apos;&lt;span style=&quot;color: #7388d6;&quot;&gt;[&lt;/span&gt;uncomplicate.commons.core &lt;span style=&quot;color: #F5666D;&quot;&gt;:refer&lt;/span&gt; &lt;span style=&quot;color: #909183;&quot;&gt;[&lt;/span&gt;with-release&lt;span style=&quot;color: #909183;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #7388d6;&quot;&gt;]&lt;/span&gt;
         &apos;&lt;span style=&quot;color: #7388d6;&quot;&gt;[&lt;/span&gt;uncomplicate.neanderthal.core &lt;span style=&quot;color: #F5666D;&quot;&gt;:refer&lt;/span&gt; &lt;span style=&quot;color: #909183;&quot;&gt;[&lt;/span&gt;transfer! iamax native&lt;span style=&quot;color: #909183;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #7388d6;&quot;&gt;]&lt;/span&gt;
         &apos;&lt;span style=&quot;color: #7388d6;&quot;&gt;[&lt;/span&gt;uncomplicate.diamond
           &lt;span style=&quot;color: #909183;&quot;&gt;[&lt;/span&gt;tensor &lt;span style=&quot;color: #F5666D;&quot;&gt;:refer&lt;/span&gt; &lt;span style=&quot;color: #709870;&quot;&gt;[&lt;/span&gt;tensor with-diamond&lt;span style=&quot;color: #709870;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #909183;&quot;&gt;]&lt;/span&gt;
           &lt;span style=&quot;color: #909183;&quot;&gt;[&lt;/span&gt;dnn &lt;span style=&quot;color: #F5666D;&quot;&gt;:refer&lt;/span&gt; &lt;span style=&quot;color: #709870;&quot;&gt;[&lt;/span&gt;network&lt;span style=&quot;color: #709870;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #909183;&quot;&gt;]&lt;/span&gt;
           &lt;span style=&quot;color: #909183;&quot;&gt;[&lt;/span&gt;onnxrt &lt;span style=&quot;color: #F5666D;&quot;&gt;:refer&lt;/span&gt; &lt;span style=&quot;color: #709870;&quot;&gt;[&lt;/span&gt;onnx&lt;span style=&quot;color: #709870;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #909183;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #7388d6;&quot;&gt;]&lt;/span&gt;
         &apos;&lt;span style=&quot;color: #7388d6;&quot;&gt;[&lt;/span&gt;uncomplicate.diamond.internal.dnnl.factory &lt;span style=&quot;color: #F5666D;&quot;&gt;:refer&lt;/span&gt; &lt;span style=&quot;color: #909183;&quot;&gt;[&lt;/span&gt;dnnl-factory&lt;span style=&quot;color: #909183;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #7388d6;&quot;&gt;]&lt;/span&gt;
         &apos;&lt;span style=&quot;color: #7388d6;&quot;&gt;[&lt;/span&gt;uncomplicate.diamond.internal.cudnn.factory &lt;span style=&quot;color: #F5666D;&quot;&gt;:refer&lt;/span&gt; &lt;span style=&quot;color: #909183;&quot;&gt;[&lt;/span&gt;cudnn-factory&lt;span style=&quot;color: #909183;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #7388d6;&quot;&gt;]&lt;/span&gt;
         &apos;&lt;span style=&quot;color: #7388d6;&quot;&gt;[&lt;/span&gt;hello-world.native &lt;span style=&quot;color: #F5666D;&quot;&gt;:refer&lt;/span&gt; &lt;span style=&quot;color: #909183;&quot;&gt;[&lt;/span&gt;input-desc input-tz mnist-onnx&lt;span style=&quot;color: #909183;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #7388d6;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
None of the following ways to run CUDA models has preference, you use the one that best suits your needs.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-orge34c8e7&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;orge34c8e7&quot;&gt;Way one&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-orge34c8e7&quot;&gt;
&lt;p&gt;
One of the ways to run ONNX models on your GPU is to simply use Deep Diamond&apos;s cuDNN factory
as the backend for your tensors. Then, the machinery recognizes what you need and proceeds
doing everything on the GPU, using the right stream for tensors, Deep Diamond operations,
and ONNX Runtime operations. This looks exactly the same as any other Deep Diamond example
from this blog or the DLFP book.
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-clojure&quot;&gt;&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;with-diamond cudnn-factory &lt;span style=&quot;color: #7388d6;&quot;&gt;[]&lt;/span&gt;
  &lt;span style=&quot;color: #7388d6;&quot;&gt;(&lt;/span&gt;with-release &lt;span style=&quot;color: #909183;&quot;&gt;[&lt;/span&gt;cuda-input-tz &lt;span style=&quot;color: #709870;&quot;&gt;(&lt;/span&gt;tensor input-desc&lt;span style=&quot;color: #709870;&quot;&gt;)&lt;/span&gt;
                 mnist &lt;span style=&quot;color: #709870;&quot;&gt;(&lt;/span&gt;network cuda-input-tz &lt;span style=&quot;color: #907373;&quot;&gt;[&lt;/span&gt;mnist-onnx&lt;span style=&quot;color: #907373;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #709870;&quot;&gt;)&lt;/span&gt;
                 classify! &lt;span style=&quot;color: #709870;&quot;&gt;(&lt;/span&gt;mnist cuda-input-tz&lt;span style=&quot;color: #709870;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #909183;&quot;&gt;]&lt;/span&gt;
    &lt;span style=&quot;color: #909183;&quot;&gt;(&lt;/span&gt;transfer! input-tz cuda-input-tz&lt;span style=&quot;color: #909183;&quot;&gt;)&lt;/span&gt;
    &lt;span style=&quot;color: #909183;&quot;&gt;(&lt;/span&gt;iamax &lt;span style=&quot;color: #709870;&quot;&gt;(&lt;/span&gt;native &lt;span style=&quot;color: #907373;&quot;&gt;(&lt;/span&gt;classify!&lt;span style=&quot;color: #907373;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #709870;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #909183;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #7388d6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;pre class=&quot;example&quot;&gt;
7
&lt;/pre&gt;


&lt;p&gt;
..it says.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-org45bbc19&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;org45bbc19&quot;&gt;Way two&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-org45bbc19&quot;&gt;
&lt;p&gt;
As an ONNX model usually defines the whole network, you don&apos;t need to use Deep Diamond&apos;s
network as a wrapper. The &lt;code&gt;onnx&lt;/code&gt; function can create a Deep Diamond blueprint,
and Deep Diamond blueprints can be used as standalone layer creators. Just like
in the following code snippet.
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-clojure&quot;&gt;&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;with-diamond cudnn-factory &lt;span style=&quot;color: #7388d6;&quot;&gt;[]&lt;/span&gt;
  &lt;span style=&quot;color: #7388d6;&quot;&gt;(&lt;/span&gt;with-release &lt;span style=&quot;color: #909183;&quot;&gt;[&lt;/span&gt;cuda-input-tz &lt;span style=&quot;color: #709870;&quot;&gt;(&lt;/span&gt;tensor input-desc&lt;span style=&quot;color: #709870;&quot;&gt;)&lt;/span&gt;
                 mnist-bp &lt;span style=&quot;color: #709870;&quot;&gt;(&lt;/span&gt;onnx cuda-input-tz &lt;span style=&quot;color: #4E9A06;&quot;&gt;&quot;../../data/mnist-12.onnx&quot;&lt;/span&gt; &lt;span style=&quot;color: #F5666D;&quot;&gt;nil&lt;/span&gt;&lt;span style=&quot;color: #709870;&quot;&gt;)&lt;/span&gt;
                 infer-number! &lt;span style=&quot;color: #709870;&quot;&gt;(&lt;/span&gt;mnist-bp cuda-input-tz&lt;span style=&quot;color: #709870;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #909183;&quot;&gt;]&lt;/span&gt;
    &lt;span style=&quot;color: #909183;&quot;&gt;(&lt;/span&gt;transfer! input-tz cuda-input-tz&lt;span style=&quot;color: #909183;&quot;&gt;)&lt;/span&gt;
    &lt;span style=&quot;color: #909183;&quot;&gt;(&lt;/span&gt;iamax &lt;span style=&quot;color: #709870;&quot;&gt;(&lt;/span&gt;native &lt;span style=&quot;color: #907373;&quot;&gt;(&lt;/span&gt;infer-number!&lt;span style=&quot;color: #907373;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #709870;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #909183;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #7388d6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;pre class=&quot;example&quot;&gt;
7
&lt;/pre&gt;


&lt;p&gt;
&amp;#x2026; again.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-orga90330f&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;orga90330f&quot;&gt;Way three&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-orga90330f&quot;&gt;
&lt;p&gt;
We can even mix CUDA and CPU. Let&apos;s say your input and output tensors are in the main
memory, and you&apos;d like to process them on the CPU, but you want to take advantage
of the GPU for the model processing itself. Nothing is easier, if you use Deep Diamond.
Just specify an &lt;code&gt;:ep&lt;/code&gt; (execution provider) in the &lt;code&gt;onnx&lt;/code&gt; function configuration, and tell it that
you&apos;d like to use only CUDA. Now your network is executed on the GPU, while your
input and output tensors are in the main memory, and can be easily accessed.
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-clojure&quot;&gt;&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;with-release &lt;span style=&quot;color: #7388d6;&quot;&gt;[&lt;/span&gt;mnist &lt;span style=&quot;color: #909183;&quot;&gt;(&lt;/span&gt;network input-tz &lt;span style=&quot;color: #709870;&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color: #907373;&quot;&gt;(&lt;/span&gt;onnx &lt;span style=&quot;color: #4E9A06;&quot;&gt;&quot;../../data/mnist-12.onnx&quot;&lt;/span&gt; &lt;span style=&quot;color: #6276ba;&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color: #F5666D;&quot;&gt;:ep&lt;/span&gt; &lt;span style=&quot;color: #858580;&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color: #F5666D;&quot;&gt;:cuda&lt;/span&gt;&lt;span style=&quot;color: #858580;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #6276ba;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #907373;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #709870;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #909183;&quot;&gt;)&lt;/span&gt;
               infer-number! &lt;span style=&quot;color: #909183;&quot;&gt;(&lt;/span&gt;mnist input-tz&lt;span style=&quot;color: #909183;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #7388d6;&quot;&gt;]&lt;/span&gt;
        &lt;span style=&quot;color: #7388d6;&quot;&gt;(&lt;/span&gt;iamax &lt;span style=&quot;color: #909183;&quot;&gt;(&lt;/span&gt;infer-number!&lt;span style=&quot;color: #909183;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #7388d6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;pre class=&quot;example&quot;&gt;
7
&lt;/pre&gt;


&lt;p&gt;
&amp;#x2026; and again the same answer.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-org21da661&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;org21da661&quot;&gt;Way four&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-org21da661&quot;&gt;
&lt;p&gt;
Still need more options? No problem, &lt;code&gt;onnx&lt;/code&gt; can create a standalone blueprint, and that blueprint
recognizes the &lt;code&gt;:ep&lt;/code&gt; configuration too.
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-clojure&quot;&gt;&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;with-release &lt;span style=&quot;color: #7388d6;&quot;&gt;[&lt;/span&gt;mnist-bp &lt;span style=&quot;color: #909183;&quot;&gt;(&lt;/span&gt;onnx input-tz &lt;span style=&quot;color: #4E9A06;&quot;&gt;&quot;../../data/mnist-12.onnx&quot;&lt;/span&gt; &lt;span style=&quot;color: #709870;&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color: #F5666D;&quot;&gt;:ep&lt;/span&gt; &lt;span style=&quot;color: #907373;&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color: #F5666D;&quot;&gt;:cuda&lt;/span&gt;&lt;span style=&quot;color: #907373;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #709870;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #909183;&quot;&gt;)&lt;/span&gt;
               infer-number! &lt;span style=&quot;color: #909183;&quot;&gt;(&lt;/span&gt;mnist-bp input-tz&lt;span style=&quot;color: #909183;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #7388d6;&quot;&gt;]&lt;/span&gt;
        &lt;span style=&quot;color: #7388d6;&quot;&gt;(&lt;/span&gt;iamax &lt;span style=&quot;color: #909183;&quot;&gt;(&lt;/span&gt;infer-number!&lt;span style=&quot;color: #909183;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #7388d6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;pre class=&quot;example&quot;&gt;
7
&lt;/pre&gt;


&lt;p&gt;
No surprises here.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-org6e7e7e4&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;org6e7e7e4&quot;&gt;Is there anything easier?&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-org6e7e7e4&quot;&gt;
&lt;p&gt;
If you&apos;ve seen code in any programming language that does this in a simpler and easier
way, please let me know, so we can try to make Clojure even better in the age of AI!
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-org8562baa&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;org8562baa&quot;&gt;The books&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-org8562baa&quot;&gt;
&lt;p&gt;
Should I mention that the book &lt;a href=&quot;https://aiprobook.com/deep-learning-for-programmers/&quot;&gt;Deep Learning for Programmers: An Interactive Tutorial with
CUDA, OpenCL, DNNL, Java, and Clojure&lt;/a&gt; teaches the nuts and bolts of neural networks and deep learning
by showing you how Deep Diamond is built, &lt;b&gt;from scratch&lt;/b&gt;? In interactive sessions. Each line of code
can be executed and the results inspected in the plain Clojure REPL. The best way to master something is to build
it yourself!
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
</description>
        <pubDate>Sun, 09 Nov 2025 18:49:00 +0100</pubDate>
        <link>http://dragan.rocks/articles/25/Four-Ways-to-ONNX-on-GPU-in-Clojure-and-CUDA</link>
        <guid isPermaLink="true">http://dragan.rocks/articles/25/Four-Ways-to-ONNX-on-GPU-in-Clojure-and-CUDA</guid>
        
        
        <category>Clojure,</category>
        
        <category>AI,</category>
        
        <category>Deep</category>
        
        <category>Diamond,</category>
        
        <category>Tensors</category>
        
      </item>
    
      <item>
        <title>Get Ready for Clojure, GPU, and AI in 2026 with CUDA 13.0</title>
        <description>&lt;div id=&quot;outline-container-orgd4dbf90&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;orgd4dbf90&quot;&gt;A little anniversary&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-orgd4dbf90&quot;&gt;
&lt;p&gt;
Did you know that CUDA has been available in Clojure for the last 9 years through ClojureCUDA,
and GPU programming through OpenCL for more than 10? I almost forgot about
these anniversaries.
&lt;/p&gt;

&lt;p&gt;
Ten years ago most people liked it a lot, starred it on Github, patted me on the back,
but then concluded that they don&apos;t have an Nvidia card available on their laptops,
or, if they had GPUs, that they won&apos;t have time to learn to think in massive parallel
algorithms, or if they have time and will, that there are no GPUs in the servers,
so what would they do with their applications, even if they created them in Clojure,
and so on, and so off :)
&lt;/p&gt;

&lt;p&gt;
But, &lt;a href=&quot;https://github.com/uncomplicate/clojurecuda&quot;&gt;ClojureCUDA&lt;/a&gt;&lt;iframe class=&quot;github-btn&quot; src=&quot;https://ghbtns.com/github-btn.html?user=uncomplicate&amp;amp;repo=clojurecuda&amp;amp;type=watch&quot; width=&quot;100&quot; height=&quot;20&quot; title=&quot;Star on GitHub&quot; frameBorder=&quot;0&quot;&gt;&lt;/iframe&gt; and &lt;a href=&quot;https://github.com/uncomplicate/clojurecl&quot;&gt;ClojureCL&lt;/a&gt;&lt;iframe class=&quot;github-btn&quot; src=&quot;https://ghbtns.com/github-btn.html?user=uncomplicate&amp;amp;repo=clojurecl&amp;amp;type=watch&quot; width=&quot;100&quot; height=&quot;20&quot; title=&quot;Star on GitHub&quot; frameBorder=&quot;0&quot;&gt;&lt;/iframe&gt; continued living on for these 10 years, I used them in
creating &lt;a href=&quot;https://github.com/uncomplicate/neanderthal&quot;&gt;Neanderthal&lt;/a&gt;&lt;iframe class=&quot;github-btn&quot; src=&quot;https://ghbtns.com/github-btn.html?user=uncomplicate&amp;amp;repo=neanderthal&amp;amp;type=watch&quot; width=&quot;100&quot; height=&quot;20&quot; title=&quot;Star on GitHub&quot; frameBorder=&quot;0&quot;&gt;&lt;/iframe&gt;, &lt;a href=&quot;https://github.com/uncomplicate/deep-diamond&quot;&gt;Deep Diamond&lt;/a&gt;&lt;iframe class=&quot;github-btn&quot; src=&quot;https://ghbtns.com/github-btn.html?user=uncomplicate&amp;amp;repo=deep-diamond&amp;amp;type=watch&quot; width=&quot;100&quot; height=&quot;20&quot; title=&quot;Star on GitHub&quot; frameBorder=&quot;0&quot;&gt;&lt;/iframe&gt;, and &lt;a href=&quot;https://github.com/uncomplicate/diamond-onnxrt&quot;&gt;Diamond ML&lt;iframe class=&quot;github-btn&quot; src=&quot;https://ghbtns.com/github-btn.html?user=uncomplicate&amp;amp;repo=diamond-onnxrt&amp;amp;type=watch&quot; width=&quot;100&quot; height=&quot;20&quot; title=&quot;Star on GitHub&quot; frameBorder=&quot;0&quot;&gt;&lt;/iframe&gt;&lt;/a&gt;, and they proved themselves
as simple and reliable tools. I still had trouble convincing Clojure programmers that
they can write GPU programs that run as fast as they&apos;d wrote them in C++, but
&lt;i&gt;interactively&lt;/i&gt; in the Cloujre REPL, without C++ hell.
&lt;/p&gt;

&lt;p&gt;
But I&apos;m not easy to shake off! If it&apos;s necessary, I&apos;ll continue for 10 more years,
for I&apos;m convinced there&apos;d be a moment when Clojure programmers are going to
say &quot;hmmm, this is something that we &lt;i&gt;can&lt;/i&gt; use and be good at!&quot;.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-org747f487&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;org747f487&quot;&gt;CUDA 13 is here!&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-org747f487&quot;&gt;
&lt;p&gt;
I&apos;ve recently released  &lt;a href=&quot;https://github.com/uncomplicate/clojurecuda&quot;&gt;ClojureCUDA&lt;/a&gt;&lt;iframe class=&quot;github-btn&quot; src=&quot;https://ghbtns.com/github-btn.html?user=uncomplicate&amp;amp;repo=clojurecuda&amp;amp;type=watch&quot; width=&quot;100&quot; height=&quot;20&quot; title=&quot;Star on GitHub&quot; frameBorder=&quot;0&quot;&gt;&lt;/iframe&gt;  0.25.0, with support for the latest CUDA 13.0.2!
&lt;/p&gt;

&lt;p&gt;
Why not celebrate that by opening the REPL, and coding your first Hello World application
on the GPU? I promise, it won&apos;t be a usual GPU carpet of text; this is ClojureCUDA,
it follows the Clojure philosophy by being simple and interactive!
&lt;/p&gt;

&lt;p&gt;
There&apos;s not much sense in wielding a GPU to print out &quot;Hello World&quot;.
Note that it is also not very useful to work with scalar numbers and call a GPU function
to add or multiply two numbers. No. Unless you have many, many, numbers to crunch,
stay by your trusty CPU. For our purposes, many, many, numbers would be two vectors
of dimension 3 (hey, it&apos;s hello world; imagine it&apos;s 3 billion). Also, even when we
have many, many, numbers the sheer cost of getting them to the GPU memory would
destroy any gains we get in the computation speed, so we must also ensure that
we want to perfom many complicated operations. Well, we will only do the
simple operation of adding these two vectors, and we will pretend that this
operation is extra-demanding (we&apos;re hello-worlders today, we can cheat a bit).
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-orgba9ae10&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;orgba9ae10&quot;&gt;CUDA Hello World&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-orgba9ae10&quot;&gt;
&lt;p&gt;
First things first, we require the functions that we&apos;ll use.
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-clojure&quot;&gt;&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;require &apos;&lt;span style=&quot;color: #7388d6;&quot;&gt;[&lt;/span&gt;uncomplicate.commons.core &lt;span style=&quot;color: #F5666D;&quot;&gt;:refer&lt;/span&gt; &lt;span style=&quot;color: #909183;&quot;&gt;[&lt;/span&gt;release&lt;span style=&quot;color: #909183;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #7388d6;&quot;&gt;]&lt;/span&gt;
         &apos;&lt;span style=&quot;color: #7388d6;&quot;&gt;[&lt;/span&gt;uncomplicate.clojure-cpp &lt;span style=&quot;color: #F5666D;&quot;&gt;:refer&lt;/span&gt; &lt;span style=&quot;color: #909183;&quot;&gt;[&lt;/span&gt;float-pointer pointer-seq&lt;span style=&quot;color: #909183;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #7388d6;&quot;&gt;]&lt;/span&gt;
         &apos;&lt;span style=&quot;color: #7388d6;&quot;&gt;[&lt;/span&gt;uncomplicate.clojurecuda.core
           &lt;span style=&quot;color: #F5666D;&quot;&gt;:refer&lt;/span&gt; &lt;span style=&quot;color: #909183;&quot;&gt;[&lt;/span&gt;compile! context device function grid-1d init launch! mem-alloc-driver
                   mem-alloc-pinned mem-alloc-runtime memcpy-host! module parameters program
                   synchronize! push-context!&lt;span style=&quot;color: #909183;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #7388d6;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
If it seems to you that this list already looks too large, I agree with you.
But, don&apos;t be afraid; in Uncomplicate libraries there are so many higher-level
helpers that you&apos;ll rarely need to touch these. I only use them here because
I want to show you that even when we program at the base CUDA level, Clojure
can do it interactively and each line can be evaluated by itself, and each
intermediate result can be inspected and understood.
&lt;/p&gt;

&lt;p&gt;
I&apos;ll use &lt;code&gt;def&lt;/code&gt; for poor man variables, and &lt;code&gt;pop-context!&lt;/code&gt; so this is evaluated step-by-step. The real
code would be much simpler; resources can be managed by &lt;code&gt;with-release&lt;/code&gt; and &lt;code&gt;with-context&lt;/code&gt;!
&lt;/p&gt;

&lt;p&gt;
First we initialize CUDA and create the the CUDA context.
&lt;/p&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-clojure&quot;&gt;&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;init&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;
&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #A52A2A; font-weight: bold;&quot;&gt;def&lt;/span&gt; &lt;span style=&quot;color: #0084C8; font-weight: bold;&quot;&gt;ctx&lt;/span&gt; &lt;span style=&quot;color: #7388d6;&quot;&gt;(&lt;/span&gt;context &lt;span style=&quot;color: #909183;&quot;&gt;(&lt;/span&gt;device&lt;span style=&quot;color: #909183;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #7388d6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
Unfortunately, CUDA insists on managing contexts in different threads by itself, so we have
to let CUDA know that we want to use the context that we&apos;ve just created. ClojureCUDA
has some macros that can help with making this simpler, such as &lt;code&gt;with-context&lt;/code&gt;, and &lt;code&gt;in-context&lt;/code&gt;,
but we&apos;ll do this hello world as real ninjas, with basic tools!
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-clojure&quot;&gt;&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;push-context! ctx&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
Many language integrations try to let you write &lt;i&gt;everything&lt;/i&gt; in that language, both the
host code that manages GPU computations, and the GPU kernels themselves. So far, they
don&apos;t fare too well compared to C++ CUDA, even when it comes to simplicity of such kernel code.
ClojureCUDA doesn&apos;t do that, for a reason. We are practical people. We understand that
we won&apos;t be able compile kernels ourselves and be competitive with Nvidia. So, we write
kernels in C++ that Nvidia uses, since they are typically not that complicated compared
to host code that manages them. We can load these kernels as strings, and I find it&apos;s
most convenient to not sprinkle these strings throughout my &lt;code&gt;.clj&lt;/code&gt; source files,
but to load them from &lt;code&gt;.cu&lt;/code&gt; files, which contain C++ code that text editors recognize.
&lt;/p&gt;

&lt;p&gt;
We load the kernel source.
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-clojure&quot;&gt;&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #A52A2A; font-weight: bold;&quot;&gt;def&lt;/span&gt; &lt;span style=&quot;color: #0084C8; font-weight: bold;&quot;&gt;kernel-source&lt;/span&gt; &lt;span style=&quot;color: #7388d6;&quot;&gt;(&lt;/span&gt;slurp &lt;span style=&quot;color: #4E9A06;&quot;&gt;&quot;test/cuda/examples/jnvrtc-vector-add.cu&quot;&lt;/span&gt;&lt;span style=&quot;color: #7388d6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
Next, we compile it.
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-clojure&quot;&gt;&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #A52A2A; font-weight: bold;&quot;&gt;def&lt;/span&gt; &lt;span style=&quot;color: #0084C8; font-weight: bold;&quot;&gt;prog&lt;/span&gt; &lt;span style=&quot;color: #7388d6;&quot;&gt;(&lt;/span&gt;compile! &lt;span style=&quot;color: #909183;&quot;&gt;(&lt;/span&gt;program kernel-source&lt;span style=&quot;color: #909183;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #7388d6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
We create the module&amp;#x2026;
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-clojure&quot;&gt;&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #A52A2A; font-weight: bold;&quot;&gt;def&lt;/span&gt; &lt;span style=&quot;color: #0084C8; font-weight: bold;&quot;&gt;m&lt;/span&gt; &lt;span style=&quot;color: #7388d6;&quot;&gt;(&lt;/span&gt;module prog&lt;span style=&quot;color: #7388d6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
&amp;#x2026; and load the &lt;code&gt;add&lt;/code&gt; function that was defined in the kernel code. CUDA kernels
are short functions that run on the GPU.
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-clojure&quot;&gt;&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #A52A2A; font-weight: bold;&quot;&gt;def&lt;/span&gt; &lt;span style=&quot;color: #0084C8; font-weight: bold;&quot;&gt;add&lt;/span&gt; &lt;span style=&quot;color: #7388d6;&quot;&gt;(&lt;/span&gt;function m &lt;span style=&quot;color: #4E9A06;&quot;&gt;&quot;add&quot;&lt;/span&gt;&lt;span style=&quot;color: #7388d6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
This way we get the best of both worlds: we edit short C++ kernels, and then load them
in our Clojure REPL and manage the kernels they define. If we change anything, there&apos;s
no need for recompilation of everything; just the short &lt;code&gt;.cu&lt;/code&gt; file that changed, and
this is also interactive, as these tools are available as Clojure functions.
&lt;/p&gt;

&lt;p&gt;
Next, this kernel needs data! We allocate some memory on the GPU. There are a few different
types that CUDA offers, and even a few CUDA APIS: runtime and driver. Typically, the runtime
API is what CUDA uses in the C++ code that mixes host and GPU device code, while the driver
API is more geared towards tools such is ClojureCUDA. But, some CUDA libraries will expect
inputs to be from the runtime API, and ClojureCUDA supports both. We can even mix them!
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-clojure&quot;&gt;&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #A52A2A; font-weight: bold;&quot;&gt;def&lt;/span&gt; &lt;span style=&quot;color: #0084C8; font-weight: bold;&quot;&gt;gpu-a&lt;/span&gt; &lt;span style=&quot;color: #7388d6;&quot;&gt;(&lt;/span&gt;mem-alloc-runtime &lt;span style=&quot;color: #909183;&quot;&gt;(&lt;/span&gt;* &lt;span style=&quot;color: #2F8B58; font-weight: bold;&quot;&gt;Float&lt;/span&gt;/BYTES 3&lt;span style=&quot;color: #909183;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #7388d6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;
&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #A52A2A; font-weight: bold;&quot;&gt;def&lt;/span&gt; &lt;span style=&quot;color: #0084C8; font-weight: bold;&quot;&gt;gpu-b&lt;/span&gt; &lt;span style=&quot;color: #7388d6;&quot;&gt;(&lt;/span&gt;mem-alloc-driver &lt;span style=&quot;color: #909183;&quot;&gt;(&lt;/span&gt;* &lt;span style=&quot;color: #2F8B58; font-weight: bold;&quot;&gt;Float&lt;/span&gt;/BYTES 3&lt;span style=&quot;color: #909183;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #7388d6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
The data needs to be transferred to the GPU memory. There are many functions in CUDA for
doing that for every combination of different argument types. ClojureCUDA simplifies this
a lot with protocols, and usually &lt;code&gt;memcpy-host!&lt;/code&gt; will find the right way to transfer the
data. We also need the place to keep the results, unless we want to overwrite one of
the two input arrays.
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-clojure&quot;&gt;&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;memcpy-host! &lt;span style=&quot;color: #7388d6;&quot;&gt;(&lt;/span&gt;float-pointer &lt;span style=&quot;color: #909183;&quot;&gt;[&lt;/span&gt;1 2 3&lt;span style=&quot;color: #909183;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #7388d6;&quot;&gt;)&lt;/span&gt; gpu-a&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;
&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;memcpy-host! &lt;span style=&quot;color: #7388d6;&quot;&gt;(&lt;/span&gt;float-pointer &lt;span style=&quot;color: #909183;&quot;&gt;[&lt;/span&gt;2 3 4&lt;span style=&quot;color: #909183;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #7388d6;&quot;&gt;)&lt;/span&gt; gpu-b&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;
&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #A52A2A; font-weight: bold;&quot;&gt;def&lt;/span&gt; &lt;span style=&quot;color: #0084C8; font-weight: bold;&quot;&gt;gpu-result&lt;/span&gt; &lt;span style=&quot;color: #7388d6;&quot;&gt;(&lt;/span&gt;mem-alloc-pinned &lt;span style=&quot;color: #909183;&quot;&gt;(&lt;/span&gt;* &lt;span style=&quot;color: #2F8B58; font-weight: bold;&quot;&gt;Float&lt;/span&gt;/BYTES 3&lt;span style=&quot;color: #909183;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #7388d6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
That&apos;s a lot of work to set everything up! Let&apos;s compute it at last!
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-clojure&quot;&gt;&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;launch! add &lt;span style=&quot;color: #7388d6;&quot;&gt;(&lt;/span&gt;grid-1d 3&lt;span style=&quot;color: #7388d6;&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: #7388d6;&quot;&gt;(&lt;/span&gt;parameters 3 gpu-a gpu-b gpu-result&lt;span style=&quot;color: #7388d6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
The kernels are launched asynchronously. That means that the &lt;code&gt;launch!&lt;/code&gt; function returns
as soon as it puts the kernel in the computation queue of the GPU, typically &lt;i&gt;before&lt;/i&gt; the kernel
has actually been executed; there might be 1000 kernels in the queue before this one. We can
explicitly wait until the kernel has completed its work by calling &lt;code&gt;synchronize!&lt;/code&gt;.
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-clojure&quot;&gt;&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;synchronize!&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
Since we now know that the new data is in the &lt;code&gt;gpu-result&lt;/code&gt; array, we will have to
move it back to the host if we wont to see it.
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-clojure&quot;&gt;&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;pointer-seq &lt;span style=&quot;color: #7388d6;&quot;&gt;(&lt;/span&gt;memcpy-host! gpu-result &lt;span style=&quot;color: #909183;&quot;&gt;(&lt;/span&gt;float-pointer 3&lt;span style=&quot;color: #909183;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #7388d6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-clojure&quot;&gt;=&amp;gt; &lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;3.0 5.0 7.0&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;
Yeah, I know, a dozen lines of code for a simple addition of two vectors.
But hear me out: the management code for more demanding kernels is not much
more complicated. So, it&apos;s a dozen lines for this simple case, but it will
be a dozen lines for some real crunching. Or 23 lines, but not 2000 lines.
&lt;/p&gt;

&lt;p&gt;
Plus, there are so many functions &lt;i&gt;in the libraries&lt;/i&gt; for computing vectors,
matrices, and tensors, that you&apos;ll write your own kernels only occasionally,
and you&apos;ll still get great speed, once you learn the basics.
&lt;/p&gt;

&lt;p&gt;
So, invest some time in 2026, learn the basics of GPU computing,
and enjoy the coming AI age! In Clojure!
&lt;/p&gt;

&lt;p&gt;
Oh, I didn&apos;t show you the C++ kernel code. It&apos;s C++, it must be scary!
No, it&apos;s not. CUDA kernels are written in a subset of C++, without the
scary parts!
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-cpp&quot;&gt;&lt;span style=&quot;color: #A52A2A; font-weight: bold;&quot;&gt;extern&lt;/span&gt; &lt;span style=&quot;color: #4E9A06;&quot;&gt;&quot;C&quot;&lt;/span&gt;
__global__ &lt;span style=&quot;color: #2F8B58; font-weight: bold;&quot;&gt;void&lt;/span&gt; &lt;span style=&quot;color: #00578E; font-weight: bold;&quot;&gt;add&lt;/span&gt;(&lt;span style=&quot;color: #2F8B58; font-weight: bold;&quot;&gt;int&lt;/span&gt; &lt;span style=&quot;color: #0084C8; font-weight: bold;&quot;&gt;n&lt;/span&gt;, &lt;span style=&quot;color: #2F8B58; font-weight: bold;&quot;&gt;float&lt;/span&gt; *&lt;span style=&quot;color: #0084C8; font-weight: bold;&quot;&gt;a&lt;/span&gt;, &lt;span style=&quot;color: #2F8B58; font-weight: bold;&quot;&gt;float&lt;/span&gt; *&lt;span style=&quot;color: #0084C8; font-weight: bold;&quot;&gt;b&lt;/span&gt;, &lt;span style=&quot;color: #2F8B58; font-weight: bold;&quot;&gt;float&lt;/span&gt; *&lt;span style=&quot;color: #0084C8; font-weight: bold;&quot;&gt;sum&lt;/span&gt;) {
    &lt;span style=&quot;color: #2F8B58; font-weight: bold;&quot;&gt;int&lt;/span&gt; &lt;span style=&quot;color: #0084C8; font-weight: bold;&quot;&gt;i&lt;/span&gt; = blockIdx.x * blockDim.x + threadIdx.x;
    &lt;span style=&quot;color: #A52A2A; font-weight: bold;&quot;&gt;if&lt;/span&gt; (i &amp;lt; n) {
        sum[i] = a[i] + b[i];
    }
};
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
&amp;#x2026; and, hey, we shouldn&apos;t forget to clean up the memory! Since if we didn&apos;t use
&lt;code&gt;def&lt;/code&gt;, we could just rely on &lt;code&gt;with-release&lt;/code&gt; to do this for us, but we did everything
manually, and now we have to clean up manually.
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-clojure&quot;&gt;&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;release gpu-result&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;
&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;release gpu-b&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;
&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;release gpu-a&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;
&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;release add&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;
&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;release m&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;
&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;release prog&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;
&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;release ctx&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
</description>
        <pubDate>Thu, 30 Oct 2025 17:37:00 +0100</pubDate>
        <link>http://dragan.rocks/articles/25/Get-Ready-Clojure-GPU-AI-2026-CUDA-13</link>
        <guid isPermaLink="true">http://dragan.rocks/articles/25/Get-Ready-Clojure-GPU-AI-2026-CUDA-13</guid>
        
        
        <category>Clojure,</category>
        
        <category>AI,</category>
        
        <category>Deep</category>
        
        <category>Diamond,</category>
        
        <category>Tensors</category>
        
      </item>
    
      <item>
        <title>Clojure Runs ONNX AI Models Now - Join the AI fun!</title>
        <description>&lt;p&gt;
Hello, Clojurians! I haven&apos;t written here in a long time. Was I tired? Is anybody reading blogs
anymore? Who knows. But that was not the main reason.
&lt;/p&gt;

&lt;p&gt;
I&apos;ve been working on several Clojure projects sponsored by the &lt;a href=&quot;https://www.clojuriststogether.org/news/clojurists-together-2025-long-term-funding-announcement/&quot;&gt;Clojurists Together&lt;/a&gt; Foundation.
I did a ton of things, but after all this programming, I was kinda tired, and kept slugging when it comes
to telling people about the work done! That&apos;s not very smart, but you know how it goes&amp;#x2026; :) But, then, if we don&apos;t
tell people about awesome software that we have, nobody is going to use it, so finally I had to stop kicking
this down the road, sit, and write the first post. It&apos;s been long overdue, so expect more posts soon!
&lt;/p&gt;
&lt;div id=&quot;outline-container-orge2dbf4b&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;orge2dbf4b&quot;&gt;ONNX Runtime in one line of Clojure&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-orge2dbf4b&quot;&gt;
&lt;p&gt;
The most recent thing I&apos;m currently working on started its life as &lt;a href=&quot;https://github.com/uncomplicate/diamond-onnxrt&quot;&gt;Clojure ML&lt;/a&gt;&lt;iframe class=&quot;github-btn&quot; src=&quot;https://ghbtns.com/github-btn.html?user=uncomplicate&amp;amp;repo=clojure-onnxrt&amp;amp;type=watch&quot; width=&quot;100&quot; height=&quot;20&quot; title=&quot;Star on GitHub&quot; frameBorder=&quot;0&quot;&gt;&lt;/iframe&gt; (again, superthanks to
&lt;a href=&quot;https://www.clojuriststogether.org/news/q3-2025-funding-announcement/&quot;&gt;Clojurists Together for sponsoring this&lt;/a&gt;). I proposed to create a human-friendly Clojure API for AI/DL/ML
models, and back it by the first implementation, in this case based on &lt;a href=&quot;https://onnxruntime.ai/&quot;&gt;ONNX Runtime&lt;/a&gt;. Of course, it should all be integrated
into existing Clojure libraries, and follow the Clojure way of doing stuff as much as possible!
&lt;/p&gt;

&lt;p&gt;
The idea is to get an existing, pre-trained ML model previously exported to the &lt;a href=&quot;https://onnx.ai/&quot;&gt;ONNX&lt;/a&gt; format from whatever technology
the authors chose (which in today&apos;s world is typically Python and PyTorch), and put it into production
in Clojure and JVM. It should be seamless and in-process, without any clunky interoperability, copy, translation, etc.
Of course, our Clojure numerical libraries fully support GPU computing, so it goes without saying
that we want that, too! Just to be clear, &lt;i&gt;we do not use nor need any Python or Python interop for this, we use the &lt;a href=&quot;https://onnxruntime.ai/&quot;&gt;ONNX Runtime&lt;/a&gt;&apos;s underlying C library&lt;/i&gt;.
&lt;/p&gt;

&lt;p&gt;
Nice idea, but what parts of this well intended story can we evaluate in our REPLs right now?
At least some promising demo? Are we on the trail? To access that AI goodness, we surely have to
do a sophisticated dance? Are the steps hard to learn? Do we need to watch carefully for
slippery floor? Is it accessible to mere mortals?
&lt;/p&gt;

&lt;p&gt;
Here&apos;s the gist:
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-clojure&quot;&gt;&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;onnx &lt;span style=&quot;color: #4E9A06;&quot;&gt;&quot;data/mnist-12.onnx&quot;&lt;/span&gt;&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
&quot;Wait, what?&quot;, you&apos;ll say. One function? One tini, tiny, function, with one laughingly trivial argument?
Is that an API? What does such trivial API do? &quot;Now you confused me!&quot;, you&apos;ll scratch your head.
It&apos;s just a stick.
&lt;/p&gt;

&lt;p&gt;
I hope I&apos;ve also intrigued you, so please keep reading to see it in action (this post is actually
generated from a live REPL session, so the example is fully executable, not just interesting bits
on the table, and a ton of complex boilerplate under a Persian rug).
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-org2a73fbe&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;org2a73fbe&quot;&gt;Hello World, the MNIST image recognition model&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-org2a73fbe&quot;&gt;
&lt;p&gt;
For this recipe, you&apos;ll need the following ingredients: &lt;a href=&quot;https://github.com/uncomplicate/deep-diamond&quot;&gt;Deep Diamond&lt;/a&gt; tensors (one cup), &lt;a href=&quot;https://github.com/uncomplicate/deep-diamond&quot;&gt;Deep Diamond&lt;/a&gt;
network (one slice), one &lt;a href=&quot;https://neanderthal.uncomplicate.org&quot;&gt;Neanderthal &lt;/a&gt;&lt;iframe class=&quot;github-btn&quot; src=&quot;https://ghbtns.com/github-btn.html?user=uncomplicate&amp;amp;repo=neanderthal&amp;amp;type=watch&amp;amp;count=true&quot; width=&quot;100&quot; height=&quot;20&quot; title=&quot;Star on GitHub&quot; frameBorder=&quot;0&quot;&gt;&lt;/iframe&gt; &lt;code&gt;transfer!&lt;/code&gt; function for moving data around for demo purposes,
and that&apos;s it! Oh, yes, don&apos;t forget the new &lt;code&gt;onnx&lt;/code&gt; function. We load the &lt;code&gt;native&lt;/code&gt; namespace, and
the right &lt;a href=&quot;https://github.com/uncomplicate/deep-diamond&quot;&gt;Deep Diamond&lt;/a&gt; &lt;iframe class=&quot;github-btn&quot; src=&quot;https://ghbtns.com/github-btn.html?user=uncomplicate&amp;amp;repo=deep-diamond&amp;amp;type=watch&amp;amp;count=true&quot; width=&quot;100&quot; height=&quot;20&quot; title=&quot;Star on GitHub&quot; frameBorder=&quot;0&quot;&gt;&lt;/iframe&gt; engine is set up for our system (yes, even on Mac OS, thanks to &lt;a href=&quot;https://www.clojuriststogether.org/news/clojurists-together-2025-long-term-funding-announcement/&quot;&gt;Clojurists Together&lt;/a&gt;!).
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-clojure&quot;&gt;&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;require &apos;&lt;span style=&quot;color: #7388d6;&quot;&gt;[&lt;/span&gt;uncomplicate.neanderthal.core &lt;span style=&quot;color: #F5666D;&quot;&gt;:refer&lt;/span&gt; &lt;span style=&quot;color: #909183;&quot;&gt;[&lt;/span&gt;transfer! iamax&lt;span style=&quot;color: #909183;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #7388d6;&quot;&gt;]&lt;/span&gt;
         &apos;&lt;span style=&quot;color: #7388d6;&quot;&gt;[&lt;/span&gt;uncomplicate.diamond
           &lt;span style=&quot;color: #909183;&quot;&gt;[&lt;/span&gt;tensor &lt;span style=&quot;color: #F5666D;&quot;&gt;:refer&lt;/span&gt; &lt;span style=&quot;color: #709870;&quot;&gt;[&lt;/span&gt;tensor desc&lt;span style=&quot;color: #709870;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #909183;&quot;&gt;]&lt;/span&gt;
           &lt;span style=&quot;color: #909183;&quot;&gt;[&lt;/span&gt;dnn &lt;span style=&quot;color: #F5666D;&quot;&gt;:refer&lt;/span&gt; &lt;span style=&quot;color: #709870;&quot;&gt;[&lt;/span&gt;network&lt;span style=&quot;color: #709870;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #909183;&quot;&gt;]&lt;/span&gt;
           &lt;span style=&quot;color: #909183;&quot;&gt;[&lt;/span&gt;onnxrt &lt;span style=&quot;color: #F5666D;&quot;&gt;:refer&lt;/span&gt; &lt;span style=&quot;color: #709870;&quot;&gt;[&lt;/span&gt;onnx&lt;span style=&quot;color: #709870;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #909183;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #7388d6;&quot;&gt;]&lt;/span&gt;
         &apos;&lt;span style=&quot;color: #7388d6;&quot;&gt;[&lt;/span&gt;uncomplicate.diamond.native&lt;span style=&quot;color: #7388d6;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-orgc0eecd9&quot; class=&quot;outline-3&quot;&gt;
&lt;h3 id=&quot;orgc0eecd9&quot;&gt;The ONNX model&lt;/h3&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-orgc0eecd9&quot;&gt;
&lt;p&gt;
We evaluate the &lt;code&gt;onnx&lt;/code&gt; function, and it loads the model.
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-clojure&quot;&gt;&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #A52A2A; font-weight: bold;&quot;&gt;def&lt;/span&gt; &lt;span style=&quot;color: #0084C8; font-weight: bold;&quot;&gt;mnist-onnx&lt;/span&gt; &lt;span style=&quot;color: #7388d6;&quot;&gt;(&lt;/span&gt;onnx &lt;span style=&quot;color: #4E9A06;&quot;&gt;&quot;../../data/mnist-12.onnx&quot;&lt;/span&gt;&lt;span style=&quot;color: #7388d6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;pre class=&quot;example&quot;&gt;
#&apos;user/mnist-onnx
&lt;/pre&gt;


&lt;p&gt;
Sure, that&apos;s easy, but how is &lt;i&gt;that&lt;/i&gt; useful? Well, the result is a function. This function
has just been set up with ONNX internals, so now it can create &lt;a href=&quot;https://github.com/uncomplicate/deep-diamond&quot;&gt;Deep Diamond&lt;/a&gt; network layers
and fit in with the rest of the Tensor-y stuff that DD already provides.
&lt;/p&gt;

&lt;p&gt;
The ONNX Runtime model revolves around environment, session, input and output tensors,
type info, and a lot of other stuff and brittle ceremony. Sure, sometimes you need
to reach these internals, and &lt;code&gt;diamond-onnxrt&lt;/code&gt; provides clojurized internals API even for that.
However, it can sing the main song, and set all the right arguments at the right places for you.
Even the &lt;code&gt;onnx&lt;/code&gt; function supports option map, where you can tell what you like, and it will take
care to configure ONNX to do the right thing, but this is a story for another article.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-org56b31c2&quot; class=&quot;outline-3&quot;&gt;
&lt;h3 id=&quot;org56b31c2&quot;&gt;The rest is the usual Deep Diamond stuff, which is simple as beans!&lt;/h3&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-org56b31c2&quot;&gt;
&lt;p&gt;
The &lt;a href=&quot;https://en.wikipedia.org/wiki/MNIST_database&quot;&gt;MNIST dataset&lt;/a&gt; specifies images of hand-written digits, in just one grayscale channel, each \(28\times28\) pixels
a challenging task for 1989&apos;s USPO and the tecnology from back then, but a hello world level
stuff for today&apos;s accelerated libraries (still, keep in mind that if you tried to code even this easy
example without such libraries, you&apos;ll be surprised how slow that can be!).
&lt;/p&gt;

&lt;p&gt;
We create a tensor descriptor for such input (this step can be left out, but I&apos;m being pedantic to accommodate beginners):
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-clojure&quot;&gt;&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #A52A2A; font-weight: bold;&quot;&gt;def&lt;/span&gt; &lt;span style=&quot;color: #0084C8; font-weight: bold;&quot;&gt;input-desc&lt;/span&gt; &lt;span style=&quot;color: #7388d6;&quot;&gt;(&lt;/span&gt;desc &lt;span style=&quot;color: #909183;&quot;&gt;[&lt;/span&gt;1 1 28 28&lt;span style=&quot;color: #909183;&quot;&gt;]&lt;/span&gt; &lt;span style=&quot;color: #F5666D;&quot;&gt;:float&lt;/span&gt; &lt;span style=&quot;color: #F5666D;&quot;&gt;:nchw&lt;/span&gt;&lt;span style=&quot;color: #7388d6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;pre class=&quot;example&quot;&gt;
#&apos;user/input-desc
&lt;/pre&gt;


&lt;p&gt;
Next, we create a reusable abstract network blueprint, that can then create concrete networks
tailored for training, or optimized for inference, that is classifying MNIST images.
Normally, we would have to train these networks, or load the parameters from somewhere,
but in this case it contains only of the &lt;code&gt;onnx&lt;/code&gt; model, which had already been trained and
already knows all the right weights, so no training is needed (nor available with ONNX Runtime yet;
it&apos;s main job is inference in production).
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-clojure&quot;&gt;&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #A52A2A; font-weight: bold;&quot;&gt;def&lt;/span&gt; &lt;span style=&quot;color: #0084C8; font-weight: bold;&quot;&gt;mnist&lt;/span&gt; &lt;span style=&quot;color: #7388d6;&quot;&gt;(&lt;/span&gt;network input-desc &lt;span style=&quot;color: #909183;&quot;&gt;[&lt;/span&gt;mnist-onnx&lt;span style=&quot;color: #909183;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #7388d6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;pre class=&quot;example&quot;&gt;
#&apos;user/mnist
&lt;/pre&gt;


&lt;p&gt;
Note that all these things so far look and behave just as ordinary Clojure objects. You can
use them even outside this specific structure. Full flexibility that I hope will spark your creativity.
&lt;/p&gt;

&lt;p&gt;
We&apos;ll also need a place for the actual image that we&apos;d like to classify. This particular network
that I downloaded from ONNX Runtime examples specifies exactly one image at input, to classify one at a time.
Typically, if we have many images, it&apos;s better to compute them in batches, but it&apos;s just a hello-world, after all,
we won&apos;t be too demanding.
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-clojure&quot;&gt;&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #A52A2A; font-weight: bold;&quot;&gt;def&lt;/span&gt; &lt;span style=&quot;color: #0084C8; font-weight: bold;&quot;&gt;input-tz&lt;/span&gt; &lt;span style=&quot;color: #7388d6;&quot;&gt;(&lt;/span&gt;tensor input-desc&lt;span style=&quot;color: #7388d6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;pre class=&quot;example&quot;&gt;
#&apos;user/input-tz
&lt;/pre&gt;


&lt;p&gt;
A blueprint (mnist in this case) is a function that can create networks optimized for inference
with concrete tensors, adequate internal tensors, and parameters.
The following line is the moment when the network is actually created from the abstract descriptors
contained in its blueprint, to the actual engines, operation primitives, and tensors in memory.
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-clojure&quot;&gt;&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #A52A2A; font-weight: bold;&quot;&gt;def&lt;/span&gt; &lt;span style=&quot;color: #0084C8; font-weight: bold;&quot;&gt;classify!&lt;/span&gt; &lt;span style=&quot;color: #7388d6;&quot;&gt;(&lt;/span&gt;mnist input-tz&lt;span style=&quot;color: #7388d6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;pre class=&quot;example&quot;&gt;
#&apos;user/classify!
&lt;/pre&gt;


&lt;p&gt;
True to the Clojure philosophy, &lt;code&gt;mnist&lt;/code&gt; is a function, which, given the specification for
desired input, &lt;code&gt;(mnist input-tz)&lt;/code&gt; produces classify!, which is a function, too, but for actual inference!
It might sound cumbersome when it&apos;s written out, but the code shows it&apos;s elegance. No need for
complex APIs. Each thing does exactly one thing, and does it in the most simple way, by just
evaluating with one or two parameters!
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-org64c65d8&quot; class=&quot;outline-3&quot;&gt;
&lt;h3 id=&quot;org64c65d8&quot;&gt;Now we got a function that classifies images&lt;/h3&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-org64c65d8&quot;&gt;
&lt;p&gt;
This is how you would typically use this
&lt;/p&gt;

&lt;p&gt;
Step one: classify! is now a typical Clojure function! Evaluate it:
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-clojure&quot;&gt;&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;classify!&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;pre class=&quot;example&quot;&gt;
{:shape [1 10], :data-type :float, :layout [10 1]} (-0.04485602676868439 0.007791661191731691 0.06810081750154495 0.02999374084174633 -0.1264096349477768 0.14021874964237213 -0.055284902453422546 -0.04938381537795067 0.08432205021381378 -0.05454041436314583)
&lt;/pre&gt;


&lt;p&gt;
The result is a ten-element tensor, each element represents the possibility that the category
at its index is the right one.
So we should just find which element contains the highest value, and that&apos;d be our category,
which in the MNIST example is, very conveniently a digit 0 to 9 that is equal to that index.
&lt;/p&gt;

&lt;p&gt;
However, you can see that the current values are just random small numbers. This is because
we never loaded any image data to the input tensor! It just classified random noise as not very likely
to be an image of any digit.
&lt;/p&gt;

&lt;p&gt;
We need step zero: place the image data in network&apos;s input somehow. This could be done in
many different ways (for example, by memory-mapping the image data on disk), but we&apos;ll
keep it simple, and we&apos;ll just transfer it naively from an in-place Clojure sequence. (this is a hello-world :)
&lt;/p&gt;

&lt;p&gt;
The following sequence is copied from the actual MNIST data, but I just took the data of the first image, and
scaled it to 0-1 range instead of 0-255.
&lt;/p&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-clojure&quot;&gt;&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;transfer! &lt;span style=&quot;color: #7388d6;&quot;&gt;(&lt;/span&gt;map #&lt;span style=&quot;color: #909183;&quot;&gt;(&lt;/span&gt;float &lt;span style=&quot;color: #709870;&quot;&gt;(&lt;/span&gt;/ &lt;span style=&quot;color: #0084C8; font-weight: bold;&quot;&gt;%&lt;/span&gt; 255&lt;span style=&quot;color: #709870;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #909183;&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: #909183;&quot;&gt;[&lt;/span&gt;0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 &lt;span style=&quot;color: #ee82ee; background-color: #333333;&quot;&gt;0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 84.0 185.0 159.0 151.0 60.0 36.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 222.0 254.0 254.0 254.0 254.0 241.0 198.0 198.0 198.0 198.0 198.0 198.0 198.0 198.0 170.0 52.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 67.0 114.0 72.0 114.0 163.0 227.0 254.0 225.0 254.0 254.0 254.0 250.0 229.0 254.0 254.0 140.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 17.0 66.0 14.0 67.0 67.0 67.0 59.0 21.0 236.0 254.0 106.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 83.0 253.0 209.0 18.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 22.0 233.0 255.0 83.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 129.0 254.0 238.0 44.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 59.0 249.0 254.0 62.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 133.0 254.0 187.0 5.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 9.0 205.0 248.0 58.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 126.0 254.0 182.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 75.0 251.0 240.0 57.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 19.0 221.0 254.0 166.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 3.0 203.0 254.0 219.0 35.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 38.0 254.0 254.0 77.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 31.0 224.0 254.0 115.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 133.0 254.0 254.0 52.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 61.0 242.0 254.0 254.0 52.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 121.0 254.0 254.0 219.0 40.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 121.0 254.0 207.0 18.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0&lt;/span&gt;&lt;span style=&quot;color: #909183; background-color: #333333;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #7388d6; background-color: #333333;&quot;&gt;)&lt;/span&gt;
           input-tz&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;pre class=&quot;example&quot;&gt;
{:shape [1 1 28 28], :data-type :float, :layout [784 784 28 1]} (0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0)
&lt;/pre&gt;


&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-clojure&quot;&gt;&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;classify!&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;pre class=&quot;example&quot;&gt;
{:shape [1 10], :data-type :float, :layout [10 1]} (-1.2567189931869507 0.6275832653045654 8.642718315124512 9.428943634033203 -13.740066528320312 -6.045698642730713 -23.486745834350586 28.3399658203125 -6.7914958000183105 3.941998243331909)
&lt;/pre&gt;


&lt;p&gt;
Now, we see some better looking results, but are we the one who need to look at a bunch of numbers and compare them?
&lt;/p&gt;

&lt;p&gt;
No, the machine should do that. Luckily, &lt;a href=&quot;https://neanderthal.uncomplicate.org&quot;&gt;Neanderthal &lt;/a&gt;&lt;iframe class=&quot;github-btn&quot; src=&quot;https://ghbtns.com/github-btn.html?user=uncomplicate&amp;amp;repo=neanderthal&amp;amp;type=watch&amp;amp;count=true&quot; width=&quot;100&quot; height=&quot;20&quot; title=&quot;Star on GitHub&quot; frameBorder=&quot;0&quot;&gt;&lt;/iframe&gt; has just the right function for this!
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-clojure&quot;&gt;&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;iamax &lt;span style=&quot;color: #7388d6;&quot;&gt;(&lt;/span&gt;classify!&lt;span style=&quot;color: #7388d6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;pre class=&quot;example&quot;&gt;
7
&lt;/pre&gt;


&lt;p&gt;
And this is the kind of answer that we can show our clients! What&apos;s on this image? Easy, it&apos;s 7!
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-org1776049&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;org1776049&quot;&gt;Can you tell me the main point of this, in one paragraph?&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-org1776049&quot;&gt;
&lt;p&gt;
Yes. Clojure programmers typically write functions. Functions are things that take something at the input,
compute stuff internally, and return an output, which is hopefully useful downstream.
The funcion transforms the input into the output according to the logic that we programmers
wrote in code, following some algorithm that we designed for the purpose. Now, &lt;i&gt;sometimes&lt;/i&gt;
the problem is so convoluted that we don&apos;t have the slightest idea how to write that
transformation in code, but what we (or someone else) do have is lots of data, and in many
such cases we can train a general machinery (neural networks for example) to find out a good
enough transformation. Sometimes someone else have already done the hard part by training the network,
exporting it to a standard format (ONNX) and gave it to you! &lt;b&gt;Now, you can load it in Clojure and use it
as a Clojure function.&lt;/b&gt; You don&apos;t even need to know how it works internally, but it does
the thing that you need, it transforms the input tensors that you have into just the right
output tensors. What you do with these outputs is up to you :)
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;outline-container-orgd2386cd&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;orgd2386cd&quot;&gt;Who is this for?&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-orgd2386cd&quot;&gt;
&lt;p&gt;
Do you need to be an AI researcher to find this useful? Absolutely not! This can appeal to any Clojure engineer.
&lt;/p&gt;

&lt;p&gt;
AI researchers try to find novel AI models, or to push their model by 0.1% on an artificial
benchmark. Recently, they don&apos;t necessarily even do that, some of them found the way to chase funding at crazy evaluations,
and catch it.
Some of them don&apos;t necessarily write code but work with mathematical models trying to figure a way to do some abstract thing.
Or, if they are PhD students, they spend endless nights fiddling with Python and PyTorch trying to
figure this or that task assigned by their laboratory, or they just try to catch a bit of sleep while
a GPU cluster crunches some tiny step in an endless training cycle.
&lt;/p&gt;

&lt;p&gt;
There&apos;s nothing wrong with that, but if you&apos;re a Clojure programmer, you probably don&apos;t have time,
opportunity, experience, or even interest to work on that stuff. But, even if you don&apos;t want
(or can&apos;t) understand AI internals, you can still be very creative with the &lt;i&gt;applications&lt;/i&gt;.
Now there are many, many, published ML models that work, many of them are even exported
to ONNX, and quite usable. You don&apos;t need to invent a new OpenAI competitor, there are
many more mundane problems that can be solved by taking an already existing model and
applying it in a niche context, in a domain that you know well. You don&apos;t even need to
understand exactly what or how the model does what it does, you can treat it as a black-box function
that transforms inputs and outputs, and that function just need a bit more care to work
than a regular Clojure four-liner that you&apos;d normally write and be proud of.
&lt;/p&gt;

&lt;p&gt;
Although (sadly) Clojure has not find its way in the big guns AI arena, Clojure &lt;i&gt;is&lt;/i&gt; a
very capable capable language and Clojure programmers very knowledgeable people when it
comes to integrating stuff into real-world applications! So, here it is, now you don&apos;t have
to make compromises; you can got to &lt;a href=&quot;https://huggingface.co/&quot;&gt;Hugging Face, or some other AI related community&lt;/a&gt;,
find ONNX models that other people already prepared, and join the AI fun, &lt;b&gt;directly from Clojure&lt;/b&gt;.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
</description>
        <pubDate>Sun, 26 Oct 2025 16:56:00 +0100</pubDate>
        <link>http://dragan.rocks/articles/25/Clojure-Runs-ONNX-AI-Models-Now</link>
        <guid isPermaLink="true">http://dragan.rocks/articles/25/Clojure-Runs-ONNX-AI-Models-Now</guid>
        
        
        <category>Clojure,</category>
        
        <category>AI,</category>
        
        <category>Deep</category>
        
        <category>Diamond,</category>
        
        <category>Tensors</category>
        
      </item>
    
      <item>
        <title>Apple silicon support in Clojure&apos;s Neanderthal Fast Matrix Library</title>
        <description>&lt;p&gt;
I&apos;ve applied for Clojurists Together funding to explore and hopefully implement a Neanderthal
Apple silicon backend. If you are a Clojurists Together member, and you think that this functionality
is important, please have that in mind when voting. Here&apos;s the proposal that I&apos;ve sent. Of course,
any suggestions are welcome and highly appreciated!
&lt;/p&gt;

&lt;div id=&quot;outline-container-orgc980671&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;orgc980671&quot;&gt;The proposal&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-orgc980671&quot;&gt;
&lt;p&gt;
My goal with this funding in 2025 is to support Apple silicon (M cpus) in Neanderthal
(and other Uncomplicate libraries where that makes sense and where it&apos;s possible).
&lt;/p&gt;

&lt;p&gt;
This will hugely streamline user experience regarding high performance computing in Clojure for Apple macOS users,
which is a considerable chunk of Clojure community. They ask for it all the time, and I am always sorry to tell them
that I still don&apos;t have a solution. Once upon a time, Neanderthal worked on Mac too, but then Apple did one of their
complete turnarounds with M1&amp;#x2026; This basically broke all number crunching software on macs, and the world is slow to catch up.
Several Clojure developers started exploring high performance computing on Apple, but didn&apos;t get too far; it&apos;s LOTS of functionality.
So, having Neandeathal support Apple would enable several Clojure data processing communities to leapfrog the whole milestone
and concentrate on more high-level tasks.
&lt;/p&gt;

&lt;p&gt;
This affects Neanderthal (matrices &amp;amp; vectors), and Deep Diamond (tensors &amp;amp; deep learning) the most. Nvidia&apos;s CUDA is not physically available
on Macs at all, while OpenCL is discontinued in favor of Apple&apos;s proprietary Metal (and who knows what else they&apos;ve came up with since).
&lt;/p&gt;

&lt;p&gt;
Neanderthal is a Clojure library for fast matrix computations based on the highly optimized native libraries and computation routines for both CPU and GPU.
It is a lean, high performance, infrastructure for working with vectors and matrices in Clojure, which is the foundation for implementing high performance computing related tasks, including, but not limited to, machine learning and artificial intelligence.
Deep Diamond is a tensor and deep learning Clojure library that uses Neanderthal and ClojureCUDA under the hood (among other things).
&lt;/p&gt;

&lt;p&gt;
So, what are the missing parts for Apple silicon?
&lt;/p&gt;

&lt;ol class=&quot;org-ol&quot;&gt;
&lt;li&gt;A good C++/native interop. That is more or less solved by JavaCPP, but their ARM support is still in its infancy, especially regarding distribution. But it is improving.&lt;/li&gt;
&lt;li&gt;A good BLAS/LAPACK alternative. There&apos;s OpenBLAS, and there&apos;s Apple&apos;s Accelerate. Both support only a part of Intel&apos;s MKL functionality. But, if we don&apos;t insist on 100% coverage (we&apos;re not) and are willing to accept missing operations to be slower, I could implement the most important ones in Clojure if nothing else is available.&lt;/li&gt;
&lt;li&gt;A good GPU computing alternative. CUDA is not supported on Apple, and OpenCL has been discontinued by Apple. So that leaves us with Apple&apos;s Metal, which is a mess (or so I hear). So I wouldn&apos;t put too much hope on GPU, at the moment. Maybe much, much, later, with much, much, more experience&amp;#x2026;&lt;/li&gt;
&lt;li&gt;Assorted auxiliary operations that are not in BLAS/LAPACK/Apple Accelerate, which are usually programmed in C++ in native-land. I&apos;d have to see how many appear, and what I have to do with them.&lt;/li&gt;
&lt;li&gt;Explore what&apos;s the situation related to tensors and deep learning on Apple. I doubt that Intel&apos;s DNNL can cover this, but who knows. Also, Apple certainly supports something, but how compatible it is with cuDNN and DNNL, is a complete unknown to me&amp;#x2026;&lt;/li&gt;
&lt;li&gt;Who knows which roadblocks can pop up.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;
So, there&apos;s a lots of functionality to be implemented, and there&apos;s a lots of unknowns.
&lt;/p&gt;

&lt;p&gt;
I propose to * Implement an Apple M engine for Neanderthal.* This involves:
&lt;/p&gt;
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;buying an Apple M2/3 Mac (the cheapest M3 in Serbia is almost 3000 USD (with VAT).&lt;/li&gt;
&lt;li&gt;learning enough macOS tools (Xcode was terrible back in the days) to be able to do anything.&lt;/li&gt;
&lt;li&gt;exploring JavaCPP support for ARM and macOS.&lt;/li&gt;
&lt;li&gt;exploring relevant libraries (OpenBLAS may even work through JavaCPP).&lt;/li&gt;
&lt;li&gt;exploring Apple Accelerate.&lt;/li&gt;
&lt;li&gt;learning enough JavaCPP tooling to be able to see whether it is realistic that I build Accelerate wrapper (and if I can&apos;t, at least to know how much I don&apos;t know).&lt;/li&gt;
&lt;li&gt;I forgot even little C/C++ that I did know back in the day. This may also give me some headaches, as I&apos;ll have to quickly pick up whatever is needed.&lt;/li&gt;
&lt;li&gt;writing articles about relevant topics so Clojurians can pick this functionality as it arrives.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;
It may include implementing Tensor &amp;amp; Deep Learning support for Apple in Deep Diamond, but
that depends on how far I get with Neanderthal. I hope that I can do it, but can&apos;t promise it.
&lt;/p&gt;

&lt;p&gt;
By the end of 2025, I am fairly sure that I can provide Apple support for Neanderthal (and ClojureCPP) and I hope that I can  even add it for Deep Diamond.
&lt;/p&gt;

&lt;p&gt;
Projects directly involved:
&lt;a href=&quot;https://github.com/uncomplicate/neanderthal&quot;&gt;https://github.com/uncomplicate/neanderthal&lt;/a&gt;
&lt;a href=&quot;https://github.com/uncomplicate/deep-diamond&quot;&gt;https://github.com/uncomplicate/deep-diamond&lt;/a&gt;
&lt;a href=&quot;https://github.com/uncomplicate/clojure-cpp&quot;&gt;https://github.com/uncomplicate/clojure-cpp&lt;/a&gt;
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
</description>
        <pubDate>Tue, 19 Nov 2024 22:15:00 +0100</pubDate>
        <link>http://dragan.rocks/articles/24/Apple-Silicon-Support-for-Clojure-Neanderthal-Fast-Matrix-Library</link>
        <guid isPermaLink="true">http://dragan.rocks/articles/24/Apple-Silicon-Support-for-Clojure-Neanderthal-Fast-Matrix-Library</guid>
        
        
        <category>Clojure,</category>
        
        <category>AI,</category>
        
        <category>Matrices,</category>
        
        <category>Neanderthal,</category>
        
        <category>Vectors,</category>
        
        <category>Linear</category>
        
        <category>Algebra,</category>
        
        <category>Apple</category>
        
      </item>
    
      <item>
        <title>Recurrent Networks Hello World in Clojure with new Deep Diamond RNN support on CPU and GPU</title>
        <description>&lt;p&gt;
I&apos;ve been busy in the last period working on new major features in Deep Diamond, one of which
is the support for Recurrent Neural Networks (RNN). It&apos;s not been an easy ride, but I can finally
show you some results! Big thanks for everyone that&apos;s helping me with this by buying my books
(or subscribing to the upcoming editions), and Clojurists Together, who generously funded
me in the past year to work on this.
&lt;/p&gt;

&lt;p&gt;
I know that most of you probably don&apos;t have much more than passing familiarity
with deep learning, let alone recurrent neural networks, and that&apos;s why I&apos;ll try
to show a very simple example on the level of Hello World that anyone interested
in machine learning and programming can understand and try.
&lt;/p&gt;

&lt;p&gt;
So, enough talk, let&apos;s get down to business.
&lt;/p&gt;

&lt;div id=&quot;outline-container-orga87de2e&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;orga87de2e&quot;&gt;What are we doing&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-orga87de2e&quot;&gt;
&lt;p&gt;
We are demonstrating a hammer: recurrent neural networks. Just kidding; we would like
to create a (software) device that can learn to predict the next data point in a series.
Depending on the data, this can be done in a number of ways (even
by convolutional neural networks (CNN) that Deep Diamond already supported), one of
which is RNN. So, we are creating a recurrent network, and training it with a set
of data for this task.
&lt;/p&gt;

&lt;p&gt;
An example of data that fits this task would be temperature at some place, stock prices,
and any other (possibly infinite) sequence of numbers in one of more dimensions that
have an ordinal relation, that is, has an abstract notion of time attached to it. Then,
we are trying to forecast one or more values that are happening in the future (temperature
the next day, or the closing price of a stock, etc.).
&lt;/p&gt;

&lt;p&gt;
Since Hello World has to be dead simple, a real example would have too many opaque
numbers, so we&apos;ll solve an artificially trivial task of teaching our network
to predict the next number in the series for obvious series such as 1, 2, 3, 4, 5.
Of course, in real life we rarely need to solve that exact task with such a bazooka
as RNN, but if this is your first contact with time series prediction with deep
learning, I guess it&apos;d be just what works best.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;

&lt;div id=&quot;outline-container-org1560cc6&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;org1560cc6&quot;&gt;Let&apos;s get down to code&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-org1560cc6&quot;&gt;
&lt;p&gt;
First, we&apos;ll require a bunch of Clojure namespaces that we need.
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-clojure&quot;&gt;&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;require &apos;&lt;span style=&quot;color: #7388d6;&quot;&gt;[&lt;/span&gt;uncomplicate.commons.core &lt;span style=&quot;color: #F5666D;&quot;&gt;:refer&lt;/span&gt; &lt;span style=&quot;color: #909183;&quot;&gt;[&lt;/span&gt;with-release &lt;span style=&quot;color: #A52A2A; font-weight: bold;&quot;&gt;let-release&lt;/span&gt; release&lt;span style=&quot;color: #909183;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #7388d6;&quot;&gt;]&lt;/span&gt;
         &apos;&lt;span style=&quot;color: #7388d6;&quot;&gt;[&lt;/span&gt;uncomplicate.neanderthal
           &lt;span style=&quot;color: #909183;&quot;&gt;[&lt;/span&gt;core &lt;span style=&quot;color: #F5666D;&quot;&gt;:refer&lt;/span&gt; &lt;span style=&quot;color: #709870;&quot;&gt;[&lt;/span&gt;ge dim amax submatrix subvector mrows trans transfer transfer! view-vctr
                         native view-ge cols mv! rk! raw col row nrm2 scal! ncols dim rows axpby!&lt;span style=&quot;color: #709870;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #909183;&quot;&gt;]&lt;/span&gt;
           &lt;span style=&quot;color: #909183;&quot;&gt;[&lt;/span&gt;native &lt;span style=&quot;color: #F5666D;&quot;&gt;:refer&lt;/span&gt; &lt;span style=&quot;color: #709870;&quot;&gt;[&lt;/span&gt;fge native-float fv iv&lt;span style=&quot;color: #709870;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #909183;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #7388d6;&quot;&gt;]&lt;/span&gt;
         &apos;&lt;span style=&quot;color: #7388d6;&quot;&gt;[&lt;/span&gt;uncomplicate.diamond
           &lt;span style=&quot;color: #909183;&quot;&gt;[&lt;/span&gt;tensor &lt;span style=&quot;color: #F5666D;&quot;&gt;:refer&lt;/span&gt; &lt;span style=&quot;color: #709870;&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color: #0084C8; font-weight: bold;&quot;&gt;*diamond-factory*&lt;/span&gt; tensor offset! connector transformer
                           desc revert shape input output view-tz batcher&lt;span style=&quot;color: #709870;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #909183;&quot;&gt;]&lt;/span&gt;
           &lt;span style=&quot;color: #909183;&quot;&gt;[&lt;/span&gt;dnn &lt;span style=&quot;color: #F5666D;&quot;&gt;:refer&lt;/span&gt; &lt;span style=&quot;color: #709870;&quot;&gt;[&lt;/span&gt;rnn infer sum activation inner-product dense
                        network init! train cost train train-shuffle ending&lt;span style=&quot;color: #709870;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #909183;&quot;&gt;]&lt;/span&gt;
           &lt;span style=&quot;color: #909183;&quot;&gt;[&lt;/span&gt;native &lt;span style=&quot;color: #F5666D;&quot;&gt;:refer&lt;/span&gt; &lt;span style=&quot;color: #709870;&quot;&gt;[]&lt;/span&gt;&lt;span style=&quot;color: #909183;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #7388d6;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
All the AI in the world would be useless to us if we hadn&apos;t measured some data from the real world
to feed it. Suppose (for the sake of Hello World), that I &quot;measured&quot; a narrow range of whole number domain
by generating it from thin air. Does this data tell us anything about stock market? Of course not, and
please does not expect any model that we train on this data to magically be informed on anything that
could not be learned from the data it has seen.
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-clojure&quot;&gt;&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #A52A2A; font-weight: bold;&quot;&gt;def&lt;/span&gt; &lt;span style=&quot;color: #0084C8; font-weight: bold;&quot;&gt;simple-sequence&lt;/span&gt; &lt;span style=&quot;color: #7388d6;&quot;&gt;(&lt;/span&gt;range -100 100&lt;span style=&quot;color: #7388d6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;pre class=&quot;example&quot; id=&quot;org4f7e086&quot;&gt;
(-100 -99 -98 -97 -96 -95 -94 -93 -92 -91 -90 -89 -88 -87 -86 -85 ...)
&lt;/pre&gt;

&lt;p&gt;
Now, I&apos;ll create a blueprint for an arbitrary recurrent neural network (RNN). This network has 3
recurrent layers (Gated Recurrent Unit cells), an abbreviation to one timestep, and
two dense layers at the end. Please note that I used a completely arbitrary architecture.
Neither this layer structure, nor the number of hidden neurons are optimal for this data;
we are not even sure it&apos;s any good. If anything, it&apos;s probably a huge overkill.
I chose it simply to show you how it&apos;s easy to construct with &lt;a href=&quot;https://github.com/uncomplicate/deep-diamond&quot;&gt;Deep Diamond&lt;/a&gt;(&lt;iframe class=&quot;github-btn&quot; src=&quot;https://ghbtns.com/github-btn.html?user=uncomplicate&amp;amp;repo=deep-diamond&amp;amp;type=watch&amp;amp;count=true&quot; width=&quot;100&quot; height=&quot;20&quot; title=&quot;Star on GitHub&quot; frameBorder=&quot;0&quot;&gt;&lt;/iframe&gt;),
as it will practically do everything on its own if you specify the bare minimum,
that is &quot;what you want&quot;. And we hope it&apos;ll at least learn to work well at the end,
as non-optimal as it is.
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-clojure&quot;&gt;&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #A52A2A; font-weight: bold;&quot;&gt;def&lt;/span&gt; &lt;span style=&quot;color: #0084C8; font-weight: bold;&quot;&gt;net-bp&lt;/span&gt; &lt;span style=&quot;color: #7388d6;&quot;&gt;(&lt;/span&gt;network &lt;span style=&quot;color: #909183;&quot;&gt;(&lt;/span&gt;desc &lt;span style=&quot;color: #709870;&quot;&gt;[&lt;/span&gt;5 32 1&lt;span style=&quot;color: #709870;&quot;&gt;]&lt;/span&gt; &lt;span style=&quot;color: #F5666D;&quot;&gt;:float&lt;/span&gt; &lt;span style=&quot;color: #F5666D;&quot;&gt;:tnc&lt;/span&gt;&lt;span style=&quot;color: #909183;&quot;&gt;)&lt;/span&gt;
                     &lt;span style=&quot;color: #909183;&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color: #709870;&quot;&gt;(&lt;/span&gt;rnn &lt;span style=&quot;color: #907373;&quot;&gt;[&lt;/span&gt;128&lt;span style=&quot;color: #907373;&quot;&gt;]&lt;/span&gt; &lt;span style=&quot;color: #F5666D;&quot;&gt;:gru&lt;/span&gt;&lt;span style=&quot;color: #709870;&quot;&gt;)&lt;/span&gt;
                      &lt;span style=&quot;color: #709870;&quot;&gt;(&lt;/span&gt;rnn 2&lt;span style=&quot;color: #709870;&quot;&gt;)&lt;/span&gt;
                      &lt;span style=&quot;color: #709870;&quot;&gt;(&lt;/span&gt;abbreviate&lt;span style=&quot;color: #709870;&quot;&gt;)&lt;/span&gt;
                      &lt;span style=&quot;color: #709870;&quot;&gt;(&lt;/span&gt;dense &lt;span style=&quot;color: #907373;&quot;&gt;[&lt;/span&gt;128&lt;span style=&quot;color: #907373;&quot;&gt;]&lt;/span&gt; &lt;span style=&quot;color: #F5666D;&quot;&gt;:relu&lt;/span&gt;&lt;span style=&quot;color: #709870;&quot;&gt;)&lt;/span&gt;
                      &lt;span style=&quot;color: #709870;&quot;&gt;(&lt;/span&gt;dense &lt;span style=&quot;color: #907373;&quot;&gt;[&lt;/span&gt;1&lt;span style=&quot;color: #907373;&quot;&gt;]&lt;/span&gt; &lt;span style=&quot;color: #F5666D;&quot;&gt;:linear&lt;/span&gt;&lt;span style=&quot;color: #709870;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #909183;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #7388d6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
There is no place here to explain what RNN is and how it works internally, other than pointing that
recurrent layers have an ability to handle sequential relations of its input by &quot;memorizing&quot;
the signals that pass through it. The upcoming version of my book  &lt;a href=&quot;https://aiprobook.com/deep-learning-for-programmers/&quot;&gt;Deep Learning for Programmers&lt;/a&gt; (2.0)
discusses RNNs in more detail.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;

&lt;div id=&quot;outline-container-orgbe3f6b0&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;orgbe3f6b0&quot;&gt;Formatting the input data&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-orgbe3f6b0&quot;&gt;
&lt;p&gt;
The input of this network differs from fully connected or convolutional networks by explicitly
modeling the time dimension, &quot;t&quot; in the &quot;:tnc&quot; format. Technically, you can feed it with any
3D tensor that matches its &lt;code&gt;[5 32 1]&lt;/code&gt; shape, but for that data to be in context, it has to
actually be arranged as 5 timesteps of a minibatch of 32 samples of 1-dimensional data.
&lt;/p&gt;

&lt;p&gt;
We do have 1-dimensional data, but how do we fit our &lt;code&gt;(range -100 100)&lt;/code&gt; sequence to
its input? We do have more than 5 timesteps (we have 400), and we are far from 32 samples, since
we only have one! We could try to just cram the sequence as-is by doing &lt;code&gt;(transfer! simple-sequence (input net))&lt;/code&gt;
but this would be the &quot;garbage in&quot; part of &quot;garbage in - garbage out&quot;. No. The solution is,
as always in machine learning, to actually think what our data represents, and matching it
with our knowledge of how the actual model intends to process its input.
&lt;/p&gt;

&lt;p&gt;
What we do need is a bunch of 5-long sequences, such as &lt;code&gt;[1 2 3 4 5]&lt;/code&gt; and the output
that we would deem correct. In this case, &lt;b&gt;I choose&lt;/b&gt; that the goal is to teach the network
to output &lt;b&gt;6&lt;/b&gt; to this input (or a number sufficiently close to it). So, the training
data should be input sequences such as &lt;code&gt;[3 4 5 6 7]&lt;/code&gt; and &lt;code&gt;[-12 -11 -10 -9 -8]&lt;/code&gt;, and
target outputs such as &lt;code&gt;[8]&lt;/code&gt; and &lt;code&gt;[-7]&lt;/code&gt;. I hope you see how a bunch of these sequences,
almost 400, and their respective target outputs could be extracted from &lt;code&gt;simple-sequence&lt;/code&gt;.
&lt;/p&gt;

&lt;p&gt;
The following function employs some stock &lt;a href=&quot;https://neanderthal.uncomplicate.org&quot;&gt;Neanderthal&lt;/a&gt; (&lt;iframe class=&quot;github-btn&quot; src=&quot;https://ghbtns.com/github-btn.html?user=uncomplicate&amp;amp;repo=neanderthal&amp;amp;type=watch&amp;amp;count=true&quot; width=&quot;100&quot; height=&quot;20&quot; title=&quot;Star on GitHub&quot; frameBorder=&quot;0&quot;&gt;&lt;/iframe&gt;) matrix functions to process
the data and pack it into input and target output tensors &lt;code&gt;[x-train]&lt;/code&gt; and &lt;code&gt;[y-train]&lt;/code&gt;.
I don&apos;t have time to explain each step, which is not trivial, but this is fairly standard
vector/matrix/tensor stuff, well explained in both books from my &lt;a href=&quot;https://aiprobook.com&quot;&gt;Interactive Programming for Artificial Intelligence book series&lt;/a&gt;.
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-clojure&quot;&gt;&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #A52A2A; font-weight: bold;&quot;&gt;defn&lt;/span&gt; &lt;span style=&quot;color: #00578E; font-weight: bold;&quot;&gt;split-series&lt;/span&gt; &lt;span style=&quot;color: #7388d6;&quot;&gt;[&lt;/span&gt;fact s &lt;span style=&quot;color: #2E3436; background-color: #EDEDED;&quot;&gt;^&lt;/span&gt;&lt;span style=&quot;color: #2F8B58; font-weight: bold;&quot;&gt;long&lt;/span&gt; t&lt;span style=&quot;color: #7388d6;&quot;&gt;]&lt;/span&gt;
  &lt;span style=&quot;color: #7388d6;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #A52A2A; font-weight: bold;&quot;&gt;let&lt;/span&gt; &lt;span style=&quot;color: #909183;&quot;&gt;[&lt;/span&gt;n &lt;span style=&quot;color: #709870;&quot;&gt;(&lt;/span&gt;- &lt;span style=&quot;color: #907373;&quot;&gt;(&lt;/span&gt;ncols s&lt;span style=&quot;color: #907373;&quot;&gt;)&lt;/span&gt; t&lt;span style=&quot;color: #709870;&quot;&gt;)&lt;/span&gt;
        c &lt;span style=&quot;color: #709870;&quot;&gt;(&lt;/span&gt;mrows s&lt;span style=&quot;color: #709870;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #909183;&quot;&gt;]&lt;/span&gt;
    &lt;span style=&quot;color: #909183;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #A52A2A; font-weight: bold;&quot;&gt;let-release&lt;/span&gt; &lt;span style=&quot;color: #709870;&quot;&gt;[&lt;/span&gt;x-tz &lt;span style=&quot;color: #907373;&quot;&gt;(&lt;/span&gt;tensor fact &lt;span style=&quot;color: #6276ba;&quot;&gt;[&lt;/span&gt;t n c&lt;span style=&quot;color: #6276ba;&quot;&gt;]&lt;/span&gt; &lt;span style=&quot;color: #F5666D;&quot;&gt;:float&lt;/span&gt; &lt;span style=&quot;color: #F5666D;&quot;&gt;:tnc&lt;/span&gt;&lt;span style=&quot;color: #907373;&quot;&gt;)&lt;/span&gt;
                  y-tz &lt;span style=&quot;color: #907373;&quot;&gt;(&lt;/span&gt;tensor fact &lt;span style=&quot;color: #6276ba;&quot;&gt;[&lt;/span&gt;n c&lt;span style=&quot;color: #6276ba;&quot;&gt;]&lt;/span&gt; &lt;span style=&quot;color: #F5666D;&quot;&gt;:float&lt;/span&gt; &lt;span style=&quot;color: #F5666D;&quot;&gt;:nc&lt;/span&gt;&lt;span style=&quot;color: #907373;&quot;&gt;)&lt;/span&gt;
                  x-ge &lt;span style=&quot;color: #907373;&quot;&gt;(&lt;/span&gt;trans &lt;span style=&quot;color: #6276ba;&quot;&gt;(&lt;/span&gt;view-ge &lt;span style=&quot;color: #858580;&quot;&gt;(&lt;/span&gt;view-vctr x-tz&lt;span style=&quot;color: #858580;&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: #858580;&quot;&gt;(&lt;/span&gt;* n c&lt;span style=&quot;color: #858580;&quot;&gt;)&lt;/span&gt; t&lt;span style=&quot;color: #6276ba;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #907373;&quot;&gt;)&lt;/span&gt;
                  s-vctr &lt;span style=&quot;color: #907373;&quot;&gt;(&lt;/span&gt;view-vctr s&lt;span style=&quot;color: #907373;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #709870;&quot;&gt;]&lt;/span&gt;
      &lt;span style=&quot;color: #709870;&quot;&gt;(&lt;/span&gt;transfer! &lt;span style=&quot;color: #907373;&quot;&gt;(&lt;/span&gt;submatrix s 0 t c n&lt;span style=&quot;color: #907373;&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: #907373;&quot;&gt;(&lt;/span&gt;view-ge &lt;span style=&quot;color: #6276ba;&quot;&gt;(&lt;/span&gt;view-vctr y-tz&lt;span style=&quot;color: #6276ba;&quot;&gt;)&lt;/span&gt; c n&lt;span style=&quot;color: #907373;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #709870;&quot;&gt;)&lt;/span&gt;
      &lt;span style=&quot;color: #709870;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #A52A2A; font-weight: bold;&quot;&gt;dotimes&lt;/span&gt; &lt;span style=&quot;color: #907373;&quot;&gt;[&lt;/span&gt;j t&lt;span style=&quot;color: #907373;&quot;&gt;]&lt;/span&gt;
        &lt;span style=&quot;color: #907373;&quot;&gt;(&lt;/span&gt;transfer! &lt;span style=&quot;color: #6276ba;&quot;&gt;(&lt;/span&gt;subvector s-vctr &lt;span style=&quot;color: #858580;&quot;&gt;(&lt;/span&gt;* j c&lt;span style=&quot;color: #858580;&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: #858580;&quot;&gt;(&lt;/span&gt;* c n&lt;span style=&quot;color: #858580;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #6276ba;&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: #6276ba;&quot;&gt;(&lt;/span&gt;row x-ge j&lt;span style=&quot;color: #6276ba;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #907373;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #709870;&quot;&gt;)&lt;/span&gt;
      &lt;span style=&quot;color: #709870;&quot;&gt;[&lt;/span&gt;x-tz y-tz&lt;span style=&quot;color: #709870;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #909183;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #7388d6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;

&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
Here&apos;s how the output looks like on an ever simpler example of 2-step sample sequences produced from
5 element long full sequence.
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-clojure&quot;&gt;&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #A52A2A; font-weight: bold;&quot;&gt;def&lt;/span&gt; &lt;span style=&quot;color: #0084C8; font-weight: bold;&quot;&gt;dummy&lt;/span&gt; &lt;span style=&quot;color: #7388d6;&quot;&gt;(&lt;/span&gt;fge 1 5 &lt;span style=&quot;color: #909183;&quot;&gt;(&lt;/span&gt;range 5&lt;span style=&quot;color: #909183;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #7388d6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;pre class=&quot;example&quot; id=&quot;orgbda5dd2&quot;&gt;
#RealGEMatrix[float, mxn:1x5, layout:column, offset:0]
   ▥       ↓       ↓       ↓       ↓       ↓       ┓
   →       0.00    1.00    2.00    3.00    4.00
   ┗                                               ┛
&lt;/pre&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-clojure&quot;&gt;&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #A52A2A; font-weight: bold;&quot;&gt;def&lt;/span&gt; &lt;span style=&quot;color: #0084C8; font-weight: bold;&quot;&gt;dummy-split&lt;/span&gt; &lt;span style=&quot;color: #7388d6;&quot;&gt;(&lt;/span&gt;split-series &lt;span style=&quot;color: #0084C8; font-weight: bold;&quot;&gt;*diamond-factory*&lt;/span&gt; dummy 2&lt;span style=&quot;color: #7388d6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;pre class=&quot;example&quot; id=&quot;orgb48fd65&quot;&gt;
[{:shape [2 3 1], :data-type :float, :layout [3 1 1]} (0.0 1.0 2.0 1.0 2.0 3.0)
 {:shape [3 1], :data-type :float, :layout [1 1]} (2.0 3.0 4.0)]
&lt;/pre&gt;

&lt;p&gt;
This split produces 3 samples for training, each sample has 2 entries, and for each sample there is a desired output.
The tensor printout does not show dimensions, which would be super hard to make sense anyway due to large
dimensionality and enormous number of entries in any tensor of any use. We can extract a matrix view,
in cases when it makes sense.
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-clojure&quot;&gt;&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;view-ge &lt;span style=&quot;color: #7388d6;&quot;&gt;(&lt;/span&gt;view-vctr &lt;span style=&quot;color: #909183;&quot;&gt;(&lt;/span&gt;dummy-split 0&lt;span style=&quot;color: #909183;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #7388d6;&quot;&gt;)&lt;/span&gt; 3 2&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;pre class=&quot;example&quot; id=&quot;org77f14ff&quot;&gt;
#RealGEMatrix[float, mxn:3x2, layout:column, offset:0]
   ▥       ↓       ↓       ┓
   →       0.00    1.00
   →       1.00    2.00
   →       2.00    3.00
   ┗                       ┛
&lt;/pre&gt;

&lt;p&gt;
So, inputs are arranged in rows: &lt;code&gt;[0 1]&lt;/code&gt;, &lt;code&gt;[1 2]&lt;/code&gt;, and &lt;code&gt;[2 3]&lt;/code&gt;. That&apos;s because tensor&apos;s
default layout is &lt;code&gt;:tnc&lt;/code&gt;, meaning that innermost grouping is channels (\(C=1\)), (mini)batch size (\(N=3\))
and time ($T=2).
&lt;/p&gt;

&lt;p&gt;
Ok, so, finally, we transform our own data so that the network can learn from it.
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-clojure&quot;&gt;&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #A52A2A; font-weight: bold;&quot;&gt;def&lt;/span&gt; &lt;span style=&quot;color: #0084C8; font-weight: bold;&quot;&gt;full-series&lt;/span&gt; &lt;span style=&quot;color: #7388d6;&quot;&gt;(&lt;/span&gt;fge 1 200 simple-sequence&lt;span style=&quot;color: #7388d6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;pre class=&quot;example&quot; id=&quot;org571a5a0&quot;&gt;
#RealGEMatrix[float, mxn:1x200, layout:column, offset:0]
   ▥       ↓       ↓       ↓       ↓       ↓       ┓
   →    -100.00  -99.00    ⁙      98.00   99.00
   ┗                                               ┛
&lt;/pre&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-clojure&quot;&gt;&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #A52A2A; font-weight: bold;&quot;&gt;def&lt;/span&gt; &lt;span style=&quot;color: #0084C8; font-weight: bold;&quot;&gt;train-data&lt;/span&gt; &lt;span style=&quot;color: #7388d6;&quot;&gt;(&lt;/span&gt;split-series &lt;span style=&quot;color: #0084C8; font-weight: bold;&quot;&gt;*diamond-factory*&lt;/span&gt; full-series 5&lt;span style=&quot;color: #7388d6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;pre class=&quot;example&quot; id=&quot;org02f92de&quot;&gt;
[{:shape [5 195 1], :data-type :float, :layout [195 1 1]} (-100.0 -99.0 -98.0 -97.0 -96.0 -95.0 -94.0 -93.0 -92.0 -91.0 -90.0 -89.0 -88.0 -87.0 -86.0 -85.0)
 {:shape [195 1], :data-type :float, :layout [1 1]} (-95.0 -94.0 -93.0 -92.0 -91.0 -90.0 -89.0 -88.0 -87.0 -86.0 -85.0 -84.0 -83.0 -82.0 -81.0 -80.0)]
&lt;/pre&gt;

&lt;p&gt;
The printouts of long tensors show only a subset of the content of the tensor.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;

&lt;div id=&quot;outline-container-org186bca1&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;org186bca1&quot;&gt;The actual network&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-org186bca1&quot;&gt;
&lt;p&gt;
The blueprint that we&apos;ve created at the beginning of the article can be simplified
for later reuse. Please note that it&apos;s not some super-opaque magical compiler.
The network architecture is defined as a simple Clojure vector of straight Clojure
functions!
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-clojure&quot;&gt;&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #A52A2A; font-weight: bold;&quot;&gt;def&lt;/span&gt; &lt;span style=&quot;color: #0084C8; font-weight: bold;&quot;&gt;architecture&lt;/span&gt; &lt;span style=&quot;color: #7388d6;&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color: #909183;&quot;&gt;(&lt;/span&gt;rnn &lt;span style=&quot;color: #709870;&quot;&gt;[&lt;/span&gt;128&lt;span style=&quot;color: #709870;&quot;&gt;]&lt;/span&gt; &lt;span style=&quot;color: #F5666D;&quot;&gt;:gru&lt;/span&gt;&lt;span style=&quot;color: #909183;&quot;&gt;)&lt;/span&gt;
                   &lt;span style=&quot;color: #909183;&quot;&gt;(&lt;/span&gt;rnn 2&lt;span style=&quot;color: #909183;&quot;&gt;)&lt;/span&gt;
                   &lt;span style=&quot;color: #909183;&quot;&gt;(&lt;/span&gt;abbreviate&lt;span style=&quot;color: #909183;&quot;&gt;)&lt;/span&gt;
                   &lt;span style=&quot;color: #909183;&quot;&gt;(&lt;/span&gt;dense &lt;span style=&quot;color: #709870;&quot;&gt;[&lt;/span&gt;128&lt;span style=&quot;color: #709870;&quot;&gt;]&lt;/span&gt; &lt;span style=&quot;color: #F5666D;&quot;&gt;:relu&lt;/span&gt;&lt;span style=&quot;color: #909183;&quot;&gt;)&lt;/span&gt;
                   &lt;span style=&quot;color: #909183;&quot;&gt;(&lt;/span&gt;dense &lt;span style=&quot;color: #709870;&quot;&gt;[&lt;/span&gt;1&lt;span style=&quot;color: #709870;&quot;&gt;]&lt;/span&gt; &lt;span style=&quot;color: #F5666D;&quot;&gt;:linear&lt;/span&gt;&lt;span style=&quot;color: #909183;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #7388d6;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;pre class=&quot;example&quot; id=&quot;org7edb365&quot;&gt;
[#function[uncomplicate.diamond.dnn/rnn/fn--43604]
 #function[uncomplicate.diamond.dnn/rnn/fn--43604]
 #function[uncomplicate.diamond.dnn/abbreviate/fn--43609]
 #function[uncomplicate.diamond.dnn/fully-connected/fn--43493]
 #function[uncomplicate.diamond.dnn/fully-connected/fn--43493]]
&lt;/pre&gt;

&lt;p&gt;
This architecture is independent from the specific input dimensions.
We create a blueprint by specifying the dimensions and the architecture.
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-clojure&quot;&gt;&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #A52A2A; font-weight: bold;&quot;&gt;def&lt;/span&gt; &lt;span style=&quot;color: #0084C8; font-weight: bold;&quot;&gt;net-bp&lt;/span&gt; &lt;span style=&quot;color: #7388d6;&quot;&gt;(&lt;/span&gt;network &lt;span style=&quot;color: #909183;&quot;&gt;(&lt;/span&gt;desc &lt;span style=&quot;color: #709870;&quot;&gt;[&lt;/span&gt;5 32 1&lt;span style=&quot;color: #709870;&quot;&gt;]&lt;/span&gt; &lt;span style=&quot;color: #F5666D;&quot;&gt;:float&lt;/span&gt; &lt;span style=&quot;color: #F5666D;&quot;&gt;:tnc&lt;/span&gt;&lt;span style=&quot;color: #909183;&quot;&gt;)&lt;/span&gt;
                     architecture&lt;span style=&quot;color: #7388d6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
This blueprint is independent of the learning algorithm. It is a function
that creates the actual network training program. In this case, I will
use gradient descent with adaptive moments (:adam). Before we start learning,
we initialize the network with random weights, automatically chosen by
 &lt;a href=&quot;https://github.com/uncomplicate/deep-diamond&quot;&gt;Deep Diamond&lt;/a&gt;(&lt;iframe class=&quot;github-btn&quot; src=&quot;https://ghbtns.com/github-btn.html?user=uncomplicate&amp;amp;repo=deep-diamond&amp;amp;type=watch&amp;amp;count=true&quot; width=&quot;100&quot; height=&quot;20&quot; title=&quot;Star on GitHub&quot; frameBorder=&quot;0&quot;&gt;&lt;/iframe&gt;) according to good practices, but you are free to use another
initialization function that is more to your liking. Everything in Deep Diamond
is modular and implemented in Clojure fashion of &quot;assemble your own if you wish&quot;.
If you are content with my choices, then everything is automatic!
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-clojure&quot;&gt;&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #A52A2A; font-weight: bold;&quot;&gt;def&lt;/span&gt; &lt;span style=&quot;color: #0084C8; font-weight: bold;&quot;&gt;net&lt;/span&gt; &lt;span style=&quot;color: #7388d6;&quot;&gt;(&lt;/span&gt;init! &lt;span style=&quot;color: #909183;&quot;&gt;(&lt;/span&gt;net-bp &lt;span style=&quot;color: #F5666D;&quot;&gt;:adam&lt;/span&gt;&lt;span style=&quot;color: #909183;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #7388d6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
Here&apos;s the network printout, in case you
&lt;/p&gt;

&lt;pre class=&quot;example&quot; id=&quot;orgd1b0c68&quot;&gt;
=======================================================================
#SequentialNetwork[train, input:[5 32 1], layers:5, workspace:1]
-----------------------------------------------------------------------
#Adam[topology::gru, shape:[5 32 128], activation: :identity]
 parameters: [{:shape [1 1 129 3 128], :data-type :float, :layout [49536 49536 384 128 1]} (2.1676771211787127E-5 -5.19975537827122E-6 5.7575953178456984E-6 2.380384103162214E-5 -2.894530371122528E-5 -2.4803119913485716E-7 -1.6729745766497217E-5 -2.902976348195807E-6 4.530028309090994E-5 5.464621608552989E-6 -5.7127394939016085E-6 1.593221713847015E-5 -1.1793279554694891E-5 -7.507987476174094E-8 -1.1438844921940472E-5 5.965541276964359E-6) {:shape [1 1 3 128], :data-type :float, :layout [384 384 128 1]} (0.0035437364131212234 -0.001584756188094616 0.0013698132243007421 -1.2431709910742939E-4 1.7048766312655061E-4 0.002398068318143487 0.00372034078463912 -0.0021170536056160927 8.799560600891709E-4 -0.0023348634131252766 8.223060867749155E-4 -1.1841517698485404E-4 -0.004045043606311083 9.459585417062044E-4 -0.0037800846621394157 -0.002804018324241042)]
-----------------------------------------------------------------------
#Adam[topology::gru, shape:[5 32 128], activation: :identity]
 parameters: [{:shape [2 1 256 3 128], :data-type :float, :layout [98304 98304 384 128 1]} (2.276021717761978E-7 3.804875632340554E-6 1.058972247847123E-5 2.8063212198503606E-7 1.8309128790860996E-5 -9.416969078301918E-6 -7.987003414200444E-8 1.0779360309243202E-5 2.222931470896583E-6 -1.2704362234217115E-5 1.5140467439778149E-5 -2.0407780539244413E-5 -1.5779027080498054E-6 -1.0661310625437181E-5 -3.834541985270334E-6 -1.0737002412497532E-5) {:shape [2 1 3 128], :data-type :float, :layout [384 384 128 1]} (8.910018368624151E-4 0.003690000157803297 -4.8378523206338286E-4 -0.0034620240330696106 0.0031146425753831863 6.610305863432586E-4 0.00204548635520041 0.001728582545183599 -0.0027434946969151497 0.007643579971045256 0.00425624568015337 -0.00295245717279613 1.8937387721962295E-5 -0.0027048818301409483 -0.0012806318700313568 -0.0028582836966961622)]
-----------------------------------------------------------------------
{:shape [32 128], :topology :abbreviate}
#Adam[topology::dense, shape:[32 128], activation: :relu]
 parameters: [{:shape [128 128], :data-type :float, :layout [8192 1024]} (-0.004568892996758223 -0.004355841316282749 0.005139997228980064 -0.005750759970396757 -0.004274052567780018 0.005599929019808769 -0.003351157531142235 -0.008299742825329304 -0.0031023912597447634 0.0013810413656756282 0.002118719043210149 0.0023180078715085983 -0.005323362536728382 -0.013326002284884453 7.393552223220468E-4 -0.013735005632042885) {:shape [128], :data-type :float, :layout [1]} (0.5049463510513306 -0.47153180837631226 -1.3509427309036255 -1.3017100095748901 -0.39814749360084534 0.8303372263908386 0.6530964970588684 -0.22249580919742584 -1.326366901397705 0.16360507905483246 -0.022157425060868263 2.0535836219787598 1.8076190948486328 -0.0799550786614418 -1.6791125535964966 -0.7451670169830322)]
-----------------------------------------------------------------------
#Adam[topology::dense, shape:[32 1], activation: :linear]
 parameters: [{:shape [1 128], :data-type :float, :layout [1 1]} (0.003621552372351289 -0.004416522569954395 2.548426273278892E-4 0.006995228119194508 0.0013199367094784975 -0.0018220240017399192 0.009454095736145973 0.003091101534664631 -0.01203352864831686 -0.014204473234713078 -0.007159397471696138 0.0039085038006305695 0.0029486482962965965 -0.009481357410550117 0.009158425033092499 -0.004999339580535889) {:shape [1], :data-type :float, :layout [1]} (-0.09112684428691864)]
=======================================================================
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;

&lt;div id=&quot;outline-container-orga09ae80&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;orga09ae80&quot;&gt;Training, finally!&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-orga09ae80&quot;&gt;
&lt;p&gt;
Hey, I promised you a Hello World, and I&apos;ve been beating the bush for half an hour
formatting the data. And we didn&apos;t even touched the biggest obstacle: actually training
the network. Is it hard? Yes, but not for the user. Now it&apos;s time for &lt;a href=&quot;https://github.com/uncomplicate/deep-diamond&quot;&gt;Deep Diamond&lt;/a&gt;(&lt;iframe class=&quot;github-btn&quot; src=&quot;https://ghbtns.com/github-btn.html?user=uncomplicate&amp;amp;repo=deep-diamond&amp;amp;type=watch&amp;amp;count=true&quot; width=&quot;100&quot; height=&quot;20&quot; title=&quot;Star on GitHub&quot; frameBorder=&quot;0&quot;&gt;&lt;/iframe&gt;) to beat the hell out of your
CPU or GPU. But it will at leas do this on its own :)
&lt;/p&gt;

&lt;p&gt;
Since this is a Hello World, we&apos;ll start with 50 epochs and see how it&apos;s going.
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-clojure&quot;&gt;&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;time &lt;span style=&quot;color: #7388d6;&quot;&gt;(&lt;/span&gt;train-shuffle net &lt;span style=&quot;color: #909183;&quot;&gt;(&lt;/span&gt;train-data 0&lt;span style=&quot;color: #909183;&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: #909183;&quot;&gt;(&lt;/span&gt;train-data 1&lt;span style=&quot;color: #909183;&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: #F5666D;&quot;&gt;:quadratic&lt;/span&gt; 50 &lt;span style=&quot;color: #909183;&quot;&gt;[&lt;/span&gt;0.005&lt;span style=&quot;color: #909183;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #7388d6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;pre class=&quot;example&quot; id=&quot;orgc9d095f&quot;&gt;
&quot;Elapsed time: 769.986155 msecs&quot;
3238.298712769756
&lt;/pre&gt;

&lt;p&gt;
Hmmmm. The cost of 3000 and change does not look very good. Would more training help?
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-clojure&quot;&gt;&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;time &lt;span style=&quot;color: #7388d6;&quot;&gt;(&lt;/span&gt;train-shuffle net &lt;span style=&quot;color: #909183;&quot;&gt;(&lt;/span&gt;train-data 0&lt;span style=&quot;color: #909183;&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: #909183;&quot;&gt;(&lt;/span&gt;train-data 1&lt;span style=&quot;color: #909183;&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: #F5666D;&quot;&gt;:quadratic&lt;/span&gt; 50 &lt;span style=&quot;color: #909183;&quot;&gt;[&lt;/span&gt;0.005&lt;span style=&quot;color: #909183;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #7388d6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;pre class=&quot;example&quot; id=&quot;org9bea272&quot;&gt;
&quot;Elapsed time: 744.456035 msecs&quot;
708.0862449675478
&lt;/pre&gt;

&lt;p&gt;
Still bad, but it&apos;s improving! For the sake of experinmenting, I&apos;ve run this ten(ish) times,
and the cost has been steadily decreasing, to the point that it looks good now.
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-clojure&quot;&gt;&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;time &lt;span style=&quot;color: #7388d6;&quot;&gt;(&lt;/span&gt;train-shuffle net &lt;span style=&quot;color: #909183;&quot;&gt;(&lt;/span&gt;train-data 0&lt;span style=&quot;color: #909183;&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: #909183;&quot;&gt;(&lt;/span&gt;train-data 1&lt;span style=&quot;color: #909183;&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: #F5666D;&quot;&gt;:quadratic&lt;/span&gt; 50 &lt;span style=&quot;color: #909183;&quot;&gt;[&lt;/span&gt;0.005&lt;span style=&quot;color: #909183;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #7388d6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;pre class=&quot;example&quot; id=&quot;org94fe921&quot;&gt;
&quot;Elapsed time: 720.427332 msecs&quot;
0.13662090173881225
&lt;/pre&gt;

&lt;p&gt;
We don&apos;t have to stick to 50-epoch runs. Let&apos;s do 500 at once.
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-clojure&quot;&gt;&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;time &lt;span style=&quot;color: #7388d6;&quot;&gt;(&lt;/span&gt;train-shuffle net &lt;span style=&quot;color: #909183;&quot;&gt;(&lt;/span&gt;train-data 0&lt;span style=&quot;color: #909183;&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: #909183;&quot;&gt;(&lt;/span&gt;train-data 1&lt;span style=&quot;color: #909183;&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: #F5666D;&quot;&gt;:quadratic&lt;/span&gt; 500 &lt;span style=&quot;color: #909183;&quot;&gt;[&lt;/span&gt;0.005&lt;span style=&quot;color: #909183;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #7388d6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;pre class=&quot;example&quot; id=&quot;orgb7cb238&quot;&gt;
&quot;Elapsed time: 6325.427605 msecs&quot;
0.008672867995529465
&lt;/pre&gt;

&lt;p&gt;
This looks nice. A thousand epochs might seem a lot, but considering the large network size,
recurrent layers, and the scarceness of the training data, it might actually be appropriate.
On the other hand, Deep Diamond did it blazingly fast, in a mere dozen seconds! In the world
of machine learning, this is nothing.
&lt;/p&gt;



&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-clojure&quot;&gt;&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #A52A2A; font-weight: bold;&quot;&gt;def&lt;/span&gt; &lt;span style=&quot;color: #0084C8; font-weight: bold;&quot;&gt;question&lt;/span&gt; &lt;span style=&quot;color: #7388d6;&quot;&gt;(&lt;/span&gt;tensor &lt;span style=&quot;color: #909183;&quot;&gt;[&lt;/span&gt;5 1 1&lt;span style=&quot;color: #909183;&quot;&gt;]&lt;/span&gt; &lt;span style=&quot;color: #F5666D;&quot;&gt;:float&lt;/span&gt; &lt;span style=&quot;color: #F5666D;&quot;&gt;:tnc&lt;/span&gt;&lt;span style=&quot;color: #7388d6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;
&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;transfer! &lt;span style=&quot;color: #7388d6;&quot;&gt;[&lt;/span&gt;1 2 3 4 5&lt;span style=&quot;color: #7388d6;&quot;&gt;]&lt;/span&gt; question&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;pre class=&quot;example&quot; id=&quot;org62e7889&quot;&gt;
{:shape [5 1 1], :data-type :float, :layout [1 1 1]} (1.0 2.0 3.0 4.0 5.0)
&lt;/pre&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-clojure&quot;&gt;&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;infer net question&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;pre class=&quot;example&quot; id=&quot;org8d055e2&quot;&gt;
Dragan says: Requested subtensor is outside of bounds.
{:src-index -31, :src-cnt 1, :dst-index 0, :dst-cnt 32, :mb-size 1}
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;

&lt;div id=&quot;outline-container-org2a87b99&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;org2a87b99&quot;&gt;Using the network for inference&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-org2a87b99&quot;&gt;
&lt;p&gt;
Now that we have our super useful network, we can stop and think: but how do we use it?
First, we need data that could be interpreted as a &quot;question&quot;. Our network needs a sequence
of five numbers, and when fed, will answer with one number. Obviously, these should be
provided as tensors of appropriate dimensions.
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-clojure&quot;&gt;&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #A52A2A; font-weight: bold;&quot;&gt;def&lt;/span&gt; &lt;span style=&quot;color: #0084C8; font-weight: bold;&quot;&gt;question&lt;/span&gt; &lt;span style=&quot;color: #7388d6;&quot;&gt;(&lt;/span&gt;tensor &lt;span style=&quot;color: #909183;&quot;&gt;[&lt;/span&gt;5 1 1&lt;span style=&quot;color: #909183;&quot;&gt;]&lt;/span&gt; &lt;span style=&quot;color: #F5666D;&quot;&gt;:float&lt;/span&gt; &lt;span style=&quot;color: #F5666D;&quot;&gt;:tnc&lt;/span&gt;&lt;span style=&quot;color: #7388d6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;
&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;transfer! &lt;span style=&quot;color: #7388d6;&quot;&gt;[&lt;/span&gt;1 2 3 4 5&lt;span style=&quot;color: #7388d6;&quot;&gt;]&lt;/span&gt; question&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
However, invoking inference would cause the complaint from the network.
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-clojure&quot;&gt;&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;infer net question&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-clojure&quot;&gt;Execution error &lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;ExceptionInfo&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt; at &lt;span style=&quot;color: #2F8B58; font-weight: bold;&quot;&gt;uncomplicate.commons.utils&lt;/span&gt;/dragan-says-ex &lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;utils.clj:105&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;.
Dragan says: Requested subtensor is outside of bounds.
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
Our network&apos;s input requires a minibatch of 32 samples. The &lt;code&gt;infer&lt;/code&gt; function
can handle more, and do the inference in mini batches of 32, but it can&apos;t handle
fewer samples.
&lt;/p&gt;

&lt;p&gt;
One of the solutions is to create another blueprint with the same structure, and transfer
learned weights to the new network.
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-clojure&quot;&gt;&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #A52A2A; font-weight: bold;&quot;&gt;def&lt;/span&gt; &lt;span style=&quot;color: #0084C8; font-weight: bold;&quot;&gt;net1-bp&lt;/span&gt; &lt;span style=&quot;color: #7388d6;&quot;&gt;(&lt;/span&gt;network &lt;span style=&quot;color: #909183;&quot;&gt;(&lt;/span&gt;desc &lt;span style=&quot;color: #709870;&quot;&gt;[&lt;/span&gt;5 1 1&lt;span style=&quot;color: #709870;&quot;&gt;]&lt;/span&gt; &lt;span style=&quot;color: #F5666D;&quot;&gt;:float&lt;/span&gt; &lt;span style=&quot;color: #F5666D;&quot;&gt;:tnc&lt;/span&gt;&lt;span style=&quot;color: #909183;&quot;&gt;)&lt;/span&gt;
                      architecture&lt;span style=&quot;color: #7388d6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
While we&apos;re at it, we don&apos;t need to create a complex network capable of learning
(:adam or :sgd). We can create a much cheaper inference network that takes fewer resources.
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-clojure&quot;&gt;&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #A52A2A; font-weight: bold;&quot;&gt;def&lt;/span&gt; &lt;span style=&quot;color: #0084C8; font-weight: bold;&quot;&gt;net1-infer&lt;/span&gt; &lt;span style=&quot;color: #7388d6;&quot;&gt;(&lt;/span&gt;net1-bp&lt;span style=&quot;color: #7388d6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;
&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;transfer! net net1-infer&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
Now, finally, give us the answer, network!
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-clojure&quot;&gt;&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;infer net1-infer question&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;pre class=&quot;example&quot; id=&quot;org3c752ba&quot;&gt;
{:shape [1 1], :data-type :float, :layout [1 1]} (6.016137599945068)
&lt;/pre&gt;

&lt;p&gt;
So, being asked what is the next element in the sequence of &lt;code&gt;[1.0 2.0 3.0 4.0 5.0]&lt;/code&gt;
(remember, we specified data type :float), our network answers &lt;code&gt;[6.0161]&lt;/code&gt; which is
close enough to the actual target value that we can mark this as correct.
But, it&apos;s not a great achievement, since our network already saw this sequence in
training. A hash map would have done much better job at guessing this. Let&apos;s try
a previously unseen sequence.
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-clojure&quot;&gt;&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;transfer! &lt;span style=&quot;color: #7388d6;&quot;&gt;[&lt;/span&gt;10 12 14 16 18&lt;span style=&quot;color: #7388d6;&quot;&gt;]&lt;/span&gt; question&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;
&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;infer net1-infer question&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;pre class=&quot;example&quot; id=&quot;orgb175460&quot;&gt;
{:shape [1 1], :data-type :float, :layout [1 1]} (17.750324249267578)
&lt;/pre&gt;

&lt;p&gt;
Not that off, but one would expect 19.0. What went wrong? We trained our network
with ducks \((x+1)\) and asked it about geese \((x+2)\). What about griffons?
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-clojure&quot;&gt;&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;transfer! &lt;span style=&quot;color: #7388d6;&quot;&gt;[&lt;/span&gt;10 1 100 16 34&lt;span style=&quot;color: #7388d6;&quot;&gt;]&lt;/span&gt; question&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;
&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;infer net1-infer question&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;pre class=&quot;example&quot; id=&quot;orgedddbbb&quot;&gt;
{:shape [1 1], :data-type :float, :layout [1 1]} (-6.679039001464844)
&lt;/pre&gt;

&lt;p&gt;
Now the answer does not make any sense, but would you be able to come with a better answer?
&lt;/p&gt;

&lt;p&gt;
All, right, let&apos;s try with a sequence that is similar to the one we used in training,
but is out of the range of data that the network has seen.
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-clojure&quot;&gt;&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;transfer! &lt;span style=&quot;color: #7388d6;&quot;&gt;[&lt;/span&gt;1000 1001 1002 1003 1004&lt;span style=&quot;color: #7388d6;&quot;&gt;]&lt;/span&gt; question&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;
&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;infer net1-infer question&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;pre class=&quot;example&quot; id=&quot;orga438f17&quot;&gt;
{:shape [1 1], :data-type :float, :layout [1 1]} (96.41997528076172)
&lt;/pre&gt;

&lt;p&gt;
Nope, not much success, but we should not have expected any. The network can not
answer question outside its domain of expertise.
&lt;/p&gt;

&lt;p&gt;
Let&apos;s try with previously unseen data, but inside the domain that we used for training (floats from -100.0 to 1000).
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-clojure&quot;&gt;&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;transfer! &lt;span style=&quot;color: #7388d6;&quot;&gt;[&lt;/span&gt;37.4 38.4 39.4 40.4 41.4&lt;span style=&quot;color: #7388d6;&quot;&gt;]&lt;/span&gt; question&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;
&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;infer net1-infer question&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;pre class=&quot;example&quot; id=&quot;org96991c4&quot;&gt;
{:shape [1 1], :data-type :float, :layout [1 1]} (42.39200210571289)
&lt;/pre&gt;

&lt;p&gt;
This is actually pretty close!
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;

&lt;div id=&quot;outline-container-orgd6b4463&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;orgd6b4463&quot;&gt;What about GPU?&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-orgd6b4463&quot;&gt;
&lt;p&gt;
Sure!
&lt;/p&gt;


&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-clojure&quot;&gt;&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #A52A2A; font-weight: bold;&quot;&gt;def&lt;/span&gt; &lt;span style=&quot;color: #0084C8; font-weight: bold;&quot;&gt;nvidia&lt;/span&gt; &lt;span style=&quot;color: #7388d6;&quot;&gt;(&lt;/span&gt;cudnn-factory&lt;span style=&quot;color: #7388d6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;

&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #A52A2A; font-weight: bold;&quot;&gt;def&lt;/span&gt; &lt;span style=&quot;color: #0084C8; font-weight: bold;&quot;&gt;gpu-net-bp&lt;/span&gt; &lt;span style=&quot;color: #7388d6;&quot;&gt;(&lt;/span&gt;network nvidia
                         &lt;span style=&quot;color: #909183;&quot;&gt;(&lt;/span&gt;desc &lt;span style=&quot;color: #709870;&quot;&gt;[&lt;/span&gt;5 32 1&lt;span style=&quot;color: #709870;&quot;&gt;]&lt;/span&gt; &lt;span style=&quot;color: #F5666D;&quot;&gt;:float&lt;/span&gt; &lt;span style=&quot;color: #F5666D;&quot;&gt;:tnc&lt;/span&gt;&lt;span style=&quot;color: #909183;&quot;&gt;)&lt;/span&gt;
                         architecture&lt;span style=&quot;color: #7388d6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;

&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #A52A2A; font-weight: bold;&quot;&gt;def&lt;/span&gt; &lt;span style=&quot;color: #0084C8; font-weight: bold;&quot;&gt;gpu-net&lt;/span&gt; &lt;span style=&quot;color: #7388d6;&quot;&gt;(&lt;/span&gt;init! &lt;span style=&quot;color: #909183;&quot;&gt;(&lt;/span&gt;gpu-net-bp &lt;span style=&quot;color: #F5666D;&quot;&gt;:adam&lt;/span&gt;&lt;span style=&quot;color: #909183;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #7388d6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;

&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #A52A2A; font-weight: bold;&quot;&gt;def&lt;/span&gt; &lt;span style=&quot;color: #0084C8; font-weight: bold;&quot;&gt;gpu-train-data&lt;/span&gt; &lt;span style=&quot;color: #7388d6;&quot;&gt;(&lt;/span&gt;split-series nvidia full-series 5&lt;span style=&quot;color: #7388d6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;
Let&apos;s hit it with 1000 epochs right away.
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-clojure&quot;&gt;&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;time &lt;span style=&quot;color: #7388d6;&quot;&gt;(&lt;/span&gt;train-shuffle gpu-net &lt;span style=&quot;color: #909183;&quot;&gt;(&lt;/span&gt;gpu-train-data 0&lt;span style=&quot;color: #909183;&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: #909183;&quot;&gt;(&lt;/span&gt;gpu-train-data 1&lt;span style=&quot;color: #909183;&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: #F5666D;&quot;&gt;:quadratic&lt;/span&gt; 1000 &lt;span style=&quot;color: #909183;&quot;&gt;[&lt;/span&gt;0.005&lt;span style=&quot;color: #909183;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #7388d6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;pre class=&quot;example&quot; id=&quot;orgf957073&quot;&gt;
&quot;Elapsed time: 5734.688665 msecs&quot;
4.561427662266859E-4
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
</description>
        <pubDate>Fri, 26 Aug 2022 16:25:00 +0200</pubDate>
        <link>http://dragan.rocks/articles/22/Recurrent-networks-hello-world-sequence-prediction-in-Clojure-with-new-Deep-Diamond</link>
        <guid isPermaLink="true">http://dragan.rocks/articles/22/Recurrent-networks-hello-world-sequence-prediction-in-Clojure-with-new-Deep-Diamond</guid>
        
        
        <category>Clojure,</category>
        
        <category>RNN,</category>
        
        <category>Deep</category>
        
        <category>Diamond,</category>
        
        <category>Learning,</category>
        
        <category>Recurrent</category>
        
        <category>Neural</category>
        
        <category>Networks</category>
        
      </item>
    
      <item>
        <title>Clojure Sound - 5 - Double Click with Foot Control</title>
        <description>&lt;p&gt;
In the &lt;a href=&quot;./Clojure-Sound-4-Ctrl-Left-Pedal&quot;&gt;last article&lt;/a&gt; we created a receiver function that listened to signals from our
foot controller and started or stopped playback on consecutive clicks. The trouble
with our player it that it only works until the end of the track. The &lt;code&gt;start!&lt;/code&gt; function
does not automatically rewind the playback. Neither &lt;code&gt;stop!&lt;/code&gt; does that. Our program is
responsible for detecting that the track should be rewound, perhaps by detecting that
we reached the end of track (but even that is not fool proof, since audio infrastructure
is not that precise). Now we have to think about a foot user interface that is useful
and simple at the same time - there&apos;s not many different precise actions that a foot can do.
&lt;/p&gt;

&lt;p&gt;
My idea at this time is the following: distinguish three gestures:
&lt;/p&gt;
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;Button (un)pressed (value 0)&lt;/li&gt;
&lt;li&gt;Button pressed (value 127)&lt;/li&gt;
&lt;li&gt;Button pressed twice in a short time span (doubleclick). This can have two varieties:
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;First pressed (value 127), then (un)pressed (value 0)&lt;/li&gt;
&lt;li&gt;(Un)pressed (value 0), then pressed (value 127).&lt;/li&gt;
&lt;li&gt;The values 0 and 127 always interchange, there&apos;s no way to send the same value twice in a row (with the MIDI controller I have).&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;div id=&quot;org0144506&quot; class=&quot;figure&quot;&gt;
&lt;p&gt;&lt;img src=&quot;../img/clojure-sound/fc_300_angle_gal.jpg&quot; alt=&quot;fc_300_angle_gal.jpg&quot; /&gt;
&lt;/p&gt;
&lt;/div&gt;

&lt;p&gt;
This gives us 4 different signals from one button that we can work with, which doesn&apos;t seem &lt;i&gt;that&lt;/i&gt; much,
but on the other hand, we can&apos;t assume that the feet of our user that is doing all this stomping is
able or eager for much more complicated stuff.
&lt;/p&gt;

&lt;p&gt;
So, if I assume that the particular button is dedicated to a particular clip playback,
I see the following actions:
&lt;/p&gt;
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;If the button is (un)pressed (value 0), the clip should stop, regardless of the previous state. If the clip has not been playing, nothing changes.&lt;/li&gt;
&lt;li&gt;If the button is pressed (value 127), the clip should start, regardless of the previous state. If the clip has been playing, it just keeps playing.&lt;/li&gt;
&lt;li&gt;If the button is clicked twice in a row, the things might get complicated!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;
It&apos;s not exactly rocket science level complicated, but we still need to think what to do.
In our desktop user interface toolkits, we are accustomed to working with a very high level
API. We write functions that react to gestures (click, left click, right click, double click, wheel scroll, touch, etc.)
but we are not responsible for detecting these gestures from the signals that our Magic Trackpad sends;
the drivers and the operating system take care of that complexity. We just write actions that happen &lt;code&gt;onDoubleclick&lt;/code&gt;.
&lt;/p&gt;

&lt;p&gt;
But here, we have to take care of the whole stream of raw signals. How should we distinguish between
an action that happens when the button is clicked once, and an action that should register that first click, and
wait for the second one, which may never come? And, we would like the solution to be simple!
&lt;/p&gt;

&lt;p&gt;
I drew a simple state transition diagram (with a pen on a napkin) and concluded that for our limited
foot control it can be simplified to this:
&lt;/p&gt;
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;As soon as the button is pressed, evaluate either &lt;code&gt;start!&lt;/code&gt; (value 127), or &lt;code&gt;stop!&lt;/code&gt; (value 0) function.&lt;/li&gt;
&lt;li&gt;When the button is pressed shortly after it has been pressed the previous time (say, 600 milliseconds), treat it as a double click, and initiate the alternative action.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;
This leaves us with two tasks:
&lt;/p&gt;
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;Detecting doubleclick&lt;/li&gt;
&lt;li&gt;Deciding on a simple decision process for the alternative action (remember, the user should anticipate the action while playing the guitar).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;
The usual imports:
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-clojure&quot;&gt;&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #A52A2A; font-weight: bold;&quot;&gt;ns&lt;/span&gt; &lt;span style=&quot;color: #2F8B58; font-weight: bold;&quot;&gt;my-midi&lt;/span&gt;&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;
&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;require &apos;&lt;span style=&quot;color: #7388d6;&quot;&gt;[&lt;/span&gt;uncomplicate.commons.core &lt;span style=&quot;color: #F5666D;&quot;&gt;:refer&lt;/span&gt; &lt;span style=&quot;color: #909183;&quot;&gt;[&lt;/span&gt;close! info&lt;span style=&quot;color: #909183;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #7388d6;&quot;&gt;]&lt;/span&gt;
         &apos;&lt;span style=&quot;color: #7388d6;&quot;&gt;[&lt;/span&gt;uncomplicate.clojure-sound
           &lt;span style=&quot;color: #909183;&quot;&gt;[&lt;/span&gt;core &lt;span style=&quot;color: #F5666D;&quot;&gt;:refer&lt;/span&gt; &lt;span style=&quot;color: #F5666D;&quot;&gt;:all&lt;/span&gt;&lt;span style=&quot;color: #909183;&quot;&gt;]&lt;/span&gt;
           &lt;span style=&quot;color: #909183;&quot;&gt;[&lt;/span&gt;midi &lt;span style=&quot;color: #F5666D;&quot;&gt;:refer&lt;/span&gt; &lt;span style=&quot;color: #F5666D;&quot;&gt;:all&lt;/span&gt;&lt;span style=&quot;color: #909183;&quot;&gt;]&lt;/span&gt;
           &lt;span style=&quot;color: #909183;&quot;&gt;[&lt;/span&gt;sampled &lt;span style=&quot;color: #F5666D;&quot;&gt;:refer&lt;/span&gt; &lt;span style=&quot;color: #F5666D;&quot;&gt;:all&lt;/span&gt;&lt;span style=&quot;color: #909183;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #7388d6;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;div id=&quot;outline-container-org98665ef&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;org98665ef&quot;&gt;Detecting doubleclick&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-org98665ef&quot;&gt;
&lt;p&gt;
If you went back to one of the previous articles and connect the &lt;code&gt;println&lt;/code&gt; as a receiver for
the controller you have, you&apos;d see that each message contains its timestamps in microseconds.
We can detect whether a &quot;click&quot; message comes shortly after the previous &quot;unclick&quot; simply by
subtracting the previous message timestamp. The only trouble is that we don&apos;t have access
to message history.
&lt;/p&gt;

&lt;p&gt;
If we saved the last message, we have all the information we need; not only that we know both timestamps,
we can even recognized whether the last message is of the same kind, and coming from the same button!
Fast pressing &lt;i&gt;different&lt;/i&gt; buttons does not count as &quot;doubleclick&quot;. Clojure gives us several elegant
facilities for state management. In this case, the state is internal, so we don&apos;t have to care about
synchronization. We don&apos;t need what refs, agents, or atoms offer. I think that the simple &lt;code&gt;volatile!&lt;/code&gt;
can serve our needs rather well.
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-clojure&quot;&gt;&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #A52A2A; font-weight: bold;&quot;&gt;defn&lt;/span&gt; &lt;span style=&quot;color: #00578E; font-weight: bold;&quot;&gt;play&lt;/span&gt; &lt;span style=&quot;color: #7388d6;&quot;&gt;[&lt;/span&gt;line&lt;span style=&quot;color: #7388d6;&quot;&gt;]&lt;/span&gt;
  &lt;span style=&quot;color: #7388d6;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #A52A2A; font-weight: bold;&quot;&gt;let&lt;/span&gt; &lt;span style=&quot;color: #909183;&quot;&gt;[&lt;/span&gt;previous-message &lt;span style=&quot;color: #709870;&quot;&gt;(&lt;/span&gt;volatile! &lt;span style=&quot;color: #907373;&quot;&gt;(&lt;/span&gt;short-message &lt;span style=&quot;color: #F5666D;&quot;&gt;:control-change&lt;/span&gt; 0 0&lt;span style=&quot;color: #907373;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #709870;&quot;&gt;)&lt;/span&gt;
        previous-timestamp &lt;span style=&quot;color: #709870;&quot;&gt;(&lt;/span&gt;volatile! 0&lt;span style=&quot;color: #709870;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #909183;&quot;&gt;]&lt;/span&gt;
    &lt;span style=&quot;color: #909183;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #A52A2A; font-weight: bold;&quot;&gt;fn&lt;/span&gt; &lt;span style=&quot;color: #709870;&quot;&gt;[&lt;/span&gt;message timestamp&lt;span style=&quot;color: #709870;&quot;&gt;]&lt;/span&gt;
      &lt;span style=&quot;color: #709870;&quot;&gt;(&lt;/span&gt;future
        &lt;span style=&quot;color: #907373;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #A52A2A; font-weight: bold;&quot;&gt;case&lt;/span&gt; &lt;span style=&quot;color: #6276ba;&quot;&gt;(&lt;/span&gt;command-type-key &lt;span style=&quot;color: #858580;&quot;&gt;(&lt;/span&gt;status message&lt;span style=&quot;color: #858580;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #6276ba;&quot;&gt;)&lt;/span&gt;
          &lt;span style=&quot;color: #F5666D;&quot;&gt;:control-change&lt;/span&gt; &lt;span style=&quot;color: #6276ba;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #A52A2A; font-weight: bold;&quot;&gt;let&lt;/span&gt; &lt;span style=&quot;color: #858580;&quot;&gt;[&lt;/span&gt;doubleclick &lt;span style=&quot;color: #80a880;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #A52A2A; font-weight: bold;&quot;&gt;and&lt;/span&gt; &lt;span style=&quot;color: #887070;&quot;&gt;(&lt;/span&gt;= &lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;data1 @previous-message&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;data1 message&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #887070;&quot;&gt;)&lt;/span&gt;
                                                 &lt;span style=&quot;color: #887070;&quot;&gt;(&lt;/span&gt;&amp;lt; &lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;- timestamp @previous-timestamp&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt; 600000&lt;span style=&quot;color: #887070;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #80a880;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #858580;&quot;&gt;]&lt;/span&gt;
                            &lt;span style=&quot;color: #858580;&quot;&gt;(&lt;/span&gt;vreset! previous-timestamp timestamp&lt;span style=&quot;color: #858580;&quot;&gt;)&lt;/span&gt;
                            &lt;span style=&quot;color: #858580;&quot;&gt;(&lt;/span&gt;vreset! previous-message message&lt;span style=&quot;color: #858580;&quot;&gt;)&lt;/span&gt;
                            &lt;span style=&quot;color: #858580;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #A52A2A; font-weight: bold;&quot;&gt;case&lt;/span&gt; &lt;span style=&quot;color: #80a880;&quot;&gt;(&lt;/span&gt;data1 message&lt;span style=&quot;color: #80a880;&quot;&gt;)&lt;/span&gt;
                              80 &lt;span style=&quot;color: #80a880;&quot;&gt;(&lt;/span&gt;play-control &lt;span style=&quot;color: #887070;&quot;&gt;(&lt;/span&gt;data2 message&lt;span style=&quot;color: #887070;&quot;&gt;)&lt;/span&gt; repeated&lt;span style=&quot;color: #80a880;&quot;&gt;)&lt;/span&gt;
                              &lt;span style=&quot;color: #F5666D;&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;color: #858580;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #6276ba;&quot;&gt;)&lt;/span&gt;
          &lt;span style=&quot;color: #F5666D;&quot;&gt;:program-change&lt;/span&gt; &lt;span style=&quot;color: #4E9A06;&quot;&gt;&quot;We&apos;ll do something with other buttons later!&quot;&lt;/span&gt;
          &lt;span style=&quot;color: #F5666D;&quot;&gt;:default&lt;/span&gt;&lt;span style=&quot;color: #907373;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #709870;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #909183;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #7388d6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
Building on the &lt;code&gt;play&lt;/code&gt; function from the last article, I&apos;ve added closures via &lt;code&gt;let&lt;/code&gt; to keep track of the previous
message and its timestamp, and a simple case to distinguish &lt;code&gt;:control-change&lt;/code&gt; vs &lt;code&gt;:program-change&lt;/code&gt; messages.
I&apos;ve also delegated the action logic to an extracted function &lt;code&gt;play-control&lt;/code&gt;.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;

&lt;div id=&quot;outline-container-org8113ef8&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;org8113ef8&quot;&gt;Alternative action&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-org8113ef8&quot;&gt;
&lt;p&gt;
The &lt;code&gt;play-control&lt;/code&gt; function receives the value and whether the click is double. What should it do? Of course, the first click
starts or stops the clip. But, what happens with doubleclick when value is 0, and what when value is 127?
The first detailed state transition chart was not that trivial. It all depends whether the clip position was 0, maximum value,
or something in between. My idea is to enable rewind, so the main theme is &quot;doubleclick should rewind the clip&quot;. But,
is there a difference whether the clip was stopped or not?
&lt;/p&gt;

&lt;p&gt;
For example, let&apos;s say that the clip was in the middle, and stopped. The first click starts it, and the second is detected
after 300 milliseconds. We can rewind the clip, and it&apos;s logical to me that the clip should stop, instead of instantly
emitting sound. After I analyzed all other situations, it turned out that the simplest logic does quite a logical thing.
&lt;/p&gt;

&lt;p&gt;
I left out the state transition diagram and my analysis on purpose. I hope that this inspire you to
think about &lt;i&gt;your own&lt;/i&gt; applications that use similar controllers. It&apos;s unlikely that you practice guitar at this moment,
and it&apos;s equally unlikely that you have the same foot controller. Or you do! Anyway, here&apos;s very simple logic of
my &lt;code&gt;play-control&lt;/code&gt;:
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-clojure&quot;&gt;&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #A52A2A; font-weight: bold;&quot;&gt;defn&lt;/span&gt; &lt;span style=&quot;color: #00578E; font-weight: bold;&quot;&gt;play-control&lt;/span&gt; &lt;span style=&quot;color: #7388d6;&quot;&gt;[&lt;/span&gt;clip &lt;span style=&quot;color: #2E3436; background-color: #EDEDED;&quot;&gt;^&lt;/span&gt;&lt;span style=&quot;color: #2F8B58; font-weight: bold;&quot;&gt;long&lt;/span&gt; v rewind&lt;span style=&quot;color: #7388d6;&quot;&gt;]&lt;/span&gt;
    &lt;span style=&quot;color: #7388d6;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #A52A2A; font-weight: bold;&quot;&gt;if&lt;/span&gt; &lt;span style=&quot;color: #909183;&quot;&gt;(&lt;/span&gt;&amp;lt; 64 v&lt;span style=&quot;color: #909183;&quot;&gt;)&lt;/span&gt;
      &lt;span style=&quot;color: #909183;&quot;&gt;(&lt;/span&gt;start! clip&lt;span style=&quot;color: #909183;&quot;&gt;)&lt;/span&gt;
      &lt;span style=&quot;color: #909183;&quot;&gt;(&lt;/span&gt;stop! clip&lt;span style=&quot;color: #909183;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #7388d6;&quot;&gt;)&lt;/span&gt;
    &lt;span style=&quot;color: #7388d6;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #A52A2A; font-weight: bold;&quot;&gt;when&lt;/span&gt; &lt;span style=&quot;color: #909183;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #A52A2A; font-weight: bold;&quot;&gt;or&lt;/span&gt; rewind &lt;span style=&quot;color: #709870;&quot;&gt;(&lt;/span&gt;&amp;lt; 0 &lt;span style=&quot;color: #907373;&quot;&gt;(&lt;/span&gt;frame-length clip&lt;span style=&quot;color: #907373;&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: #907373;&quot;&gt;(&lt;/span&gt;+ &lt;span style=&quot;color: #6276ba;&quot;&gt;(&lt;/span&gt;frame-position clip&lt;span style=&quot;color: #6276ba;&quot;&gt;)&lt;/span&gt; 1000000&lt;span style=&quot;color: #907373;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #709870;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #909183;&quot;&gt;)&lt;/span&gt;
      &lt;span style=&quot;color: #909183;&quot;&gt;(&lt;/span&gt;frame-position! clip 0&lt;span style=&quot;color: #909183;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #7388d6;&quot;&gt;)&lt;/span&gt;
  clip&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
Here&apos;s what it does. At the start, the clip is not playing, and the button 80 is either in on (value 127) or off state (value 0),
depending on the state you left it when you used it prior to that. If the button is in on state, the first click stops the clip,
effectively doing nothing that changes what you hear, since the clip was stopped anyway. That was needed because on my controller,
there is a red led light that indicates the on/off state, and I want it to match the playback.
&lt;/p&gt;

&lt;p&gt;
Then, when you press the button again, the clip starts playing. Whenever you press it again, it starts or stops
the playback, matching the red light. But, you might want to rewind it for whatever reason in the middle of the clip.
If the clip was playing, the first click will stop it, and the subsequent (double) click will start it again, and immediately
move its position to the beginning. If the clip was stopped, the first click will start it, but the second will stop it immediately,
and rewind it, so it&apos;s ready to play when you click it the third time. Effectively, if you press the button
twice in a short timeframe in the middle of the clip, it will just continue what it did (play or wait) but from the beginning.
&lt;/p&gt;

&lt;p&gt;
If the clip reaches the end, it will be silent, but the red light will still be bright (there&apos;s no way I know of that
I can direct my controller to change that, as it seems to not listen to MIDI commands). The first
click will issue the stop command, and the second will start the playback. Now, I decided to relax the requirement
for rewind in that case. Even if these two commands were not issued quickly, there&apos;s no reason for the clip
to stay at the end, because there&apos;s no sound there whatever you do, which is not very useful (in this use case).
&lt;/p&gt;

&lt;p&gt;
If the clip somehow ended in end of clip, but stopped state, with the led light off, the first click
will start it, and immediately rewind it to the beginning.
&lt;/p&gt;

&lt;p&gt;
I have also noticed that the clip that is very close to its end, but not exactly there, is a good candidate
for rewinding. So, everything under a second until the end is treated as &quot;rewind whatever happens&quot; (in this use case!).
&lt;/p&gt;

&lt;p&gt;
At the end, the playback logic turned out to be much simpler than I anticipated when I analyzed
all states where clip and the controller (with its red LED light) can be.
It is an easy trap to overcomplicate things and create sophisticated universal solutions. In this case,
even if we had a more high level API, it would need to be configured, and we would miss the special
case when the clip is near the end. Sometimes the humble code is the right stuff. Clojure and simple go well together!
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
</description>
        <pubDate>Sat, 30 Jul 2022 17:45:00 +0200</pubDate>
        <link>http://dragan.rocks/articles/22/Clojure-Sound-5-Double-Click-with-Foot-Control</link>
        <guid isPermaLink="true">http://dragan.rocks/articles/22/Clojure-Sound-5-Double-Click-with-Foot-Control</guid>
        
        
        <category>Clojure,</category>
        
        <category>Clojure</category>
        
        <category>Sound,</category>
        
        <category>Music</category>
        
      </item>
    
      <item>
        <title>Clojure Sound - 4 - Ctrl-Left-Pedal</title>
        <description>&lt;p&gt;
In the last article we managed to connect a MIDI controller and receive
updates whenever something happens to its knobs and buttons. So what?
As it is, nothing. Printing out messages is not of much use, beyond perhaps
getting informed about how these messages look like, and what kind of data they
typically contain. On another thought, exactly &lt;i&gt;that&lt;/i&gt; is often valuable,
because how else can we debug what&apos;s happening and learn how to use
these devices. They typically don&apos;t come with terrific manuals.
&lt;/p&gt;

&lt;p&gt;
Luckily, basic use revolves around receiving one of a few kind of standard
messages, that typically contain only a handful of bytes, more or less conforming
to the MIDI standard, so it&apos;s up to us to assign the meaning according to
our use case. If we care to read the standard, we could try to pick the closest
meaning in our application, but if that&apos;s not possible, or practical, well&amp;#x2026;
you live only once. Let&apos;s celebrate creativity and be silly.
&lt;/p&gt;

&lt;div id=&quot;outline-container-org56a36fb&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;org56a36fb&quot;&gt;What I would like&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-org56a36fb&quot;&gt;
&lt;p&gt;
Cool, so, at first, I have an audio recording of a few chords interposed with some talk and noise,
just a single &lt;code&gt;wav&lt;/code&gt; file. I&apos;d like to discover how to play only selected segments (i.e. the chords I&apos;m interested in guessing),
with arbitrary repetitions. The purpose of this is not to create a perfect looper or learning device, at least not yet.
At first, I&apos;m just interested in creating the crudest audio player, and discovering how to
connect the player to react to the input from the MIDI controller that we connected last week.
&lt;/p&gt;


&lt;div id=&quot;org9cadb83&quot; class=&quot;figure&quot;&gt;
&lt;p&gt;&lt;img src=&quot;../img/clojure-sound/faderfox-mx12.jpg&quot; alt=&quot;faderfox-mx12.jpg&quot; /&gt;
&lt;/p&gt;
&lt;/div&gt;

&lt;p&gt;
After that, it would be nice to see whether the foot pedal works in the same way,
or it needs more poking.
&lt;/p&gt;


&lt;div id=&quot;org7c8a2e7&quot; class=&quot;figure&quot;&gt;
&lt;p&gt;&lt;img src=&quot;../img/clojure-sound/fc_300_angle_gal.jpg&quot; alt=&quot;fc_300_angle_gal.jpg&quot; /&gt;
&lt;/p&gt;
&lt;/div&gt;

&lt;p&gt;
As we discovered last week, the more modern Faderfox MX12 connects through USB and is listed as one of
the connected MIDI devices. The Roland FC-300 foot pedal, does not support USB, so I connect it
via a 5-pin MIDI cable to my USB sound card. It will probably be displayed as a MIDI in/out of
that sound card (more on that later).
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;

&lt;div id=&quot;outline-container-orgc7be1b8&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;orgc7be1b8&quot;&gt;MIDI Controller (hands)&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-orgc7be1b8&quot;&gt;
&lt;p&gt;
The usual imports:
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-clojure&quot;&gt;&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #A52A2A; font-weight: bold;&quot;&gt;ns&lt;/span&gt; &lt;span style=&quot;color: #2F8B58; font-weight: bold;&quot;&gt;my-midi&lt;/span&gt;&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;
&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;require &apos;&lt;span style=&quot;color: #7388d6;&quot;&gt;[&lt;/span&gt;uncomplicate.commons.core &lt;span style=&quot;color: #F5666D;&quot;&gt;:refer&lt;/span&gt; &lt;span style=&quot;color: #909183;&quot;&gt;[&lt;/span&gt;close! info&lt;span style=&quot;color: #909183;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #7388d6;&quot;&gt;]&lt;/span&gt;
         &apos;&lt;span style=&quot;color: #7388d6;&quot;&gt;[&lt;/span&gt;uncomplicate.clojure-sound
           &lt;span style=&quot;color: #909183;&quot;&gt;[&lt;/span&gt;core &lt;span style=&quot;color: #F5666D;&quot;&gt;:refer&lt;/span&gt; &lt;span style=&quot;color: #F5666D;&quot;&gt;:all&lt;/span&gt;&lt;span style=&quot;color: #909183;&quot;&gt;]&lt;/span&gt;
           &lt;span style=&quot;color: #909183;&quot;&gt;[&lt;/span&gt;midi &lt;span style=&quot;color: #F5666D;&quot;&gt;:refer&lt;/span&gt; &lt;span style=&quot;color: #F5666D;&quot;&gt;:all&lt;/span&gt;&lt;span style=&quot;color: #909183;&quot;&gt;]&lt;/span&gt;
           &lt;span style=&quot;color: #909183;&quot;&gt;[&lt;/span&gt;sampled &lt;span style=&quot;color: #F5666D;&quot;&gt;:refer&lt;/span&gt; &lt;span style=&quot;color: #F5666D;&quot;&gt;:all&lt;/span&gt;&lt;span style=&quot;color: #909183;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #7388d6;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
The following code is what we&apos;ve done previously: find out the Fiderfox input device and open it.
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-clojure&quot;&gt;&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;device-info&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;pre class=&quot;example&quot; id=&quot;orge48c433&quot;&gt;
| :description | Software MIDI Synthesizer                    | :name | Gervill             | :vendor | OpenJDK                            | :version | 1.0             |
| :description | Software sequencer                           | :name | Real Time Sequencer | :vendor | Oracle Corporation                 | :version | Version 1.0     |
| :description | Faderfox MX12, USB MIDI, Faderfox MX12       | :name | MX12 [default]      | :vendor | ALSA (http://www.alsa-project.org) | :version | 5.18.10-arch1-1 |
| :description | Faderfox MX12, USB MIDI, Faderfox MX12       | :name | MX12 [hw:0,0,0]     | :vendor | ALSA (http://www.alsa-project.org) | :version | 5.18.10-arch1-1 |
| :description | Scarlett 2i4 USB, USB MIDI, Scarlett 2i4 USB | :name | USB [hw:1,0,0]      | :vendor | ALSA (http://www.alsa-project.org) | :version | 5.18.10-arch1-1 |
| :description | Faderfox MX12, USB MIDI, Faderfox MX12       | :name | MX12 [default]      | :vendor | ALSA (http://www.alsa-project.org) | :version | 5.18.10-arch1-1 |
| :description | Faderfox MX12, USB MIDI, Faderfox MX12       | :name | MX12 [hw:0,0,0]     | :vendor | ALSA (http://www.alsa-project.org) | :version | 5.18.10-arch1-1 |
| :description | Scarlett 2i4 USB, USB MIDI, Scarlett 2i4 USB | :name | USB [hw:1,0,0]      | :vendor | ALSA (http://www.alsa-project.org) | :version | 5.18.10-arch1-1 |
&lt;/pre&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-clojure&quot;&gt;&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #A52A2A; font-weight: bold;&quot;&gt;def&lt;/span&gt; &lt;span style=&quot;color: #0084C8; font-weight: bold;&quot;&gt;mx12&lt;/span&gt; &lt;span style=&quot;color: #7388d6;&quot;&gt;(&lt;/span&gt;map device &lt;span style=&quot;color: #909183;&quot;&gt;(&lt;/span&gt;filter #&lt;span style=&quot;color: #709870;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #2F8B58; font-weight: bold;&quot;&gt;clojure.string&lt;/span&gt;/includes? &lt;span style=&quot;color: #907373;&quot;&gt;(&lt;/span&gt;info &lt;span style=&quot;color: #0084C8; font-weight: bold;&quot;&gt;%&lt;/span&gt; &lt;span style=&quot;color: #F5666D;&quot;&gt;:name&lt;/span&gt;&lt;span style=&quot;color: #907373;&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: #4E9A06;&quot;&gt;&quot;MX12&quot;&lt;/span&gt;&lt;span style=&quot;color: #709870;&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: #709870;&quot;&gt;(&lt;/span&gt;device-info&lt;span style=&quot;color: #709870;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #909183;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #7388d6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;
&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #A52A2A; font-weight: bold;&quot;&gt;def&lt;/span&gt; &lt;span style=&quot;color: #0084C8; font-weight: bold;&quot;&gt;mx12in&lt;/span&gt; &lt;span style=&quot;color: #7388d6;&quot;&gt;(&lt;/span&gt;first &lt;span style=&quot;color: #909183;&quot;&gt;(&lt;/span&gt;filter transmitter? mx12&lt;span style=&quot;color: #909183;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #7388d6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;
&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;open! mx12in&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;pre class=&quot;example&quot; id=&quot;org99ee8f7&quot;&gt;
| {:class &quot;MidiInDevice&quot;, :status :open, :micro-position 464, :description &quot;Faderfox MX12, USB MIDI, Faderfox MX12&quot;, :name &quot;MX12 [default]&quot;, :vendor &quot;ALSA (http://www.alsa-project.org)&quot;, :version &quot;5.18.10-arch1-1&quot;} |
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;

&lt;div id=&quot;outline-container-org97b8d90&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;org97b8d90&quot;&gt;Receiver&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-org97b8d90&quot;&gt;
&lt;p&gt;
Now, we should receive the input from MX12, but instead of printing it out to the REPL,
we would like to control something. The first thing that comes to my mind is to start and stop
the playback. Nothing more. Let&apos;s say that I choose one of the buttons, for example the leftmost
gray one. When it&apos;s pressed, and its led light is on, my sound recording should be playing.
When it&apos;s off, my clip should stop.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;

&lt;div id=&quot;outline-container-orgc54d481&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;orgc54d481&quot;&gt;The Clip&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-orgc54d481&quot;&gt;
&lt;p&gt;
But how do I access the recording at all?
In Clojure Sound, the simplest (and the most straightforward) way of playing a pre-recorded
sound is as a &lt;i&gt;clip&lt;/i&gt;. I can load the actual &lt;code&gt;wav&lt;/code&gt; as a (Java/Clojure) resource, or URL,
or any number of supported methods, create an &lt;code&gt;audio-input-stream&lt;/code&gt;, and then create a &lt;code&gt;clip&lt;/code&gt;
out of it.
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-clojure&quot;&gt;&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #A52A2A; font-weight: bold;&quot;&gt;def&lt;/span&gt; &lt;span style=&quot;color: #0084C8; font-weight: bold;&quot;&gt;ssr&lt;/span&gt; &lt;span style=&quot;color: #7388d6;&quot;&gt;(&lt;/span&gt;audio-input-stream &lt;span style=&quot;color: #909183;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #2F8B58; font-weight: bold;&quot;&gt;clojure.java.io&lt;/span&gt;/resource &lt;span style=&quot;color: #4E9A06;&quot;&gt;&quot;justin/ssr-1.2.wav&quot;&lt;/span&gt;&lt;span style=&quot;color: #909183;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #7388d6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;
&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #A52A2A; font-weight: bold;&quot;&gt;def&lt;/span&gt; &lt;span style=&quot;color: #0084C8; font-weight: bold;&quot;&gt;ssr-clip&lt;/span&gt; &lt;span style=&quot;color: #7388d6;&quot;&gt;(&lt;/span&gt;line &lt;span style=&quot;color: #909183;&quot;&gt;(&lt;/span&gt;line-info &lt;span style=&quot;color: #F5666D;&quot;&gt;:clip&lt;/span&gt; &lt;span style=&quot;color: #709870;&quot;&gt;(&lt;/span&gt;audio-format ssr&lt;span style=&quot;color: #709870;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #909183;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #7388d6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
Now the clip can be manipulated by Clojure Sound functions whose names speak for themselves, such
as &lt;code&gt;open!&lt;/code&gt;, &lt;code&gt;start!&lt;/code&gt;, &lt;code&gt;stop!&lt;/code&gt;, &lt;code&gt;frame-position!&lt;/code&gt;, etc. Let&apos;s try it!
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-clojure&quot;&gt;&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;open! ssr-clip ssr&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;
&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;start! ssr-clip&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;pre class=&quot;example&quot; id=&quot;org1eabcd0&quot;&gt;
| {:class &quot;Clip&quot;, :status :open, :level -1.0, :active false, :running false} |
| {:class &quot;Clip&quot;, :status :open, :level -1.0, :active true, :running true}   |
&lt;/pre&gt;

&lt;p&gt;
The clip that you provided (obviously, different than the one I&apos;m using) should start playing.
We could wait until it reaches the end, or we can stop it at any time.
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-clojure&quot;&gt;&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;stop! ssr-clip&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;pre class=&quot;example&quot; id=&quot;org3d7ff31&quot;&gt;
| :class | Clip | :status | :closed | :level | -1.0 | :active | false | :running | false |
&lt;/pre&gt;

&lt;p&gt;
Note that wen you start it again, it picks up where it stopped, instead of starting all over from the beginning.
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-clojure&quot;&gt;&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;start! ssr-clip&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;pre class=&quot;example&quot; id=&quot;orgbe2d900&quot;&gt;
| :class | Clip | :status | :closed | :level | -1.0 | :active | false | :running | false |
&lt;/pre&gt;

&lt;p&gt;
Should we want it to jump to any position, including the beginning, we can call the &lt;code&gt;frame-position!&lt;/code&gt;, or the =tick-position! function.
The following code rewinds the clip to the very beginning.
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-clojure&quot;&gt;&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;frame-position! ssr-clip 0&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;pre class=&quot;example&quot; id=&quot;org6c07b97&quot;&gt;
| :class | Clip | :status | :open | :level | -1.0 | :active | true | :running | true |
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;

&lt;div id=&quot;outline-container-orgf525606&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;orgf525606&quot;&gt;Receiver, again&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-orgf525606&quot;&gt;
&lt;p&gt;
Now we can return to the receiver function. One thing that comes to my mind is that
I can dedicate a button to toggle between starting and stopping the playback. Let&apos;s say
that I dedicate the first gray button from the left on the MX12 for that task. How do I know
how to access its events? One way is to read that in the documentation, but the problem is
that the documentation is often cryptic or nonexistent. The other is to poke at the device,
and see the event log through the printing function that we&apos;ve already used. That&apos;s how
I&apos;ve discovered that the gray button I&apos;m interested has a &lt;code&gt;:controller&lt;/code&gt; id &lt;code&gt;37&lt;/code&gt;, and sends
&lt;code&gt;:value&lt;/code&gt; 0 for &lt;i&gt;off&lt;/i&gt;, and value 127 for the &lt;i&gt;on&lt;/i&gt; state, in accordance to the MIDI standard.
The on/off state is indicated on the device by a red LED light. A basic receiver would then
just check for controller 37, and &lt;code&gt;start!&lt;/code&gt; or &lt;code&gt;stop!&lt;/code&gt; the clip (&lt;code&gt;line&lt;/code&gt;) that we provide,
depending on its value.
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-clojure&quot;&gt;&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #A52A2A; font-weight: bold;&quot;&gt;defn&lt;/span&gt; &lt;span style=&quot;color: #00578E; font-weight: bold;&quot;&gt;play&lt;/span&gt; &lt;span style=&quot;color: #7388d6;&quot;&gt;[&lt;/span&gt;line&lt;span style=&quot;color: #7388d6;&quot;&gt;]&lt;/span&gt;
  &lt;span style=&quot;color: #7388d6;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #A52A2A; font-weight: bold;&quot;&gt;fn&lt;/span&gt; &lt;span style=&quot;color: #909183;&quot;&gt;[&lt;/span&gt;message _&lt;span style=&quot;color: #909183;&quot;&gt;]&lt;/span&gt;
    &lt;span style=&quot;color: #909183;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #A52A2A; font-weight: bold;&quot;&gt;let&lt;/span&gt; &lt;span style=&quot;color: #709870;&quot;&gt;[&lt;/span&gt;data &lt;span style=&quot;color: #907373;&quot;&gt;(&lt;/span&gt;decode message&lt;span style=&quot;color: #907373;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #709870;&quot;&gt;]&lt;/span&gt;
      &lt;span style=&quot;color: #709870;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #A52A2A; font-weight: bold;&quot;&gt;when&lt;/span&gt; &lt;span style=&quot;color: #907373;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #A52A2A; font-weight: bold;&quot;&gt;and&lt;/span&gt; &lt;span style=&quot;color: #6276ba;&quot;&gt;(&lt;/span&gt;map? data&lt;span style=&quot;color: #6276ba;&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: #6276ba;&quot;&gt;(&lt;/span&gt;= 37 &lt;span style=&quot;color: #858580;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #F5666D;&quot;&gt;:controller&lt;/span&gt; data&lt;span style=&quot;color: #858580;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #6276ba;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #907373;&quot;&gt;)&lt;/span&gt;
        &lt;span style=&quot;color: #907373;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #A52A2A; font-weight: bold;&quot;&gt;if&lt;/span&gt; &lt;span style=&quot;color: #6276ba;&quot;&gt;(&lt;/span&gt;&amp;lt; 64 &lt;span style=&quot;color: #858580;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #F5666D;&quot;&gt;:value&lt;/span&gt; data&lt;span style=&quot;color: #858580;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #6276ba;&quot;&gt;)&lt;/span&gt;
          &lt;span style=&quot;color: #6276ba;&quot;&gt;(&lt;/span&gt;start! line&lt;span style=&quot;color: #6276ba;&quot;&gt;)&lt;/span&gt;
          &lt;span style=&quot;color: #6276ba;&quot;&gt;(&lt;/span&gt;stop! line&lt;span style=&quot;color: #6276ba;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #907373;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #709870;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #909183;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #7388d6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
The &lt;code&gt;play&lt;/code&gt; function assumes that we&apos;re going to receive a Control Change MIDI message,
and expects that the decoded data identifies the controller and value. We will talk
more about different kinds of MIDI messages and how to handle the bytes that they
deliver. Fortunately, Clojure Sound helps with decoding these bytes according to
the message type, but it couldn&apos;t help if we&apos;d asked for nonexistent data in
a wrong format. That&apos;s why &lt;code&gt;play&lt;/code&gt; is not a universal, do-it-all, function.
The programmer (you!) has to put some thinking in designing it to fit the use case.
&lt;/p&gt;

&lt;p&gt;
Now we connect this receiver function to MX12.
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-clojure&quot;&gt;&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;connect! mx12in &lt;span style=&quot;color: #7388d6;&quot;&gt;(&lt;/span&gt;receiver &lt;span style=&quot;color: #909183;&quot;&gt;(&lt;/span&gt;play ssr-clip&lt;span style=&quot;color: #909183;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #7388d6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;pre class=&quot;example&quot; id=&quot;orgfc8a690&quot;&gt;
| :class | MidiInTransmitter | :id | 1772000663 |
&lt;/pre&gt;

&lt;p&gt;
Now I&apos;ll press the button and I expect the clip to start playing&amp;#x2026;.
&lt;/p&gt;

&lt;p&gt;
Yes, I hear the sound. When I press the button again, the sound stops. Press it again, it continues.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;

&lt;div id=&quot;outline-container-orgef35c97&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;orgef35c97&quot;&gt;Controlling playback with Roland FC-300 pedalboard&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-orgef35c97&quot;&gt;
&lt;p&gt;
Now that I&apos;ve connected my clip with my Faderfox MX12, I wonder how difficult it can be to control it with the pedal.
The first challenge is connection: FC-300 does not support USB. Fortunately, my external USB sound card
does have 5-pin MIDI ports, so I connected the pedal through this.
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-clojure&quot;&gt;&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #A52A2A; font-weight: bold;&quot;&gt;def&lt;/span&gt; &lt;span style=&quot;color: #0084C8; font-weight: bold;&quot;&gt;scarlett&lt;/span&gt; &lt;span style=&quot;color: #7388d6;&quot;&gt;(&lt;/span&gt;map device &lt;span style=&quot;color: #909183;&quot;&gt;(&lt;/span&gt;filter #&lt;span style=&quot;color: #709870;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #2F8B58; font-weight: bold;&quot;&gt;clojure.string&lt;/span&gt;/includes? &lt;span style=&quot;color: #907373;&quot;&gt;(&lt;/span&gt;info &lt;span style=&quot;color: #0084C8; font-weight: bold;&quot;&gt;%&lt;/span&gt; &lt;span style=&quot;color: #F5666D;&quot;&gt;:description&lt;/span&gt;&lt;span style=&quot;color: #907373;&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: #4E9A06;&quot;&gt;&quot;Scarlett&quot;&lt;/span&gt;&lt;span style=&quot;color: #709870;&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: #709870;&quot;&gt;(&lt;/span&gt;devi&lt;span style=&quot;color: #ee82ee; background-color: #333333;&quot;&gt;ce-info&lt;/span&gt;&lt;span style=&quot;color: #709870; background-color: #333333;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #909183; background-color: #333333;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #7388d6; background-color: #333333;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #707183; background-color: #333333;&quot;&gt;)&lt;/span&gt;
&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #A52A2A; font-weight: bold;&quot;&gt;def&lt;/span&gt; &lt;span style=&quot;color: #0084C8; font-weight: bold;&quot;&gt;scarlett-in&lt;/span&gt; &lt;span style=&quot;color: #7388d6;&quot;&gt;(&lt;/span&gt;first &lt;span style=&quot;color: #909183;&quot;&gt;(&lt;/span&gt;filter transmitter? scarlett&lt;span style=&quot;color: #909183;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #7388d6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;
&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;open! scarlett-in&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
Now I&apos;m going to press some buttons on the pedal, and spy the output.
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-clojure&quot;&gt;&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;connect! scarlett-in &lt;span style=&quot;color: #7388d6;&quot;&gt;(&lt;/span&gt;receiver &lt;span style=&quot;color: #909183;&quot;&gt;(&lt;/span&gt;partial println &lt;span style=&quot;color: #4E9A06;&quot;&gt;&quot;Hello FC-300&quot;&lt;/span&gt;&lt;span style=&quot;color: #909183;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #7388d6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
The output looks something like this.
&lt;/p&gt;

&lt;pre class=&quot;example&quot; id=&quot;org996d915&quot;&gt;
Hello FC-300 {:channel 14, :command nil, :data nil} 80025801
Hello FC-300 {:channel 14, :command nil, :data nil} 80226589
Hello FC-300 {:channel 14, :command nil, :data nil} 80426603
Hello FC-300 {:channel 0, :command :control-change, :controller 80, :value 127, :control :gp-control-5} 80517901
Hello FC-300 {:channel 14, :command nil, :data nil} 80626739
Hello FC-300 {:channel 14, :command nil, :data nil} 80826209
&lt;/pre&gt;

&lt;p&gt;
Note that there is an empty message at channel 14 every 200 milliseconds regardless
of me pressing any of the buttons. I am not sure why this occurs, nor I found
the explanation in the (70 page long) manual, or on Internet forums.
I suspect it&apos;s some signal for time synchronization, but that&apos;s just me,
an inexperienced MIDI beginner, guessing. On the other hand,
the rest of the output is familiar.
&lt;/p&gt;

&lt;p&gt;
There are two stomps (foot buttons?) dedicated to general purpose control, that fit my need.
As per MIDI standard, they send controller ID 80. I can change that in the pedal
settings to 37, and re-use the same function I&apos;ve used for MX12, but this
is cumbersome, might break what standard programs expect from this pedal,
and 37 was arbitrary in my use case to begin with. I think, in general,
this hardware is rather cumbersome to program, so it might be good idea
to just accept what they send by default, and then do any re-mapping and
re-routing in Clojure-world, where automation is much easier!
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-clojure&quot;&gt;&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #A52A2A; font-weight: bold;&quot;&gt;defn&lt;/span&gt; &lt;span style=&quot;color: #00578E; font-weight: bold;&quot;&gt;pedal-play&lt;/span&gt; &lt;span style=&quot;color: #7388d6;&quot;&gt;[&lt;/span&gt;line&lt;span style=&quot;color: #7388d6;&quot;&gt;]&lt;/span&gt;
  &lt;span style=&quot;color: #7388d6;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #A52A2A; font-weight: bold;&quot;&gt;fn&lt;/span&gt; &lt;span style=&quot;color: #909183;&quot;&gt;[&lt;/span&gt;message _&lt;span style=&quot;color: #909183;&quot;&gt;]&lt;/span&gt;
    &lt;span style=&quot;color: #909183;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #A52A2A; font-weight: bold;&quot;&gt;let&lt;/span&gt; &lt;span style=&quot;color: #709870;&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color: #907373;&quot;&gt;{&lt;/span&gt;controller &lt;span style=&quot;color: #F5666D;&quot;&gt;:controller&lt;/span&gt;
           value &lt;span style=&quot;color: #F5666D;&quot;&gt;:value&lt;/span&gt;&lt;span style=&quot;color: #907373;&quot;&gt;}&lt;/span&gt; &lt;span style=&quot;color: #907373;&quot;&gt;(&lt;/span&gt;decode message&lt;span style=&quot;color: #907373;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #709870;&quot;&gt;]&lt;/span&gt;
      &lt;span style=&quot;color: #709870;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #A52A2A; font-weight: bold;&quot;&gt;case&lt;/span&gt; controller
        80 &lt;span style=&quot;color: #907373;&quot;&gt;(&lt;/span&gt;start! line&lt;span style=&quot;color: #907373;&quot;&gt;)&lt;/span&gt;
        81 &lt;span style=&quot;color: #907373;&quot;&gt;(&lt;/span&gt;stop! line&lt;span style=&quot;color: #907373;&quot;&gt;)&lt;/span&gt;
        &lt;span style=&quot;color: #F5666D;&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;color: #709870;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #909183;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #7388d6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
I varied the setup a bit, and now one button is dedicated for start, and the other to stop command.
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-clojure&quot;&gt;&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;close! scarlett-in&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;
&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;connect! scarlett-in &lt;span style=&quot;color: #7388d6;&quot;&gt;(&lt;/span&gt;receiver &lt;span style=&quot;color: #909183;&quot;&gt;(&lt;/span&gt;pedal-play ssr-clip&lt;span style=&quot;color: #909183;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #7388d6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;
&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;open! scarlett-in&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
Does it work? Yes, it does!
&lt;/p&gt;

&lt;p&gt;
Note that I haven&apos;t used any fancy GUI reactive library. I wanted to show a simple
example. But we can guess that this forest of message codes and filtering can
quickly become unwieldy. Maybe we need a state machine to handle this. Or we
might use some atoms and refs? Or core.async channels? Sure, and you are
free to use any of these in specific use cases. Maybe I&apos;ll discover some
nice patterns that work elegantly. &quot;Hardware&quot; user interface and the
challenges it brings is not &lt;i&gt;that&lt;/i&gt; dissimilar from &lt;i&gt;graphical&lt;/i&gt; user interface.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;

&lt;div id=&quot;outline-container-org76a0261&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;org76a0261&quot;&gt;Two-way communication&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-org76a0261&quot;&gt;
&lt;p&gt;
Regardless of whether I press control buttons on MX12 or FC-300, the clip acts accordingly.
&lt;/p&gt;

&lt;p&gt;
The only glitch in this setup is the LED indication for these buttons: if I change
the state of the clip from one controller, the other is unaware of that change.
For example, if I start the clip from the MX12, its LED will flash, but then when
I stop it from the FC-300, it just keeps flashing. When I press the button 37 on MX12
it initiate stopping, but the clip has already been stopped, so this achieves nothing.
&lt;/p&gt;

&lt;p&gt;
What we really need is a way to notify controller of this change. You might guess
that we should send the same control change message to the controller, and it
will update its hardware. Easy!
&lt;/p&gt;

&lt;p&gt;
However, when I did this, nothing changes. It seems that the controller is built
only to control other things, not to be controlled. I can&apos;t find any reference
in the manuals that would indicate that these two controllers can react to
appropriate messages to do what I need here. Information I&apos;ve found on the
Internet is very obscure, and seems to confirm my suspicions here, for FC-300.
In general, it seems that most MIDI controllers are built to control other things,
not to be updated themselves. When I think about this, it&apos;s expected: if the pedal
is in position X, what is controller to do when I try to update? Turn on a motor
and bring the pedal in the appropriate physical position? I guess that
would be too much trouble for little gain. How much would such pedal cost?
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
</description>
        <pubDate>Wed, 13 Jul 2022 20:45:00 +0200</pubDate>
        <link>http://dragan.rocks/articles/22/Clojure-Sound-4-Ctrl-Left-Pedal</link>
        <guid isPermaLink="true">http://dragan.rocks/articles/22/Clojure-Sound-4-Ctrl-Left-Pedal</guid>
        
        
        <category>Clojure,</category>
        
        <category>Clojure</category>
        
        <category>Sound,</category>
        
        <category>Music</category>
        
      </item>
    
      <item>
        <title>Clojure Sound 3 - Hello MIDI Controller</title>
        <description>&lt;p&gt;
You may not know that music instrument were connected devices even in the Stone Age, that is,
many decades ago. In the 80&apos;s that even resulted in the standard that facilitated connectivity
of heterogeneous devices. Typically, you&apos;d have a keyboard, a synthesizer, some external knobs,
maybe effect boxes, and many of them could be connected by cable and talk to each other, even
though that synth might be 27 years old, and the keyboard 2 years old.
&lt;/p&gt;

&lt;p&gt;
That&apos;s the power of standard. MIDI might not be technically impressive. Especially
for 2022, its transfer rate is unbelievably slow. On the other hand, a random
device that you&apos;d pick up at the store, on a yard sale, e-bay, or even
at the dumpster, is almost guaranteed to have a MIDI connector.
&lt;/p&gt;

&lt;p&gt;
So, even though you&apos;d have a hard time connecting your iPhone with your Linux laptop,
my guitar can talk with my Arch Linux desktop just fine (I&apos;m not kidding, it really does!).
&lt;/p&gt;

&lt;p&gt;
Making that guitar send a meaningful data to my computer is another pair of shoes.
MIDI is very basic, and it&apos;s up to the user program to make sense of the data it receives.
It is likely that you&apos;ll want to use a random exotic device in a very specific way;
after all, music and art are all about originality. But, to walk on the Moon, we first
have to get up from our bed. That&apos;s today&apos;s objective: taking input from a MIDI device,
and controlling something on our computer by twisting knobs.
&lt;/p&gt;

&lt;div id=&quot;outline-container-org60d416b&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;org60d416b&quot;&gt;The software&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-org60d416b&quot;&gt;
&lt;p&gt;
As for the software, we need nothing more than &lt;a href=&quot;https://github.com/uncomplicate/clojure-sound&quot;&gt;Clojure Sound&lt;/a&gt;(&lt;iframe class=&quot;github-btn&quot; src=&quot;https://ghbtns.com/github-btn.html?user=uncomplicate&amp;amp;repo=clojure-sound&amp;amp;type=watch&amp;amp;count=true&quot; width=&quot;100&quot; height=&quot;20&quot; title=&quot;Star on GitHub&quot; frameBorder=&quot;0&quot;&gt;&lt;/iframe&gt;), of course!
&lt;/p&gt;

&lt;p&gt;
You can read how to prepare a fairly basic Clojure project in &lt;a href=&quot;./Maple-Leaf-Rag-Clojure-Sound&quot;&gt;the first article in Clojure Sound tutorial series&lt;/a&gt;.
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-clojure&quot;&gt;&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;require &apos;&lt;span style=&quot;color: #7388d6;&quot;&gt;[&lt;/span&gt;uncomplicate.commons.core &lt;span style=&quot;color: #F5666D;&quot;&gt;:refer&lt;/span&gt; &lt;span style=&quot;color: #909183;&quot;&gt;[&lt;/span&gt;close! info&lt;span style=&quot;color: #909183;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #7388d6;&quot;&gt;]&lt;/span&gt;
         &apos;&lt;span style=&quot;color: #7388d6;&quot;&gt;[&lt;/span&gt;uncomplicate.clojure-sound
           &lt;span style=&quot;color: #909183;&quot;&gt;[&lt;/span&gt;core &lt;span style=&quot;color: #F5666D;&quot;&gt;:refer&lt;/span&gt; &lt;span style=&quot;color: #F5666D;&quot;&gt;:all&lt;/span&gt;&lt;span style=&quot;color: #909183;&quot;&gt;]&lt;/span&gt;
           &lt;span style=&quot;color: #909183;&quot;&gt;[&lt;/span&gt;midi &lt;span style=&quot;color: #F5666D;&quot;&gt;:refer&lt;/span&gt; &lt;span style=&quot;color: #F5666D;&quot;&gt;:all&lt;/span&gt;&lt;span style=&quot;color: #909183;&quot;&gt;]&lt;/span&gt;
           &lt;span style=&quot;color: #909183;&quot;&gt;[&lt;/span&gt;sampled &lt;span style=&quot;color: #F5666D;&quot;&gt;:refer&lt;/span&gt; &lt;span style=&quot;color: #F5666D;&quot;&gt;:all&lt;/span&gt;&lt;span style=&quot;color: #909183;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #7388d6;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;

&lt;div id=&quot;outline-container-orgf9d2623&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;orgf9d2623&quot;&gt;The hardware&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-orgf9d2623&quot;&gt;
&lt;p&gt;
It is unlikely that you&apos;ll have the same controller that I do, but so what? Any MIDI
device that has a button or a knob on it will do!
&lt;/p&gt;

&lt;p&gt;
At this moment, I&apos;m using &lt;a href=&quot;http://www.faderfox.de/mx12.html&quot;&gt;Faderfox MX12&lt;/a&gt;, not because it&apos;s a great device (which it is!),
but because it conveniently sat next to my table. Also, being a newer device, it supports
MIDI-over-USB connectivity (otherwise, I&apos;d have to use an old-school MIDI cable, and plug it into
an external USB sound card that also has a MIDI jack, which I do have, but you likely do not).
&lt;/p&gt;


&lt;div id=&quot;org8a059d4&quot; class=&quot;figure&quot;&gt;
&lt;p&gt;&lt;img src=&quot;../img/clojure-sound/faderfox-mx12.jpg&quot; alt=&quot;faderfox-mx12.jpg&quot; /&gt;
&lt;/p&gt;
&lt;/div&gt;

&lt;p&gt;
If you have any device at home that is remotely related to music, please check it for MIDI support.
If you don&apos;t, and you&apos;ll like to follow along, you may find a cheap old controller, any
working MIDI device will do, as long as you can connect it and as long as it has at least
one area to press or stick to twist!
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;

&lt;div id=&quot;outline-container-org930787c&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;org930787c&quot;&gt;What I would like&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-org930787c&quot;&gt;
&lt;p&gt;
In the past several months, I&apos;ve been learning to play guitar, which includes some basic
of music theory. There is a nice ear training exercise where you listen to a chord (several notes played at the same time)
and try to guess the exact chord that you&apos;ve heard. If you have a training buddy, that is easy:
one of you can play the chord, and the other could try to guess. Most of us do this alone, though.
If I play the chord, I spoil the guessing part, which is the whole point of the exercise.
&lt;/p&gt;

&lt;p&gt;
So, I thought of a solution. What if I could record a bunch of chords, and then somehow randomly
play them? I would like this. There is a challenge, though: to record chords, I&apos;d have to move fingers
away from my guitar, and put them on my keyboard. Then, when guessing, I&apos;d have to press keys for start,
repeat, or end. But ear training likely requires that I actively strum my guitar to help my guessing
by comparing with the recorded sample. That leaves the keyboard out.
&lt;/p&gt;

&lt;p&gt;
Ideally, I&apos;d use a &lt;i&gt;foot&lt;/i&gt; controller, such as this &lt;a href=&quot;https://www.roland.com/global/products/fc-300/&quot;&gt;Roland FC-300&lt;/a&gt; (short of Foot Controller, I suppose with 300 feet :)
&lt;/p&gt;


&lt;div id=&quot;org628abdd&quot; class=&quot;figure&quot;&gt;
&lt;p&gt;&lt;img src=&quot;../img/clojure-sound/fc_300_angle_gal.jpg&quot; alt=&quot;fc_300_angle_gal.jpg&quot; /&gt;
&lt;/p&gt;
&lt;/div&gt;

&lt;p&gt;
I would press one of stomps 1-5 to record 5 different chord examples, and then press
buttons 1 and 2 to play and stop random samples, pressing stomps 2-6 to enter my answers.
The software, Clojure program running in REPL, might display results of my guessing,
or accumulate them for later scoring. There are many possibilities, but the first
step that we need to solve is: how does our program talk with these controllers
in the first place?
&lt;/p&gt;

&lt;p&gt;
Roland FC-300 has an additional obstacle of not supporting USB, so I&apos;d have to
use additional MIDI-to-USB sound card. I&apos;ll leave that for later,
and in this article we will talk to the Faderfox.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;

&lt;div id=&quot;outline-container-org5b9382f&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;org5b9382f&quot;&gt;MIDI device&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-org5b9382f&quot;&gt;
&lt;p&gt;
First, thing, we make sure the device is connected to our computer. Then,
we list all MIDI devices that our computer know of with &lt;code&gt;(device-info)&lt;/code&gt;.
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-clojure&quot;&gt;&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;device-info&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;table border=&quot;2&quot; cellspacing=&quot;0&quot; cellpadding=&quot;6&quot; rules=&quot;groups&quot; frame=&quot;hsides&quot;&gt;


&lt;colgroup&gt;
&lt;col  class=&quot;org-left&quot; /&gt;

&lt;col  class=&quot;org-left&quot; /&gt;

&lt;col  class=&quot;org-left&quot; /&gt;

&lt;col  class=&quot;org-left&quot; /&gt;

&lt;col  class=&quot;org-left&quot; /&gt;

&lt;col  class=&quot;org-left&quot; /&gt;

&lt;col  class=&quot;org-left&quot; /&gt;

&lt;col  class=&quot;org-left&quot; /&gt;
&lt;/colgroup&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td class=&quot;org-left&quot;&gt;:description&lt;/td&gt;
&lt;td class=&quot;org-left&quot;&gt;Software MIDI Synthesizer&lt;/td&gt;
&lt;td class=&quot;org-left&quot;&gt;:name&lt;/td&gt;
&lt;td class=&quot;org-left&quot;&gt;Gervill&lt;/td&gt;
&lt;td class=&quot;org-left&quot;&gt;:vendor&lt;/td&gt;
&lt;td class=&quot;org-left&quot;&gt;OpenJDK&lt;/td&gt;
&lt;td class=&quot;org-left&quot;&gt;:version&lt;/td&gt;
&lt;td class=&quot;org-left&quot;&gt;1.0&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td class=&quot;org-left&quot;&gt;:description&lt;/td&gt;
&lt;td class=&quot;org-left&quot;&gt;Software sequencer&lt;/td&gt;
&lt;td class=&quot;org-left&quot;&gt;:name&lt;/td&gt;
&lt;td class=&quot;org-left&quot;&gt;Real Time Sequencer&lt;/td&gt;
&lt;td class=&quot;org-left&quot;&gt;:vendor&lt;/td&gt;
&lt;td class=&quot;org-left&quot;&gt;Oracle Corporation&lt;/td&gt;
&lt;td class=&quot;org-left&quot;&gt;:version&lt;/td&gt;
&lt;td class=&quot;org-left&quot;&gt;Version 1.0&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td class=&quot;org-left&quot;&gt;:description&lt;/td&gt;
&lt;td class=&quot;org-left&quot;&gt;Scarlett 2i4 USB, USB MIDI, Scarlett 2i4 USB&lt;/td&gt;
&lt;td class=&quot;org-left&quot;&gt;:name&lt;/td&gt;
&lt;td class=&quot;org-left&quot;&gt;USB [hw:2,0,0]&lt;/td&gt;
&lt;td class=&quot;org-left&quot;&gt;:vendor&lt;/td&gt;
&lt;td class=&quot;org-left&quot;&gt;ALSA (&lt;a href=&quot;http://www.alsa-project.org&quot;&gt;http://www.alsa-project.org&lt;/a&gt;)&lt;/td&gt;
&lt;td class=&quot;org-left&quot;&gt;:version&lt;/td&gt;
&lt;td class=&quot;org-left&quot;&gt;5.18.7-arch1-1&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td class=&quot;org-left&quot;&gt;:description&lt;/td&gt;
&lt;td class=&quot;org-left&quot;&gt;Faderfox MX12, USB MIDI, Faderfox MX12&lt;/td&gt;
&lt;td class=&quot;org-left&quot;&gt;:name&lt;/td&gt;
&lt;td class=&quot;org-left&quot;&gt;MX12 [hw:3,0,0]&lt;/td&gt;
&lt;td class=&quot;org-left&quot;&gt;:vendor&lt;/td&gt;
&lt;td class=&quot;org-left&quot;&gt;ALSA (&lt;a href=&quot;http://www.alsa-project.org&quot;&gt;http://www.alsa-project.org&lt;/a&gt;)&lt;/td&gt;
&lt;td class=&quot;org-left&quot;&gt;:version&lt;/td&gt;
&lt;td class=&quot;org-left&quot;&gt;5.18.7-arch1-1&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td class=&quot;org-left&quot;&gt;:description&lt;/td&gt;
&lt;td class=&quot;org-left&quot;&gt;Scarlett 2i4 USB, USB MIDI, Scarlett 2i4 USB&lt;/td&gt;
&lt;td class=&quot;org-left&quot;&gt;:name&lt;/td&gt;
&lt;td class=&quot;org-left&quot;&gt;USB [hw:2,0,0]&lt;/td&gt;
&lt;td class=&quot;org-left&quot;&gt;:vendor&lt;/td&gt;
&lt;td class=&quot;org-left&quot;&gt;ALSA (&lt;a href=&quot;http://www.alsa-project.org&quot;&gt;http://www.alsa-project.org&lt;/a&gt;)&lt;/td&gt;
&lt;td class=&quot;org-left&quot;&gt;:version&lt;/td&gt;
&lt;td class=&quot;org-left&quot;&gt;5.18.7-arch1-1&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td class=&quot;org-left&quot;&gt;:description&lt;/td&gt;
&lt;td class=&quot;org-left&quot;&gt;Faderfox MX12, USB MIDI, Faderfox MX12&lt;/td&gt;
&lt;td class=&quot;org-left&quot;&gt;:name&lt;/td&gt;
&lt;td class=&quot;org-left&quot;&gt;MX12 [hw:3,0,0]&lt;/td&gt;
&lt;td class=&quot;org-left&quot;&gt;:vendor&lt;/td&gt;
&lt;td class=&quot;org-left&quot;&gt;ALSA (&lt;a href=&quot;http://www.alsa-project.org&quot;&gt;http://www.alsa-project.org&lt;/a&gt;)&lt;/td&gt;
&lt;td class=&quot;org-left&quot;&gt;:version&lt;/td&gt;
&lt;td class=&quot;org-left&quot;&gt;5.18.7-arch1-1&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;
We see two devices that we already recognize from earlier articles,
two appearances of my Scarlett 2i4 external audio card,
and two appearance of Faderfox MX12. Why do these appear twice?
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-clojure&quot;&gt;&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #A52A2A; font-weight: bold;&quot;&gt;def&lt;/span&gt; &lt;span style=&quot;color: #0084C8; font-weight: bold;&quot;&gt;mx12&lt;/span&gt; &lt;span style=&quot;color: #7388d6;&quot;&gt;(&lt;/span&gt;map device &lt;span style=&quot;color: #909183;&quot;&gt;(&lt;/span&gt;filter #&lt;span style=&quot;color: #709870;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #2F8B58; font-weight: bold;&quot;&gt;clojure.string&lt;/span&gt;/includes? &lt;span style=&quot;color: #907373;&quot;&gt;(&lt;/span&gt;info &lt;span style=&quot;color: #0084C8; font-weight: bold;&quot;&gt;%&lt;/span&gt; &lt;span style=&quot;color: #F5666D;&quot;&gt;:name&lt;/span&gt;&lt;span style=&quot;color: #907373;&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: #4E9A06;&quot;&gt;&quot;MX12&quot;&lt;/span&gt;&lt;span style=&quot;color: #709870;&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: #709870;&quot;&gt;(&lt;/span&gt;device-info&lt;span style=&quot;color: #709870;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #909183;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #7388d6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;pre class=&quot;example&quot;&gt;
#&apos;user/mx12
&lt;/pre&gt;


&lt;p&gt;
Here&apos;s the first one.
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-clojure&quot;&gt;&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;first mx12&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;table border=&quot;2&quot; cellspacing=&quot;0&quot; cellpadding=&quot;6&quot; rules=&quot;groups&quot; frame=&quot;hsides&quot;&gt;


&lt;colgroup&gt;
&lt;col  class=&quot;org-left&quot; /&gt;

&lt;col  class=&quot;org-left&quot; /&gt;

&lt;col  class=&quot;org-left&quot; /&gt;

&lt;col  class=&quot;org-left&quot; /&gt;

&lt;col  class=&quot;org-left&quot; /&gt;

&lt;col  class=&quot;org-right&quot; /&gt;

&lt;col  class=&quot;org-left&quot; /&gt;

&lt;col  class=&quot;org-left&quot; /&gt;

&lt;col  class=&quot;org-left&quot; /&gt;

&lt;col  class=&quot;org-left&quot; /&gt;

&lt;col  class=&quot;org-left&quot; /&gt;

&lt;col  class=&quot;org-left&quot; /&gt;

&lt;col  class=&quot;org-left&quot; /&gt;

&lt;col  class=&quot;org-left&quot; /&gt;
&lt;/colgroup&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td class=&quot;org-left&quot;&gt;:class&lt;/td&gt;
&lt;td class=&quot;org-left&quot;&gt;MidiOutDevice&lt;/td&gt;
&lt;td class=&quot;org-left&quot;&gt;:status&lt;/td&gt;
&lt;td class=&quot;org-left&quot;&gt;:closed&lt;/td&gt;
&lt;td class=&quot;org-left&quot;&gt;:micro-position&lt;/td&gt;
&lt;td class=&quot;org-right&quot;&gt;-1&lt;/td&gt;
&lt;td class=&quot;org-left&quot;&gt;:description&lt;/td&gt;
&lt;td class=&quot;org-left&quot;&gt;Faderfox MX12, USB MIDI, Faderfox MX12&lt;/td&gt;
&lt;td class=&quot;org-left&quot;&gt;:name&lt;/td&gt;
&lt;td class=&quot;org-left&quot;&gt;MX12 [hw:3,0,0]&lt;/td&gt;
&lt;td class=&quot;org-left&quot;&gt;:vendor&lt;/td&gt;
&lt;td class=&quot;org-left&quot;&gt;ALSA (&lt;a href=&quot;http://www.alsa-project.org&quot;&gt;http://www.alsa-project.org&lt;/a&gt;)&lt;/td&gt;
&lt;td class=&quot;org-left&quot;&gt;:version&lt;/td&gt;
&lt;td class=&quot;org-left&quot;&gt;5.18.7-arch1-1&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;
Note the &lt;code&gt;:class&lt;/code&gt; &lt;code&gt;MidiOutDevice&lt;/code&gt;. This instance can only send MIDI messages from computer to the device.
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-clojure&quot;&gt;&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;second mx12&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;table border=&quot;2&quot; cellspacing=&quot;0&quot; cellpadding=&quot;6&quot; rules=&quot;groups&quot; frame=&quot;hsides&quot;&gt;


&lt;colgroup&gt;
&lt;col  class=&quot;org-left&quot; /&gt;

&lt;col  class=&quot;org-left&quot; /&gt;

&lt;col  class=&quot;org-left&quot; /&gt;

&lt;col  class=&quot;org-left&quot; /&gt;

&lt;col  class=&quot;org-left&quot; /&gt;

&lt;col  class=&quot;org-right&quot; /&gt;

&lt;col  class=&quot;org-left&quot; /&gt;

&lt;col  class=&quot;org-left&quot; /&gt;

&lt;col  class=&quot;org-left&quot; /&gt;

&lt;col  class=&quot;org-left&quot; /&gt;

&lt;col  class=&quot;org-left&quot; /&gt;

&lt;col  class=&quot;org-left&quot; /&gt;

&lt;col  class=&quot;org-left&quot; /&gt;

&lt;col  class=&quot;org-left&quot; /&gt;
&lt;/colgroup&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td class=&quot;org-left&quot;&gt;:class&lt;/td&gt;
&lt;td class=&quot;org-left&quot;&gt;MidiInDevice&lt;/td&gt;
&lt;td class=&quot;org-left&quot;&gt;:status&lt;/td&gt;
&lt;td class=&quot;org-left&quot;&gt;:open&lt;/td&gt;
&lt;td class=&quot;org-left&quot;&gt;:micro-position&lt;/td&gt;
&lt;td class=&quot;org-right&quot;&gt;13220527818&lt;/td&gt;
&lt;td class=&quot;org-left&quot;&gt;:description&lt;/td&gt;
&lt;td class=&quot;org-left&quot;&gt;Faderfox MX12, USB MIDI, Faderfox MX12&lt;/td&gt;
&lt;td class=&quot;org-left&quot;&gt;:name&lt;/td&gt;
&lt;td class=&quot;org-left&quot;&gt;MX12 [hw:3,0,0]&lt;/td&gt;
&lt;td class=&quot;org-left&quot;&gt;:vendor&lt;/td&gt;
&lt;td class=&quot;org-left&quot;&gt;ALSA (&lt;a href=&quot;http://www.alsa-project.org&quot;&gt;http://www.alsa-project.org&lt;/a&gt;)&lt;/td&gt;
&lt;td class=&quot;org-left&quot;&gt;:version&lt;/td&gt;
&lt;td class=&quot;org-left&quot;&gt;5.18.7-arch1-1&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;
The second one is &lt;code&gt;MidiInDevice&lt;/code&gt;, which receives data, but doesn&apos;t know anything about sending.
&lt;/p&gt;

&lt;p&gt;
In this case, the system sees the device through these two lenses. In other cases, one object might
be capable of both sending and receiving, as in the case of the &lt;code&gt;&quot;Real Time Sequencer&quot;&lt;/code&gt;.
&lt;/p&gt;

&lt;p&gt;
But how would our program know this, without us deciphering this from the &lt;code&gt;:class&lt;/code&gt; output?
The program could check for transmitter and receiver capabilities by calling appropriate predicates,
and filter devices that match our requirements. In this case, we&apos;re interested in detecting button
presses and knob turnings from the device, so we are looking for the transmitter.
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-clojure&quot;&gt;&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #A52A2A; font-weight: bold;&quot;&gt;def&lt;/span&gt; &lt;span style=&quot;color: #0084C8; font-weight: bold;&quot;&gt;mx12in&lt;/span&gt; &lt;span style=&quot;color: #7388d6;&quot;&gt;(&lt;/span&gt;first &lt;span style=&quot;color: #909183;&quot;&gt;(&lt;/span&gt;filter transmitter? mx12&lt;span style=&quot;color: #909183;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #7388d6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;pre class=&quot;example&quot;&gt;
#&apos;user/mx12in
&lt;/pre&gt;


&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-clojure&quot;&gt;mx12in
&lt;/pre&gt;
&lt;/div&gt;

&lt;table border=&quot;2&quot; cellspacing=&quot;0&quot; cellpadding=&quot;6&quot; rules=&quot;groups&quot; frame=&quot;hsides&quot;&gt;


&lt;colgroup&gt;
&lt;col  class=&quot;org-left&quot; /&gt;

&lt;col  class=&quot;org-left&quot; /&gt;

&lt;col  class=&quot;org-left&quot; /&gt;

&lt;col  class=&quot;org-left&quot; /&gt;

&lt;col  class=&quot;org-left&quot; /&gt;

&lt;col  class=&quot;org-right&quot; /&gt;

&lt;col  class=&quot;org-left&quot; /&gt;

&lt;col  class=&quot;org-left&quot; /&gt;

&lt;col  class=&quot;org-left&quot; /&gt;

&lt;col  class=&quot;org-left&quot; /&gt;

&lt;col  class=&quot;org-left&quot; /&gt;

&lt;col  class=&quot;org-left&quot; /&gt;

&lt;col  class=&quot;org-left&quot; /&gt;

&lt;col  class=&quot;org-left&quot; /&gt;
&lt;/colgroup&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td class=&quot;org-left&quot;&gt;:class&lt;/td&gt;
&lt;td class=&quot;org-left&quot;&gt;MidiInDevice&lt;/td&gt;
&lt;td class=&quot;org-left&quot;&gt;:status&lt;/td&gt;
&lt;td class=&quot;org-left&quot;&gt;:open&lt;/td&gt;
&lt;td class=&quot;org-left&quot;&gt;:micro-position&lt;/td&gt;
&lt;td class=&quot;org-right&quot;&gt;13220813146&lt;/td&gt;
&lt;td class=&quot;org-left&quot;&gt;:description&lt;/td&gt;
&lt;td class=&quot;org-left&quot;&gt;Faderfox MX12, USB MIDI, Faderfox MX12&lt;/td&gt;
&lt;td class=&quot;org-left&quot;&gt;:name&lt;/td&gt;
&lt;td class=&quot;org-left&quot;&gt;MX12 [hw:3,0,0]&lt;/td&gt;
&lt;td class=&quot;org-left&quot;&gt;:vendor&lt;/td&gt;
&lt;td class=&quot;org-left&quot;&gt;ALSA (&lt;a href=&quot;http://www.alsa-project.org&quot;&gt;http://www.alsa-project.org&lt;/a&gt;)&lt;/td&gt;
&lt;td class=&quot;org-left&quot;&gt;:version&lt;/td&gt;
&lt;td class=&quot;org-left&quot;&gt;5.18.7-arch1-1&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;

&lt;div id=&quot;outline-container-orgd7aa1ef&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;orgd7aa1ef&quot;&gt;Receiver&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-orgd7aa1ef&quot;&gt;
&lt;p&gt;
All right, we have a device object that sends MIDI messages. But how do we access these messages?
We need to implement a receiver to our liking (or use an existing one in unlikely case that someone
already implemented our custom creative requirements; remember, this is music, not accounting).
&lt;/p&gt;

&lt;p&gt;
Usually, it&apos;s a PITA. Clojure Sound makes it easy by:
&lt;/p&gt;
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;Decoding raw byte MIDI data into nice Clojure maps and keywords, and integers, and floats.&lt;/li&gt;
&lt;li&gt;Helping plain functions to listen for MIDI events.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;
We&apos;ll create a trivial listener that just prints the messages to the REPL output,
and connect it to &lt;code&gt;mx12in&lt;/code&gt;. First, we have to &lt;code&gt;open!&lt;/code&gt; the device, or it will refuse connections.
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-clojure&quot;&gt;&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;open! mx12in&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;
&lt;span style=&quot;color: #707183;&quot;&gt;(&lt;/span&gt;connect! mx12in &lt;span style=&quot;color: #7388d6;&quot;&gt;(&lt;/span&gt;receiver &lt;span style=&quot;color: #909183;&quot;&gt;(&lt;/span&gt;partial println &lt;span style=&quot;color: #4E9A06;&quot;&gt;&quot;Hello Faderfox&quot;&lt;/span&gt;&lt;span style=&quot;color: #909183;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #7388d6;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #707183;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;table border=&quot;2&quot; cellspacing=&quot;0&quot; cellpadding=&quot;6&quot; rules=&quot;groups&quot; frame=&quot;hsides&quot;&gt;


&lt;colgroup&gt;
&lt;col  class=&quot;org-left&quot; /&gt;
&lt;/colgroup&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td class=&quot;org-left&quot;&gt;{:class &quot;MidiInDevice&quot;, :status :open, :micro-position 13220961811, :description &quot;Faderfox MX12, USB MIDI, Faderfox MX12&quot;, :name &quot;MX12 [hw:3,0,0]&quot;, :vendor &quot;ALSA (&lt;a href=&quot;http://www.alsa-project.org&quot;&gt;http://www.alsa-project.org&lt;/a&gt;)&quot;, :version &quot;5.18.7-arch1-1&quot;}&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td class=&quot;org-left&quot;&gt;{:class &quot;MidiInTransmitter&quot;, :id 2000879663}&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;
Here&apos;s what I get when I start turning a knob.
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-clojure&quot;&gt;Hello Faderfox &lt;span style=&quot;color: #707183;&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color: #F5666D;&quot;&gt;:channel&lt;/span&gt; 0, &lt;span style=&quot;color: #F5666D;&quot;&gt;:command&lt;/span&gt; &lt;span style=&quot;color: #F5666D;&quot;&gt;:cc&lt;/span&gt;, &lt;span style=&quot;color: #F5666D;&quot;&gt;:controller&lt;/span&gt; 13, &lt;span style=&quot;color: #F5666D;&quot;&gt;:value&lt;/span&gt; 1, &lt;span style=&quot;color: #F5666D;&quot;&gt;:control&lt;/span&gt; &lt;span style=&quot;color: #F5666D;&quot;&gt;:effect-control-2&lt;/span&gt;&lt;span style=&quot;color: #707183;&quot;&gt;}&lt;/span&gt; 1273&lt;span style=&quot;color: #ee82ee; background-color: #333333;&quot;&gt;2693869&lt;/span&gt;
Hello Faderfox &lt;span style=&quot;color: #707183;&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color: #F5666D;&quot;&gt;:channel&lt;/span&gt; 0, &lt;span style=&quot;color: #F5666D;&quot;&gt;:command&lt;/span&gt; &lt;span style=&quot;color: #F5666D;&quot;&gt;:cc&lt;/span&gt;, &lt;span style=&quot;color: #F5666D;&quot;&gt;:controller&lt;/span&gt; 13, &lt;span style=&quot;color: #F5666D;&quot;&gt;:value&lt;/span&gt; 1, &lt;span style=&quot;color: #F5666D;&quot;&gt;:control&lt;/span&gt; &lt;span style=&quot;color: #F5666D;&quot;&gt;:effect-control-2&lt;/span&gt;&lt;span style=&quot;color: #707183;&quot;&gt;}&lt;/span&gt; 1273&lt;span style=&quot;color: #ee82ee; background-color: #333333;&quot;&gt;2693869&lt;/span&gt;
Hello Faderfox &lt;span style=&quot;color: #707183;&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color: #F5666D;&quot;&gt;:channel&lt;/span&gt; 0, &lt;span style=&quot;color: #F5666D;&quot;&gt;:command&lt;/span&gt; &lt;span style=&quot;color: #F5666D;&quot;&gt;:cc&lt;/span&gt;, &lt;span style=&quot;color: #F5666D;&quot;&gt;:controller&lt;/span&gt; 13, &lt;span style=&quot;color: #F5666D;&quot;&gt;:value&lt;/span&gt; 2, &lt;span style=&quot;color: #F5666D;&quot;&gt;:control&lt;/span&gt; &lt;span style=&quot;color: #F5666D;&quot;&gt;:effect-control-2&lt;/span&gt;&lt;span style=&quot;color: #707183;&quot;&gt;}&lt;/span&gt; 1273&lt;span style=&quot;color: #ee82ee; background-color: #333333;&quot;&gt;2704461&lt;/span&gt;
Hello Faderfox &lt;span style=&quot;color: #707183;&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color: #F5666D;&quot;&gt;:channel&lt;/span&gt; 0, &lt;span style=&quot;color: #F5666D;&quot;&gt;:command&lt;/span&gt; &lt;span style=&quot;color: #F5666D;&quot;&gt;:cc&lt;/span&gt;, &lt;span style=&quot;color: #F5666D;&quot;&gt;:controller&lt;/span&gt; 13, &lt;span style=&quot;color: #F5666D;&quot;&gt;:value&lt;/span&gt; 2, &lt;span style=&quot;color: #F5666D;&quot;&gt;:control&lt;/span&gt; &lt;span style=&quot;color: #F5666D;&quot;&gt;:effect-control-2&lt;/span&gt;&lt;span style=&quot;color: #707183;&quot;&gt;}&lt;/span&gt; 1273&lt;span style=&quot;color: #ee82ee; background-color: #333333;&quot;&gt;2704461&lt;/span&gt;
Hello Faderfox &lt;span style=&quot;color: #707183;&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color: #F5666D;&quot;&gt;:channel&lt;/span&gt; 0, &lt;span style=&quot;color: #F5666D;&quot;&gt;:command&lt;/span&gt; &lt;span style=&quot;color: #F5666D;&quot;&gt;:cc&lt;/span&gt;, &lt;span style=&quot;color: #F5666D;&quot;&gt;:controller&lt;/span&gt; 13, &lt;span style=&quot;color: #F5666D;&quot;&gt;:value&lt;/span&gt; 3, &lt;span style=&quot;color: #F5666D;&quot;&gt;:control&lt;/span&gt; &lt;span style=&quot;color: #F5666D;&quot;&gt;:effect-control-2&lt;/span&gt;&lt;span style=&quot;color: #707183;&quot;&gt;}&lt;/span&gt; 1273&lt;span style=&quot;color: #ee82ee; background-color: #333333;&quot;&gt;2718154&lt;/span&gt;
Hello Faderfox &lt;span style=&quot;color: #707183;&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color: #F5666D;&quot;&gt;:channel&lt;/span&gt; 0, &lt;span style=&quot;color: #F5666D;&quot;&gt;:command&lt;/span&gt; &lt;span style=&quot;color: #F5666D;&quot;&gt;:cc&lt;/span&gt;, &lt;span style=&quot;color: #F5666D;&quot;&gt;:controller&lt;/span&gt; 13, &lt;span style=&quot;color: #F5666D;&quot;&gt;:value&lt;/span&gt; 3, &lt;span style=&quot;color: #F5666D;&quot;&gt;:control&lt;/span&gt; &lt;span style=&quot;color: #F5666D;&quot;&gt;:effect-control-2&lt;/span&gt;&lt;span style=&quot;color: #707183;&quot;&gt;}&lt;/span&gt; 1273&lt;span style=&quot;color: #ee82ee; background-color: #333333;&quot;&gt;2718154&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
Nice! My computer understands my controller!
&lt;/p&gt;

&lt;p&gt;
As this article is getting big, and it&apos;s 2 AM, I&apos;ll consider this a milestone, publish it,
play guitar for a short time, and go to sleep. I deserve sleep, too :) In the next article,
we&apos;ll create a more useful receiver that will use the information from these messages
to control these chords I&apos;ve been singing praises for!
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
</description>
        <pubDate>Thu, 30 Jun 2022 23:59:00 +0200</pubDate>
        <link>http://dragan.rocks/articles/22/Clojure-Sound-3-Hello-MIDI-Controller</link>
        <guid isPermaLink="true">http://dragan.rocks/articles/22/Clojure-Sound-3-Hello-MIDI-Controller</guid>
        
        
        <category>Clojure,</category>
        
        <category>Clojure</category>
        
        <category>Sound,</category>
        
        <category>Music</category>
        
      </item>
    
  </channel>
</rss>
