Text Generation
GGUF
Japanese
English
llama.cpp
Mixture of Experts
expert-pruning
intel-mac
cpu
local-agent
imatrix
conversational
Instructions to use miutti/intel-mac-local-llm with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- llama.cpp
How to use miutti/intel-mac-local-llm with llama.cpp:
Install (macOS, Linux)
curl -LsSf https://llama.app/install.sh | sh # Start a local OpenAI-compatible server with a web UI: llama serve -hf miutti/intel-mac-local-llm:UD-Q2_K_XL # Run inference directly in the terminal: llama cli -hf miutti/intel-mac-local-llm:UD-Q2_K_XL
Install from WinGet (Windows)
winget install llama.cpp # Start a local OpenAI-compatible server with a web UI: llama serve -hf miutti/intel-mac-local-llm:UD-Q2_K_XL # Run inference directly in the terminal: llama cli -hf miutti/intel-mac-local-llm:UD-Q2_K_XL
Use pre-built binary
# Download pre-built binary from: # https://github.com/ggerganov/llama.cpp/releases # Start a local OpenAI-compatible server with a web UI: ./llama-server -hf miutti/intel-mac-local-llm:UD-Q2_K_XL # Run inference directly in the terminal: ./llama-cli -hf miutti/intel-mac-local-llm:UD-Q2_K_XL
Build from source code
git clone https://github.com/ggerganov/llama.cpp.git cd llama.cpp cmake -B build cmake --build build -j --target llama-server llama-cli # Start a local OpenAI-compatible server with a web UI: ./build/bin/llama-server -hf miutti/intel-mac-local-llm:UD-Q2_K_XL # Run inference directly in the terminal: ./build/bin/llama-cli -hf miutti/intel-mac-local-llm:UD-Q2_K_XL
Use Docker
docker model run hf.co/miutti/intel-mac-local-llm:UD-Q2_K_XL
- LM Studio
- Jan
- vLLM
How to use miutti/intel-mac-local-llm with vLLM:
Install from pip and serve model
# Install vLLM from pip: pip install vllm # Start the vLLM server: vllm serve "miutti/intel-mac-local-llm" # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:8000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "miutti/intel-mac-local-llm", "messages": [ { "role": "user", "content": "What is the capital of France?" } ] }'Use Docker
docker model run hf.co/miutti/intel-mac-local-llm:UD-Q2_K_XL
- Ollama
How to use miutti/intel-mac-local-llm with Ollama:
ollama run hf.co/miutti/intel-mac-local-llm:UD-Q2_K_XL
- Unsloth Desktop
- Pi
How to use miutti/intel-mac-local-llm with Pi:
Start the llama.cpp server
# Install llama.cpp: brew install llama.cpp # Start a local OpenAI-compatible server: llama serve -hf miutti/intel-mac-local-llm:UD-Q2_K_XL
Configure the model in Pi
# Install Pi: npm install -g @earendil-works/pi-coding-agent # Add to ~/.pi/agent/models.json: { "providers": { "llama-cpp": { "baseUrl": "http://localhost:8080/v1", "api": "openai-completions", "apiKey": "none", "models": [ { "id": "miutti/intel-mac-local-llm:UD-Q2_K_XL" } ] } } }Run Pi
# Start Pi in your project directory: pi
- Docker Model Runner
How to use miutti/intel-mac-local-llm with Docker Model Runner:
docker model run hf.co/miutti/intel-mac-local-llm:UD-Q2_K_XL
- Lemonade
How to use miutti/intel-mac-local-llm with Lemonade:
Pull the model
# Download Lemonade from https://lemonade-server.ai/ lemonade pull miutti/intel-mac-local-llm:UD-Q2_K_XL
Run and chat with the model
lemonade run user.intel-mac-local-llm-UD-Q2_K_XL
List all available models
lemonade list
- Hermes Agent
How to use miutti/intel-mac-local-llm with Hermes Agent:
Start the llama.cpp server
# Install llama.cpp: brew install llama.cpp # Start a local OpenAI-compatible server: llama serve -hf miutti/intel-mac-local-llm:UD-Q2_K_XL
Configure Hermes
# Install Hermes: curl -fsSL https://hermes-agent.nousresearch.com/install.sh | bash hermes setup # Point Hermes at the local server: hermes config set model.provider custom hermes config set model.base_url http://127.0.0.1:8080/v1 hermes config set model.default miutti/intel-mac-local-llm:UD-Q2_K_XL
Run Hermes
hermes
- Atomic Chat
- OpenClaw
How to use miutti/intel-mac-local-llm with OpenClaw:
Start the llama.cpp server
# Install llama.cpp: brew install llama.cpp # Start a local OpenAI-compatible server: llama serve -hf miutti/intel-mac-local-llm:UD-Q2_K_XL
Configure OpenClaw
# Install OpenClaw: npm install -g openclaw@latest # Register the local server and set it as the default model: openclaw onboard --non-interactive --mode local \ --auth-choice custom-api-key \ --custom-base-url http://127.0.0.1:8080/v1 \ --custom-model-id "miutti/intel-mac-local-llm:UD-Q2_K_XL" \ --custom-provider-id llama-cpp \ --custom-compatibility openai \ --custom-text-input \ --accept-risk \ --skip-health
Run OpenClaw
openclaw agent --local --agent main --message "Hello from Hugging Face"
Download source/kernel/cards_build.py from miutti/intel-mac-local-llm: direct link, hf CLI and curl.
- Browser
- Download file 17.4 kB
-
https://huggingface.co/miutti/intel-mac-local-llm/resolve/main/source/kernel/cards_build.py
- Command line
-
hf download hf://miutti/intel-mac-local-llm/source/kernel/cards_build.py
-
curl -L -o cards_build.py https://huggingface.co/miutti/intel-mac-local-llm/resolve/main/source/kernel/cards_build.py
17.4 kB
| #!/usr/bin/env python3 | |
| # -*- coding: utf-8 -*- | |
| """単語カード生成器 (cards_build.py) | |
| 設計思想: 掛け算(ニューラルネットの行列積)を一切使わない。 | |
| 共起回数を「数えるだけ」で、言葉のブレを吸収する疎ベクトル(単語カード)を作る。 | |
| 分布仮説に基づくカウントベース意味表現。GPU不要・学習不要。 | |
| - Python 3.14 標準ライブラリのみ (numpy 等の外部ライブラリは使わない) | |
| - 形態素解析器は使わない。日本語は文字N-gram(2〜4文字)、英数字は単語単位 | |
| - メモリ16GBのIntel Macでも動くよう、逐次読み込み + 定期的な枝刈りで抑える | |
| """ | |
| from __future__ import annotations | |
| import argparse | |
| import json | |
| import math | |
| import os | |
| import sys | |
| import time | |
| import unicodedata | |
| from collections import Counter, defaultdict | |
| # ---------------------------------------------------------------------- | |
| # 設定値 | |
| # ---------------------------------------------------------------------- | |
| # 対象とする拡張子 | |
| TEXT_EXTS = (".txt", ".md") | |
| # 日本語N-gramの長さ範囲 | |
| NGRAM_MIN = 2 | |
| NGRAM_MAX = 4 | |
| # ペア表が肥大化したときに枝刈りを始める閾値(メモリ保護) | |
| MAX_PAIRS = 6_000_000 | |
| # 1行あたりに切り出すトークン数の上限(異常に長い行への保険) | |
| MAX_SPANS_PER_LINE = 200_000 | |
| # ---------------------------------------------------------------------- | |
| # トークナイズ | |
| # ---------------------------------------------------------------------- | |
| def _is_word_char(ch: str) -> bool: | |
| """英数字(ASCII語を構成する文字)かどうか。""" | |
| return ch.isascii() and (ch.isalnum() or ch == "_") | |
| def _is_hiragana(ch: str) -> bool: | |
| """ひらがなかどうか(1文字語として採らないため)。""" | |
| return "ぁ" <= ch <= "ゟ" | |
| def _is_jp_char(ch: str) -> bool: | |
| """日本語として N-gram 対象にする文字かどうか。 | |
| ひらがな・カタカナ・漢字・全角英数などの「文字」を対象にし、 | |
| 句読点や記号・空白は区切りとして扱う。 | |
| """ | |
| if ch.isspace(): | |
| return False | |
| if ch.isascii(): | |
| return False | |
| cat = unicodedata.category(ch) | |
| # L*(文字) と Nd(数字) のみ通す。P*(記号) M* S* は区切り扱い。 | |
| return cat.startswith("L") or cat == "Nd" | |
| def spans(text: str): | |
| """テキストから (開始位置, 終了位置, 語) のリストを作る。 | |
| - 英数字の連続 → 1語(小文字化) | |
| - 日本語文字の連続 → その中の 2〜4 文字のN-gramを全位置で切り出す | |
| 位置情報を持たせるのは、共起を「文字距離」で測り、かつ | |
| 重なり合うN-gram同士を共起としてカウントしないためである。 | |
| """ | |
| out = [] | |
| n = len(text) | |
| i = 0 | |
| while i < n: | |
| ch = text[i] | |
| if _is_word_char(ch): | |
| j = i | |
| while j < n and _is_word_char(text[j]): | |
| j += 1 | |
| out.append((i, j, text[i:j].lower())) | |
| i = j | |
| elif _is_jp_char(ch): | |
| j = i | |
| while j < n and _is_jp_char(text[j]): | |
| j += 1 | |
| seg = text[i:j] | |
| seg_len = j - i | |
| for k in range(seg_len): | |
| # 1文字語: ひらがな1文字は助詞などノイズになるので除外し、 | |
| # 漢字・カタカナ・全角英数の1文字だけ語として認める | |
| # (「猫」「犬」「石」「川」など1文字語を拾うために必要) | |
| if not _is_hiragana(seg[k]): | |
| out.append((i + k, i + k + 1, seg[k])) | |
| for L in range(NGRAM_MIN, NGRAM_MAX + 1): | |
| if k + L > seg_len: | |
| break | |
| out.append((i + k, i + k + L, seg[k:k + L])) | |
| i = j | |
| else: | |
| i += 1 | |
| if len(out) > MAX_SPANS_PER_LINE: | |
| break | |
| return out | |
| # ---------------------------------------------------------------------- | |
| # 入力ファイルの収集 | |
| # ---------------------------------------------------------------------- | |
| def iter_files(paths): | |
| """パス(ファイル or ディレクトリ)のリストから対象ファイルを再帰的に列挙。""" | |
| seen = set() | |
| for p in paths: | |
| p = os.path.abspath(p) | |
| if os.path.isdir(p): | |
| for root, dirs, files in os.walk(p): | |
| dirs[:] = [d for d in dirs if not d.startswith(".")] | |
| for f in sorted(files): | |
| if f.lower().endswith(TEXT_EXTS): | |
| fp = os.path.join(root, f) | |
| if fp not in seen: | |
| seen.add(fp) | |
| yield fp | |
| elif os.path.isfile(p): | |
| if p not in seen: | |
| seen.add(p) | |
| yield p | |
| def iter_lines(paths): | |
| """全対象ファイルの行を逐次返す(メモリに全文を載せない)。""" | |
| for fp in iter_files(paths): | |
| try: | |
| with open(fp, "r", encoding="utf-8", errors="replace") as fh: | |
| for line in fh: | |
| line = line.strip() | |
| if line: | |
| yield line | |
| except OSError as e: | |
| print(f"[warn] 読めません: {fp}: {e}", file=sys.stderr) | |
| # ---------------------------------------------------------------------- | |
| # 本体: 共起カウント → PPMI → 上位top_k | |
| # ---------------------------------------------------------------------- | |
| def build(corpus_paths, out_path="cards.json", window=4, min_count=3, top_k=150) -> dict: | |
| """コーパスから単語カード(PPMI疎ベクトル)を作り JSON に保存する。 | |
| corpus_paths : テキストファイル or ディレクトリのリスト(.txt .md を再帰探索) | |
| out_path : 保存先 JSON | |
| window : 共起とみなす文字距離(語のスパン間の隙間がこの文字数以内) | |
| min_count : この回数未満しか出ない語は捨てる | |
| top_k : 1語あたり残す共起相手の数(疎ベクトルの次元) | |
| 戻り値は保存した辞書そのもの。 | |
| """ | |
| t0 = time.time() | |
| # --- パス1: 語の出現回数を数える ------------------------------------ | |
| uni = Counter() | |
| n_lines = 0 | |
| n_chars = 0 | |
| for line in iter_lines(corpus_paths): | |
| n_lines += 1 | |
| n_chars += len(line) | |
| for _, _, w in spans(line): | |
| uni[w] += 1 | |
| # min_count 未満を捨てる(ここで語彙がぐっと減る) | |
| vocab = {w: c for w, c in uni.items() if c >= min_count} | |
| del uni | |
| if not vocab: | |
| raise ValueError("語彙が空です。コーパスが小さすぎるか min_count が大きすぎます。") | |
| # --- パス2: 共起回数を数える ---------------------------------------- | |
| # pair[(a, b)] = 回数 (a < b の順に正規化して1回だけ持つ) | |
| pair = Counter() | |
| ctx_total = Counter() # 共起カウント上の各語の周辺度数 | |
| total_pairs = 0 | |
| for line in iter_lines(corpus_paths): | |
| sp = [(s, e, w) for (s, e, w) in spans(line) if w in vocab] | |
| m = len(sp) | |
| for i in range(m): | |
| si, ei, wi = sp[i] | |
| for j in range(i + 1, m): | |
| sj, ej, wj = sp[j] | |
| # 位置は開始位置の昇順ではないので、隙間は絶対値で見る | |
| if sj - ei > window: | |
| # 開始位置が単調非減少なので、これ以降はさらに遠い | |
| if sj - ei > window + NGRAM_MAX: | |
| break | |
| continue | |
| # スパンが1文字でも重なるN-gram同士は共起にしない | |
| if sj < ei and ej > si: | |
| continue | |
| if wi == wj: | |
| continue | |
| key = (wi, wj) if wi < wj else (wj, wi) | |
| pair[key] += 1 | |
| ctx_total[wi] += 1 | |
| ctx_total[wj] += 1 | |
| total_pairs += 1 | |
| # メモリ保護: 大きくなりすぎたら回数1のペアを捨てる | |
| if len(pair) > MAX_PAIRS: | |
| pair = Counter({k: v for k, v in pair.items() if v > 1}) | |
| if total_pairs == 0: | |
| raise ValueError("共起が1件も取れませんでした。window を広げてください。") | |
| # --- PPMI 化 --------------------------------------------------------- | |
| # PMI(a,b) = log2( P(a,b) / (P(a) * P(b)) ) | |
| # = log2( c(a,b) * N / (c(a) * c(b)) ) ※ N は共起総数(片側基準) | |
| # 負の値は 0 に切る(PPMI)。 | |
| N = float(total_pairs * 2) # ctx_total は1ペアにつき両側を数えているため | |
| vecs_raw = defaultdict(list) | |
| for (a, b), c in pair.items(): | |
| if c < min_count and c < 2: | |
| continue | |
| ca = ctx_total.get(a, 0) | |
| cb = ctx_total.get(b, 0) | |
| if ca == 0 or cb == 0: | |
| continue | |
| # 掛け算は使うが行列積ではない。ここは素直に確率比を対数で取る。 | |
| pmi = math.log2((c * N) / (ca * cb)) | |
| if pmi <= 0.0: | |
| continue | |
| vecs_raw[a].append((b, pmi)) | |
| vecs_raw[b].append((a, pmi)) | |
| del pair | |
| # --- 上位 top_k だけ残す -------------------------------------------- | |
| vecs = {} | |
| for w, items in vecs_raw.items(): | |
| items.sort(key=lambda kv: kv[1], reverse=True) | |
| vecs[w] = {k: round(v, 4) for k, v in items[:top_k]} | |
| elapsed = time.time() - t0 | |
| data = { | |
| "meta": { | |
| "version": 1, | |
| "window": window, | |
| "min_count": min_count, | |
| "top_k": top_k, | |
| "ngram": [NGRAM_MIN, NGRAM_MAX], | |
| "n_lines": n_lines, | |
| "n_chars": n_chars, | |
| "vocab_size": len(vecs), | |
| "total_pairs": total_pairs, | |
| "build_seconds": round(elapsed, 3), | |
| }, | |
| "vecs": vecs, | |
| } | |
| if out_path: | |
| tmp = out_path + ".tmp" | |
| with open(tmp, "w", encoding="utf-8") as fh: | |
| json.dump(data, fh, ensure_ascii=False) | |
| os.replace(tmp, out_path) | |
| return data | |
| # ---------------------------------------------------------------------- | |
| # 使う側 | |
| # ---------------------------------------------------------------------- | |
| def _bigrams(s: str) -> set: | |
| """文字bigram集合(未知語のフォールバック照合用)。""" | |
| if not s: | |
| return set() | |
| # 前後に境界記号を付ける。こうしないと1文字語(「猫」)の bigram 集合が | |
| # 「子猫」などと一切重ならず、フォールバックが機能しない。 | |
| t = "" + s + "" | |
| return {t[i:i + 2] for i in range(len(t) - 1)} | |
| class Cards: | |
| """生成済みカードを読み込んで、語の近さを測るためのクラス。""" | |
| def __init__(self, vecs: dict, meta: dict | None = None): | |
| self.vecs = vecs | |
| self.meta = meta or {} | |
| # 疎ベクトルのノルムを前計算(コサイン類似度の分母) | |
| self._norm = {w: math.sqrt(sum(v * v for v in d.values())) or 1.0 | |
| for w, d in vecs.items()} | |
| # 未知語フォールバック用の bigram インデックス | |
| self._bi_index = None | |
| # -- 読み込み -------------------------------------------------------- | |
| def load(cls, path) -> "Cards": | |
| with open(path, "r", encoding="utf-8") as fh: | |
| data = json.load(fh) | |
| return cls(data.get("vecs", {}), data.get("meta", {})) | |
| # -- 未知語の解決 ---------------------------------------------------- | |
| def _build_bi_index(self): | |
| idx = defaultdict(list) | |
| for w in self.vecs: | |
| for bg in _bigrams(w): | |
| idx[bg].append(w) | |
| self._bi_index = idx | |
| def resolve(self, word: str) -> str | None: | |
| """語彙に無い語を、文字bigramのJaccard係数が最大の既知語に寄せる。""" | |
| if word in self.vecs: | |
| return word | |
| if not word: | |
| return None | |
| if self._bi_index is None: | |
| self._build_bi_index() | |
| qb = _bigrams(word) | |
| # 候補を bigram インデックスで絞る(全語走査を避ける) | |
| cand = Counter() | |
| for bg in qb: | |
| for w in self._bi_index.get(bg, ()): | |
| cand[w] += 1 | |
| best, best_s = None, 0.0 | |
| for w, common in cand.items(): | |
| wb = _bigrams(w) | |
| union = len(qb) + len(wb) - common | |
| if union <= 0: | |
| continue | |
| s = common / union | |
| if s > best_s: | |
| best, best_s = w, s | |
| return best | |
| # -- 類似度 ---------------------------------------------------------- | |
| def _vec(self, word: str): | |
| w = self.resolve(word) | |
| if w is None: | |
| return None, None | |
| return self.vecs[w], self._norm[w] | |
| def similarity(self, a: str, b: str) -> float: | |
| """疎ベクトルのコサイン類似度。共通キーだけを足し合わせる。""" | |
| va, na = self._vec(a) | |
| vb, nb = self._vec(b) | |
| if va is None or vb is None: | |
| return 0.0 | |
| # 小さい方を走査して共通キーだけ計算する | |
| if len(va) > len(vb): | |
| va, vb = vb, va | |
| dot = 0.0 | |
| get = vb.get | |
| for k, x in va.items(): | |
| y = get(k) | |
| if y is not None: | |
| dot += x * y | |
| if dot <= 0.0: | |
| return 0.0 | |
| return dot / (na * nb) | |
| def nearest(self, word: str, candidates: list, threshold: float = 0.15): | |
| """候補リストの中から最も意味の近いものを返す。(候補, スコア)。""" | |
| best, best_s = None, 0.0 | |
| for c in candidates: | |
| s = self.similarity(word, c) | |
| if s > best_s: | |
| best, best_s = c, s | |
| if best is None or best_s < threshold: | |
| return (None, 0.0) | |
| return (best, best_s) | |
| def neighbors(self, word: str, n: int = 10) -> list: | |
| """意味の近い語トップn(確認・デバッグ用)。[(語, スコア), ...]""" | |
| w = self.resolve(word) | |
| if w is None: | |
| return [] | |
| vw = self.vecs[w] | |
| nw = self._norm[w] | |
| # 共通キーを持ちうる語だけを転置的に集める(全語走査を避ける) | |
| cands = set() | |
| for k in vw: | |
| kv = self.vecs.get(k) | |
| if kv: | |
| cands.update(kv.keys()) | |
| cands.discard(w) | |
| out = [] | |
| for c in cands: | |
| vc = self.vecs.get(c) | |
| if not vc: | |
| continue | |
| small, large = (vw, vc) if len(vw) <= len(vc) else (vc, vw) | |
| dot = 0.0 | |
| get = large.get | |
| for k, x in small.items(): | |
| y = get(k) | |
| if y is not None: | |
| dot += x * y | |
| if dot > 0.0: | |
| out.append((c, dot / (nw * self._norm[c]))) | |
| out.sort(key=lambda kv: kv[1], reverse=True) | |
| return out[:n] | |
| # ---------------------------------------------------------------------- | |
| # CLI | |
| # ---------------------------------------------------------------------- | |
| def main(argv=None) -> int: | |
| ap = argparse.ArgumentParser(description="共起カウントだけで単語カードを作る") | |
| sub = ap.add_subparsers(dest="cmd", required=True) | |
| p_build = sub.add_parser("build", help="コーパスからカードを生成") | |
| p_build.add_argument("paths", nargs="+", help="テキストファイル/ディレクトリ") | |
| p_build.add_argument("--out", default="cards.json") | |
| p_build.add_argument("--window", type=int, default=4) | |
| p_build.add_argument("--min-count", type=int, default=3) | |
| p_build.add_argument("--top-k", type=int, default=150) | |
| p_near = sub.add_parser("near", help="意味の近い語を表示") | |
| p_near.add_argument("word") | |
| p_near.add_argument("--cards", default="cards.json") | |
| p_near.add_argument("-n", type=int, default=10) | |
| p_sim = sub.add_parser("sim", help="2語の類似度") | |
| p_sim.add_argument("a") | |
| p_sim.add_argument("b") | |
| p_sim.add_argument("--cards", default="cards.json") | |
| args = ap.parse_args(argv) | |
| if args.cmd == "build": | |
| data = build(args.paths, out_path=args.out, window=args.window, | |
| min_count=args.min_count, top_k=args.top_k) | |
| m = data["meta"] | |
| size = os.path.getsize(args.out) if os.path.exists(args.out) else 0 | |
| print(f"語彙数 {m['vocab_size']} / 共起 {m['total_pairs']} / " | |
| f"{m['build_seconds']}秒 / {size:,} バイト -> {args.out}") | |
| return 0 | |
| if args.cmd == "near": | |
| cards = Cards.load(args.cards) | |
| w = cards.resolve(args.word) | |
| if w is None: | |
| print("語彙にありません") | |
| return 1 | |
| if w != args.word: | |
| print(f"(未知語のため『{w}』として扱います)") | |
| for word, score in cards.neighbors(w, args.n): | |
| print(f"{score:.4f}\t{word}") | |
| return 0 | |
| if args.cmd == "sim": | |
| cards = Cards.load(args.cards) | |
| print(f"{cards.similarity(args.a, args.b):.4f}") | |
| return 0 | |
| return 1 | |
| if __name__ == "__main__": | |
| raise SystemExit(main()) | |