日本語対応のDeepSeek R1をローカルで Ollama や LM Studioで使ってみる


Deepseek

はじめに

サイバーエージェントさんがDeepSeekに日本語データを追加学習したLLMを公開されました。
早速、それほど高性能ではないPCを使ってローカルで動かしてみます。

検証PCのスペック

Operating System: Windows 11 Pro 64-bit (10.0, Build 26100) (26100.ge_release.240331-1435)
Processor: 12th Gen Intel(R) Core(TM) i7-12700H (20 CPUs), ~2.7GHz
Memory: 32768MB RAM
Card name: NVIDIA RTX A2000 8GB Laptop GPU

利用モデル

次の14Bモデルを量子化したモデルを利用させていただきます。

  • Q4_K_M
  • Q5_K_M
  • Q8_0

LM Studioによる動作確認

【検証1】日本一高い山の名称と標高を教えてください

Q4_K_M (1分11秒)

日本の最高峰は「富士山(ふじさん)です。
標高は3,776メートルとされます。

補足情報

  1. 測量の歴史:
    国土地理院が2013年に実施した詳細な調査では、富士山の頂点(神社側経路での最高峰地点)は約3,776mと算出されました。ただし、過去には地震や地形変動による微小な違いが報告されることもあります。
  2. 文化的背景:
    富士山は「日本百名山」の第1位に選定され、神聖な山として崇拝されています。登山道(富士宮ルート)では本宮神社から頂上まで約4.6キロメートルを歩きます。
  3. 地形図との関係:
    過去には「富士の剣釡」付近で標高測定方法に議論が起きたこともあり、厳密な数値は科学技術の進歩により微調整される可能性があります。
Q5_K_M (1分6秒)

日本で最も高い山は富士山(ふじさん)です。
その標高は、国土地理院が2017年に測定した結果に基づき 3,776.24メートル とされています。

補足情報

  • 「海抜」か「基面」で変わる理由: 富士山の標高には「海抜」と「基面(富士山頂から山麓までの垂直距離)」の解釈があります。一般的に「海抜」が使われますが、測定方法や参照点によって数値にわずかな差が出ることがあります。
  • 伝統的な認識: かつては3,782メートルとされていたことが多く、富士山頂には「標高3,780mの看板」が残っています。

話題

近年では「富士山=世界文化遺産(ユネスコ)」として登録されている点や、「富士五湖」へのアクセスなど、観光資源としても有名です。
公式情報は国土地理院のデータが最も正確ですので、旅行計画や学

Q8_0 (1分18秒)

日本最高峰は富士山(ふじさん)で、標高3,776メートル(2021年測量結果)です。
ただし、正確な数値には議論があり、観光庁が公表する「登録文化財の範囲」は4.5kmを基準としていますが、科学的な標高測定は3,768m(2021年)とされています。

補足情報

  • 活火山であり、噴火警戒レベルは**1(普段の状態)**です。
  • 毎年約3万人超が登山者として富士山に登頂します。
  • 「世界文化遺産」にも登録された神聖な山で、古くは**「聖なる槍ヶ岳」**と呼ばれることもありました。

他の主要山としては:

  • 立山(りゅうせん):標高2,953m
  • 槍ヶ岳(やりがたけ):標高3,180m
    があります。

【検証2】フィボナッチ数列のn番目を求めるPython関数

Q4_K_M  (1分52秒)

フィボナッチ数列のn番目を求めるPython関数を、以下のように実装できます。効率性を考慮したイテレーティブ(ループ処理)方式と、再帰的な方法の2つのバリエーションを提示します。

バリエーション1: イテレーティブ(O(n)時間計算量)

def fibonacci_iterative(n):
    """
    イテレーティブ方式でフィボナッチ数を計算
    
    Args:
        n (int): 0から始まるインデックスの整数
    
    Returns:
        int: F[n]
    """
    a, b = 0, 1
    if n == 0:
        return a
    for _ in range(1, n):
        a, b = b, a + b
    return b

バリエーション2: 再帰的(O(2^n)時間計算量)

from functools import lru_cache

@lru_cache(maxsize=None)
def fibonacci_recursive(n):
    """
    再帰方式でフィボナッチ数を計算(メモ化付き)
    
    Args:
        n (int): 0から始まるインデックスの整数
    
    Returns:
        int: F[n]
    """
    if n == 0:
        return 0
    elif n == 1:
        return 1
    else:
        return fibonacci_recursive(n-1) + fibonacci_recursive(n-2)

テストケース(共通)

test_cases = [
    (0, 0),   # F0=0
    (1, 1),   # F1=1
    (2, 1),   # F2=1
    (5, 5),   # F5=5
    (6, 8)    # F6=8
]

for n, expected in test_cases:
    assert fibonacci_iterative(n) == expected
    assert fibonacci_recursive(n) == expected

特徴比較

