<![CDATA[rolisz's blog]]>https://rolisz.ro/https://rolisz.ro/favicon.pngrolisz's bloghttps://rolisz.ro/Ghost 5.26Mon, 08 May 2023 14:11:56 GMT60<![CDATA[Telegram notifications from Jupyter Notebooks]]>When running long running code in Jupyter, I want to get notified when it finished so that I can get back to it. There is an extension to do that with browser notifications, but there are times when I leave the computer while waiting for an ML training to finish.

]]>
https://rolisz.ro/2023/05/08/telegram-notifications-in-jupyter-notebooks/645416a08905a7dd5d51ea8dMon, 08 May 2023 14:10:57 GMT

When running long running code in Jupyter, I want to get notified when it finished so that I can get back to it. There is an extension to do that with browser notifications, but there are times when I leave the computer while waiting for an ML training to finish.

For long running CLI commands there is the ntfy, a command line tool that allows you to send notifications through a lot of channels.

So I hacked the two together to get some code that automatically messages me on Telegram when a cell finished more than 60 seconds after it started. This extension is registered automatically on the startup of any IPython and Jupyter notebook (even if they are installed in random virtual environments). Why Telegram? Because I already have it installed and it seemed like the easiest integration to set up.

The code has to be placed in ~\.ipython\profile_default\startup\01notification.py. You can place multiple files in this folder and they are loaded in lexicographic order, so you should prepend a number if you care about order. First, a couple of magic imports:

import time
import subprocess

from IPython.core.getipython import get_ipython
from IPython.core.magic_arguments import argument, magic_arguments, parse_argstring
from IPython.core.magic import (register_line_magic)

To send the notification using ntfy, I'm simply calling the program using subprocess. The path resolution used by subprocess is not clear to me, so I had to use the full path to the executable.

def display_notification(message):
    subprocess.run([r"C:\Users\Roland\AppData\Local\Programs\Python\Python310\Scripts\ntfy.exe", "-b", "telegram", "send", message]) 

Then we define some variables, one for the threshold for notification and the other one for remembering the start of the execution:

autonotify_after = 60
run_start_time = None

And now we define the magic function (that's what these things are called in IPython). It has two arguments, one to override the duration of the threshold for notifications and the other for the default message. I copy pasted the decorators as you see them. After parsing the arguments (which come as a string), we register two event handlers: one to run before a cell is executed and one after a cell is executed.

@magic_arguments()
@argument(
    "-a", "--after", default=None,
    help="Send notification if cell execution is longer than x seconds"
)
@argument(
    "-m",
    "--message",
    default="Cell Execution Has Finished!",
    help="Custom notification message"
)
@register_line_magic
def autonotify(line):
    # Record options
    args = parse_argstring(autonotify, line)
    message = args.message.lstrip("\'\"").rstrip("\'\"")
    if args.after:
        global autonotify_after
        autonotify_after = args.after
    ### Register events
    ip = get_ipython()

    # Register new events
    ip.events.register('pre_run_cell', pre_run_cell)
    ip.events.register('post_run_cell', lambda: post_run_cell(message))

The handler to run before a cell is simple: we just record the start time of the run.

def pre_run_cell():
    global run_start_time
    run_start_time = time.time()

The second handler is slightly more complex. We look at the output of the last cell and append it to the message if it's not an "empty" value. We check how long has elapsed to know whether to show a notification or not:

def post_run_cell(message):
    # Set last output as notification message
    last_output = get_ipython().user_global_ns['_']
    # Don't use output if it's None or empty (but still allow False, 0, etc.)
    try:
        if last_output is not None and len(str(last_output)):
            message = message + "\n" + str(last_output)
    except ValueError:
        pass # can't convert to string. Use default message
    
    # Check autonotify options and perform checks
    if not check_after(): 
        return
    display_notification(message)


def check_after():
    # Check if the time elapsed is over the specified time.
    now, start = time.time(), run_start_time
    return autonotify_after >= 0 and start and (now - start) >= autonotify_after

The last piece of magic is to run this function. The other blog post I was inspired by said you should delete the function for things to work properly, so I did that as well:

ipython = get_ipython()
ipython.magic('autonotify')
del autonotify

And voila, now you will get Telegram notifications automatically when your model  finishes training! Setting up a Telegram bot is left as an exercise for the reader.

]]>
<![CDATA[TIL: Recreating tmux socket]]>I use tmux as a multiplexer and for running some long-running commands on servers. Today I encountered a weird issue: when trying to attach to an existing tmux session (or when trying to do anything with tmux), I would get the following error:

