iT邦幫忙

2024 iThome 鐵人賽

DAY 26
1
AI/ ML & Data

一個Kaggle金牌解法是如何誕生的?跟隨Kaggle NLP競賽高手的討論,探索解題脈絡系列 第 26

[Day 26]"是人是AI,一照便知" - 沒想到最終能找出LLM槍手的原因,是因為LLM太完美了?!

  • 分享至 

  • xImage
  •  

自從2023年大型語言模型如ChatGPT火起來後,這些AI不僅能寫出幾乎和人一樣的文章,還開始影響學生的學習方式。雖然這讓寫作業變得簡單了,但也可能讓學生們的寫作能力退步。

安娜老師是一位充滿熱情的中學教師,一直鼓勵學生們發揮創意、培養獨立思考。但最近她發現了一些奇怪的現象:有些學生的作業突然間變得特別好,卻看不到他們個人的想法和努力。這讓安娜老師起了疑心,懷疑是不是有學生在偷偷使用像ChatGPT這樣的AI工具來完成作業。

2023 年底,Study.com 調查了美國 1000 多名 18 歲以上的學生,結果發現高達 89% 的學生會用 ChatGPT 寫作業,53% 的學生甚至會用它寫論文。

面對這個現象,一部分高校老師反對學生使用像 "ChatGPT" 的生成式 AI 技術來寫作業,因為 ChatGPT 目前的寫作能力已經讓老師很難分辨到底作業是學生自己認真寫的,還是透過 chatgpt 幫忙寫的。
既然老師無法透過作業判斷學生的真實程度,就會影響課程內容的規劃和教學品質。所以在去年,美國紐約市有多家公立學校陸續禁止學生使用chatgpt幫忙寫作業,甚至有校長直接將「使用 chatgpt 幫忙寫作業」的行為和「作弊」劃上等號。

在這場紛亂中,GPTZero 一款由普林斯頓大學大四學生 Edward Tian 開發的「反AI」檢測工具,推出後幾個小時內就吸引兩千多人註冊使用。

GPTZero 主要是利用困惑度(Perplexity)和突發性(Burstiness)這兩個指標,來檢測當前輸入的文本是人類書寫的還是AI生成的。
「困惑度」(關於困惑度的介紹可以參考我在[Day16]寫的介紹)是將文本輸入到另外一個 pretrained 模型根據 loss 計算出的數值,如果對測試的AI模型來說,當前文本的困惑度很低,那代表AI模型對這些文字很熟悉,這些文字就有可能是由AI生成的。
「突發性」則是在評估輸入文本的句子結構變化程度。人類所書寫的文本往往會有長句、短句與句式結構等的變化,但 AI 生成的文本通常複雜度較低,這些句式結構的變化較少,因此可從這些特色去分辨。
image
(👆🏻圖片來源)

GPTZero 剛推出時誤報率很低,代表 AI 生成的文本和人類書寫的內容還是有明顯的特徵可以區分的。

The Learning Agency Lab 在 2023 年 11 月推出一個為期 3 個月的檢測 AI 生成文本競賽: LLM - Detect AI Generated Text,目標是鼓勵參賽者開發能準確區分中學和高中學生所寫的文章與由大型語言模型(LLM)所寫的文章的模型。

資料集介紹

這次主辦方建構了一個包含 10,000 筆由中學和高中學生以及 LLM 生成的 essay 所組成的 dataset。所有的文章都是根據七個作文題目中的一個來寫的。在每個題目中,學生被要求閱讀一到多篇 source context,然後根據題目的指示發揮撰寫文章。在使用LLM生成文章時,可能提供了同樣的信息作為輸入,也可能沒有提供。

整個 dataset 共有 7 個題目,其中挑選 2 個題目以及根據這 2 個題目所寫的 1378 篇 essay 組成訓練資料集,其中只有 3 筆是由 LLM 生成的,其他都是人類學生所寫。
所以我們可能要自己用 LLM 生成更多文本來擴增訓練資料集。

剩下的九千多筆資料來自另外五個題目所寫的 essay 構成 public 與 hidden dataset。

接下來我們來介紹主辦方提供的資料集格式:

  • {test|train}_essays.csv
    id:每篇作文的唯一識別碼。
    prompt_id:標識該篇作文的題目 id。
    text:作文的內容。
    generated:這一欄就是 label,標示作文是由學生撰寫(0)還是由 LLM(大型語言模型)生成(1)。
    image

  • train_prompts.csv
    prompt_id:每個題目的 id
    prompt_name:題目的標題
    instructions:給學生的作文指導說明。
    source_text:給學生的參考資料,學生要根據這些參考資料依據 instruction 的方向寫出作文。
    這些參考資料的格式為 Markdown。重要段落由數字編號標識,例如 0 段落一。\n\n1 段落二...,作文有時會引用這些段落編號。
    每篇文章的標題前會有標記,如 # 標題。
    如果有作者,作者的名字會在標題後面標明,例如 by 作者名。並非所有文章都有標明作者,文章中可能還包含次標題,如 ## 次標題。
    image
    (訓練集只有兩個題目(prompt))

