<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://nigerianpickle.github.io/Blog/feed.xml" rel="self" type="application/atom+xml" /><link href="https://nigerianpickle.github.io/Blog/" rel="alternate" type="text/html" /><updated>2026-09-01T15:00:31-05:00</updated><id>https://nigerianpickle.github.io/Blog/feed.xml</id><title type="html">Nwogo’s Blog</title><subtitle>A personal blog.</subtitle><author><name>Daniel Nwogo</name></author><entry><title type="html">Fine-tuning NLLB for Ìjẹ̀bú Yorùbá</title><link href="https://nigerianpickle.github.io/Blog/2026/09/01/fine-tuning-nllb-for-ijebu-yoruba/" rel="alternate" type="text/html" title="Fine-tuning NLLB for Ìjẹ̀bú Yorùbá" /><published>2026-09-01T09:59:44-05:00</published><updated>2026-09-01T09:59:44-05:00</updated><id>https://nigerianpickle.github.io/Blog/2026/09/01/fine-tuning-nllb-for-ijebu-yoruba</id><content type="html" xml:base="https://nigerianpickle.github.io/Blog/2026/09/01/fine-tuning-nllb-for-ijebu-yoruba/"><![CDATA[<h2 id="motivation">Motivation</h2>

<h3 id="what-is-nllb">What Is NLLB?</h3>

<p>NLLB: No Language Left Behind is a multilingual translation model. It’s trained on data using data mining techniques tailored for low-resource languages and supports over 200 languages.</p>

<p>My mom is Yorùbá, specifically from an Ìjẹ̀bú background. Growing up with that background, one thing I caught on to;  is that “Yorùbá” isn’t really one language. There’s a version everyone treats as the default (which is mostly drawn from Ọ̀yọ́), and then there’s what people actually speak at home, which can sound pretty different depending on where your family is from. Words, pronunciation, sometimes whole phrasing changes.</p>

<p>This isn’t just a personal observation, it’s a documented gap. Yorùbá has something like 47 million speakers across Nigeria, Benin, and Togo, and standard Yorùbá has gotten real attention from NLP researchers over the years, but until pretty recently, basically none of the non-standard dialects had any dedicated resources at all.</p>

<p><img src="/Blog/assets/img/2026-09-01-fine-tuning-nllb-for-ijebu-yoruba-1.jpg" alt="Yoruba has the 37th highest speakers in the world (https://en.wikipedia.org/wiki/List_of_languages_by_total_number_of_speakers#cite_note-9)" /></p>

