Posted on
Artificial Intelligence

Artificial Intelligence Portfolio Projects

Author
  • User
    linuxbash
    Posts by this author
    Posts by this author

4 Linux-Friendly AI Portfolio Projects You Can Ship This Week

If your résumé lists “AI/ML,” but your GitHub is light on real-world repos, hiring managers will scroll past. The fastest way to stand out: publish small, polished AI projects that run reproducibly on Linux with simple Bash commands. This post gives you four portfolio-ready ideas, each with setup commands, minimal code, and a path to demonstrable results.

Why this works:

  • It proves you can go end-to-end: data, model, automation, and reproducibility.

  • Linux-first projects showcase the tooling you’ll use on real servers: Bash, Git, Make, DVC, system packages.

  • Recruiters and engineers can clone and run your work in minutes.

Use the projects below as templates, customize them, and ship.


Prerequisites: Install the basics (APT, DNF, Zypper)

Pick your distro and install these core tools.

# Debian/Ubuntu
sudo apt update
sudo apt install -y python3 python3-venv python3-pip git build-essential wget curl make ffmpeg

# Fedora/RHEL/CentOS Stream
sudo dnf -y groupinstall "Development Tools"
sudo dnf install -y python3 python3-pip git wget curl make ffmpeg

# openSUSE (Leap/Tumbleweed)
sudo zypper refresh
sudo zypper install -y python3 python3-pip git gcc make wget curl ffmpeg

Create a workspace and Python virtual environment:

mkdir -p ~/ai-portfolio && cd ~/ai-portfolio
python3 -m venv .venv
source .venv/bin/activate
python -m pip install --upgrade pip

Optional (handy for notebooks):

pip install jupyter

Project 1 — Log Anomaly Detector (shell + scikit-learn)

Value: Turn raw Linux logs into a tiny anomaly detector. Shows data wrangling, classic ML, and ops awareness.

Install Python deps:

pip install scikit-learn pandas joblib

Extract features from system logs (works with journald; falls back to syslog). This script counts log lines per hour over the last 7 days.

mkdir -p scripts
cat > scripts/extract_log_features.sh << 'EOF'
#!/usr/bin/env bash
set -euo pipefail
OUT="${1:-features.csv}"
if command -v journalctl >/dev/null 2>&1; then
  journalctl --since "7 days ago" -o short-iso |
  awk '{ split($1,dt,"T"); split(dt[2],tm,":"); key=dt[1]" "tm[1]":00"; cnt[key]++ } END { print "hour,count"; for (k in cnt) print k","cnt[k] }' |
  sort > "$OUT"