can't create socket: Permission denied
]]>
https://rolisz.ro/2023/04/28/tmux-socket/644ba41f9faad2d80e8ee757Fri, 28 Apr 2023 10:54:33 GMTI use tmux as a multiplexer and for running some long-running commands on servers. Today I encountered a weird issue: when trying to attach to an existing tmux session (or when trying to do anything with tmux), I would get the following error:

can't create socket: Permission denied

A quick search on Kagi revealed that it might be permissions issue. I tried resetting the permission of the /tmp/tmux-* folders, but it didn't help.

What did work however was recreating the socket the tmux server uses to communicate with the tmux client. To do that, you have to run the following command:

killall -s SIGUSR1 tmux

And then the tmux attach worked perfectly, showing me all the windows from my old session.

I have no idea why this happened though.

]]>
<![CDATA[Interview about deep fakes]]>Yesterday my friend Marius Corici called me and asked me if I wanted to be interviewed (again) by ProTV, this time about deep fakes. This time it was a Zoom interview, and they asked me not to blur my background (ugh). And I had my second 15 seconds of fame

]]>
https://rolisz.ro/2023/04/08/interview-about-deep-fakes/643187c2e62b4433b9006685Sat, 08 Apr 2023 15:37:27 GMT

Yesterday my friend Marius Corici called me and asked me if I wanted to be interviewed (again) by ProTV, this time about deep fakes. This time it was a Zoom interview, and they asked me not to blur my background (ugh). And I had my second 15 seconds of fame last night (the actual interview was 5 minutes long, but they cut out most of it).

0:00
/

tl;dr: Deep fakes are already here, they are getting easier and easier to make and it's a cat and mouse game to detect them.

Source: ProTV

]]>
<![CDATA[Making a loudness monitor for online meetings]]>As I work from home 90% of the time, I run into a small issue during meetings: I sometimes speak too loudly. Before my daughter Gloria arrived, this was something that annoyed my wife and others in the house, but now, when Gloria is sleeping, this is not just an

]]>
https://rolisz.ro/2023/02/02/making-a-loudness-monitor/63c85a12164d3b23b60b6280Thu, 02 Feb 2023 15:43:56 GMT

As I work from home 90% of the time, I run into a small issue during meetings: I sometimes speak too loudly. Before my daughter Gloria arrived, this was something that annoyed my wife and others in the house, but now, when Gloria is sleeping, this is not just an annoyance, it's a BIG problem, because nobody wants to wake up a toddler.

While I do have monitoring that alerts me via Signal that I'm speaking too loud (my wife), I wanted to write a program to do that all the time, in the spirit of using programming to make my life nicer.

So I started to look for a Python library that can give me information about the sound level from my microphone. A quick Kagi search revealed several options, but sounddevice seemed like the best one.

The first step is to identify the microphone. For that I need the name as it's know to the operating system. I can get that by running the following code in a Python console:

> import sounddevice as sd
> sd.query_devices()
0 Microsoft Sound Mapper - Input, MME (2 in, 0 out)
1 Microphone (Yeti Stereo Microph, MME (2 in, 0 out)
2 Microphone (WO Mic Device), MME (2 in, 0 out)
....
> sd.query_devices()[1]['name']
'Microphone (Yeti Stereo Microph'

I get a long list of stuff, but I see something with Yeti in the name so I grab that one.

Now let's start listening to the microphone. Sounddevice offers a callback based API, where it passes along the raw audio data received from the microphone. From that, I estimate the loudness by calculating the norm of the sound:

import numpy as np
import sounddevice as sd


def print_sound(indata, frames, t, status):
    volume = np.linalg.norm(indata) * 10
    print(volume)


name = 'Microphone (Yeti Stereo Microph'
with sd.InputStream(device=name,callback=print_sound):
    for i in range(5):
        sd.sleep(1000)

Running this gives something as follows. Can you guess where I snapped my fingers?

0.3724626451730728
0.6015866994857788
0.9348087012767792
0.7427176833152771
0.8615989238023758
0.7162655889987946
0.5638395622372627
0.7117109000682831
59.17434215545654
50.70761203765869
20.951063632965088
14.069621562957764
9.29598331451416
5.908793210983276
3.782018721103668
2.402055263519287
1.7902085185050964
1.1522774398326874
0.793280228972435

The next step is to make it warn me when I speak too loud. For this I keep a buffer of the latest sound intensities in order to be able to detect when either something loud has been happening for a long time or if a really loud noise happened in the last frames:

import time
from collections import deque

import numpy as np
import sounddevice as sd


last_alert = time.time() - 10
q = deque(maxlen=200)


def print_sound(indata, frames, t, status):
    global last_alert
    volume_norm = np.linalg.norm(indata) * 10
    q.append(volume_norm)
    last_elements = [q[i] for i in range(-min(50, len(q)), 0)]
    recent_avg_sound = sum(last_elements) / len(last_elements)
    num_high_count = len([x for x in q if x > 20])
    if num_high_count > 30 or recent_avg_sound > 50:
        if time.time() - last_alert > 10:
            print(f"You are speaking at {volume_norm:.2f}. Think of Gloria!\a")
            last_alert = time.time()


name = 'Microphone (Yeti Stereo Microph'
with sd.InputStream(device=name,callback=print_sound):
    while True:
        sd.sleep(1000)

Now, when running from a Terminal (either on Windows or Linux), this will make a bell sound if in the last 5 seconds (that's about 200 frames) there have been more than 30 frames with loudness over 20 or if in the last second the average was over 50 (this would mean a really loud sound).

If you want to run this outside of Terminal, you can use beepy for example to make sounds and replace the print statement with this:

from beepy import beep

beep(sound="error")

To run this on startup on Windows, I created the following ps1 script in the startup folder:

C:\Users\Roland\Programming\mic_check\.venv\Scripts\pythonw.exe C:\Users\Roland\Programming\mic_check\mic_check.py

Another improvement would be to make it easier to see current loudness and to be able to quit it easily (because the ps1 script runs in the background). For this I used the infi.systray library on Windows:

from infi.systray import SysTrayIcon

def quit(systray):
    global still_on
    still_on = False


menu_options = ()
systray = SysTrayIcon("icon.ico", "Mic check tray icon", menu_options, on_quit=quit)
systray.start()
still_on = True
name = 'Microphone (Yeti Stereo Microph'
with sd.InputStream(device=name,callback=print_sound):
    while still_on:
        sd.sleep(1000)

And now, hopefully I'll learn to control my loudness better!

You can find the full code here.

]]>
<![CDATA[Learning in public: Transcribing podcasts with Whisper]]>My next project where I learn in public is about doing transcripts with Whisper.

Whisper is a quite good automatic speech recognition model that is open source and can run on your own computers, provided you have a GPU.

I prefer reading to listening, so I wanted to transcribe my

]]>
https://rolisz.ro/2022/11/23/transcribing-podcasts-with-whisper/637e3bc0ebfb31ec616c42f3Wed, 23 Nov 2022 15:32:34 GMT

My next project where I learn in public is about doing transcripts with Whisper.

Whisper is a quite good automatic speech recognition model that is open source and can run on your own computers, provided you have a GPU.

I prefer reading to listening, so I wanted to transcribe my long list of things to listen to, ideally in automatic way.

The first step was to use Whisper to transcribe anything dropped into a folder. I recorded myself while doing this and I plan to do at least 2 more sessions of this.

Lesson learned: OBS studio uses a lot of resources and sometimes the recording has issues because of Whisper also hogging up resources.

]]>
<![CDATA[Where's rolisz?]]>The last couple of months have been quite busy for me. Consultant life is starting to pick up the pace (at least some aspects of it), especially the traveling part.

It started in March: Make IT in Oradea, a startup incubator where I'm involved as a mentor, had

]]>
https://rolisz.ro/2022/07/15/traveling-again/62c09716c43b7b1471d94470Fri, 15 Jul 2022 10:50:38 GMT

The last couple of months have been quite busy for me. Consultant life is starting to pick up the pace (at least some aspects of it), especially the traveling part.

Where's rolisz?

It started in March: Make IT in Oradea, a startup incubator where I'm involved as a mentor, had its first in person pitching event in Timisoara. I was invited to be a part of the jury evaluating the submissions. I had never been to Timisoara before so it was I managed to scratch that itch of traveling to a new city. Unfortunately, I was not very impressed by the city, but at least I met some interesting people.

Where's rolisz?

In April, Today Software Magazine had its first in person event in two years and I presented briefly about modern NLP methods. The presentation was an exercise of my improvisation skills, because the platform used to show the slides had technical difficulties while I was speaking, so I had to wing it.

Where's rolisz?
All the speakers from The Developers conference

And then June was busy. I gave a talk at The Developers, the first in person technical conference in Cluj. I talked about Large Language Models. I listened to some great talks and I talked to some people who are also in the consulting business and got some great advice (and some not so encouraging things, such as the guy who signed a contract with a client 7 years after the client heard him speak at a conference).

