gpt-oss

gpt-oss ist ein Modell, das vom ChatGPT Betreiber OpenAI selbst trainiert wurde.

von ChatGPT generiertes Symbolfoto zu LLM ( ein stilisiertes, von einzelnen Lampen erhelltes Gehirn)
raspithek.de - Olli Graf
llmCreative Commons Attribution-NonCommercial-ShareAlike 4.0 International License . loading=
Large Language Model (Symbolbild)

gpt-oss

Dieses Modell kommt mit 20b und 120b Parametern und steht unter Apache 2.0 Lizenz.

Es verspricht, eine neue lokale Erfahrung und ist für leistungsstarkes Reasoning, Agentenaufgaben und vielseitige Anwendungsfälle für Entwickler konzipiert.

20b

Das Modell mit 20b Parametern passt mit seinem ca. 13GB Umfang noch in den Speicher des Raspberry Pi 5 16GB, so dass ich den als Testplattform benutze. Nach beinah einer Viertelstunde kommt ein bestenfalls mittelmäßiges Ergebnis zurück.

Ergebnis von gpt-oss:20b, diesmal in deutscher Sprache
raspithek.de - Olli Graf
gpt-oss-20bCreative Commons Attribution-NonCommercial-ShareAlike 4.0 International License . loading=
Ergebnis von gpt-oss:20b, diesmal in deutscher Sprache

120b

Das 120b Modell ist fünf mal so groß wie das 20b und kann ich nur auf meinem Desktop PC mit 128GB RAM testen. Nach fast genau 8 Minuten habe ich eine Antwort von sehr guter Qualität.

ModelHerstellerParameterSpeicherverbrauchLizenzTestsystemLaufzeitAntwortqualität
gpt-ossOpenAI20b13GBApache 2.0Raspberry Pi 5 16GB14 Minuten 54,629214351smittelmäßig
gpt-ossOpenAI120b65 GBApache 2.0Intel i9-10900K (20) @ 5.300GHz8 Minuten 0,491043453ssehr gut
tinyllamaOpenSource1,1b637MBApacheRaspberry Pi 5B 8GB24.387617981sUnsinnige Antwort.
phiMicrosoft2,8b1,6GBMITRaspberry Pi 5B 8GB2 Minuten 39.691083496steilweise brauchbar
llavaMicrosoft7,2b4,7GBApacheRaspberry Pi 5B 8GB1 Minute 25.629187111szufriedenstellend
llama3Meta8,0b4,7GBMETA LLAMA 3 COMMUNITY LICENSE AGREEMENTRaspberry Pi 5B 8GB
3 Minuten 4.925977295s
gut
deepseek-v3Deepseek681,0b404GBDEEPSEEK LICENSE AGREEMENTRaspberry Pi 5B 8GB
deepseek-r1Deepseek7,6b4,7GBMITRaspberry Pi 5B 8GB8 Minuten 23.00118112svöllig unbrauchbar
gemma3Google4,3b3,3GBGemma Terms of UseRaspberry Pi 5B 8GB1 Minute 14.086309352sunbrauchbar
gemma3Google12b8,1GBGemma Terms Of UseIntel i9-10900K (20) @ 5.300GHz3 Minuten 34.5325445ssehr gut
gemma3Google27b17GBGemma Terms of UseIntel i9-10900K (20) @ 5.300GHz4 Minuten 41.199445574ssehr gut
phi4Microsoft14b9,1GBMITRaspberry Pi 5B 16GB3 Minuten 17.342953352steilweise brauchbar
phi4:14b-Q8_0Microsoft14b17GBMITIntel i9-10900K (20) @ 5.300GHz5 Minuten 42.156362295sunbrauchbar
phi4:14b-fp16Microsoft14b29GBMITIntel i9-10900K (20) @ 5.300GHz7 Minuten 34.78815032sunsinnig
phi4:14b-q4_K_MMicro14b9,1GBMITRaspberry Pi 5B 16GB4 Minuten 44.654069613sThema verfehlt

Zusatzaufgabe

Um die Programmierfähigkeit des 120b Modells zu testen, habe ich es gebeten, mir ein bash Script zu schreiben, dass alle im aktuellen Verzeichnis vorhandenen .bz2 Dateien mit pbzip2 entpackt und mit zstd neu komprimiert.