else
  grep -h "^[A-Z][a-z][a-z] " /var/log/*log* 2>/dev/null |
  awk '{ h=$3; if (h ~ /:/) { split(h,tm,":"); key=$1" "$2" "tm[1]":00"; cnt[key]++ } } END { print "hour,count"; for (k in cnt) print k","cnt[k] }' |
  sort > "$OUT"
fi
echo "Wrote $OUT"
EOF
chmod +x scripts/extract_log_features.sh

Train an Isolation Forest and score anomalies:

cat > train_isoforest.py << 'PY'
import pandas as pd
from sklearn.ensemble import IsolationForest
import joblib

df = pd.read_csv("features.csv")
X = df[["count"]].values
model = IsolationForest(contamination=0.02, random_state=42)
model.fit(X)
df["anomaly"] = model.predict(X)  # -1 = anomaly, 1 = normal
df.to_csv("features_scored.csv", index=False)
joblib.dump(model, "isoforest.joblib")
print("Saved isoforest.joblib and features_scored.csv")
PY

./scripts/extract_log_features.sh features.csv
python train_isoforest.py
column -t -s, features_scored.csv | tail -n 10

Deliverables you’ll show in your repo:

  • A README with how to run, sample output, and a short “What counts as an anomaly” note.

  • A screenshot or snippet of anomalies detected over a week.

  • Optional: a cron-able shell script that runs weekly and writes a report.


Project 2 — CLI Image Classifier (PyTorch) on CIFAR-10

Value: Demonstrates modern DL skills with a simple, reproducible command-line interface.

Install PyTorch (CPU-only for portability) and Pillow:

pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cpu
pip install pillow

Train on CIFAR-10 with a tiny CNN:

cat > train_cifar.py << 'PY'
import torch, torch.nn as nn, torch.optim as optim
from torch.utils.data import DataLoader
from torchvision import datasets, transforms
import os

device = torch.device("cuda" if torch.cuda.is_available() else "cpu")

transform = transforms.Compose([
    transforms.ToTensor(),
    transforms.Normalize((0.5,0.5,0.5), (0.5,0.5,0.5))
])

trainset = datasets.CIFAR10(root="./data", train=True, download=True, transform=transform)
testset  = datasets.CIFAR10(root="./data", train=False, download=True, transform=transform)
trainloader = DataLoader(trainset, batch_size=128, shuffle=True, num_workers=2)
testloader  = DataLoader(testset,  batch_size=256, shuffle=False, num_workers=2)

class SmallCNN(nn.Module):
    def __init__(self):
        super().__init__()
        self.net = nn.Sequential(
            nn.Conv2d(3, 32, 3, padding=1), nn.ReLU(), nn.MaxPool2d(2),
            nn.Conv2d(32, 64, 3, padding=1), nn.ReLU(), nn.MaxPool2d(2),
            nn.Flatten(),
            nn.Linear(64*8*8, 256), nn.ReLU(),
            nn.Linear(256, 10)
        )
    def forward(self, x): return self.net(x)

model = SmallCNN().to(device)
opt = optim.Adam(model.parameters(), lr=1e-3)
crit = nn.CrossEntropyLoss()

for epoch in range(5):
    model.train()
    total, correct, loss_sum = 0, 0, 0.0
    for x,y in trainloader:
        x,y = x.to(device), y.to(device)
        opt.zero_grad()
        logits = model(x)
        loss = crit(logits, y); loss.backward(); opt.step()
        loss_sum += loss.item() * x.size(0)
        correct += (logits.argmax(1)==y).sum().item()
        total += x.size(0)
    print(f"Epoch {epoch+1}: train_loss={loss_sum/total:.4f} train_acc={correct/total:.3f}")

model.eval()
total, correct = 0, 0
with torch.no_grad():
    for x,y in testloader:
        x,y = x.to(device), y.to(device)
        logits = model(x)
        correct += (logits.argmax(1)==y).sum().item()
        total += x.size(0)
print(f"Test acc: {correct/total:.3f}")

os.makedirs("models", exist_ok=True)
torch.save(model.state_dict(), "models/cifar_smallcnn.pt")
print("Saved models/cifar_smallcnn.pt")
PY

python train_cifar.py

Simple CLI inference:

cat > predict.py << 'PY'
import sys, torch
from PIL import Image
from torchvision import transforms
import torch.nn as nn

labels = ["airplane","automobile","bird","cat","deer","dog","frog","horse","ship","truck"]

class SmallCNN(nn.Module):
    def __init__(self):
        super().__init__()
        self.net = nn.Sequential(
            nn.Conv2d(3, 32, 3, padding=1), nn.ReLU(), nn.MaxPool2d(2),
            nn.Conv2d(32, 64, 3, padding=1), nn.ReLU(), nn.MaxPool2d(2),
            nn.Flatten(),
            nn.Linear(64*8*8, 256), nn.ReLU(),
            nn.Linear(256, 10)
        )
    def forward(self, x): return self.net(x)

transform = transforms.Compose([
    transforms.Resize((32,32)),
    transforms.ToTensor(),
    transforms.Normalize((0.5,0.5,0.5), (0.5,0.5,0.5))
])

img_path = sys.argv[1]
img = Image.open(img_path).convert("RGB")
x = transform(img).unsqueeze(0)

model = SmallCNN()
model.load_state_dict(torch.load("models/cifar_smallcnn.pt", map_location="cpu"))
model.eval()
with torch.no_grad():
    logits = model(x)
    prob = torch.softmax(logits, dim=1)[0]
    top = torch.topk(prob, 3)
    for i in range(3):
        print(f"{labels[top.indices[i]]}: {top.values[i].item():.3f}")
PY

python predict.py path/to/your/test_image.jpg

Deliverables:

  • README with setup, train, and predict commands.

  • Example predictions on 3–5 images.

  • A note on trade-offs (CPU-only vs GPU).


Project 3 — Batch Speech-to-Text with Whisper (ffmpeg + faster-whisper)

Value: Real utility for podcasts/meetings; demonstrates AI inference pipelines and Linux media tooling.

We already installed ffmpeg above.

Install the model runtime:

pip install faster-whisper

Transcribe all audio files in a directory to SRT:

cat > transcribe_dir.py << 'PY'
import sys, pathlib
from faster_whisper import WhisperModel

indir = pathlib.Path(sys.argv[1] if len(sys.argv) > 1 else ".")
model = WhisperModel("base", device="cpu", compute_type="int8")

for audio in indir.glob("*.*"):
    if audio.suffix.lower() not in {".mp3",".wav",".m4a",".flac",".ogg"}:
        continue
    print(f"Transcribing {audio} ...")
    segments, info = model.transcribe(str(audio))
    def ts(t):
        h=int(t//3600); m=int((t%3600)//60); s=t%60
        return f"{h:02}:{m:02}:{int(s):02},{int((s-int(s))*1000):03}"
    lines = []
    i=1
    for seg in segments:
        lines += [str(i), f"{ts(seg.start)} --> {ts(seg.end)}", seg.text.strip(), ""]
        i+=1
    out = audio.with_suffix(".srt")
    out.write_text("\n".join(lines), encoding="utf-8")
    print(f"Wrote {out}")
PY

python transcribe_dir.py ~/audio

Convert videos to audio first if needed:

ffmpeg -i input.mp4 -vn -acodec pcm_s16le -ar 16000 -ac 1 output.wav

Deliverables:

  • Before/after demo (short clip → SRT).

  • Benchmark note (model size vs speed/accuracy).

  • Optional: a Bash wrapper that processes new files via inotifywait.


Project 4 — Reproducible ML with DVC + Make

Value: Shows you understand MLOps fundamentals: data versioning, pipelines, metrics, and one-command repro.

Install:

pip install dvc pandas scikit-learn joblib

Scaffold a tiny pipeline:

mkdir -p my-ml-pipeline && cd my-ml-pipeline
git init
python3 -m venv .venv && source .venv/bin/activate
python -m pip install --upgrade pip dvc pandas scikit-learn joblib
dvc init
git add . && git commit -m "init with DVC"
mkdir -p data/raw data/processed models scripts

Fetch a dataset (Wine Quality):

wget -O data/raw/winequality-red.csv \
  https://archive.ics.uci.edu/ml/machine-learning-databases/wine-quality/winequality-red.csv

Data prep:

cat > scripts/prepare.py << 'PY'
import pandas as pd, os
from sklearn.model_selection import train_test_split
os.makedirs("data/processed", exist_ok=True)
df = pd.read_csv("data/raw/winequality-red.csv", sep=";")
train, test = train_test_split(df, test_size=0.2, random_state=42)
train.to_csv("data/processed/train.csv", index=False)
test.to_csv("data/processed/test.csv", index=False)
print("Wrote data/processed/train.csv and test.csv")
PY

Train + metrics:

cat > scripts/train.py << 'PY'
import pandas as pd, json, os, joblib
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import Pipeline

train = pd.read_csv("data/processed/train.csv", sep=",")
test  = pd.read_csv("data/processed/test.csv", sep=",")

X_train, y_train = train.drop(columns=["quality"]), train["quality"] >= 6
X_test,  y_test  = test.drop(columns=["quality"]),  test["quality"] >= 6

pipe = Pipeline([
    ("scaler", StandardScaler(with_mean=False)),
    ("clf", LogisticRegression(max_iter=1000))
])
pipe.fit(X_train, y_train)
pred = pipe.predict(X_test)
acc = accuracy_score(y_test, pred)

os.makedirs("models", exist_ok=True)
joblib.dump(pipe, "models/model.joblib")
with open("metrics.json","w") as f: json.dump({"accuracy": acc}, f, indent=2)
print(f"Accuracy: {acc:.3f}. Saved models/model.joblib and metrics.json")
PY

Declare the pipeline in DVC:

cat > dvc.yaml << 'YAML'
stages:
  prepare:
    cmd: python scripts/prepare.py
    deps:
    - scripts/prepare.py
    - data/raw/winequality-red.csv
    outs:
    - data/processed/train.csv
    - data/processed/test.csv
  train:
    cmd: python scripts/train.py
    deps:
    - scripts/train.py
    - data/processed/train.csv
    - data/processed/test.csv
    outs:
    - models/model.joblib
    metrics:
    - metrics.json
YAML

Optional Makefile to orchestrate:

cat > Makefile << 'MK'
.PHONY: setup data repro clean

setup:
    python -m venv .venv && . .venv/bin/activate && pip install -U pip dvc pandas scikit-learn joblib

data:
    wget -O data/raw/winequality-red.csv https://archive.ics.uci.edu/ml/machine-learning-databases/wine-quality/winequality-red.csv

repro:
    dvc repro && dvc metrics show

clean:
    rm -rf data/processed models metrics.json
MK

Run it:

git add .
git commit -m "Add pipeline"
make repro   # or: dvc repro && dvc metrics show

Deliverables:

  • metrics.json under version control.

  • dvc.yaml showing clean stages and dependencies.

  • README explaining “clone → make repro → see metrics”.


How to present these projects

  • Polish your READMEs: “Prereqs, Install, Run, Sample Output, Design Notes.”

  • Add “Reproducibility” badges: show commands to recreate results.

  • Include a short “What I learned / trade-offs” section.

  • Keep repos small and runnable on CPU in <10 minutes.

  • Add CI to run a smoke test (lint/train one epoch/infer one file).


Conclusion and Next Steps (CTA)

Pick one project above and ship a v1 in the next 48 hours: 1) Create the repo and paste the minimal scripts shown here. 2) Verify a clean run on a fresh Linux shell using the APT/DNF/Zypper steps. 3) Write a tight README with a one-screenshot demo. 4) Post it on LinkedIn/Twitter with a 2–3 sentence summary of your impact.

Then iterate:

  • Add tests and a Makefile target.

  • Containerize or publish a small demo video.

  • Move to the next project and repeat.

Your portfolio doesn’t need to be big—just real, reproducible, and clearly explained. Start now.