Showing posts with label AI. Show all posts
Showing posts with label AI. Show all posts

Tuesday, May 19, 2026

FinOps Beyond Cloud: Flagging Which LLM Path Runs

It’s 2026, and I pretend less that coding stops at merge. Plans still matter, but margin (revenue minus cost) matters too: if usage jumps, many users pile onto cheap tiers, or ARPU (average revenue per user) stays low, is your default technical path still affordable?

If you tilt product-minded, you often want costs and revenue to steer behavior—not just quarterly decks—and you ship guardrails (limits and alerts for spend and risk) plus metrics so typo fixes aren’t casually riding flagship AI tiers.

This post is a relaxed tour of one slice of that: treating cloud and model spend as something you design for, not something you discover on the invoice.

1. What a product-minded engineer optimizes beyond “merged”

Shipped is rarely the final step. The sharper test: multiply usage, push traffic through loss-leader tiers—does profitability still behave?

Checklist framing:

  1. Costs and revenue should sway day-to-day decisions.
  2. Use the cheapest good-enough path first; expensive models owe you justification.
  3. Add observability (logs/metrics showing what paths ran in prod) early so invoices don’t become the dashboard.

2. A profitability-aware seam—not just “flip the rollout switch”

Cost-aware feature flagging is more than switching release trains. (Feature flags toggle behavior remotely without reinstalling everywhere.) Core question shifts to:

For this payer plus this job step, does calling the pricey model earn its keep right now?

Two halves:

Inputs (FinOps-style facts): tooling that exposes spend (AWS Pricing CalculatorOpenCost), quotas (vendor-enforced caps), subscription revenue—not only beta_user=true.

Outputs: same outward job, staged execution—offline libraries; lighter Gemini Flash-class SKU; heavier Pro-class SKU when needed; delay/batch—not one greedy lane dialing the richest model every hop. (SKU or "Stock Keeping Unit" is vendor shorthand for a priced product bundle—the name on the invoice.)

Treat it like authentication (auth—checking who acts) guarding expensive work—but margin sits beside permission.


3. Models answer prompts—they don’t run budgets

A reader might ask whether frontier models magically cheap-route some of the simpler work.

Simply said: No. They optimize outputs within the SKU you bought; no accountants live there. You pick SKU tiers—they chase quality inside that sandbox. Toss a heavyweight tier at a petty job and it still replies, while metering charges requests, not vibes.

Operational decisions stay yours: routing (offline versus vendor lane), backoff (pause before retries when throttled), and hard-stop retry budgets. Models themselves won’t politely refund spend.


4. Total cost of ownership (TCO)—dashboards versus sloppy lanes

(TCO = total cost of ownership) includes quiet extras—not only billed tokens—like wrong tier ladders, retry storms, consolation “redo” generations after junk answers.

Log routing branch, approximate tokens (what vendors bill on) before stray heavyweight completions overshadow dashboard cost. Procurement warning ahead: illustrative magnitudes only—junk routing has landed teams roughly two to four orders of magnitude (~100×–10,000×) hotter than guarded paths.

Prefer modest telemetry before invoices swell.


5. From toy splitter to nearer-production routers

Toy setup uses HTTP POST /v1/check with JSON { text, task } and tasks spellcheck or summarize.

Environment COST_OPTIMIZATION_ENABLED when on triggers Typo.js (open-source English spellchecking) plus an extractive summary (reuses existing sentences—invents nothing).

When offGemini 2.5 Flash (Google positions this as its lighter SKU string gemini-2.5-flash) owns both passes.

Closer to prod, swap the simple “if-this-then-that” rules for nuanced routing plus subscription and billing knobs—still feeding FinOps signals.


6. Sampling experiment—methods first; numbers follow

This section lays out (1) what mechanically reran, (2) tables in later subsections, (3) how extrapolation pencils out—lab notebook plus spreadsheet honesty, not magic.

6.1 What reran—and what got skipped deliberately

Bench here means scripted automation issuing the same deterministic requests.

Ran: fabricated multi-section write-up (~290 words) with sequential jobs (spellcheck then summarize). Express route POST /v1/check. Flag COST_OPTIMIZATION_ENABLED jointly toggles offline Typo stack versus Gemini 2.5 Flash via @google/genai. Then a script prints timings plus playful dollar placeholders—not accounting truth.

Skipped: proportional live traffic mixtures, randomized A/B tests (A/B: compare flows across user subsets)—this isolate covers mechanism, not population behavior.

Driving question stays:

Holding document shape steady and accepting cheaper summaries, how many vendor completions vanish?