方法時間計算量メモリ使用量最適な用途
イテレーティブ方式O(n)O(1)nが大きい場合に最適(n=1e6まで対応可能)
再帰的メモ化方式O(n)O(n)nが非常に小さい場合や学習目的
答え式(ビネの公式)O(1)O(1)特殊な用途のみ(精度問題あり)

nが大きい値を扱う場合は、イテレーティブ方式か、更に高速化するためにはマトリックス法やビネの近似式など他のアルゴリズムを検討してください。

Q5_K_M (1分12秒)

フィボナッチ数列の第n項を効率的に求めるPython関数を作成します。以下の3つのアプローチがあります:

# 方法1: イテレーティブ(O(n)時間、O(1)空間)
def fibonacci_iterative(n):
    if n < 0:
        raise ValueError("n must be a non-negative integer")
    elif n == 0:
        return 0
    elif n == 1:
        return 1
    
    a, b = 0, 1
    for _ in range(2, n+1):
        c = a + b
        a = b
        b = c
    return b

# 方法2: 再帰(メモ化あり)(O(n)時間、O(n)空間)
from functools import lru_cache

@lru_cache(maxsize=None)
def fibonacci_recursive(n):
    if n < 0:
        raise ValueError("n must be a non-negative integer")
    return n if n <= 1 else fibonacci_recursive(n-1) + fibonacci_recursive(n-2)

# 方法3: 矩形行列法(O(log n)時間)
import math

def fibonacci_matrix(n):
    def matrix_mult(a, b):
        return [
            [a[0]*b[0]+a[1]*b[2], a[0]*b[1]+a[1]*b[3]],
            [a[1]*b[0]+a[2]*b[2], a[1]*b[1]+a[2]*b[3]]
        ]
    
    def matrix_power(matrix, power):
        result = [[1, 0], [0, 1]]  # 単位行列
        while power > 0:
            if power % 2 == 1:
                result = matrix_mult(result, matrix)
            matrix = matrix_mult(matrix, matrix)
            power //= 2
        return result
    
    base_matrix = [[1, 1], [1, 0]]
    powered = matrix_power(base_matrix, n-1)
    return powered[0][0]

使用方法例:

print(fibonacci_iterative(5))   # 5 (F₅=5)
print(fibonacci_recursive(7))  # 21 (F₇=21)
print(fibonacci_matrix(8))    # 34 (F₈=34)

# 大規模なn(例:n=10^6)の場合
print(fibonacci_iterative(1_000_000))

特徴比較:

方法時間計算量空間計算量
イテレーティブO(n)O(1)
再帰(メモ化)O(n)O(n)
矩形行列法O(log n)O(1)

注意事項:

  • 負のnまたは非整数に対してはエラーを発生させます
  • 大規模なn(例: n=10^6)でも効率的に計算できます
  • イテレーティブと矩形行列法はO(n)とO(log n)の時間計算量ですが、実際には定数係数が異なるため最適化が必要です

最適化例:

def fibonacci_optimized(n):
    if n < 0:
        raise ValueError("n must be a non-negative integer")
    elif n in (0, 1):
        return n
    
    a, b = 1, 0  # F2 = 1
    for _ in range(2, n+1):
        a, b = a + b, a
    return b

Q8_0 (4分54秒)

以下はフィボナッチ数列の第n項目を求めるPython関数です。効率的な反復法(O(n)計算量)を使用した実装です。

def fibonacci(n):
    if n < 0:
        raise ValueError("n must be a non-negative integer")
    
    a, b = 0, 1
    for _ in range(n):
        a, b = b, a + b
    
    return a

# 使用例
print(fibonacci(0))   # 0
print(fibonacci(1))   # 1
print(fibonacci(2))   # 1
print(fibonacci(3))   # 2
print(fibonacci(4))   # 3

特徴と注意点:

  1. エラーハンドリング: 負の数を入力するとValueErrorを発生
  2. 計算量: O(n)時間計算量(nが大きい場合は別のアルゴリズムを推奨)
  3. メモ効率: O(1)空間計算量で実装

代替アルゴリズム候補:

  • ビネの公式(O(log n)計算量):正確性に注意が必要
  • 行列分解:高速な再帰的な方法
  • 動的計画法:メモ化を活用したループ法

nが非常に大きい場合や正確な大数を扱う必要がある場合は、別のアルゴリズム(例:ビネの公式または高速二乗法)の使用を検討してください。

Ollamaでの動作確認

最近のOllamaはHugging Faceから直接モデルをダウンロードできます。
Q5_K_Mのモデルを使う場合には、次のコマンドを実行します。

ollama run hf.co/bluepen5805/DeepSeek-R1-Distill-Qwen-14B-Japanese-gguf:Q5_K_M

まとめ

ひとまず、低スペックPCでも量子化したDeepSeek R1の日本語データ追加学習モデルが動作することを確認しました。日本語の処理もそれほどおかしくはなさそうです。

回答の内容の正誤詳細は確認していません。

また、オリジナルのDeepSeekでは回答されないような中国国内の事件に関する情報も回答できていました。