🍎

Macで使用できるVRAMを拡張する方法と注意点

2024/10/31に公開

はじめに

どんな人向けの記事?

  • 新型Macに興味のある方
  • Macで生成AIを動かすことに興味のある方
実行環境
Mac Studio(M2 Ultra 128GB)

概要

  • Apple Silicon搭載Macでユニファイドメモリの75%以上をVRAMとして使う方法の紹介
  • 拡張したVRAMを使ってコーディング性能が高いと噂されるDeepSeek-V2.5(236B)を動かす
  • 注意点や気付きについて

結論

まず結論から書くと、下記のコマンドを打つことでVRAMに使えるメモリ容量を変更できます。

$ sudo sysctl iogpu.wired_limit_mb=[VRAMに使いたいメモリ容量(単位はMB)]

背景

ここ最近、M4チップ搭載の新型Macの予約注文が始まり、具体的な仕様も明らかになりました。

私がZennでブログ記事を書き始めたきっかけは、M2 Ultraを搭載したMac Studioを買ったことなので、新型Macと聞いて反応せずにはいられませんでした。

https://zenn.dev/robustonian/articles/selection_of_gpus_for_local_llm

そこで下記の投稿をしたわけですが、、、

https://x.com/gosrum/status/1851399725041537052

Xを眺めていると、75%以上のメモリをVRAMとして使えるみたいな表現をしている方が何人かいて、あれ?と思い、改めて75%の制約はどこから来たんのかを調べてみることにしました。

そもそも75%という数字はどこから来た?

これは、ollamaのサービスを停止した状態で下記のコマンドで確認することができました。

$ ollama serve

するとollamaが起動し、出力の最後で'msg="inference compute" id=0 library=metal variant="" compute="" driver=0.0 name="" total="96.0 GiB" available="96.0 GiB"という文字列が表示されます。私のMacはメモリが128GBなので、確かに96GB/128GB=75%となっていることを確認できます。

買った当時はXでも75%しか使えないというポストを見ていて、上記はその情報と整合していたため、75%が物理的な限界だと思い込んでいました。

このパラメータって変更できないの?

この疑問について調べたところ、簡単にパラメータの変更が出来ることが判明しました。しかも1年以上前に解決していたようです。

https://www.reddit.com/r/LocalLLaMA/comments/186phti/m1m2m3_increase_vram_allocation_with_sudo_sysctl/

パラメータを変更できるからと言って100%にするとシステムが不安定になったり、SWAPによって速度が逆に低下することがあるので最低でも8GBぐらいはシステム用に確保したほうが良いそうです。

96GB→120GBに変更してみる

というわけで、早速8GBを除いた120GBをVRAMとして使用する設定にしてみます。

$ sudo sysctl iogpu.wired_limit_mb=122880
iogpu.wired_limit_mb: 0 -> 122880

どうやらデフォルト値は0のようで、0の場合は96GB(75%)となるみたいです。

$ ollama serve
...
...
...
... msg="inference compute" id=0 library=metal variant="" compute="" driver=0.0 name="" total="120.0 GiB" available="120.0 GiB"

確かに120GBが使えるようになってます!

DeepSeek-V2.5を動かしてみる

せっかくなので、パラメータサイズ236BのDeepSeek-V2.5を動かしてみます。

https://huggingface.co/bartowski/DeepSeek-V2.5-GGUF

120GBで動きそうな最大の量子化モデルとしてIQ3_Mを採用しました。サイズが大きいのでollamaに変換するまでが少し大変でしたが、ollamaで実行してチャットできることを確認できました!

Open WebUIで動かしてみる

ollamaで動かすだけでは少し物足りないので、Open WebUIのArtifacts機能を使って、少し見栄えが良いものが作れるか検証します。

今回はかなり雑ですが、htmlとcssとjavascriptでなにか面白いものを作ってください。という無茶振りをしてみました。結果は以下の通りです。無茶振りにもめげず、一発でちょっと面白い機能が作れました。

  • スクリーンショット

スクリーンショットだけだと分かりづらいと思うので、一応動画も上げておきます。

  • 動画
    →マウスカーソルが見えないので分かりづらいですが、マウスカーソルが通過したところが光っています。

  • ソースコード含む出力(参考)

出力

HTML、CSS、JavaScript を使って簡単で楽しいアニメーション効果を持つ「インタラクティブな星屑」を作りましょう。このコードは、マウスの動きに反応して画面上に星が輝くアニメーションを作成します。

HTML (index.html)

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>インタラクティブな星屑</title>
    <link rel="stylesheet" href="styles.css">
</head>
<body>
    <div id="starsContainer"></div>
    <script src="script.js"></script>