And then the fun started: flying abroad again. It's been almost two years since I flew and even that was a short 50 minute flight. And it's been 3 years since I have been abroad (Debrecen doesn't really count).

Where's rolisz?
The OTH team at CodeX

Through Oradea Tech Hub I was invited to mentor at the CodeX hackathon in Riga. It was a really well organized hackathon. The venue was great and it was great to feel the energy from the students (mostly). I definitely wouldn't pull an all-nighter for a hackathon anymore :))

I have to admit I didn't know much about Riga before and I was very pleasantly surprised. It's not a very big city, but it has a cool vibe and it's very clean. 10/10 would recommend, I want to go there again with Roda and Gloria.

It has many buildings in the style of Art Nouveau, like Oradea (where I live), so I finally found out what Art Nouveau is! It also has a statue of St. Roland, so that might have contributed to me liking the city so much.

Where's rolisz?

The last trip in June was to Berlin, where I attended the datalift summit and I was a session chair. That was a really good conference! I met so many great people, all doing machine learning. I hope I can even collaborate with some of them sometime soon.

But the city itself... didn't impress me. I won't go again to Berlin anytime soon. The food was really good, with lots of very diverse options available, but the city itself... meh, too dirty. Sure, the city center is nice, but once you've seen one European capital, you've seen them all.

Where's rolisz?

Now it's time for a bit of relaxing, so now I'm in Sibiu (where I have grandparents). It's Gloria's first longer trip away from home, so we're curious how she'll handle it! So far so good, so we're hoping for at least two more trips in the next months!

]]>
<![CDATA[Roland tries new things: Horse riding]]>My two brothers in law are fans of horse riding and last week they invited the rest of the family to join them for a day of horse riding. They encouraged us with fun tales of how of them fell off/was thrown off a horse. Having not done anything

]]>
https://rolisz.ro/2022/06/09/horse-riding/629ce3446c14f50797d067d9Thu, 09 Jun 2022 14:48:55 GMT

My two brothers in law are fans of horse riding and last week they invited the rest of the family to join them for a day of horse riding. They encouraged us with fun tales of how of them fell off/was thrown off a horse. Having not done anything new in a while, Roda and I agreed to it.

Roland tries new things: Horse riding
The 10 minute horse riding intro

When we arrived at the Kalota Lovarda, we received a brief intro to how to ride a horse while it walks and an even shorter intro on how to ride it while it trots. Turns out riding a horse is not a passive activity, but you have to move your hips to nudge the horse to keep moving, while also lightly pulling on the reins. If you let the reins go, the horse will most likely take a break to eat some grass. Horses really love eating grass and will do that whenever they have the chance.

Roland tries new things: Horse riding
My horse, Titi

The first five minutes of the intro had me regretting that I signed up for activity. Do this for the rest of the day? Oh boy, oh boy. Please don't fall of the horse! Please don't throw me off, horsey!

Roland tries new things: Horse riding
"Excited" to start our trip

It was an interesting experience where I learned a lot, such as the fact that horses have thick skin, so they don't care about going through bushes and thorns - but you do. Also, when going through a thicker forest, horses only make sure they don't hit trees - your knees are none of their concern, or worse, not even your head when going below some low branches.

Roland tries new things: Horse riding

The views were beautiful, as always, but honestly, I'm not sure if I'd rather do the trips on horses or while walking. There is a certain serenity that comes with the rhythm of horses step, which makes the scenery more enjoyable in a way. But it's so exhausting after 8 hours....

Also, horses have very different personalities and behaviors. Some horses have no problem pooping while walking, others, like my Titi, would always stop whenever he felt the need to relieve himself. Sometimes he would even go off the path, as a courtesy to the others. Some horses would avoid stepping into the mess others left, other horses had no problems marching straight through.

Roland tries new things: Horse riding

One of the funnier things on the journey was when the owner of the horses got off this horse for some reason and then his horse ran away. I think he spent 15 minutes trying to get back on him. It was quite funny, but it also made most of us reconsider getting off our horses.

When we got to the restaurant after 3 hours, everyone was relieved to finally get off the horse and give our bottoms a well deserved rest. But then it was time to go back, on a slightly different route. This time, even the horses were tired. The older ones would stop periodically for a quick break. But, after 2.5 hours, we did get back to the stables safely.

Roland tries new things: Horse riding
Tired horses, tired riders