Extrapolation (spoken plainly):

Rough monthly dollars skipped ≈ (cloud completions you avoided) × (realistic dollars per completion).

Assume each workflow run equals the spell+summarize pair (two HTTP POSTs)—linear scaling versus monthly runs. Lock those two POSTs/run, multiply by how many drafts, audits, or refactors fire monthly.

6.2 Head-to-head results (the sample)

MetricOptimization ONOptimization OFF
Requests22
Offline routes20
Cloud (Gemini)02
Avg latency (ms)~2378~4788
Placeholder session total$0.000000$0.000230

The session total is only the demo knobs COST_CLOUD_SPELLCHECK + COST_CLOUD_SUMMARY in server.js—fine for a workshop, not a bill.

Plain-language takeaway for this slice: optimization on skipped every Gemini invocation that off made for these two tasks (0 vs 2 calls → 100% avoidance for this pair only). Tradeoff: extractive bullets and a full-file dictionary pass are cheap, but the spell step can land around a few seconds on a long draft (~4.7s on the first spellcheck request in my run), while the offline summary stayed single-digit ms.

6.3 Projecting to volume (drafts, edits, audits, refactors)

Illustrative token sketch—same Flash-style guesses baked into the benchmark (~2200 / 2000 in/out for the long corrective pass, ~2200 / 450 for exec summary, $0.15/M in and $0.60/M out; verify Gemini pricing). Think of a run as one time you execute spellcheck + summarize on a body—e.g. a new draft, a heavy edit, an audit pass that re-queues the pair, or a refactor that rewrites a section and re-runs the tooling.

ItemOptimization ON (this demo)Optimization OFF (all Gemini for these two tasks)
Cloud calls / month @ 5k runs (2 POSTs per run)010,000
Order-of-magnitude API $ / month~$0~$10.65
Avoided vs all-cloud at that volume (token model only)~$10.65

Scale the numerator: at 50k runs/month—stacking draft cycles, revision rounds, audit and compliance re-checks, refactors, anything that replays this two-step cloud path—the same all-cloud token math lands near ~$106/month for that slice alone—before you add any new AI feature. The cost-aware pattern is convincing here because the growth lever is obvious: more passes through the pipeline ⇒ more invocations ⇒ the same percentage of avoided calls buys proportionally more dollars as activity grows.

6.4 Where product growth quietly multiplies cost (features, not just users)

Users rarely stop at “spellcheck + summary.” Roadmaps add adjacent model tasks: e.g. AI glossary (“explain this acronym for a non-security exec”), keyword callouts next to the summary, a risk-language nudgeemail-ready rewrite, or second-pass tightening. If each is implemented as another always-on Gemini call, you get multiplication: two cloud tasks become three, four, five—each time someone runs the flow—while routing stays an afterthought.

A cost-aware seam doesn’t mean shipping worse product; it means deciding per task (plan tier, cache, template, small model, batch, human review) instead of defaulting “new AI affordance ⇒ new flagship invocation.” The bench only models two tasks, but the projection mental model extends: every new task is a coefficient on monthly variable spend unless you fold it into the same router.

6.5 Why this is still a convincing case for the approach

  1. The sample isolates mechanism: you can see exactly which HTTP paths hit the model when the flag flips—no mystery meat in “optimization.”
  2. Volume makes small per-call numbers real: ~$0.00107/POST on the all-cloud token estimate at 10k calls/month is easy to shrug off until draft/edit/audit/refactor volume (and features) push you to 100k+ calls.
  3. Feature creep is the hidden multiplier: routing discipline is how you ship more AI-shaped surface area without linear-to-cloud spend on every new button.


Please note: The playground code for server.js is at the bottom of this post. The post treats that run as a sample you can scale with your own monthly pipeline volume—how often teams hit spellcheck + summarize across drafts, edits, audits, refactors, and so on—and your task list. Dollar figures mix placeholder session costs and illustrative token mathabsolute savings scale with users, calls per run, model tier, and how many new AI features stay cloud-default—plug in real metering before treating any number as financial guidance.


require('dotenv').config();
const express = require('express');
const { GoogleGenAI, ApiError } = require('@google/genai');
const Typo = require('typo-js');

const app = express();
app.use(express.json());

const dictionary = new Typo('en_US');

const genai = new GoogleGenAI({
    apiKey: process.env.GEMINI_API_KEY,
});

