Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Emnlp #7

Open
wants to merge 93 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
93 commits
Select commit Hold shift + click to select a range
a2ca02a
Add ATP-specific generate DVs workflow
vinhowe May 12, 2023
095912c
Apparently we could generate DVs automatically
vinhowe May 12, 2023
298d028
Add survey cost estimation code
vinhowe May 16, 2023
b6a536e
Add code to automatically generate ATP configs
vinhowe May 16, 2023
a65478c
Lowercase variables because it works for neurips
vinhowe May 16, 2023
39026e1
Add 'culling sampled below n' code (note!)
vinhowe May 16, 2023
f937f59
Merge branch 'main' into neurips
vinhowe May 19, 2023
80110d9
Add output for debugging prompt construction
vinhowe May 19, 2023
08e9bb5
Revert "Lowercase variables because it works for neurips"
vinhowe May 19, 2023
7e7adef
Undo ValidOption lowercasing
vinhowe May 19, 2023
7435097
Revert "Add 'culling sampled below n' code (note!)"
vinhowe May 20, 2023
e0df35c
Remove n_culle_sampled_below everywhere
vinhowe May 20, 2023
97e84c8
Unsort imports in survey.py
vinhowe May 20, 2023
b013cb9
Ignore .DS_Store
vinhowe May 20, 2023
298cf23
Merge branch 'main' into emnlp
vinhowe May 20, 2023
a990667
s/config_filename/variables_filename/g
vinhowe May 20, 2023
5fc9c00
Filter out out-of-schema variable values
vinhowe May 20, 2023
bd7a057
Working async openai sampler impl
vinhowe May 20, 2023
490e07c
Reformat
vinhowe May 20, 2023
81c22f7
Remove extra comment
vinhowe May 20, 2023
3bd43df
Update example_configure_survey.py
vinhowe May 20, 2023
7b68fa6
Remove unused argparse import
vinhowe May 20, 2023
fea3a1f
Reformat
vinhowe May 20, 2023
b4a8fe9
Merge branch 'emnlp' into async-openai-sampling
vinhowe May 20, 2023
3728470
Remove unused prompt printing
vinhowe May 20, 2023
a218599
Merge branch 'emnlp' into async-openai-sampling
vinhowe May 20, 2023
2877aab
Remove comments for copilot
vinhowe May 20, 2023
4e8155d
Merge branch 'emnlp' into async-openai-sampling
vinhowe May 20, 2023
10b50a5
replace responses.csv -> data.csv
vinhowe May 20, 2023
a41a1bd
Update folder structure.
alexgshaw May 22, 2023
27615c8
Add style check GitHub workflow
vinhowe May 22, 2023
056761b
Merge branch 'emnlp' into async-openai-sampling
vinhowe May 22, 2023
8035a00
Bug fix + add slot for response object.
alexgshaw May 22, 2023
98b4acf
Fix index typing error.
alexgshaw May 22, 2023
687dcd0
Merge branch 'emnlp' into async-openai-sampling
vinhowe May 22, 2023
bd381ba
Merge branch 'emnlp' into async-openai-sampling
vinhowe May 22, 2023
a7febdf
Update async openai sampler to return response
vinhowe May 22, 2023
82c356c
Add ordinal property to variables.json
vinhowe May 22, 2023
08f02c5
Handle AutoModel async
vinhowe May 22, 2023
05ddeef
Merge pull request #8 from BYU-PCCL/async-openai-sampling
vinhowe May 22, 2023
2ed52ae
Merge branch 'emnlp' into add-ordinal-to-variables
vinhowe May 22, 2023
2c31a63
Merge pull request #11 from BYU-PCCL/add-ordinal-to-variables
alexgshaw May 22, 2023
64afba1
Fix survey sampling.
alexgshaw May 22, 2023
23bb834
Merge branch 'emnlp' of https://github.com/BYU-PCCL/lm-survey into emnlp
alexgshaw May 22, 2023
2b82b88
Update atp configuration
vinhowe May 22, 2023
f126bc5
Add ordinal functionality to Question class.
alexgshaw May 22, 2023
639d687
Merge branch 'emnlp' of https://github.com/BYU-PCCL/lm-survey into emnlp
alexgshaw May 22, 2023
3740cfc
Rework folder structure.
alexgshaw May 22, 2023
d7198fb
Temp. revert "Add style check GitHub workflow"
vinhowe May 23, 2023
b0b14e5
bug fix.
alexgshaw May 23, 2023
aee5f3c
Minor bug fix on question.
alexgshaw May 23, 2023
f260e71
rename schema to variable
alexgshaw May 23, 2023
83bdc97
gitignore update
alexgshaw May 23, 2023
ea66dd5
Added crude representativeness scoring
chrisrytting May 24, 2023
8008a9f
Merge branch 'emnlp' of github.com:BYU-PCCL/lm-survey into emnlp
chrisrytting May 24, 2023
ac835b2
Update estimate survey to experiment config file
vinhowe May 24, 2023
d47640a
Merge branch 'emnlp' of github.com:BYU-PCCL/lm-survey into emnlp
vinhowe May 24, 2023
e3c4c8e
breadth experiment
chrisrytting May 24, 2023
f9347ac
Merge branch 'emnlp' of github.com:BYU-PCCL/lm-survey into emnlp
chrisrytting May 24, 2023
67bbf30
Merge branch 'emnlp' of github.com:BYU-PCCL/lm-survey into emnlp
vinhowe May 24, 2023
5940ff0
Add create atp experiment script
vinhowe May 24, 2023
39c2fe4
Check in variables
vinhowe May 24, 2023
95da00f
Clean up create atp experiment imports
vinhowe May 24, 2023
562fb9d
Do formatting for create atp experiment
vinhowe May 24, 2023
28e3ac9
Update check survey prompts for experiments
vinhowe May 24, 2023
4e79da7
Update estimate survey to experiment config file
vinhowe May 24, 2023
cde6e24
Fix ATP configuration script
vinhowe May 24, 2023
9076e10
Use ordinals to find invalid options
vinhowe May 24, 2023
9eba1c9
Fix
vinhowe May 24, 2023
f0cf51d
Fix rate limit error import
vinhowe May 25, 2023
f510c3e
Bump up rate limit to what OpenAI says we have
vinhowe May 25, 2023
9aaead3
Push updates variables
vinhowe May 26, 2023
ac8e3fb
Add force flag.
alexgshaw May 26, 2023
6e9d77f
Sampler fix.
alexgshaw May 26, 2023
0a24acd
Added logging, added functionality to fill in missing response_objects
chrisrytting May 26, 2023
ad4525d
Merge branch 'emnlp' of github.com:BYU-PCCL/lm-survey into emnlp
chrisrytting May 26, 2023
b058a5f
Bug fix.
alexgshaw May 26, 2023
34115df
Merge branch 'emnlp' of github.com:BYU-PCCL/lm-survey into emnlp
chrisrytting May 27, 2023
5b3c884
added some helpers
chrisrytting May 29, 2023
07fdbbe
Added tests for infilling
chrisrytting May 29, 2023
21b8e75
Added infilling ability, some more logging, and some extra DVS functi…
chrisrytting May 29, 2023
446672c
Removed data push mistake
chrisrytting May 29, 2023
835da77
Merge branch 'emnlp' of github.com:BYU-PCCL/lm-survey into emnlp
vinhowe May 29, 2023
1aff991
Remove unused import in async sampler
vinhowe May 29, 2023
8f7e6ad
Add updated estimate_survey.py
vinhowe May 30, 2023
849e91e
Minor fixes.
alexgshaw May 31, 2023
91b8041
Get rid of horrible rate limit print
vinhowe May 31, 2023
e1b1c52
Merge branch 'emnlp' of github.com:BYU-PCCL/lm-survey into emnlp
vinhowe May 31, 2023
f65c797
Made the rep calculation neater
chrisrytting Jun 2, 2023
c96a889
Merge branch 'emnlp' of github.com:BYU-PCCL/lm-survey into emnlp
chrisrytting Jun 2, 2023
0909387
Merge branch 'emnlp' of github.com:BYU-PCCL/lm-survey into emnlp
vinhowe Jun 2, 2023
df555c6
Added weighting and an ability to extract D_H from opinionqa dataset
chrisrytting Jun 3, 2023
a0ba33e
Merge branch 'emnlp' of github.com:BYU-PCCL/lm-survey into emnlp
chrisrytting Jun 3, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions configure_atp.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import argparse
import json
import os
from pathlib import Path