<p><em>Yoruba has the 37th highest speakers in the world (https://en.wikipedia.org/wiki/List_of_languages_by_total_number_of_speakers#cite_note-9)</em></p>

<p>That’s the general pattern with low-resource language work, actually: the “low-resource” conversation almost always means most of the data about the ethnology of language is missing.</p>

<p>I came across a Global Voices interview with Aremu Anuoluwapo, a computational linguist who, along with Oreva Ahia (a PhD student at the University of Washington), built YorùLect specifically to address this.</p>

<p>The story behind it is a lot more grounded than “we scraped some data.” Anuoluwapo traces the idea back to an undergrad dialectology course, where he first noticed that even a basic word like “stool” differs between his hometown dialect and standard Yorùbá. He and Ahia later worked out the project’s framework in person, and he then traveled to the specific communities where each target dialect is spoken to actually collect the data,   deliberately choosing dialects from different regional branches of the language (southwest, southeast, and beyond) rather than just picking whatever was easiest to reach.</p>

<p>A few things from that interview reframed how I’m thinking about this project. First, they’d already run the comparison I was planning to run myself:</p>

<p>They tested existing ASR and MT systems on these dialects before any fine-tuning and found the pure performance was bad, with fine-tuning helping but not closing the gap evenly.</p>

<p>Interestingly, they found Ifè came out closest to standard Yorùbá, and Ìlàje came out most different, partly because Ìlàje uses letters that don’t even exist in the standard alphabet.</p>

<p>Second, data collection itself was the hard part:</p>

<p>Some dialects barely have a population of fluent writers, so their approach was to record speech first and get native speakers to transcribe it afterward, rather than assuming written data would just be sitting there to find.</p>

<p><img src="/Blog/assets/img/2026-09-01-fine-tuning-nllb-for-ijebu-yoruba-2.jpg" alt="&quot;An Egungun Priest&quot;" /></p>

<p><em>“An Egungun Priest”</em></p>

<p>That last point is worth sitting with. The actual hard, unglamorous part of low-resource NLP isn’t the model.</p>

<p>It’s the fact that someone had to have this idea, travel to specific communities, and do the work of collecting and transcribing dialect data with real speakers.</p>

<p>I’m not doing any of that. I’m standing entirely on top of it. Which is fine, that’s what public research datasets are for, but I want to be upfront that the genuinely hard part of this space already happened before I show up. What I’m doing is a much smaller, more contained question layered on top of their work.</p>

<h2 id="my-experiment">My Experiment</h2>

<p>So the question I actually want to poke at with my own small slice of this: if I take a model that already knows standard Yorùbá, can I nudge it to specifically understand Ìjẹ̀bú? Given their own finding that dialects vary a lot in how much fine-tuning helps, does Ìjẹ̀bú respond well to this, or is the gap stubborn?</p>

<h2 id="what-i-actually-think-is-going-to-happen">what I actually think is going to happen</h2>

<p>Here’s my prediction, written down now so I can’t quietly move the goalposts later:</p>

<ul>
  <li>If I take NLLB (Meta’s translation model, already knows 200+ languages including standard Yorùbá) and just point it at Ìjẹ̀bú with zero extra training, it’ll do noticeably worse than it does on standard Yorùbá. Not useless, but visibly worse.</li>
  <li>If I then fine-tune it on a few hundred Ìjẹ̀bú parallel sentences from YorùLect, that gap should shrink. Not disappear — a few hundred examples is not a lot — but shrink in a way that’s measurable.</li>
</ul>

<p>If neither of those things happen — if zero-shot is already fine, or fine-tuning does nothing — that’s also a real result and I’ll say so.</p>

<h2 id="the-actual-plan">the actual plan</h2>

<ul>
  <li>Model: NLLB-200-distilled-600M. Not the bigger 1.3B/3.3B versions — this one’s small enough to actually train on what I’ve got access to, and it’s what basically every low-resource fine-tuning writeup I’ve read uses for exactly this reason.</li>
  <li>Data: YorùLect’s Ìjẹ̀bú split. Roughly 800 sentences to train on, 200 to check against while training, 500 held back to actually measure performance at the end.</li>
  <li>Metric: BLEU and chrF2, since that’s the standard pair for this kind of MT eval and it’s what most of the papers I’ve been reading report, so I can actually compare.</li>
  <li>Steps: get a standard-Yorùbá baseline running first (so I know my pipeline itself isn’t broken), then run zero-shot on Ìjẹ̀bú, then fine-tune, then compare.</li>
</ul>

<p>I’ve never actually fine-tuned a translation model before, so there’s a real chance week one is just me fighting library versions and tokenizer weirdness before I see a single real number. If so, that’s going in the next post too.</p>

<p>More soon.</p>]]></content><author><name>Daniel Nwogo</name></author><summary type="html"><![CDATA[Motivation]]></summary></entry><entry><title type="html">How I Publish Blogs from Telegram Using Cloudflare and GitHub</title><link href="https://nigerianpickle.github.io/Blog/2026/09/01/how-i-publish-blogs-from-telegram-using-cloudflare-and-githu/" rel="alternate" type="text/html" title="How I Publish Blogs from Telegram Using Cloudflare and GitHub" /><published>2026-09-01T09:14:28-05:00</published><updated>2026-09-01T09:14:28-05:00</updated><id>https://nigerianpickle.github.io/Blog/2026/09/01/how-i-publish-blogs-from-telegram-using-cloudflare-and-githu</id><content type="html" xml:base="https://nigerianpickle.github.io/Blog/2026/09/01/how-i-publish-blogs-from-telegram-using-cloudflare-and-githu/"><![CDATA[<p>I have a lot of things I’ve procrastinated on. Like this blog, like this side project I’m writing. Most of the time it’s some limbic friction I feel. But more often, I think it’s because the processes in my day-to-day life aren’t as streamlined as they could be with AI. There’s a lot AI can do for us, especially in terms of running tasks autonomously.(<a href="https://www.linkedin.com/pulse/how-automate-your-daily-tasks-using-ai-golabstech-idg6e/">I’m not the only one who thinks this way either.</a>)</p>

<p>So I finally put on my engineering hat and started working on this project. The reason I wanted a blog I could publish from Telegram was simple: I wanted to be able to write and publish on my very long commute to work.</p>

<p>So what did I actually need?</p>

<p>A blog that was live, and a way for Telegram to talk to it.</p>

<h2 id="the-problem-structured">The problem, structured</h2>

<p>Before touching any code, the requirement broke down into 3 main concerns:</p>

<p>Constraint 1 (the trigger has to be a chat message)</p>

<p>Since the way I wanted the system to be designed was mostly conversational, since I would be writing this on my commute, on a phone.</p>

<p>Constraint 2 (the site should be easy to manage)</p>

<p>I needed a site with no server to run updates on, no database to back up, and nothing that cost money.</p>