Unfortunately, I never managed to reliably get my horse to trot and more importantly, I never managed to learn how I should move in the saddle while trotting, to avoid making an omelette. Maybe next time? But it won't be anytime soon. I'd rather go to the aquapark.

]]>
<![CDATA[On the usefulness of a little bit of programming]]>While I am a professional software developer (or machine learning consultant, to be more exact) and I have started learning programming more than 10 years ago, I went to college to study it, I spend a lot of my free time learning more about this domain (because I love it)

]]>
https://rolisz.ro/2022/03/15/on-the-usefulness-of-a-little-bit-of-programming/62307a8aecbf7104750afc7dTue, 15 Mar 2022 14:07:44 GMT

While I am a professional software developer (or machine learning consultant, to be more exact) and I have started learning programming more than 10 years ago, I went to college to study it, I spend a lot of my free time learning more about this domain (because I love it), I'm starting to realize that knowing a bit of programming is a super power, from which many people could benefit, if only they knew just a bit of coding.

For example, about 6 years ago I wrote a 2 line JavaScript bookmarklet for a recruiter, that reduced the number of clicks he had to do, from 10 clicks to 3, for each of several thousand candidates. It was a simple script that looked for an HTML tag, extracted a value and put it in the clipboard (from where he pasted it into a spreadsheet). The guy was so happy that he gave me a peer bonus, because it saved him hours of boring work.

Another example is when I have to replace something many times in a text document and I can quickly write a regex to do it. My dad sometimes calls me to do that for him when he is typesetting books.

This week I wanted to read a transcribed sermon that came in a .doc format. For more pleasant reading, I copy pasted it into a markdown file, quickly fixed some Markdown issues (mostly lists and headers), ran it through Pandoc and got a beautiful HTML, that was easy on the eyes. I sprinkled in some copy pasted JavaScript and I had automatic popups for Bible verses when hovering over references.

Julia Evans recently wrote about some tiny personal programs she wrote that both had marginal utility in her life and also brought her joy while writing them.

Doing this kind of programming doesn't require knowing a lot about programming, much less how to develop software professionally, but it does require you to have a knowledge of what is possible with code and either a low enough friction to get started (such as a text editor with a built-in regex search and replace), or a high enough motivation (such as wanting to avoid tens of hours of boring work) to do it.

But unfortunately, I don't know if this is something that can be learned quickly. All these examples I gave took me 5-10 minutes to implement, but that's because I already knew a fair bit of JavaScript, I've had to process Markdown in the past, I've written regexes many times for work and I've had a general awareness of Pandoc, even if I didn't use it much before. If I had to search Kagi for all of these (or if I didn't even know what to search for), it would take a lot longer.

In my opinion, this approach is much more useful than the no-code approach that is popular today (at least among startups) and it would be great to see more startups trying to reduce the friction for doing just a bit of coding, not eliminating coding at all. Grist seems like a pretty good approach in this direction.

What's your favorite quick "hack" where you used a bit of coding knowledge to bring quality of life improvements for yourself?

]]>
<![CDATA[Facilitating Code Retreat in Oradea]]>After 8 years, I finally went again to a Code Retreat, but this time as a facilitator, not as a participant. As far as I know, it was the first time it was done in Oradea, so kudos to the Oradea Tech Hub team for organizing it.

My co-facilitator was

]]>
https://rolisz.ro/2022/02/27/facilitating-code-retreat-in-oradea/621a73fee4d316d11048ac95Sun, 27 Feb 2022 14:47:00 GMT

After 8 years, I finally went again to a Code Retreat, but this time as a facilitator, not as a participant. As far as I know, it was the first time it was done in Oradea, so kudos to the Oradea Tech Hub team for organizing it.

My co-facilitator was Bogdan Bota, who is the co-founder of OptiOffer, with whom I share a surprising number of views on technology and programming. Some of these common things are that neither of us is a big fans of OOP and TDD, so we didn't push that angle too much.

One surprise for me was that the mix of languages that people knew has changed a lot. Java and C# were much rarer, while Javascript was ubiquitous. There were a couple of high school students, who were working with C++ (because that's what's taught in Romania in programming classes).

Facilitating Code Retreat in Oradea

The participants enjoyed the different challenges we gave them, even if some of them were annoying (but realistic), such as changing requirements or partners mid-session. Bogdi and I had the most fun though, guiding them through this.

We got really good feedback, people had fun and said they learned a lot, and almost everyone was asking about when is the next event going to be. Naomi, I hope you'll organize many more great events!

]]>
<![CDATA[To changes]]>During the last 1 year I've had a lot of changes in my life. I became an independent machine learning consultant. Other people consider me an entrepreneur. I'm still in disbelief about that label, but it's becoming true, especially since I launched my first

]]>
https://rolisz.ro/2022/01/01/to-change/61d0896bbb23f815486168e0Sat, 01 Jan 2022 20:32:00 GMT