/** Placeholder $ per cloud call (tune for FinOps demos; real bills use metering). */
const COST_CLOUD_SPELLCHECK = Number(process.env.COST_CLOUD_SPELLCHECK) || 0.00005;
const COST_CLOUD_SUMMARY = Number(process.env.COST_CLOUD_SUMMARY) || 0.00018;

/** Correct spelling per word; preserves whitespace and punctuation (en_US). */
function correctWithTypo(text) {
    return text.replace(/\b[\w']+\b/g, (word) => {
        if (dictionary.check(word)) return word;
        const suggestion = dictionary.suggest(word)[0];
        return suggestion || word;
    });
}

/** Cheap path: lead sentences + pseudo-bullets (no API). */
function extractiveExecutiveSummary(text) {
    const t = text.trim().replace(/\s+/g, ' ');
    const sentences = t.split(/(?<=[.!?])\s+/).filter((s) => s.length > 15);
    const head = sentences.slice(0, 4).join(' ');
    const base =
        head.length >= 200 ? head : t.slice(0, Math.min(1200, t.length)) + (t.length > 1200 ? '…' : '');
    const lines = base
        .split(/(?<=[.!?])\s+/)
        .filter(Boolean)
        .slice(0, 5)
        .map((s) => `- ${s.trim()}`);
    return lines.join('\n');
}

let sessionTotalCost = 0;

function isTruthyEnv(name) {
    const v = process.env[name];
    if (v == null) return false;
    return /^(1|true|yes)$/i.test(String(v).trim());
}

/** Pull a readable message out of SDK errors (often `message` is stringified JSON). */
function geminiErrorDetail(err) {
    const msg = err && typeof err.message === 'string' ? err.message : String(err);
    try {
        const parsed = JSON.parse(msg);
        const inner = parsed && parsed.error ? parsed.error : parsed;
        if (inner && typeof inner.message === 'string') {
            return { summary: inner.message, code: inner.code, status: inner.status };
        }
    } catch (_) {
        /* use raw */
    }
    return { summary: msg };
}

app.post('/v1/check', async (req, res) => {
    const { text, task } = req.body ?? {};
    if (typeof text !== 'string' || !text.trim()) {
        return res.status(400).json({ error: 'Body must include non-empty string `text`.' });
    }
    if (task !== 'spellcheck' && task !== 'summarize') {
        return res.status(400).json({
            error: 'Body must include `task`: "spellcheck" | "summarize".',
        });
    }

    const isOptimizationOn = isTruthyEnv('COST_OPTIMIZATION_ENABLED');
    const words = text.trim().split(/\s+/);

    let output = '';
    let engine = '';
    let cost = 0;

    try {
        if (task === 'spellcheck') {
            if (isOptimizationOn) {
                if (words.length <= 5) {
                    output = correctWithTypo(text);
                    engine = 'Offline (Typo.js)';
                } else {
                    output = correctWithTypo(text);
                    engine = 'Offline (Typo.js full document)';
                }
                cost = 0;
            } else {
                const model = process.env.GEMINI_MODEL || 'gemini-2.5-flash';
                const response = await genai.models.generateContent({
                    model,
                    contents: [
                        'You correct spelling and obvious typos only. Preserve structure, headings, and meaning. Reply with the full corrected text only—no preamble or quotes.',
                        `Document:\n${text}`,
                    ].join('\n\n'),
                });
                const raw = response.text;
                if (raw == null || !String(raw).trim()) {
                    throw new Error('Empty response from model');
                }
                output = String(raw).trim();
                engine = `Cloud spellcheck (${model})`;
                cost = COST_CLOUD_SPELLCHECK;
            }
        } else {
            // summarize → executive summary
            if (isOptimizationOn) {
                output = extractiveExecutiveSummary(text);
                engine = 'Offline (extractive executive summary)';
                cost = 0;
            } else {
                const model = process.env.GEMINI_MODEL || 'gemini-2.5-flash';
                const response = await genai.models.generateContent({
                    model,
                    contents: [
                        'Condense the report into an executive summary for leadership: 3–5 bullet points, plain text, each line starting with "- ". Be factual; do not invent risks or metrics.',
                        `Report:\n${text}`,
                    ].join('\n\n'),
                });
                const raw = response.text;
                if (raw == null || !String(raw).trim()) {
                    throw new Error('Empty response from model');
                }
                output = String(raw).trim();
                engine = `Cloud summary (${model})`;
                cost = COST_CLOUD_SUMMARY;
            }
        }

        sessionTotalCost += cost;
        console.log(`[${new Date().toISOString()}] task=${task} Engine: ${engine} | Cost: $${cost}`);

        res.json({
            task,
            output,
            engine,
            stats: { sessionTotal: sessionTotalCost.toFixed(6) },
        });
    } catch (error) {
        if (error instanceof ApiError) {
            const { summary, code, status: bodyStatus } = geminiErrorDetail(error);
            const httpStatus =
                typeof error.status === 'number' && error.status >= 400 && error.status <= 599
                    ? error.status
                    : 502;
            console.error('[Gemini ApiError]', httpStatus, summary);
            const label =
                httpStatus === 429
                    ? 'Gemini quota or rate limit (check plan / AI Studio quotas)'
                    : 'Gemini API error';
            return res.status(httpStatus).json({
                error: label,
                details: summary,
                geminiCode: code,
                geminiStatus: bodyStatus,
            });
        }
        console.error('[Report pipeline]', error);
        res.status(500).json({ error: 'System Error', details: error.message });
    }
});

