<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>alperiox</title><description>blog</description><link>https://alperiox.dev/</link><language>en</language><item><title>Draft Example</title><link>https://alperiox.dev/posts/draft/</link><guid isPermaLink="true">https://alperiox.dev/posts/draft/</guid><pubDate>Fri, 01 Jul 2022 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;This Article is a Draft&lt;/h1&gt;
&lt;p&gt;This article is currently in a draft state and is not published. Therefore, it will not be visible to the general audience. The content is still a work in progress and may require further editing and review.&lt;/p&gt;
&lt;p&gt;When the article is ready for publication, you can update the &quot;draft&quot; field to &quot;false&quot; in the Frontmatter:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;---
title: Draft Example
published: 2024-01-11T04:40:26.381Z
tags: [Markdown, Blogging, Demo]
category: Examples
draft: false
---
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>Training YOLOv9 for Detecting Firearms</title><link>https://alperiox.dev/posts/gelan-firearm/</link><guid isPermaLink="true">https://alperiox.dev/posts/gelan-firearm/</guid><description>Train and deploy YOLOv9</description><pubDate>Thu, 14 Mar 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I try to build some simple projects when new YOLO versions come out. This time, I tried to build a firearm detector.&lt;/p&gt;
&lt;p&gt;As always, the most difficult aspect of training YOLO models is preparing the dataset (at least for me). So this time too, I had too much work to do to prepare the dataset. While checking out datasets in &lt;a href=&quot;https://universe.roboflow.com/&quot;&gt;Roboflow Universe&lt;/a&gt;, I knew that I needed a way to merge different datasets to increase the generalization power of the model. Unfortunately, there wasn&apos;t such a tool in the &lt;a href=&quot;https://supervision.roboflow.com/latest/&quot;&gt;supervision&lt;/a&gt; module so I had to prepare one for myself. [^1] I started by defining some requirements:&lt;/p&gt;
&lt;p&gt;I needed to be able to,&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;merge different datasets&lt;/li&gt;
&lt;li&gt;group similar labels together&lt;/li&gt;
&lt;li&gt;filter the labels that I don&apos;t want to include&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;and finally,&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;datasets must have a similar structure (I picked COCO by default)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;But that wasn&apos;t enough. Since I had picked COCO as my default dataset structure, I needed to transform the merged dataset to YOLO&apos;s supported format to set up the training phase. So, I needed to use COCO&apos;s outdated Python API.&lt;/p&gt;
&lt;p&gt;I have found a rather &lt;a href=&quot;https://github.com/gautamchitnis/cocoapi&quot;&gt;updated version&lt;/a&gt; of it, so forked it and updated the API to make it compatible with my current workflow. (&lt;a href=&quot;https://github.com/alperiox/cocoapi&quot;&gt;my fork&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;Most of the work was done in the dataset preparation, but I was able to implement the functionality to merge datasets while also merging the labels (or filtering the unwanted ones). Check the messy colab notebook &lt;a href=&quot;https://colab.research.google.com/drive/1Sa1f7seL5CmiDl9reh9EAxFlk-LAPR39?usp=sharing&quot;&gt;here&lt;/a&gt; if you&apos;re interested. I plan to wrap it up into a simple script but in the future, please.&lt;/p&gt;
&lt;p&gt;Training the model couldn&apos;t be easier, really. I used &lt;a href=&quot;https://github.com/SkalskiP/yolov9&quot;&gt;Piotr Skalski&apos;s YOLOv9 fork&lt;/a&gt; and simply trained the model for &lt;code&gt;10 epochs&lt;/code&gt; using &lt;code&gt;16 samples&lt;/code&gt; per batch and augmented the training samples using &lt;code&gt;mozaic augmentation&lt;/code&gt; [^2]&lt;/p&gt;
&lt;p&gt;The training results weren&apos;t as bad as I thought!
&lt;img src=&quot;../../assets/gelan-firearm/results.png&quot; alt=&quot;results&quot; /&gt;&lt;/p&gt;
&lt;p&gt;False negatives are critical in this project, as incorrect negative classification might have serious consequences. Thus, while the model had decent precision, having rather lower recall meant that there are impactful amount of false negatives. We can see that from the following confusion matrix as well
&lt;img src=&quot;../../assets/gelan-firearm/confusion_matrix.png&quot; alt=&quot;confusion matrix&quot; /&gt;&lt;/p&gt;
&lt;p&gt;As a result, while the model does a decent job for a model trained in an hour or two, it&apos;s not ready to use in real-life applications where having false negatives would impact peoples lives.&lt;/p&gt;
&lt;h1&gt;TODO: model onnx&apos;e cevrildi, calisiyoda. ama detection pipeline&apos;in duzenlenmesi gerekiyor, ona bakip devam etmek gerek&lt;/h1&gt;
&lt;p&gt;But hey, we can still build a &lt;code&gt;gradio&lt;/code&gt; app to showcase the model! &lt;a&gt;It&apos;s live in huggingface&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;[^1]: there&apos;s a &lt;code&gt;merge&lt;/code&gt; function in the &lt;code&gt;supervision&lt;/code&gt; module, but it&apos;s just doesn&apos;t cover my use case where I want to merge multiple datasets while also filtering the respective &lt;strong&gt;classes&lt;/strong&gt;.
[^2]: Mosaic data augmentation simply combines some training samples into one in certain ratios, it was first introduced in YOLOv4 and it lets model to learn how to identify smaller objects.&lt;/p&gt;
</content:encoded></item><item><title>Simple Guides for Fuwari</title><link>https://alperiox.dev/posts/guide/</link><guid isPermaLink="true">https://alperiox.dev/posts/guide/</guid><description>How to use this blog template.</description><pubDate>Mon, 01 Apr 2024 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;Cover image source: &lt;a href=&quot;https://image.civitai.com/xG1nkqKTMzGDvpLrqFT7WA/208fc754-890d-4adb-9753-2c963332675d/width=2048/01651-1456859105-(colour_1.5),girl,_Blue,yellow,green,cyan,purple,red,pink,_best,8k,UHD,masterpiece,male%20focus,%201boy,gloves,%20ponytail,%20long%20hair,.jpeg&quot;&gt;Source&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This blog template is built with &lt;a href=&quot;https://astro.build/&quot;&gt;Astro&lt;/a&gt;. For the things that are not mentioned in this guide, you may find the answers in the &lt;a href=&quot;https://docs.astro.build/&quot;&gt;Astro Docs&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Front-matter of Posts&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;---
title: My First Blog Post
published: 2023-09-09
description: This is the first post of my new Astro blog.
image: ./cover.jpg
tags: [Foo, Bar]
category: Front-end
draft: false
---
&lt;/code&gt;&lt;/pre&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Attribute&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;title&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The title of the post.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;published&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The date the post was published.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;description&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;A short description of the post. Displayed on index page.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;image&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The cover image path of the post.&amp;lt;br/&amp;gt;1. Start with &lt;code&gt;http://&lt;/code&gt; or &lt;code&gt;https://&lt;/code&gt;: Use web image&amp;lt;br/&amp;gt;2. Start with &lt;code&gt;/&lt;/code&gt;: For image in &lt;code&gt;public&lt;/code&gt; dir&amp;lt;br/&amp;gt;3. With none of the prefixes: Relative to the markdown file&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;tags&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The tags of the post.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;category&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The category of the post.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;draft&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;If this post is still a draft, which won&apos;t be displayed.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2&gt;Where to Place the Post Files&lt;/h2&gt;
&lt;p&gt;Your post files should be placed in &lt;code&gt;src/content/posts/&lt;/code&gt; directory. You can also create sub-directories to better organize your posts and assets.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;src/content/posts/
├── post-1.md
└── post-2/
    ├── cover.png
    └── index.md
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>Markdown Extended Features</title><link>https://alperiox.dev/posts/markdown-extended/</link><guid isPermaLink="true">https://alperiox.dev/posts/markdown-extended/</guid><description>Read more about Markdown features in Fuwari</description><pubDate>Wed, 01 May 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;GitHub repository cards&lt;/h2&gt;
&lt;p&gt;You can add dynamic cards that link to GitHub repositories, on page load, the repository information is pulled from the GitHub API.&lt;/p&gt;
&lt;p&gt;::github{repo=&quot;Fabrizz/MMM-OnSpotify&quot;}&lt;/p&gt;
&lt;p&gt;Create a GitHub repository card with the code &lt;code&gt;::github{repo=&quot;&amp;lt;owner&amp;gt;/&amp;lt;repo&amp;gt;&quot;}&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;::github{repo=&quot;saicaca/fuwari&quot;}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Admonitions&lt;/h2&gt;
&lt;p&gt;Following types of admonitions are supported: &lt;code&gt;note&lt;/code&gt; &lt;code&gt;tip&lt;/code&gt; &lt;code&gt;important&lt;/code&gt; &lt;code&gt;warning&lt;/code&gt; &lt;code&gt;caution&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;:::note
Highlights information that users should take into account, even when skimming.
:::&lt;/p&gt;
&lt;p&gt;:::tip
Optional information to help a user be more successful.
:::&lt;/p&gt;
&lt;p&gt;:::important
Crucial information necessary for users to succeed.
:::&lt;/p&gt;
&lt;p&gt;:::warning
Critical content demanding immediate user attention due to potential risks.
:::&lt;/p&gt;
&lt;p&gt;:::caution
Negative potential consequences of an action.
:::&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;:::note
Highlights information that users should take into account, even when skimming.
:::