from lm_survey.survey.survey import Survey

if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument(
"wave", type=Path, nargs="+", help="Path(s) to wave of ATP to configure"
)
parser.add_argument("--base-config", type=Path, help="Path to optional base config")
args = parser.parse_args()

for wave in args.wave:
config_path = wave / "config.json"

survey = Survey(name="ATP_W92", data_filename=wave / "responses.csv")

survey.generate_atp_config(config_path)

# This is a simple way to put some extra stuff in the config
if args.base_config:
with args.base_config.open("r") as f:
base_config = json.load(f)
with config_path.open("r") as f:
config = json.load(f)
config.extend(base_config)
with config_path.open("w") as f:
json.dump(config, f, indent=2)
185 changes: 185 additions & 0 deletions estimate_survey.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
import argparse
import json
import os
import typing

import numpy as np
import pandas as pd
from tqdm import tqdm

from lm_survey.samplers import AutoSampler, BaseSampler
from lm_survey.survey import Survey


def estimate_survey_costs(
sampler: BaseSampler,
survey_name: str,
*,
n_samples_per_dependent_variable: typing.Optional[int] = None,
n_top_mutual_info_dvs: typing.Optional[int] = None,
n_cull_sampled_below: typing.Optional[int] = None,
):
# TODO(vinhowe): fix this
survey_directory = survey_name