<p>Constraint 3 (the conversational end and blog post needed to communicate)</p>

<p>I needed to come up with a simple protocol for communication between the 2 ends of my system.</p>

<p>After taking some time to think and consulting with over a thousand experts (prompting Claude’s 85,000 MOE), I finally arrived at a solution for each of my constraints.</p>

<h2 id="my-solution">My solution</h2>

<p>For constraint 1 (the trigger):</p>

<p>I used a Telegram bot. Telegram makes it very easy to consult with the BotFather and get a bot created.</p>

<p><img src="/Blog/assets/img/2026-09-01-how-i-publish-blogs-from-telegram-using-cloudflare-and-githu-1.jpg" alt="" /></p>

<p>Telegram’s Bot API supports webhooks natively, so Telegram can push an event to a URL the moment a message arrives, which was perfect. This was exactly what I needed to create a blog conversationally from Telegram.</p>

<p>For constraint 2 (easy site):</p>

<p>The solution for the easy site was sitting right in front of me. I used GitHub Pages running Jekyll with static output. This provided me with free hosting, and made the source of truth just files in a Git repo. That meant “publishing a post” could be reduced to “committing a file”. The process of handling commits has an existing, well-documented API.</p>

<p>For constraint 3 (the connection):</p>

<p>Duh duh duh.</p>

<p>This is where I feel the actual skill sits. The Sprezzatura, the It factor, whatever you may call it.</p>

<p>Point being, this is where the actual engineering decision lived. A webhook needs something listening on a public URL, and I didn’t want to run or pay for a server that sits idle 99% of the time waiting for a commute.</p>

<p>So I needed serverless computers. Cloudflare Workers fit exactly: near-zero cost at low volume, no infrastructure to maintain, and a request/response model that matches what a webhook actually needs.</p>

<p>That decision immediately created a new problem, though, which turned out to be the most interesting part of the build.</p>

<h2 id="state-on-stateless-infrastructure">State on stateless infrastructure</h2>

<p>Serverless compute is stateless by design, so every request gets a fresh context with no memory of the last one.</p>

<p>But for what I wanted, I wanted to create the blog post piece by piece, conversationally. Every part of the blog post isn’t a single request. It’s a conversation: send a title, then an image, then several paragraphs, then confirm.</p>

<p>So what does this mean for my stateless worker? The system has to remember which step you’re on between messages that might arrive minutes apart, and the compute layer handling those messages has no built-in way to remember anything.</p>

<h2 id="hot-fix">Hot Fix!</h2>

<p>The fix, once I actually understood it: the Worker has amnesia after every single message. So instead of trying to remember anything itself, it writes a note to itself in a shared notebook (Cloudflare KV) after every message, and reads that note back before deciding what to do next.</p>

<p>The conversation isn’t held in the Worker’s memory at all.</p>

<p>So where’s the conversation actually living?</p>

<p>In a JSON object sitting in Cloudflare KV, labeled with my Telegram chat ID. That object is just four things: what step I’m on, my title so far, a reference to my header image, and a list of everything I’ve written or sent. Every message, the Worker’s entire job is: read that object, update it based on what I just sent, save it back.</p>

<p>After fixing that, we have our publishing pipeline.</p>

<h2 id="publishing-what-actually-happens">Publishing: what actually happens</h2>

<p>When you confirm a post, the Worker does a sequence of things against GitHub’s Contents API: fetch each image’s bytes from Telegram, commit each one, assemble the markdown and front matter, commit that.</p>

<p>So a single post I write might actually be four or five separate saves happening behind the scenes: one per image, plus one for the post itself.</p>

<p>Every part of my blog is decoupled when my Worker is building it.</p>

<p>Let that stick with you…</p>

<p>There’s no transaction wrapping the whole sequence. If the process fails partway through, you can end up with an orphaned image committed with no post referencing it, and no clean way to resume from where it stopped.</p>

<p>This is a limitation of my system right now, and I think the fix would be a more durable job record written before the calls to the GitHub API start. But that’s next weekend’s problem.</p>

<h2 id="closing">Closing</h2>

<p>It works now. I write on the bus and it’s live by the time I get to my desk at work. There are still some rough edges, but I’m probably going to keep working and refactoring this project</p>

<p><img src="/Blog/assets/img/2026-09-01-how-i-publish-blogs-from-telegram-using-cloudflare-and-githu-2.jpg" alt="My blog haha" /></p>