const PORT = Number(process.env.PORT) || 3000;

const server = app.listen(PORT);
server.once('listening', () => {
    console.log(`Report spellcheck + executive summary API on port ${PORT}`);
});
server.once('error', (err) => {
    console.error('Server failed to start:', err.code === 'EADDRINUSE' ? `port ${PORT} is already in use` : err.message);
    process.exit(1);
});



Monday, April 20, 2026

Local AI on an M1 Pro: From "Post-Apocalyptic" Slowness to a Functional Reality

We’ve all seen headlines like this: "The end of paid coding assistants!" or "Run your own private AI locally for free!" As someone who values privacy and hates the dependency on monthly subscriptions, I decided to see if my trusty MacBook Pro (M1 Pro, 32GB RAM) could become my trustworthy coding workstation.

My journey started with a massive failure, moved through a "thinking" loop, and finally landed on a configuration that actually works. Here is how I turned my Mac into a functional local coding station.

(Yeah... I’ve reached the stage where I won’t bother with perfect screenshots. If I need to show the output of my fun tinkering on an isolated machine, I’ll just take a blurry photo of the screen with my old phone. It’s much more relaxed that way.)



Phase 1: The "Heavyweight" Disaster with "Qwen 3.5 Coder Next"

I started ambitious. Installing Ollama was the simplest part. Then I pulled Qwen 3.5 Coder Next. I thought 32GB of RAM would be enough. I was wrong.

The Experience:

  • Initial 'Hi': 25 seconds.

  • Coding Task: 7+ minutes to generate just some initial instructions and start writing the variables section for an Arduino script.

  • The Culprit: My logs showed the model needed 51.3 GiB of memory. Since I only have 32GB, Ollama had to shove 26GB of the "brain" onto my CPU.


The long wait after a simple "Hi".

 

The painful 7+ minutes of waiting while watching the slow code generation and seeing my computer's memory heavily consumed.



Phase 2: The "Thinking" Trap with "Qwen 3.5 9B"

I pivoted to a smaller model: Qwen 3.5 9B. On paper, this should have been lightning fast. However, I ran into a new hurdle: Reasoning Loops.

Even with the smaller 9B model, the "Reasoning/Thinking" phase was taking forever—sometimes up to 7 minutes of "thinking" without a single line of code being written. At one point, it even got caught in a logical loop, and I had to restart the process.

A lot of thinking for 7+ minutes and no action but much less memory consumption.



Phase 3: The Breakthrough (The "Nothink" Secret)

The real "Aha!" moment came when I realized I didn't need the model to spend several minutes pondering the meaning of life for a simple Arduino script. I just needed the code.

I used a simple command to bypass the heavy reasoning phase: >>> /set nothink

The difference was huge:

  • Total Response Time: 2 minutes and 28 seconds for a complete, complex answer.

  • Content Quality: It wasn't just code. It gave me prerequisites, circuit wiring, full Arduino code, security tips, and even improvement ideas.

  • Memory Efficiency: The logs show this model is a perfect fit for the M1 Pro. It only used about 9.1 GiB of total memory, meaning 100% of the model layers (33/33) stayed on the GPU (Metal).

This time, with 'nothink', it was spitting out the answer much faster.



Technical Insights from the Logs

If you are troubleshooting your own local setup, here is what I learned from the Ollama server logs:

  1. Check your Offloading: In my successful 9B run, the logs said: offloaded 33/33 layers to GPU. This is the ideal case. If that number isn't 100%, your performance will be affected.

  2. Flash Attention is King: The logs confirmed enabling flash attention. This helps the Mac handle long conversations without slowing down.

  3. The "Unified" Advantage: My M1 Pro was able to allocate a recommendedMaxWorkingSetSize of ~26GB. By using the 9B model (which only needs ~9GB), I left plenty of room for my system to breathe.


