-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathexperiment_general.py
More file actions
220 lines (185 loc) · 10.1 KB
/
Copy pathexperiment_general.py
File metadata and controls
220 lines (185 loc) · 10.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
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
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
from Utils import initialize_models,get_tests,get_conditions
import argparse
from transformers import AutoTokenizer
import torch
softmax = torch.nn.Softmax(-1)
import pandas as pd
import numpy as np
import openai
from time import sleep
try:
tokenizer = AutoTokenizer.from_pretrained("huggyllama/llama-30b")
except:
tokenizer = None
def get_prompt(instruction,item,answers,options,meta_instruction,persona):
question = instruction(item)
option_text = "\n".join([options[j] + ": " + answers[j] for j in range(len(answers))])
main_text = question + "\n" + option_text + "\nAnswer:"
meta=meta_instruction(persona)
return meta,main_text
def eval_model(model=None,instruction=None,item=None,answers=None,options=None,meta_instruction = None,p_answers=None,p_options =None,persona =None,coagulator=None ,i_negated=None):
options = np.array(options)
answers = np.array(answers)
#Permute answers, and associate each answer to an option
option_map = {options[i]: answers[p_answers][i] for i in range(len(options))}
#Permute options, create prompts for the options and associated answers
options_in = options[p_options]
answers_in = [option_map[option] for option in options_in]
meta,main_text = get_prompt(instruction,item,answers_in,options_in,meta_instruction,persona)
ps,prompt,log = query(model,meta,main_text,options,coagulator)
#Option i is associated to answer_permutation(answers)[i]
#=> Apply reverse permutation to obtain answers in correct order. Argsort reverses permutations.
ps = ps[np.argsort(p_answers)]
#If item is negated: Reverse the scale!
if i_negated:
ps = ps[np.arange(len(options))[::-1]]
return ps,prompt,log
def query(model,meta,main_text,options,coagulator):
if type(model) is not str:
model_type = "Local"
elif model in ["gpt-4-0613","gpt-4-0314","gpt-3.5-turbo-0613","gpt-3.5-turbo-0301"]:
model_type = "OpenAI_Chat"
elif model in ["text-davinci-003","text-davinci-002","text-davinci-001","davinci"]:
model_type = "OpenAI_Complete"
else:
assert False, model
if model_type == "Local":
prompt = coagulator(meta,main_text,model)
tokens = tokenizer(prompt,return_tensors="pt")["input_ids"]
token_lengths = [len(i) for i in tokenizer(list(options))["input_ids"]]
assert (sum(token_lengths)/len(token_lengths)) == token_lengths[0] #Either all options are numeric or all are letters
if token_lengths[0] == 3:
tokens = torch.cat([tokens,torch.tensor([[29871]])],1) #Append "is a number" token to the prompt
#Evaluate model
with torch.no_grad():
outputs = model(tokens.to(torch.device("cuda"))).logits[0,-1]
#Write down tokens representing each of the options
option_tokens = np.array([i[-1] for i in tokenizer(list(options))["input_ids"]])
#Probabilities for the options in the original order. No need to undo the option permutation here.
#LLama seems to tokenize single letters without an additional space
ps = softmax(outputs)[option_tokens].detach().cpu().numpy()
indices,values = torch.topk(outputs,25)
log = "i: " + str(indices.detach().cpu().numpy()) + " v:" + str(values.detach().cpu().numpy())
elif model_type == "OpenAI_Chat":
prompt = coagulator(meta,main_text,model)
#Query model until it actually responds.
retry = True
while retry:
try:
response = openai.ChatCompletion.create(model=model,messages=prompt,temperature = 1.0,max_tokens = 1)
retry = False
if model in ["gpt-4-0613","gpt-4-0314"]:
sleep(1.0) #Respect rate limit
else:
sleep(1.0) #Respect rate limit
except Exception as e:
print(e)
retry = True
#Write down tokens representing each of the options
outputs = []
for j in range(len(options)):
#Chat models appear to tokenize single letters without an added space
if options[j] == response.choices[0].message.content:
outputs.append(1.0)
else:
outputs.append(0.0)
#In case of refusal, record that separately and send notification
ps = np.array(outputs)
if sum(ps) == 0:
print(prompt,"refusal")
ps = np.ones_like(ps)/len(options)
log = str(response.choices[0].message.content)
elif model_type == "OpenAI_Complete":
prompt = coagulator(meta,main_text,model)
retry = True
while retry:
try:
response = openai.Completion.create(
model=model,
prompt=prompt,
temperature=0.0,
max_tokens=1,
logprobs=5,
)
retry = False
sleep(0.025) #Respect rate limit
except Exception as e:
print(e)
retry = True
logprobs = response["choices"][0].logprobs.top_logprobs[0]
#Calculate imputation values for missing probabilities
min_p = np.min(np.exp([logprobs[key] for key in logprobs.keys()]))
missing_p = 1 - np.sum(np.exp([logprobs[key] for key in logprobs.keys()]))
p_impute = min(min_p,missing_p)
#Probabilities for the options in the original order
outputs = []
for j in range(len(options)):
#Non-chat models appear to tokenize single letters with a space in front
if " "+options[j] in logprobs.keys():
outputs.append(np.exp(logprobs[" "+options[j]]))
else:
#Impute missing probabilities
outputs.append(p_impute)
#Normalize probabilities
ps = outputs / np.sum(outputs)
log = str(dict(response.choices[0].logprobs.top_logprobs[0]))
return ps,prompt,log
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument('model_name',type=str)
parser.add_argument('conditions',type=str)
parser.add_argument('test',type=str)
args = parser.parse_args()
if args.model_name in ["llama-2-7b-chat-hf","llama-2-70b-chat","llama-2-7b-hf","llama-2-70b-hf"]:
models = initialize_models([args.model_name],["float32"])
model = models[args.model_name+"_float32"]
else:
model = args.model_name
with open('../test.txt') as reader:
openai.api_key = reader.read()
cond_options,cond_answers,cond_p_answers,cond_p_options,cond_instructions,cond_meta_instructions,cond_persona,cond_coagulator = get_conditions(args.conditions)
#All conditions except for personas are list(zip) with items,names
tests = get_tests(args.test)
aspect_names = ["O","E","C","A","N"]
aspects= {test_name: {aspect_name:
[list(tests[test_name][(tests[test_name]["label_ocean"]==aspect_name)
& (tests[test_name]["key"]==key)]["text"])
for key in [1,-1]]
for aspect_name in aspect_names} for test_name in list(tests.keys())}
result_list = []
counter = 0
for options,options_name in cond_options:
for answers,answers_name in cond_answers:
for inst,inst_name in cond_instructions:
for meta,meta_name in cond_meta_instructions:
for coagulator,coagulator_name in cond_coagulator:
for p_answer,p_answer_name in cond_p_answers:
for p_option,p_option_name in cond_p_options:
for persona in cond_persona:
counter = counter+1
print(str(counter) + "/" + str(len(cond_persona)))
for test_name in list(tests.keys()):
for aspect_name in aspect_names:
print(aspect_name)
for reverse_key in [0,1]:
for item in aspects[test_name][aspect_name][reverse_key]:
ps,prompt,log = eval_model(model=model,
instruction=inst,
item=item,
answers=answers,
options=options,
meta_instruction = meta,
p_answers=p_answer,
p_options = p_option,
persona = persona,
coagulator=coagulator,
i_negated = bool(reverse_key))
#print(ps,prompt,log)
result_list.append(
{"persona":persona,"aspect":aspect_name,"reverse": reverse_key,"item":item,
"options":options_name,"answers":answers_name,"reverse_answers":p_answer_name,
"reverse_options":p_option_name,"instruction":inst_name,"meta":meta_name,"coagulator":coagulator_name,
"item":item,"test_name":test_name, "p1":ps[0],"p2":ps[1],"p3":ps[2],"p4":ps[3],"p5":ps[4],
"prompt":prompt,"log":log})
print(log)
pd.DataFrame(result_list).to_csv("output_raw/"+args.model_name+"_"+args.conditions+"_"+args.test+".csv") #Save results once a persona-condition is fully evaluated.