AIコードコメント検出器の改良
Better AI code comment detector (entropicthoughts.com)
要約
本記事では、AIが生成したコードコメントを検出する新しい分類器について解説しています。この分類器は公開データに基づいて構築され、77%のバランス精度を達成し、インタラクティブな機能分析を提供します。実世界のデータではさらに高い性能を示し、AI生成コードの検出能力を向上させています。
全文翻訳
AIコードコメント検出器の改良版
[画像: better-ai-comment-classifier.jpg]
以前のAIコメント分類器をトレーニングした際、私は一部個人所有の非公開データを使用し、やや不安定な基盤の上に構築したため、コードやデータを共有できませんでした。今回は、公開データとより良い基盤の上で再構築しました!
まず、試してみることをお勧めします。このWebページに貼り付けたものはブラウザから離れることはないので、安全に好きなものをお試しいただけます。テスターには早期バージョンを試してもらったところ、主に肯定的なフィードバックを得られました。
前回の記事でClaude-ismsを分析したようなロボット特有の挙動の分析は行いません。なぜなら、新しい分類器のUIでは、分類されているテキストの任意の部分をクリックするだけで、どの特徴がその部分に影響を与え、全体の判断にどのように寄与しているかを確認できるからです。以下は、拡張された特徴活性化ビューの例です。
[画像: aicomclas-demo.png]
パフォーマンスに関しては、主要な数値はバランス精度77%です。これは、人間が書いたコメントとロボットが生成したコメントが等しく発生すると仮定した場合、分類器が人間対ロボットの判定をどれだけ正しく行えるかを示しています。
分類器は予測確率も表示しますが、これはキャリブレーションされているため、特定の判定が正しい確率として読み取ることができます。これは、既知の確率を持つ事象に対して分類器が割り当てる確率を示すキャリブレーション曲線を通じてテストします。
[画像: aicomclas-calib-01.svg]
すべての点が参照対角線に非常に近いため、それらがほぼ正しいことがわかります。これは、複数の長さのコメント全体で有効であり、適合された温度パラメータがデータ量の増加に伴う信頼度の向上を調整します。
混同行列を見ることで、分類器の失敗モードについてより詳細な情報を得ることができます。この表では、「ロボット」が陽性クラス、つまり検出したいものと見なされます。略語は、真/偽の陽性/陰性率を表します。
| 判定: 人間 | 判定: ロボット | |
|---|---|---|
| 入力: 人間 | tnr = 0.73 | fpr = 0.27 |
| 入力: ロボット | fnr = 0.20 | tpr = 0.80 |
既知の人間による入力に対して、分類器は73%の時間で正しく人間であると判定します。既知のロボットによる入力に対しては、80%の時間で正しく判定されます。これは、両方のケース(既知の人間と既知のロボット)で誤り率が約25%であることを意味します。これは高く聞こえるかもしれません!
しかし、この誤り率はすべての可能な入力に対する集計値であることを忘れないでください。個々の判定については、偽陽性のリスクが低い場合や高い場合を知っているため、あまり気にする必要はありません。分類器が非常に確信している場合(例:確信度が80%以上の場合)、偽陽性のリスクは5%に低下します。分類器が不確かな場合(確信度が約50%の場合)、キャリブレーションにより約半分の確率で誤った判定を下します。
この混同行列の数値は、分類器について議論する際に非常に頻繁に使用されるため、より学術的な読者が期待するかもしれないので、言及するだけです。以下に、その他の要求された数値を示します。
| 精度 (Accuracy) | 77% |
| 適合率 (Precision) | 75% |
| 再現率 (Recall) | 80% |
| 感度 (Sensitivity) | 80% |
| 特異度 (Specificity) | 73% |
| F1スコア | 77% |
精度、適合率、F1スコアはベースレートに依存しますが、ここでは無知の仮定、つまり人間が書いたコメントとロボットが生成したコメントの均等な混合から計算されています。
これらの数値はすべてクロスバリデーションから得られています。また、人間とロボットによる実際のコメントの小規模な非合成セットを手動でテストし、分類器がサンプル外でどの程度うまく一般化するかを確認しました。
| 判定: 人間 | 判定: ロボット | |
|---|---|---|
| 入力: 人間 | tnr = 0.89 | fpr = 0.11 |
| 入力: ロボット | fnr = 0.14 | tpr = 0.86 |
これは以下のパフォーマンス数値に翻訳されます。
| 精度 (Accuracy) | 88% |
| 適合率 (Precision) | 89% |
| 再現率 (Recall) | 86% |
| 感度 (Sensitivity) | 86% |
| 特異度 (Specificity) | 89% |
| F1スコア | 87% |
これは非常に良好です!非合成で、より現実世界のケースの方が、トレーニングデータよりも分類器が識別しやすいようです。
もちろん、これらすべてはコードコメントのみでテストされています。この分類器は、他の種類のロボット生成テキストを検出するために構築されたものではありません。検出は可能ですが、その精度については保証しません。
さて、それが済んだところで、どのように作られたかについて話しましょう。
データ収集
最初のステップは、以前と同様に、良いデータセットを構築することです。理想的には、これを綿密に計画し、最初から正しく行うでしょう。もしそうすれば、この分類器を動かすデータセットを得るのに約30ドルで済むはずです。これは、より類似したモデルを識別する上で収穫逓減に達するのに十分なデータを含んでいます。11 より強力な分類器をより多くのデータで抽出することは可能ですが、分類器のパワーは支出額の対数に比例してスケールするように見えるため、非常に高価になります。つまり、計画を立てて最初から正しく行えば、の話です。私はそうしませんでした。特徴を評価しているときに、持っていたデータがジャンクであり、すべて再収集する必要があることを後になって発見しました22 💸。それからしばらくして、データがまだジャンクであり、再び再収集する必要があることを再び発見しました33 💸💸💸。
一般的なアイデアは、許可されたライセンスまたはコピーレフトのリポジトリのセットを見つけ、それらの最新コミットを2021年のものからチェックアウトし、そのコミットからいくつかのランダムなファイルを取得することでした。これらは人間が書いたコメントを含んでいます。次に、それらのファイルからすべてのコメントを削除し、同じファイルに対してLLMに新しいコメントを生成させます。これにより、ロボットコメントが得られます。各ファイルあたりのトークン数をすべてのクラス(人間とLLMモデル)間でバランスさせるように努める限り、分類器がテキストのスタイル自体ではなく、ファイルやリポジトリを区別することを学習するような、主題の漏洩を防ぐことができます。
一般的なアイデアはシンプルです!しかし、悪魔は通常、そこにいます。私が犯した間違いをいくつか挙げます(順不同):
- 各LLMに異なるソースファイルを指定してコメントを生成させてしまった。これは主題の漏洩を引き起こします。
- 人間のコメントが非常に少ないファイルに対してLLMコメントを生成した。これも人間とロボットの境界を越えた主題の漏洩を引き起こします。
- ソースファイル内の人間のコメントを隠蔽する際に、ドキュメンテーション文字列(docstrings)を削除し忘れた。これにより、LLMは既存のリポジトリのスタイルに合わせようとするため、人間により似たコメントを生成します。ただし、これは思ったよりも影響が小さかったと言えます。
- 上記に関連して、一部の言語はコメントに対して多くの異なる構文をサポートしており、一部は他のものよりも頻繁に使用されます。すべての構文で既存のコメントを検出できなかった場合、コメントが残ってLLMの生成を汚染し、生成されたすべてのデータを取得するのを困難にします。
- 非常に短い人間のコメントをフィルタリングしなかった。ほとんどの人間のコメントは、「main task structure」や「chIcon」、「Alias」のようなものしか言わず、それらを含めると、人間はひどい書き方をするということを分類器に教えてしまいます。LLMはより詳細なコメントを書くように指示されていたため、より詳細な人間のコメントと比較するのが理にかなっています。
- LLMコメント生成に固定されたプロンプトを使用した。これは、モデルと人間を分離するために必要なすべての奇妙な点を学習するには、バリエーションが狭すぎるデータセットにつながります。
これらの問題のすべてが、データを最初から再生成する必要があったわけではありません。既存のデータをフィルタリングおよび前処理することで回避できたものもありました。いずれにせよ、これはプロジェクトの中で最も楽しくない部分であり、理論上の30ドルよりもはるかに多くの費用がかかりました。
特徴評価
データ収集後、そのデータで機能する分類器を設計する必要があります。これは、候補となる特徴(feature)を評価することを意味します。これは金銭的には高価ではありませんが、CPU時間がかかります。特徴を最も強力な意味で評価することは、候補となる特徴のすべてのサブセットで分類器をトレーニングし、どれが最もパフォーマンスが良いかを確認することを意味します。これは現実的ではありません。15個の候補特徴しかない場合でも、30,000を超える異なる分類器をトレーニングする必要があり、それらはクロスバリデーションのためにそれぞれ5回トレーニングする必要があります。
最終的に私がやったのは、個々の特徴でトレーニングされた分類器の精度によって特徴選択をガイドすることでした。つまり、「文字の頻度分布は、単語の長さよりもロボットと人間の区別に優れているか?」をチェックするスクリプトを作成し、異なる特徴や異なるクラスとの比較のためにそれを繰り返しました。44 異なるクラスとは、ロボット対人間の比較だけでなく、Claude対Grok、GPT対Geminiなどの比較も含まれることを意味します。
クラスペアの比較ごとに、特徴ランキングのリストが生成されました。これらのリストは、特徴の順序についてほとんど合意していましたが、いくつかの不一致もありました。特徴のパワーによるランキングと、相対ランキングに関する不一致の強さが、以下のグラフに示されています。
[画像: aicomclas-singlefeats.svg]
グラフは直感的に読めると思いますが、念のため説明します。
- 黒い矢印は、接続された2つの特徴の相対的な強さについて、すべての比較が合意したことを意味します。55 技術的には、比較が合意しなかった場合でも、反対意見ではなかったことを意味します。つまり、4つの比較で特徴AとBがほぼ同じパワーであると示され、5番目の比較で特徴Aが特徴Bよりも優れていると示された場合、グラフは5分の4の意見にもかかわらず、BからAへの黒い矢印を表示します。
- 青い矢印は、少なくとも2つの比較で2つの特徴の相対的な強さについて合意し、1つの比較のみが不一致であったことを意味します。
- 赤い矢印は、より多くの不一致(矢印のラベルに正確な数値が表示されています)を示しますが、矢印は支配的な意見の方向に向けられています。
各特徴ボックスには、ビット単位の情報量も表示されています。これは、その特徴が2つのクラスを区別するのに平均してどれだけ役立つかを示しています。
このグラフは非常に楽しく見られるだけでなく、非常に有益でもあります!特徴名は意味不明かもしれませんが、それぞれについて簡単な説明をします。実行例として、ドナルド・トランプの演説からの以下の抜粋と、エコノミストの記事からの同様のランダムな抜粋を使用します。
markets are at their highest point in many years but we can actually say of all time
the oecd member countries that have taken part in every edition of pisa reached a peak around
以下がその特徴です。
-
bigwords: コメント中の5文字より長い単語の割合。派手な言語の古典的なスタイルマーカーですが、明らかな場合を除いて、区別には非常に弱い特徴です。トランプ氏の抜粋の
bigwords値は18%ですが、エコノミストの記事は29%です。 -
wordlen: 各単語をその単語の長さを表す数値に置き換え、頻度をカウントします。これはbigwordsに似ていますが、分布全体を捉えます。トランプ氏の単語は3文字が30%、2文字が24%、4〜7文字がそれぞれ15%、それ以上が6%です。エコノミストはより広い分布を持ち、最も一般的な長さ(35%)は4文字で、次に2〜7文字の範囲で非常に均等な割合、9文字と1文字がそれぞれ5%です。
-
freqrank: 各単語を、その単語の一般的な度合いに基づいた数字に置き換えます。最も一般的な単語は0、その後の10個は1、さらにその後の100個は2、といった具合です。そして、これらの数字の頻度をカウントします。トランプ氏は主にランク2とランク3の単語をそれぞれ50%と30%の頻度で使用しています。これは上位100位と上位1000位の単語に対応します。エコノミストの記事にはランク2の単語は非常に少なく(ランク1の単語は多いですが!)、ランク3とランク4の単語を多く含んでおり、これもトランプ氏よりも複雑な語彙を示しています。
-
wordfreq: 少数の機能語の頻度をカウントします。「the」、「in」、「many」、「all」などの内容の薄い単語をテキストがどれだけ含んでいるかを確認します。トランプ氏の例では機能語を繰り返していませんが、この特徴は anyway 単語「are」、「at」、「their」、「in」、「many」、「but」、「we」、「can」、「of」、「all」の単一の出現を報告します。エコノミストの記事には異なるセットがあります:「the」、「that」、「have」、「part」、「in」、「every」、「of」、「a」、「around」。これらの短い抜粋では、これはあまり多くを語りませんが、より多くのデータがあれば、テキストのソースを区別し始めることができます。
-
word2gram: 機能語と他の単語をフィルタリングした単語のバイグラムをカウントします。これは元のテキストにはなかった奇妙なバイグラムを生成しますが、人々の書き方を分析する一般的な方法であり続けています。トランプ氏の例では、他のバイグラムの中でも「are at」、「at their」、「their in」、「in many」、「many but」などがあります。エコノミストは「the that」、「that have」、「have part」、「part in」などがあります。
-
word2gram_adj: 他の単語をフィルタリングせずに、実際にテキスト中で隣接して見つかった場合にのみ、機能語のバイグラムをカウントします。これは、元のテキストに実際に存在したバイグラムのみを生成するため、書き方を分析するより自然な方法のように思えますが、グラフからわかるように、通常のword2gramよりも弱い指標です。トランプ氏の例では、「are at」、「at their」がありますが、その後「in many」にジャンプし、さらに「but we」、「we can」などにジャンプします。エコノミストは「that have」、「part in」、「in every」に還元されます。エコノミストは機能語の文字列が少ないことがわかります。
-
word3gramとword3gram_adjは、前の2つと同様ですが、トリグラム(3単語の連なり)です。トランプ氏の例では、
word3gram_adjに「are at their」と「but we can」という2つの値があります。エコノミストには「part in every」という1つだけです。 -
charfreq: コメント中の各文字の頻度をカウントします。ソースが記号の使用に異なる傾向がある場合、これは強力な信号になり得ます。トランプ氏とエコノミストの両方が英語を使用しており、選択した断片の単語数が同じであるため、文字の頻度は実際には非常に似ています。
-
char2gramとchar3gram: コメント中の文字のバイグラムとトリグラムの頻度をカウントします。これは、句読点や単語選択のスタイルについて何かを語り始めます。トランプ氏もエコノミストもこれらの抜粋で句読点を使用しなかったため、文字の頻度のみを見ることができます。これらの例では、バイグラム「space-followed-by-a」に基づいて、トランプ氏がエコノミストよりも「a」で単語を開始する頻度が高いことがわかります。対照的に、エコノミストはトランプ氏よりも「n」で単語を終了する頻度が高いです。
-
wordfreq_raw: 単語の頻度をカウントしますが、機能語に限定されません。この利点は、ソースが強く好む単語(例えば、「mediated」のような機能語リストにはないが、生の単語頻度があれば分類器はその単語で区別を学習できる)がある場合です。66 そして、彼らは編集者の「お気に入りを殺せ」というアドバイスに従わなかった。しかし、これは危険な特徴でもあり、分類器が主題の違いを捉えてしまう可能性があります。例えば、エコノミストの場合、テキストに略語「oecd」が含まれていればエコノミストのものであると学習するかもしれませんが、単語「actually」が含まれていればドナルド・トランプのものであると学習するかもしれません。77 まあ、それは悪いルールではないかもしれませんが、他のケースでは意図しない結果につながる可能性があることがわかります!
ただし、コードコメント分類器のためにバランスの取れたデータセットを構築するのに苦労したことを思い出してください。そこでその成果が現れます。生の単語頻度特徴には主題の漏洩はほとんどなく、代わりに実際のスタイル上の癖を捉えています。
-
word2gram_raw、word3gram_raw: 機能語をフィルタリングせずに、単語のバイグラムとトリグラムの頻度を取ります。 -
wink、upos、ptb: 各単語を品詞(pos)タグに変換し、それらのposタグの頻度をカウントします。これが強力な信号である理由は、単語の選択に気を取られることなく、異なるソースがどのように自身を表現するかを捉えることができるからです。この特徴の3つのバリアントは、異なる品詞タグ付けエンジンを使用していますが、88 一部のエンジンは他のエンジンよりも正確です。しかし、それらはすべてほぼ同じ結果を生成します。
wink-nlpエンジンの利点は、グラフでは他の2つよりも弱いですが、ブラウザで実行できることです。品詞タグの置き換えは、トランプ氏の演説を
NNS VBP IN PRP$ JJS NN IN JJ NNS CC PRP MD RB VB IN DT NNのようなシーケンスに変換します。このシーケンスはエコノミストよりも複数名詞(NNS)が多く含まれていますが、エコノミストは一方で固有名詞(NNP)と限定詞(DT)をより多く含んでいます。 -
wink2gram、upos2gram、ptb2gram、wink3gram、upos3gram、ptb3gramは、上記のバイグラムおよびトリグラムのバリアントです。
単一の特徴で分類器を評価する場合、上記のグラフが表すものですが、品詞タグのn-グラムは、どのタグ付けエンジンを使用しても非常に強力であることがわかります。文字のn-グラムも強力であり、生の単語頻度も悪くありません。
しかし、単一の特徴だけでは不十分です。なぜなら、複数の特徴で分類器をトレーニングすると、特徴は相互作用するからです。相互作用により、一部の特徴は冗長になりますが、特徴の組み合わせが個々の特徴よりも強力になることもあります!私はトップスコアリングの単一特徴のセットから始め、個々の特徴を追加および削除してそれらが互いにどのように影響するかを確認することで、特徴の組み合わせを体系的に評価しましたが、最終的にはその演習にうんざりして、本番用分類器の特徴セットをかなり任意に選択しました。99 また、トレーニングスクリプトには、特徴とその関連頻度が区別されるクラス間でどのように変化するかを探索できるいくつかのサブコマンドもありました。
分類の解釈
分類器は7つの方法で分類するようにトレーニングされています。単一のコメントが与えられると、以下の7つのソースを区別しようとします。
- 人間
- GPT 5.6
- Gemini 3.7
- Claude 5
- Kimi K2.7
- Grok 4.6
- GLM 5.2
しかし、しばらくすると、何かが奇妙に思えてきました。Kimi K2.7またはGLMが最も可能性の高いLLMモデルの1つであるとほぼ常に予測されました。特徴ベクトルの中心点のプロットをしばらく行った後、これらの2つのモデルのスタイルが他のすべてのモデルと重複していることが明らかになりました1010 分解(distillation)がどのように機能するかはわかりませんが、関連用語のように聞こえます。そのため、分類器の判断は、実際のソースに割り当てられるのではなく、それらの2つのモデルに部分的に分散されます。代わりに、それらのモデルなしで分類器を再トレーニングするのではなく、分類時にそれらのモデルに割り当てられた確率質量を、トレーニング中にそれらから吸い取った質量の割合に応じて、残りのモデルに再分散させます。これにより、Kimi K2.7は主にGrokとClaudeに確率を寄付し、GLMは他のすべてのモデルにほぼ均等に寄付します。
また、分類器を使い始めたときに、私が本当に知りたいのはコメントが人間によって書かれたものかロボットによって生成されたものかであり、どのLLMモデルがコメントを生成したかを知ることはめったに重要ではないことに気づきました。そのため、分類段階で、分類器がトレーニングされている1/7の事前確率ではなく、人間/ロボットの50/50の事前確率を模倣するように確率質量が再正規化されます。
7方向の分類器をトレーニングし、5方向の分類器に縮小し、さらに2方向の分類に単純化するのは、ばかげているように見えるかもしれません。最初から2方向の分類器をトレーニングすることもできたはずです!しかし、複雑な方法で行うことには2つの利点があります。
- メインの予測の隣にクールなLLMモデルの内訳を表示できるようになります。
- 人間が書いたものとロボットが生成したテキストを分離する高次元表面の複雑な形状をより良く捉えることができるかもしれません。
縮小された7方向分類器とトレーニングされた2方向分類器の正式なベンチマークはまだ実行していませんが、パフォーマンスの違いはそれほど大きくないと思いますので、最初の点を真の利点と考えてください。
残っている問題の1つは、前の記事と同じ問題です。L1正規化された特徴では、ロジスティック回帰の結果の確率が非常に小さくなります。別のパスでトレーニングされたモデルを取得し、入力の長さの平方根に基づいた予測を極端化する温度係数kをキャリブレーションします。
インターフェースの構築
最初は分類用のCLIインターフェースを構築しましたが、すぐに以下のことに気づきました。
- モデルをバンドルしたWebページとして提供すれば、他の人が遊びやすくなるでしょう。
- より洗練された診断インターフェースがあれば、私が診断やトラブルシューティングを行うのが容易になり、ブラウザの方が簡単でしょう。
分類器モデルのサイズが、生の形式で数メガバイトに達することを心配していました。そのため、係数を量子化し、ドキュメント頻度フィルターですべての特徴の語彙を削減しました。つまり、コメントの小さなサブセットにしか存在しない特徴値を削除しました。精度曲線には約0.05%の膝があり、これはコメントのその割合未満にしか存在しない特徴値は分類器の一部ではないことを意味します。モデルは現在355 kBです。
Webインターフェースがもたらしたもう1つの変更点は、ブラウザで入力の品詞タグ付けができるようになる必要があったことです!これにより、パフォーマンスの高いPythonベースのエンジン(nltkとspaCy)が利用できなくなり、wink-nlpを使用せざるを得なくなりました。理論的には、一方のエンジンでトレーニングし、もう一方のエンジンで分類入力を前処理しても問題はないはずですが、入力が些細な理由でサンプル外になるのを避けるために、Pythonでもwink-nlpを使用することを選択しました。これはPythonがNode.jsプロセスを呼び出すことを意味し、あまりきれいではありません。
最終的な注意点
しかし、ソースコードはどこに?ソースコードを約束しました!
私は本当に、これらすべてについて自分でコードを書くつもりでした。モデル、特徴、可視化などを使った実験をロボットに生成させ、最終バージョンは自分で書き直して、コードの品質を保証するつもりでした。
しかし、私はそれをしたくありません。これはサイドクエストであり、多くの時間を費やすことができるものではありません。AIのゴミコードを読みたくないなら、実装を読まないでください。代わりに、どのように行われたかのこの説明を読んで、自分で作ることもできるかもしれません。
また、Sourcehutの新しい利用規約が明日からすべての変更に適用され、LLM生成コードをホストするためにそれを使用することが禁止されているため、これに取り組む可能性は低いでしょう。この形でお楽しみください!