The Verdict: Is it a "Free" Coding Assistant?

Is a "free" local coding assistant possible? Yes—but resources matters. If you try to run massive models on a 32GB Mac, you'll feel like you're back in the era of dial-up.

If this continues to feel this good, I’m considering the ultimate "pro" move: Using this Mac as a headless AI server. I can connect it to a secure network and put it away on a shelf and connect to its "brain" from my other computers for chatting or from within VS Code (with the suitable plugin's of course) or even my phone. My main coding machine stays cool and quiet, while the M1 Pro does all the heavy lifting in the background.

I hope that my little weekend experiment has helped you in any way with insights or inspiration to set on your own journey of finding your own AI independence.


Tuesday, April 7, 2026

The Rise of the Product Engineer: Title Trend or New Reality?

 

This career topic has been on my mind for a while, and I've been trying to collect more information about it for my own career's sake. And now I think I have an idea clear enough to be shared. I hope it benefits someone out there.

The "Product Engineer" title has exploded in popularity this year. This shift is happening for three main reasons:

  • AI-Assisted Coding: Since AI can now handle basic coding tasks, companies need engineers who can move "above" the code to control the requirements (inputs) and the architecture (outputs).

  • Flatter Teams: Tech companies are removing middle layers, requiring engineers to be more independent.

  • Faster Delivery: To move quickly, the line between "thinking about the product" and "writing the code" must disappear.

However, after talking to managers, recruiters, and "Product Engineers", I realized that not everyone defines this role the same way. Here are the three main types of "Product Engineers" I have observed:

1. The "Label Switch" (Product in Name Only)

In these companies, the title is just a marketing trick. They swapped the word "Software" for "Product," but nothing else changed.

  • The Reality: Whether you are a junior or a senior, your job is the same as a traditional "heads-down" coder.

  • The Hiring Process: The interview is 100% technical. They don't assess your business knowledge or how you think about users.

  • The Day-to-Day: You receive a ticket, you code it, and you move on. The "product" part is just a fancy new sticker on your LinkedIn profile. You might negotiate the requirements or the sequence of shipping things with your PM, but that's the same thing as the past decades in any small to medium startup. Nothing new.

2. The Product-Minded Engineer

This is a more mature approach, often seen in tech companies with a transparent and flexible management style. Here, the engineer is a partner to the Product Manager (PM).

  • The Reality: Mid-level and senior engineers are expected to help improve requirements, not just follow them. There is a heavy focus on customer value over "tech talk."

  • The Hiring Process: Interviews include a specific section to discuss how you’ve solved user problems, how you collaborate with designers, and how you interact with the PMs in earlier stages.

  • The Day-to-Day: About 10% of your time is spent on product strategy. You are a pragmatist who knows when to choose a "good enough" technical solution to help the user faster. However, the PM still holds the final accountability for the roadmap.

3. The "Part-Time PM" Engineer

This is the most intense version of the role and the unicorn of that job title. These companies need someone who can lead a project from a blank page to a finished product.

  • The Reality: You are essentially a Product Manager who also writes code. You are responsible for the "Why" and the "How."

  • The Hiring Process: Be prepared for deep questions about product frameworks, data analysis, and user research. They want to see if you can lead a squad of engineers.

  • The Day-to-Day: You participate in ideation, talk to stakeholders, and conduct user interviews. You shape the work for the rest of the team and ensure the technical output matches the business goals perfectly. Expect extra accountabilities with this version.


Conclusion

The software industry is moving away from "coding as a service" toward "problem-solving as a service." Depending on the company, a Product Engineer can be a simple developer or a business leader. If you are looking for this role, make sure to ask during the interview: "How much influence do I actually have over the 'Why' of the product? And am I actually accountable for any decision made?"

Monday, October 1, 2018

Week 7 Reloaded - Fine-tuning VGG16 model for CIFAR-10 dataset

Week 7 is the last week of this deep-learning plan. And I didn’t want to finish before trying a bit more to have better results. So here we go again.

This time I learned two things: Google Colaboratory and Lambda layer. Those two have helped me refactor my code in two notebooks to get better results.

Google Colaboratory

Because my computer was so slow to process such dataset, I didn’t have the luxury of experimenting with models and hyperparameters. So one obvious step was to look for an online solution to process my python code with an acceptable speed. Google Colaboratory was a nice and free solution that fitted my needs.

If you haven’t used it before, here is a nice tutorial
This processing power allowed me to rerun a previous notebook to train my own CNN for CIFAR-10 dataset. But for 100 epochs instead of only 15. This allowed me to see how my model was performing well enough to reach an accuracy of 82.68%. (compared to 74.53% with 15 epochs)

You can find the whole python notebook for my own model on Github here.

Fine-tuning VGG16 model

Now that I had Google Colaboratory, I could try a huge number of changes in different hyperparameters and layers customization. After a couple of days of trying, I could get a maximum accuracy of 73.33%. (compared to 68.03% with less tinkering).

This was the maximum test accuracy I could get. After that, the model was just overfitting to reach 90 something % training accuracy and no test accuracy improvement. I could go further and inject normalization and dropout layers. But that was enough for me for that part of my homework.

I could also solve my problem of not having enough memory to resize all the data and having to use part of it. This was possible by using a Lambda layer as an input and use it to Reshape every batch. Another solution was to use ImageDataGenerator. But I didn’t have to use it for now.

You can find the whole python notebook for a customization of VGG16 on Github here.

What’s next

Instead of spending more time tinkering with an existing model to reach a result that I could reach easier with my own model, I thought it is not worth it. Of course I already achieved the purpose of this homework to recycle an existing model and adapt it to my needs. Now it was time to move on.

Next is to find a real-world problem and work on it with real-world data to achieve an acceptable solution. And this new solution should not only be a quick and dirty bunch of python files, but rather a proper project with coding standards and a user-friendly interface. This way, I can learn even more and sharpen my skills.


Resources:

Sunday, September 23, 2018

Week 7 - Transfer learning with VGG16 model and CIFAR-10 dataset

Here I come to the 7th and final week of the initial plan to start working with deep learning. This week’s assignment was to use an existing CNN to learn the CIFAR-10 dataset. The VGG16 model was chosen for me to try. It was a quite interesting assignment to find some problems I will probably be facing again in the future.

Let’s talk about what I did this week.

You can find the whole python notebook on Github here.

My images are small


This was the first problem I faced. According to the Keras documentation, the model takes a minimum size of 32px. But actually when I tried, it was a minimum of 48px. But my dataset had images of size 32px. So I had to resize the images. This turned out to take more time that expected. There were a few solutions for resizing such data. And to find a suitable and less complicated solution, it took me quite some time to read the documentation of each one and try it.


My computer is a humble one

Not only did I have to resize the images -which was the easy part with integers- but I also had to convert the data type to float32 and normalize the data. This resizing task was not that easy for my computer after the the conversion to float32. That’s why -and after many times of a dead ipython kernel- I ended up using only one third of the training data and converting the data in batches.

The error was always:

Allocation of X exceeds 10% of system memory.

This was not even a large set of data, but I should start looking into learning about more optimized methods of processing such data.

How to reuse the VGG16 model?

Now getting to the step of reusing the model, I faced the question of how to reuse it. There were 4 options depending on the data I have and the data the model used initially for training. You can learn more about the options here: http://cs231n.github.io/transfer-learning/.

For my case, I assumed that the CIFAR-10 data is similar enough to the ImageNet data used for training the VGG16 model. So I used the model as a fixed feature extractor and I only added the fully connected layers at the end to classify 10 classes instead of 1000.

The long wait for results

Now that I’ve solved the initial problems of preparing the data and the model, I started the training for the output layer of the model. This took about 4 hours. And after the wait, the test accuracy was 68% compared to 87.77% training accuracy. :( I already had a better accuracy last week (74.53%) using my own network.

The sad end of the day

This was a sad result after a long time of waiting and restarting the computer a few times. But I believe that I should get used to this as a fundamental part of this data life. Now I have to find out the reason behind the result.

  • Was it overfitting related to the model?
  • Was it because the data was not enough?
  • Or was it because my images were smaller that what the network was trained for?
  • Do I have to fine-tune the model more?
Whatever the reason is, I will have to start by finding a quicker computer/cloud solution to make it easier to test any theory.

What’s next

The next step was to find a bigger real-world data set to play with it. But given the performance I had on my computer, my next step will be looking for an affordable cloud solution to train my models. This way I can put more time into learning and trying instead of spending half a day or even a whole day to test one theory. And I also want to investigate this not-so-large array resizing problem.


Resources:

Tuesday, September 11, 2018

Week 5/6 - Convolutional neural network (CNN) with CIFAR-10 dataset

Here I am in Week 5&6 of my mentor’s plan to practice deep-learning and start solving real problems. This time, my homework was about designing another CNN like the previous week but with the CIFAR-10 dataset.

At first, I was intimidated and thought that I really sucked and that I cannot really move on by myself. But Which I think was close to being true. :D But after several hours of looking closely at the dataset and reading the Keras documentation, I started to find results! Here they are.

You can find the whole python notebook on Github here.

UPDATE: I reran the code but for 100 epochs and could reach a 82.68% accuracy. The notebook is found here.

The accuracy I could get this time compared to previous MNIST homework reminded me of the difference between my 9X% results at school compared to the embarrassing university’s results :D

Anyways. I could get an accuracy of 74.53%. This already required a lot of time to train on my humble computer with no GPU (I think about 2 hours). That’s why I only have one model in my notebook this time. That’s because it took a lot of time to test a single model, so I decided to try something crazy; waiting for only one epoch to finish and looking at the resulting accuracy. If it was not so promising, I stop the process and try with a different design and so on. At the end, I decided to let the current one proceed till the end and see the result.

After reaching this number, I thought it is time to look online at how people solve such a problem. And then I found that link: https://github.com/BIGBALLON/cifar-10-cnn#accuracy-of-all-my-implementations

That person could also reach an accuracy of 76.27% at first with -I think- a known network that noobs like me don’t know yet. Then he had to go for more complicated and more famous networks to get much better results. Of course, the training time with a GPU was so scary; going for a day or even two.

What’s next


The conclusion of this week actually proves how good the plan I am following is. Because now I can see how complicated and time consuming it is to solve such a problem with small images and only 10 classes. That’s why next week of the plan is “transfer learning”. So I have to use an existing network (VGG16) and adapt it to my dataset to have better results.



Saturday, September 8, 2018

Week 2/3/4 - Convolutional neural network (CNN) with MNIST dataset

Week 2 of my deep learning plan was to train a convolutional network using the MNIST dataset. The intent is to learn the basics of convolutional networks. Instead of writing the code of my homework here again, I will only link to it on Github and speak about my experience with it here.

You can find the whole python notebook on Github here.
This homework was the fist step of feeling not like the hello-world example in week 1. The first step was to load the MNIST data like before, analyzing the data and curating it before processing. It was not complicated but it was a nice start to realizing how important this step is for deciding how to design the network.

Next was the mix of confusion and fun. It was basically about looking for the reasonable number of hidden layers and number of filters per layer. After finding the ‘popular’ numbers for such a problem (what if my problem is a personal/custom one? back to that later in the future inshallah), it was time to try differt depths and different values for hyperparameters like dropout and filters. This was actually a boring and a time consuming step. Just to try some basic variations, I had to keep my computer running for about 4 hours. And I didn’t even try so many variations (only 7 variations).

The results were fine and I could reach an accuracy of 99.32% compared to 98.48% in my previous feedforward assignment.

Week 3 & 4


Week 3 & 4 were actually about playing with hyperparameters and optimization. So it was somehow included in my current assignment. I could get a taste of how they can affect the results and how I should give a considerable time, changing and observing the effects of such parameters and deciding which parameters can introduce an accuracy improvement.



Week 1 - Feedforward network with MNIST dataset

Week 1 of the plan was to train a feedforward network using the MNIST dataset. This is probably the easiest and most straightforward example to understand how the training cycle goes.

Before starting, I should mention that the code for this week -and the other weeks too- was not written from scratch by me. And that’s the main difference between school and work. It treated this homework the same way I treat work. I can google what I want and understand/refactor it. It can also be about reading about a specific network and understanding the recommended range of values for a specific parameter or the recommended layers structure.

This time, it was too simple that I copied the code and started playing with it to understand how it works. And as we move forward in the weeks, I had to write more myself. Consider it a Hello World week. Now lets see the code!

You can find the whole python notebook on Github here.
Resources:

Week 0 - Jupyter notebook with Keras and Tensorflow

Starting with my deep-learning learning plan, I wanted to have a good development environment. This meant having a Docker image that can work on any device I am using with no extra setup needed. My choice was to use Keras with Tensorflow core for an easy start with not so many unwanted details at this step. I also chose to use Jupyter notebook to have a nice interface to trace/explain my code along with graphs and output numbers.

The following is my finalized Dockerfile with the latest versions which worked exactly how I wanted it.


# To build the container
# docker build -t jupyter-keras .
# To run the container:
# docker run -it -v /$(pwd)/:/home/jovyan/work -p 8888:8888 jupyter-keras:latest start-notebook.sh --NotebookApp.token=''

# To access the notbook from the browser:
# http://localhost:8888/tree

# To login in to the server:
# docker exec -it  /bin/bash

# To check Keras version:
# python -c 'import keras; print(keras.__version__)'

FROM jupyter/scipy-notebook

MAINTAINER Gaarv <@Gaarv1911>

USER root

# bash instead of dash to use source
RUN ln -snf /bin/bash /bin/sh

USER jovyan

RUN pip install --upgrade pip \
  && pip install --upgrade tensorflow \
  && pip install --upgrade --no-deps git+git://github.com/keras-team/keras.git \
&& pip install --upgrade --no-deps h5py

Tuesday, September 4, 2018

A deep-learning plan from a mentor

I’ve been learning machine learning by myself for a long time. From one Coursera specialization to a course to a YouTube playlist. But then I felt the problem with starting. I am learning the theory with some basic applications, but I don’t know how to go on by myself and start a project and analyze the data and find the correct structure and find-tune the parameters and so on…

Then came to me the old idea one more time; I need a mentor who knows how such professional life works and what really matters more. And after some searching and asking, I found one through a friend of a friend of a friend. And then she contacted me and offered help.

 

 And after explaining to her what I know and what I want in life from this exercise, she formulated a plan for me. So here I am posting it.

Week 1: Feedforward networks


A good start is the simple MNIST dataset. So train a feedforward network to study the basics of neural networks.

Week 2: Convolutional networks

Change the previous network to a convolutional network to study the basics of convolutional network.

Week 3: Hyperparameter optimization

Change the number of layers and different learning rates and other hyperparameters to learn validation and hyperparameter optimization.

Week 4: Dropout and batch normalization

Introduce dropout and batch normalization to the network to learn regularization and the rest of hyperparameter optimization. Up till now, it’s learning deep learning basics rather than a project.

Week 5&6: CIFAR-10 dataset

Repeat the above classification project but switch to CIFAR-10 dataset. There might be a few changes in the process, like input normalization and the need for more conv layers and so on. But this should solidify the knowledge.

Week 7: Transfer learning

Since you won’t train on your own from scratch all the time (no time and no resources), we sometimes borrow the lower layers from pre-trained networks and refine them. Use VGG model parameters with any other dataset and retrain for fine-tuning .

Which tools to use?

Since all the project is deep learning stick to Tensorflow and Keras, Keras is way easier but it is not as flexible. So you may want to choose between them based on your end goal. But give both a try and make sure you understand the basics in a theoretical level first. Consult a tutorial or a book or whatever you’re comfortable with. There are tons of materials online. Stanford course is one. It is more academic but easy. You won’t need other libraries, like scikit unless you want to play and compare with other algorithms or perhaps do a little input manipulation via them.

What’s next?

I assume if you reached this level, you’d have a pretty decent knowledge with clean data. I’ll look into other datasets to play with, as I know people who don’t consider the standard research datasets as a project but rather more of a tutorial following. So when you add it to your CV, it’ll look better.



I was almost done with all the steps and then got busy in life once again. Now I wanted to start the engines again and move on to a personal project to learn more, but I have some solid doubts that I did not do a 100% clean homework. That’s why I wanted to post my solution for every week again after revising it, cleaning it, and making sure that I can understand and present it well.


Monday, April 25, 2011

My Career Shift - II

Okay, I made a schedule for the next phase. It is about three months long, but I hope it is useful as I thought. The main objectives of this phase are:
  • Strengthen my knowledge of Python.
  • Learn and apply the basics of AI, so I can decide the following phase depending on the current one.

The schedule is as follows:
  • It starts from 1 May 2011.
  • OS to use is Ubuntu 11.04. Just a normal usage to get used to it, so whenever I have to use it technically, I don't start from scratch. And because I want to be be free of cracked applications.
  • 2-week course to revise the basics of Python and cover the main modules. [1:14 May]
  • 1-week project to apply what I learned. [15:21 May] [project not decided yet]
  • 8-week course to start AI from the beginning. I didn't go deep anyways, but this time with applying the examples using Python. [22May:16July]
  • Reading about Software Product Management will get in the queue with other general books I read.
  • I should not put in mind the targeted platform for my future applications. I can watch the market carefully. But choosing the platform is not part of the current phase.

Resources:
I try to use only free resources ...

Choosing Python, not Ruby:

Learning Python:

Learning AI:
I haven't decided the best place to learn AI yet. But till now the NPTEL course was an average one. I still have some time to find better books/resources.

If you have comments/suggestions, you are more than welcomed.