During the last 1 year I've had a lot of changes in my life. I became an independent machine learning consultant. Other people consider me an entrepreneur. I'm still in disbelief about that label, but it's becoming true, especially since I launched my first side-project (or is still a side project if it's just one of the many things you do?). Sometimes I feel like I barely recognize myself and how I think.

The machine learning consultant part has changed a lot as well. When I started off a year ago, I had many ideas of what I would do: trainings, online courses, consulting, train lots of ML models. Drawing the line at the end of the year has revealed that I did few of the things I thought I would do and that actually, the most profitable things were things I never thought I would do. I barely did any teaching, I did some consulting, but developing a full stack proof of concept for a startup was by far the best thing financially (and really fun too). Hmmmm.... maybe I should update the list of services I offer.

I started out as a machine learning consultant. But almost all of my work has been related to natural language processing (aka: working with text). Hmmmm.... maybe I should niche down to just NLP.

Some things didn't change. I still have a pathological fear of picking up the phone to call someone. Luckily, most of my clients came to me, instead of me having to go to them.

I thought I would have to do a lot of marketing, lots of blog posts, tweets, Youtube videos. I had one good blog post that brought in two clients. All the other clients came through referral and word of mouth. Hmmmm.... who knew networking is that important? And maybe, just maybe, my blog is not as important.

For a long time I was a lurker on forums, rarely posting anything. This year I've discovered several communities where for some reason, I started being more active. Hmmm... maybe I'm not that introverted.

The biggest change was becoming a daddy. I now have a very different reason to look forward to every day: Gloria. Of course, it comes with it's own challenges, including some curveballs, but boy, is it great.

To changes
My beautiful giggly daughter, who melts my heart whenver I look at her

There are some negative changes as well: it was the first year in a long time when I didn't fly at all :(

Here's to more changes in 2020 v2 and to being nimble, as God leads me!

]]>
<![CDATA[Learning in Public: Exploring the BT iPay API]]>Dan Luu and Jamie Brandon have argued quite successfully that increasing your productivity and velocity as a developer can lead to good return on investment. So I've been thinking about doing the same and I was inspired by Michael Lynch to record myself while coding and then to

]]>
https://rolisz.ro/2021/11/16/learning-in-public-exploring-the-bt-ipay-api/6193efe8bb23f8154861688cTue, 16 Nov 2021 19:09:28 GMT

Dan Luu and Jamie Brandon have argued quite successfully that increasing your productivity and velocity as a developer can lead to good return on investment. So I've been thinking about doing the same and I was inspired by Michael Lynch to record myself while coding and then to analyze the mistakes I've made.

That was quite fun and I got some very useful feedback from it, so I thought I'd share this video, as a way of learning in public.

First lesson: my green screen doesn't play nice with my IKEA chair that has a mesh in the back. My apologies for the awful looking webcam overlay.

And some development lessons:

  • I go with the mouse several times to the menu to select "Format code". I should learn the shortcut for that, or even better, I should set PyCharm to auto format the file when saving.
  • I spent a lot of time on figuring out the parameters for the first call and on formatting them as a dictionary. I could have sped up understanding how to send the parameters by URL decoding the provided example and for the formatting I could have used a multi cursor for quicker editing.
  • BurpSuite/HTTP Toolkit was recommended as a way to explore HTTP APIs.
  • When I was writing the client.register_payment call I had to hover a lot over the function definition to see the order of parameters. Copying the function definition would have been faster and it would have made it easier to define keyword arguments, which are clearer for a function with so many parameters.

Thas was quite fun and useful. Thank you Michael and Catalin for the feedback!

]]>
<![CDATA[The right time for every habit]]>I've written many times about various goals and plans I've had over the last couple of years. I blogged publicly about it because I had heard that precommitment helps with realizing goals. But, considering that many of the goals on those lists didn't get

]]>
https://rolisz.ro/2021/10/09/the-right-time-for-every-habit/616091a7e8b5e067fe3b8323Sat, 09 Oct 2021 09:34:50 GMT

I've written many times about various goals and plans I've had over the last couple of years. I blogged publicly about it because I had heard that precommitment helps with realizing goals. But, considering that many of the goals on those lists didn't get touched at all, even though I repeated them every year for three years, precommitment didn't give the promised results.