Nach 34 Minuten erhielt ich dieses Script

#!/usr/bin/env bash
#====================================================================
#  bz2-to-zst.sh
#
#  Convert every *.bz2 file in the current directory to *.zst
#  using parallel pbzip2 for decompression and zstd for recompression.
#
#  Usage:
#      ./bz2-to-zst.sh [-d] [-l LEVEL] [-t THREADS] [FILE...]
#
#  Options:
#      -d            Delete the original .bz2 file after a successful
#                    conversion (default: keep the original).
#      -l LEVEL      zstd compression level (0‑22). Default is 3.
#      -t THREADS    Number of threads for both pbzip2 and zstd.
#                    If omitted, both utilities use their own defaults.
#      FILE...       Specific .bz2 files to process (otherwise all *.bz2).
#
#  Requirements:
#      * pbzip2  (parallel bzip2 implementation)
#      * zstd    (Zstandard compressor)
#
#  Author:  ChatGPT  (2025‑08‑10)
#====================================================================

set -euo pipefail   # abort on errors, unset vars, and failed pipes

# ---------- default configuration ----------
delete_original=false
zstd_level=3
zstd_threads=
pbzip2_threads=
declare -a targets   # will hold the list of files to process

# ---------- helper functions ----------
usage() {
    cat <<EOF
Usage: $(basename "$0") [-d] [-l LEVEL] [-t THREADS] [FILE...]

  -d            Delete the original .bz2 after successful conversion.
  -l LEVEL      zstd compression level (0‑22). Default: $zstd_level
  -t THREADS    Number of threads for both pbzip2 and zstd (if omitted each
                tool picks its own default).
  FILE...       One or more specific *.bz2 files to convert.
                If omitted, all *.bz2 files in the current directory are used.

Examples:
  $(basename "$0")                # convert every *.bz2, keep originals
  $(basename "$0") -d            # convert and delete *.bz2 afterwards
  $(basename "$0") -l 19 file1.bz2 file2.bz2
  $(basename "$0") -t 8          # use 8 threads for both tools
EOF
    exit 1
}

check_program() {
    local prog=$1
    if ! command -v "$prog" >/dev/null 2>&1; then
        echo "Error: '$prog' not found in PATH." >&2
        exit 1
    fi
}

# ---------- parse arguments ----------
while (( $# )); do
    case "$1" in
        -d|--delete)   delete_original=true; shift ;;
        -l|--level)    [[ -n ${2-} ]] || { echo "Missing argument for $1"; usage; }
                       zstd_level=$2; shift 2 ;;
        -t|--threads)  [[ -n ${2-} ]] || { echo "Missing argument for $1"; usage; }
                       zstd_threads=$2; pbzip2_threads=$2; shift 2 ;;
        -h|--help)     usage ;;
        -*)
                       echo "Unknown option: $1"; usage ;;
        *)             targets+=("$1"); shift ;;
    esac
done

