Graniteによるコードの要約

公開日 2026年01月14日
更新日 2026年07月17日
ガラスアークの3Dレンダリング
By Joshua Noble

はじめに

コードの要約は、コードのスニペットの自然言語による記述を生成するプロセスです。一般的なコード要約の用途には、新しいコード・ベースの調査、新しいプログラミング言語の学習、コードコメントや関数の説明の生成などがあります。コード断片の要約を生成することは、自然言語文書のテキスト要約を生成することと似ています。要約を生成する大規模言語モデル(LLM)は、読み込んでいるプログラミング言語を理解するとともに、そのコードが実現しようとしている処理の基盤となるロジックを識別する必要がある点が異なります。

コード要約は、ソースコードの自動要約、ドキュメンテーション用の自然言語による要約の作成、大規模なコードベースの解析などを通じて、ソフトウェア保守を支援するソフトウェア開発の重要な要素です。Transformerベースのアプローチを採用した新しいLLMモデルは、コード要約モデルとして機能するだけでなく、コード生成も実行できます。これらの機能が可能なのは、コードやコメント、それらに対応するドキュメンテーションを含むGitHubリポジトリーなどを基に構築された大規模なデータ・セットでモデルが学習されているためです。

LLMが普及する前は、コード要約のアプローチではコードの意味を解析し、コードから各識別子の抽象構文木(AST)を生成し、それを使ってドキュメンテーションを作成する必要がありました1,2ディープラーニングとニューラル・ネットワークの登場により、コンピューター・サイエンスに基づくアプローチは、ニューラル機械翻訳の手法を取り入れたアプローチへと移行しました3,4

Transformerモデルの場合、コンテキスト・ウィンドウが大きいほど成果は向上します。Granite-8B-Code-Instruct-128Kなどの最新のGranite Codeモデルの多くは、128Kのコンテキスト・ウィンドウを備えています。コンテキスト・ウィンドウを大きくすると、モデルは作業メモリにより多くのテキストを保持できます。これにより、長時間にわたるチャットや長いドキュメント、コードベースの重要な場面や詳細を把握しやすくなります。この作業記憶により、LLMベースのチャットボットは、直近のやり取りだけでなく長い文脈全体でも一貫した応答を生成でき、人間による評価と各種評価指標の両方で、コンテキスト・ウィンドウの小さいモデルを上回る性能を発揮できます5

コンテキスト・ウィンドウが大きくなると、モデルは作業メモリーにより多くのテキストを保持できるようになり、長時間にわたるチャットや長いドキュメント、コードベースの重要な場面や詳細を把握しやすくなります。

ChatGPTが最初に導入されたとき、コンテキスト・ウィンドウは4,000トークンでした。会話がチャット・インターフェースの3,000語という制限を超えると、チャットボットはハルシネーションを起こし、本題から外れてしまう可能性がありました。現在、標準は32,000トークンであり、業界は128,000トークンに移行しています。これは250ページの本の長さです。IBMは現在、128,000トークンのウィンドウを備えた2つのGraniteモデルを用意しており、さらに多くのモデルが開発中です。

トラック上を転がるボールの3Dデザイン

最新のAIニュース + インサイト

AIやクラウドなどについて、専門家が厳選したインサイトやニュースを、Thinkニュースレターで毎週お届けします。

ステップ1:環境を設定する

このステップでは、Jupyter NotebookにアクセスするためのIBMアカウントの作成手順を説明します。

1. IBM® Cloudアカウントを使用して、watsonx.aiにログインします。

2. +をクリックして、新しいプロジェクトを作成します。

a. 「Create an empty project(空のプロジェクトを作成)」を選択します。

b. 「Name(名前)」フィールドにプロジェクト名を入力します。

c. まだ作成されていない場合は、プロジェクト資産を保管するためのCloud Object Storageを作成します。

d. 「Create(作成)」を選択します。

3. Jupyter Notebookを作成します。

a. プロジェクト環境で「Assets(資産)」タブを選択します。

b. 「New asset(新しい資産)」をクリックします。

c. 左側のパネルで「Working with models(モデルの操作)」オプションを選択します。

d. 「Working with data and models using Python and R notebooks(PythonとRノートブックを使用してデータとモデルを操作)」をクリックします。