So since 2019, I haven't set big, public yearly goals, even though I still try to carve out some directions for myself every year.

But I am glad to report that despite focusing less on such goals, I've managed to create two habits that have been on my list for a long time, through very different means.

Working out

The right time for every habit

During the last 52 weeks (so 1 year basically), I have done 113 workouts, meaning just a bit more often than 2 times a week.

While I was working at Google, I managed to work out quite often, but there it was easier because I had to go down only 2 floors from my desk to get to the office. After moving to Romania, I would have had to go to a gym. I had one attempt to do that, but my car didn't start just when I wanted to go to the gym and it was raining so I couldn't go by bike, so I gave up. Then I bought barbells, dumbells and a squat rack, but, for 2 years, I used them at most 10 times.

But last year in October, after much internal mulling, I realized I need to change how I approach my body and my health. I need to start prioritizing it, and not just in a "New Year's Eve resolution" kind of way. My health has to be a priority and that means other things have to go. For this, I had to learn how to workout, what exercises to do to achieve the outcomes that I wanted. It also meant closing my work laptop at 6 PM and getting into my gym clothes. Other times, instead of enjoying a slow morning, I would lift some weights and get sweaty. To make more efficient use of time, I would sometimes work out during the mid-week online church service (I still ask myself if that's good or bad).

The ongoing pandemic helped a bit, because I didn't travel so much, at most a couple of days here and there. But even then I would try to get in a bodyweight workout.

The conclusion remains the same: I need to prioritize my health, keeping an eye on the longterm. I still have much work to do in this area, especially on the nutrition side, but even there I'm slowly learning better how my body works and how I need to fuel it.

Memorizing Bible verses

The right time for every habit
Statistics from my Anki deck for Bible verses

This goal was on my list every year from 2016 to 2018 and every year I would utterly fail it. I would learn 1-2 verses and that's it.

But in 2019, someone from Brazil visited our church and told us how some young people from his church each memorized a book of the New Testament. And I decided, I'll do the same.

What had changed was that I had learned more about the science of memorization. I knew of some people who had memorized vast amounts of information, so my first step was to inform myself what would be the best way to do that. I tried putting that into practice and I've never stopped. For two years I have been using Anki to memorize Bible verses. I have memorized all of Galatians and I'm halfway through Ephesians.

While I am convinced that this habit is very beneficial for my spiritual life, I think the key here was breaking the requirement into small pieces that can be done easily. There are very few days when this takes more than 10 minutes. It's something that I can easily do in bed, right before I go to sleep. Or I can do while waiting in a queue at a shop.

The other thing that helps is to see how good my memory can become with enough practice. There are verses that Anki estimates I'll have to revisit only in 3 years. I notice that my short term memory is better. Memorizing more things is so useful, that I have started memorizing other things as well, from my wife's phone number to PowerShell commands to my business's registration number.

More work to be done

Roland is still a work in progress. God still has much to do in my life. But I want to celebrate every win, even as I look forward to what I'll learn in the coming months.

]]>
<![CDATA[Opening Jupyter Notebooks in the right browser from WSL]]>I mentioned last year that I've slowly moved back to using Windows more and more. In the mean time, my transition is almost completely done. This year I've pretty much booted into ArchLinux to update it, about once a month and that's it. I

]]>
https://rolisz.ro/2021/09/23/opening-jupyter-notebooks-in-the-right-browser-from-wsl/614c740d56c059246e90e2f3Thu, 23 Sep 2021 19:10:57 GMT

I mentioned last year that I've slowly moved back to using Windows more and more. In the mean time, my transition is almost completely done. This year I've pretty much booted into ArchLinux to update it, about once a month and that's it. I am otherwise very happy with WSL1 for when I need to run Linux only tools, such as auto-sklearn.

There was one small hickup: when opening a Jupyter Notebook from WSL, it would try to open the notebooks in the Linux environment, which is a CLI environment, so it opened them in Lynx, not in the Firefox instance that runs on the Windows side of things. While Lynx is cute, it's not the most useful interface for a Jupyter Notebook.

Opening Jupyter Notebooks in the right browser from WSL
Jupyter Notebook opening in Lynx

I could quit Lynx by pressing q and then I would CTRL-Click on the link showed in the terminal and Jupyter would open in Firefox. But hey, I'm a programmer and I don't want to do extra clicks. Today I learned how to fix this problem.

First, we need to tell WSL to use the browser from Linux. This can be done by setting the BROWSER environment variable to point to the location of Firefox in Windows, but with the path as seen by WSL:

 export BROWSER=/mnt/c/Program\ Files/Mozilla\ Firefox/firefox.exe

