import logging logging.basicConfig(level='ERROR') import numpy as np from pathlib import Path import openai import torch import zlib import statistics from torch.utils.data import DataLoader from transformers import AutoTokenizer, AutoModelForCausalLM from tqdm import tqdm import math import numpy as np from datasets import load_dataset from options import Options from ipdb import set_trace as bp from eval import * from utils import evaluate_model from analyze import analyze_data import argparse import os import sys import gc import pickle models = {} def save_data(filename, data): with open(filename, 'wb') as filehandle: # store the data as binary data stream pickle.dump(data, filehandle) def load_data(filename): with open(filename, 'rb') as filehandle: # read the data as binary data stream loaded_data = pickle.load(filehandle) return loaded_data def load_model(name1): if name1 not in models: model1 = AutoModelForCausalLM.from_pretrained(name1, return_dict=True, device_map='auto') model1.eval() tokenizer1 = AutoTokenizer.from_pretrained(name1) tokenizer1.pad_token = tokenizer1.eos_token models[name1] = model1 models[name1 + "_tokenizer"] = tokenizer1 return models[name1], models[name1 + "_tokenizer"] def calculatePerplexity(sentence, model, tokenizer, gpu): """ exp(loss) """ input_ids = torch.tensor(tokenizer.encode(sentence)).unsqueeze(0) input_ids = input_ids.to(gpu) with torch.no_grad(): outputs = model(input_ids, labels=input_ids) loss, logits = outputs[:2] ''' extract logits: ''' # Apply softmax to the logits to get probabilities probabilities = torch.nn.functional.log_softmax(logits, dim=-1) # probabilities = torch.nn.functional.softmax(logits, dim=-1) all_prob = [] input_ids_processed = input_ids[0][1:] for i, token_id in enumerate(input_ids_processed): probability = probabilities[0, i, token_id].item() all_prob.append(probability) return torch.exp(loss).item(), all_prob, loss.item() def sample_generation(sentence, model, tokenizer, args,data_name): half_sentence_index = math.ceil(len(sentence.split())*args['prefix_length']) if half_sentence_index > 0: prefix = " ".join(sentence.split()[:half_sentence_index]) else: prefix = '<|startoftext|> ' input_ids = torch.tensor(tokenizer.encode(prefix)).unsqueeze(0) input_ids = input_ids.to(model.device) output = model.generate(input_ids, max_new_tokens=(len(sentence.split())-half_sentence_index), min_new_tokens=1, num_return_sequences=int(args['num_z']), pad_token_id=tokenizer.eos_token_id, **args['generate_args']) # print(output) complete_generated_text = tokenizer.batch_decode(output, skip_special_tokens=True) return complete_generated_text def RMIA_1(text,target_loss,ref_loss,model1,tokenizer1,ratio_gen,neighbors_dl): target_losses_z = evaluate_model(model1,tokenizer1,neighbors_dl) result = torch.count_nonzero(target_losses_z < target_loss).item() / len(target_losses_z) return result def get_neighbors(text,ref_loss,model2,tokenizer2,ratio_gen,data_name): cur_args = {'prefix_length': ratio_gen, 'num_z': 50, 'generate_args': {'do_sample': True}} neighbors = sample_generation(text, model2, tokenizer2, cur_args,data_name) neighbors_dl = DataLoader(neighbors, batch_size=32, shuffle=False) return neighbors_dl def evaluate_data(test_data, col_name, target_model, ref_model, ratio_gen, data_name): global model1,model2,tokenizer1,tokenizer2 print(f"all data size: {len(test_data)}") random.seed(0) random.shuffle(test_data) test_data = test_data[:100] inference2_pass = None neighbors_dls = None ref_model_clean = ref_model.replace("/","-") data_name_clean = data_name.replace("/","-") os.makedirs(os.path.join(f"saves/{ref_model_clean}",f"{data_name_clean}"),exist_ok=True) try: inference2_pass = load_data(f'saves/{ref_model_clean}/{data_name_clean}/inference2_pass.txt') neighbors_dls = load_data(f'saves/{ref_model_clean}/{data_name_clean}/neighbors_dls.txt') except: ### MODEL 2 likelihoods model2, tokenizer2 = load_model(ref_model) inference2_pass = [] #0: p_ref, #1: all_prob_ref, #2: p_ref_likelihood for ex in tqdm(test_data): text = ex[col_name] new_ex = inference_model2(model2, tokenizer2, text) inference2_pass.append(new_ex) # Invariant. Doesn't take in model1 so I'm good ### Neighbors: neighbors_dls = [] counter = 0 for ex in tqdm(test_data): text = ex[col_name] new_ex = get_neighbors(text,inference2_pass[counter][2],model2,tokenizer2,ratio_gen,data_name) counter = counter + 1 neighbors_dls.append(new_ex) del models[ref_model] del models[ref_model + "_tokenizer"] model2.cpu() del model2 del tokenizer2 gc.collect() torch.cuda.empty_cache() # Because it uses temp it is not invariant, however taking a snapshot in time should be just fine. save_data(f'saves/{ref_model_clean}/{data_name_clean}/inference2_pass.txt',inference2_pass) save_data(f'saves/{ref_model_clean}/{data_name_clean}/neighbors_dls.txt',neighbors_dls) print("Saved ref data, exiting.") ### MODEL 1 likelihoods model1, tokenizer1 = load_model(target_model) inference1_pass = [] #0: p1, #1: all_prob, #2: p1_likelihood, #3: p_lower, #4: p_lower_likelihood for ex in tqdm(test_data): text = ex[col_name] new_ex = inference_model1(model1,tokenizer1,text) inference1_pass.append(new_ex) ### RIMA results counter = 0 results = [] for ex in tqdm(test_data): text = ex[col_name] new_ex = RMIA_1(text,inference1_pass[counter][2],inference2_pass[counter][2],model1,tokenizer1,ratio_gen,neighbors_dls[counter]) counter = counter + 1 results.append(new_ex) del models[target_model] del models[target_model + "_tokenizer"] model1.cpu() del model1 del tokenizer1 gc.collect() torch.cuda.empty_cache() ### Inference ex all_output = [] counter = 0 for ex in tqdm(test_data): text = ex[col_name] pred = {} pred["minkprob_w/_ref"] = results[counter] pred["ppl"] = inference1_pass[counter][0] pred["ppl/Ref_ppl (calibrate PPL to the reference model)"] = inference1_pass[counter][2]-inference2_pass[counter][2] pred["ppl/lowercase_ppl"] = -(np.log(inference1_pass[counter][3]) / np.log(inference1_pass[counter][0])).item() zlib_entropy = len(zlib.compress(bytes(text, 'utf-8'))) pred["ppl/zlib"] = np.log(inference1_pass[counter][0])/zlib_entropy ex["pred"] = pred counter = counter + 1 all_output.append(ex) return all_output def inference_model1 (model1, tokenizer1, text): p1, all_prob, p1_likelihood = calculatePerplexity(text, model1, tokenizer1, gpu=model1.device) p_lower, _, p_lower_likelihood = calculatePerplexity(text.lower(), model1, tokenizer1, gpu=model1.device) return [p1, all_prob, p1_likelihood, p_lower, p_lower_likelihood] def inference_model2 (model2, tokenizer2, text): p_ref, all_prob_ref, p_ref_likelihood = calculatePerplexity(text, model2, tokenizer2, gpu=model2.device) return [p_ref,all_prob_ref,p_ref_likelihood] def main(target_model,ref_model,output_dir,data,length,key_name,ratio_gen): output_dir = f"{output_dir}/{target_model}_{ref_model}/{key_name}" Path(output_dir).mkdir(parents=True, exist_ok=True) # load model and data data_name = data if "jsonl" in data: data = load_jsonl(f"{data}") elif data == "truthful_qa": # bp() dataset = load_dataset(data, "multiple_choice", split="validation") data = convert_huggingface_data_to_list_dic(dataset) data = process_truthful_qa(data) elif data == "cais/mmlu": dataset = load_dataset(data, "all", split="test") data = convert_huggingface_data_to_list_dic(dataset) data = process_mmlu(data) elif data == "ai2_arc": dataset = load_dataset(data, "ARC-Challenge", split="test") data = convert_huggingface_data_to_list_dic(dataset) data = process_arc(data) elif data == "gsm8k": dataset = load_dataset(data, "main", split="test") data = convert_huggingface_data_to_list_dic(dataset) data = process_gsm8k(data) elif data == "Rowan/hellaswag": dataset = load_dataset(data, "default", split="validation") # We use validation since labels for the test set are not available? data = convert_huggingface_data_to_list_dic(dataset) data = process_hellaswag(data) elif data == "winogrande": dataset = load_dataset(data, "winogrande_xl", split="validation") data = convert_huggingface_data_to_list_dic(dataset) data = process_winogrande(data) #model1, model2, tokenizer1, tokenizer2 = load_model(target_model, ref_model) all_output = evaluate_data(data,key_name, target_model, ref_model,ratio_gen,data_name) dump_jsonl(all_output, f"{output_dir}/all_output.jsonl") return analyze_data(all_output) # fig_fpr_tpr(all_output, output_dir)