<p><em>My blog haha</em></p>]]></content><author><name>Daniel Nwogo</name></author><summary type="html"><![CDATA[I have a lot of things I've procrastinated on. Like this blog, like this side project I'm writing. Most of the time it's some limbic friction I feel. But more often, I think it's b]]></summary></entry><entry><title type="html">Haiku to celebrate 200 Commits at 23:04, 14/08/2026</title><link href="https://nigerianpickle.github.io/Blog/2026/08/24/haiku-to-celebrate-200-commits-at-23-04/" rel="alternate" type="text/html" title="Haiku to celebrate 200 Commits at 23:04, 14/08/2026" /><published>2026-08-24T18:13:18-05:00</published><updated>2026-08-24T18:13:18-05:00</updated><id>https://nigerianpickle.github.io/Blog/2026/08/24/haiku-to-celebrate-200-commits-at-23-04</id><content type="html" xml:base="https://nigerianpickle.github.io/Blog/2026/08/24/haiku-to-celebrate-200-commits-at-23-04/"><![CDATA[<p>Four months still to go,</p>

<p>two hundred already logged</p>

<p>Just commit, commit.</p>

<p><img src="/Blog/assets/img/2026-08-24-haiku-to-celebrate-200-commits-at-23-04-1.webp" alt="" /></p>]]></content><author><name>Daniel Nwogo</name></author><summary type="html"><![CDATA[Four months still to go,]]></summary></entry><entry><title type="html">Why growing up can suck</title><link href="https://nigerianpickle.github.io/Blog/2026/08/18/why-growing-up-can-suck/" rel="alternate" type="text/html" title="Why growing up can suck" /><published>2026-08-18T04:53:44-05:00</published><updated>2026-08-18T04:53:44-05:00</updated><id>https://nigerianpickle.github.io/Blog/2026/08/18/why-growing-up-can-suck</id><content type="html" xml:base="https://nigerianpickle.github.io/Blog/2026/08/18/why-growing-up-can-suck/"><![CDATA[<p>As I’ve grown older, I’ve realized that along with losing your physical rigor; there are additional taxes that comes with aging that no one tells you</p>

<p>I’m only 23 and I feel like time is moving way faster than I can keep up with. Both socially, career-wise and mentally. As I grow I older and my responsibilities start to increase, I find myself realizing how little time we have on this planet. People talk about how your 20’s fly, but rarely talk about how 40 years can fly in an instant.</p>

<p>This post isn’t really a doom one and doesn’t really aim to do much, but I want you reading to understand that there is no time. That book you want to write, that project you want to finish, is going nowhere.  Do it, or don’t = nothing is going to change. If you truly want It in you heart, you are going to work ard for it, and it will suck.</p>

<p><img src="/assets/img/2026-08-18-why-growing-up-can-suck-backdrop.jpg" alt="" /></p>]]></content><author><name>Daniel Nwogo</name></author><summary type="html"><![CDATA[As I’ve grown older,..]]></summary></entry><entry><title type="html">Tenshin vs Takeru</title><link href="https://nigerianpickle.github.io/Blog/2026/01/19/tenshin-takeru/" rel="alternate" type="text/html" title="Tenshin vs Takeru" /><published>2026-01-19T17:00:00-06:00</published><updated>2026-01-19T17:00:00-06:00</updated><id>https://nigerianpickle.github.io/Blog/2026/01/19/tenshin%20takeru</id><content type="html" xml:base="https://nigerianpickle.github.io/Blog/2026/01/19/tenshin-takeru/"><![CDATA[<p>Y’all need to watch tenshin takeru. Japanese people love fighting. The fans were going CRAZY!</p>

<p>(https://www.youtube.com/watch?v=H9h-3KvBRww&amp;t=362s)</p>

<p><img src="" alt="" /></p>]]></content><author><name>Daniel Nwogo</name></author><summary type="html"><![CDATA[Japanese fans are crazy dude!]]></summary></entry><entry><title type="html">How to fight.</title><link href="https://nigerianpickle.github.io/Blog/2026/01/03/first-post/" rel="alternate" type="text/html" title="How to fight." /><published>2026-01-03T00:00:00-06:00</published><updated>2026-01-03T00:00:00-06:00</updated><id>https://nigerianpickle.github.io/Blog/2026/01/03/first-post</id><content type="html" xml:base="https://nigerianpickle.github.io/Blog/2026/01/03/first-post/"><![CDATA[<p>How do people fight? do they fight with their heart? or do they fight with their mind?
I belive the sport of fighting is truly a reflection of our day to day lives and when i started this journey i would’ve never thought i would’ve come this far</p>]]></content><author><name>Daniel Nwogo</name></author><summary type="html"><![CDATA[How do people fight? do they fight with their heart? or do they fight with their mind? I belive the sport of fighting is truly a reflection of our day to day lives and when i started this journey i would’ve never thought i would’ve come this far]]></summary></entry></feed>