這依然是一個 code competition,所以我們沒辦法直接看到 test data 的 text 以及 prompt 等資訊。提交的格式也不是預測 0, 1 label,而是預測「該篇文章是 LLM 生成的機率」,所以是一個介在 0~1 之間的連續小數。(當然你也可以不這樣做,我們後面會提到)
image

評估指標介紹

這次評估的方式也很單純:使用 ROC 曲線下面積(AUC-ROC)來計算預測機率和真實標籤之間的關係。
ROC AUC(Receiver Operating Characteristic Area Under the Curve)是一種用來評估二元分類模型性能的指標。它將預測結果的真陽性率(True Positive Rate, TPR)與假陽性率(False Positive Rate, FPR)進行比較,以反映模型的區分能力。

下面簡單介紹一下這個指標的計算方式~

  • 計算 ROC 曲線的步驟
  1. 排序預測分數:根據模型的預測分數,將樣本從高到低排序。預測分數可以是機率(介於 0 到 1 之間)或其他分數(如 -100 到 0),只要反映出樣本屬於正類的可能性大小即可。

  2. 確定閾值:遍歷所有預測分數作為閾值,將大於或等於此閾值的樣本分類為正類(1),否則分類為負類(0)。

  3. 計算 TPR 和 FPR:對於每個閾值,計算真陽性率和假陽性率。
    TPR(真陽性率):TPR = TP / (TP + FN),即正類被正確預測的比例。
    FPR(假陽性率):FPR = FP / (FP + TN),即負類被錯誤預測為正類的比例。

  4. 繪製 ROC 曲線:將所有閾值的 FPR 和 TPR 組成的點連接起來,即得到 ROC 曲線。

  5. 計算 AUC:AUC 是 ROC 曲線下方的面積,範圍在 0 到 1 之間。AUC 越接近 1,表示模型性能越好,越接近 0.5,表示模型區分能力接近隨機猜測。

AUC 的數學意義是隨機抽取一個正樣本和一個負樣本,模型將正樣本的預測分數判定為高於負樣本的機率。換句話說,AUC 反映了模型在所有可能的閾值下的平均性能。

AUC 衡量的是正樣本和負樣本的排序是否正確,而不是它們的實際機率值。
因此,對於 AUC 評估來說,只需要確保正樣本的預測值高於負樣本的預測值即可。即便我們提交的分數不是在 0~1 之間也沒關係,只要注意把越有可能是 AI 生成的分數打高分一些,把越有可能是人類寫的文章打低分一點就好了。

舉例來說:
假設我們有以下 5 個樣本,其真實標籤(ground truth)和模型的預測分數如下:

樣本 真實標籤 預測分數
A 1 -10
B 0 -20
C 1 -5
D 0 -15
E 1 -8

接下來我們排序預測分數由高到低:

樣本 真實標籤 預測分數
C 1 -5
E 1 -8
A 1 -10
D 0 -15
B 0 -20

然後遍歷各個閾值時的 TPR 和 FPR:

閾值 TPR FPR
>=-5 1/3 1/2
>=-8 2/3 1/2
>=-10 3/3 1/2
>=-15 3/3 1/1
>=-20 3/3 0/0

ROC 曲線的點為 (0,0), (0.5,1/3), (0.5,2/3), (0.5,1), (1,1)。計算這些點下方的面積,即為 AUC。

AUC=0.5×(1/3+2/3)+0.5×(1−2/3)=0.75
這表示該模型能以 75% 的機率正確區分正負樣本。

目前為止,你已經了解比賽的目標、資料集的概況以及 output 的格式了,與評分所使用的 metric 了。


❓❓可以暫停一下,思考看看,如果你是參賽者,你會如何設計你的第一個解題方案呢?你的第一步是什麼❓❓


到目前為止,我們可以確定的是:

  • Train data 只有兩個題目,但是 test data 有另外五個未曾見過的題目,所以要怎麼讓模型從 training data transfer 到 testing data 未曾見過的題目,是一個很重要的挑戰。
  • 一定要用 LLM 生成不同的 essay 來擴增資料,而且擴增資料要想辦法擴增一些不是 training data 那兩個題目的內容,甚至可以用不同的 LLM生成假資料來增加模型的泛化能力。

💡 Data Leakage

如果我們仔細看 training data 提供的那兩個題目的標題:

  • Car-free cities
  • Does the electoral college work?