with open(
os.path.join(survey_directory, "independent-variables.json"), "r"
) as file:
independent_variable_names = json.load(file)

with open(os.path.join(survey_directory, "dependent-variables.json"), "r") as file:
dependent_variable_names = json.load(file)

data_filename = os.path.join(survey_directory, "responses.csv")
config_filename = os.path.join(survey_directory, "config.json")

survey = Survey(
name=survey_name,
data_filename=data_filename,
config_filename=config_filename,
independent_variable_names=independent_variable_names,
dependent_variable_names=dependent_variable_names,
)

if n_top_mutual_info_dvs is not None:
cached_mutual_info_stats_filename = os.path.join(
survey_directory, "cached_mutual_info_stats.csv"
)
if os.path.exists(cached_mutual_info_stats_filename):
mutual_info_stats = pd.read_csv(
cached_mutual_info_stats_filename, index_col=0
)
else:
mutual_info_stats = survey.mutual_info_stats()
mutual_info_stats.to_csv(cached_mutual_info_stats_filename)
# already sorted; get the first n_top_mutual_info_dvs from the index
dependent_variable_names = mutual_info_stats.index[:n_top_mutual_info_dvs]
# replace survey with a new one with only the top n_top_mutual_info_dvs
survey = Survey(
name=survey_name,
data_filename=data_filename,
config_filename=config_filename,
independent_variable_names=independent_variable_names,
dependent_variable_names=dependent_variable_names,
)

dependent_variable_samples = list(
survey.iterate(
n_samples_per_dependent_variable=n_samples_per_dependent_variable,
n_cull_sampled_below=n_cull_sampled_below,
)
)

# print random sample of prompts
# print(
# "\n===\n===\n===\n".join(
# np.random.choice(
# [
# dependent_variable_sample.prompt
# for dependent_variable_sample in dependent_variable_samples
# ],
# 10,
# )
# )
# )

prompt_count = len(dependent_variable_samples)

if hasattr(sampler, "batch_estimate_prompt_cost"):
completion_costs = sampler.batch_estimate_prompt_cost(
[
dependent_variable_sample.prompt
for dependent_variable_sample in dependent_variable_samples
]
)
else:
completion_costs = []
for dependent_variable_sample in tqdm(dependent_variable_samples):
completion_cost = sampler.estimate_prompt_cost(
dependent_variable_sample.prompt
)
completion_costs.append(completion_cost)

total_completion_cost = np.sum(completion_costs)

return {
"prompt_count": prompt_count,
"cost": total_completion_cost,
}


def main(
model_name: str,
survey_names: typing.List[str],
n_samples_per_dependent_variable: typing.Optional[int] = None,
n_top_mutual_info_dvs: typing.Optional[int] = None,
n_cull_sampled_below: typing.Optional[int] = None,
) -> None:
sampler = AutoSampler(model_name=model_name)

survey_costs = {}
for survey_name in tqdm(survey_names):
estimate = estimate_survey_costs(
sampler=sampler,
survey_name=survey_name,
n_samples_per_dependent_variable=n_samples_per_dependent_variable,
n_top_mutual_info_dvs=n_top_mutual_info_dvs,
n_cull_sampled_below=n_cull_sampled_below,
)
survey_costs[survey_name] = estimate

total_cost = sum([estimate["cost"] for estimate in survey_costs.values()])

total_prompt_count = sum(
[estimate["prompt_count"] for estimate in survey_costs.values()]
)

if len(survey_names) > 1:
print(f"Cost per survey:")
for survey_name, survey_cost in survey_costs.items():
print(
f"{survey_name}: ${(survey_cost['cost'] / 100):.2f} ({survey_cost['prompt_count']}"
" prompts)"
)

print(f"Total cost: ${(total_cost / 100):.2f} ({total_prompt_count} prompts)")


if __name__ == "__main__":
parser = argparse.ArgumentParser()

parser.add_argument(
"-m",
"--model_name",
type=str,
required=True,
)
parser.add_argument(
"-n",
"--n_samples_per_dependent_variable",
type=int,
)
parser.add_argument(
"--n_cull_sampled_below",
type=int,
)
parser.add_argument(
"--n_top_mutual_info_dvs",
type=int,
)
# Positional argument for survey dir(s)
parser.add_argument(
"survey_name",
nargs="+",
type=str,
)

args = parser.parse_args()