:::tip
Optional information to help a user be more successful.
:::
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The title of the admonition can be customized.&lt;/p&gt;
&lt;p&gt;:::note[MY CUSTOM TITLE]
This is a note with a custom title.
:::&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;:::note[MY CUSTOM TITLE]
This is a note with a custom title.
:::
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;[!TIP]
&lt;a href=&quot;https://github.com/orgs/community/discussions/16925&quot;&gt;The GitHub syntax&lt;/a&gt; is also supported.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;&amp;gt; [!NOTE]
&amp;gt; The GitHub syntax is also supported.

&amp;gt; [!TIP]
&amp;gt; The GitHub syntax is also supported.
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>Markdown Example</title><link>https://alperiox.dev/posts/markdown/</link><guid isPermaLink="true">https://alperiox.dev/posts/markdown/</guid><description>A simple example of a Markdown blog post.</description><pubDate>Sun, 01 Oct 2023 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;An h1 header&lt;/h1&gt;
&lt;p&gt;Paragraphs are separated by a blank line.&lt;/p&gt;
&lt;p&gt;2nd paragraph. &lt;em&gt;Italic&lt;/em&gt;, &lt;strong&gt;bold&lt;/strong&gt;, and &lt;code&gt;monospace&lt;/code&gt;. Itemized lists
look like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;this one&lt;/li&gt;
&lt;li&gt;that one&lt;/li&gt;
&lt;li&gt;the other one&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Note that --- not considering the asterisk --- the actual text
content starts at 4-columns in.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Block quotes are
written like so.&lt;/p&gt;
&lt;p&gt;They can span multiple paragraphs,
if you like.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Use 3 dashes for an em-dash. Use 2 dashes for ranges (ex., &quot;it&apos;s all
in chapters 12--14&quot;). Three dots ... will be converted to an ellipsis.
Unicode is supported. ☺&lt;/p&gt;
&lt;h2&gt;An h2 header&lt;/h2&gt;
&lt;p&gt;Here&apos;s a numbered list:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;first item&lt;/li&gt;
&lt;li&gt;second item&lt;/li&gt;
&lt;li&gt;third item&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Note again how the actual text starts at 4 columns in (4 characters
from the left side). Here&apos;s a code sample:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# Let me re-iterate ...
for i in 1 .. 10 { do-something(i) }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you probably guessed, indented 4 spaces. By the way, instead of
indenting the block, you can use delimited blocks, if you like:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;define foobar() {
    print &quot;Welcome to flavor country!&quot;;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;(which makes copying &amp;amp; pasting easier). You can optionally mark the
delimited block for Pandoc to syntax highlight it:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import time
# Quick, count to ten!
for i in range(10):
    # (but not *too* quick)
    time.sleep(0.5)
    print i
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;An h3 header&lt;/h3&gt;
&lt;p&gt;Now a nested list:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;First, get these ingredients:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;carrots&lt;/li&gt;
&lt;li&gt;celery&lt;/li&gt;
&lt;li&gt;lentils&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Boil some water.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Dump everything in the pot and follow
this algorithm:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; find wooden spoon
 uncover pot
 stir
 cover pot
 balance wooden spoon precariously on pot handle
 wait 10 minutes
 goto first step (or shut off burner when done)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Do not bump wooden spoon or it will fall.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Notice again how text always lines up on 4-space indents (including
that last line which continues item 3 above).&lt;/p&gt;
&lt;p&gt;Here&apos;s a link to &lt;a href=&quot;http://foo.bar&quot;&gt;a website&lt;/a&gt;, to a &lt;a href=&quot;local-doc.html&quot;&gt;local
doc&lt;/a&gt;, and to a &lt;a href=&quot;#an-h2-header&quot;&gt;section heading in the current
doc&lt;/a&gt;. Here&apos;s a footnote [^1].&lt;/p&gt;
&lt;p&gt;[^1]: Footnote text goes here.&lt;/p&gt;
&lt;p&gt;Tables can look like this:&lt;/p&gt;
&lt;p&gt;size material color&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;9 leather brown
10 hemp canvas natural
11 glass transparent&lt;/p&gt;
&lt;p&gt;Table: Shoes, their sizes, and what they&apos;re made of&lt;/p&gt;
&lt;p&gt;(The above is the caption for the table.) Pandoc also supports
multi-line tables:&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;keyword text&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;red Sunsets, apples, and
other red or reddish
things.&lt;/p&gt;
&lt;p&gt;green Leaves, grass, frogs
and other things it&apos;s
not easy being.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;A horizontal rule follows.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Here&apos;s a definition list:&lt;/p&gt;
&lt;p&gt;apples
: Good for making applesauce.
oranges
: Citrus!
tomatoes
: There&apos;s no &quot;e&quot; in tomatoe.&lt;/p&gt;
&lt;p&gt;Again, text is indented 4 spaces. (Put a blank line between each
term/definition pair to spread things out more.)&lt;/p&gt;
&lt;p&gt;Here&apos;s a &quot;line block&quot;:&lt;/p&gt;
&lt;p&gt;| Line one
| Line too
| Line tree&lt;/p&gt;
&lt;p&gt;and images can be specified like so:&lt;/p&gt;
&lt;p&gt;Inline math equations go in like so: $\omega = d\phi / dt$. Display
math should get its own line and be put in in double-dollarsigns:&lt;/p&gt;
&lt;p&gt;$$I = \int \rho R^{2} dV$$&lt;/p&gt;
&lt;p&gt;And note that you can backslash-escape any punctuation characters
which you wish to be displayed literally, ex.: `foo`, *bar*, etc.&lt;/p&gt;
</content:encoded></item><item><title>RAG for Q&amp;A with PDFs</title><link>https://alperiox.dev/posts/rag-pdf-qna/</link><guid isPermaLink="true">https://alperiox.dev/posts/rag-pdf-qna/</guid><description>Use Gemini to answer questions using a PDF as the knowledge store</description><pubDate>Fri, 07 Jun 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;In order to improve my Upwork profile a little, I grabbed the most successful freelancers in AI and checked their projects. One of them was building a retrieval system for question answering with PDFs, so here we are.&lt;/p&gt;
&lt;p&gt;I always lean on cloud providers when it comes to LLMs. This time too, I used Gemini with GCP. The project was rather simple, I needed to construct vector database, fetch documents and use them in the prompt that will generate the real answer. I also needed a graphical interface so I had to choose between Gradio or Streamlit.&lt;/p&gt;
&lt;p&gt;My toolset was pretty simple, &lt;a href=&quot;https://www.langchain.com/&quot;&gt;Langchain&lt;/a&gt; for utilizing the LLM and setting up the retrieval system and &lt;a href=&quot;https://streamlit.io/&quot;&gt;Streamlit&lt;/a&gt; for the user interface. I defined several variables to store the session data in &lt;a href=&quot;https://streamlit.io/&quot;&gt;Streamlit&lt;/a&gt;, specifically for storing the path of currently selected PDF, the list of uploaded documents, currently loaded vector store, and for the retrieval system.&lt;/p&gt;
&lt;p&gt;I simply created a new Chroma vector database when a document is uploaded for the first time, the documents were splitted to chunks of &lt;code&gt;1000&lt;/code&gt; characters and the embeddings were calculated using &lt;a href=&quot;https://cloud.google.com/vertex-ai&quot;&gt;VertexAI&lt;/a&gt;s embedding model, &lt;code&gt;textembedding-gecko&lt;/code&gt;. The database was also stored in the filesystem with a random &lt;code&gt;uuid&lt;/code&gt;. Loading the corresponding database when it&apos;s selected in the user interface was simple, the important thing was to set up the LLM chain successfully so we could retrieve the data from the database. And thankfully it was also easy thanks to &lt;a href=&quot;https://www.langchain.com/&quot;&gt;Langchain&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;And in the end, here&apos;s the finished version of it:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/rag-pdf-qna/image.png&quot; alt=&quot;chatting with pdfs 1&quot; /&gt;
&lt;img src=&quot;../../assets/rag-pdf-qna/image-1.png&quot; alt=&quot;chatting with pdfs 2&quot; /&gt;&lt;/p&gt;
&lt;p&gt;The project is not deployed on anywhere, but is &lt;a href=&quot;https://github.com/alperiox/rag-pdf-qna&quot;&gt;available on github&lt;/a&gt;.&lt;/p&gt;
</content:encoded></item><item><title>TinyAya Expedition: S2S Translation from a Text Backbone?</title><link>https://alperiox.dev/posts/tinyaya-expedition-retrospective/</link><guid isPermaLink="true">https://alperiox.dev/posts/tinyaya-expedition-retrospective/</guid><description>A retrospective on building a Turkish-Hindi speech-to-speech translation model from scratch — the decisions we made, the ones we got wrong, and what we would do differently.</description><pubDate>Fri, 10 Jul 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I had the chance to lead an expedition team in TinyAya Expedition of Cohere, here&apos;s my experience on building a Turkish - Hindi speech to speech translation model, from scratch (?).&lt;/p&gt;
&lt;h2&gt;The Premise&lt;/h2&gt;
&lt;p&gt;I was pretty interested in Speech to Speech models and was thinking of working on some more modeling in my spare time, while looking around for what to build, I saw TinyAya Expedition; an expedition where teams are trying to build something out of TinyAya models. The model doesn&apos;t support multimodality but supports 70+ languages, so figured it&apos;d be a fun project to try to make it S2S.&lt;/p&gt;
&lt;p&gt;Thankfully when I proposed the project there were some people that are interested in it, so we met, tried to come up with a plan, and then started working. Since our members were either Hindi or Turkish, we picked those two for our translation task.&lt;/p&gt;
&lt;p&gt;The question was if a text-only multilingual model would learn speech-to-speech translation without explicit and massive audio pre-training beforehand. We picked translation because we wanted it to have a purpose, and was curious if TinyAya&apos;s language support would help it learn the task.&lt;/p&gt;
&lt;p&gt;Our plan was pretty simple though, adapt Moshi&apos;s architecture, swap the backbone with TinyAya, generate data and then train!&lt;/p&gt;
&lt;p&gt;Applying the plan though... wasn&apos;t so simple.&lt;/p&gt;
&lt;h2&gt;1: The Codec Dead End&lt;/h2&gt;
&lt;p&gt;Our first major decision was whether to fine-tune Mimi (Moshi&apos;s audio codec) on Hindi/Turkish speech or use it off-the-shelf.&lt;/p&gt;
&lt;p&gt;So we spent some time on benchmarking several codecs, tried finetuning Mimi (Moshi&apos;s codec), DualCodec, and while there were several more codecs on our list, we weren&apos;t able to finish benchmarking all of them. Mainly because we were busy with our daily work, the expedition was a side project, after all.&lt;/p&gt;
&lt;p&gt;Though at the end, we couldn&apos;t see any marginal improvement on our target languages when we tried finetuning Mimi and DualCodec. While i&apos;m sure our training setup wasn&apos;t optimized for increasing their performance on the languages we picked, the diminishing results from the training indicated we&apos;re already good to go with the base Mimi:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Codec&lt;/th&gt;
&lt;th&gt;OOD STOI&lt;/th&gt;
&lt;th&gt;OOD PESQ-wb&lt;/th&gt;
&lt;th&gt;OOD DNSMOS&lt;/th&gt;
&lt;th&gt;Verdict&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Base Mimi&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.921&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;3.31&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;2.87&lt;/td&gt;
&lt;td&gt;Best generalization&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fine-tuned Mimi&lt;/td&gt;
&lt;td&gt;0.825&lt;/td&gt;
&lt;td&gt;2.27&lt;/td&gt;
&lt;td&gt;2.76&lt;/td&gt;
&lt;td&gt;Overfitted, degraded&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DualCodec&lt;/td&gt;
&lt;td&gt;0.881&lt;/td&gt;
&lt;td&gt;2.40&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;2.95&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Best perceptual, worst signal&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;Decision:&lt;/strong&gt; Use base Mimi unmodified. This was the right call — it also meant Moshiko&apos;s pretrained depth decoder weights worked without adaptation. So... less parameters to optimize.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What we&apos;d do differently:&lt;/strong&gt; Skip the codec fine-tuning entirely. The quality we were getting from the base codecs were good-enough already and we neither had training compute nor time to work on the project exhaustively. We should have recognized this from the start and saved the time.&lt;/p&gt;
&lt;h2&gt;2: Data Generation — Cheap but Messy&lt;/h2&gt;
&lt;p&gt;No TR&amp;lt;-&amp;gt;HI parallel speech corpus exists, so we built one. This part actually worked well — eventually.&lt;/p&gt;
&lt;h3&gt;TTS Model Selection&lt;/h3&gt;
&lt;p&gt;We evaluated four TTS models: XTTSv2, Chatterbox, Fish Speech, and OmniVoice.&lt;/p&gt;
&lt;p&gt;Our setup was simple, collect Turkish or Hindi text from online datasets or generate the text -&amp;gt; translate using Command from Cohere if we don&apos;t have the Turkish&amp;lt;-&amp;gt;Hindi pair -&amp;gt; generate speech -&amp;gt; check the generated speech.&lt;/p&gt;
&lt;p&gt;The best decision was using Vast.ai, apparently it&apos;s possible to manage bunch of instances through an api key, so with limited scopes, it&apos;s also possible to come up with a simple MCP that manages these instances and get you the cheapest instances possible, I have a small mcp server for it, so we used that one: &lt;a href=&quot;https://github.com/alperiox/vast-mcp&quot;&gt;vast-mcp&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I guess the second best decision here was using OmniVoice voice design, it supports structured text descriptions like &lt;code&gt;[gender]female[pitch]moderate[accent]Indian&lt;/code&gt; so it was possible to expand our dataset to variety of speakers. We had tried simple voice cloning but it was fairly slow compared to designing the voice. But it had its setbacks too, some text descriptions we&apos;ve used throughout the data generation was producing erroneous samples pretty frequently.&lt;/p&gt;
&lt;p&gt;At the end, we designed 14 voice profiles and deployed 42 Vast.ai GPU instances, cost ~$50 for 911 hours and 1.3M clips of data.&lt;/p&gt;
&lt;h3&gt;Quality Control&lt;/h3&gt;
&lt;p&gt;Of course since we&apos;re generating synthetic data, we had to come up with a quality control mechanism, we built &lt;a href=&quot;https://github.com/tiny-aya-simultaneous-translation/sound-quality-check&quot;&gt;sound-quality-check&lt;/a&gt;, a simple round-trip ASR validation pipeline: generate audio → transcribe back with Whisper → compare against original text. 86% pass rate. The 14% failures concentrated in extreme voice designs (&lt;code&gt;male_old_deep&lt;/code&gt; had the highest rejection rate) and very long sentences.&lt;/p&gt;
&lt;h2&gt;3: Architecture — Getting the Details Wrong&lt;/h2&gt;
&lt;p&gt;The architecture itself (Moshi-style three-stream with TinyAya backbone) was sound. The implementation had bugs, because debugging all those stuff after my 12+ hr shifts were a bit tiring, honestly. Here are some of the bugs we found out and fixed along the way:&lt;/p&gt;
&lt;h3&gt;The Off-by-One That Looked Fine&lt;/h3&gt;
&lt;p&gt;The composite model&apos;s depth decoder position mapping was initially wrong: position 0 (text prediction) was matched against CB0 targets. Total training loss was 0.007 — looked perfect. But per-codebook accuracy revealed every single codebook was misaligned by one position. Aggregate metrics hid a fundamental bug.&lt;/p&gt;
&lt;h3&gt;The Silent Collator Drop&lt;/h3&gt;
&lt;p&gt;The batch collator silently dropped &lt;code&gt;user_audio_codes&lt;/code&gt; and &lt;code&gt;model_audio_codes&lt;/code&gt; during batching. Training fell back to single-stream mode with &lt;code&gt;model_audio_embed&lt;/code&gt; receiving zero gradients. We completed an entire test run before discovering this. But that&apos;s why we have test runs, right?&lt;/p&gt;
&lt;h2&gt;4: Multi-GPU Training — FSDP Hell&lt;/h2&gt;
&lt;p&gt;We went through &lt;strong&gt;8 distinct FSDP checkpoint failures&lt;/strong&gt; before save/load/resume worked especially in TPUs:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;model_audio_embed&lt;/code&gt; not included in the checkpoint&lt;/li&gt;
&lt;li&gt;FSDP shards saved instead of full tensors (needed &lt;code&gt;summon_full_params&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;save_pretrained&lt;/code&gt; calling allgather on rank 0 only (all ranks must participate)&lt;/li&gt;
&lt;li&gt;Optimizer state not gathered properly (needed &lt;code&gt;full_optim_state_dict&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Resume loading model weights &lt;em&gt;after&lt;/em&gt; FSDP wrapping (must load &lt;em&gt;before&lt;/em&gt;)&lt;/li&gt;
&lt;li&gt;Audio demo generation causing NCCL timeout (rank 0 doing inference while rank 1 waits)&lt;/li&gt;
&lt;li&gt;HuggingFace Hub push causing rank desync&lt;/li&gt;
&lt;li&gt;Disk filling up during training (no checkpoint pruning)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Each of these caused a failed training run. Some lost hours of compute; one filled a 2TB disk.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The core lesson:&lt;/strong&gt; With FSDP, &lt;em&gt;any&lt;/em&gt; operation that touches model parameters must involve all ranks. Logging, saving, pushing, generating samples — anything that only runs on rank 0 will deadlock the other ranks. We eventually wrote a &lt;code&gt;validate_full_pipeline.sh&lt;/code&gt; that tests train → save → load → forward → resume → save → compare. This should have existed before the first real training run.&lt;/p&gt;
&lt;h2&gt;5: TPU Training — A Different Kind of Pain&lt;/h2&gt;
&lt;p&gt;The TPU adaptation (for Google TRC-granted v6e chips) introduced a new class of issues:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;4-hour backward compile:&lt;/strong&gt; &lt;code&gt;scan_layers&lt;/code&gt; TypeError on &lt;code&gt;torch_xla 2.9&lt;/code&gt; forced a manual loop fallback, which meant XLA couldn&apos;t fuse the backward pass. First backward step: 4 hours 25 minutes. After the fix: ~25 minutes.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;IP quota exhaustion:&lt;/strong&gt; v6e-64 (8-host slice) needs exactly 8 external IPs, hitting GCP&apos;s 8-IP regional limit. We pivoted to single-host v6e-8 to avoid multi-host complexity entirely.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Attention mask NaN:&lt;/strong&gt; v6e bf16 turned &lt;code&gt;-inf&lt;/code&gt; attention mask values into NaN. Fix: clamp masks to &lt;code&gt;&amp;gt;= -1e4&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;No TPU memory reporting:&lt;/strong&gt; &lt;code&gt;torch_xla&lt;/code&gt; memory info returns None. We had no visibility into HBM usage until Mayank added per-chip telemetry.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;What we&apos;d do differently:&lt;/strong&gt; Start with single-host TPU from the beginning. Multi-host XLA introduces an entirely separate class of problems (FSDPv2 sharding, IP quotas, multi-host rendezvous). Single-host v6e-8 was sufficient and avoided all of this.&lt;/p&gt;
&lt;h2&gt;Why TPUs though?&lt;/h2&gt;
&lt;p&gt;Duh, we didn&apos;t have any GPU compute. I was going to train that model regardless of the compute type, we found TPUs so we supported TPUs.&lt;/p&gt;
&lt;h2&gt;6: The Text Stream Revelation&lt;/h2&gt;
&lt;p&gt;Honestly not much of a revelation, available text stream would carry over some information regarding to the speech tokens, Moshi&apos;s paper calls this the &quot;inner monologue&quot; — a parallel text stream that anchors the model&apos;s hidden states in language meaning.&lt;/p&gt;
&lt;p&gt;But one of our buggy runs helped us to validate it, we didn&apos;t have text alignments in the training run, so the model fell back to audio-only loss and yeah, that didn&apos;t help at all.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Run&lt;/th&gt;
&lt;th&gt;Text Loss&lt;/th&gt;
&lt;th&gt;Audio Loss&lt;/th&gt;
&lt;th&gt;Text Acc&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Broken (no alignments)&lt;/td&gt;
&lt;td&gt;12.51 (random)&lt;/td&gt;
&lt;td&gt;6.1 (plateaued)&lt;/td&gt;
&lt;td&gt;0%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Working (with alignments)&lt;/td&gt;
&lt;td&gt;7.2&lt;/td&gt;
&lt;td&gt;6.03&lt;/td&gt;
&lt;td&gt;learning&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;This was later confirmed at scale: Mayank&apos;s v0.3 sweep on the full 1.24M corpus showed text accuracy reaching 77% (ppl ~3.25) after just 1 epoch, with audio still improving. The model nearly solved text prediction while audio was still catching up — exactly what you&apos;d expect if TinyAya&apos;s multilingual text knowledge was transferring.&lt;/p&gt;
&lt;h2&gt;The Autoregressive Evaluation Bug&lt;/h2&gt;
&lt;p&gt;During pipeline validation for the production run, an off-by-one was found in &lt;code&gt;eval_checkpoint.py&lt;/code&gt;: the AR loop read &lt;code&gt;hidden[t]&lt;/code&gt; (which predicts position t+1 under the training convention) but wrote the token at position t. Every generated frame was shifted one position AND conditioned on a placeholder token.&lt;/p&gt;
&lt;p&gt;This means every AR/ASR-BLEU number previously reported understated actual quality. The bug lived only in the evaluation harness — the model and training pipeline were never affected.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Lesson:&lt;/strong&gt; For the love of god, please, please validate AI agent&apos;s results.&lt;/p&gt;
&lt;h2&gt;What We Got Right&lt;/h2&gt;
&lt;p&gt;Despite the failures, the core hypothesis held:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Moshi&apos;s architecture is modular.&lt;/strong&gt; The depth decoder transferred across backbones without retraining. This means teams can focus compute on the temporal backbone and reuse pretrained acoustic modeling.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Data generation scales cheaply.&lt;/strong&gt; $50 for 911 hours using OmniVoice voice design mode. The bottleneck is compute for training, not data.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Text-only backbones can learn audio.&lt;/strong&gt; TinyAya went from zero audio experience to 27% CB0 accuracy on the full corpus — 544x above random chance — in one epoch.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;The text stream provides real semantic grounding.&lt;/strong&gt; 77% text accuracy after 1 epoch confirms that TinyAya&apos;s multilingual knowledge transfers to the audio modality.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;What Remains Open&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Translation quality hasn&apos;t emerged yet.&lt;/strong&gt; The model learns language identity (Hindi output for TR→HI, Turkish for HI→TR) but sentence-level translation hasn&apos;t been verified at scale. The 3-epoch production run should answer this.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Uniform vs Whisper alignments.&lt;/strong&gt; We generated uniform alignments (words spread evenly across duration) as a quick fix. Whisper-based word-level timestamps would be more accurate for natural-sounding TTS output. The current results show uniform alignments work, but we don&apos;t know how much better Whisper-based would be.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The D+E combination.&lt;/strong&gt; The sweep winner (arm D: LoRA on all 36 layers) and runner-up (arm E: stronger regularization) were never tested together. This is the obvious next hyperparameter probe.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;The Real Lesson&lt;/h2&gt;
&lt;p&gt;The biggest time sink wasn&apos;t any single bug — it was the compounding effect of silent failures. The collator dropping tensors, the text padding drowning real signal, the alignment data missing from the upload, the AR evaluation off-by-one. Each one looked fine from the outside. Loss was decreasing. No errors in the logs. Everything appeared to work.&lt;/p&gt;
&lt;p&gt;Almost all of us were using AI agents to write the pieces of the code for us. While coding ourselves, our intuition about the subject helps us tremendously while finding out bugs and errors along the pipeline, your agent doesn&apos;t have that. It doesn&apos;t know what to validate, what to check, and how to check. The suggestions it comes up within its loop doesn&apos;t make sense at times.&lt;/p&gt;
&lt;p&gt;I think this kind of supports the idea of AI being just a tool, while it helps tremendously, it doesn&apos;t have the unconscious intuition you have about the subject, so without validating the steps, or without installing validation steps along the way, it loses it somewhere in the loop. Without knowing the correct validation steps, or little sanity checks, I&apos;d lose it too, though.&lt;/p&gt;
</content:encoded></item><item><title>I built GPT from scratch (a very, very small version of it)</title><link>https://alperiox.dev/posts/transformers-from-scratch/</link><guid isPermaLink="true">https://alperiox.dev/posts/transformers-from-scratch/</guid><description>I wanted to understand how these stuff work, internally, so I built transformers from scratch with just PyTorch.</description><pubDate>Sun, 21 Jul 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I was following Andrej Karpathy&apos;s wonderful series about deep learning on YouTube when I saw the videos about implementing GPT and GPT-2. Just how cool is that?&lt;/p&gt;
&lt;p&gt;To be honest, I was pretty excited to get there since I always wanted to dive deeper into such concepts. I&apos;ll try to explain how this stuff works internally in this piece, hopefully with some visualizations as well.&lt;/p&gt;
</content:encoded></item><item><title>Include Video in the Posts</title><link>https://alperiox.dev/posts/video/</link><guid isPermaLink="true">https://alperiox.dev/posts/video/</guid><description>This post demonstrates how to include embedded video in a blog post.</description><pubDate>Tue, 01 Aug 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Just copy the embed code from YouTube or other platforms, and paste it in the markdown file.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;---
title: Include Video in the Post
published: 2023-10-19
// ...
---

&amp;lt;iframe width=&quot;100%&quot; height=&quot;468&quot; src=&quot;https://www.youtube.com/embed/5gIf0_xpFPI?si=N1WTorLKL0uwLsU_&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allowfullscreen&amp;gt;&amp;lt;/iframe&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;YouTube&lt;/h2&gt;
&lt;p&gt;&amp;lt;iframe width=&quot;100%&quot; height=&quot;468&quot; src=&quot;https://www.youtube.com/embed/5gIf0_xpFPI?si=N1WTorLKL0uwLsU_&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; allowfullscreen&amp;gt;&amp;lt;/iframe&amp;gt;&lt;/p&gt;
&lt;h2&gt;Bilibili&lt;/h2&gt;
&lt;p&gt;&amp;lt;iframe width=&quot;100%&quot; height=&quot;468&quot; src=&quot;//player.bilibili.com/player.html?bvid=BV1fK4y1s7Qf&amp;amp;p=1&quot; scrolling=&quot;no&quot; border=&quot;0&quot; frameborder=&quot;no&quot; framespacing=&quot;0&quot; allowfullscreen=&quot;true&quot;&amp;gt; &amp;lt;/iframe&amp;gt;&lt;/p&gt;
</content:encoded></item><item><title>Personal Protective Equipment detection with YOLOv10</title><link>https://alperiox.dev/posts/yolov10-ppe-detection/</link><guid isPermaLink="true">https://alperiox.dev/posts/yolov10-ppe-detection/</guid><description>Fine-tune and deploy YOLOv10 for detecting PPE!</description><pubDate>Wed, 29 May 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://colab.research.google.com/drive/1dCGbqEEylMX6bhj70rINF6QCuMIVcvbC?usp=sharing&quot;&gt;Colab Notebook for training&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://arxiv.org/pdf/2405.14458&quot;&gt;Paper&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;As always, I built a simple model as the new YOLO version came out. This time, it was personal protective equipment detection.&lt;/p&gt;
&lt;p&gt;The YOLOv10&apos;s modeling approach is just so cool! We usually get multiple assignments per instance in the given object, resulting in a one-to-many mapping. While this approach results in more supervisory signals, it also introduces inefficiencies in inference. Because we would need to apply an algorithm like &lt;a href=&quot;https://towardsdatascience.com/non-maximum-suppression-nms-93ce178e177c&quot;&gt;NMS&lt;/a&gt; to filter out redundant predictions.&lt;/p&gt;
&lt;p&gt;So... YOLOv10 included a one-to-one mapping head to the model along with a one-to-many head. The authors introduce a &lt;strong&gt;consistent matching metric&lt;/strong&gt; to quantitatively assess the level of concordance between predictions and instances, this metric also includes two hyperparameters. Then they derived a metric from the &lt;a href=&quot;https://en.wikipedia.org/wiki/Wasserstein_metric&quot;&gt;Wasserstein-1&lt;/a&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Wasserstein_metric&quot;&gt;metric&lt;/a&gt; including the &lt;strong&gt;consistent matching metric&lt;/strong&gt; to determine the supervision gap between two heads.&lt;/p&gt;
&lt;p&gt;And in the end, it was possible to optimize the one-to-one head in the direction of the one-to-many head&apos;s optimization. Because the derived distance converges to 0 as the one-to-one head&apos;s prediction goes up in the ranks of one-to-many head&apos;s outputs. If they also choose the &lt;strong&gt;consistent matching metric&lt;/strong&gt;&apos;s hyperparameters well, then mathematically the best output from one-to-many is the best for one-to-one as well. This means that they can train the model using richer signals from one-to-many head and optimize the one-to-one head as well. This approach removes the need for &lt;a href=&quot;https://towardsdatascience.com/non-maximum-suppression-nms-93ce178e177c&quot;&gt;NMS&lt;/a&gt; in the inference phase, reducing the potential performance drawbacks.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/yolov10-ppe/architecture.png&quot; alt=&quot;model architecture&quot; /&gt;&lt;/p&gt;
&lt;p&gt;I wanted to highlight a few things before moving on to my project. Because damn, training YOLO models are easy. Like really, really easy. Often, the most cumbersome part of the project is the data preparation phase, which is also much easier thanks to &lt;a href=&quot;https://universe.roboflow.com/&quot;&gt;Roboflow Universe&lt;/a&gt;. So all you need to do is pick a dataset, download it in YOLO format, and run the training script.&lt;/p&gt;
&lt;p&gt;Well, I just... did that too. Picked a dataset for PPE detection and ran the training script. I usually convert the model to ONNX before trying to deploy it, it was the same this time too. I prepared a simple demo as a &lt;a href=&quot;https://huggingface.co/spaces/alperiox/yolov10-ppe-detection&quot;&gt;Huggingface Space&lt;/a&gt;. The training was pretty successful, as I trained the model with default hyperparameters for just 20 epochs.&lt;/p&gt;
&lt;h3&gt;Results&lt;/h3&gt;
&lt;p&gt;It&apos;s easy to see that predicting a bounding box when the person doesn&apos;t have a glove, goggles, hard hat, mask or safety vest introduces a difficulty in predicting other labels. I think that&apos;s because there would be multiple similar bounding boxes with different labels.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/yolov10-ppe/image.png&quot; alt=&quot;alt text&quot; /&gt;&lt;/p&gt;
&lt;p&gt;I can imagine why &lt;code&gt;Mask&lt;/code&gt;s are often confused with &lt;code&gt;NO-Hardhat&lt;/code&gt; boxes, probably because of the data labeling part. When I checked the initial dataset, I could see there are similar images where &lt;code&gt;Mask&lt;/code&gt; or &lt;code&gt;NO-Hardhat&lt;/code&gt; labels both fit well. Like:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Mask&lt;/th&gt;
&lt;th&gt;NO-Hardhat&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;img src=&quot;../../assets/yolov10-ppe/image-1.png&quot; alt=&quot;two masked people&quot; /&gt;&lt;/td&gt;
&lt;td&gt;&lt;img src=&quot;../../assets/yolov10-ppe/image-2.png&quot; alt=&quot;a masked person&quot; /&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Like, &lt;code&gt;NO-Hardhat&lt;/code&gt; could be easily determined as &lt;code&gt;Mask&lt;/code&gt; by a human like me. So I don&apos;t put it on the algorithm.&lt;/p&gt;
&lt;p&gt;In the end, the model trained well but I think it could use some more training steps. I&apos;m happy with the results though.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../assets/yolov10-ppe/image-3.png&quot; alt=&quot;training results&quot; /&gt;&lt;/p&gt;
</content:encoded></item></channel></rss>