如果有看過我在[Day 4]討論「自動作文評分競賽」的 prompt name 的話,應該會發現這兩個 prompt 跟 Persuade 2.0 Corpus 的那 15 個 prompt 重疊了。
那剩下那 5 個 prompt 會不會也出自 Persuade 2.0 Corpus 剩餘那 13 個 prompt 呢?

簡單的資料處理後,我們發現 training data 中來自 Kaggle-PERSUADE 的 essay 分別出自下面這七個 Prompt: 'Driverless cars', 'Does the electoral college work?', 'Facial action coding system', '"A Cowboy Who Rode the Waves"', 'The Face on Mars', 'Exploring Venus','Car-free cities'。
(擷取自 [Day4]「破解 prompt name」謎題的段落)

沒錯!不過這幾個比賽都是 "The Learning Agency Lab" 辦的,所以在這些 data 之間發現共通的信息好像也不足為奇~
但對參賽者來說,就可以利用這些 data leakage 來挖掘主辦方沒公開的 test data 的信息了!

既然我們開始懷疑 testing data 的 prompt 根本就是從 Persuade 2.0 Corpus 剩下的那 13 個 prompt 去挑,那我們就可以做一些 LB Probing 來測試了。
關於一些 LB Probing 的嘗試,有興趣的朋友可以參考我寫的[Day 4]探究 Train vs. Test Set 的真實差距:善用 Topic Modeling, Cross / Adversarial Validation等實用技巧!

  • 假設:主辦單位從 Persuade 2.0 Corpus 的 15 個 prompt 中挑出其中 7 個來組成本次賽題的 dataset prompts

為了驗證這個假設,我這邊提供一種可以做的 LB Probing 思路:
根據某種 rule,例如用那兩個 prompt 的 data 先訓練一個 deberta,提交一個 baseline 版本紀錄這個 baseline 的 LB 分數。接下來在提交的baseline代碼中加上:

test_prompt_name = "Driverless cars"
if (test_df.prompt_name == test_prompt_name):
    submit_df['pred'] = 0

如果測試資料中真的包含該個 prompt name 的 data,那 LB 的分數應該會比 Baseline LB 分數還要差一點,或是觀察出明顯的變化;如果沒有的話,那根本不會進入這一段代碼,所以 LB 分數還是會和 baseline LB 分數一樣。

就這樣逐一將 test_prompt_name 替換成 Persuade 2.0 Corpus 剩下的 13 個 prompt name,紀錄有哪些 prompt name 的 LB 分數和 baseline LB 分數差異較大,那代表 test data 中包含這些 prompt。

最終在網友@Carl McBride Ellis分幾天提交Probing test 後(每天有提交上限),發現 7 個 prompt 應該就是下面這些:

  • "Car-free cities"
  • "Does the electoral college work?"
  • "Exploring Venus"
  • "The Face on Mars"
  • "Facial action coding system"
  • "A Cowboy Who Rode the Waves"
  • "Driverless cars"

太好了!
有了所有 prompt name 後,我們之後就可以用這些資訊讓不同 LLM 生成假資料來擴增訓練數據集~

除此之外,我們挖出整個 dataset 用到的所有 prompt name 後,很自然就會好奇-----
那 training data 的 1378 篇 essay 是不是也都出自 Persuade 2.0 Corpus 呢? 如果是的話,我們就可以根據這些 prompt name 去 Persuade 2.0 Corpus 找對應的資訊,甚至也可以合理懷疑,test data 中的人類學生的 essay,是不是也出自 Persuade 2.0 Corpus呢?
關於這部分的假設和驗證,非常類似我們在「自動作文評分競賽」那幾天所討論的事情,所以詳細的驗證方法可以參考我在[Day2], [Day3], [Day4]寫的內容~

我們直接說結論:
如果用 exactly match 去找的話,training data 只有兩三篇可以在 Persuade 2.0 Corpus 找到一樣的 text;但是如果用模糊搜索(先用 embedding similarity 去找->再用normalized levenshtein distance < 0.3去找),可以發現有 1367/1375 篇 training data 中的 essay text 可以在 Persuade 2.0 Corpus 找到對應該筆資料,只是這些 training data 相較 Persuade 2.0 Corpus 的來源,做了一定程度的修改,包含:

在大部分被 match 的這些 essay 都可以觀察到有一些特別的 character 從 PERSUADE 的原文被移除了,以及內文中有些提到 title, closing 的部分被移除、空白符號被移除。
還在少部分的 data 觀察到有一些字母被插入或是被調換,就好像「打錯字」一樣。
舉例來說:
image
(👆🏻 圖片來源)

上圖是用 diff 比較一篇 training data 和 Persuade 2.0 Corpus match 到的原文的結果。
淺藍色是該筆 data 對應的原文有而該training data沒有的字;淺粉色則相反,是該 training data 有但是原文沒有的字)
可以發現這筆 training data 被莫名其妙插入一堆 i,而且有些本來是 "r", "s"的字母被替換成 "i",然後移除括號和第一段最後一句的大部分字母。
如果我們更深入去統計「打錯字」的情況,會發現和原文相比,有 644 筆 data 出現把原文 "a" 替換成 "t" 的情況;有 378 筆 data 把 "i" 替換成 "s",諸如此類。