Running jupyter notebook after this will correctly open a window in Firefox, but it will open it with a Linux path towards a redirect file that does the authentication for Jupyter. Because Firefox runs in Windows, it can't access the path on the Linux side.

But there is a way to tell Jupyter to open the normal localhost links, not the ones that point to a local redirect file. For this, you have to create a Jupyter config (unless you already have one):

> jupyter notebook --generate-config
Writing default config to: /home/rolisz/.jupyter/jupyter_notebook_config.py

Then edit this file and change the use_redirect_file parameter to be true (and uncomment it if needed):

c.NotebookApp.use_redirect_file = True

From now, running jupyter notebook in WSL will open properly!

]]>
<![CDATA[Half a year as an indie consultant]]>It's hard to believe it's been more than half an year since I started my own company and became an independent machine learning consultant. It's been a very interesting ride.

There have been plenty of moments where the predominant feeling was "what now?

]]>
https://rolisz.ro/2021/07/09/half-a-year-as-an-indie-consultant/60d58d48a0cb673c37e93d2bFri, 09 Jul 2021 14:57:00 GMT

It's hard to believe it's been more than half an year since I started my own company and became an independent machine learning consultant. It's been a very interesting ride.

There have been plenty of moments where the predominant feeling was "what now?". How am I going to find more clients? How to negotiate with this client? The Dip, as it's called by Seth Godin, is very real and very scary. When you draw the line and see how much you've earned over six months... you start getting serious doubts. Was it worth it? Wouldn't it have been better (and much easier) to just find a nice job?

But there are other moments: when I realize I have freedom to choose my clients and the projects that I work on; after working for a whole day on something that I love, ML, without any useless meetings; when deciding with almost complete freedom the tech stack which will be used to build the ML side of things; when I take a day off almost whenever I want, just because I don't feel like working on that particular project on that particular day. Or when I realize that I am a consultant, that my clients look to me for advice and that they actually take my advice seriously. If I say that the way they did things previously won't work and they should do things differently? They'll get to it right away.

And then there are moments when I realize I barely have time to read any state of the art machine learning papers and instead I have to learn the basics of marketing, branding, business development, communication, coaching, explaining, teaching - and to put all of this into practice. Most of my clients don't care if I'm using the latest state of the art Transformer architecture (and don't even know what on earth that is). They don't even know what machine learning is. But they need someone to explain it to them - to people who have built successful companies in their own fields - and to help them understand if it's something that they need or not.

I am thankful to God for guiding me on this new path, of which I have dreamed for a long time. Faith in his faithfulness is what has kept me steady when my knees wavered.

I am grateful to my dear wife who was willing to take this risk alongside me and has been very supportive all along the way.

I am very glad I have a good accountant who can help me with all the paperwork of the company.

I am grateful to the whole team from Oradea Tech Hub, who have helped me get my name out there, and especially to my friend David Achim with whom I did many rounds of business strategy discussions.

And I am thankful to many others who have cheered me on, who have encouraged me and who have put in a good word for me to potential clients.

]]>
<![CDATA[Happy 11th Birthday!]]>My blog has circled the Sun for another year. You got 37 more posts in the meantime. The Obsidian post was very popular, as was the Rust Codenames series. Vmmem issues are finding a solution on my blog as well.  The second half of last year was slower than

]]>
https://rolisz.ro/2021/06/08/happy-11th-birthday/60bfba22a3c3ed7839d6f32eTue, 08 Jun 2021 19:17:05 GMT

My blog has circled the Sun for another year. You got 37 more posts in the meantime. The Obsidian post was very popular, as was the Rust Codenames series. Vmmem issues are finding a solution on my blog as well.  The second half of last year was slower than the first one, but it's ok.

I kinda split my blog into two: personal posts stayed here, anything related to machine learning goes to my new domain, which is for my consulting business. I still want to post some technical content here and I do hope I'll make it to the front page of HN again :D

I haven't had as much time to write posts because I've been busy with all kinds of other content: an in person machine learning course here in Oradea, several presentations, some about machine learning, some about quick iteration, some locally, some online. It turns I only have so much creative juice in me every day.

I've resumed my goals to blog again, but at a much more humble rate. Sometimes I'm tempted to try daily blogging, but I'm a bit afraid of that commitment and of the quality of the posts that would result from that. Some people say that writing daily turns on the faucets of creativity and you'll have plenty of ideas. But for now I'll stick to a more reasonable goal of two posts per month.

]]>