e. 「Name(名前)」フィールドにノートブックの名前を入力します。構成を定義するには、「Runtime 23.1(4 vCPU 16 GB RAM)」の「Python」を選択します。

f. 「Create(作成)」を選択します。

4. watsonx.ai RuntimeのインスタンスとAPIキーを設定します。

a. watsonx.ai Runtimeサービス・インスタンスを作成します(適切なリージョンを選択し、無料の「Lite」プランを選択します)。

b. APIキーを生成します。

c. watsonx.ai Runtimeサービス・インスタンスを、watsonx.aiで作成したプロジェクトに関連付けます。

ステップ2:Granite Code Instructを読み込む

まず、オープンソースのHugging Face Hubライブラリーをインストールして、モデルをダウンロードします。

!pip install huggingface_hub

それでは、Granite-8B-Code-Instruct-128Kをダウンロードします。

from transformers import AutoTokenizer, AutoModelForCausalLM

tokenizer = AutoTokenizer.from_pretrained("ibm-granite/granite-8b-code-instruct-128k")
model = AutoModelForCausalLM.from_pretrained("ibm-granite/granite-8b-code-instruct-128k")

これで、Granite Code Instructを使い始められます。

ステップ3:簡単な説明を得る

GitHubリポジトリーから取得したGluonTSライブラリーのかなり複雑な関数呼び出しを、モデルに与えてみましょう。これはプロンプトに貼り付けるには長いコード・ブロックなので、変数に格納します。

