- 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.yamlshowing 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.