[(('a', 't'), 644),
 (('i', 's'), 378),
 (('o', 's'), 173),
 (('i', 't'), 110),
 (('i', 'r'), 45),
 (('e', 'i'), 21),
 (('a', 'l'), 17),
 (('i', 'e'), 16),
 (('e', 'l'), 14),
 (('v', 'V'), 13)]

看起來就還滿奇怪的,感覺是有人根據某種 rule 把修改過的原文拿過來當 training data,在這些 training data 中製造寫作者「打錯字」的錯覺。

現在問題來了....

為什麼主辦單位要這樣做?

Typo 假設

如果我們生成一個混合大量 LLM(包含 chatgpt, llama, Claude 等開源閉源模型)生成的 essay,以及人類學生所寫的essay,來比較這些文章的錯誤率,我們可以發現:
image
(Label 1 是 AI 寫的文章, Label 0 是人類學生寫的文章)
(👆🏻圖片來源)
學生寫的文章錯字比例相比 AI 也太高了吧!

不過這好像也合理,LLM的回覆在語意內容上有可能牛頭不對馬嘴,但真的很少會有「打錯字」的情況發生。

所以如果我們用大量 AI 生成的文本,以及主辦單位提供的人類學生作文自己組一個擴增版的數據集:

Text generated with ChatGPT by MOTH (https://www.kaggle.com/datasets/alejopaullier/daigt-external-dataset)
Persuade corpus contributed by Nicholas Broad (https://www.kaggle.com/datasets/nbroad/persaude-corpus-2/)
Text generated with Llama-70b and Falcon180b by Nicholas Broad (https://www.kaggle.com/datasets/nbroad/daigt-data-llama-70b-and-falcon180b)
Text generated with ChatGPT by Radek (https://www.kaggle.com/datasets/radek1/llm-generated-essays)
Official train essays
Essays I generated with various LLMs

僅僅是靠下面 14 行 code,根據錯字率來分辨是 human 寫的還是 AI 寫的文章:

import language_tool_python
tool = language_tool_python.LanguageTool('en-US')
def how_many_typos(text):    
    return len(tool.check(text))
import pandas as pd
test_df = pd.read_csv('/kaggle/input/llm-detect-ai-generated-text/test_essays.csv', sep=',')
ntypos=test_df['text'].apply(lambda x: how_many_typos(x))
sub = pd.DataFrame()
sub['id'] = test_df['id']
sub['generated'] = -ntypos 
sub.to_csv('submission.csv', index=False)

只要這 14 行 code,在我們自己生成的擴增訓練集上就可以達到 0.951 的 ROC-AUC score!

可是!

如果我們把同樣的代碼上傳到kaggle,最後得到的 LB 分數只有:0.636。

這說明什麼呢?

說明主辦方一定也是發現人類學生寫的文章錯字率明顯比 AI 高許多,僅用這一個特徵就可以很好地區分文章是誰寫的。

為了讓賽題變得更複雜一些,Host在整個資料集上都用某種 rule,把原本正確的文章(不管是人類還是 AI 寫的),引入一定程度的錯字。
例如前面討論過的,莫名其妙插入 "i",或是把某些字母做替換,營造一種「打錯字」的感覺。
透過這些操作,在學生和 AI 寫的文章都加入一定比例的錯字率,就能避免參賽者只依靠這個特徵就能拿高分的情況。

這個發現是不是還滿有趣的呢?xdd

所以最後勝出的模型,除了可以利用「錯字率」這個特徵,還是需要從其他 linugistic 或 semantic 的角度去挖掘人類和AI作文的差異!

明天會繼續從資料觀察一些細節,逐步把金牌解法的脈絡勾勒出來~

我們明天見~


謝謝讀到最後的你,希望你會覺得有趣!
如果喜歡這系列,別忘了按下訂閱,才不會錯過最新更新,也可以按讚⭐️給我鼓勵唷!
如果有任何回饋和建議,歡迎在留言區和我說✨✨


LLM - Detect AI Generated Text 解法分享系列)


上一篇
[Day25]誰說打kaggle比賽一定要訓練模型?從第三名的解法看 Self-Consistency + Code Reasoning 之外的比賽工程技巧
下一篇
[Day 27]照妖(AI)鏡下的秘密-利用TF-IDF、BPE編碼、Kmeans Cluster和DetectGPT技術區分人類與AI寫作
系列文
一個Kaggle金牌解法是如何誕生的?跟隨Kaggle NLP競賽高手的討論,探索解題脈絡30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言