ll_func_2 = """

    def call(
        self, data: torch.Tensor, weights: torch.Tensor
    ) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor]:

    assert (
        data.shape == weights.shape
    ), "data and observed_indicator must have same shape"

    with torch.no_grad():

        observed_data = torch.where(weights == 1, data, torch.nan)
        med = torch.nanmedian(observed_data, dim=self.dim, keepdim=True).values
        q1 = torch.nanquantile(observed_data, 0.25, dim=self.dim, keepdim=True)
        q3 = torch.nanquantile(observed_data, 0.75, dim=self.dim, keepdim=True)
        iqr = q3 - q1

        # if observed data is all zeros, nanmedian returns nan
        loc = torch.where(torch.isnan(med), torch.zeros_like(med), med)
        scale = torch.where(torch.isnan(iqr), torch.ones_like(iqr), iqr)
        scale = torch.maximum(scale, torch.full_like(iqr, self.minimum_scale))
        scaled_data = (data - loc) / scale

        if not self.keepdim:
            loc = torch.squeeze(loc, dim=self.dim)
            scale = torch.squeeze(scale, dim=self.dim)

        # assert no nans in scaled data, loc or scale
        assert not torch.any(torch.isnan(scaled_data))
        assert not torch.any(torch.isnan(loc))
        assert not torch.any(torch.isnan(scale))
        assert not torch.any(scale == 0)

        return scaled_data, loc, scaledef call(
            self, data: torch.Tensor, weights: torch.Tensor
        ) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor]:

        assert (
            data.shape == weights.shape
        ), "data and observed_indicator must have same shape"

 

これで、チャットをトークン化し、model.generate() を呼び出して、Granite Codeに要約を生成させることができます。

chat = [
{ "role": "user", "content": "Explain what this function does" + ll_func_2 },
]
chat = tokenizer.apply_chat_template(chat, tokenize=False, add_generation_prompt=True)

# have the encoder turn text into output tokens
inputs = tokenizer(chat, return_tensors="pt").input_ids
start_index = inputs.shape[-1]

# generate output tokens
output = model.generate(inputs, max_new_tokens=1500)

# have the decoder turn output tokens into text
output = tokenizer.batch_decode(output[start_index:])

# loop over the batch to print, in this example the batch size is 1
print(output[0])

生成された要約を確認してみましょう。

Answer:
This function performs data normalization using the interquartile range (IQR) method. It takes two arguments: data and weights. The data argument is a tensor of shape (batch_size, sequence_length, hidden_size), where batch_size is the number of samples in a batch, sequence_length is the length of the input sequence, and hidden_size is the dimensionality of the hidden state. The weights argument is a tensor of shape (batch_size, sequence_length), where each element is either 0 or 1, indicating whether the corresponding element in the data tensor is observed or missing.

The function first checks that the data and weights tensors have the same shape. Then, it computes the median and IQR of the observed data points (those with a weight of 1) using the torch.nanmedian and torch.nanquantile functions. The torch.nanmedian function computes the median along the specified dimension (`self.dim`), while the torch.nanquantile function computes the 25th and 75th percentiles.

Next, the function computes the location (`loc`) and scale (`scale`) parameters of the normalized distribution. The location is set to the median of the observed data points, and the scale is set to the IQR of the observed data points. If the observed data points are all zeros, the function sets the location to zero. The function also ensures that the scale is at least a minimum value (`self.minimum_scale`) to avoid division by zero.

Finally, the function computes the normalized data (`scaled_data`) by subtracting the location and dividing by the scale. If the keepdim argument is set to False, the function removes the specified dimension from the location and scale tensors. The function also performs assertions to ensure that the normalized data, location, and scale tensors do not contain any NaN values or zeros in the scale.

The function returns a tuple containing the normalized data, location, and scale tensors.

この説明は非常に詳細で、入力した関数とその基盤となるアルゴリズムを正確に説明しています。

ステップ4:ドキュメンテーションを生成する

ドキュメンテーションの生成は、将来そのコードを読むユーザーにコードの内容を説明するだけでなく、pydoc のようなツール向けのドキュメント生成にも役立つため、コード要約の強力な応用例です。

Granite Code に対して、関数のドキュメンテーション文字列(docstring)を生成するようプロンプトできるようになりました。コンテキストウィンドウが大きいため、docstring を生成するリクエストと共に関数全体を渡すことができます。

次の関数に対して、適切な形式の Python ドキュメンテーション文字列(docstring)を記述してください。

def get_json_from_html(html: str, key: str, num_chars: int = 2, stop: str = '"') -> str:
    pos_begin = html.find(key) + len(key) + num_chars
    pos_end = html.find(stop, pos_begin)
    return html[pos_begin:pos_end]

Granite Code は、Python 形式の優れたドキュメンテーションを生成します。

Extracts a JSON object from the given HTML string using the specified key and stop character.
Args:

    html (str): The input HTML string to extract the JSON object from.

    key (str): The key used to locate the start of the JSON object in the HTML string.

    num_chars (int, optional): The number of characters after the key to include in the extracted JSON object. Defaults to 2.

    stop (str, optional): The character that marks the end of the JSON object in the HTML string. Defaults to '"'.

Returns:

    str: The extracted JSON object as a string.

必要に応じて、大きなコンテキスト・ウィンドウ内に保持されている前のプロンプトを再利用できます。

chat = "Rewrite the previous function to be a class method and include the docstrings."

# have the encoder turn text into output tokens
inputs = tokenizer(chat, return_tensors="pt").input_ids
start_index = inputs.shape[-1]

# generate output tokens
output = model.generate(inputs, max_new_tokens=1500)

# have the decoder turn output tokens into text
output = tokenizer.batch_decode(output[start_index:])

# loop over the batch to print, in this example the batch size is 1
print(output[0])

以下が返されます。

class HtmlJsonExtractor:

    def init(self, html):

    """
    Initializes the HtmlJsonExtractor object with the given HTML string.

    Args:

        html (str): The input HTML string to extract JSON objects from.
    """

        self.html = html

    @classmethod

    def extract(cls, html, key, num_chars=2, stop='"'):

    """
    Extracts a JSON object from the given HTML string using the specified key and stop character.

    Args:

        html (str): The input HTML string to extract the JSON object from.

        key (str): The key used to locate the start of the JSON object in the HTML string.

        num_chars (int, optional): The number of characters after the key to include in the extracted JSON object. Defaults to 2.

             stop (str, optional): The character that marks the end of the JSON object in the HTML string. Defaults to '"'.

    Returns:

        str: The extracted JSON object as a string.
    """

        pos_begin = html.find(key) + len(key) + num_chars
        pos_end = html.find(stop, pos_begin)
        return html[pos_begin:pos_end]

これで、モデルは適切な名前のクラスを作成し、前のコードをそのクラスのメソッドとして配置し、docstring を挿入しました。

ステップ5:コードレビューを受ける

それでは、コード・スニペットの最適化を支援するようモデルにプロンプトしてみましょう。

chat = """Please optimize the following code:

def fib(n):
    if (n < 2):
        return 1
    else:
        return fib(n-1) + fib(n-2)"""

Granite Code は次の結果を返します。

The given Python function fib(n) calculates the nth Fibonacci number using recursion. However, this implementation has a time complexity of O(2^n), which is inefficient for large inputs. We can

optimize it using dynamic programming or memoization to reduce the time complexity to O(n). Here's an optimized version of the function:

```python

def fib_optimized(n, memo={}):
    if n < 2:
        return 1
    elif n not in memo:
        memo[n] = fib_optimized(n-1, memo) + fib_optimized(n-2, memo)
    return memo[n]
```

This optimized version uses a dictionary memo to store previously calculated Fibonacci numbers. When calculating the nth Fibonacci number, it first checks if it has already been calculated and stored in memo. If so, it returns the stored value instead of recalculating it, which saves time and improves performance.

ここで、モデルは、効率性の観点からこの関数の問題点を説明し、実装の Big-O 計算量も示しただけでなく、より優れた実装も提供しました。レビューと説明を提供することは、要約を活用する方法の一つであり、より一般的なコード生成の一環として、開発者によるコード改善を支援することにもつながります。

概要

このチュートリアルでは、コードの要約について学び、128kトークンの拡張コンテキスト・ウィンドウを備えたGranite Codeモデルを使用して、Pythonコードの説明を生成しました。また、プロンプトを使用して、新しいドキュメンテーションを生成し、コードの一部にクラスを追加し、拡張されたコンテキスト・ウィンドウを使用して、そのドキュメンテーションを新しいコード・ウィンドウに追加しました。最後に、Granite Codeにコード・スニペットを分析・要約させて、どのように改善できるか説明してもらいました。

執筆者

Joshua Noble

Data Scientist

関連ソリューション
IBM Bob

セキュリティーで保護された意図認識型の開発を実現するAIパートナー、IBM®  Bobにより、ソフトウェア・デリバリーを加速します。

IBM Bobはこちら
開発者向けAIソリューション

企業向けツールを活用し、AIアプリケーションの開発、デプロイ、管理をより迅速に実行します。

開発者向けAIの詳細はこちら
アプリケーション・モダナイゼーション・サービス

インテリジェントなAIモダナイゼーションにより、レガシー・システムを再構築します。

アプリケーション・モダナイゼーション・サービスの詳細はこちら
次のステップ

生成AIと高度な自動化を活用し、企業向けのコードをより迅速かつ一貫性を持って提供します。Bobモデルは開発者のスキルを拡張し、モダナイゼーション・ワークフローの効率化や複雑な開発タスクの簡素化を実現します。

  1. AIコーディング・エージェントの紹介
  2. 開発者向けAIソリューションの詳細はこちら
参照

1 Sonia Haiduc, Jairo Aponte, Andrian Marcus, “Supporting program comprehension with source code summarization,” ICSE ‘10: Proceedings of the 32nd ACM/IEEE International Conference on Software Engineering https://doi.org/10.1145/3377811.3380383.

2 Paul W. McBurney, Collin McMillan, “Automatic Source Code Summarization of Context for Java Methods,” https://ieeexplore.ieee.org/document/7181703.

3 Chen Lin, Zhichao Ouyang, Junqing Zhuang, Jianqiang Chen, Hui Li, Rongxin Wu, “Improving Code Summarization with Block-wise Abstract Syntax Tree Splitting” IEEE/ACM, International Conference on Program Comprehension (ICPC 2021) https://arxiv.org/abs/2103.07845.

4 Jian Zhang, Xu Wang, Hongyu Zhang, Hailong Sun, Xudong Liu, “Retrieval-based neural source code summarization,” ICSE ‘10: Proceedings of the 32nd ACM/IEEE International Conference on Software Engineeringhttps://doi.org/10.1145/1810295.1810335.

5 Xinyi Hou, Yanjie Zhao, Yue Huang, Zhou Yang, Kailong Wang, Li Li, Xiapu Luo, David Jin, John Grundy, Haoyu Wang, “Large Language Models for Software Engineering: A Systematic Literature Review”, https://arxiv.org/abs/2308.10620.