<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Andrey Volodin on Medium]]></title>
        <description><![CDATA[Stories by Andrey Volodin on Medium]]></description>
        <link>https://medium.com/@s1ddok?source=rss-215d6c63b088------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/0*apVD2h9GY62BHEbs.jpg</url>
            <title>Stories by Andrey Volodin on Medium</title>
            <link>https://medium.com/@s1ddok?source=rss-215d6c63b088------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Mon, 13 Jul 2026 20:31:32 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@s1ddok/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com" rel="hub"/>
        <item>
            <title><![CDATA[Control your GPU fan speeds while connecting to your machine via SSH]]></title>
            <link>https://medium.com/@s1ddok/control-your-gpu-fan-speeds-while-connecting-to-your-machine-via-ssh-e01895b8909e?source=rss-215d6c63b088------2</link>
            <guid isPermaLink="false">https://medium.com/p/e01895b8909e</guid>
            <category><![CDATA[nvidia]]></category>
            <category><![CDATA[fan-speed]]></category>
            <category><![CDATA[nvidia-settings]]></category>
            <category><![CDATA[gpu]]></category>
            <category><![CDATA[ssh]]></category>
            <dc:creator><![CDATA[Andrey Volodin]]></dc:creator>
            <pubDate>Fri, 14 Oct 2022 17:30:10 GMT</pubDate>
            <atom:updated>2022-10-14T17:30:10.456Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*V7VEID217ucUqjKLIOLvvA.png" /><figcaption>Example of thermals of EVGA 3090 using fixed fan speed of 90%</figcaption></figure><p>While I’m not able to live in my house that is located in country that started a war, I still need to do neural net training and cloud GPUs are not something I can afford right now.</p><p>Normally, I like to ramp up my fans in my workstation so that cards don’t overheat during multiple day training sessions. I used to be using <strong>GUI</strong> apps that <strong>NVIDIA</strong> ships, but now I can only access my PC via <strong>SSH</strong> connection.</p><p><strong>NVIDIA</strong> has nvidia-settings console app which technically allows you to set any <strong>GPU</strong> settings using terminal. I started googling on how to set the fan speed for individual <strong>GPU</strong> using that.</p><p>First of all, you have to set a bitmask that will allow controlling cooling settings:</p><pre>sudo nvidia-xconfig --cool-bits=28</pre><p>Then, what most forum answers on the web suggest, you should use this command:</p><pre>sudo nvidia-settings -a &quot;[gpu:0]/GPUFanControlState=1&quot; \<br>-a &quot;[fan:0]/GPUTargetFanSpeed=90&quot;</pre><p>Which is pretty self-explanatory. First argument <strong>enables controlling fans</strong> in the first <strong>GPU</strong>, second one assigns <strong>target fan speed</strong> in percentage (0–100) for the first fan.</p><blockquote><strong>Note: </strong>Fans are enumareted continously across all GPUs, i.e. I have 2 fans on each GPU and in order to control first fan on second GPU I have to use <strong>fan:2</strong></blockquote><p>However, after running this command through you’ll likely see this:</p><pre>Unable to init server: Could not connect: Connection refused</pre><pre>ERROR: The control display is undefined; please run `nvidia-settings --help` for usage information.</pre><p>What this means is that apparently nvidia-settings cannot connect to the running <strong>X</strong> server. In fact it was built so that you can interact with your <strong>GPU</strong> only if you have a graphics interface operational!</p><p>I had spent quite some time coming up with creative google prompts to find something that is addressing this on the web but failed to. <a href="https://thebravestatistician.wordpress.com/2017/08/13/tweaking-your-nvidia-gpu-via-ssh-using-nvidia-settings/">This article</a> brings us closer to solution, but still doesn’t do the trick. Fortunately, I was able to solve this puzzle using a combination of facts that I was able to collect.</p><p>Our goal is to trick nvidia-settings app into thinking that it is being used under a <strong>GUI</strong> session on a display. We need to define two variable for this purpose: DISPLAY and XAUTHORITY.</p><p>First one is easy, we can simply assign to random “first” display, like this:</p><pre>export DISPLAY=:0</pre><p>The article I mentioned also suggests a value for XAUTHORITY but unfortunately <strong>it didn’t work for me and likely won’t work for you</strong>, because every system has it’s own authority for X server, that is also depends on OS you running and other factors. In order to find a correct value for this you should run this command:</p><pre>ps a | grep X</pre><p>The command filters out all processed that has a mention of <strong>X</strong> server. On my machine I get this output:</p><pre>3067 tty1     Sl+    0:01 /usr/lib/xorg/Xorg vt1 -displayfd 3 -auth /run/user/121/gdm/Xauthority -background none -noreset -keeptty -verbose 3<br> 5121 pts/0    S+     0:00 grep --color=auto --exclude-dir=.bzr --exclude-dir=CVS --exclude-dir=.git --exclude-dir=.hg --exclude-dir=.svn --exclude-dir=.idea --exclude-dir=.tox</pre><p>The part that we are interested in is -auth /run/user/121/gdm/Xauthority. Copy the value of -auth argument and use it to define XAUTHORITY bash variable, like so:</p><pre>export XAUTHORITY=/run/user/121/gdm/Xauthority</pre><p>Then we can try assigning settings again:</p><pre>sudo nvidia-settings -a “[gpu:1]/GPUFanControlState=1”</pre><p>And now we can see desired output:</p><pre>Attribute &#39;GPUFanControlState&#39; (server:0[gpu:1]) assigned value 1.</pre><p>Using this approach you setup any options of nvidia-settings, you can examine the whole list by running:</p><pre>sudo nvidia-settings -q all</pre><p>I hope this article will help to avoid headache for those who use their workstation over SSH.</p><p>Peace ✌️</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=e01895b8909e" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[One weird trick for Development Pod type of experience using Swift Package Manager and Xcode 12]]></title>
            <link>https://medium.com/@s1ddok/one-weird-trick-for-development-pod-type-of-experience-using-swift-package-manager-and-xcode-12-4de02d881ec1?source=rss-215d6c63b088------2</link>
            <guid isPermaLink="false">https://medium.com/p/4de02d881ec1</guid>
            <category><![CDATA[ios]]></category>
            <category><![CDATA[cocoapods]]></category>
            <category><![CDATA[swift-package-manager]]></category>
            <category><![CDATA[swift]]></category>
            <category><![CDATA[xcode]]></category>
            <dc:creator><![CDATA[Andrey Volodin]]></dc:creator>
            <pubDate>Sat, 08 Aug 2020 16:22:09 GMT</pubDate>
            <atom:updated>2020-08-08T19:41:19.817Z</atom:updated>
            <content:encoded><![CDATA[<p><strong>CocoaPods</strong> served us very well for long years. It is an absolutely great package manager that is both convenient and robust enough to support very complex build pipelines that go well beyond regular <strong>iOS/macOS/tvOS</strong> development (like <strong>OpenCV2</strong> <em>C++ library</em>, etc). It is so robust that it took <strong>Swift Package Manager</strong> more than 3 years to fill the gap between the two. Finally, with<strong> Xcode 12</strong> and <strong>Swift 5.3</strong> toolchain we are receiving long-awaited support for resources, binary packages and robust build settings for <strong>SwiftPM</strong>. Those additions are going to become major enablers for folks to convert their <strong>Pods</strong> into <strong>Packages</strong>.</p><h4>Why you should convert your Pods into Packages</h4><p><strong>SwiftPM</strong> is also going to bring a lot of neat things like <strong>static linkage</strong> by default and <strong>dedicated bundles</strong> for framework resources, so one should definitely consider migrating from <strong>CocoaPods</strong> to <strong>SwiftPM</strong> as it can make your app <em>faster, smaller</em> and also provide some <em>nice code-generated things</em> in your code, like Bundle.module. Conversion process is pretty straightforward for 99% of frameworks out there. Plus, there are plenty of articles on the web right now explaining how to achieve that in under 15 mins.</p><h4>Development Pods experience</h4><p>However, there is one feature that was <em>particularly great</em> in <strong>CocoaPods</strong>. They call it <strong>Development Pods</strong>. Essentially, they allow you to<em> work on your frameworks simultaneously to the client side</em>, iterating very quickly, being able to check your framework changes against client integration. This feature was not only <em>very powerful</em>, but also <em>very easy to use</em>. In order to achieve that you simple have to provide a path to a local copy of your <strong>Pods</strong> and reinstall pods. Dead easy.</p><pre>pod ‘Grain’, :path =&gt; ‘../Grain’</pre><p>This feature is so great it has literally been enabling me to actually work as a developer for all those years I’ve been using <strong>CocoaPods</strong>, especially given that I work on a <em>highly modular </em>engine that is spread across tens of frameworks.</p><h4>Editing Packages from CLI</h4><p>SwiftPM has a pretty convenient interface for package editing in its CLI. What you have to do is to run a single command inside your project:</p><pre>swift package edit &lt;package name&gt; --path &lt;path/to/dependency&gt; </pre><p>A checkout of &lt;package name&gt; will be created if it doesn&#39;t exist at the given path. If a checkout exists, package manager will validate the package name at the given path and attach to it. The package manager will also create a symlink in the Packages/ directory to the checkout path.</p><h4>Using Swift Package Manager for framework development with Xcode</h4><p>In the early days of <strong>SwiftPM</strong> it was really tricky to achieve simultaneous development. It was possible, but it wasn’t something you’d want to call a good development experience. <strong>CocoaPods</strong> were way cooler.</p><p>The problem became even bigger when <strong>Xcode</strong> introduced native support for <strong>Swift Packages</strong>. While it was possible to use local URLs pointing to <strong>Packages</strong> stored in your local file system, it still required way more clicks and things to do to simply convert a framework into a development mode, hack on it and see how it affects a client app.</p><p>It’s been my go-to solution for those rare <strong>SwiftPM</strong> projects I’ve been working on. Things changes when I discovered that <strong>Xcode</strong> can actually provide very similar experience to what you used to have with <strong>Development Pods</strong>. It is kinda weird that this feature <em>isn’t really exposed into any visible UI</em>, or at least I couldn’t discover it anywhere.</p><h4>The solution</h4><p>So let’s imagine you have set up a <strong>Xcode</strong> project with some <strong>Packages</strong> from <strong>GitHub</strong>. In my case it will be a single library for <strong>Metal</strong> development, <a href="https://github.com/s1ddok/Alloy"><strong>Alloy</strong></a>, that I recently converted from <strong>Pod</strong> to a <strong>Package</strong>. The setup looks very simply:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*MmaUJggiFqokWX5-Y3Srbw.png" /><figcaption>Initial project setup with a remote Swift Package</figcaption></figure><blockquote><strong>Note</strong>: from what I understand, it is important to start with a remote package setup, otherwise local development may not work for you.</blockquote><p>So imagine you now want to change few things inside a library while continuing working on a hosting application. All you need to do is… drag and drop a folder with a local copy of your library into the project, like this:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/800/1*jvNe_PeVEs2WeP_9uj_U0w.gif" /></figure><p>That’s it! This local copy of your framework will now “override” the one that was connected via remote <strong>URL</strong>. You can now change your framework in whatever way you like and immediately observe the result.</p><h4>Going back to remote</h4><p>Once you’ve finished your work on a local copy and pushed your changes into a remote, you can go back to using a published version of your framework. In case of a <strong>CLI</strong> you have to call a single command, unedit:</p><pre>swift package unedit &lt;package name&gt;</pre><p>If you are using <strong>Xcode</strong> it is sufficient to simply remove that package you’ve dragged and <strong>Xcode</strong> automatically resolve the remote one without any effort from your side.</p><h4>Final words</h4><p>SwiftPM is really great for Swift community and Swift apps, but it also very important for it to provide convenient experience for developers to be able to use to it’s fullest. Hope it was helpful! Hit me up <a href="https://twitter.com/s1ddok">on twitter</a> in case you have any questions, I will be happy to answer!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=4de02d881ec1" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Automated CocoaPod releases with GitHub Actions]]></title>
            <link>https://medium.com/swlh/automated-cocoapod-releases-with-github-actions-8526dd4535c7?source=rss-215d6c63b088------2</link>
            <guid isPermaLink="false">https://medium.com/p/8526dd4535c7</guid>
            <category><![CDATA[ios]]></category>
            <category><![CDATA[swift]]></category>
            <category><![CDATA[github]]></category>
            <category><![CDATA[github-actions]]></category>
            <category><![CDATA[cocoapods]]></category>
            <dc:creator><![CDATA[Andrey Volodin]]></dc:creator>
            <pubDate>Tue, 10 Sep 2019 12:44:17 GMT</pubDate>
            <atom:updated>2019-09-11T06:42:24.277Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*aJtYGDQ_vpSOIYQP0bnFwA.png" /></figure><p>In this article we are going to quickly cover a trivial GitHub Actions setup I use for my open source Metal library <a href="https://github.com/s1ddok/Alloy">Alloy</a> to automatically publish new versions into CocoaPods trunk register.</p><p>First, we will need to grab a registration token from CocoaPods. You can get it by using the pod trunk register command.</p><pre>pod trunk register your@email.com -- description &quot;GitHub Actions Token&quot;</pre><p>You will receive an e-mail with a confirmation link to confirm you are the owner of that e-mail. Once you’ve confirmed the token you can obtain it from private files using the following command:</p><pre>grep -A2 &#39;trunk.cocoapods.org&#39; ~/.netrc</pre><p>You will see something like this:</p><pre>machine trunk.cocoapods.org<br> login &lt;<a href="mailto:siddok@gmail.com">y</a>our@email.com&gt;<br> password &lt;TOKEN&gt;</pre><p>Copy the token you’ve got and then go to <strong>Settings </strong>of your repo:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*6DB6QLJaf-vCVX-2IZEC8A.png" /></figure><p>Next, open <strong>Secrets</strong> in the side menu:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/500/1*yr-kVdrqEG-c4WWiDeHJbg.png" /></figure><p>Press <strong>“Add a new secret”</strong> and create a new secret named <strong>COCOAPODS_TRUNK_TOKEN</strong> with the value of token you’ve just copied.</p><h3>Setting up a GitHub Action</h3><p>Okay, once you’ve done with the CocoaPods you are ready to proceed onto writing your first GitHub Action. Go to <strong>Actions</strong> of your repo and press “<strong>Set up a workflow yourself</strong>”:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*1ph-2rRmiWpmnOa5_dfoaA.png" /></figure><p>And then replace the script with the following:</p><pre>name: CI</pre><pre>on:<br>  push:<br>    branches:<br>    - master<br>    <br>jobs:<br>  build:</pre><pre>  runs-on: macOS-latest<br>    <br>    steps:<br>    - uses: actions/checkout@v1<br>    - name: Publish to CocoaPod register<br>      env:<br>        COCOAPODS_TRUNK_TOKEN: ${{ secrets.COCOAPODS_TRUNK_TOKEN }}<br>      run: |<br>        pod trunk push &lt;YOURLIBRARY&gt;.podspec</pre><p>What this means is pretty clear:</p><ol><li>Our script will run on every <strong>push</strong> into <strong>master</strong> branch of a repo</li><li>We will have only one build job which will run on<strong> latest macOS</strong> (you can specify <strong>macOS-10.14</strong> for example</li><li>At first we will checkout our repo using another built-in action called <strong>actions/checkout@v1</strong></li><li>We are declaring a <strong>COCOAPODS_TRUNK_TOKEN</strong> that is initialized with a secret value that we specified earlier so that nobody can access publishing even though your library and actions may be open-sourced</li><li>Finally, we call our command to push library into CocoaPods register</li></ol><p>I use this 3 steps process to publish my libs:</p><ol><li>Create a tag in the branch you are going to merge</li><li>Bump a version number inside a podspec to match the latest tag you’ve created</li><li>Merge branch into master and action will be triggered</li></ol><h3>Final words</h3><p>We’ve just created a minimal example on how to automatically publish your libraries safely and securely. Of course you shouldn’t stop there: you can add automatic unit-test launches or more complex release pipelines into that.</p><p>If you have any questions please hit me up <a href="https://twitter.com/s1ddok">on Twitter</a>.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=8526dd4535c7" width="1" height="1" alt=""><hr><p><a href="https://medium.com/swlh/automated-cocoapod-releases-with-github-actions-8526dd4535c7">Automated CocoaPod releases with GitHub Actions</a> was originally published in <a href="https://medium.com/swlh">The Startup</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Combine the power of CoreGraphics and Metal by sharing resource memory]]></title>
            <link>https://medium.com/@s1ddok/combine-the-power-of-coregraphics-and-metal-by-sharing-resource-memory-eabb4c1be615?source=rss-215d6c63b088------2</link>
            <guid isPermaLink="false">https://medium.com/p/eabb4c1be615</guid>
            <category><![CDATA[coregraphics]]></category>
            <category><![CDATA[ios]]></category>
            <category><![CDATA[metal]]></category>
            <category><![CDATA[macos]]></category>
            <category><![CDATA[swift]]></category>
            <dc:creator><![CDATA[Andrey Volodin]]></dc:creator>
            <pubDate>Tue, 05 Mar 2019 13:47:29 GMT</pubDate>
            <atom:updated>2019-03-05T13:47:29.468Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*iirY4e44BOUcIQckRDKsIg.png" /></figure><p><strong>Metal API </strong>is great, it opens up a whole lot of possibilities on both mobile and desktop devices. However, <strong>GPUs</strong> can be sometimes a bit clumsy, especially in high-precision things like <em>font rendering or curve drawing</em>, so sometimes you really miss good old <strong>CPU</strong> things. It happens to me pretty often that I would love to use some tiny bits of <strong>CoreGraphics</strong> functionality, but keep my <strong>GPU</strong> pipelines fast and efficient, with absence of <em>redundant conversions</em> or <em>CPU/GPU synchronization breaks</em>.</p><p>The case that inspired me to write this article was to give users the ability to draw a mask overlay in order to identify zones where they want certain effects to appear. It is of course possible to implement drawing with <strong>Metal</strong>, but that will require a lot of work: keeping a path data, triangulation and rendering logic. For quick prototype it is much easier to just use <strong>CoreGraphics</strong>, however the most straightforward approach is to create a <strong>CGImage</strong> from <strong>UI canvas </strong>and then convert to a <strong>MTLTexture</strong> to feed it as a mask to some shaders.</p><h3>Interdimensional portal</h3><p>But what if we would love to avoid unnecessary conversions and draw <strong>CoreGraphics</strong> paths straight into <strong>MTLTexture</strong>? That’s appears to be totally possible!</p><p>In order to achieve that we have to share a memory buffer between some <strong>CGContext</strong> and <strong>MTLTexture</strong>. Metal has a possibility to create textures from <strong>MTLBuffer</strong> objects, and <strong>MTLBuffer</strong> in turn has an opportunity to point into already allocated memory.</p><p>So what we need to do is the following:</p><ol><li>Allocate memory for <strong>CGContext</strong></li><li>Create <strong>MTLBuffer</strong> pointing to the same memory</li><li>Create <strong>MTLTexture</strong> out of <strong>MTLBuffer</strong></li><li>Voila!</li></ol><h3>The implementation</h3><blockquote><strong>Disclaimer #1:</strong> In this demo I use <a href="https://github.com/s1ddok/Alloy"><strong>Alloy</strong></a>, this is a <strong>Metal</strong> library that I use in all of my <strong>GPU</strong> projects on Apple platforms. It provides <strong>a very tiny, Swifty API</strong> over vanilla <strong>Metal</strong></blockquote><blockquote><strong>Disclaimer #2:</strong> I neither do any decomposition in the demo nor error handling. <strong>Everything is done in a view controller, force-unwrapped or fatal-errored.</strong> This article serves as a reference snippet.</blockquote><p>Things are a bit tricky when it comes to allocating no-copy memory for <strong>MTLBuffer</strong>. To make it happy, it has to be <em>perfectly aligned</em>, usually to <strong>4096</strong> bytes. <strong>MTLTextures</strong> are also acting fussy when it comes to what <strong>MTLBuffer</strong> it can be created from: we have to <em>align each texture row </em>and the alignment is <em>dependent on the pixel format</em> we want to use. Luckily, both of these tasks are doable!</p><blockquote>For the sake of the demo we will allocate a shared resource for a drawable single-channel mask over <strong>MTKView</strong>.</blockquote><p>Every time our <strong>MTKView</strong> will change its size, we will reallocate the mask. It is of course not necessary, but it is the simplest approach.</p><p>First, we will need to know a RAM page size from the system, for this reason we will use <strong>getpagesize()</strong> function. Now we have to calculate amount of aligned bytes per row and the total allocation size. To allocate aligned memory we will use <strong>posix_memalign(_,_,_)</strong> system function.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/20efd9d871c41b70bc56fed887d3e1a5/href">https://medium.com/media/20efd9d871c41b70bc56fed887d3e1a5/href</a></iframe><blockquote>Note that from this point we are responsible for deallocating this memory, however we will handle it a bit later</blockquote><p>Now we are ready to create a <strong>CGContext</strong> from this memory, you probably have done this many times, so this should be pretty straightforward:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/cd1e72587d566d5a19baf94235e016c5/href">https://medium.com/media/cd1e72587d566d5a19baf94235e016c5/href</a></iframe><blockquote>I use <strong>CGImageAlphaInfo.none</strong> here to indicate that this is a grayscale image, but you can also use <strong>.alphaOnly</strong></blockquote><p>Using the exact same memory we can now create a no-copy <strong>MTLBuffer</strong>, making it responsible for deallocating the memory. However you can of course manage this on your own by passing <strong>nil</strong> to the last argument.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/062644551686742904e4734c4c174f6f/href">https://medium.com/media/062644551686742904e4734c4c174f6f/href</a></iframe><p>Now, the final step: we are creating a texture from this buffer. <strong>Storage mode</strong> of the texture must be the same with the buffer. There are additional requirements for different platform/OS that you can read <a href="https://developer.apple.com/documentation/metal/mtlbuffer/1613852-maketexture">here</a>.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/2f474a3987dda3637d9cd7eb59d3af76/href">https://medium.com/media/2f474a3987dda3637d9cd7eb59d3af76/href</a></iframe><p>Since we’ve initially allocated memory in a format that Metal should be happy with, everything should go just fine.</p><h3>Demo</h3><p>Okay, now we are all set! After caching <strong>CGContext</strong> and <strong>MTLTexture</strong> somewhere, you can do whatever you want with them.</p><p>We will create a simple app, that will allow you “scratch” over a blurred texture, the final result can be seen in the video:</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2Ffl-d978Do4A%3Ffeature%3Doembed&amp;url=http%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3Dfl-d978Do4A&amp;image=https%3A%2F%2Fi.ytimg.com%2Fvi%2Ffl-d978Do4A%2Fhqdefault.jpg&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=youtube" width="640" height="480" frameborder="0" scrolling="no"><a href="https://medium.com/media/52284c74fd776f4a6c620512af1d134e/href">https://medium.com/media/52284c74fd776f4a6c620512af1d134e/href</a></iframe><p>Let’s start with finding <strong>a cute puppy image</strong>, loading it into a <strong>MTLTexture</strong> and then blurring using <strong>Metal Performance Shaders</strong>.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/a3509d1b2e300a625c345a3b7cdaf1c5/href">https://medium.com/media/a3509d1b2e300a625c345a3b7cdaf1c5/href</a></iframe><p>Simple <strong>Metal fragment shader</strong> will handle the blending of original, overlay and mask textures:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/3f631229ca10323ba223e72551e342d4/href">https://medium.com/media/3f631229ca10323ba223e72551e342d4/href</a></iframe><p>Then we just need to dispatch it whenever a <strong>MTKView</strong> wants to redraw itself.</p><blockquote>You should take into account the memory synchronization that happens between <strong>CPU</strong> and <strong>GPU</strong>. You should not create a situation where this buffer can be simultaneously accessed by <strong>CoreGraphics</strong> and <strong>Metal</strong>, especially on <strong>macOS</strong>.</blockquote><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/3baf1518985e4f55426027ba5d222ae2/href">https://medium.com/media/3baf1518985e4f55426027ba5d222ae2/href</a></iframe><blockquote>To prevent this article from bloating, I purposefully didn’t include <strong>render pipeline state creation snippets</strong>,<strong> vertex shaders</strong> and <strong>CoreGraphics</strong> drawing code using <strong>UIKit</strong> touch APIs, you can find the full <a href="https://github.com/s1ddok/MetalCoreGraphics">source code here</a>.</blockquote><h3>Conclusion</h3><p>Mixing <strong>CoreGraphics</strong> and <strong>Metal</strong> can be really useful and can work both ways: draw text from <strong>CoreText</strong> to <strong>Metal</strong> or render 3d mesh into <strong>CGContext</strong> and process it somehow on <strong>CPU</strong>. The rest is your imagination!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=eabb4c1be615" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Using first-class type objects to create UITableViews with multiple cell types]]></title>
            <link>https://medium.com/@s1ddok/using-first-class-type-objects-to-create-uitableviews-with-multiple-cell-types-d3a7e646df53?source=rss-215d6c63b088------2</link>
            <guid isPermaLink="false">https://medium.com/p/d3a7e646df53</guid>
            <category><![CDATA[uitableview]]></category>
            <category><![CDATA[swift]]></category>
            <category><![CDATA[ios]]></category>
            <category><![CDATA[uitableviewcell]]></category>
            <category><![CDATA[uikit]]></category>
            <dc:creator><![CDATA[Andrey Volodin]]></dc:creator>
            <pubDate>Tue, 29 May 2018 12:31:49 GMT</pubDate>
            <atom:updated>2018-05-29T12:39:21.362Z</atom:updated>
            <content:encoded><![CDATA[<h3>Problem</h3><p>When you work for AI company, you always do a lot of technical demos to play with a certain technology in the wild. Modern algorithms tend to have quite a lot of parameters you would want to experiment with and sometimes the result of the work can only be approved by human, especially when it is related to any kind of image processing/computer vision or AR/ML type of apps, where you have to check results with your eyes.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/756/1*CKRqe1PT050YVssUBNSKDw.png" /></figure><p>This often leads to the situation where you have to create a bunch of on-screen buttons/sliders so that you can parameterize core logic and see how new hyper-parameters affects the result. After a handful of such demos I decided to create a custom debug menu, where you can add several options in a declarative way and then observe changes.</p><p>I made a prototype in a day by forking an existing debug tool <strong>Dotzu. </strong>Project is still in a beginning stage, but it more or less fits my needs for now. You can play with it in a <a href="https://github.com/s1ddok/DebugMenu">public repo</a>. Below is the small demo of achieved results:</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2FiHlwJS2AAxY%3Ffeature%3Doembed&amp;url=http%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DiHlwJS2AAxY&amp;image=https%3A%2F%2Fi.ytimg.com%2Fvi%2FiHlwJS2AAxY%2Fhqdefault.jpg&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=youtube" width="640" height="480" frameborder="0" scrolling="no"><a href="https://medium.com/media/48431b14ac5fd90425d209f14355460a/href">https://medium.com/media/48431b14ac5fd90425d209f14355460a/href</a></iframe><h3>Implementation</h3><p>In this small tutorial I’m going to show you a technique which I used to achieve dynamic cell type evaluation in a single <strong>UITableView</strong>. What I wanted to achieve is that I could create an array of <strong>Option </strong>objects all of which conforms to a single protocol. This array basically will be an array of <strong>models</strong>. Then I want my make my table view <strong>controller</strong> to understand what type of cell (<strong>view</strong>) it has to use for it representation. I also wanted to avoid using <strong>enum</strong>s, <strong>switch</strong>, or <strong>long conditional chaining </strong>(if-else), so that it will be extensible from outside and adding new type of options wouldn’t require rewriting existing library/controller code. Another goal is to encapsulate configuration code for every cell inside its class definition to move it outside of controller.</p><p>I started with declaring a protocol for our options. Since it is a 1-day prototype I didn’t put too much of a thought into this protocol, since I’m not quite sure about whole design, but for now let’s require every option to have a name. It also should probably have an <strong>associatedtype</strong>, but let’s keep it simple for now.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/82173f4308bd072471e07e4626ee41b3/href">https://medium.com/media/82173f4308bd072471e07e4626ee41b3/href</a></iframe><p>Next, let’s declare a protocol for cells that can represent an option: <strong>OptionCell</strong>. It also a dead-easy protocol which basically requires an object to know how to configure itself for an option.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/71411f8f75416bd11c6093bfe3c92a0b/href">https://medium.com/media/71411f8f75416bd11c6093bfe3c92a0b/href</a></iframe><p>Alright, as we now have all needed protocols, let’s create first option type and corresponding cell view. We will start with <strong>BoolOption</strong> which is often used for <strong>feature-toggling</strong>.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/26d5e4027bc6b937670ba76ecfadeb91/href">https://medium.com/media/26d5e4027bc6b937670ba76ecfadeb91/href</a></iframe><figure><img alt="" src="https://cdn-images-1.medium.com/max/988/1*c6CPseruzyGu2LKuNfLx1Q.png" /><figcaption>BoolOptionCell.xib</figcaption></figure><p>Now, the interesting part. We create a <strong>UITableViewController</strong> subclass with no cell prototype in its storyboard:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/544/1*a0UWdHrb-AbYGQBWJ71wVA.png" /><figcaption>UserOptions.storyboard</figcaption></figure><p>All the magic goes into its implementation. Let’s go through:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/252036098151eea8a64261b17a4e333b/href">https://medium.com/media/252036098151eea8a64261b17a4e333b/href</a></iframe><ol><li>At the very bottom we declare an <strong>array of model</strong>s to be presented</li><li>Here is the most interesting part. Since first-class type objects are not comparable, we use <strong>ObjectIdentifier</strong> struct from <strong>Swift standard library</strong> to create <strong>Hashable</strong>/<strong>Equatable</strong> proxy object for each <strong>Type</strong> object. We declare a dictionary and two handy methods to register and obtain types from it.</li></ol><blockquote>Since it is a repetetive code part, it should probably be moved into separate class called <strong>TypeRegister</strong> or something like that.</blockquote><p>3. In <strong>viewDidLoad() </strong>method we register cell types into table view using a small helper method.</p><p>4. Next we register associative Model-View pairs into our type dictionary.</p><p>5. In a <strong>cellForRowAt: </strong>we get a model from our array, determine a cell type for it and dequeue a cell of appropriate type.</p><p>6. Finally, we tell UITableView to use Auto-Layout to calculate height of cells, since it can very from one option to another.</p><p>That’s it! Now you have super-flexible 60 lines of code implementation of UITableView, that can handle unlimited amount of models in it.</p><h3>Usage</h3><p>Usage of the framework is super easy. All you have to do is to initialize debug menu once (usually in AppDelegate) by calling one method:</p><blockquote>DebugMenu.sharedManager.enable()</blockquote><p>And then declare your options in a declarative manner (usually in controller’s <strong>viewDidLoad</strong>):</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/951c1bb4889eb42ada06a125c9531869/href">https://medium.com/media/951c1bb4889eb42ada06a125c9531869/href</a></iframe><p>The result of this call can be seen on the video in the beginning of the story</p><blockquote>Since the repo is dedicated for debug purposes, you probably would want to cover all interactions with <strong>DebugMenu</strong> with <strong>#if DEBUG … #endif </strong>clauses.</blockquote><h3><strong>Final words</strong></h3><p>Since UI engineering is not what I do on daily-basis I would love to hear your feedback on the technique and to hear any directions on how to do it even better. Hope you enjoyed the read!</p><p>Don’t forget to play with the repo on <a href="https://github.com/s1ddok/DebugMenu">GitHub</a> and follow me on <a href="https://twitter.com/s1ddok">twitter</a>.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=d3a7e646df53" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Holistically-Nested Edge Detection on iOS with CoreML and Swift]]></title>
            <link>https://medium.com/@s1ddok/holistically-nested-edge-detection-on-ios-with-coreml-and-swift-e45df264cf66?source=rss-215d6c63b088------2</link>
            <guid isPermaLink="false">https://medium.com/p/e45df264cf66</guid>
            <category><![CDATA[coreml]]></category>
            <category><![CDATA[swift]]></category>
            <category><![CDATA[machine-learning]]></category>
            <category><![CDATA[caffe]]></category>
            <category><![CDATA[ios]]></category>
            <dc:creator><![CDATA[Andrey Volodin]]></dc:creator>
            <pubDate>Mon, 03 Jul 2017 12:52:02 GMT</pubDate>
            <atom:updated>2017-07-03T14:28:08.062Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/256/1*ib9zlUzRLUtDpntJtM4fjA.png" /></figure><p><strong>CoreML</strong> was one of the loudest reveals on WWDC 2017. Machine Learning is taking over the world, so Apple released it just on time to get the hype.</p><p>There are a lot of examples in the web on how to use CoreML for classification purposes. Most of them use classic models like <strong>Inception-v3</strong> or <strong>MobileNet</strong>.</p><p>The problem is that you can barely imagine someone who needs classification neural net in 2017 in their app :) Today I would love to show you how to use <strong>CoreML</strong> for<strong> image-to-image</strong> neural nets.</p><p>For that purpose I’ve chosen <strong>Holistically-Nested Edge Detection, </strong>which has <a href="https://github.com/s9xie/hed">publicly available pre-trained caffe model</a>, which is just what we need to dive in.</p><p>In this tutorial I’m not going to deeply touch the <strong>CoreML tools setup</strong>, I assume you to be already familiar with them.</p><h3>Step 1. Convert model from Caffe to CoreML</h3><p>The process of converting model is fairly simple, but if you want to concentrate on iOS/Swift parts, you can <a href="https://github.com/s1ddok/HED-CoreML/tree/master/HED-CoreML/Models">download pre-converted models in the accompanying repo</a> and proceed to Step 2.</p><p>For those, who want to do everything themselves, first go to <a href="https://github.com/s9xie/hed"><strong>HED</strong></a> repository and download it. There in <strong><em>examples/hed </em></strong>folder you can find a file named <a href="https://github.com/s9xie/hed/blob/master/examples/hed/deploy.prototxt">deploy.prototxt</a>. This file contains meta-information about the model, so that inference engine (Caffe in this case) can find appropriate weights for all layers. Next thing you need is pre-trained model, you can train one yourself, but that goes beyond the scope of this tutorial. You can find one <a href="http://vcl.ucsd.edu/hed/hed_pretrained_bsds.caffemodel">here</a>.</p><p>Okay, now you need the <strong>deploy file</strong> with meta information and <strong>pre-trained model</strong>.</p><p>Next, open your favourite <strong>Python</strong> editor and create a fairly simple script, which should look something like this:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/3102b00b70d3cee13ea1f66a3d0e2b46/href">https://medium.com/media/3102b00b70d3cee13ea1f66a3d0e2b46/href</a></iframe><p>Don’t get upset if you don’t understand those <strong>magic numbers of chanel-biases</strong> or why the input tensor should be <strong>BGR</strong>. All you need to know for now is that those requirements come from original <strong>Caffe</strong> model.</p><p>Call it from the same directory, where two previously downloaded files are landed:</p><blockquote><strong><em>python convert.py</em></strong></blockquote><p>However, it won’t work out of the box. You will see the following error:</p><blockquote><strong>RuntimeError: Unsupported option ‘0’ for the parameter ‘offset size’ in layer ‘crop’ of type ‘Crop’ during caffe conversion.</strong></blockquote><p>The problem is that <strong>CoreML</strong> can’t find enough information to setup <strong>Crop</strong> layer internally. To fix this, you will need to add the following parameter to every <strong>Crop</strong> layer in <strong>deploy.prototxt</strong>:</p><blockquote><em>crop_param {<br> axis: 2<br> offset: 32<br> offset: 32<br>}</em></blockquote><p>With those parameters the result image will not be offseted and will fit original one just fine.</p><p>However, this is not the only fix you will have to do. After you will try convert one more time, you will see something like this:</p><blockquote><strong>RuntimeError: Caffe layer ‘sigmoid-dsn1’ is defined in the .prototxt file but is missing from the the .caffemodel file</strong></blockquote><p>That is because <strong>CoreML</strong> doesn’t support “empty” layers. Good thing it only doesn’t work for <strong>Sigmoid</strong> layers, which are fairly easy to implement yourself. What you have to do is to comment out (with <strong><em>#</em></strong>) all Sigmoid layers in <strong>deploy.prototxt</strong>.</p><p>Now you should be just fine and after few seconds you will see <strong>HED_main.mlmodel </strong>file in the same directory with your caffe model. That file is everything we need to launch this neural net in iOS Application, simply drag and drop it in your application.</p><blockquote>Note: HED is the model which contains “side-outputs”. Those are model calculation’s results on intermediate steps, but in this particular case they can be used as well. However, CoreML doesn’t support side-outputs if they are used by “upper” layers, so if you would love to grab those, you will have to modify deploy.protoxt file so that those layers are final ones. I included <a href="https://github.com/s1ddok/HED-CoreML/tree/master/caffe">examples on how to do it in the accompanying repo</a>. Best thing about side-outputs is that if they fit your requirements, then it could save a significant amount of size in your application, for example original model is around 59mb, while dsn3 output is only 7mb.</blockquote><h3>Step 2. Launch inference from Swift in your app</h3><p>All you need to do to integrate the model into your application is to drag the <strong>.mlmodel</strong> file into your <strong>XCode</strong> project and add it into your <strong>application’s target</strong>.</p><p><strong>CoreML</strong> models contain <strong>pre-generated code</strong>, which allow you to use models like classes in <strong>Swift</strong> or <strong>Objective-C</strong>. That said, to create and use the model you simply need to do the following:</p><blockquote><strong><em>let hedMain = HED_fuse()</em></strong></blockquote><p>Next thing you have to do is to convert your input image (which is likely to be <strong>UIImage</strong> instance) to models’ input format. In our case it is <strong>500x500 <em>CVPixelBuffer</em></strong> object. You can find conversion util extensions in the repo.</p><p>Next, you have to call <strong><em>.prediction(data:) </em></strong>to launch actual inference of the model on input data. What you will get in return is <strong>MLFeatureProvider, </strong>which contains model’s computation results. To retreive features you need to call <strong><em>.featureValue(for:) </em></strong>and pass the name of output layer you want to get features from. If you don’t want to hardcode things into your code, you can use something like this:</p><blockquote><strong><em>results.featureValue(for: results.featureNames.first!)</em></strong></blockquote><p>To know the shape of the output feature you should use <strong>shape</strong> property. In our case it will be<strong><em> 1x1x500x500 </em></strong>which corresponds to single-channel image.</p><p>At this points we have two problems:</p><ol><li>The result features are in Double format, which is not really useful.</li><li>The result features are not normalized.</li></ol><p>While first is trivial to fix, the second is actually pretty interesting. The thing is that before CoreML, every company who did their own ML had either hardcoded <strong>MPS</strong> (Metal Performance Shaders) models or runtime model builders (similar to what <strong>Apple</strong> released in <strong>MPS Graph API</strong>) with custom converters. The main challenge with those was to combine usage of <strong>MPS</strong> with the missing layers, which is actually the case here: <strong>CoreML</strong> can’t parse our <strong>Sigmoid</strong> layers properly (not really the <strong>Sigmoid</strong> itself is the problem here, but for the tutorial we will pretend like <strong>CoreML</strong> doesn’t contain <strong>Sigmoid </strong>layer), so we have to sort of plug it in.</p><p>Implementing <strong>custom layers in Metal</strong> for <strong>CoreML</strong> goes beyond this tutorial. Good thing for us is that our “missing” layer is <em>final one</em>. In case the layer is in <em>the middle of computation process</em>, you will have to <em>split</em> your <strong>CoreML</strong> model in two: before and after that layer. For the sake of this tutorial we will just normalize our result tensor with <strong>sigmoid</strong> on <strong>CPU</strong>.</p><blockquote>Let me know if you would love to see the article on implementing custom layers.</blockquote><p>Here you can the snippet of how to normalize our result features on <strong>CPU</strong> using <strong>sigmoid</strong> function and put it into <strong>UInt8</strong> buffer.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/b6bfa3be0f49fa58fcfea0988705fed6/href">https://medium.com/media/b6bfa3be0f49fa58fcfea0988705fed6/href</a></iframe><p>Last thing you will need to do is to convert freshly-baked <strong>UInt8</strong> buffer into single-channel <strong>CGImage</strong> and display it.</p><p>The results looks like this:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ImPsHMh68ZNPYyw_uaSB9g.png" /><figcaption>Different output’s results shown.</figcaption></figure><p>Today we learned how to integrate <strong>image-to-image models</strong> into iOS Applications. We also learned how to implement simplest missing layers on <strong>CPU</strong> and display results of tensor.</p><p>You can find WWDC Session that covers basics of <strong>CoreML</strong>: <a href="https://developer.apple.com/documentation/coreml/integrating_a_core_ml_model_into_your_app">Integrating a Core ML Model into Your App</a>.</p><p>And the <strong>accompanying repo</strong> here: <a href="https://github.com/s1ddok/HED-CoreML">https://github.com/s1ddok/HED-CoreML</a></p><p>Let me know if you are interested in more articles about <strong>CoreML</strong>!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=e45df264cf66" width="1" height="1" alt="">]]></content:encoded>
        </item>
    </channel>
</rss>