I've been enjoying Birdnet quite a bit! In a previous post I talked a bit about how I have a little raspberry pi in our hallway, listing the birds that are singing outside our house. It is hooked up to the microphones on the outdoor webcams we have. It brings me great joy to know there are robins, dippers and even a Tawny Owl in the vicinity. Great stuff! However, recently, it all broke!
A combination of duff SD card on the pi, and some FreeBSD upgrades meant I had to redo everything. I've ended up running birdnet in a Linux VM, running on FreeBSD using their vm platform called Bhyve. It's a suite of programs that allows you to manage virtual machines on a FreeBSD box! It took a long while, but I finally figured it all out. I figure this might be useful to some of you out there.
This little post is all about getting a virtual machine, running Tensorflow and Birdnet, all on a FreeBSD hypervisor.
Since this is a technical post, with the end goal of identifying birds, I'll include some bird snaps I've taken to make it all less dry!
In the past, I've used Linux as my main server setup. After a while, I started getting into ZFS for storing all my important files. It seemed to do all the things I wanted - encryption, RAID and good redundancy and performance. Getting it to work on Linux wasn't impossible but it felt like a FreeBSD thing really. The more I looked into FreeBSD the more I seemed to like it. No nonsense with SystemD (or at the very lesat, no drama), fairly simple setup and ZFS is right there out of the box.
The Register ran an article recently about how FreeBSD was boring, but in a good way. It's reliable, dependable and isn't really on any of the hype trains. It restrains me a bit from messing too much because lets face it, there's always a temptation to muck about with things you shouldn't. FreeBSD reins me in a bit, and that's no bad thing where it matters.
But of course, I do need to occasionally run something like Birdnet and FreeBSD makes that difficult. Well, perhaps not difficult, just I had to do it properly! ;)
So Birdnet requires Tensorflow, the A.I library from google. I don't use Tensorflow anymore, having moved over to Pytorch some time ago. I find tensorflow is very picky and difficult to install, requiring specific python versions. It's even harder to build from scratch. The FreeBSD version of Tensorflow at FreshPorts (a community of package builders porting software to FreeBSD) is broken, and doesn't seem like it will be fixed anytime soon (I have considered it). This means we need a Linux setup of some kind.
FreeBSD has had containers for a long time, way before it was cool. One can create jails, a FreeBSD term for a containerised process of sorts. In Linux world, one can use Docker. In fact, this is what I was doing for a while. BirdNet has a docker container all setup and ready to go. This is perhaps the easiest way to get Birdnet running on your own server.
Sadly, Docker isn't available for FreeBSD - it doesn't really make much sense. I'm not really experienced with setting up jails and containers from scratch. I figured it might be easier to run things inside a VM instead. It's a bit heavyweight but it does have a few advantages: I can always just move the VM to another box or run more than one server process on it.
Bhyve is a hypervisor manager for FreeBSD. The documentation in the FreeBSD website isn't a bad place to start, but I found the program vm-bhyve to be a little bit easier to work with. The readme that comes with that project is spot on!
The thing to remember is that Bhyve seems to use a secondary program - a version of Grub - that actually does the loading of Linux Kernel. Now I couldn't get this to work with ext4 book partitions, so I made sure the boot partition of my virtual machine was formatted as FAT32.
I asked around on chaos.social, the Mastodon instance, to see if there were any small, headless Linux installs. I got an answer that seems obvious in hindsight - Alpine Linux. I say obvious - it seems to be the one that everyone uses in their Docker containers. I've never really played with it before so I thought I'd give it a go.
Alpine is super light-weight - it's only a few 100 meg in size. Not bad! It also has a super easy installer. Aside from it's size, it's main feature is that it's built around the Musl C library. This version of Lib-C claims to be smaller, faster, safer and correct. All sounds good to me, though I hear it can lead to some odd crashes or incompatibilities.
However, I had a fair bit of trouble with Alpine Linux. Although the setup was quite easy (making sure to export BOOTFS=vfat before you run setup-alpine), I had trouble getting Tensorflow installed. The version of Python that comes with the latest version of Alpine is 3.12. Tensorflow is only supported up to Python 3.11. I attempted to install an older package via pip but this is not really the Alpine way; there is no support for installing older packages. I can understand why - package management is no easy thing. So I tried again with an older version, but I couldn't get Tensorflow to install at all. As I recall, it's all to do with the compiled sections not understanding the new Musl C standard library and the associated compiler. Not much I can do about that.
In the end, I decided to leave Alpine behind. I think there's definitely a use for it, but running an AI box may not be one of them. There are plenty of Docker images out there that have Tensorflow running; all nicely pre-built. But as I'm not using Docker in this instance, it's no use to me. If I had a more professional hypervisor, I might setup a Linux VM with Docker, but at that point I can just run Birdnet in a Docker image. Might not be a bad idea in the future actually.
But for now, I've gone back to Arch Linux which I know quite well. Installing it is a bit more involved, and it's not quite as light weight as Alpine, but it's still pretty good.
One needs to edit the /etc/rc.conf with the following:
vm_enable=”YES”
vm_dir=”zfs:zroot/bhyve”
The vm_dir can be wherever one wants to hold their VMs.
Add to the end of /boot/loader.conf:
vmm_load=”YES”
We need to setup a little bit of networking, as follows:
ifconfig tap0 create
sysctl net.link.tap.up_on_open=1
ifconfig bridge0 create
ifconfig bridge0 addm eth0 addm tap0
ifconfig bridge0 up
Replace eth0 with the device you have connected to the internet. The tap device is one way of getting VMs to talk to the rest of the world. I'm sure there are other ways to do this.
Now, lets setup the VM proper:
vm init
cp /usr/local/share/examples/vm-bhyve/* /zroot/bhyve/.templates
vm iso arch.iso
vm create logicoma
Replace arch.iso with the iso file you've downloaded. This gets copied to a separate directory. logicoma is the name of the vm. There will be a logicoma.conf you should edit.
Modify the logicoma.conf in the /zroot/bhyve/logicoma directory to be as follows:
loader="grub"
graphics="no"
cpu=1
memory=2048M
network0_type="virtio-net"
network0_switch="public"
disk0_type="virtio-blk"
disk0_name="disk0.img"
grub_install0="set root=(cd0)"
grub_install1="linux /arch/boot/x86_64/vmlinuz-linux initrd=/arch/boot/x86_64/initramfs-linux.img archisobasedir=arch archisolabel=ARCH_202410 ro modules=loop,squashfs,sd-mod,usb-storage,sr-mod"
grub_install2="initrd /arch/boot/x86_64/initramfs-linux.img"
grub_run0="set root=(hd0,1)"
grub_run1="linux /vmlinuz-linux root=/dev/vda3 modules=ext4"
grub_run2="initrd /initramfs-linux.img"
uuid="1829ddcd-8592-11ef-a133-64006a7d41aa"
network0_mac="58:9c:fc:06:23:ee"
Then, the final set of commands should be:
vm install logicoma arch.iso
At this point, just follow the setup on the Arch Linux Wiki. That should get you going. The disks appear as /dev/vda I believe. Aside from that, it's more or less the standard Arch install.
That should be it. We can reboot in when we like.
The last part of the puzzle is getting Birdnet to work. I use the BirdNET-Analyzer package on github. I've had to fork it though, in order to get a slightly tighter server.py - you can find my version on github too. Once I've made the virtual environment and run pip to get the required packages, one can run the server program.
In the end, I suppose I could submit the wav files I record to an online server somewhere online and publish the birds we hear to the wider world. Bird Weather is such a site. Maybe that's the next step?
In the end, it's been good to learn a bit more about FreeBSD and how it deals with VMs. More to learn I'm sure.