main(
model_name=args.model_name,
survey_names=args.survey_name,
n_samples_per_dependent_variable=args.n_samples_per_dependent_variable,
n_top_mutual_info_dvs=args.n_top_mutual_info_dvs,
n_cull_sampled_below=args.n_cull_sampled_below,
)
6 changes: 6 additions & 0 deletions lm_survey/samplers/auto_sampler.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,12 @@ def send_prompt(self, prompt, n_probs):
def sample_several(self, prompt, temperature=0, n_tokens=10):
return self.sampler.sample_several(prompt, temperature, n_tokens)

def estimate_prompt_cost(self, prompt: str) -> float:
return self.sampler.estimate_prompt_cost(prompt)

def __getattr__(self, attr):
return getattr(self.sampler, attr)


if __name__ == "__main__":
sampler = AutoSampler("gpt3-ada")
Expand Down
11 changes: 11 additions & 0 deletions lm_survey/samplers/base_sampler.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,14 @@ def get_best_next_token(self, prompt: str, **kwargs) -> str:
"""
logprobs = self.send_prompt(prompt=prompt, n_probs=1, **kwargs)
return list(logprobs.keys())[0]

@abstractmethod
def estimate_prompt_cost(self, prompt: str, **kwargs) -> float:
"""
Estimates the cost of sending the given prompt to a LM.
Arguments:
prompt (str) a prompt to be sent to LM
Return:
float the estimated cost of sending the prompt in USD cents
"""
pass
3 changes: 3 additions & 0 deletions lm_survey/samplers/hf_sampler.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,9 @@ def sample_several(self, prompt, temperature=0, n_tokens=10):
)
return preds[0][len(prompt) + 1 :]

def estimate_prompt_cost(self, _prompt: str, **_kwargs) -> float:
raise NotImplementedError


if __name__ == "__main__":
sampler = HfSampler(model_name="/mnt/pccfs2/backed_up/models/llama/hf/llama-7b-hf")
Expand Down
43 changes: 43 additions & 0 deletions lm_survey/samplers/openai_sampler.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,25 @@
import typing

import tiktoken
import torch

from lm_survey.samplers.base_sampler import BaseSampler
import openai

OPENAI_TOKEN_COSTS = {
# cents per 1000 tokens
"text-davinci-003": 2,
"text-davinci-002": 2,
"text-davinci-001": 2,
"text-curie-001": 0.2,
"text-babbage-001": 0.05,
"text-ada-001": 0.04,
"davinci": 2,
"curie": 0.2,
"babbage": 0.05,
"ada": 0.04,
}


class OpenAiSampler(BaseSampler):
def __init__(self, *args, **kwargs):
Expand All @@ -18,6 +36,8 @@ def __init__(self, *args, **kwargs):
if openai.api_key is None:
raise ValueError("OpenAI API key must be set")

self.tokenizer = None

def rank_completions(self, prompt, completions):
# 100 is the maximum number of log probs we can get.
top_log_probs = self.send_prompt(prompt, n_probs=100)
Expand Down Expand Up @@ -64,6 +84,29 @@ def sample_several(self, prompt, temperature=0, n_tokens=10):
)
return response["choices"][0]["text"] # type: ignore

def _setup_tokenizer(self):
if not self.tokenizer:
self.tokenizer = tiktoken.encoding_for_model(self.engine)

def estimate_prompt_cost(self, prompt: str):
self._setup_tokenizer()
# +1 for single token completion
token_count = len(self.tokenizer.encode(prompt)) + 1
return OPENAI_TOKEN_COSTS[self.engine] * token_count / 1000

def batch_estimate_prompt_cost(
self, prompts: typing.List[str]
) -> typing.List[float]:
self._setup_tokenizer()
# +1 for single token completion
token_counts = [
len(encoded) + 1 for encoded in self.tokenizer.encode_batch(prompts)
]
return [
OPENAI_TOKEN_COSTS[self.engine] * (token_count / 1000)
for token_count in token_counts
]


if __name__ == "__main__":
sampler = OpenAiSampler("gpt3-ada")
Expand Down
8 changes: 4 additions & 4 deletions lm_survey/survey/question.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ def __init__(
text: typing.Optional[str] = None,
natural_language: typing.Optional[str] = None,
) -> None:
self.raw = raw
self.text = text
vinhowe marked this conversation as resolved.
Show resolved Hide resolved
self.raw = raw.lower()
self.text = text.lower()
self.natural_language = natural_language

def to_dict(self) -> typing.Dict[str, typing.Optional[str]]:
Expand Down Expand Up @@ -44,10 +44,10 @@ def __init__(
) -> None:
self.key = key
self.text = text
self.invalid_options = set(invalid_options)
self.invalid_options = set(map(str.lower, (invalid_options)))
vinhowe marked this conversation as resolved.
Show resolved Hide resolved

self.valid_options = {
option["raw"]: ValidOption(**option) for option in valid_options
option["raw"].lower(): ValidOption(**option) for option in valid_options
}

self.valid_options_index_map = {
Expand Down
Loading