# If no explicit file list was given, use a glob expansion.
if [[ ${#targets[@]} -eq 0 ]]; then
    shopt -s nullglob   # makes *.bz2 expand to an empty list instead of the pattern itself
    for f in *.bz2; do
        [[ -f $f ]] && targets+=("$f")
    done
    shopt -u nullglob
fi

# Bail out early if nothing to do.
if [[ ${#targets[@]} -eq 0 ]]; then
    echo "No *.bz2 files found in the current directory."
    exit 0
fi

# ---------- sanity checks ----------
check_program pbzip2
check_program zstd

# Verify that the chosen compression level is numeric and within zstd's range.
if ! [[ $zstd_level =~ ^[0-9]+$ ]] || (( zstd_level < 0 || zstd_level > 22 )); then
    echo "Error: ZSTD level must be an integer between 0 and 22 (got '$zstd_level')." >&2
    exit 1
fi

# ---------- conversion loop ----------
for src in "${targets[@]}"; do
    # Guard against non‑existent files (maybe they were removed meanwhile)
    if [[ ! -f $src ]]; then
        echo "Skipping missing file: $src"
        continue
    fi

    # Derive destination name: strip .bz2 (or .tbz2, .tbz) and add .zst
    dst="${src%.*}.zst"

    # If a .zst already exists, skip to avoid overwriting.
    if [[ -e $dst ]]; then
        echo "Target already exists, skipping: $dst"
        continue
    fi

    echo "Converting: $src$dst"

    # Build command lines (add thread flags only if user supplied them)
    pbzip2_cmd=(pbzip2 -dc)               # -d = decompress, -c = write to stdout
    [[ -n $pbzip2_threads ]] && pbzip2_cmd+=( -p "$pbzip2_threads" )

    zstd_cmd=(zstd -q -$zstd_level -o "$dst" -)  # - = read from stdin
    [[ -n $zstd_threads ]] && zstd_cmd+=( -T "$zstd_threads" )

    # Run the pipeline.  Using `pipefail` + `set -e` means any failure aborts.
    "${pbzip2_cmd[@]}" "$src" | "${zstd_cmd[@]}"

    # If we reach this point the conversion succeeded.
    if $delete_original; then
        rm -f -- "$src"
        echo "Deleted original: $src"
    fi
done

echo "All done."

Das ist etwas umfangreicher als ich ursprünglich angefordert hatte. Aber der Aufruf ./bz2-to-zstd.sh *.bz2 tut, was er soll.

Der parameterlose Aufruf konvertiert alle .bz2 Testdateien erfolgreich zu einem zstd Archiv.
raspithek.de - Olli Graf
bz2-to-zstd-sucessCreative Commons Attribution-NonCommercial-ShareAlike 4.0 International License . loading=
Der parameterlose Aufruf konvertiert alle .bz2 Testdateien erfolgreich zu einem zstd Archiv.

Wenn ich allerdings über die Kommandozeilen Parameter den Kompressionslevel auf 5 setzen und zstd alle Kerne des Rechners benutzen lassen will, kommt es zu einem Fehler im Skript. ./bz2-to-zstd.sh -l 5 -t 0 *.bz2

Mit Parametern bricht das Script mit Fehler ab.
raspithek.de - Olli Graf
bz2-to-zstd-failCreative Commons Attribution-NonCommercial-ShareAlike 4.0 International License . loading=
Mit Parametern bricht das Script mit Fehler ab.

Es hat mich dann eine Weile Sucharbeit gekostet, um die insgesamt 3 Fehler zu finden

  1. Beim Parsen von –threads müssen separate Variabel für den pzib2 und den zstd Aufruf gesetzt werden.
  2. Beim Aufruf von zstd war ein überflüssiges Leerzeichen zwischen dem -t Parameter und dem Wert.
  3. Das Sript versuchte mehrere Dateien gleichzeitig zu konvertieren, was pbzip2 nicht zu lässt.

Hier also nochmal eine lauffähige Version des Scripts.

#!/usr/bin/env bash
#====================================================================
#  bz2-to-zst.sh
#
#  Convert every *.bz2 file in the current directory to *.zst
#  using parallel pbzip2 for decompression and zstd for recompression.
#
#  Usage:
#      ./bz2-to-zst.sh [-d] [-l LEVEL] [-t THREADS] [FILE...]
#
#  Options:
#      -d            Delete the original .bz2 file after a successful
#                    conversion (default: keep the original).
#      -l LEVEL      zstd compression level (0-22). Default is 3.
#      -t THREADS    Number of threads for both pbzip2 and zstd.
#                    If 0 is given: pbzip2 uses default autodetect (all cores),
#                    zstd uses -T0 (all cores).
#      FILE...       Specific .bz2 files to process (otherwise all *.bz2).
#
#====================================================================

set -euo pipefail   # abort on errors, unset vars, and failed pipes

# ---------- default configuration ----------
delete_original=false
zstd_level=3
zstd_threads=
pbzip2_threads=
declare -a targets   # will hold the list of files to process

# ---------- helper functions ----------
usage() {
    cat <<EOF
Usage: $(basename "$0") [-d] [-l LEVEL] [-t THREADS] [FILE...]

  -d            Delete the original .bz2 after successful conversion.
  -l LEVEL      zstd compression level (0-22). Default: $zstd_level
  -t THREADS    Number of threads for both pbzip2 and zstd (if omitted each
                tool picks its own default; 0 means "all cores").
  FILE...       One or more specific *.bz2 files to convert.
                If omitted, all *.bz2 files in the current directory are used.
EOF
    exit 1
}

check_program() {
    local prog=$1
    if ! command -v "$prog" >/dev/null 2>&1; then
        echo "Error: '$prog' not found in PATH." >&2
        exit 1
    fi
}

# ---------- parse arguments ----------
while (( $# )); do
    case "$1" in
        -d|--delete)   delete_original=true; shift ;;
        -l|--level)
            [[ -n ${2-} ]] || { echo "Missing argument for $1"; usage; }
            zstd_level=$2; shift 2 ;;
        -t|--threads)
            [[ -n ${2-} ]] || { echo "Missing argument for $1"; usage; }
            if [[ $2 -eq 0 ]]; then
                zstd_threads=0        # zstd: alle Kerne
                pbzip2_threads=       # pbzip2: kein -p -> Autodetect
            else
                zstd_threads=$2
                pbzip2_threads=$2
            fi
            shift 2 ;;
        -h|--help)     usage ;;
        -*)
            echo "Unknown option: $1"; usage ;;
        *)             targets+=("$1"); shift ;;
    esac
done

# If no explicit file list was given, use a glob expansion.
if [[ ${#targets[@]} -eq 0 ]]; then
    shopt -s nullglob
    for f in *.bz2; do
        [[ -f $f ]] && targets+=("$f")
    done
    shopt -u nullglob
fi

if [[ ${#targets[@]} -eq 0 ]]; then
    echo "No *.bz2 files found in the current directory."
    exit 0
fi

# ---------- sanity checks ----------
check_program pbzip2
check_program zstd

if ! [[ $zstd_level =~ ^[0-9]+$ ]] || (( zstd_level < 0 || zstd_level > 22 )); then
    echo "Error: ZSTD level must be an integer between 0 and 22 (got '$zstd_level')." >&2
    exit 1
fi

# ---------- conversion loop ----------
for src in "${targets[@]}"; do
    if [[ ! -f $src ]]; then
        echo "Skipping missing file: $src"
        continue
    fi

    dst="${src%.*}.zst"

    if [[ -e $dst ]]; then
        echo "Target already exists, skipping: $dst"
        continue
    fi

    echo "Converting: $src$dst"

    # Build command lines fresh in each loop
    pbzip2_cmd=(pbzip2 -dc)
    [[ -n $pbzip2_threads ]] && pbzip2_cmd+=(-p "$pbzip2_threads")

    zstd_cmd=(zstd -q -$zstd_level -o "$dst" -)
    [[ -n $zstd_threads ]] && zstd_cmd+=(-T"$zstd_threads")

    # Debug
    echo "DEBUG: pbzip2_cmd=${pbzip2_cmd[@]} src=$src zstd_cmd=${zstd_cmd[@]}"

    # Run pipeline
    "${pbzip2_cmd[@]}" "$src" | "${zstd_cmd[@]}"

    if $delete_original; then
        rm -f -- "$src"
        echo "Deleted original: $src"
    fi
done

echo "All done."
Mit den Korrekturen können auch die Parameter übergeben werden.
raspithek.de - Olli Graf
bz2-to-zstd-fixedCreative Commons Attribution-NonCommercial-ShareAlike 4.0 International License . loading=
Mit den Korrekturen können auch die Parameter übergeben werden.

Diese Probleme hätte das Script nicht gehabt, hätte gpt-oss sich daran gehalten, nur die Konvertierungsschleife zu schreiben und den Parameterteil weggelassen.

Fazit

Der Vorreiter für LLM im Internet macht auf dem Raspberry Pi eher eine jämmerliche Figur.

Schreibe einen Kommentar

Insert math as
Block
Inline
Additional settings
Formula color
Text color
#333333
Type math using LaTeX
Preview
\({}\)
Nothing to preview
Insert
Creative Commons License
Except where otherwise noted, the content on this site is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.
raspithek.de - Olli Graf
WordPress Cookie Hinweis von Real Cookie Banner