Upload 3 files
Browse files- app.py +68 -30
- models/watermark_faster.py +14 -16
app.py
CHANGED
@@ -1,13 +1,18 @@
|
|
1 |
import gradio as gr
|
2 |
from models.watermark_faster import watermark_model
|
3 |
-
import pdb
|
4 |
from options import get_parser_main_model
|
5 |
|
6 |
opts = get_parser_main_model().parse_args()
|
7 |
-
model = watermark_model(language=
|
8 |
-
def watermark_embed_demo(raw):
|
9 |
|
10 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
11 |
return watermarked_text
|
12 |
|
13 |
def watermark_extract(raw):
|
@@ -16,42 +21,75 @@ def watermark_extract(raw):
|
|
16 |
|
17 |
return f"{confidence:.2f}%"
|
18 |
|
19 |
-
def precise_watermark_detect(raw):
|
20 |
-
is_watermark, p_value, n, ones, z_value = model.watermark_detector_precise(raw)
|
21 |
confidence = (1 - p_value) * 100
|
22 |
|
23 |
return f"{confidence:.2f}%"
|
24 |
|
25 |
-
|
26 |
demo = gr.Blocks()
|
27 |
with demo:
|
28 |
with gr.Column():
|
29 |
-
gr.
|
30 |
-
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
-
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
50 |
|
51 |
-
|
|
|
|
|
|
|
|
|
52 |
|
|
|
53 |
|
54 |
if __name__ == "__main__":
|
55 |
gr.close_all()
|
56 |
demo.title = "Watermarking Text Generated by Black-Box Language Models"
|
57 |
-
demo.launch()
|
|
|
1 |
import gradio as gr
|
2 |
from models.watermark_faster import watermark_model
|
|
|
3 |
from options import get_parser_main_model
|
4 |
|
5 |
opts = get_parser_main_model().parse_args()
|
6 |
+
model = watermark_model(language=opts.language, mode=opts.mode, tau_word=opts.tau_word, lamda=opts.lamda)
|
|
|
7 |
|
8 |
+
def create_model(language,tau_word):
|
9 |
+
global model
|
10 |
+
model = watermark_model(language=language, mode=opts.mode, tau_word=tau_word, lamda=opts.lamda)
|
11 |
+
# gr.update(visible=True)
|
12 |
+
return language,tau_word
|
13 |
+
def watermark_embed_demo(raw,tau_word):
|
14 |
+
|
15 |
+
watermarked_text = model.embed(raw,tau_word)
|
16 |
return watermarked_text
|
17 |
|
18 |
def watermark_extract(raw):
|
|
|
21 |
|
22 |
return f"{confidence:.2f}%"
|
23 |
|
24 |
+
def precise_watermark_detect(raw,tau_word):
|
25 |
+
is_watermark, p_value, n, ones, z_value = model.watermark_detector_precise(raw,tau_word)
|
26 |
confidence = (1 - p_value) * 100
|
27 |
|
28 |
return f"{confidence:.2f}%"
|
29 |
|
|
|
30 |
demo = gr.Blocks()
|
31 |
with demo:
|
32 |
with gr.Column():
|
33 |
+
with gr.Row():
|
34 |
+
with gr.Column(scale=9):
|
35 |
+
gr.Markdown(
|
36 |
+
"""
|
37 |
+
# 💦[Watermarking Text Generated by Black-Box Language Models](https://arxiv.org/abs/2305.08883)
|
38 |
+
"""
|
39 |
+
)
|
40 |
+
language = gr.Dropdown(
|
41 |
+
label="Language", choices=["English", "Chinese"], value="English"
|
42 |
+
)
|
43 |
+
tau_word = gr.Number(label="tau_word", value=0.8)
|
44 |
+
|
45 |
+
# with gr.Column():
|
46 |
+
# with gr.Row():
|
47 |
+
# gr.Markdown("# Watermarking Text Generated by Black-Box Language Models")
|
48 |
+
# with gr.Row(scale=0.25):
|
49 |
+
# language = gr.Dropdown(
|
50 |
+
# label="Language", choices=["English", "Chinese"], value="English"
|
51 |
+
# )
|
52 |
+
# tau_word = gr.Number(label="tau_word", value=0.8)#gr.Slider(0, 1, value=0.8, label="tau_word", info="Choose between 0 and 1")
|
53 |
+
# model_button = gr.Button("Load Model")
|
54 |
+
# inputs = [language,tau_word]
|
55 |
+
# model_button.click(fn=create_model, inputs=inputs,outputs=[language,tau_word])
|
56 |
+
with gr.Tab("Welcome"):
|
57 |
+
gr.Markdown(
|
58 |
+
"""
|
59 |
+
This space exhibits a watermarking technique that allows third parties to independently inject an authentication watermark into generated text.
|
60 |
+
We provide implementations for both English and Chinese text (you can select the respective language in the top right corner).
|
61 |
+
Furthermore, you can adjust the value of $\\tau_{word}$ to control the similarity between the original text and the watermarked text.
|
62 |
+
We recommend setting $\\tau_{word}$ at 0.8 for English and 0.75 for Chinese.
|
63 |
+
Generally, a larger $\\tau_{word}$ increases the similarity between the original and watermarked text, but it also weakens the strength of the watermark.
|
64 |
+
More details can be found in our [ArXiv preprint](https://arxiv.org/abs/2305.08883).
|
65 |
+
"""
|
66 |
+
)
|
67 |
+
with gr.Tab("Watermark Injection & Detection"):
|
68 |
+
language.change(fn=create_model, inputs=language,outputs=language)
|
69 |
+
with gr.Row():
|
70 |
+
inputs = gr.TextArea(label="Input text", placeholder="Copy your text here...")
|
71 |
+
output = gr.Textbox(label="Watermarked Text",lines=7)
|
72 |
+
analysis_button = gr.Button("Inject Watermark")
|
73 |
+
inputs_embed = [inputs,tau_word]
|
74 |
+
analysis_button.click(fn=watermark_embed_demo, inputs=inputs_embed, outputs=output)
|
75 |
+
|
76 |
+
inputs_w = gr.TextArea(label="Text to Analyze", placeholder="Copy your watermarked text here...")
|
77 |
+
with gr.Row():
|
78 |
+
mode = gr.Dropdown(
|
79 |
+
label="Detection Mode", choices=["Fast", "Precise"], value="Fast"
|
80 |
+
)
|
81 |
+
output_detect = gr.Textbox(label="Confidence (the likelihood of the text containing a watermark)")
|
82 |
+
detect_button = gr.Button("Detect")
|
83 |
|
84 |
+
def detect_watermark(inputs_w, mode, tau_word):
|
85 |
+
if mode == "Fast":
|
86 |
+
return watermark_extract(inputs_w)
|
87 |
+
else:
|
88 |
+
return precise_watermark_detect(inputs_w,tau_word)
|
89 |
|
90 |
+
detect_button.click(fn=detect_watermark, inputs=[inputs_w, mode, tau_word], outputs=output_detect)
|
91 |
|
92 |
if __name__ == "__main__":
|
93 |
gr.close_all()
|
94 |
demo.title = "Watermarking Text Generated by Black-Box Language Models"
|
95 |
+
demo.launch(share = True, server_port=8898)
|
models/watermark_faster.py
CHANGED
@@ -8,8 +8,8 @@ import hashlib
|
|
8 |
from scipy.stats import norm
|
9 |
import gensim
|
10 |
import pdb
|
11 |
-
|
12 |
-
|
13 |
from transformers import AutoTokenizer, AutoModelForSequenceClassification
|
14 |
|
15 |
from transformers import BertForMaskedLM, BertTokenizer, RobertaForSequenceClassification, RobertaTokenizer
|
@@ -21,8 +21,6 @@ import paddle
|
|
21 |
from jieba import posseg
|
22 |
paddle.enable_static()
|
23 |
import re
|
24 |
-
nltk.download('punkt')
|
25 |
-
nltk.download('averaged_perceptron_tagger')
|
26 |
def cut_sent(para):
|
27 |
para = re.sub('([。!?\?])([^”’])', r'\1\n\2', para)
|
28 |
para = re.sub('([。!?\?][”’])([^,。!?\?\n ])', r'\1\n\2', para)
|
@@ -70,6 +68,7 @@ class watermark_model:
|
|
70 |
self.w2v_model = api.load("glove-wiki-gigaword-100")
|
71 |
nltk.download('stopwords')
|
72 |
self.stop_words = set(stopwords.words('english'))
|
|
|
73 |
|
74 |
def cut(self,ori_text,text_len):
|
75 |
if self.language == 'Chinese':
|
@@ -273,8 +272,7 @@ class watermark_model:
|
|
273 |
return all_processed_tokens,new_index_space
|
274 |
|
275 |
|
276 |
-
def filter_candidates(self, init_candidates_list, tokens, index_space, input_text):
|
277 |
-
|
278 |
all_context_word_similarity_scores = self.context_word_sim(init_candidates_list, tokens, index_space, input_text)
|
279 |
|
280 |
all_sentence_similarity_scores = self.sentence_sim(init_candidates_list, tokens, index_space, input_text)
|
@@ -287,7 +285,7 @@ class watermark_model:
|
|
287 |
for idx, candidate in enumerate(init_candidates):
|
288 |
global_word_similarity_score = self.global_word_sim(tokens[masked_token_index], candidate)
|
289 |
word_similarity_score = self.lamda*context_word_similarity_scores[idx]+(1-self.lamda)*global_word_similarity_score
|
290 |
-
if word_similarity_score >=
|
291 |
filtered_candidates.append((candidate, word_similarity_score))
|
292 |
|
293 |
if len(filtered_candidates) >= 1:
|
@@ -320,7 +318,7 @@ class watermark_model:
|
|
320 |
|
321 |
return best_candidates, new_index_space
|
322 |
|
323 |
-
def watermark_embed(self,text):
|
324 |
input_text = text
|
325 |
# Tokenize the input text
|
326 |
tokens = self.tokenizer.tokenize(input_text)
|
@@ -344,7 +342,7 @@ class watermark_model:
|
|
344 |
init_candidates, new_index_space = self.candidates_gen(tokens,index_space,input_text, 8, 0)
|
345 |
if len(new_index_space)==0:
|
346 |
return text
|
347 |
-
enhanced_candidates, new_index_space = self.filter_candidates(init_candidates,tokens,new_index_space,input_text)
|
348 |
|
349 |
enhanced_candidates, new_index_space = self.get_candidate_encodings(tokens, enhanced_candidates, new_index_space)
|
350 |
|
@@ -356,7 +354,7 @@ class watermark_model:
|
|
356 |
watermarked_text = re.sub(r'(?<=[\u4e00-\u9fff])\s+(?=[\u4e00-\u9fff,。?!、:])|(?<=[\u4e00-\u9fff,。?!、:])\s+(?=[\u4e00-\u9fff])', '', watermarked_text)
|
357 |
return watermarked_text
|
358 |
|
359 |
-
def embed(self, ori_text):
|
360 |
sents = self.sent_tokenize(ori_text)
|
361 |
sents = [s for s in sents if s.strip()]
|
362 |
num_sents = len(sents)
|
@@ -369,9 +367,9 @@ class watermark_model:
|
|
369 |
sent_pair = sents[i]
|
370 |
# keywords = jieba.analyse.extract_tags(sent_pair, topK=5, withWeight=False)
|
371 |
if len(watermarked_text) == 0:
|
372 |
-
watermarked_text = self.watermark_embed(sent_pair)
|
373 |
else:
|
374 |
-
watermarked_text = watermarked_text + self.watermark_embed(sent_pair)
|
375 |
if len(self.get_encodings_fast(ori_text)) == 0:
|
376 |
# print(ori_text)
|
377 |
return ''
|
@@ -411,7 +409,7 @@ class watermark_model:
|
|
411 |
is_watermark = z >= threshold
|
412 |
return is_watermark, p_value, n, ones, z
|
413 |
|
414 |
-
def get_encodings_precise(self, text):
|
415 |
# pdb.set_trace()
|
416 |
sents = self.sent_tokenize(text)
|
417 |
sents = [s for s in sents if s.strip()]
|
@@ -441,7 +439,7 @@ class watermark_model:
|
|
441 |
continue
|
442 |
|
443 |
init_candidates, new_index_space = self.candidates_gen(tokens,index_space,sent_pair, 8, 0)
|
444 |
-
enhanced_candidates, new_index_space = self.filter_candidates(init_candidates,tokens,new_index_space,sent_pair)
|
445 |
|
446 |
# pdb.set_trace()
|
447 |
for j,idx in enumerate(new_index_space):
|
@@ -451,9 +449,9 @@ class watermark_model:
|
|
451 |
return encodings
|
452 |
|
453 |
|
454 |
-
def watermark_detector_precise(self,text,alpha=0.05):
|
455 |
p = 0.5
|
456 |
-
encodings = self.get_encodings_precise(text)
|
457 |
n = len(encodings)
|
458 |
ones = sum(encodings)
|
459 |
if n == 0:
|
|
|
8 |
from scipy.stats import norm
|
9 |
import gensim
|
10 |
import pdb
|
11 |
+
from transformers import BertForMaskedLM as WoBertForMaskedLM
|
12 |
+
from wobert import WoBertTokenizer
|
13 |
from transformers import AutoTokenizer, AutoModelForSequenceClassification
|
14 |
|
15 |
from transformers import BertForMaskedLM, BertTokenizer, RobertaForSequenceClassification, RobertaTokenizer
|
|
|
21 |
from jieba import posseg
|
22 |
paddle.enable_static()
|
23 |
import re
|
|
|
|
|
24 |
def cut_sent(para):
|
25 |
para = re.sub('([。!?\?])([^”’])', r'\1\n\2', para)
|
26 |
para = re.sub('([。!?\?][”’])([^,。!?\?\n ])', r'\1\n\2', para)
|
|
|
68 |
self.w2v_model = api.load("glove-wiki-gigaword-100")
|
69 |
nltk.download('stopwords')
|
70 |
self.stop_words = set(stopwords.words('english'))
|
71 |
+
self.nlp = spacy.load('en_core_web_sm')
|
72 |
|
73 |
def cut(self,ori_text,text_len):
|
74 |
if self.language == 'Chinese':
|
|
|
272 |
return all_processed_tokens,new_index_space
|
273 |
|
274 |
|
275 |
+
def filter_candidates(self, init_candidates_list, tokens, index_space, input_text, tau_word):
|
|
|
276 |
all_context_word_similarity_scores = self.context_word_sim(init_candidates_list, tokens, index_space, input_text)
|
277 |
|
278 |
all_sentence_similarity_scores = self.sentence_sim(init_candidates_list, tokens, index_space, input_text)
|
|
|
285 |
for idx, candidate in enumerate(init_candidates):
|
286 |
global_word_similarity_score = self.global_word_sim(tokens[masked_token_index], candidate)
|
287 |
word_similarity_score = self.lamda*context_word_similarity_scores[idx]+(1-self.lamda)*global_word_similarity_score
|
288 |
+
if word_similarity_score >= tau_word and sentence_similarity_scores[idx] >= self.tau_sent:
|
289 |
filtered_candidates.append((candidate, word_similarity_score))
|
290 |
|
291 |
if len(filtered_candidates) >= 1:
|
|
|
318 |
|
319 |
return best_candidates, new_index_space
|
320 |
|
321 |
+
def watermark_embed(self,text,tau_word):
|
322 |
input_text = text
|
323 |
# Tokenize the input text
|
324 |
tokens = self.tokenizer.tokenize(input_text)
|
|
|
342 |
init_candidates, new_index_space = self.candidates_gen(tokens,index_space,input_text, 8, 0)
|
343 |
if len(new_index_space)==0:
|
344 |
return text
|
345 |
+
enhanced_candidates, new_index_space = self.filter_candidates(init_candidates,tokens,new_index_space,input_text,tau_word)
|
346 |
|
347 |
enhanced_candidates, new_index_space = self.get_candidate_encodings(tokens, enhanced_candidates, new_index_space)
|
348 |
|
|
|
354 |
watermarked_text = re.sub(r'(?<=[\u4e00-\u9fff])\s+(?=[\u4e00-\u9fff,。?!、:])|(?<=[\u4e00-\u9fff,。?!、:])\s+(?=[\u4e00-\u9fff])', '', watermarked_text)
|
355 |
return watermarked_text
|
356 |
|
357 |
+
def embed(self, ori_text, tau_word):
|
358 |
sents = self.sent_tokenize(ori_text)
|
359 |
sents = [s for s in sents if s.strip()]
|
360 |
num_sents = len(sents)
|
|
|
367 |
sent_pair = sents[i]
|
368 |
# keywords = jieba.analyse.extract_tags(sent_pair, topK=5, withWeight=False)
|
369 |
if len(watermarked_text) == 0:
|
370 |
+
watermarked_text = self.watermark_embed(sent_pair, tau_word)
|
371 |
else:
|
372 |
+
watermarked_text = watermarked_text + self.watermark_embed(sent_pair, tau_word)
|
373 |
if len(self.get_encodings_fast(ori_text)) == 0:
|
374 |
# print(ori_text)
|
375 |
return ''
|
|
|
409 |
is_watermark = z >= threshold
|
410 |
return is_watermark, p_value, n, ones, z
|
411 |
|
412 |
+
def get_encodings_precise(self, text, tau_word):
|
413 |
# pdb.set_trace()
|
414 |
sents = self.sent_tokenize(text)
|
415 |
sents = [s for s in sents if s.strip()]
|
|
|
439 |
continue
|
440 |
|
441 |
init_candidates, new_index_space = self.candidates_gen(tokens,index_space,sent_pair, 8, 0)
|
442 |
+
enhanced_candidates, new_index_space = self.filter_candidates(init_candidates,tokens,new_index_space,sent_pair,tau_word)
|
443 |
|
444 |
# pdb.set_trace()
|
445 |
for j,idx in enumerate(new_index_space):
|
|
|
449 |
return encodings
|
450 |
|
451 |
|
452 |
+
def watermark_detector_precise(self,text,tau_word,alpha=0.05):
|
453 |
p = 0.5
|
454 |
+
encodings = self.get_encodings_precise(text,tau_word)
|
455 |
n = len(encodings)
|
456 |
ones = sum(encodings)
|
457 |
if n == 0:
|