{"id":202,"date":"2026-03-30T13:41:33","date_gmt":"2026-03-30T10:41:33","guid":{"rendered":"https:\/\/tel-zur.net\/blog\/?p=202"},"modified":"2026-03-30T13:42:49","modified_gmt":"2026-03-30T10:42:49","slug":"unsloth-studio-for-computer-architecture-education","status":"publish","type":"post","link":"https:\/\/tel-zur.net\/blog\/2026\/03\/30\/unsloth-studio-for-computer-architecture-education\/","title":{"rendered":"Unsloth Studio for Computer Architecture education"},"content":{"rendered":"\n<p>The goal of this post is to describe the creation of a fine tuned LLM for assisting students in learning the RISC-V ISA and writing assembly codes. I already developed a RAG system that acts as a smart agent for that. In this article we will explore an alternative approach where we use an existing local LLM and fine tune it into a new LLM model which is suppose to be a better expert in assisting students in RISC-V ISA. This model can be created using the new Unsloth Studio.<\/p>\n\n\n\n<p><strong>Unsloth Studio<\/strong><\/p>\n\n\n\n<p>Unsloth Studio is a new package that can be downloaded from: <a href=\"https:\/\/unsloth.ai\/docs\/new\/studio\">https:\/\/unsloth.ai\/docs\/new\/studio<\/a>. The installation on Linux is straight forward:<\/p>\n\n\n<pre class=\"wp-block-code synano has-header\" data-header=\"Bash\" data-theme=\"default\"><code class=\"language-bash\">curl -fsSL https:\/\/unsloth.ai\/install.sh | sh<\/code><\/pre>\n\n\n<p><strong>The data sources <\/strong><\/p>\n\n\n\n<p>I took a mixture of PDF tutorials and guides and repositories of RISC-V assembly language codes taken from 3 github sites. Using Python scripts the sources were converted into a single <em>jsonl<\/em> format file which is required by Unsloth Studio as a valid dataset. However, in a second round of development I used the <em><strong>recipes<\/strong><\/em> feature of Unsloth Studio to directly import PDF source files and then convert them into a useful dataset.<\/p>\n\n\n\n<p>My computing system is an Ubuntu laptop with core i9 and 32GB RAM and an RTX4060 GPU with 8GB VRAM. Starting Unsloth studio is straight forward:<\/p>\n\n\n<pre class=\"wp-block-code synano has-header\" data-header=\"Bash\" data-theme=\"default\"><code class=\"language-bash\">unsloth studio -H 0.0.0.0 -p 8888<\/code><\/pre>\n\n\n<p><strong>Launching Unsloth Studio<\/strong><\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"515\" src=\"https:\/\/tel-zur.net\/blog\/wp-content\/uploads\/2026\/03\/image-14-1024x515.png\" alt=\"\" class=\"wp-image-208\" srcset=\"https:\/\/tel-zur.net\/blog\/wp-content\/uploads\/2026\/03\/image-14-1024x515.png 1024w, https:\/\/tel-zur.net\/blog\/wp-content\/uploads\/2026\/03\/image-14-300x151.png 300w, https:\/\/tel-zur.net\/blog\/wp-content\/uploads\/2026\/03\/image-14-768x387.png 768w, https:\/\/tel-zur.net\/blog\/wp-content\/uploads\/2026\/03\/image-14.png 1200w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>Point the browser to <a href=\"http:\/\/127.0.0.1:8888\">http:\/\/127.0.0.1:8888<\/a> to access the dashboard.<\/p>\n\n\n\n<p><strong>Start the training<\/strong><\/p>\n\n\n\n<p>I choose as a base LLM model the <em>unsloth\/Qwen3-4B-Instruct-2507<\/em> which fits my hardware constrains. The studio makes use of the GPU as can be seen in the next two screenshots: nvidia-smi and nvtop:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\"><\/blockquote>\n\n\n\n<figure class=\"wp-block-image size-large is-resized\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"540\" src=\"https:\/\/tel-zur.net\/blog\/wp-content\/uploads\/2026\/03\/image-15-1024x540.png\" alt=\"\" class=\"wp-image-210\" style=\"aspect-ratio:1.8963338447954659;width:705px;height:auto\" srcset=\"https:\/\/tel-zur.net\/blog\/wp-content\/uploads\/2026\/03\/image-15-1024x540.png 1024w, https:\/\/tel-zur.net\/blog\/wp-content\/uploads\/2026\/03\/image-15-300x158.png 300w, https:\/\/tel-zur.net\/blog\/wp-content\/uploads\/2026\/03\/image-15-768x405.png 768w, https:\/\/tel-zur.net\/blog\/wp-content\/uploads\/2026\/03\/image-15.png 1200w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"706\" src=\"https:\/\/tel-zur.net\/blog\/wp-content\/uploads\/2026\/03\/Screenshot-from-2026-03-28-12-05-44-1024x706.png\" alt=\"\" class=\"wp-image-211\" srcset=\"https:\/\/tel-zur.net\/blog\/wp-content\/uploads\/2026\/03\/Screenshot-from-2026-03-28-12-05-44-1024x706.png 1024w, https:\/\/tel-zur.net\/blog\/wp-content\/uploads\/2026\/03\/Screenshot-from-2026-03-28-12-05-44-300x207.png 300w, https:\/\/tel-zur.net\/blog\/wp-content\/uploads\/2026\/03\/Screenshot-from-2026-03-28-12-05-44-768x529.png 768w, https:\/\/tel-zur.net\/blog\/wp-content\/uploads\/2026\/03\/Screenshot-from-2026-03-28-12-05-44.png 1200w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p><strong>Creating the dataset<\/strong><\/p>\n\n\n\n<p>I used, an already installed, <em>Ollama<\/em> and a local <em>qwen2.5_7b<\/em> model for this step. In the <em>Document file<\/em> block (see the next figure at the bottom left) I added 8 PDF sources. The complex and delicate part is in the <em>riscv_qa<\/em> block (the bottom right) where the <em>prompt<\/em>, the <em>response format<\/em>, and the <em>instructions<\/em> should be set and optimized. These settings are critical for generating a high quality model that, in principle, is expected to out perform the original LLM.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large is-resized\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"417\" src=\"https:\/\/tel-zur.net\/blog\/wp-content\/uploads\/2026\/03\/image-21-1024x417.png\" alt=\"\" class=\"wp-image-229\" style=\"aspect-ratio:2.4556699193260174;width:768px;height:auto\" srcset=\"https:\/\/tel-zur.net\/blog\/wp-content\/uploads\/2026\/03\/image-21-1024x417.png 1024w, https:\/\/tel-zur.net\/blog\/wp-content\/uploads\/2026\/03\/image-21-300x122.png 300w, https:\/\/tel-zur.net\/blog\/wp-content\/uploads\/2026\/03\/image-21-768x313.png 768w, https:\/\/tel-zur.net\/blog\/wp-content\/uploads\/2026\/03\/image-21.png 1401w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>The next step is to run the workflow and generate the dataset. This step can take a long time. A typical log of this step is shown in the next figure:<\/p>\n\n\n<pre class=\"wp-block-code synano has-header\" data-header=\"\" data-theme=\"default\"><code class=\"language-auto\">[11:52:53 PM] [INFO] Job started\n\n[11:52:53 PM] [INFO] \ud83c\udfa8 Creating Data Designer dataset\n\n[11:52:54 PM] [INFO] \u2705 Validation passed\n\n[11:52:54 PM] [INFO] \u26d3\ufe0f Sorting column configs into a Directed Acyclic Graph\n\n[11:52:54 PM] [INFO] \ud83e\ude7a Running health checks for models...\n\n[11:52:54 PM] [INFO] |-- \ud83d\udc40 Checking &#039;qwen2.5:7b&#039; in provider named &#039;ollama&#039; for model alias &#039;ollama_qwen2.5_7b&#039;...\n\n[11:52:57 PM] [INFO] |-- \u2705 Passed!\n\n[11:52:57 PM] [INFO] \u23f3 Processing batch 1 of 1\n\n[11:52:57 PM] [INFO] \ud83c\udf31 Sampling 200 records from seed dataset\n\n[11:52:57 PM] [INFO] |-- seed dataset size: 2088 records\n\n[11:52:57 PM] [INFO] |-- sampling strategy: shuffle\n\n[11:52:57 PM] [INFO] |-- selection: rows [0 to 10] inclusive\n\n[11:52:57 PM] [INFO] |-- seed dataset size after selection: 11 records\n\n[11:52:57 PM] [INFO] \ud83d\uddc2\ufe0f llm-structured model config for column &#039;riscv_qa&#039;\n\n[11:52:57 PM] [INFO] |-- model: &#039;qwen2.5:7b&#039;\n\n[11:52:57 PM] [INFO] |-- model alias: &#039;ollama_qwen2.5_7b&#039;\n\n[11:52:57 PM] [INFO] |-- model provider: &#039;ollama&#039;\n\n[11:52:57 PM] [INFO] |-- inference parameters:\n\n[11:52:57 PM] [INFO] |  |-- generation_type=chat-completion\n\n[11:52:57 PM] [INFO] |  |-- max_parallel_requests=4\n\n[11:52:57 PM] [INFO] |  |-- timeout=120\n\n[11:52:57 PM] [INFO] |  |-- temperature=0.10\n\n[11:52:57 PM] [INFO] |  |-- top_p=0.90\n\n[11:52:57 PM] [INFO] |  |-- max_tokens=150\n\n[11:52:57 PM] [INFO] \u26a1\ufe0f Processing llm-structured column &#039;riscv_qa&#039; with 4 concurrent workers\n\n[11:52:57 PM] [INFO] \u23f1\ufe0f llm-structured column &#039;riscv_qa&#039; will report progress every 20 records\n\n[11:55:38 PM] [INFO] |-- \ud83d\ude34 llm-structured column &#039;riscv_qa&#039; progress: 20\/200 (10%) complete, 20 ok, 0 failed, 0.12 rec\/s, eta 1452.7s\n\n[11:58:14 PM] [INFO] |-- \ud83d\ude34 llm-structured column &#039;riscv_qa&#039; progress: 40\/200 (20%) complete, 40 ok, 0 failed, 0.13 rec\/s, eta 1270.7s\n\n[12:00:44 AM] [INFO] |-- \ud83e\udd71 llm-structured column &#039;riscv_qa&#039; progress: 60\/200 (30%) complete, 60 ok, 0 failed, 0.13 rec\/s, eta 1091.1s\n\n[12:03:25 AM] [INFO] |-- \ud83e\udd71 llm-structured column &#039;riscv_qa&#039; progress: 80\/200 (40%) complete, 80 ok, 0 failed, 0.13 rec\/s, eta 941.7s\n\n[12:06:02 AM] [INFO] |-- \ud83d\ude10 llm-structured column &#039;riscv_qa&#039; progress: 100\/200 (50%) complete, 100 ok, 0 failed, 0.13 rec\/s, eta 785.5s\n\n[12:08:35 AM] [INFO] |-- \ud83d\ude10 llm-structured column &#039;riscv_qa&#039; progress: 120\/200 (60%) complete, 120 ok, 0 failed, 0.13 rec\/s, eta 625.6s\n\n[12:11:07 AM] [INFO] |-- \ud83d\ude10 llm-structured column &#039;riscv_qa&#039; progress: 140\/200 (70%) complete, 140 ok, 0 failed, 0.13 rec\/s, eta 467.2s\n\n[12:13:40 AM] [INFO] |-- \ud83d\ude0a llm-structured column &#039;riscv_qa&#039; progress: 160\/200 (80%) complete, 160 ok, 0 failed, 0.13 rec\/s, eta 310.9s\n\n[12:16:13 AM] [INFO] |-- \ud83d\ude0a llm-structured column &#039;riscv_qa&#039; progress: 180\/200 (90%) complete, 180 ok, 0 failed, 0.13 rec\/s, eta 155.2s\n\n[12:18:53 AM] [INFO] |-- \ud83e\udd29 llm-structured column &#039;riscv_qa&#039; progress: 200\/200 (100%) complete, 200 ok, 0 failed, 0.13 rec\/s, eta 0.0s\n\n[12:18:54 AM] [INFO] \ud83d\udcca Model usage summary:\n\n[12:18:54 AM] [INFO] |-- model: qwen2.5:7b\n\n[12:18:54 AM] [INFO] |-- tokens: input=134447, output=11209, total=145656, tps=93\n\n[12:18:54 AM] [INFO] |-- requests: success=200, failed=0, total=200, rpm=7\n\n[12:18:54 AM] [INFO] \ud83d\udcd0 Measuring dataset column statistics:\n\n[12:18:54 AM] [INFO] |-- \ud83d\uddc2\ufe0f column: &#039;riscv_qa&#039;\n\n[12:18:55 AM] [INFO] Job completed<\/code><\/pre>\n\n\n<p>Before stating the training process one should associate the dataset columns to roles, e.g. a <em>user<\/em> and an <em>assistant<\/em> in my case &#8211; see next figure:<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"916\" height=\"472\" src=\"https:\/\/tel-zur.net\/blog\/wp-content\/uploads\/2026\/03\/image-20.png\" alt=\"\" class=\"wp-image-225\" srcset=\"https:\/\/tel-zur.net\/blog\/wp-content\/uploads\/2026\/03\/image-20.png 916w, https:\/\/tel-zur.net\/blog\/wp-content\/uploads\/2026\/03\/image-20-300x155.png 300w, https:\/\/tel-zur.net\/blog\/wp-content\/uploads\/2026\/03\/image-20-768x396.png 768w\" sizes=\"auto, (max-width: 916px) 100vw, 916px\" \/><\/figure>\n\n\n\n<p><strong>Model training<\/strong><\/p>\n\n\n\n<p>To start the training process on has to click on <em>Start training<\/em>. The training step is summarized in the next 2 figures:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"660\" src=\"https:\/\/tel-zur.net\/blog\/wp-content\/uploads\/2026\/03\/image-12-1024x660.png\" alt=\"\" class=\"wp-image-203\" srcset=\"https:\/\/tel-zur.net\/blog\/wp-content\/uploads\/2026\/03\/image-12-1024x660.png 1024w, https:\/\/tel-zur.net\/blog\/wp-content\/uploads\/2026\/03\/image-12-300x193.png 300w, https:\/\/tel-zur.net\/blog\/wp-content\/uploads\/2026\/03\/image-12-768x495.png 768w, https:\/\/tel-zur.net\/blog\/wp-content\/uploads\/2026\/03\/image-12.png 1416w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"697\" src=\"https:\/\/tel-zur.net\/blog\/wp-content\/uploads\/2026\/03\/image-22-1024x697.png\" alt=\"\" class=\"wp-image-231\" srcset=\"https:\/\/tel-zur.net\/blog\/wp-content\/uploads\/2026\/03\/image-22-1024x697.png 1024w, https:\/\/tel-zur.net\/blog\/wp-content\/uploads\/2026\/03\/image-22-300x204.png 300w, https:\/\/tel-zur.net\/blog\/wp-content\/uploads\/2026\/03\/image-22-768x522.png 768w, https:\/\/tel-zur.net\/blog\/wp-content\/uploads\/2026\/03\/image-22.png 1198w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p><strong>Testing the new model<\/strong><\/p>\n\n\n\n<p>It is possible to compare, side by side, the original LLM and the new fine tuned model. For that click on <em>compare in chat<\/em>. I compared the model with the following 3 queries:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Explain this instruction: lw x5, 0(x6)<\/li>\n\n\n\n<li>In one short paragraph, generate a RISC-V assembly to add two registers.<\/li>\n\n\n\n<li>Write RISC-V assembly code to be executed on the RARS simulator to compute factorial of a small integer N and print the result N! Just give the code.<\/li>\n<\/ol>\n\n\n\n<p>Screenshots of the 3 replies are shown below. Sadly, one can see that the fine tuned model completely failed in the 3<sup>rd<\/sup> question and it produced similar replies to the original LLM for questions 1 and 2, therefore it seems to be not useful for my educational project.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"955\" height=\"398\" src=\"https:\/\/tel-zur.net\/blog\/wp-content\/uploads\/2026\/03\/image-23.png\" alt=\"\" class=\"wp-image-233\" srcset=\"https:\/\/tel-zur.net\/blog\/wp-content\/uploads\/2026\/03\/image-23.png 955w, https:\/\/tel-zur.net\/blog\/wp-content\/uploads\/2026\/03\/image-23-300x125.png 300w, https:\/\/tel-zur.net\/blog\/wp-content\/uploads\/2026\/03\/image-23-768x320.png 768w\" sizes=\"auto, (max-width: 955px) 100vw, 955px\" \/><\/figure>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"955\" height=\"398\" src=\"https:\/\/tel-zur.net\/blog\/wp-content\/uploads\/2026\/03\/image-24.png\" alt=\"\" class=\"wp-image-234\" srcset=\"https:\/\/tel-zur.net\/blog\/wp-content\/uploads\/2026\/03\/image-24.png 955w, https:\/\/tel-zur.net\/blog\/wp-content\/uploads\/2026\/03\/image-24-300x125.png 300w, https:\/\/tel-zur.net\/blog\/wp-content\/uploads\/2026\/03\/image-24-768x320.png 768w\" sizes=\"auto, (max-width: 955px) 100vw, 955px\" \/><\/figure>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"955\" height=\"454\" src=\"https:\/\/tel-zur.net\/blog\/wp-content\/uploads\/2026\/03\/image-25.png\" alt=\"\" class=\"wp-image-235\" srcset=\"https:\/\/tel-zur.net\/blog\/wp-content\/uploads\/2026\/03\/image-25.png 955w, https:\/\/tel-zur.net\/blog\/wp-content\/uploads\/2026\/03\/image-25-300x143.png 300w, https:\/\/tel-zur.net\/blog\/wp-content\/uploads\/2026\/03\/image-25-768x365.png 768w\" sizes=\"auto, (max-width: 955px) 100vw, 955px\" \/><\/figure>\n\n\n\n<p><strong>Summary<\/strong><\/p>\n\n\n\n<p>The conclusion from this experiment is that the machinery exists and works. However to create a good fine-tuned model one has to invest a lot of effort in creating a high quality data source with a correct mixture of tutorials, examples, and assembly codes. In addition, one has to iterate and tune the <em>prompt<\/em>, the <em>response format<\/em>, and the <em>instructions<\/em>. Although Unsloth Studio has a nice and easy GUI still there is a needed learning curve in order to create a useful tool. Since I already have a working dedicated RAG system that works fine I am not convinced that it is worth the effort to invest more time in creating a superior fine tuned LLM. In any case it was an interesting learning experience and I recommend you to try Unsloth Studio. Perhaps it will fit your specific needs. Good luck!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>The goal of this post is to describe the creation of a fine tuned LLM for assisting students in learning the RISC-V ISA and writing assembly codes. I already developed a RAG system that acts as a smart agent for that. In this article we will explore an alternative approach where we use an existing &hellip; <\/p>\n<p class=\"link-more\"><a href=\"https:\/\/tel-zur.net\/blog\/2026\/03\/30\/unsloth-studio-for-computer-architecture-education\/\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &#8220;Unsloth Studio for Computer Architecture education&#8221;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-202","post","type-post","status-publish","format-standard","hentry","category-uncategorized","entry"],"_links":{"self":[{"href":"https:\/\/tel-zur.net\/blog\/wp-json\/wp\/v2\/posts\/202","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/tel-zur.net\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/tel-zur.net\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/tel-zur.net\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/tel-zur.net\/blog\/wp-json\/wp\/v2\/comments?post=202"}],"version-history":[{"count":30,"href":"https:\/\/tel-zur.net\/blog\/wp-json\/wp\/v2\/posts\/202\/revisions"}],"predecessor-version":[{"id":247,"href":"https:\/\/tel-zur.net\/blog\/wp-json\/wp\/v2\/posts\/202\/revisions\/247"}],"wp:attachment":[{"href":"https:\/\/tel-zur.net\/blog\/wp-json\/wp\/v2\/media?parent=202"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/tel-zur.net\/blog\/wp-json\/wp\/v2\/categories?post=202"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/tel-zur.net\/blog\/wp-json\/wp\/v2\/tags?post=202"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}