</body>
</html>

CSS (styles.css)

body, html {
    margin: 0;
    padding: 0;
    overflow: hidden;
}

#starsContainer {
    position: absolute;
    width: 100%;
    height: 100%;
    background-color: #000;
    z-index: -1;
}

.star {
    position: absolute;
    border-radius: 50%;
    background-color: white;
    opacity: 0;
    animation: twinkle 2s infinite ease-in-out;
}

@keyframes twinkle {
    0%, 100% {
        opacity: 0;
    }
    50% {
        opacity: 1;
    }
}

JavaScript (script.js)

document.addEventListener('DOMContentLoaded', function() {
    const container = document.getElementById('starsContainer');
    let stars = [];

    // 星を生成する関数
    function createStar(x, y) {
        const star = document.createElement('div');
        star.className = 'star';
        star.style.left = `${x}px`;
        star.style.top = `${y}px`;
        star.style.width = `${Math.random() * 5 + 1}px`;
        star.style.height = star.style.width;
        container.appendChild(star);
        stars.push(star);
    }

    // マウスの動きに応じて星を生成するイベントリスナー
    document.addEventListener('mousemove', function(event) {
        const x = event.clientX;
        const y = event.clientY;
        createStar(x, y);
    });

    // 星を定期的に削除する関数
    setInterval(() => {
        if (stars.length > 0) {
            const star = stars.shift();
            container.removeChild(star);
        }
    }, 2000);
});

説明

  1. HTML: index.htmlでは、星を表示するためのコンテナ要素(#starsContainer)とJavaScriptを読み込むためのスクリプトタグが含まれています。
  2. CSS: styles.cssでは、背景色を黒に設定し、星のアニメーション(点滅)を定義しています。
  3. JavaScript: script.jsでは、マウスが動くたびに新しい星を生成し、一定時間後に削除する処理を行っています。各星はランダムな大きさとアニメーションで表示されます。

このコードを実行すると、マウスを動かすたびに画面上に点滅する星が現れるインタラクティブな効果が得られます。

脱線してしまいましたが、コーディング性能が高いと噂されるDeepSeek-V2.5が動かせて大満足です。

注意点

今回の記事でコマンド一つでMacで使用できるVRAM容量を拡張できることがわかりましたが、改めて注意点を記載しておきます。

  • システムメモリとして最低8GBは確保しておきましょう。メモリが足りなくなり、SWAPもなくなったらフリーズします。
  • たとえフリーズしなくても、SWAPが使われている状態はむしろ速度低下を招くことがあります。必要なときだけVRAMを拡張するぐらいが安全かもしれません。

また、主にローカルLLM向けに私が数ヶ月Macを動かしてきて感じたことについても言及します。
最初の記事でVRAM容量が大きければすべてを解決する、みたいな書き方をしました。
しかし、実際にはそうではありませんでした。

  • ロードするモデルのファイルサイズ(≒ そのモデルを動かす必要最小VRAM容量)が大きくなるほど、テキスト生成速度が遅くなる
    • ちなみに今回使ったDeepSeek-V2.5のようなMoEモデルなら、巨大なパラメータサイズでも、アクティブパラメータは小さいのでテキスト生成はそこまで遅くなりません。
  • ファイルサイズが大きくなるとプロンプト評価速度は劇的に遅くなる
    • しかも、どうやらこの問題はMoEモデルを使っても解決しないのではないかと思ってます。
      →少なくとも今回DeepSeek-V2.5を使った場合は、なんとプロンプト評価速度よりもテキスト生成速度の方が速いという衝撃的な結果でした。。。(表参照)
    • つまり、例え180GB近いモデルをVRAMでロードできたからといって、実用的な速度で動かせる可能性が低いと思ってます。
プロンプト評価 テキスト生成(アクティブパラメータ21B)
13.0 tokens/s 13.7 tokens/s

例えば2600tokenのソースコードを入れると、プロンプトを読み込むだけで200秒もかかってしまいます。これでは例えテキスト生成速度が10tokens/s以上あったとしても、文字を出力し始めるまでが非常に長くなり、精神的に疲れてしまいます。

まとめ

今回の記事では下記について記載しました。

  • Macで使用できるVRAMを拡張する方法
  • サイズが100GBを超えるDeepSeek-V2.5で検証
  • VRAMの拡張およびMacでローカルLLMを動かす際の注意点等

これまで推論速度の評価をあまりしてこなかったので、他のモデルとの比較グラフ等は用意できませんでしたが、今後はShaberi3ベンチマーク評価だけでなく速度も評価していきたいと思います。

最後まで読んでいただきありがとうございました。次回もぜひよろしくお願いします。

Discussion