Add files using upload-large-folder tool
Browse filesThis view is limited to 50 files because it contains too many changes.
See raw diff
- .gitattributes +3 -0
- scripts/yans/baseline_phi2/averaging_checkpoint.sh +20 -0
- scripts/yans/baseline_phi2/preprocess_train.sh +15 -0
- scripts/yans/baseline_phi2/save_hf_model.sh +9 -0
- scripts/yans/baseline_phi2/train.sh +101 -0
- scripts/yans/eval/lm-evaluation-harness/scripts/__init__.py +0 -0
- scripts/yans/eval/lm-evaluation-harness/scripts/clean_training_data/README.md +33 -0
- scripts/yans/eval/lm-evaluation-harness/scripts/clean_training_data/__init__.py +0 -0
- scripts/yans/eval/lm-evaluation-harness/scripts/clean_training_data/compress_and_package.py +73 -0
- scripts/yans/eval/lm-evaluation-harness/scripts/clean_training_data/generate_13_grams.py +216 -0
- scripts/yans/eval/lm-evaluation-harness/scripts/clean_training_data/investigate_pile.py +94 -0
- scripts/yans/eval/lm-evaluation-harness/scripts/clean_training_data/janitor_util.cpp +208 -0
- scripts/yans/eval/lm-evaluation-harness/scripts/clean_training_data/process_sorted_buckets.py +131 -0
- scripts/yans/eval/lm-evaluation-harness/scripts/clean_training_data/sort_13_gram_buckets.py +63 -0
- scripts/yans/eval/lm-evaluation-harness/scripts/cost_estimate.py +98 -0
- scripts/yans/eval/lm-evaluation-harness/scripts/harness_example.py +38 -0
- scripts/yans/eval/lm-evaluation-harness/scripts/main_eval.py +127 -0
- scripts/yans/eval/lm-evaluation-harness/scripts/make_table_tasks.py +52 -0
- scripts/yans/eval/lm-evaluation-harness/scripts/merge_json.py +48 -0
- scripts/yans/eval/lm-evaluation-harness/scripts/run_task_for_models.sh +28 -0
- scripts/yans/lm-evaluation-harness/.coveragerc +28 -0
- scripts/yans/lm-evaluation-harness/.flake8 +5 -0
- scripts/yans/lm-evaluation-harness/.gitignore +24 -0
- scripts/yans/lm-evaluation-harness/.pre-commit-config.yaml +54 -0
- scripts/yans/lm-evaluation-harness/CITATION.bib +10 -0
- scripts/yans/lm-evaluation-harness/CODEOWNERS +1 -0
- scripts/yans/lm-evaluation-harness/LICENSE.md +21 -0
- scripts/yans/lm-evaluation-harness/README.md +497 -0
- scripts/yans/lm-evaluation-harness/bin/python +3 -0
- scripts/yans/lm-evaluation-harness/bin/python3 +3 -0
- scripts/yans/lm-evaluation-harness/bin/python3.10 +3 -0
- scripts/yans/lm-evaluation-harness/docs/API_guide.md +198 -0
- scripts/yans/lm-evaluation-harness/docs/CONTRIBUTING.md +79 -0
- scripts/yans/lm-evaluation-harness/docs/README.md +11 -0
- scripts/yans/lm-evaluation-harness/docs/decontamination.md +71 -0
- scripts/yans/lm-evaluation-harness/docs/img/fewshot_example_gpt3.png +0 -0
- scripts/yans/lm-evaluation-harness/docs/interface.md +162 -0
- scripts/yans/lm-evaluation-harness/docs/model_guide.md +163 -0
- scripts/yans/lm-evaluation-harness/docs/new_task_guide.md +492 -0
- scripts/yans/lm-evaluation-harness/docs/task_guide.md +317 -0
- scripts/yans/lm-evaluation-harness/eval.sh +5 -0
- scripts/yans/lm-evaluation-harness/eval2.sh +5 -0
- scripts/yans/lm-evaluation-harness/eval3.sh +5 -0
- scripts/yans/lm-evaluation-harness/eval4.sh +5 -0
- scripts/yans/lm-evaluation-harness/examples/lm-eval-overview.ipynb +1230 -0
- scripts/yans/lm-evaluation-harness/examples/visualize-wandb.ipynb +170 -0
- scripts/yans/lm-evaluation-harness/examples/visualize-zeno.ipynb +115 -0
- scripts/yans/lm-evaluation-harness/ignore.txt +8 -0
- scripts/yans/lm-evaluation-harness/ja_eval.sh +5 -0
- scripts/yans/lm-evaluation-harness/ja_eval2.sh +5 -0
.gitattributes
CHANGED
@@ -33,3 +33,6 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
|
33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
|
|
33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
36 |
+
scripts/yans/lm-evaluation-harness/bin/python3.10 filter=lfs diff=lfs merge=lfs -text
|
37 |
+
scripts/yans/lm-evaluation-harness/bin/python3 filter=lfs diff=lfs merge=lfs -text
|
38 |
+
scripts/yans/lm-evaluation-harness/bin/python filter=lfs diff=lfs merge=lfs -text
|
scripts/yans/baseline_phi2/averaging_checkpoint.sh
ADDED
@@ -0,0 +1,20 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
set -eux
|
2 |
+
LLM_RECIPES_DIR=/code/llm-recipes
|
3 |
+
|
4 |
+
CHECKPOINTS=(
|
5 |
+
/work/models/additiona_trained/mistral-llm-recipes-mistral-ja-v1/iter_0019200/model.pt
|
6 |
+
/work/models/additiona_trained/mistral-llm-recipes-mistral-ja-v1/iter_0019400/model.pt
|
7 |
+
/work/models/additiona_trained/mistral-llm-recipes-mistral-ja-v1/iter_0019600/model.pt
|
8 |
+
/work/models/additiona_trained/mistral-llm-recipes-mistral-ja-v1/iter_0019800/model.pt
|
9 |
+
/work/models/additiona_trained/mistral-llm-recipes-mistral-ja-v1/iter_0020000/model.pt
|
10 |
+
)
|
11 |
+
# Concatenate the checkpoints
|
12 |
+
INPUTS=${CHECKPOINTS[@]}
|
13 |
+
|
14 |
+
OUTPUT_DIR=/work/models/additiona_trained/mistral-llm-recipes-mistral-ja-v1/averaged/averaged-19200-20000.pt
|
15 |
+
mkdir -p $(dirname $OUTPUT_DIR)
|
16 |
+
|
17 |
+
python $LLM_RECIPES_DIR/tools/merge_checkpoints.py \
|
18 |
+
--inputs $INPUTS \
|
19 |
+
--output $OUTPUT_DIR
|
20 |
+
|
scripts/yans/baseline_phi2/preprocess_train.sh
ADDED
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
set -eux
|
2 |
+
LLM_RECIPES_DIR=/project
|
3 |
+
INPUT_JSONL_FILE_PATH=${1:-/share/yans/datasets/jsonl/llm-jp-corpus-v1/ja/ja_wiki/train_0.jsonl}
|
4 |
+
OUTPUT_FILE_PREFIX=${2:-/work/llm_recipes/datasets/bin/baseline_phi2/llm_jp_corpus_v1_ja_wiki_train_0/data}
|
5 |
+
TOKENIZER_PATH=${3:-/share/pretrained_lm/Phi/Phi-2}
|
6 |
+
mkdir -p $(dirname $OUTPUT_FILE_PREFIX)
|
7 |
+
|
8 |
+
python $LLM_RECIPES_DIR/megatron_lm/tools/preprocess_data.py \
|
9 |
+
--input $INPUT_JSONL_FILE_PATH \
|
10 |
+
--output-prefix $OUTPUT_FILE_PREFIX \
|
11 |
+
--tokenizer-type HFPreTrainedTokenizer \
|
12 |
+
--tokenizer-model $TOKENIZER_PATH \
|
13 |
+
--workers 32 \
|
14 |
+
--append-eod \
|
15 |
+
--log-interval 1000
|
scripts/yans/baseline_phi2/save_hf_model.sh
ADDED
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
set -eux
|
2 |
+
LLM_RECIPES_DIR=/code/llm-recipes
|
3 |
+
source $LLM_RECIPES_DIR/scripts/wmt2024/tokens.sh
|
4 |
+
|
5 |
+
python $LLM_RECIPES_DIR/tools/save_hf_model.py \
|
6 |
+
--base_model_name_or_path mistralai/Mistral-7B-v0.1 \
|
7 |
+
--state_dict_path /work/models/additiona_trained/mistral-llm-recipes-mistral-ja-v1/averaged/averaged-19200-20000.pt \
|
8 |
+
--output_dir /work/models/additiona_trained_hf/mistral-llm-recipes-mistral-ja-v1-averaged-19200-20000 \
|
9 |
+
--hf_repo_id skim-wmt24/mistral-llm-recipes-mistral-ja-v1-averaged-19200-20000-hf
|
scripts/yans/baseline_phi2/train.sh
ADDED
@@ -0,0 +1,101 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
set -eux
|
2 |
+
NOW=`date +%Y-%m-%d-%H:%M:%S`
|
3 |
+
LLM_RECIPES_DIR=/project
|
4 |
+
source $LLM_RECIPES_DIR/scripts/wmt2024/tokens.sh
|
5 |
+
rm -f /tmp/hffs-*
|
6 |
+
|
7 |
+
export WANDB_NOTES="Train sample"
|
8 |
+
wandb login
|
9 |
+
NUM_GPU_PER_NODE=$(nvidia-smi --query-gpu=name --format=csv,noheader | wc -l)
|
10 |
+
NUM_NODES=1
|
11 |
+
NUM_GPUS=$((${NUM_NODES} * ${NUM_GPU_PER_NODE}))
|
12 |
+
|
13 |
+
# training config
|
14 |
+
SEQ_LENGTH=4096
|
15 |
+
SLIDING_WINDOW_SIZE=131072
|
16 |
+
DATA_PARALLEL_SIZE=$NUM_GPUS
|
17 |
+
|
18 |
+
MICRO_BATCH_SIZE=1
|
19 |
+
GLOBAL_BATCH_SIZE=320
|
20 |
+
TRAIN_STEPS=20000
|
21 |
+
VALID_MICRO_BATCH_SIZE=1
|
22 |
+
|
23 |
+
# optimizer config
|
24 |
+
LR=2e-5
|
25 |
+
MIN_LR=1e-6
|
26 |
+
LR_WARMUP_STEPS=500
|
27 |
+
LR_DECAY_STEPS=$TRAIN_STEPS
|
28 |
+
WEIGHT_DECAY=0.1
|
29 |
+
GRAD_CLIP=1.0
|
30 |
+
|
31 |
+
# checkpoint & tokenizer
|
32 |
+
TOKENIZER_MODEL=/share/pretrained_lm/Phi/Phi-2
|
33 |
+
BASE_MODEL=$TOKENIZER_MODEL
|
34 |
+
|
35 |
+
LOAD_DIR=$BASE_MODEL
|
36 |
+
SAVE_DIR=/work/llm_recipes/models/yans-baseline-Phi-2
|
37 |
+
mkdir -p $(dirname $SAVE_DIR)
|
38 |
+
SAVE_BASE_NAME=$(basename $SAVE_DIR)
|
39 |
+
LOG_FILE_PATH=$SAVE_DIR/train_${NOW}.log
|
40 |
+
|
41 |
+
mkdir -p ${SAVE_DIR}
|
42 |
+
|
43 |
+
# data config
|
44 |
+
TRAIN_DATA_PATH="519177757 /work/llm_recipes/datasets/bin/baseline_phi2/llm_jp_corpus_v1_ja_wiki_train_0/data_text_document"
|
45 |
+
TRAIN_DATA_PATH="${TRAIN_DATA_PATH} 519177757 /work/llm_recipes/datasets/bin/baseline_phi2/llm_jp_corpus_v1_ja_wiki_train_0/data_text_document"
|
46 |
+
|
47 |
+
VALID_DATA_PATH="519177757 /work/llm_recipes/datasets/bin/baseline_phi2/llm_jp_corpus_v1_ja_wiki_train_0/data_text_document"
|
48 |
+
TEST_DATA_PATH=${VALID_DATA_PATH}
|
49 |
+
|
50 |
+
|
51 |
+
set +e
|
52 |
+
cd $LLM_RECIPES_DIR
|
53 |
+
# run
|
54 |
+
|
55 |
+
DISTRIBUTED_ARGS="--nproc_per_node $NUM_GPU_PER_NODE --nnodes 1 --node_rank 0 --master_addr localhost --master_port 8000"
|
56 |
+
torchrun $DISTRIBUTED_ARGS examples/finetuning.py \
|
57 |
+
--seq-length ${SEQ_LENGTH} \
|
58 |
+
--sliding-window-size ${SLIDING_WINDOW_SIZE} \
|
59 |
+
--micro-batch-size ${MICRO_BATCH_SIZE} \
|
60 |
+
--valid_micro_batch_size ${VALID_MICRO_BATCH_SIZE} \
|
61 |
+
--global-batch-size ${GLOBAL_BATCH_SIZE} \
|
62 |
+
--train-iters ${TRAIN_STEPS} \
|
63 |
+
--tokenizer-type HFPreTrainedTokenizer \
|
64 |
+
--tokenizer-model ${TOKENIZER_MODEL} \
|
65 |
+
--train-data-path ${TRAIN_DATA_PATH} \
|
66 |
+
--valid-data-path ${VALID_DATA_PATH} \
|
67 |
+
--test-data-path ${TEST_DATA_PATH} \
|
68 |
+
--lr ${LR} \
|
69 |
+
--min-lr ${MIN_LR} \
|
70 |
+
--lr-decay-style cosine \
|
71 |
+
--lr-warmup-iters ${LR_WARMUP_STEPS} \
|
72 |
+
--lr-decay-iters ${LR_DECAY_STEPS} \
|
73 |
+
--weight-decay ${WEIGHT_DECAY} \
|
74 |
+
--grad-clip-norm ${GRAD_CLIP} \
|
75 |
+
--optimizer anyprecision \
|
76 |
+
--adam-beta1 0.9 \
|
77 |
+
--adam-beta2 0.95 \
|
78 |
+
--adam-eps 1e-6 \
|
79 |
+
--save-interval 500 \
|
80 |
+
--eval-interval 500 \
|
81 |
+
--eval-iters 10 \
|
82 |
+
--bf16 \
|
83 |
+
--mixed-precision \
|
84 |
+
--base-model ${BASE_MODEL} \
|
85 |
+
--save ${SAVE_DIR} \
|
86 |
+
--load ${SAVE_DIR} \
|
87 |
+
--fsdp-activation-checkpointing \
|
88 |
+
--sharding-strategy FULL_SHARD \
|
89 |
+
--checkpoint-type LOCAL_STATE_DICT \
|
90 |
+
--save-n-checkpoints 10 \
|
91 |
+
--upload-all-checkpoints-to-hf \
|
92 |
+
--hf-upload-retry-limit 2 \
|
93 |
+
--hf-repo-id shirayukikun/$SAVE_BASE_NAME \
|
94 |
+
--wandb-entity "keitokudo" \
|
95 |
+
--wandb-project "llm_tutorial" \
|
96 |
+
--wandb-name ${SAVE_BASE_NAME}_train_${NOW} 2>&1 | tee $LOG_FILE_PATH
|
97 |
+
|
98 |
+
# --attn-implementation eager \
|
99 |
+
# --uploa-all-checkpoints-to-hf
|
100 |
+
|
101 |
+
rm -f /tmp/hffs-*
|
scripts/yans/eval/lm-evaluation-harness/scripts/__init__.py
ADDED
File without changes
|
scripts/yans/eval/lm-evaluation-harness/scripts/clean_training_data/README.md
ADDED
@@ -0,0 +1,33 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
janitor.py contains a script to remove benchmark data contamination from training data sets.
|
2 |
+
It uses the approach described in the [GPT-3 paper](https://arxiv.org/abs/2005.14165).
|
3 |
+
|
4 |
+
## Algorithm
|
5 |
+
1) Collects all contamination text files that are to be removed from training data
|
6 |
+
2) Filters training data by finding `N`gram matches between the training data
|
7 |
+
and any contamination
|
8 |
+
1) `N`grams ignore case and punctuation and are split on whitespace.
|
9 |
+
2) Matching `N`gram substrings are removed, as is a `window_to_remove` character window around
|
10 |
+
the match, splitting the training data into chunks
|
11 |
+
3) Any chunks less than `minimum_slice_length` are removed
|
12 |
+
4) Training data sets split into more than `too_dirty_cutoff` are considered
|
13 |
+
completey contaminated and removed
|
14 |
+
|
15 |
+
OpenAI used:
|
16 |
+
```
|
17 |
+
ngram_n = 13
|
18 |
+
window_to_remove = 200
|
19 |
+
minimum_slice_length = 200
|
20 |
+
too_dirty_cutoff = 10
|
21 |
+
```
|
22 |
+
|
23 |
+
## Compiling
|
24 |
+
|
25 |
+
Janitor can be used as a pure python program, but it is much faster if the ngram
|
26 |
+
code is run in C++. To compile the C++ code, run
|
27 |
+
|
28 |
+
```
|
29 |
+
pip install pybind11
|
30 |
+
c++ -O3 -Wall -shared -std=c++11 -fPIC $(python3 -m pybind11 --includes) janitor_util.cpp -o janitor_util$(python3-config --extension-suffix)
|
31 |
+
```
|
32 |
+
|
33 |
+
If your your compiler isn't linked to python, you may need to add to the above `-undefined dynamic_lookup`
|
scripts/yans/eval/lm-evaluation-harness/scripts/clean_training_data/__init__.py
ADDED
File without changes
|
scripts/yans/eval/lm-evaluation-harness/scripts/clean_training_data/compress_and_package.py
ADDED
@@ -0,0 +1,73 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import glob
|
2 |
+
import argparse
|
3 |
+
import os
|
4 |
+
import subprocess
|
5 |
+
import shutil
|
6 |
+
|
7 |
+
from tqdm import tqdm
|
8 |
+
from tqdm_multiprocess import TqdmMultiProcessPool
|
9 |
+
|
10 |
+
import logging
|
11 |
+
from tqdm_multiprocess.logger import setup_logger_tqdm
|
12 |
+
|
13 |
+
logger = logging.getLogger(__name__)
|
14 |
+
|
15 |
+
|
16 |
+
def process_task(
|
17 |
+
working_directory, output_directory, bucket_file_path, tqdm_func, global_tqdm
|
18 |
+
):
|
19 |
+
command = f"zstd {bucket_file_path}"
|
20 |
+
logger.info(command)
|
21 |
+
subprocess.call(command, shell=True)
|
22 |
+
|
23 |
+
compressed_file = bucket_file_path + ".zst"
|
24 |
+
if output_directory:
|
25 |
+
shutil.move(compressed_file, output_directory)
|
26 |
+
|
27 |
+
os.remove(bucket_file_path)
|
28 |
+
global_tqdm.update()
|
29 |
+
|
30 |
+
|
31 |
+
def compress_and_move(working_directory, output_directory, process_count):
|
32 |
+
os.makedirs(output_directory, exist_ok=True)
|
33 |
+
original_info_file_path = os.path.join(working_directory, "info.json")
|
34 |
+
assert os.path.exists(original_info_file_path)
|
35 |
+
|
36 |
+
tasks = []
|
37 |
+
bucket_file_paths = glob.glob(
|
38 |
+
os.path.join(working_directory, "output", f"*.bkt.txt.sorted")
|
39 |
+
)
|
40 |
+
for bucket_file_path in bucket_file_paths:
|
41 |
+
task = (process_task, (working_directory, output_directory, bucket_file_path))
|
42 |
+
tasks.append(task)
|
43 |
+
|
44 |
+
pool = TqdmMultiProcessPool(process_count)
|
45 |
+
|
46 |
+
def on_done(_):
|
47 |
+
return None
|
48 |
+
|
49 |
+
def on_error(_):
|
50 |
+
return None
|
51 |
+
|
52 |
+
global_progress = tqdm(
|
53 |
+
total=len(bucket_file_paths), dynamic_ncols=True, unit="file"
|
54 |
+
)
|
55 |
+
_ = pool.map(global_progress, tasks, on_error, on_done)
|
56 |
+
|
57 |
+
shutil.copy(original_info_file_path, os.path.join(output_directory, "info.json"))
|
58 |
+
|
59 |
+
|
60 |
+
parser = argparse.ArgumentParser(description="sort 13gram buckets")
|
61 |
+
parser.add_argument("-dir", "--working_directory", required=True)
|
62 |
+
parser.add_argument("-output", "--output_directory", required=True)
|
63 |
+
parser.add_argument("-procs", "--process_count", type=int, default=8)
|
64 |
+
|
65 |
+
if __name__ == "__main__":
|
66 |
+
version = 1.00
|
67 |
+
print(f"Running version {version}")
|
68 |
+
|
69 |
+
logfile_path = "compress_and_package.log"
|
70 |
+
setup_logger_tqdm(logfile_path)
|
71 |
+
|
72 |
+
args = parser.parse_args()
|
73 |
+
compress_and_move(args.working_directory, args.output_directory, args.process_count)
|
scripts/yans/eval/lm-evaluation-harness/scripts/clean_training_data/generate_13_grams.py
ADDED
@@ -0,0 +1,216 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
"""
|
2 |
+
Outputs all 13-grams found in The Pile.
|
3 |
+
|
4 |
+
Loops through all documents and uses the logic found in janitor.py to extract 13-grams.
|
5 |
+
We bucket each 13-gram by hash into separate file buckets to allow easy parallel processing in the
|
6 |
+
next stage. We also include the current pile document_id with each ngram instance to allow the
|
7 |
+
filtering to exclude 13-grams that match more then 10 unique documents (done further down the pipeline).
|
8 |
+
|
9 |
+
We didn't use lm_dataformat to output as it increases time 4x (slow jsonify) and makes
|
10 |
+
resuming hard (and we had the storage).
|
11 |
+
|
12 |
+
Arguments
|
13 |
+
---------
|
14 |
+
--working_directory (-dir)
|
15 |
+
Directory containing the pile distribution. An "output" subdirectory will be created underneath
|
16 |
+
to store the bucketed 13-grams, checkpoint and done files. Default: current directory
|
17 |
+
--n_value (-n)
|
18 |
+
n value in n-gram, added for later use if ever needed. Default: 13
|
19 |
+
--bucket_count (-buckets)
|
20 |
+
Number of file buckets to use when generating 13grams. Default: 500
|
21 |
+
"""
|
22 |
+
|
23 |
+
import argparse
|
24 |
+
import json
|
25 |
+
import pickle
|
26 |
+
import os
|
27 |
+
import sys
|
28 |
+
from pathlib import Path
|
29 |
+
import glob
|
30 |
+
import signal
|
31 |
+
from signal import SIGINT
|
32 |
+
|
33 |
+
from tqdm import tqdm
|
34 |
+
|
35 |
+
from lm_eval.decontamination.janitor import Janitor, word_ngrams
|
36 |
+
from lm_eval.decontamination.archiver import TextArchive, Reader
|
37 |
+
|
38 |
+
import logging
|
39 |
+
from tqdm_multiprocess.logger import setup_logger_tqdm
|
40 |
+
|
41 |
+
logger = logging.getLogger(__name__)
|
42 |
+
|
43 |
+
terminate = False
|
44 |
+
|
45 |
+
|
46 |
+
def handler(signal_received, frame):
|
47 |
+
global terminate
|
48 |
+
terminate = True
|
49 |
+
|
50 |
+
|
51 |
+
def yield_pile(start_offsets=None, checkpoint_offset=None):
|
52 |
+
directory = "pile"
|
53 |
+
|
54 |
+
if not os.path.exists(directory):
|
55 |
+
print(
|
56 |
+
"We expect the pile archives to be in the 'pile' directory, but this was not found."
|
57 |
+
)
|
58 |
+
raise Exception("Pile directory not found.")
|
59 |
+
|
60 |
+
files = list(sorted(glob.glob(os.path.join(directory, "*.jsonl.zst*"))))
|
61 |
+
|
62 |
+
pile_global_offset = 0
|
63 |
+
start_file = 0
|
64 |
+
if checkpoint_offset:
|
65 |
+
for file_i, start_offset in enumerate(start_offsets):
|
66 |
+
if start_offset > checkpoint_offset:
|
67 |
+
break
|
68 |
+
|
69 |
+
start_file = file_i
|
70 |
+
pile_global_offset = start_offset
|
71 |
+
|
72 |
+
for file_i, file in enumerate(files):
|
73 |
+
if file_i < start_file:
|
74 |
+
logger.info(f"Skipping file {file}")
|
75 |
+
continue
|
76 |
+
logger.info(f"Reading from pile file: {file}")
|
77 |
+
reader = Reader()
|
78 |
+
for document in reader.read(file):
|
79 |
+
yield (pile_global_offset, document)
|
80 |
+
pile_global_offset += 1
|
81 |
+
|
82 |
+
|
83 |
+
# Hash buckets > disk backed files. Supports file position checkpointing and resuming
|
84 |
+
# Allows you to write continuously and checkpoint intermittently. If a failure occurs
|
85 |
+
# the buckets are simply truncated at your last checkpoint.
|
86 |
+
class Buckets:
|
87 |
+
def __init__(self, directory, num_buckets):
|
88 |
+
self.bucket_files = [
|
89 |
+
os.path.join(directory, f"ngrams_{i}.bkt.txt") for i in range(num_buckets)
|
90 |
+
]
|
91 |
+
self.buckets = list(map(TextArchive, self.bucket_files))
|
92 |
+
self.checkpoint_file = os.path.join(directory, f"bucket_offsets.ckpt")
|
93 |
+
|
94 |
+
if os.path.exists(self.checkpoint_file):
|
95 |
+
self.bucket_offsets = pickle.load(open(self.checkpoint_file, "rb"))
|
96 |
+
else:
|
97 |
+
self.bucket_offsets = [0 for i in range(len(self.buckets))]
|
98 |
+
|
99 |
+
for i, offset in enumerate(self.bucket_offsets):
|
100 |
+
bucket = self.buckets[i]
|
101 |
+
bucket.fh.seek(offset)
|
102 |
+
bucket.fh.truncate()
|
103 |
+
|
104 |
+
def add_data(self, key, value):
|
105 |
+
i = hash(key) % len(self.buckets)
|
106 |
+
bucket = self.buckets[i]
|
107 |
+
bucket.add_data(value)
|
108 |
+
|
109 |
+
def save_checkpoint(self):
|
110 |
+
for bucket in self.buckets:
|
111 |
+
bucket.fh.flush()
|
112 |
+
|
113 |
+
bucket_offsets = [bucket.fh.tell() for bucket in self.buckets]
|
114 |
+
pickle.dump(bucket_offsets, open(self.checkpoint_file, "wb"))
|
115 |
+
|
116 |
+
def close_buckets(self):
|
117 |
+
for bucket in self.buckets:
|
118 |
+
bucket.commit()
|
119 |
+
|
120 |
+
|
121 |
+
def do_ngrams_in_buckets(n_value, working_directory, bucket_count):
|
122 |
+
|
123 |
+
pile_statistics = json.load(open("pile_statistics.json", "r"))
|
124 |
+
pile_document_count = pile_statistics["Document Count"]
|
125 |
+
start_offsets = pile_statistics["File Start Offsets"]
|
126 |
+
|
127 |
+
output_directory = os.path.join(working_directory, "output")
|
128 |
+
os.makedirs(output_directory, exist_ok=True)
|
129 |
+
|
130 |
+
logger.info(f"Generating {n_value}-grams and bucketing.")
|
131 |
+
|
132 |
+
# Done file
|
133 |
+
done_file = os.path.join(output_directory, f"ngram_buckets.done")
|
134 |
+
if os.path.exists(done_file):
|
135 |
+
logger.info("ngrams already generated and bucketed, skipping")
|
136 |
+
return
|
137 |
+
|
138 |
+
# Checkpoint
|
139 |
+
checkpoint_file = os.path.join(working_directory, f"pile_offset.ckpt")
|
140 |
+
if os.path.exists(checkpoint_file):
|
141 |
+
checkpoint_offset = pickle.load(open(checkpoint_file, "rb"))
|
142 |
+
iterate = True
|
143 |
+
else:
|
144 |
+
checkpoint_offset = 0
|
145 |
+
iterate = False
|
146 |
+
|
147 |
+
logger.info(f"Starting at pile document index {checkpoint_offset}")
|
148 |
+
buckets = Buckets(output_directory, bucket_count)
|
149 |
+
|
150 |
+
janitor = Janitor()
|
151 |
+
batch_size = 1000
|
152 |
+
batch_counter = 0
|
153 |
+
|
154 |
+
with tqdm(total=checkpoint_offset, dynamic_ncols=True, unit="docs") as progress:
|
155 |
+
for offset, document in yield_pile(start_offsets, checkpoint_offset):
|
156 |
+
if iterate:
|
157 |
+
logger.info(f"Iterating to offset {checkpoint_offset} from {offset}")
|
158 |
+
progress.update(offset)
|
159 |
+
iterate = False
|
160 |
+
|
161 |
+
if offset < checkpoint_offset:
|
162 |
+
progress.update()
|
163 |
+
|
164 |
+
if terminate:
|
165 |
+
return
|
166 |
+
continue
|
167 |
+
|
168 |
+
if offset == checkpoint_offset:
|
169 |
+
progress.reset(total=pile_document_count)
|
170 |
+
progress.update(checkpoint_offset)
|
171 |
+
|
172 |
+
# Save checkpoint every "batch_size", only allow terminate after checkpoint
|
173 |
+
if batch_counter == batch_size:
|
174 |
+
progress.update(batch_size)
|
175 |
+
batch_counter = 0
|
176 |
+
buckets.save_checkpoint()
|
177 |
+
pickle.dump(offset, open(checkpoint_file, "wb"))
|
178 |
+
if terminate:
|
179 |
+
buckets.close_buckets()
|
180 |
+
return
|
181 |
+
|
182 |
+
ngrams = word_ngrams(janitor.normalize_string(document), n_value)
|
183 |
+
for ngram in ngrams:
|
184 |
+
buckets.add_data(ngram, f"{ngram} {offset}")
|
185 |
+
|
186 |
+
batch_counter += 1
|
187 |
+
|
188 |
+
buckets.close_buckets()
|
189 |
+
Path(done_file).touch()
|
190 |
+
|
191 |
+
|
192 |
+
parser = argparse.ArgumentParser(description="Generate 13 grams from Pile.")
|
193 |
+
parser.add_argument("-dir", "--working_directory", default="")
|
194 |
+
parser.add_argument("-n", "--n_value", type=int, default=13)
|
195 |
+
parser.add_argument("-buckets", "--bucket_count", type=int, default=500)
|
196 |
+
|
197 |
+
if __name__ == "__main__":
|
198 |
+
version = 1.00
|
199 |
+
print(f"Running version {version}")
|
200 |
+
|
201 |
+
if "PYTHONHASHSEED" not in os.environ or os.environ["PYTHONHASHSEED"] != "0":
|
202 |
+
print("Please run 'export PYTHONHASHSEED=0' before running generate.")
|
203 |
+
sys.exit()
|
204 |
+
|
205 |
+
# Handle sigint (ctrl-c) cleanly
|
206 |
+
previous_signal_int = signal.signal(SIGINT, handler)
|
207 |
+
|
208 |
+
logfile_path = "ngrams.log"
|
209 |
+
setup_logger_tqdm(logfile_path)
|
210 |
+
|
211 |
+
args = parser.parse_args()
|
212 |
+
do_ngrams_in_buckets(args.n_value, args.working_directory, args.bucket_count)
|
213 |
+
|
214 |
+
info_dict = {"title": "dataset ngrams", "ngram_size": 13}
|
215 |
+
info_dict_path = os.path.join(args.working_directory, "info.json")
|
216 |
+
json.dump(info_dict, open(info_dict_path, "w"))
|
scripts/yans/eval/lm-evaluation-harness/scripts/clean_training_data/investigate_pile.py
ADDED
@@ -0,0 +1,94 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from lm_eval.decontamination.archiver import Reader
|
2 |
+
import os
|
3 |
+
import json
|
4 |
+
from functools import reduce
|
5 |
+
import glob
|
6 |
+
import tqdm
|
7 |
+
|
8 |
+
from tqdm_multiprocess import TqdmMultiProcessPool
|
9 |
+
|
10 |
+
|
11 |
+
def get_file_stats(file_path, tqdm_func, global_tqdm):
|
12 |
+
reader = Reader()
|
13 |
+
total_documents = 0
|
14 |
+
total_size = 0
|
15 |
+
update_frequency = 10000
|
16 |
+
current_file_position = 0
|
17 |
+
|
18 |
+
with tqdm_func(
|
19 |
+
total=os.path.getsize(file_path), dynamic_ncols=True, unit="byte", unit_scale=1
|
20 |
+
) as progress:
|
21 |
+
for document in reader.read(file_path, get_meta=True):
|
22 |
+
total_size += len(document)
|
23 |
+
total_documents += 1
|
24 |
+
|
25 |
+
if total_documents % update_frequency == 0:
|
26 |
+
new_file_pos = reader.fh.tell()
|
27 |
+
bytes_read = new_file_pos - current_file_position
|
28 |
+
current_file_position = new_file_pos
|
29 |
+
progress.update(bytes_read)
|
30 |
+
global_tqdm.update(bytes_read)
|
31 |
+
|
32 |
+
return (total_documents, total_size)
|
33 |
+
|
34 |
+
|
35 |
+
def get_files():
|
36 |
+
directory = "pile"
|
37 |
+
files = list(sorted(glob.glob(os.path.join(directory, "*.jsonl.zst*"))))
|
38 |
+
print(files)
|
39 |
+
return files
|
40 |
+
|
41 |
+
|
42 |
+
def get_stats():
|
43 |
+
files = get_files()
|
44 |
+
total_size_bytes = sum(map(lambda x: os.path.getsize(x), files))
|
45 |
+
|
46 |
+
pool = TqdmMultiProcessPool(4)
|
47 |
+
global_tqdm = tqdm.tqdm(
|
48 |
+
total=total_size_bytes, dynamic_ncols=True, unit="byte", unit_scale=1
|
49 |
+
)
|
50 |
+
|
51 |
+
# Generate minhashes with pool
|
52 |
+
tasks = [(get_file_stats, (file,)) for file in files]
|
53 |
+
|
54 |
+
def on_done(_):
|
55 |
+
return None
|
56 |
+
|
57 |
+
def on_error(_):
|
58 |
+
return None
|
59 |
+
|
60 |
+
results = pool.map(global_tqdm, tasks, on_error, on_done)
|
61 |
+
|
62 |
+
total_documents, total_size = reduce(
|
63 |
+
lambda x, y: (x[0] + y[0], x[1] + y[1]), results
|
64 |
+
)
|
65 |
+
|
66 |
+
start_offsets = []
|
67 |
+
current_offset = 0
|
68 |
+
for file_document_count, _ in results:
|
69 |
+
start_offsets.append(current_offset)
|
70 |
+
current_offset += file_document_count
|
71 |
+
|
72 |
+
return (total_documents, total_size, start_offsets)
|
73 |
+
|
74 |
+
|
75 |
+
if __name__ == "__main__":
|
76 |
+
version = 1.01
|
77 |
+
print(f"Running version {version}")
|
78 |
+
|
79 |
+
stats_file_path = "pile_statistics.json"
|
80 |
+
if os.path.exists(stats_file_path):
|
81 |
+
stats = json.load(open(stats_file_path, "r"))
|
82 |
+
else:
|
83 |
+
document_count, total_document_size_chars, start_offsets = get_stats()
|
84 |
+
stats = {
|
85 |
+
"Data": "Pile statistics",
|
86 |
+
"Document Count": document_count,
|
87 |
+
"Total Pile Characters": total_document_size_chars,
|
88 |
+
"File Start Offsets": start_offsets,
|
89 |
+
}
|
90 |
+
json.dump(stats, open(stats_file_path, "w"), indent=4)
|
91 |
+
|
92 |
+
print(f"document_count: {stats['Document Count']}")
|
93 |
+
print(f"total_chars: {stats['Total Pile Characters']}")
|
94 |
+
print(f"start_offsets: {stats['File Start Offsets']}")
|
scripts/yans/eval/lm-evaluation-harness/scripts/clean_training_data/janitor_util.cpp
ADDED
@@ -0,0 +1,208 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#include <pybind11/pybind11.h>
|
2 |
+
#include <pybind11/stl.h>
|
3 |
+
#include <queue>
|
4 |
+
#include <string>
|
5 |
+
#include <tuple>
|
6 |
+
#include <utility>
|
7 |
+
#include <vector>
|
8 |
+
|
9 |
+
bool is_whitespace(char ch) noexcept {
|
10 |
+
// " \t\n\r\x0b\x0c" (python string.whitespace)
|
11 |
+
return ch == 32 or (9 <= ch and ch <= 13);
|
12 |
+
// return ch <= 32; // arguably too general, but slightly faster
|
13 |
+
}
|
14 |
+
|
15 |
+
bool is_punctuation(char c) noexcept {
|
16 |
+
// '!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~' ascii values: 33-47, 58-64,
|
17 |
+
// 91-96, 123-126
|
18 |
+
return (33 <= c and c <= 47) or (58 <= c and c <= 64) or
|
19 |
+
(91 <= c and c <= 96) or (123 <= c and c <= 126);
|
20 |
+
}
|
21 |
+
|
22 |
+
// Takes a string and makes ngrams of length N, splitting grams on whitespace
|
23 |
+
// and ignoring ignored characters Returns a LARGE array of ngrams
|
24 |
+
std::vector<std::string> clean_ngram(std::string const &input,
|
25 |
+
std::string const &ignore,
|
26 |
+
size_t ngram_n) noexcept {
|
27 |
+
|
28 |
+
size_t num_grams = 0;
|
29 |
+
std::vector<std::string> ngram_list;
|
30 |
+
std::vector<uint8_t> gram_lengths;
|
31 |
+
std::string current_ngram;
|
32 |
+
|
33 |
+
// Max gram length is set to 10 below.
|
34 |
+
current_ngram.reserve(11 * ngram_n);
|
35 |
+
gram_lengths.reserve(ngram_n);
|
36 |
+
|
37 |
+
bool started_gram = false;
|
38 |
+
gram_lengths.push_back(0);
|
39 |
+
|
40 |
+
// for (size_t i=0; i<input.length(); i++) {
|
41 |
+
// this is slightly faster, and we don't need the index in this one
|
42 |
+
for (auto iter = input.begin(); iter != input.end(); iter++) {
|
43 |
+
|
44 |
+
// If whitespace, end the current ngram and start the next
|
45 |
+
// alternatively, (perhaps marginally) faster: if (is_whitespace(ch)) { ...
|
46 |
+
// }
|
47 |
+
if (is_whitespace(*iter) || gram_lengths.back() > 10) {
|
48 |
+
|
49 |
+
// Skip all whitespace
|
50 |
+
while (++iter != input.end() && is_whitespace(*iter))
|
51 |
+
;
|
52 |
+
iter--;
|
53 |
+
|
54 |
+
if (started_gram) {
|
55 |
+
num_grams += 1;
|
56 |
+
|
57 |
+
// Building 1grams is a special case
|
58 |
+
if (ngram_n == 1) {
|
59 |
+
ngram_list.push_back(current_ngram);
|
60 |
+
current_ngram = current_ngram.substr(gram_lengths.front());
|
61 |
+
gram_lengths.back() = 0;
|
62 |
+
|
63 |
+
// If there are enough grams to form an ngram, save
|
64 |
+
} else if (num_grams >= ngram_n) {
|
65 |
+
// Save the current ngram
|
66 |
+
ngram_list.push_back(current_ngram);
|
67 |
+
|
68 |
+
// Start the next ngram by dropping the first gram and its space from
|
69 |
+
// the ngram
|
70 |
+
current_ngram = current_ngram.substr(gram_lengths.front() + 1);
|
71 |
+
current_ngram += ' ';
|
72 |
+
|
73 |
+
// Drop the length of the first gram and prepare to record the length
|
74 |
+
// of the new gram
|
75 |
+
gram_lengths.erase(gram_lengths.begin());
|
76 |
+
gram_lengths.push_back(0);
|
77 |
+
|
78 |
+
// Otherwise, continute building
|
79 |
+
} else {
|
80 |
+
current_ngram += ' ';
|
81 |
+
gram_lengths.push_back(0);
|
82 |
+
}
|
83 |
+
|
84 |
+
started_gram = false;
|
85 |
+
}
|
86 |
+
|
87 |
+
// Skip ignored characters
|
88 |
+
// alternatively, (perhaps marginally) faster: if (is_punctuation(ch))
|
89 |
+
// continue;
|
90 |
+
} else if (ignore.find(*iter) != std::string::npos) {
|
91 |
+
continue;
|
92 |
+
}
|
93 |
+
|
94 |
+
// If it is a non-ignored character, add it to the ngram and update the last
|
95 |
+
// gram's length
|
96 |
+
else {
|
97 |
+
current_ngram += tolower(*iter);
|
98 |
+
gram_lengths.back() += 1;
|
99 |
+
started_gram = true;
|
100 |
+
}
|
101 |
+
}
|
102 |
+
|
103 |
+
return ngram_list;
|
104 |
+
}
|
105 |
+
|
106 |
+
// Takes a string and makes ngrams of length N, splitting grams on whitespace
|
107 |
+
// and ignoring ignored characters Returns a LARGE array of tuples of (ngram,
|
108 |
+
// start_idx, end_idx)
|
109 |
+
std::vector<std::tuple<std::string, size_t, size_t>>
|
110 |
+
clean_ngram_with_indices(std::string const &input, std::string const &ignore,
|
111 |
+
size_t ngram_n) noexcept {
|
112 |
+
|
113 |
+
size_t num_grams = 0;
|
114 |
+
std::vector<std::tuple<std::string, size_t, size_t>> ngram_list;
|
115 |
+
std::vector<uint8_t> gram_lengths;
|
116 |
+
std::vector<size_t> gram_start_indices;
|
117 |
+
std::string current_ngram;
|
118 |
+
|
119 |
+
// Max gram length is set to 10 below.
|
120 |
+
current_ngram.reserve(11 * ngram_n);
|
121 |
+
|
122 |
+
bool started_gram = false;
|
123 |
+
gram_lengths.push_back(0);
|
124 |
+
gram_start_indices.push_back(0);
|
125 |
+
|
126 |
+
for (size_t i = 0; i < input.length(); i++) {
|
127 |
+
char ch = input[i];
|
128 |
+
|
129 |
+
// If whitespace, end the current ngram and start the next
|
130 |
+
if (is_whitespace(ch) || gram_lengths.back() > 10) {
|
131 |
+
|
132 |
+
// Skip all whitespace
|
133 |
+
while (++i < input.length() && is_whitespace(input[i]))
|
134 |
+
;
|
135 |
+
i--;
|
136 |
+
|
137 |
+
if (started_gram) {
|
138 |
+
num_grams += 1;
|
139 |
+
|
140 |
+
// Building 1grams is a special case
|
141 |
+
if (ngram_n == 1) {
|
142 |
+
ngram_list.push_back(
|
143 |
+
std::make_tuple(current_ngram, gram_start_indices.front(), i));
|
144 |
+
current_ngram = current_ngram.substr(gram_lengths.front());
|
145 |
+
gram_lengths.back() = 0;
|
146 |
+
gram_start_indices.back() = i + 1;
|
147 |
+
|
148 |
+
// If there are enough grams to form an ngram, save
|
149 |
+
} else if (num_grams >= ngram_n) {
|
150 |
+
|
151 |
+
// Save the current ngram
|
152 |
+
ngram_list.push_back(
|
153 |
+
std::make_tuple(current_ngram, gram_start_indices.front(), i));
|
154 |
+
|
155 |
+
// Start the next ngram by dropping the first gram and its space from
|
156 |
+
// the ngram
|
157 |
+
current_ngram = current_ngram.substr(gram_lengths.front() + 1);
|
158 |
+
current_ngram += ' ';
|
159 |
+
|
160 |
+
// Drop the length of the first gram and prepare to record the length
|
161 |
+
// of the new gram
|
162 |
+
gram_lengths.erase(gram_lengths.begin());
|
163 |
+
gram_lengths.push_back(0);
|
164 |
+
|
165 |
+
gram_start_indices.erase(gram_start_indices.begin());
|
166 |
+
gram_start_indices.push_back(i + 1);
|
167 |
+
|
168 |
+
// Otherwise, continute building
|
169 |
+
} else {
|
170 |
+
current_ngram += ' ';
|
171 |
+
gram_lengths.push_back(0);
|
172 |
+
gram_start_indices.push_back(i + 1);
|
173 |
+
}
|
174 |
+
|
175 |
+
started_gram = false;
|
176 |
+
}
|
177 |
+
|
178 |
+
// Skip ignored characters
|
179 |
+
} else if (ignore.find(ch) != std::string::npos) {
|
180 |
+
continue;
|
181 |
+
|
182 |
+
// If it is a non-ignored character, add it to the ngram and update the
|
183 |
+
// last gram's length
|
184 |
+
} else {
|
185 |
+
current_ngram += tolower(ch);
|
186 |
+
gram_lengths.back() += 1;
|
187 |
+
started_gram = true;
|
188 |
+
}
|
189 |
+
}
|
190 |
+
|
191 |
+
return ngram_list;
|
192 |
+
}
|
193 |
+
|
194 |
+
PYBIND11_MODULE(janitor_util, m) {
|
195 |
+
m.doc() = "pybind11 example plugin"; // optional module docstring
|
196 |
+
// m.def("add", &add, "A function which adds two numbers"); // example
|
197 |
+
// function
|
198 |
+
m.def("clean_ngram", &clean_ngram,
|
199 |
+
"Create ngrams of words, ignoring some characters");
|
200 |
+
m.def("clean_ngram_with_indices", &clean_ngram_with_indices,
|
201 |
+
"Create ngrams of words with indices, ignoring some characters");
|
202 |
+
}
|
203 |
+
|
204 |
+
// Example compile
|
205 |
+
// c++ -O3 -Wall -shared -std=c++11 -fPIC $(python3 -m pybind11 --includes)
|
206 |
+
// janitor_util.cpp -o janitor_util$(python3-config --extension-suffix) If
|
207 |
+
// python and gcc aren't linked, append to the above: -undefined
|
208 |
+
// dynamic_lookup
|
scripts/yans/eval/lm-evaluation-harness/scripts/clean_training_data/process_sorted_buckets.py
ADDED
@@ -0,0 +1,131 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
"""
|
2 |
+
Processes each sorted bucket, creating a new file listing all ngrams that matched more then 10
|
3 |
+
unique documents with their unique document counts. Uses multiprocessing and very little memory
|
4 |
+
as we stream from presorted buckets. Will use a lot of disk though.
|
5 |
+
|
6 |
+
Arguments
|
7 |
+
---------
|
8 |
+
--working_directory (-dir)
|
9 |
+
Directory containing the sorted buckets, processed files will be deposited here. Default: current directory
|
10 |
+
--move_dir (-move)
|
11 |
+
Directory to move processed 13grams too. Default: Do nothing
|
12 |
+
--process_count (-procs)
|
13 |
+
Number of processes to use. Default: 4
|
14 |
+
"""
|
15 |
+
|
16 |
+
import argparse
|
17 |
+
import glob
|
18 |
+
import os
|
19 |
+
from pathlib import Path
|
20 |
+
import re
|
21 |
+
import shutil
|
22 |
+
|
23 |
+
from tqdm import tqdm
|
24 |
+
from tqdm_multiprocess import TqdmMultiProcessPool
|
25 |
+
|
26 |
+
from scripts.clean_training_data.archiver import TextReader, TextArchive
|
27 |
+
|
28 |
+
import logging
|
29 |
+
from tqdm_multiprocess.logger import setup_logger_tqdm
|
30 |
+
|
31 |
+
logger = logging.getLogger(__name__)
|
32 |
+
|
33 |
+
|
34 |
+
# Multiprocessed
|
35 |
+
def process_bucket(
|
36 |
+
bucket_file_path, processed_directory, move_dir, tqdm_func, global_tqdm
|
37 |
+
):
|
38 |
+
|
39 |
+
bucket_id = re.sub("\D", "", os.path.basename(bucket_file_path)) # noqa: W605
|
40 |
+
done_file = os.path.join(
|
41 |
+
processed_directory, f"ngram_bucket_processing_{bucket_id}.done"
|
42 |
+
)
|
43 |
+
if os.path.exists(done_file):
|
44 |
+
logger.info(f"bucket {bucket_id} already processed, skipping")
|
45 |
+
return
|
46 |
+
|
47 |
+
# For managing tqdm
|
48 |
+
file_size = os.path.getsize(bucket_file_path)
|
49 |
+
bucket_progress = tqdm_func(
|
50 |
+
total=file_size, dynamic_ncols=True, unit="byte", unit_scale=1
|
51 |
+
)
|
52 |
+
current_file_position = 0
|
53 |
+
update_frequency = 100 * 1000000 # 100mb
|
54 |
+
update_counter = 0
|
55 |
+
|
56 |
+
# Iterate through and output ngrams which occur in more then 10 documents
|
57 |
+
bucket = TextReader(bucket_file_path)
|
58 |
+
|
59 |
+
output_file_path = bucket_file_path + ".processed"
|
60 |
+
output_archive = TextArchive(output_file_path, mode="wb")
|
61 |
+
|
62 |
+
current_ngram = ""
|
63 |
+
current_ngram_document_ids = set()
|
64 |
+
for line in bucket.read():
|
65 |
+
[ngram, document_id] = line.rsplit(" ", 1)
|
66 |
+
|
67 |
+
# Write ngram if more then 10 unique document occurrences
|
68 |
+
if ngram != current_ngram:
|
69 |
+
if len(current_ngram_document_ids) > 10:
|
70 |
+
output_archive.add_data(
|
71 |
+
f"{current_ngram} {len(current_ngram_document_ids)}"
|
72 |
+
)
|
73 |
+
current_ngram = ngram
|
74 |
+
current_ngram_document_ids = set()
|
75 |
+
|
76 |
+
current_ngram_document_ids.add(document_id)
|
77 |
+
|
78 |
+
# Update tqdm
|
79 |
+
update_counter += bucket.fh.tell() - current_file_position
|
80 |
+
current_file_position = bucket.fh.tell()
|
81 |
+
if update_counter > update_frequency:
|
82 |
+
bucket_progress.update(update_counter)
|
83 |
+
update_counter = 0
|
84 |
+
|
85 |
+
# Remainder
|
86 |
+
if len(current_ngram_document_ids) > 10:
|
87 |
+
output_archive.add_data(f"{current_ngram} {len(current_ngram_document_ids)}")
|
88 |
+
|
89 |
+
output_archive.commit()
|
90 |
+
Path(done_file).touch()
|
91 |
+
|
92 |
+
if move_dir:
|
93 |
+
shutil.move(output_file_path, move_dir)
|
94 |
+
|
95 |
+
global_tqdm.update()
|
96 |
+
|
97 |
+
|
98 |
+
def process_sorted_buckets(working_directory, move_dir, process_count):
|
99 |
+
bucket_file_paths = glob.glob(os.path.join(working_directory, f"*.bkt.txt.sorted"))
|
100 |
+
processed_directory = os.path.join(working_directory, "processed")
|
101 |
+
os.makedirs(processed_directory, exist_ok=True)
|
102 |
+
|
103 |
+
pool = TqdmMultiProcessPool(process_count)
|
104 |
+
tasks = [
|
105 |
+
(process_bucket, (bucket_file, processed_directory, move_dir))
|
106 |
+
for bucket_file in bucket_file_paths
|
107 |
+
]
|
108 |
+
|
109 |
+
global_tqdm = tqdm(total=len(bucket_file_paths), dynamic_ncols=True, unit="bucket")
|
110 |
+
|
111 |
+
def on_done(_):
|
112 |
+
return None
|
113 |
+
|
114 |
+
def on_error(_):
|
115 |
+
return None
|
116 |
+
|
117 |
+
_ = pool.map(global_tqdm, tasks, on_error, on_done)
|
118 |
+
|
119 |
+
|
120 |
+
parser = argparse.ArgumentParser(description="Process 13 grams from sorted buckets.")
|
121 |
+
parser.add_argument("-dir", "--working_directory", default="")
|
122 |
+
parser.add_argument("-move", "--move_dir", default="")
|
123 |
+
parser.add_argument("-procs", "--process_count", type=int, default=4)
|
124 |
+
|
125 |
+
if __name__ == "__main__":
|
126 |
+
|
127 |
+
logfile_path = "process13grams.log"
|
128 |
+
setup_logger_tqdm(logfile_path)
|
129 |
+
|
130 |
+
args = parser.parse_args()
|
131 |
+
process_sorted_buckets(args.working_directory, args.move_dir, args.process_count)
|
scripts/yans/eval/lm-evaluation-harness/scripts/clean_training_data/sort_13_gram_buckets.py
ADDED
@@ -0,0 +1,63 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
"""
|
2 |
+
Iteratively runs gnu sort on each bucket, uses up to 8 cores.
|
3 |
+
|
4 |
+
Arguments
|
5 |
+
---------
|
6 |
+
--working_directory (-dir)
|
7 |
+
Directory containing the bucketed 13-grams. Sorted buckets will be deposited in the same
|
8 |
+
directory and the unsorted buckets are removed after.
|
9 |
+
"""
|
10 |
+
|
11 |
+
import glob
|
12 |
+
import argparse
|
13 |
+
import os
|
14 |
+
import signal
|
15 |
+
from signal import SIGINT
|
16 |
+
import subprocess
|
17 |
+
|
18 |
+
from tqdm import tqdm
|
19 |
+
|
20 |
+
import logging
|
21 |
+
from tqdm_multiprocess.logger import setup_logger_tqdm
|
22 |
+
|
23 |
+
logger = logging.getLogger(__name__)
|
24 |
+
|
25 |
+
terminate = False
|
26 |
+
|
27 |
+
|
28 |
+
def handler(signal_received, frame):
|
29 |
+
global terminate
|
30 |
+
terminate = True
|
31 |
+
|
32 |
+
|
33 |
+
def sort_13_gram_buckets(working_directory):
|
34 |
+
bucket_file_paths = glob.glob(os.path.join(working_directory, f"*.bkt.txt"))
|
35 |
+
|
36 |
+
for bucket_file_path in tqdm(bucket_file_paths, dynamic_ncols=True):
|
37 |
+
sorted_file_path = bucket_file_path + ".sorted"
|
38 |
+
command = f"sort {bucket_file_path} > {sorted_file_path}"
|
39 |
+
logger.info(command)
|
40 |
+
subprocess.call(command, shell=True)
|
41 |
+
|
42 |
+
if terminate:
|
43 |
+
return
|
44 |
+
|
45 |
+
os.remove(bucket_file_path)
|
46 |
+
|
47 |
+
|
48 |
+
parser = argparse.ArgumentParser(description="sort 13gram buckets")
|
49 |
+
parser.add_argument("-dir", "--working_directory", default="")
|
50 |
+
|
51 |
+
if __name__ == "__main__":
|
52 |
+
|
53 |
+
version = 1.00
|
54 |
+
print(f"Running version {version}")
|
55 |
+
|
56 |
+
# Handle sigint (ctrl-c) cleanly
|
57 |
+
previous_signal_int = signal.signal(SIGINT, handler)
|
58 |
+
|
59 |
+
logfile_path = "sort13grambuckets.log"
|
60 |
+
setup_logger_tqdm(logfile_path)
|
61 |
+
|
62 |
+
args = parser.parse_args()
|
63 |
+
sort_13_gram_buckets(args.working_directory)
|
scripts/yans/eval/lm-evaluation-harness/scripts/cost_estimate.py
ADDED
@@ -0,0 +1,98 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import random
|
2 |
+
import transformers
|
3 |
+
from lm_eval import tasks, evaluator
|
4 |
+
from lm_eval.base import LM
|
5 |
+
|
6 |
+
|
7 |
+
class DryrunLM(LM):
|
8 |
+
def __init__(self):
|
9 |
+
self.tokencost = 0
|
10 |
+
self.tokenizer = transformers.GPT2TokenizerFast.from_pretrained("gpt2")
|
11 |
+
self.tokenizer.pad_token = "<|endoftext|>"
|
12 |
+
|
13 |
+
@classmethod
|
14 |
+
def create_from_arg_string(cls, arg_string):
|
15 |
+
return cls()
|
16 |
+
|
17 |
+
def loglikelihood(self, requests):
|
18 |
+
res = []
|
19 |
+
|
20 |
+
for ctx, cont in requests:
|
21 |
+
res.append((-random.random(), False))
|
22 |
+
self.tokencost += len(self.tokenizer.tokenize(ctx + cont))
|
23 |
+
|
24 |
+
return res
|
25 |
+
|
26 |
+
def greedy_until(self, requests):
|
27 |
+
res = []
|
28 |
+
|
29 |
+
for ctx, until in requests:
|
30 |
+
res.append("lol")
|
31 |
+
|
32 |
+
# assume worst case - generates until 256
|
33 |
+
self.tokencost += len(self.tokenizer.tokenize(ctx)) + 256
|
34 |
+
|
35 |
+
return res
|
36 |
+
|
37 |
+
def loglikelihood_rolling(self, requests):
|
38 |
+
res = []
|
39 |
+
|
40 |
+
for (s,) in requests:
|
41 |
+
# assume worst case: extra full context
|
42 |
+
self.tokencost += len(self.tokenizer.tokenize(s)) + 2048
|
43 |
+
|
44 |
+
return res
|
45 |
+
|
46 |
+
|
47 |
+
def main():
|
48 |
+
lm = DryrunLM()
|
49 |
+
|
50 |
+
task_list = "arc_challenge,arc_easy,boolq,cola,copa,headqa,hellaswag,lambada,logiqa,mathqa,mc_taco,mrpc,multirc,openbookqa,piqa,prost,pubmedqa,qnli,qqp,race,record,rte,sciq,sst,triviaqa,webqs,wic,wikitext,winogrande,wnli,wsc"
|
51 |
+
values = []
|
52 |
+
for taskname in task_list.split(","):
|
53 |
+
lm.tokencost = 0
|
54 |
+
evaluator.evaluate(
|
55 |
+
lm=lm,
|
56 |
+
task_dict={taskname: tasks.get_task(taskname)()},
|
57 |
+
num_fewshot=0,
|
58 |
+
limit=None,
|
59 |
+
bootstrap_iters=10,
|
60 |
+
description_dict=None,
|
61 |
+
)
|
62 |
+
|
63 |
+
print(taskname, lm.tokencost)
|
64 |
+
values.append(
|
65 |
+
[
|
66 |
+
taskname,
|
67 |
+
lm.tokencost,
|
68 |
+
lm.tokencost / 1000 * 0.0008,
|
69 |
+
lm.tokencost / 1000 * 0.0012,
|
70 |
+
lm.tokencost / 1000 * 0.006,
|
71 |
+
lm.tokencost / 1000 * 0.06,
|
72 |
+
]
|
73 |
+
)
|
74 |
+
from pytablewriter import MarkdownTableWriter
|
75 |
+
|
76 |
+
writer = MarkdownTableWriter()
|
77 |
+
writer.headers = ["Task", "Tokens", "Ada", "Babbage", "Curie", "Davinci"]
|
78 |
+
|
79 |
+
values.sort(key=lambda x: -x[1])
|
80 |
+
totcost = sum([x[1] for x in values])
|
81 |
+
values.append(
|
82 |
+
[
|
83 |
+
"**Total**",
|
84 |
+
totcost,
|
85 |
+
totcost / 1000 * 0.0008,
|
86 |
+
totcost / 1000 * 0.0012,
|
87 |
+
totcost / 1000 * 0.006,
|
88 |
+
totcost / 1000 * 0.06,
|
89 |
+
]
|
90 |
+
)
|
91 |
+
|
92 |
+
writer.value_matrix = values
|
93 |
+
|
94 |
+
print(writer.dumps())
|
95 |
+
|
96 |
+
|
97 |
+
if __name__ == "__main__":
|
98 |
+
main()
|
scripts/yans/eval/lm-evaluation-harness/scripts/harness_example.py
ADDED
@@ -0,0 +1,38 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#!/usr/bin/env python
|
2 |
+
# This script runs eval in the cluster. Use it as a basis for your own harnesses.
|
3 |
+
from run_eval import build_executor, run_job
|
4 |
+
from run_eval import JAEVAL8_TASKS, JAEVAL8_FEWSHOT
|
5 |
+
from main_eval import main as main_eval
|
6 |
+
|
7 |
+
|
8 |
+
def build_task_list(tasks, prompt):
|
9 |
+
out = []
|
10 |
+
# Some tasks don't have a prompt version
|
11 |
+
promptless = ["xwinograd_ja"]
|
12 |
+
for task in tasks:
|
13 |
+
if task not in promptless:
|
14 |
+
out.append(f"{task}-{prompt}")
|
15 |
+
else:
|
16 |
+
out.append(task)
|
17 |
+
return out
|
18 |
+
|
19 |
+
|
20 |
+
def main():
|
21 |
+
executor = build_executor("eval", gpus_per_task=8, cpus_per_gpu=12)
|
22 |
+
|
23 |
+
tasks = build_task_list(JAEVAL8_TASKS, "0.3")
|
24 |
+
eval_args = {
|
25 |
+
"tasks": tasks,
|
26 |
+
"num_fewshot": JAEVAL8_FEWSHOT,
|
27 |
+
"model": "hf-causal",
|
28 |
+
"model_args": "pretrained=rinna/japanese-gpt-1b,use_fast=False",
|
29 |
+
"device": "cuda",
|
30 |
+
"limit": 100,
|
31 |
+
"verbose": True,
|
32 |
+
}
|
33 |
+
|
34 |
+
run_job(executor, main_eval, eval_args=eval_args, output_path="./check.json")
|
35 |
+
|
36 |
+
|
37 |
+
if __name__ == "__main__":
|
38 |
+
main()
|
scripts/yans/eval/lm-evaluation-harness/scripts/main_eval.py
ADDED
@@ -0,0 +1,127 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
import argparse
|
3 |
+
import json
|
4 |
+
import logging
|
5 |
+
import fnmatch
|
6 |
+
|
7 |
+
from lm_eval import tasks, evaluator
|
8 |
+
|
9 |
+
logging.getLogger("openai").setLevel(logging.WARNING)
|
10 |
+
|
11 |
+
|
12 |
+
class MultiChoice:
|
13 |
+
def __init__(self, choices):
|
14 |
+
self.choices = choices
|
15 |
+
|
16 |
+
# Simple wildcard support (linux filename patterns)
|
17 |
+
def __contains__(self, values):
|
18 |
+
for value in values.split(","):
|
19 |
+
if len(fnmatch.filter(self.choices, value)) == 0:
|
20 |
+
return False
|
21 |
+
|
22 |
+
return True
|
23 |
+
|
24 |
+
def __iter__(self):
|
25 |
+
for choice in self.choices:
|
26 |
+
yield choice
|
27 |
+
|
28 |
+
|
29 |
+
def parse_args():
|
30 |
+
parser = argparse.ArgumentParser()
|
31 |
+
parser.add_argument("--model", required=True)
|
32 |
+
parser.add_argument("--model_args", default="")
|
33 |
+
parser.add_argument("--tasks", default=None, choices=MultiChoice(tasks.ALL_TASKS))
|
34 |
+
parser.add_argument("--num_fewshot", type=str, default="0")
|
35 |
+
parser.add_argument("--batch_size", type=int, default=None)
|
36 |
+
parser.add_argument("--device", type=str, default=None)
|
37 |
+
parser.add_argument("--output_path", default=None)
|
38 |
+
parser.add_argument("--limit", type=str, default=None)
|
39 |
+
parser.add_argument("--no_cache", action="store_true")
|
40 |
+
parser.add_argument("--decontamination_ngrams_path", default=None)
|
41 |
+
parser.add_argument("--description_dict_path", default=None)
|
42 |
+
parser.add_argument("--check_integrity", action="store_true")
|
43 |
+
parser.add_argument("--verbose", action="store_true")
|
44 |
+
# TODO This is deprecated and throws an error, remove it
|
45 |
+
parser.add_argument("--provide_description", action="store_true")
|
46 |
+
|
47 |
+
return parser.parse_args()
|
48 |
+
|
49 |
+
|
50 |
+
def clean_args(args) -> dict:
|
51 |
+
"""Handle conversion to lists etc. for args"""
|
52 |
+
|
53 |
+
assert not args.provide_description, "provide-description is not implemented"
|
54 |
+
|
55 |
+
if args.limit:
|
56 |
+
print(
|
57 |
+
"WARNING: --limit SHOULD ONLY BE USED FOR TESTING. REAL METRICS SHOULD NOT BE COMPUTED USING LIMIT."
|
58 |
+
)
|
59 |
+
|
60 |
+
if args.tasks is None:
|
61 |
+
args.tasks = tasks.ALL_TASKS
|
62 |
+
else:
|
63 |
+
args.tasks = pattern_match(args.tasks.split(","), tasks.ALL_TASKS)
|
64 |
+
|
65 |
+
print(f"Selected Tasks: {args.tasks}")
|
66 |
+
if args.num_fewshot is not None:
|
67 |
+
args.num_fewshot = [int(n) for n in args.num_fewshot.split(",")]
|
68 |
+
|
69 |
+
if args.limit is not None:
|
70 |
+
args.limit = [
|
71 |
+
int(n) if n.isdigit() else float(n) for n in args.limit.split(",")
|
72 |
+
]
|
73 |
+
|
74 |
+
return vars(args)
|
75 |
+
|
76 |
+
|
77 |
+
# Returns a list containing all values of the source_list that
|
78 |
+
# match at least one of the patterns
|
79 |
+
def pattern_match(patterns, source_list):
|
80 |
+
task_names = []
|
81 |
+
for pattern in patterns:
|
82 |
+
for matching in fnmatch.filter(source_list, pattern):
|
83 |
+
task_names.append(matching)
|
84 |
+
return task_names
|
85 |
+
|
86 |
+
|
87 |
+
def main(eval_args: dict, description_dict_path: str = None, output_path: str = None):
|
88 |
+
"""Run evaluation and optionally save output.
|
89 |
+
|
90 |
+
For a description of eval args, see `simple_evaluate`.
|
91 |
+
"""
|
92 |
+
if description_dict_path:
|
93 |
+
with open(description_dict_path, "r") as f:
|
94 |
+
eval_args["description_dict"] = json.load(f)
|
95 |
+
|
96 |
+
results = evaluator.simple_evaluate(**eval_args)
|
97 |
+
|
98 |
+
dumped = json.dumps(results, indent=2, ensure_ascii=False)
|
99 |
+
print(dumped)
|
100 |
+
|
101 |
+
if output_path:
|
102 |
+
os.makedirs(os.path.dirname(output_path), exist_ok=True)
|
103 |
+
with open(output_path, "w") as f:
|
104 |
+
f.write(dumped)
|
105 |
+
|
106 |
+
return results
|
107 |
+
|
108 |
+
|
109 |
+
if __name__ == "__main__":
|
110 |
+
args = parse_args()
|
111 |
+
args = clean_args(args)
|
112 |
+
|
113 |
+
# This is not used
|
114 |
+
args.pop("provide_description", None)
|
115 |
+
# treat non-eval args separately
|
116 |
+
description_dict_path = args.get("description_dict_path", None)
|
117 |
+
args.pop("description_dict_path", None)
|
118 |
+
output_path = args.get("output_path", None)
|
119 |
+
args.pop("output_path", None)
|
120 |
+
|
121 |
+
results = main(args, description_dict_path, output_path)
|
122 |
+
|
123 |
+
print(
|
124 |
+
f"{args['model']} ({args['model_args']}), limit: {args['limit']}, "
|
125 |
+
f"num_fewshot: {args['num_fewshot']}, batch_size: {args['batch_size']}"
|
126 |
+
)
|
127 |
+
print(evaluator.make_table(results))
|
scripts/yans/eval/lm-evaluation-harness/scripts/make_table_tasks.py
ADDED
@@ -0,0 +1,52 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
"""
|
2 |
+
Usage:
|
3 |
+
python make_table_tasks.py --output <markdown_filename>
|
4 |
+
"""
|
5 |
+
import argparse
|
6 |
+
import logging
|
7 |
+
from lm_eval import tasks
|
8 |
+
from pytablewriter import MarkdownTableWriter
|
9 |
+
|
10 |
+
|
11 |
+
logging.basicConfig(level=logging.INFO)
|
12 |
+
logger = logging.getLogger(__name__)
|
13 |
+
|
14 |
+
|
15 |
+
def check(tf):
|
16 |
+
if tf:
|
17 |
+
return "✓"
|
18 |
+
else:
|
19 |
+
return " "
|
20 |
+
|
21 |
+
|
22 |
+
if __name__ == "__main__":
|
23 |
+
parser = argparse.ArgumentParser()
|
24 |
+
parser.add_argument("--output", type=str, default="task_table.md")
|
25 |
+
args = parser.parse_args()
|
26 |
+
|
27 |
+
writer = MarkdownTableWriter()
|
28 |
+
writer.headers = ["Task Name", "Train", "Val", "Test", "Val/Test Docs", "Metrics"]
|
29 |
+
values = []
|
30 |
+
|
31 |
+
tasks = tasks.TASK_REGISTRY.items()
|
32 |
+
tasks = sorted(tasks, key=lambda x: x[0])
|
33 |
+
for tname, Task in tasks:
|
34 |
+
task = Task()
|
35 |
+
v = [
|
36 |
+
tname,
|
37 |
+
check(task.has_training_docs()),
|
38 |
+
check(task.has_validation_docs()),
|
39 |
+
check(task.has_test_docs()),
|
40 |
+
len(
|
41 |
+
list(
|
42 |
+
task.test_docs() if task.has_test_docs() else task.validation_docs()
|
43 |
+
)
|
44 |
+
),
|
45 |
+
", ".join(task.aggregation().keys()),
|
46 |
+
]
|
47 |
+
logger.info(v)
|
48 |
+
values.append(v)
|
49 |
+
writer.value_matrix = values
|
50 |
+
table = writer.dumps()
|
51 |
+
with open(args.output, "w") as f:
|
52 |
+
f.write(table)
|
scripts/yans/eval/lm-evaluation-harness/scripts/merge_json.py
ADDED
@@ -0,0 +1,48 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from glob import glob
|
2 |
+
from pathlib import Path
|
3 |
+
import json
|
4 |
+
import sys
|
5 |
+
|
6 |
+
# Find task-specific json files and add them to result json files.
|
7 |
+
|
8 |
+
# task name, ex: xwinograd_ja
|
9 |
+
try:
|
10 |
+
task = sys.argv[1]
|
11 |
+
except IndexError:
|
12 |
+
print("Give task name as first argument, like: xwinograd_ja")
|
13 |
+
sys.exit(1)
|
14 |
+
|
15 |
+
# task-specific result files have names like result.TASK.json
|
16 |
+
task_results = glob(f"models/**/result.{task}.json", recursive=True)
|
17 |
+
|
18 |
+
# given a task-specific file, the result.json file always exists
|
19 |
+
for tres in task_results:
|
20 |
+
tres = Path(tres)
|
21 |
+
res = tres.parent / "result.json"
|
22 |
+
|
23 |
+
with open(res) as resfile:
|
24 |
+
res_data = json.loads(resfile.read())
|
25 |
+
|
26 |
+
with open(tres) as resfile:
|
27 |
+
tres_data = json.loads(resfile.read())
|
28 |
+
|
29 |
+
if task in res_data["results"]:
|
30 |
+
# Ideally we would overwrite these, but it can be tricky to get the few
|
31 |
+
# shot order correct, so adding that later.
|
32 |
+
# TODO overwrite
|
33 |
+
print(f"Not updating {tres.parent.name} because results already present")
|
34 |
+
continue
|
35 |
+
|
36 |
+
# update the relevant keys
|
37 |
+
for key in ("results", "versions"):
|
38 |
+
res_data[key][task] = tres_data[key][task]
|
39 |
+
|
40 |
+
# because the result is new, fewshot goes at the end
|
41 |
+
# for a single task, fewshow is a scalar and not an array
|
42 |
+
# XXX is the type change a bug?
|
43 |
+
tres_fewshot = tres_data["config"]["num_fewshot"]
|
44 |
+
res_data["config"]["num_fewshot"].append(tres_fewshot)
|
45 |
+
|
46 |
+
with open(res, "w") as resfile:
|
47 |
+
out = json.dumps(res_data, indent=2)
|
48 |
+
resfile.write(out)
|
scripts/yans/eval/lm-evaluation-harness/scripts/run_task_for_models.sh
ADDED
@@ -0,0 +1,28 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#!/bin/bash
|
2 |
+
# Given a task, run it on all relevant models and update their results.
|
3 |
+
# See run_task_batch.sh for project, job name, and other batch settings.
|
4 |
+
set -eou pipefail
|
5 |
+
|
6 |
+
task=$1
|
7 |
+
fewshot=$2
|
8 |
+
# cd to script dir and then go up one so all paths work
|
9 |
+
cd $(dirname -- "$0")/..
|
10 |
+
|
11 |
+
# models.txt is a space-separated file. To generate it, use the code in this
|
12 |
+
# function from the project root, then edit the file to remove models you don't
|
13 |
+
# want to use (like community).
|
14 |
+
function generate_models_txt() {
|
15 |
+
find models/ -name harness.sh \
|
16 |
+
| xargs grep MODEL_ARGS= \
|
17 |
+
| sed -e 's:^models/::' -e 's:/harness.sh.MODEL_ARGS=: :' -e 's:"::g' \
|
18 |
+
> scripts/models.txt
|
19 |
+
}
|
20 |
+
|
21 |
+
cat scripts/models.txt | while read model_path args; do
|
22 |
+
# The echo is just for debugging
|
23 |
+
echo sbatch scripts/run_task_batch.sh $task $fewshot $args $model_path
|
24 |
+
sbatch scripts/run_task_batch.sh $task $fewshot $args $model_path
|
25 |
+
done
|
26 |
+
|
27 |
+
# after the batches have finished, use the following command to update results.json
|
28 |
+
# python scripts/merge_json.py
|
scripts/yans/lm-evaluation-harness/.coveragerc
ADDED
@@ -0,0 +1,28 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
[run]
|
2 |
+
|
3 |
+
# tasks that aren't wired up.
|
4 |
+
omit =
|
5 |
+
lm_eval/tasks/quac.py
|
6 |
+
lm_eval/tasks/storycloze.py
|
7 |
+
lm_eval/tasks/cbt.py
|
8 |
+
lm_eval/tasks/sat.py
|
9 |
+
lm_eval/tasks/triviaqa.py
|
10 |
+
lm_eval/tasks/naturalqs.py
|
11 |
+
lm_eval/models/dummy.py
|
12 |
+
|
13 |
+
[report]
|
14 |
+
exclude_lines =
|
15 |
+
# Skip any pass lines such as may be used for @abstractmethod
|
16 |
+
pass
|
17 |
+
|
18 |
+
# Have to re-enable the standard pragma
|
19 |
+
pragma: no cover
|
20 |
+
|
21 |
+
# Don't complain about missing debug-only code:
|
22 |
+
def __repr__
|
23 |
+
if self\.debug
|
24 |
+
|
25 |
+
# Don't complain if tests don't hit defensive assertion code:
|
26 |
+
raise AssertionError
|
27 |
+
raise NotImplementedError
|
28 |
+
return NotImplemented
|
scripts/yans/lm-evaluation-harness/.flake8
ADDED
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
[flake8]
|
2 |
+
ignore = E203, E266, E501, W503, F403, F401, C901
|
3 |
+
max-line-length = 127
|
4 |
+
max-complexity = 10
|
5 |
+
select = B,C,E,F,W,T4,B9
|
scripts/yans/lm-evaluation-harness/.gitignore
ADDED
@@ -0,0 +1,24 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
env
|
2 |
+
*.pyc
|
3 |
+
output/
|
4 |
+
data/
|
5 |
+
lm_cache
|
6 |
+
.idea
|
7 |
+
build
|
8 |
+
dist
|
9 |
+
*.egg-info
|
10 |
+
venv
|
11 |
+
.vscode/
|
12 |
+
temp
|
13 |
+
__pycache__
|
14 |
+
.ipynb_checkpoints
|
15 |
+
temp
|
16 |
+
test_logs/
|
17 |
+
# IPython
|
18 |
+
profile_default/
|
19 |
+
ipython_config.py
|
20 |
+
# don't track (the default location of) the cached requests
|
21 |
+
lm_eval/caching/.cache
|
22 |
+
# don't track files created by wandb
|
23 |
+
wandb
|
24 |
+
examples/wandb
|
scripts/yans/lm-evaluation-harness/.pre-commit-config.yaml
ADDED
@@ -0,0 +1,54 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Ignore test linting to avoid conflicting changes to version stability.
|
2 |
+
exclude: ^tests/testdata/
|
3 |
+
repos:
|
4 |
+
- repo: https://github.com/pre-commit/pre-commit-hooks
|
5 |
+
rev: v4.5.0
|
6 |
+
hooks:
|
7 |
+
- id: check-added-large-files
|
8 |
+
- id: check-ast
|
9 |
+
- id: check-byte-order-marker
|
10 |
+
- id: check-case-conflict
|
11 |
+
- id: check-json
|
12 |
+
- id: check-merge-conflict
|
13 |
+
args: [--assume-in-merge]
|
14 |
+
- id: check-symlinks
|
15 |
+
- id: check-yaml
|
16 |
+
args: ["--unsafe"]
|
17 |
+
- id: destroyed-symlinks
|
18 |
+
- id: detect-private-key
|
19 |
+
- id: end-of-file-fixer
|
20 |
+
- id: no-commit-to-branch
|
21 |
+
always_run: false
|
22 |
+
- id: requirements-txt-fixer
|
23 |
+
- id: trailing-whitespace
|
24 |
+
args: [--markdown-linebreak-ext=md]
|
25 |
+
- id: fix-byte-order-marker
|
26 |
+
exclude: docs/CNAME
|
27 |
+
- id: fix-encoding-pragma
|
28 |
+
args: [--remove]
|
29 |
+
- id: mixed-line-ending
|
30 |
+
args: [--fix=lf]
|
31 |
+
- repo: https://github.com/astral-sh/ruff-pre-commit
|
32 |
+
rev: v0.4.8
|
33 |
+
hooks:
|
34 |
+
# Run the linter.
|
35 |
+
- id: ruff
|
36 |
+
args:
|
37 |
+
- --fix
|
38 |
+
# Run the formatter.
|
39 |
+
- id: ruff-format
|
40 |
+
- repo: https://github.com/codespell-project/codespell
|
41 |
+
rev: v2.3.0
|
42 |
+
hooks:
|
43 |
+
- id: codespell
|
44 |
+
exclude: >
|
45 |
+
(?x)^(
|
46 |
+
.*\.json|ignore.txt|lm_eval/tasks/.*|.*yaml|.*\.ipynb
|
47 |
+
)$
|
48 |
+
args: [--check-filenames, --check-hidden, --ignore-words=ignore.txt]
|
49 |
+
# - repo: https://github.com/pre-commit/mirrors-mypy
|
50 |
+
# rev: v1.5.1
|
51 |
+
# hooks:
|
52 |
+
# - id: mypy
|
53 |
+
# additional_dependencies: [".[sentencepiece,multilingual,promptsource,gptq]", "types-PyYAML", "types-requests"]
|
54 |
+
# exclude: ^tests/.*$
|
scripts/yans/lm-evaluation-harness/CITATION.bib
ADDED
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
@misc{eval-harness,
|
2 |
+
author = {Gao, Leo and Tow, Jonathan and Abbasi, Baber and Biderman, Stella and Black, Sid and DiPofi, Anthony and Foster, Charles and Golding, Laurence and Hsu, Jeffrey and Le Noac'h, Alain and Li, Haonan and McDonell, Kyle and Muennighoff, Niklas and Ociepa, Chris and Phang, Jason and Reynolds, Laria and Schoelkopf, Hailey and Skowron, Aviya and Sutawika, Lintang and Tang, Eric and Thite, Anish and Wang, Ben and Wang, Kevin and Zou, Andy},
|
3 |
+
title = {A framework for few-shot language model evaluation},
|
4 |
+
month = 12,
|
5 |
+
year = 2023,
|
6 |
+
publisher = {Zenodo},
|
7 |
+
version = {v0.4.0},
|
8 |
+
doi = {10.5281/zenodo.10256836},
|
9 |
+
url = {https://zenodo.org/records/10256836}
|
10 |
+
}
|
scripts/yans/lm-evaluation-harness/CODEOWNERS
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
* @haileyschoelkopf @lintangsutawika
|
scripts/yans/lm-evaluation-harness/LICENSE.md
ADDED
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
MIT License
|
2 |
+
|
3 |
+
Copyright (c) 2020 EleutherAI
|
4 |
+
|
5 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6 |
+
of this software and associated documentation files (the "Software"), to deal
|
7 |
+
in the Software without restriction, including without limitation the rights
|
8 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9 |
+
copies of the Software, and to permit persons to whom the Software is
|
10 |
+
furnished to do so, subject to the following conditions:
|
11 |
+
|
12 |
+
The above copyright notice and this permission notice shall be included in all
|
13 |
+
copies or substantial portions of the Software.
|
14 |
+
|
15 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21 |
+
SOFTWARE.
|
scripts/yans/lm-evaluation-harness/README.md
ADDED
@@ -0,0 +1,497 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Language Model Evaluation Harness
|
2 |
+
|
3 |
+
[](https://doi.org/10.5281/zenodo.10256836)
|
4 |
+
|
5 |
+
---
|
6 |
+
|
7 |
+
*Latest News 📣*
|
8 |
+
|
9 |
+
- [2024/07] [API model](docs/API_guide.md) support has been updated and refactored, introducing support for batched and async requests, and making it significantly easier to customize and use for your own purposes. **To run Llama 405B, we recommend using VLLM's OpenAI-compliant API to host the model, and use the `local-completions` model type to evaluate the model.**
|
10 |
+
- [2024/07] New Open LLM Leaderboard tasks have been added ! You can find them under the [leaderboard](lm_eval/tasks/leaderboard/README.md) task group.
|
11 |
+
|
12 |
+
---
|
13 |
+
|
14 |
+
## Announcement
|
15 |
+
**A new v0.4.0 release of lm-evaluation-harness is available** !
|
16 |
+
|
17 |
+
New updates and features include:
|
18 |
+
|
19 |
+
- **New Open LLM Leaderboard tasks have been added ! You can find them under the [leaderboard](lm_eval/tasks/leaderboard/README.md) task group.**
|
20 |
+
- Internal refactoring
|
21 |
+
- Config-based task creation and configuration
|
22 |
+
- Easier import and sharing of externally-defined task config YAMLs
|
23 |
+
- Support for Jinja2 prompt design, easy modification of prompts + prompt imports from Promptsource
|
24 |
+
- More advanced configuration options, including output post-processing, answer extraction, and multiple LM generations per document, configurable fewshot settings, and more
|
25 |
+
- Speedups and new modeling libraries supported, including: faster data-parallel HF model usage, vLLM support, MPS support with HuggingFace, and more
|
26 |
+
- Logging and usability changes
|
27 |
+
- New tasks including CoT BIG-Bench-Hard, Belebele, user-defined task groupings, and more
|
28 |
+
|
29 |
+
Please see our updated documentation pages in `docs/` for more details.
|
30 |
+
|
31 |
+
Development will be continuing on the `main` branch, and we encourage you to give us feedback on what features are desired and how to improve the library further, or ask questions, either in issues or PRs on GitHub, or in the [EleutherAI discord](https://discord.gg/eleutherai)!
|
32 |
+
|
33 |
+
---
|
34 |
+
|
35 |
+
## Overview
|
36 |
+
|
37 |
+
This project provides a unified framework to test generative language models on a large number of different evaluation tasks.
|
38 |
+
|
39 |
+
**Features:**
|
40 |
+
- Over 60 standard academic benchmarks for LLMs, with hundreds of subtasks and variants implemented.
|
41 |
+
- Support for models loaded via [transformers](https://github.com/huggingface/transformers/) (including quantization via [AutoGPTQ](https://github.com/PanQiWei/AutoGPTQ)), [GPT-NeoX](https://github.com/EleutherAI/gpt-neox), and [Megatron-DeepSpeed](https://github.com/microsoft/Megatron-DeepSpeed/), with a flexible tokenization-agnostic interface.
|
42 |
+
- Support for fast and memory-efficient inference with [vLLM](https://github.com/vllm-project/vllm).
|
43 |
+
- Support for commercial APIs including [OpenAI](https://openai.com), and [TextSynth](https://textsynth.com/).
|
44 |
+
- Support for evaluation on adapters (e.g. LoRA) supported in [HuggingFace's PEFT library](https://github.com/huggingface/peft).
|
45 |
+
- Support for local models and benchmarks.
|
46 |
+
- Evaluation with publicly available prompts ensures reproducibility and comparability between papers.
|
47 |
+
- Easy support for custom prompts and evaluation metrics.
|
48 |
+
|
49 |
+
The Language Model Evaluation Harness is the backend for 🤗 Hugging Face's popular [Open LLM Leaderboard](https://huggingface.co/spaces/HuggingFaceH4/open_llm_leaderboard), has been used in [hundreds of papers](https://scholar.google.com/scholar?oi=bibs&hl=en&authuser=2&cites=15052937328817631261,4097184744846514103,1520777361382155671,17476825572045927382,18443729326628441434,14801318227356878622,7890865700763267262,12854182577605049984,15641002901115500560,5104500764547628290), and is used internally by dozens of organizations including NVIDIA, Cohere, BigScience, BigCode, Nous Research, and Mosaic ML.
|
50 |
+
|
51 |
+
## Install
|
52 |
+
|
53 |
+
To install the `lm-eval` package from the github repository, run:
|
54 |
+
|
55 |
+
```bash
|
56 |
+
git clone https://github.com/EleutherAI/lm-evaluation-harness
|
57 |
+
cd lm-evaluation-harness
|
58 |
+
pip install -e .
|
59 |
+
```
|
60 |
+
|
61 |
+
We also provide a number of optional dependencies for extended functionality. A detailed table is available at the end of this document.
|
62 |
+
|
63 |
+
## Basic Usage
|
64 |
+
### User Guide
|
65 |
+
|
66 |
+
A user guide detailing the full list of supported arguments is provided [here](./docs/interface.md), and on the terminal by calling `lm_eval -h`. Alternatively, you can use `lm-eval` instead of `lm_eval`.
|
67 |
+
|
68 |
+
A list of supported tasks (or groupings of tasks) can be viewed with `lm-eval --tasks list`. Task descriptions and links to corresponding subfolders are provided [here](./lm_eval/tasks/README.md).
|
69 |
+
|
70 |
+
### Hugging Face `transformers`
|
71 |
+
|
72 |
+
To evaluate a model hosted on the [HuggingFace Hub](https://huggingface.co/models) (e.g. GPT-J-6B) on `hellaswag` you can use the following command (this assumes you are using a CUDA-compatible GPU):
|
73 |
+
|
74 |
+
```bash
|
75 |
+
lm_eval --model hf \
|
76 |
+
--model_args pretrained=EleutherAI/gpt-j-6B \
|
77 |
+
--tasks hellaswag \
|
78 |
+
--device cuda:0 \
|
79 |
+
--batch_size 8
|
80 |
+
```
|
81 |
+
|
82 |
+
Additional arguments can be provided to the model constructor using the `--model_args` flag. Most notably, this supports the common practice of using the `revisions` feature on the Hub to store partially trained checkpoints, or to specify the datatype for running a model:
|
83 |
+
|
84 |
+
```bash
|
85 |
+
lm_eval --model hf \
|
86 |
+
--model_args pretrained=EleutherAI/pythia-160m,revision=step100000,dtype="float" \
|
87 |
+
--tasks lambada_openai,hellaswag \
|
88 |
+
--device cuda:0 \
|
89 |
+
--batch_size 8
|
90 |
+
```
|
91 |
+
|
92 |
+
Models that are loaded via both `transformers.AutoModelForCausalLM` (autoregressive, decoder-only GPT style models) and `transformers.AutoModelForSeq2SeqLM` (such as encoder-decoder models like T5) in Huggingface are supported.
|
93 |
+
|
94 |
+
Batch size selection can be automated by setting the ```--batch_size``` flag to ```auto```. This will perform automatic detection of the largest batch size that will fit on your device. On tasks where there is a large difference between the longest and shortest example, it can be helpful to periodically recompute the largest batch size, to gain a further speedup. To do this, append ```:N``` to above flag to automatically recompute the largest batch size ```N``` times. For example, to recompute the batch size 4 times, the command would be:
|
95 |
+
|
96 |
+
```bash
|
97 |
+
lm_eval --model hf \
|
98 |
+
--model_args pretrained=EleutherAI/pythia-160m,revision=step100000,dtype="float" \
|
99 |
+
--tasks lambada_openai,hellaswag \
|
100 |
+
--device cuda:0 \
|
101 |
+
--batch_size auto:4
|
102 |
+
```
|
103 |
+
|
104 |
+
> [!Note]
|
105 |
+
> Just like you can provide a local path to `transformers.AutoModel`, you can also provide a local path to `lm_eval` via `--model_args pretrained=/path/to/model`
|
106 |
+
|
107 |
+
#### Multi-GPU Evaluation with Hugging Face `accelerate`
|
108 |
+
|
109 |
+
We support three main ways of using Hugging Face's [accelerate 🚀](https://github.com/huggingface/accelerate) library for multi-GPU evaluation.
|
110 |
+
|
111 |
+
To perform *data-parallel evaluation* (where each GPU loads a **separate full copy** of the model), we leverage the `accelerate` launcher as follows:
|
112 |
+
|
113 |
+
```
|
114 |
+
accelerate launch -m lm_eval --model hf \
|
115 |
+
--tasks lambada_openai,arc_easy \
|
116 |
+
--batch_size 16
|
117 |
+
```
|
118 |
+
(or via `accelerate launch --no-python lm_eval`).
|
119 |
+
|
120 |
+
For cases where your model can fit on a single GPU, this allows you to evaluate on K GPUs K times faster than on one.
|
121 |
+
|
122 |
+
**WARNING**: This setup does not work with FSDP model sharding, so in `accelerate config` FSDP must be disabled, or the NO_SHARD FSDP option must be used.
|
123 |
+
|
124 |
+
The second way of using `accelerate` for multi-GPU evaluation is when your model is *too large to fit on a single GPU.*
|
125 |
+
|
126 |
+
In this setting, run the library *outside the `accelerate` launcher*, but passing `parallelize=True` to `--model_args` as follows:
|
127 |
+
|
128 |
+
```
|
129 |
+
lm_eval --model hf \
|
130 |
+
--tasks lambada_openai,arc_easy \
|
131 |
+
--model_args parallelize=True \
|
132 |
+
--batch_size 16
|
133 |
+
```
|
134 |
+
|
135 |
+
This means that your model's weights will be split across all available GPUs.
|
136 |
+
|
137 |
+
For more advanced users or even larger models, we allow for the following arguments when `parallelize=True` as well:
|
138 |
+
- `device_map_option`: How to split model weights across available GPUs. defaults to "auto".
|
139 |
+
- `max_memory_per_gpu`: the max GPU memory to use per GPU in loading the model.
|
140 |
+
- `max_cpu_memory`: the max amount of CPU memory to use when offloading the model weights to RAM.
|
141 |
+
- `offload_folder`: a folder where model weights will be offloaded to disk if needed.
|
142 |
+
|
143 |
+
The third option is to use both at the same time. This will allow you to take advantage of both data parallelism and model sharding, and is especially useful for models that are too large to fit on a single GPU.
|
144 |
+
|
145 |
+
```
|
146 |
+
accelerate launch --multi_gpu --num_processes {nb_of_copies_of_your_model} \
|
147 |
+
-m lm_eval --model hf \
|
148 |
+
--tasks lambada_openai,arc_easy \
|
149 |
+
--model_args parallelize=True \
|
150 |
+
--batch_size 16
|
151 |
+
```
|
152 |
+
|
153 |
+
To learn more about model parallelism and how to use it with the `accelerate` library, see the [accelerate documentation](https://huggingface.co/docs/transformers/v4.15.0/en/parallelism)
|
154 |
+
|
155 |
+
**Warning: We do not natively support multi-node evaluation using the `hf` model type! Please reference [our GPT-NeoX library integration](https://github.com/EleutherAI/gpt-neox/blob/main/eval.py) for an example of code in which a custom multi-machine evaluation script is written.**
|
156 |
+
|
157 |
+
**Note: we do not currently support multi-node evaluations natively, and advise using either an externally hosted server to run inference requests against, or creating a custom integration with your distributed framework [as is done for the GPT-NeoX library](https://github.com/EleutherAI/gpt-neox/blob/main/eval_tasks/eval_adapter.py).**
|
158 |
+
|
159 |
+
### NVIDIA `nemo` models
|
160 |
+
|
161 |
+
[NVIDIA NeMo Framework](https://github.com/NVIDIA/NeMo) is a generative AI framework built for researchers and pytorch developers working on language models.
|
162 |
+
|
163 |
+
To evaluate a `nemo` model, start by installing NeMo following [the documentation](https://github.com/NVIDIA/NeMo?tab=readme-ov-file#installation). We highly recommended to use the NVIDIA PyTorch or NeMo container, especially if having issues installing Apex or any other dependencies (see [latest released containers](https://github.com/NVIDIA/NeMo/releases)). Please also install the lm evaluation harness library following the instructions in [the Install section](https://github.com/EleutherAI/lm-evaluation-harness/tree/main?tab=readme-ov-file#install).
|
164 |
+
|
165 |
+
NeMo models can be obtained through [NVIDIA NGC Catalog](https://catalog.ngc.nvidia.com/models) or in [NVIDIA's Hugging Face page](https://huggingface.co/nvidia). In [NVIDIA NeMo Framework](https://github.com/NVIDIA/NeMo/tree/main/scripts/nlp_language_modeling) there are conversion scripts to convert the `hf` checkpoints of popular models like llama, falcon, mixtral or mpt to `nemo`.
|
166 |
+
|
167 |
+
Run a `nemo` model on one GPU:
|
168 |
+
```bash
|
169 |
+
lm_eval --model nemo_lm \
|
170 |
+
--model_args path=<path_to_nemo_model> \
|
171 |
+
--tasks hellaswag \
|
172 |
+
--batch_size 32
|
173 |
+
```
|
174 |
+
|
175 |
+
It is recommended to unpack the `nemo` model to avoid the unpacking inside the docker container - it may overflow disk space. For that you can run:
|
176 |
+
|
177 |
+
```
|
178 |
+
mkdir MY_MODEL
|
179 |
+
tar -xvf MY_MODEL.nemo -c MY_MODEL
|
180 |
+
```
|
181 |
+
|
182 |
+
#### Multi-GPU evaluation with NVIDIA `nemo` models
|
183 |
+
|
184 |
+
By default, only one GPU is used. But we do support either data replication or tensor/pipeline parallelism during evaluation, on one node.
|
185 |
+
|
186 |
+
1) To enable data replication, set the `model_args` of `devices` to the number of data replicas to run. For example, the command to run 8 data replicas over 8 GPUs is:
|
187 |
+
```bash
|
188 |
+
torchrun --nproc-per-node=8 --no-python lm_eval \
|
189 |
+
--model nemo_lm \
|
190 |
+
--model_args path=<path_to_nemo_model>,devices=8 \
|
191 |
+
--tasks hellaswag \
|
192 |
+
--batch_size 32
|
193 |
+
```
|
194 |
+
|
195 |
+
2) To enable tensor and/or pipeline parallelism, set the `model_args` of `tensor_model_parallel_size` and/or `pipeline_model_parallel_size`. In addition, you also have to set up `devices` to be equal to the product of `tensor_model_parallel_size` and/or `pipeline_model_parallel_size`. For example, the command to use one node of 4 GPUs with tensor parallelism of 2 and pipeline parallelism of 2 is:
|
196 |
+
```bash
|
197 |
+
torchrun --nproc-per-node=4 --no-python lm_eval \
|
198 |
+
--model nemo_lm \
|
199 |
+
--model_args path=<path_to_nemo_model>,devices=4,tensor_model_parallel_size=2,pipeline_model_parallel_size=2 \
|
200 |
+
--tasks hellaswag \
|
201 |
+
--batch_size 32
|
202 |
+
```
|
203 |
+
Note that it is recommended to substitute the `python` command by `torchrun --nproc-per-node=<number of devices> --no-python` to facilitate loading the model into the GPUs. This is especially important for large checkpoints loaded into multiple GPUs.
|
204 |
+
|
205 |
+
Not supported yet: multi-node evaluation and combinations of data replication with tensor or pipeline parallelism.
|
206 |
+
|
207 |
+
### Tensor + Data Parallel and Optimized Inference with `vLLM`
|
208 |
+
|
209 |
+
We also support vLLM for faster inference on [supported model types](https://docs.vllm.ai/en/latest/models/supported_models.html), especially faster when splitting a model across multiple GPUs. For single-GPU or multi-GPU — tensor parallel, data parallel, or a combination of both — inference, for example:
|
210 |
+
|
211 |
+
```bash
|
212 |
+
lm_eval --model vllm \
|
213 |
+
--model_args pretrained={model_name},tensor_parallel_size={GPUs_per_model},dtype=auto,gpu_memory_utilization=0.8,data_parallel_size={model_replicas} \
|
214 |
+
--tasks lambada_openai \
|
215 |
+
--batch_size auto
|
216 |
+
```
|
217 |
+
To use vllm, do `pip install lm_eval[vllm]`. For a full list of supported vLLM configurations, please reference our [vLLM integration](https://github.com/EleutherAI/lm-evaluation-harness/blob/e74ec966556253fbe3d8ecba9de675c77c075bce/lm_eval/models/vllm_causallms.py) and the vLLM documentation.
|
218 |
+
|
219 |
+
vLLM occasionally differs in output from Huggingface. We treat Huggingface as the reference implementation, and provide a [script](./scripts/model_comparator.py) for checking the validity of vllm results against HF.
|
220 |
+
|
221 |
+
> [!Tip]
|
222 |
+
> For fastest performance, we recommend using `--batch_size auto` for vLLM whenever possible, to leverage its continuous batching functionality!
|
223 |
+
|
224 |
+
> [!Tip]
|
225 |
+
> Passing `max_model_len=4096` or some other reasonable default to vLLM through model args may cause speedups or prevent out-of-memory errors when trying to use auto batch size, such as for Mistral-7B-v0.1 which defaults to a maximum length of 32k.
|
226 |
+
|
227 |
+
### Model APIs and Inference Servers
|
228 |
+
|
229 |
+
Our library also supports the evaluation of models served via several commercial APIs, and we hope to implement support for the most commonly used performant local/self-hosted inference servers.
|
230 |
+
|
231 |
+
To call a hosted model, use:
|
232 |
+
|
233 |
+
```bash
|
234 |
+
export OPENAI_API_KEY=YOUR_KEY_HERE
|
235 |
+
lm_eval --model openai-completions \
|
236 |
+
--model_args model=davinci \
|
237 |
+
--tasks lambada_openai,hellaswag
|
238 |
+
```
|
239 |
+
|
240 |
+
We also support using your own local inference server with servers that mirror the OpenAI Completions and ChatCompletions APIs.
|
241 |
+
|
242 |
+
```bash
|
243 |
+
lm_eval --model local-completions --tasks gsm8k --model_args model=facebook/opt-125m,base_url=http://{yourip}:8000/v1/completions,num_concurrent=1,max_retries=3,tokenized_requests=False,batch_size=16
|
244 |
+
```
|
245 |
+
Note that for externally hosted models, configs such as `--device` which relate to where to place a local model should not be used and do not function. Just like you can use `--model_args` to pass arbitrary arguments to the model constructor for local models, you can use it to pass arbitrary arguments to the model API for hosted models. See the documentation of the hosting service for information on what arguments they support.
|
246 |
+
|
247 |
+
| API or Inference Server | Implemented? | `--model <xxx>` name | Models supported: | Request Types: |
|
248 |
+
|---------------------------------------------------------------------------------------------------------------------------|---------------------------------|-----------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------|
|
249 |
+
| OpenAI Completions | :heavy_check_mark: | `openai-completions`, `local-completions` | All OpenAI Completions API models | `generate_until`, `loglikelihood`, `loglikelihood_rolling` |
|
250 |
+
| OpenAI ChatCompletions | :heavy_check_mark: | `openai-chat-completions`, `local-chat-completions` | [All ChatCompletions API models](https://platform.openai.com/docs/guides/gpt) | `generate_until` (no logprobs) |
|
251 |
+
| Anthropic | :heavy_check_mark: | `anthropic` | [Supported Anthropic Engines](https://docs.anthropic.com/claude/reference/selecting-a-model) | `generate_until` (no logprobs) |
|
252 |
+
| Anthropic Chat | :heavy_check_mark: | `anthropic-chat`, `anthropic-chat-completions` | [Supported Anthropic Engines](https://docs.anthropic.com/claude/docs/models-overview) | `generate_until` (no logprobs) |
|
253 |
+
| Textsynth | :heavy_check_mark: | `textsynth` | [All supported engines](https://textsynth.com/documentation.html#engines) | `generate_until`, `loglikelihood`, `loglikelihood_rolling` |
|
254 |
+
| Cohere | [:hourglass: - blocked on Cohere API bug](https://github.com/EleutherAI/lm-evaluation-harness/pull/395) | N/A | [All `cohere.generate()` engines](https://docs.cohere.com/docs/models) | `generate_until`, `loglikelihood`, `loglikelihood_rolling` |
|
255 |
+
| [Llama.cpp](https://github.com/ggerganov/llama.cpp) (via [llama-cpp-python](https://github.com/abetlen/llama-cpp-python)) | :heavy_check_mark: | `gguf`, `ggml` | [All models supported by llama.cpp](https://github.com/ggerganov/llama.cpp) | `generate_until`, `loglikelihood`, (perplexity evaluation not yet implemented) |
|
256 |
+
| vLLM | :heavy_check_mark: | `vllm` | [Most HF Causal Language Models](https://docs.vllm.ai/en/latest/models/supported_models.html) | `generate_until`, `loglikelihood`, `loglikelihood_rolling` |
|
257 |
+
| Mamba | :heavy_check_mark: | `mamba_ssm` | [Mamba architecture Language Models via the `mamba_ssm` package](https://huggingface.co/state-spaces) | `generate_until`, `loglikelihood`, `loglikelihood_rolling` |
|
258 |
+
| Huggingface Optimum (Causal LMs) | ✔️ | `openvino` | Any decoder-only AutoModelForCausalLM converted with Huggingface Optimum into OpenVINO™ Intermediate Representation (IR) format | `generate_until`, `loglikelihood`, `loglikelihood_rolling` | ... |
|
259 |
+
| Neuron via AWS Inf2 (Causal LMs) | ✔️ | `neuronx` | Any decoder-only AutoModelForCausalLM supported to run on [huggingface-ami image for inferentia2](https://aws.amazon.com/marketplace/pp/prodview-gr3e6yiscria2) | `generate_until`, `loglikelihood`, `loglikelihood_rolling` | ... |
|
260 |
+
| [Neural Magic DeepSparse](https://github.com/neuralmagic/deepsparse) | ✔️ | `deepsparse` | Any LM from [SparseZoo](https://sparsezoo.neuralmagic.com/) or on [HF Hub with the "deepsparse" tag](https://huggingface.co/models?other=deepsparse) | `generate_until`, `loglikelihood` | ... |
|
261 |
+
| [Neural Magic SparseML](https://github.com/neuralmagic/sparseml) | ✔️ | `sparseml` | Any decoder-only AutoModelForCausalLM from [SparseZoo](https://sparsezoo.neuralmagic.com/) or on [HF Hub](https://huggingface.co/neuralmagic). Especially useful for models with quantization like [`zoo:llama2-7b-gsm8k_llama2_pretrain-pruned60_quantized`](https://sparsezoo.neuralmagic.com/models/llama2-7b-gsm8k_llama2_pretrain-pruned60_quantized) | `generate_until`, `loglikelihood`, `loglikelihood_rolling` | ... |
|
262 |
+
| Your local inference server! | :heavy_check_mark: | `local-completions` or `local-chat-completions` | Support for OpenAI API-compatible servers, with easy customization for other APIs. | `generate_until`, `loglikelihood`, `loglikelihood_rolling` | | ... |
|
263 |
+
|
264 |
+
Models which do not supply logits or logprobs can be used with tasks of type `generate_until` only, while local models, or APIs that supply logprobs/logits of their prompts, can be run on all task types: `generate_until`, `loglikelihood`, `loglikelihood_rolling`, and `multiple_choice`.
|
265 |
+
|
266 |
+
For more information on the different task `output_types` and model request types, see [our documentation](https://github.com/EleutherAI/lm-evaluation-harness/blob/main/docs/model_guide.md#interface).
|
267 |
+
|
268 |
+
> [!Note]
|
269 |
+
> For best performance with closed chat model APIs such as Anthropic Claude 3 and GPT-4, we recommend carefully looking at a few sample outputs using `--limit 10` first to confirm answer extraction and scoring on generative tasks is performing as expected. providing `system="<some system prompt here>"` within `--model_args` for anthropic-chat-completions, to instruct the model what format to respond in, may be useful.
|
270 |
+
|
271 |
+
|
272 |
+
### Other Frameworks
|
273 |
+
|
274 |
+
A number of other libraries contain scripts for calling the eval harness through their library. These include [GPT-NeoX](https://github.com/EleutherAI/gpt-neox/blob/main/eval_tasks/eval_adapter.py), [Megatron-DeepSpeed](https://github.com/microsoft/Megatron-DeepSpeed/blob/main/examples/MoE/readme_evalharness.md), and [mesh-transformer-jax](https://github.com/kingoflolz/mesh-transformer-jax/blob/master/eval_harness.py).
|
275 |
+
|
276 |
+
To create your own custom integration you can follow instructions from [this tutorial](https://github.com/EleutherAI/lm-evaluation-harness/blob/main/docs/interface.md#external-library-usage).
|
277 |
+
|
278 |
+
### Additional Features
|
279 |
+
> [!Note]
|
280 |
+
> For tasks unsuitable for direct evaluation — either due risks associated with executing untrusted code or complexities in the evaluation process — the `--predict_only` flag is available to obtain decoded generations for post-hoc evaluation.
|
281 |
+
|
282 |
+
If you have a Metal compatible Mac, you can run the eval harness using the MPS back-end by replacing `--device cuda:0` with `--device mps` (requires PyTorch version 2.1 or higher). **Note that the PyTorch MPS backend is still in early stages of development, so correctness issues or unsupported operations may exist. If you observe oddities in model performance on the MPS back-end, we recommend first checking that a forward pass of your model on `--device cpu` and `--device mps` match.**
|
283 |
+
|
284 |
+
> [!Note]
|
285 |
+
> You can inspect what the LM inputs look like by running the following command:
|
286 |
+
> ```bash
|
287 |
+
> python write_out.py \
|
288 |
+
> --tasks <task1,task2,...> \
|
289 |
+
> --num_fewshot 5 \
|
290 |
+
> --num_examples 10 \
|
291 |
+
> --output_base_path /path/to/output/folder
|
292 |
+
> ```
|
293 |
+
> This will write out one text file for each task.
|
294 |
+
|
295 |
+
To verify the data integrity of the tasks you're performing in addition to running the tasks themselves, you can use the `--check_integrity` flag:
|
296 |
+
|
297 |
+
```bash
|
298 |
+
lm_eval --model openai \
|
299 |
+
--model_args engine=davinci \
|
300 |
+
--tasks lambada_openai,hellaswag \
|
301 |
+
--check_integrity
|
302 |
+
```
|
303 |
+
|
304 |
+
## Advanced Usage Tips
|
305 |
+
|
306 |
+
For models loaded with the HuggingFace `transformers` library, any arguments provided via `--model_args` get passed to the relevant constructor directly. This means that anything you can do with `AutoModel` can be done with our library. For example, you can pass a local path via `pretrained=` or use models finetuned with [PEFT](https://github.com/huggingface/peft) by taking the call you would run to evaluate the base model and add `,peft=PATH` to the `model_args` argument:
|
307 |
+
```bash
|
308 |
+
lm_eval --model hf \
|
309 |
+
--model_args pretrained=EleutherAI/gpt-j-6b,parallelize=True,load_in_4bit=True,peft=nomic-ai/gpt4all-j-lora \
|
310 |
+
--tasks openbookqa,arc_easy,winogrande,hellaswag,arc_challenge,piqa,boolq \
|
311 |
+
--device cuda:0
|
312 |
+
```
|
313 |
+
|
314 |
+
Models provided as delta weights can be easily loaded using the Hugging Face transformers library. Within --model_args, set the delta argument to specify the delta weights, and use the pretrained argument to designate the relative base model to which they will be applied:
|
315 |
+
```bash
|
316 |
+
lm_eval --model hf \
|
317 |
+
--model_args pretrained=Ejafa/llama_7B,delta=lmsys/vicuna-7b-delta-v1.1 \
|
318 |
+
--tasks hellaswag
|
319 |
+
```
|
320 |
+
|
321 |
+
[GPTQ](https://github.com/PanQiWei/AutoGPTQ) quantized models can be loaded by specifying their file names in `,autogptq=NAME` (or `,autogptq=True` for default names) in the `model_args` argument:
|
322 |
+
|
323 |
+
```bash
|
324 |
+
lm_eval --model hf \
|
325 |
+
--model_args pretrained=model-name-or-path,autogptq=model.safetensors,gptq_use_triton=True \
|
326 |
+
--tasks hellaswag
|
327 |
+
```
|
328 |
+
|
329 |
+
We support wildcards in task names, for example you can run all of the machine-translated lambada tasks via `--task lambada_openai_mt_*`.
|
330 |
+
|
331 |
+
## Saving Results
|
332 |
+
|
333 |
+
To save evaluation results provide an `--output_path`. We also support logging model responses with the `--log_samples` flag for post-hoc analysis.
|
334 |
+
|
335 |
+
Additionally, one can provide a directory with `--use_cache` to cache the results of prior runs. This allows you to avoid repeated execution of the same (model, task) pairs for re-scoring.
|
336 |
+
|
337 |
+
To push results and samples to the Hugging Face Hub, first ensure an access token with write access is set in the `HF_TOKEN` environment variable. Then, use the `--hf_hub_log_args` flag to specify the organization, repository name, repository visibility, and whether to push results and samples to the Hub - [example dataset on the HF Hub](https://huggingface.co/datasets/KonradSzafer/lm-eval-results-demo). For instance:
|
338 |
+
|
339 |
+
```bash
|
340 |
+
lm_eval --model hf \
|
341 |
+
--model_args pretrained=model-name-or-path,autogptq=model.safetensors,gptq_use_triton=True \
|
342 |
+
--tasks hellaswag \
|
343 |
+
--log_samples \
|
344 |
+
--output_path results \
|
345 |
+
--hf_hub_log_args hub_results_org=EleutherAI,hub_repo_name=lm-eval-results,push_results_to_hub=True,push_samples_to_hub=True,public_repo=False \
|
346 |
+
```
|
347 |
+
|
348 |
+
This allows you to easily download the results and samples from the Hub, using:
|
349 |
+
```python
|
350 |
+
from datasets import load_dataset
|
351 |
+
|
352 |
+
load_dataset("EleutherAI/lm-eval-results-private", "hellaswag", "latest")
|
353 |
+
```
|
354 |
+
|
355 |
+
For a full list of supported arguments, check out the [interface](https://github.com/EleutherAI/lm-evaluation-harness/blob/main/docs/interface.md) guide in our documentation!
|
356 |
+
|
357 |
+
## Visualizing Results
|
358 |
+
|
359 |
+
You can seamlessly visualize and analyze the results of your evaluation harness runs using both Weights & Biases (W&B) and Zeno.
|
360 |
+
|
361 |
+
### Zeno
|
362 |
+
|
363 |
+
You can use [Zeno](https://zenoml.com) to visualize the results of your eval harness runs.
|
364 |
+
|
365 |
+
First, head to [hub.zenoml.com](https://hub.zenoml.com) to create an account and get an API key [on your account page](https://hub.zenoml.com/account).
|
366 |
+
Add this key as an environment variable:
|
367 |
+
|
368 |
+
```bash
|
369 |
+
export ZENO_API_KEY=[your api key]
|
370 |
+
```
|
371 |
+
|
372 |
+
You'll also need to install the `lm_eval[zeno]` package extra.
|
373 |
+
|
374 |
+
To visualize the results, run the eval harness with the `log_samples` and `output_path` flags.
|
375 |
+
We expect `output_path` to contain multiple folders that represent individual model names.
|
376 |
+
You can thus run your evaluation on any number of tasks and models and upload all of the results as projects on Zeno.
|
377 |
+
|
378 |
+
```bash
|
379 |
+
lm_eval \
|
380 |
+
--model hf \
|
381 |
+
--model_args pretrained=EleutherAI/gpt-j-6B \
|
382 |
+
--tasks hellaswag \
|
383 |
+
--device cuda:0 \
|
384 |
+
--batch_size 8 \
|
385 |
+
--log_samples \
|
386 |
+
--output_path output/gpt-j-6B
|
387 |
+
```
|
388 |
+
|
389 |
+
Then, you can upload the resulting data using the `zeno_visualize` script:
|
390 |
+
|
391 |
+
```bash
|
392 |
+
python scripts/zeno_visualize.py \
|
393 |
+
--data_path output \
|
394 |
+
--project_name "Eleuther Project"
|
395 |
+
```
|
396 |
+
|
397 |
+
This will use all subfolders in `data_path` as different models and upload all tasks within these model folders to Zeno.
|
398 |
+
If you run the eval harness on multiple tasks, the `project_name` will be used as a prefix and one project will be created per task.
|
399 |
+
|
400 |
+
You can find an example of this workflow in [examples/visualize-zeno.ipynb](examples/visualize-zeno.ipynb).
|
401 |
+
|
402 |
+
### Weights and Biases
|
403 |
+
|
404 |
+
With the [Weights and Biases](https://wandb.ai/site) integration, you can now spend more time extracting deeper insights into your evaluation results. The integration is designed to streamline the process of logging and visualizing experiment results using the Weights & Biases (W&B) platform.
|
405 |
+
|
406 |
+
The integration provide functionalities
|
407 |
+
|
408 |
+
- to automatically log the evaluation results,
|
409 |
+
- log the samples as W&B Tables for easy visualization,
|
410 |
+
- log the `results.json` file as an artifact for version control,
|
411 |
+
- log the `<task_name>_eval_samples.json` file if the samples are logged,
|
412 |
+
- generate a comprehensive report for analysis and visualization with all the important metric,
|
413 |
+
- log task and cli specific configs,
|
414 |
+
- and more out of the box like the command used to run the evaluation, GPU/CPU counts, timestamp, etc.
|
415 |
+
|
416 |
+
First you'll need to install the lm_eval[wandb] package extra. Do `pip install lm_eval[wandb]`.
|
417 |
+
|
418 |
+
Authenticate your machine with an your unique W&B token. Visit https://wandb.ai/authorize to get one. Do `wandb login` in your command line terminal.
|
419 |
+
|
420 |
+
Run eval harness as usual with a `wandb_args` flag. Use this flag to provide arguments for initializing a wandb run ([wandb.init](https://docs.wandb.ai/ref/python/init)) as comma separated string arguments.
|
421 |
+
|
422 |
+
```bash
|
423 |
+
lm_eval \
|
424 |
+
--model hf \
|
425 |
+
--model_args pretrained=microsoft/phi-2,trust_remote_code=True \
|
426 |
+
--tasks hellaswag,mmlu_abstract_algebra \
|
427 |
+
--device cuda:0 \
|
428 |
+
--batch_size 8 \
|
429 |
+
--output_path output/phi-2 \
|
430 |
+
--limit 10 \
|
431 |
+
--wandb_args project=lm-eval-harness-integration \
|
432 |
+
--log_samples
|
433 |
+
```
|
434 |
+
|
435 |
+
In the stdout, you will find the link to the W&B run page as well as link to the generated report. You can find an example of this workflow in [examples/visualize-wandb.ipynb](examples/visualize-wandb.ipynb), and an example of how to integrate it beyond the CLI.
|
436 |
+
|
437 |
+
## How to Contribute or Learn More?
|
438 |
+
|
439 |
+
For more information on the library and how everything fits together, check out all of our [documentation pages](https://github.com/EleutherAI/lm-evaluation-harness/tree/main/docs)! We plan to post a larger roadmap of desired + planned library improvements soon, with more information on how contributors can help.
|
440 |
+
|
441 |
+
### Implementing new tasks
|
442 |
+
|
443 |
+
To implement a new task in the eval harness, see [this guide](./docs/new_task_guide.md).
|
444 |
+
|
445 |
+
In general, we follow this priority list for addressing concerns about prompting and other eval details:
|
446 |
+
1. If there is widespread agreement among people who train LLMs, use the agreed upon procedure.
|
447 |
+
2. If there is a clear and unambiguous official implementation, use that procedure.
|
448 |
+
3. If there is widespread agreement among people who evaluate LLMs, use the agreed upon procedure.
|
449 |
+
4. If there are multiple common implementations but not universal or widespread agreement, use our preferred option among the common implementations. As before, prioritize choosing from among the implementations found in LLM training papers.
|
450 |
+
|
451 |
+
These are guidelines and not rules, and can be overruled in special circumstances.
|
452 |
+
|
453 |
+
We try to prioritize agreement with the procedures used by other groups to decrease the harm when people inevitably compare runs across different papers despite our discouragement of the practice. Historically, we also prioritized the implementation from [Language Models are Few Shot Learners](https://arxiv.org/abs/2005.14165) as our original goal was specifically to compare results with that paper.
|
454 |
+
|
455 |
+
### Support
|
456 |
+
|
457 |
+
The best way to get support is to open an issue on this repo or join the [EleutherAI Discord server](https://discord.gg/eleutherai). The `#lm-thunderdome` channel is dedicated to developing this project and the `#release-discussion` channel is for receiving support for our releases. If you've used the library and have had a positive (or negative) experience, we'd love to hear from you!
|
458 |
+
|
459 |
+
## Optional Extras
|
460 |
+
Extras dependencies can be installed via `pip install -e ".[NAME]"`
|
461 |
+
|
462 |
+
| Name | Use |
|
463 |
+
|-----------------|----------------------------------------------|
|
464 |
+
| api | For using api models (Anthropic, OpenAI API) |
|
465 |
+
| deepsparse | For running NM's DeepSparse models |
|
466 |
+
| dev | For linting PRs and contributions |
|
467 |
+
| gptq | For loading models with GPTQ |
|
468 |
+
| hf_transfer | For speeding up HF Hub file downloads |
|
469 |
+
| ifeval | For running the IFEval task |
|
470 |
+
| neuronx | For running on AWS inf2 instances |
|
471 |
+
| mamba | For loading Mamba SSM models |
|
472 |
+
| math | For running math task answer checking |
|
473 |
+
| multilingual | For multilingual tokenizers |
|
474 |
+
| optimum | For running Intel OpenVINO models |
|
475 |
+
| promptsource | For using PromptSource prompts |
|
476 |
+
| sentencepiece | For using the sentencepiece tokenizer |
|
477 |
+
| sparseml | For using NM's SparseML models |
|
478 |
+
| testing | For running library test suite |
|
479 |
+
| vllm | For loading models with vLLM |
|
480 |
+
| zeno | For visualizing results with Zeno |
|
481 |
+
| --------------- | --------------------------------------- |
|
482 |
+
| all | Loads all extras (not recommended) |
|
483 |
+
|
484 |
+
## Cite as
|
485 |
+
|
486 |
+
```
|
487 |
+
@misc{eval-harness,
|
488 |
+
author = {Gao, Leo and Tow, Jonathan and Abbasi, Baber and Biderman, Stella and Black, Sid and DiPofi, Anthony and Foster, Charles and Golding, Laurence and Hsu, Jeffrey and Le Noac'h, Alain and Li, Haonan and McDonell, Kyle and Muennighoff, Niklas and Ociepa, Chris and Phang, Jason and Reynolds, Laria and Schoelkopf, Hailey and Skowron, Aviya and Sutawika, Lintang and Tang, Eric and Thite, Anish and Wang, Ben and Wang, Kevin and Zou, Andy},
|
489 |
+
title = {A framework for few-shot language model evaluation},
|
490 |
+
month = 12,
|
491 |
+
year = 2023,
|
492 |
+
publisher = {Zenodo},
|
493 |
+
version = {v0.4.0},
|
494 |
+
doi = {10.5281/zenodo.10256836},
|
495 |
+
url = {https://zenodo.org/records/10256836}
|
496 |
+
}
|
497 |
+
```
|
scripts/yans/lm-evaluation-harness/bin/python
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:45692c3da2492563eabf0a8f5dc18d20dc9c34ffe3a18202563e00bae684be91
|
3 |
+
size 5904904
|
scripts/yans/lm-evaluation-harness/bin/python3
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:45692c3da2492563eabf0a8f5dc18d20dc9c34ffe3a18202563e00bae684be91
|
3 |
+
size 5904904
|
scripts/yans/lm-evaluation-harness/bin/python3.10
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:45692c3da2492563eabf0a8f5dc18d20dc9c34ffe3a18202563e00bae684be91
|
3 |
+
size 5904904
|
scripts/yans/lm-evaluation-harness/docs/API_guide.md
ADDED
@@ -0,0 +1,198 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# TemplateAPI Usage Guide
|
2 |
+
|
3 |
+
The `TemplateAPI` class is a versatile superclass designed to facilitate the integration of various API-based language models into the lm-evaluation-harness framework. This guide will explain how to use and extend the `TemplateAPI` class to implement your own API models. If your API implements the OpenAI API you can use the `local-completions` or the `local-chat-completions` (defined [here](https://github.com/EleutherAI/lm-evaluation-harness/blob/main/lm_eval/models/openai_completions.py)) model types, which can also serve as examples of how to effectively subclass this template.
|
4 |
+
|
5 |
+
## Overview
|
6 |
+
|
7 |
+
The `TemplateAPI` class provides a template for creating API-based model implementations. It handles common functionalities such as:
|
8 |
+
|
9 |
+
- Tokenization (optional)
|
10 |
+
- Batch processing
|
11 |
+
- Caching
|
12 |
+
- Retrying failed requests
|
13 |
+
- Parsing API responses
|
14 |
+
|
15 |
+
To use this class, you typically need to subclass it and implement specific methods for your API.
|
16 |
+
|
17 |
+
## Key Methods to Implement
|
18 |
+
|
19 |
+
When subclassing `TemplateAPI`, you need to implement the following methods:
|
20 |
+
|
21 |
+
1. `_create_payload`: Creates the JSON payload for API requests.
|
22 |
+
2. `parse_logprobs`: Parses log probabilities from API responses.
|
23 |
+
3. `parse_generations`: Parses generated text from API responses.
|
24 |
+
4. `headers`: Returns the headers for the API request.
|
25 |
+
|
26 |
+
You may also need to override other methods or properties depending on your API's specific requirements.
|
27 |
+
|
28 |
+
> [!NOTE]
|
29 |
+
> Currently loglikelihood and MCQ based tasks (such as MMLU) are only supported for completion endpoints. Not for chat-completion — those that expect a list of dicts — endpoints! Completion APIs which support instruct tuned models can be evaluated with the `--apply_chat_template` option in order to simultaneously evaluate models using a chat template format while still being able to access the model logits needed for loglikelihood-based tasks.
|
30 |
+
|
31 |
+
# TemplateAPI Usage Guide
|
32 |
+
|
33 |
+
## TemplateAPI Arguments
|
34 |
+
|
35 |
+
When initializing a `TemplateAPI` instance or a subclass, you can provide several arguments to customize its behavior. Here's a detailed explanation of some important arguments:
|
36 |
+
|
37 |
+
- `model` or `pretrained` (str):
|
38 |
+
- The name or identifier of the model to use.
|
39 |
+
- `model` takes precedence over `pretrained` when both are provided.
|
40 |
+
|
41 |
+
- `base_url` (str):
|
42 |
+
- The base URL for the API endpoint.
|
43 |
+
|
44 |
+
- `tokenizer` (str, optional):
|
45 |
+
- The name or path of the tokenizer to use.
|
46 |
+
- If not provided, it defaults to using the same tokenizer name as the model.
|
47 |
+
|
48 |
+
- `num_concurrent` (int):
|
49 |
+
- Number of concurrent requests to make to the API.
|
50 |
+
- Useful for APIs that support parallel processing.
|
51 |
+
- Default is 1 (sequential processing).
|
52 |
+
|
53 |
+
- `tokenized_requests` (bool):
|
54 |
+
- Determines whether the input is pre-tokenized. Defaults to `True`.
|
55 |
+
- Requests can be sent in either tokenized form (`list[list[int]]`) or as text (`list[str]`, or `str` for batch_size=1).
|
56 |
+
- For loglikelihood-based tasks, prompts require tokenization to calculate the context length. If `False` prompts are decoded back to text before being sent to the API.
|
57 |
+
- Not as important for `generate_until` tasks.
|
58 |
+
- Ignored for chat formatted inputs (list[dict...]) or if tokenizer_backend is None.
|
59 |
+
|
60 |
+
- `tokenizer_backend` (str, optional):
|
61 |
+
- Required for loglikelihood-based or MCQ tasks.
|
62 |
+
- Specifies the tokenizer library to use. Options are "tiktoken", "huggingface", or None.
|
63 |
+
- Default is "huggingface".
|
64 |
+
|
65 |
+
- `max_length` (int, optional):
|
66 |
+
- Maximum length of input + output.
|
67 |
+
- Default is 2048.
|
68 |
+
|
69 |
+
- `max_retries` (int, optional):
|
70 |
+
- Maximum number of retries for failed API requests.
|
71 |
+
- Default is 3.
|
72 |
+
|
73 |
+
- `max_gen_toks` (int, optional):
|
74 |
+
- Maximum number of tokens to generate in completion tasks.
|
75 |
+
- Default is 256 or set in task yaml.
|
76 |
+
|
77 |
+
- `batch_size` (int or str, optional):
|
78 |
+
- Number of requests to batch together (if the API supports batching).
|
79 |
+
- Can be an integer or "auto" (which defaults to 1 for API models).
|
80 |
+
- Default is 1.
|
81 |
+
|
82 |
+
- `seed` (int, optional):
|
83 |
+
- Random seed for reproducibility.
|
84 |
+
- Default is 1234.
|
85 |
+
|
86 |
+
- `add_bos_token` (bool, optional):
|
87 |
+
- Whether to add the beginning-of-sequence token to inputs (when tokenizing).
|
88 |
+
- Default is False.
|
89 |
+
|
90 |
+
- `custom_prefix_token_id` (int, optional):
|
91 |
+
- Custom token ID to use as a prefix for inputs.
|
92 |
+
- If not provided, uses the model's default BOS or EOS token (if `add_bos_token` is True).
|
93 |
+
|
94 |
+
|
95 |
+
Example usage:
|
96 |
+
|
97 |
+
```python
|
98 |
+
class MyAPIModel(TemplateAPI):
|
99 |
+
def __init__(self, **kwargs):
|
100 |
+
super().__init__(
|
101 |
+
model="my-model",
|
102 |
+
base_url="https://api.mymodel.com/v1/completions",
|
103 |
+
tokenizer_backend="huggingface",
|
104 |
+
num_concurrent=5,
|
105 |
+
max_retries=5,
|
106 |
+
batch_size=10,
|
107 |
+
**kwargs
|
108 |
+
)
|
109 |
+
|
110 |
+
# Implement other required methods...
|
111 |
+
```
|
112 |
+
|
113 |
+
When subclassing `TemplateAPI`, you can override these arguments in your `__init__` method to set default values specific to your API. You can also add additional (potentially user-specified) arguments as needed for your specific implementation.
|
114 |
+
|
115 |
+
## Example Implementation: OpenAI API
|
116 |
+
|
117 |
+
The `OpenAICompletionsAPI` and `OpenAIChatCompletion` ([here](https://github.com/EleutherAI/lm-evaluation-harness/blob/main/lm_eval/models/openai_completions.py) classes demonstrate how to implement API models using the `TemplateAPI` class. Here's a breakdown of the key components:
|
118 |
+
|
119 |
+
### 1. Subclassing and Initialization
|
120 |
+
|
121 |
+
```python
|
122 |
+
@register_model("openai-completions")
|
123 |
+
class OpenAICompletionsAPI(LocalCompletionsAPI):
|
124 |
+
def __init__(
|
125 |
+
self,
|
126 |
+
base_url="https://api.openai.com/v1/completions",
|
127 |
+
tokenizer_backend="tiktoken",
|
128 |
+
**kwargs,
|
129 |
+
):
|
130 |
+
super().__init__(
|
131 |
+
base_url=base_url, tokenizer_backend=tokenizer_backend, **kwargs
|
132 |
+
)
|
133 |
+
```
|
134 |
+
|
135 |
+
### 2. Implementing API Key Retrieval
|
136 |
+
|
137 |
+
```python
|
138 |
+
@cached_property
|
139 |
+
def api_key(self):
|
140 |
+
key = os.environ.get("OPENAI_API_KEY", None)
|
141 |
+
if key is None:
|
142 |
+
raise ValueError(
|
143 |
+
"API key not found. Please set the OPENAI_API_KEY environment variable."
|
144 |
+
)
|
145 |
+
return key
|
146 |
+
```
|
147 |
+
|
148 |
+
### 3. Creating the Payload
|
149 |
+
|
150 |
+
```python
|
151 |
+
def _create_payload(
|
152 |
+
self,
|
153 |
+
messages: Union[List[List[int]], List[dict], List[str], str],
|
154 |
+
generate=False,
|
155 |
+
gen_kwargs: Optional[dict] = None,
|
156 |
+
**kwargs,
|
157 |
+
) -> dict:
|
158 |
+
if generate:
|
159 |
+
# ... (implementation for generation)
|
160 |
+
else:
|
161 |
+
# ... (implementation for log likelihood)
|
162 |
+
```
|
163 |
+
|
164 |
+
### 4. Parsing API Responses
|
165 |
+
|
166 |
+
```python
|
167 |
+
@staticmethod
|
168 |
+
def parse_logprobs(
|
169 |
+
outputs: Union[Dict, List[Dict]],
|
170 |
+
tokens: List[List[int]] = None,
|
171 |
+
ctxlens: List[int] = None,
|
172 |
+
**kwargs,
|
173 |
+
) -> List[Tuple[float, bool]]:
|
174 |
+
# ... (implementation)
|
175 |
+
|
176 |
+
@staticmethod
|
177 |
+
def parse_generations(outputs: Union[Dict, List[Dict]], **kwargs) -> List[str]:
|
178 |
+
# ... (implementation)
|
179 |
+
```
|
180 |
+
|
181 |
+
The requests are initiated in the `model_call` or the `amodel_call` methods.
|
182 |
+
|
183 |
+
## Implementing Your Own API Model
|
184 |
+
|
185 |
+
To implement your own API model:
|
186 |
+
|
187 |
+
1. Subclass `TemplateAPI` or one of its subclasses (e.g., `LocalCompletionsAPI`).
|
188 |
+
2. Override the `__init__` method if you need to set specific parameters.
|
189 |
+
3. Implement the `_create_payload` and `header` methods to create the appropriate payload for your API.
|
190 |
+
4. Implement the `parse_logprobs` and `parse_generations` methods to parse your API's responses.
|
191 |
+
5. Override the `api_key` property if your API requires authentication.
|
192 |
+
6. Override any other methods as necessary to match your API's behavior.
|
193 |
+
|
194 |
+
## Best Practices
|
195 |
+
|
196 |
+
1. Use the `@register_model` decorator to register your model with the framework (and import it in `lm_eval/models/__init__.py`!).
|
197 |
+
3. Use environment variables for sensitive information like API keys.
|
198 |
+
4. Properly handle batching and concurrent requests if supported by your API.
|
scripts/yans/lm-evaluation-harness/docs/CONTRIBUTING.md
ADDED
@@ -0,0 +1,79 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Contributing to LM Evaluation Harness
|
2 |
+
|
3 |
+
Welcome and thank you for your interest in the LM Evaluation Harness! We welcome contributions and feedback and appreciate your time spent with our library, and hope you find it useful!
|
4 |
+
|
5 |
+
## Important Resources
|
6 |
+
|
7 |
+
There are several places information about LM Evaluation Harness is located:
|
8 |
+
|
9 |
+
- Our [documentation pages](https://github.com/EleutherAI/lm-evaluation-harness/tree/main/docs)
|
10 |
+
- We occasionally use [GitHub Milestones](https://github.com/EleutherAI/lm-evaluation-harness/milestones) to track progress toward specific near-term version releases.
|
11 |
+
- We maintain a [Project Board](https://github.com/orgs/EleutherAI/projects/25) for tracking current work items and PRs, and for future roadmap items or feature requests.
|
12 |
+
- Further discussion and support conversations are located in the #lm-thunderdome channel of the [EleutherAI discord](https://discord.gg/eleutherai).
|
13 |
+
|
14 |
+
## Code Style
|
15 |
+
|
16 |
+
LM Evaluation Harness uses [ruff](https://github.com/astral-sh/ruff) for linting via [pre-commit](https://pre-commit.com/).
|
17 |
+
|
18 |
+
You can install linters and dev tools via
|
19 |
+
|
20 |
+
```pip install lm_eval[dev]``` or ```pip install -e ".[dev]"```
|
21 |
+
|
22 |
+
Then, run
|
23 |
+
|
24 |
+
```pre-commit install```
|
25 |
+
|
26 |
+
in order to ensure linters and other checks will be run upon committing.
|
27 |
+
|
28 |
+
## Testing
|
29 |
+
|
30 |
+
We use [pytest](https://docs.pytest.org/en/latest/) for running unit tests. All library unit tests can be run via:
|
31 |
+
|
32 |
+
```
|
33 |
+
python -m pytest --showlocals -s -vv -n=auto --ignore=tests/models/test_neuralmagic.py --ignore=tests/models/test_openvino.py
|
34 |
+
```
|
35 |
+
|
36 |
+
## Contributor License Agreement
|
37 |
+
|
38 |
+
We ask that new contributors agree to a Contributor License Agreement affirming that EleutherAI has the rights to use your contribution to our library.
|
39 |
+
First-time pull requests will have a reply added by @CLAassistant containing instructions for how to confirm this, and we require it before merging your PR.
|
40 |
+
|
41 |
+
|
42 |
+
## Contribution Best Practices
|
43 |
+
|
44 |
+
We recommend a few best practices to make your contributions or reported errors easier to assist with.
|
45 |
+
|
46 |
+
**For Pull Requests:**
|
47 |
+
- PRs should be titled descriptively, and be opened with a brief description of the scope and intent of the new contribution.
|
48 |
+
- New features should have appropriate documentation added alongside them.
|
49 |
+
- Aim for code maintainability, and minimize code copying.
|
50 |
+
- If opening a task, try to share test results on the task using a publicly-available model, and if any public results are available on the task, compare to them.
|
51 |
+
|
52 |
+
**For Feature Requests:**
|
53 |
+
- Provide a short paragraph's worth of description. What is the feature you are requesting? What is its motivation, and an example use case of it? How does this differ from what is currently supported?
|
54 |
+
|
55 |
+
**For Bug Reports**:
|
56 |
+
- Provide a short description of the bug.
|
57 |
+
- Provide a *reproducible example*--what is the command you run with our library that results in this error? Have you tried any other steps to resolve it?
|
58 |
+
- Provide a *full error traceback* of the error that occurs, if applicable. A one-line error message or small screenshot snippet is unhelpful without the surrounding context.
|
59 |
+
- Note what version of the codebase you are using, and any specifics of your environment and setup that may be relevant.
|
60 |
+
|
61 |
+
**For Requesting New Tasks**:
|
62 |
+
- Provide a 1-2 sentence description of what the task is and what it evaluates.
|
63 |
+
- Provide a link to the paper introducing the task.
|
64 |
+
- Provide a link to where the dataset can be found.
|
65 |
+
- Provide a link to a paper containing results on an open-source model on the task, for use in comparisons and implementation validation.
|
66 |
+
- If applicable, link to any codebase that has implemented the task (especially the original publication's codebase, if existent).
|
67 |
+
|
68 |
+
## How Can I Get Involved?
|
69 |
+
|
70 |
+
To quickly get started, we maintain a list of good first issues, which can be found [on our project board](https://github.com/orgs/EleutherAI/projects/25/views/8) or by [filtering GH Issues](https://github.com/EleutherAI/lm-evaluation-harness/issues?q=is%3Aopen+label%3A%22good+first+issue%22+label%3A%22help+wanted%22). These are typically smaller code changes or self-contained features which can be added without extensive familiarity with library internals, and we recommend new contributors consider taking a stab at one of these first if they are feeling uncertain where to begin.
|
71 |
+
|
72 |
+
There are a number of distinct ways to contribute to LM Evaluation Harness, and all are extremely helpful! A sampling of ways to contribute include:
|
73 |
+
- **Implementing and verifying new evaluation tasks**: Is there a task you'd like to see LM Evaluation Harness support? Consider opening an issue requesting it, or helping add it! Verifying and cross-checking task implementations with their original versions is also a very valuable form of assistance in ensuring standardized evaluation.
|
74 |
+
- **Improving documentation** - Improvements to the documentation, or noting pain points / gaps in documentation, are helpful in order for us to improve the user experience of the library and clarity + coverage of documentation.
|
75 |
+
- **Testing and devops** - We are very grateful for any assistance in adding tests for the library that can be run for new PRs, and other devops workflows.
|
76 |
+
- **Adding new modeling / inference library integrations** - We hope to support a broad range of commonly-used inference libraries popular among the community, and welcome PRs for new integrations, so long as they are documented properly and maintainable.
|
77 |
+
- **Proposing or Contributing New Features** - We want LM Evaluation Harness to support a broad range of evaluation usecases. If you have a feature that is not currently supported but desired, feel free to open an issue describing the feature and, if applicable, how you intend to implement it. We would be happy to give feedback on the cleanest way to implement new functionalities and are happy to coordinate with interested contributors via GH discussions or via discord.
|
78 |
+
|
79 |
+
We hope that this has been helpful, and appreciate your interest in contributing! Further questions can be directed to [our Discord](discord.gg/eleutherai).
|
scripts/yans/lm-evaluation-harness/docs/README.md
ADDED
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Eval Harness Documentation
|
2 |
+
|
3 |
+
Welcome to the docs for the LM Evaluation Harness!
|
4 |
+
|
5 |
+
## Table of Contents
|
6 |
+
|
7 |
+
* To learn about the public interface of the library, as well as how to evaluate via the command line or as integrated into an external library, see the [Interface](./interface.md).
|
8 |
+
* To learn how to add a new library, API, or model type to the library, as well as a quick explainer on the types of ways to evaluate an LM, see the [Model Guide](./model_guide.md).
|
9 |
+
* For an extended description of how to extend the library to new model classes served over an API, see the [API Guide](./API_guide.md).
|
10 |
+
* For a crash course on adding new tasks to the library, see our [New Task Guide](./new_task_guide.md).
|
11 |
+
* To learn more about pushing the limits of task configuration that the Eval Harness supports, see the [Task Configuration Guide](./task_guide.md).
|
scripts/yans/lm-evaluation-harness/docs/decontamination.md
ADDED
@@ -0,0 +1,71 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Decontamination
|
2 |
+
|
3 |
+
## Usage
|
4 |
+
|
5 |
+
The provided directory should contain
|
6 |
+
the ngram files and info.json produced in "Pile Ngram Generation" further down.
|
7 |
+
|
8 |
+
```bash
|
9 |
+
python -m lm_eval \
|
10 |
+
--model gpt2 \
|
11 |
+
--device 0 \
|
12 |
+
--tasks sciq
|
13 |
+
```
|
14 |
+
|
15 |
+
## Background
|
16 |
+
Downstream evaluations test model generalization, and are less useful when test set data also exists in the training set, referred to as leakage or contamination.
|
17 |
+
|
18 |
+
Filtering your training set against the test set is a good first step, however this isn't always possible, as in the case of a new benchmark or one that wasn't considered prior to model training. When training set filtering isn't possible, it is useful to measure the impact of test set leakage by detecting the contaminated test examples and producing a clean version of the benchmark.
|
19 |
+
|
20 |
+
The basis for our decontamination procedure can be found in Appendix C of "Language Models are Few-Shot Learners". OpenAI defined a test document as contaminated if any N-gram overlap existed with any training document. They used a range of N values between 8 and 13 depending on dataset, while we just used 13 for simplicity.
|
21 |
+
|
22 |
+
## Implementation
|
23 |
+
Contamination detection can be found in `lm_eval/decontaminate.py` with supporting code in `lm_eval/decontamination/`.
|
24 |
+
|
25 |
+
decontaminate.py does the following:
|
26 |
+
1. Build dictionaries of all ngrams and their corresponding evaluation/document ids.
|
27 |
+
2. Scan through sorted files containing training set n-grams.
|
28 |
+
3. If a match is found, the corresponding evaluation/document combinations are marked as contaminated.
|
29 |
+
|
30 |
+
`lm_eval/evaluator.py` can then produce a clean version of the benchmark by excluding the results of contaminated documents. For each metric, a clean version will be shown in the results with a "decontaminate" suffix.
|
31 |
+
|
32 |
+
This is disabled by default for new tasks, to support decontamination on a task override the "should_decontaminate" and "doc_to_decontamination_query" methods. For more details see the [task guide](task_guide.md).
|
33 |
+
|
34 |
+
## Pile Ngram Generation
|
35 |
+
The relevant scripts can be found in `scripts/clean_training_data`, which also import from
|
36 |
+
`lm_eval/decontamination/`
|
37 |
+
|
38 |
+
1. git clone https://github.com/EleutherAI/lm-evaluation-harness.git
|
39 |
+
2. pip install -r requirements.txt
|
40 |
+
3. Download The Pile from [The Eye](https://the-eye.eu/public/AI/pile/train/)
|
41 |
+
4. Place pile files in "pile" directory under "lm-evaluation-harness" (or create a symlink)
|
42 |
+
5. Run generate_13_grams.
|
43 |
+
|
44 |
+
```bash
|
45 |
+
export PYTHONHASHSEED=0
|
46 |
+
python -m scripts/clean_training_data/generate_13_grams \
|
47 |
+
-dir path/to/working/directory \
|
48 |
+
-n 13 \
|
49 |
+
-buckets 500
|
50 |
+
```
|
51 |
+
|
52 |
+
Took approximately 4 days for us. We had the time to wait, but this could be scaled out by doing partial pile scans on multiple instances of this script and merging the relevant buckets. We fixed PYTHONHASHSEED to ensure reproducibility of bucket hashing in case you need to stop and start.
|
53 |
+
|
54 |
+
6. Sort the generated 13-grams.
|
55 |
+
```bash
|
56 |
+
python -m scripts/clean_training_data/sort_13_gram_buckets \
|
57 |
+
-dir path/to/working/directory/output
|
58 |
+
```
|
59 |
+
|
60 |
+
Took approximately 5 days for us. You could speed this up by spreading the files around to different machines and running the sort script before gathering them together.
|
61 |
+
|
62 |
+
7. Compress the sorted 13 grams files and place them together with info.json.
|
63 |
+
|
64 |
+
This step only takes a few hours.
|
65 |
+
|
66 |
+
```bash
|
67 |
+
python -m scripts/clean_training_data/compress_and_package \
|
68 |
+
-dir path/to/working/directory \
|
69 |
+
-output path/to/final/directory \
|
70 |
+
-procs 8
|
71 |
+
```
|
scripts/yans/lm-evaluation-harness/docs/img/fewshot_example_gpt3.png
ADDED
![]() |
scripts/yans/lm-evaluation-harness/docs/interface.md
ADDED
@@ -0,0 +1,162 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# User Guide
|
2 |
+
|
3 |
+
This document details the interface exposed by `lm-eval` and provides details on what flags are available to users.
|
4 |
+
|
5 |
+
## Command-line Interface
|
6 |
+
|
7 |
+
A majority of users run the library by cloning it from Github, installing the package as editable, and running the `python -m lm_eval` script.
|
8 |
+
|
9 |
+
Equivalently, running the library can be done via the `lm-eval` entrypoint at the command line.
|
10 |
+
|
11 |
+
This mode supports a number of command-line arguments, the details of which can be also be seen via running with `-h` or `--help`:
|
12 |
+
|
13 |
+
- `--model` : Selects which model type or provider is evaluated. Must be a string corresponding to the name of the model type/provider being used. See [the main README](https://github.com/EleutherAI/lm-evaluation-harness/tree/main#model-apis-and-inference-servers) for a full list of enabled model names and supported libraries or APIs.
|
14 |
+
|
15 |
+
- `--model_args` : Controls parameters passed to the model constructor. Accepts a string containing comma-separated keyword arguments to the model class of the format `"arg1=val1,arg2=val2,..."`, such as, for example `--model_args pretrained=EleutherAI/pythia-160m,dtype=float32`. For a full list of what keyword arguments, see the initialization of the `lm_eval.api.model.LM` subclass, e.g. [`HFLM`](https://github.com/EleutherAI/lm-evaluation-harness/blob/365fcda9b85bbb6e0572d91976b8daf409164500/lm_eval/models/huggingface.py#L66)
|
16 |
+
|
17 |
+
- `--tasks` : Determines which tasks or task groups are evaluated. Accepts a comma-separated list of task names or task group names. Must be solely comprised of valid tasks/groups. A list of supported tasks can be viewed with `--tasks list`.
|
18 |
+
|
19 |
+
- `--num_fewshot` : Sets the number of few-shot examples to place in context. Must be an integer.
|
20 |
+
|
21 |
+
- `--gen_kwargs` : takes an arg string in same format as `--model_args` and creates a dictionary of keyword arguments. These will be passed to the models for all called `generate_until` (free-form or greedy generation task) tasks, to set options such as the sampling temperature or `top_p` / `top_k`. For a list of what args are supported for each model type, reference the respective library's documentation (for example, the documentation for `transformers.AutoModelForCausalLM.generate()`.) These kwargs will be applied to all `generate_until` tasks called--we do not currently support unique gen_kwargs or batch_size values per task in a single run of the library. To control these on a per-task level, set them in that task's YAML file.
|
22 |
+
|
23 |
+
- `--batch_size` : Sets the batch size used for evaluation. Can be a positive integer or `"auto"` to automatically select the largest batch size that will fit in memory, speeding up evaluation. One can pass `--batch_size auto:N` to re-select the maximum batch size `N` times during evaluation. This can help accelerate evaluation further, since `lm-eval` sorts documents in descending order of context length.
|
24 |
+
|
25 |
+
- `--max_batch_size` : Sets the maximum batch size to try to fit in memory, if `--batch_size auto` is passed.
|
26 |
+
|
27 |
+
- `--device` : Sets which device to place the model onto. Must be a string, for example, `"cuda", "cuda:0", "cpu", "mps"`. Defaults to "cuda", and can be ignored if running multi-GPU or running a non-local model type.
|
28 |
+
|
29 |
+
- `--output_path` : A string of the form `dir/file.jsonl` or `dir/`. Provides a path where high-level results will be saved, either into the file named or into the directory named. If `--log_samples` is passed as well, then per-document outputs and metrics will be saved into the directory as well.
|
30 |
+
|
31 |
+
- `--log_samples` : If this flag is passed, then the model's outputs, and the text fed into the model, will be saved at per-document granularity. Must be used with `--output_path`.
|
32 |
+
|
33 |
+
- `--limit` : Accepts an integer, or a float between 0.0 and 1.0 . If passed, will limit the number of documents to evaluate to the first X documents (if an integer) per task or first X% of documents per task. Useful for debugging, especially on costly API models.
|
34 |
+
|
35 |
+
- `--use_cache` : Should be a path where a sqlite db file can be written to. Takes a string of format `/path/to/sqlite_cache_` in order to create a cache db at `/path/to/sqlite_cache_rank{i}.db` for each process (0-NUM_GPUS). This allows results of prior runs to be cached, so that there is no need to re-run results in order to re-score or re-run a given (model, task) pair again.
|
36 |
+
|
37 |
+
- `--cache_requests` : Can be "true", "refresh", or "delete". "true" means that the cache should be used. "refresh" means that you wish to regenerate the cache, which you should run if you change your dataset configuration for a given task. "delete" will delete the cache. Cached files are stored under lm_eval/cache/.cache unless you specify a different path via the environment variable: `LM_HARNESS_CACHE_PATH`. e.g. `LM_HARNESS_CACHE_PATH=~/Documents/cache_for_lm_harness`.
|
38 |
+
|
39 |
+
- `--check_integrity` : If this flag is used, the library tests for each task selected are run to confirm task integrity.
|
40 |
+
|
41 |
+
- `--write_out` : Used for diagnostic purposes to observe the format of task documents passed to a model. If this flag is used, then prints the prompt and gold target string for the first document of each task.
|
42 |
+
|
43 |
+
- `--show_config` : If used, prints the full `lm_eval.api.task.TaskConfig` contents (non-default settings the task YAML file) for each task which was run, at the completion of an evaluation. Useful for when one is modifying a task's configuration YAML locally to transmit the exact configurations used for debugging or for reproducibility purposes.
|
44 |
+
|
45 |
+
- `--include_path` : Accepts a path to a folder. If passed, then all YAML files containing `lm-eval` compatible task configurations will be added to the task registry as available tasks. Used for when one is writing config files for their own task in a folder other than `lm_eval/tasks/`.
|
46 |
+
|
47 |
+
- `--system_instruction`: Specifies a system instruction string to prepend to the prompt.
|
48 |
+
|
49 |
+
- `--apply_chat_template` : If this flag is on, a chat template will be applied to the prompt. For Hugging Face models, the chat template is taken from the tokenizer, if the tokenizer does not have a chat template, a default one will be applied. For other models, chat templating is not currently implemented.
|
50 |
+
|
51 |
+
- `--fewshot_as_multiturn` : If this flag is on, the Fewshot examples are treated as a multi-turn conversation. Questions are provided as user content and answers are provided as assistant responses. Requires `--num_fewshot` to be set to be greater than 0, and `--apply_chat_template` to be on.
|
52 |
+
|
53 |
+
- `--predict_only`: Generates the model outputs without computing metrics. Use with `--log_samples` to retrieve decoded results.
|
54 |
+
|
55 |
+
* `--seed`: Set seed for python's random, numpy and torch. Accepts a comma-separated list of 3 values for python's random, numpy, and torch seeds, respectively, or a single integer to set the same seed for all three. The values are either an integer or 'None' to not set the seed. Default is `0,1234,1234` (for backward compatibility). E.g. `--seed 0,None,8` sets `random.seed(0)` and `torch.manual_seed(8)`. Here numpy's seed is not set since the second value is `None`. E.g, `--seed 42` sets all three seeds to 42.
|
56 |
+
|
57 |
+
* `--wandb_args`: Tracks logging to Weights and Biases for evaluation runs and includes args passed to `wandb.init`, such as `project` and `job_type`. Full list [here](https://docs.wandb.ai/ref/python/init). e.g., ```--wandb_args project=test-project,name=test-run```
|
58 |
+
|
59 |
+
* `--hf_hub_log_args` : Logs evaluation results to Hugging Face Hub. Accepts a string with the arguments separated by commas. Available arguments:
|
60 |
+
* `hub_results_org` - organization name on Hugging Face Hub, e.g., `EleutherAI`. If not provided, the results will be pushed to the owner of the Hugging Face token,
|
61 |
+
* `hub_repo_name` - repository name on Hugging Face Hub (deprecated, `details_repo_name` and `results_repo_name` should be used instead), e.g., `lm-eval-results`,
|
62 |
+
* `details_repo_name` - repository name on Hugging Face Hub to store details, e.g., `lm-eval-results`,
|
63 |
+
* `results_repo_name` - repository name on Hugging Face Hub to store results, e.g., `lm-eval-results`,
|
64 |
+
* `push_results_to_hub` - whether to push results to Hugging Face Hub, can be `True` or `False`,
|
65 |
+
* `push_samples_to_hub` - whether to push samples results to Hugging Face Hub, can be `True` or `False`. Requires `--log_samples` to be set,
|
66 |
+
* `public_repo` - whether the repository is public, can be `True` or `False`,
|
67 |
+
* `leaderboard_url` - URL to the leaderboard, e.g., `https://huggingface.co/spaces/HuggingFaceH4/open_llm_leaderboard`.
|
68 |
+
* `point_of_contact` - Point of contact for the results dataset, e.g., `[email protected]`.
|
69 |
+
* `gated` - whether to gate the details dataset, can be `True` or `False`.
|
70 |
+
|
71 |
+
## External Library Usage
|
72 |
+
|
73 |
+
We also support using the library's external API for use within model training loops or other scripts.
|
74 |
+
|
75 |
+
`lm_eval` supplies two functions for external import and use: `lm_eval.evaluate()` and `lm_eval.simple_evaluate()`.
|
76 |
+
|
77 |
+
`simple_evaluate()` can be used by simply creating an `lm_eval.api.model.LM` subclass that implements the methods described in the [Model Guide](https://github.com/EleutherAI/lm-evaluation-harness/tree/main/docs/model_guide.md), and wrapping your custom model in that class as follows:
|
78 |
+
|
79 |
+
```python
|
80 |
+
import lm_eval
|
81 |
+
...
|
82 |
+
|
83 |
+
my_model = initialize_my_model() # create your model (could be running finetuning with some custom modeling code)
|
84 |
+
...
|
85 |
+
# instantiate an LM subclass that takes your initialized model and can run
|
86 |
+
# - `Your_LM.loglikelihood()`
|
87 |
+
# - `Your_LM.loglikelihood_rolling()`
|
88 |
+
# - `Your_LM.generate_until()`
|
89 |
+
lm_obj = Your_LM(model=my_model, batch_size=16)
|
90 |
+
|
91 |
+
# indexes all tasks from the `lm_eval/tasks` subdirectory.
|
92 |
+
# Alternatively, you can set `TaskManager(include_path="path/to/my/custom/task/configs")`
|
93 |
+
# to include a set of tasks in a separate directory.
|
94 |
+
task_manager = lm_eval.tasks.TaskManager()
|
95 |
+
|
96 |
+
# Setting `task_manager` to the one above is optional and should generally be done
|
97 |
+
# if you want to include tasks from paths other than ones in `lm_eval/tasks`.
|
98 |
+
# `simple_evaluate` will instantiate its own task_manager if it is set to None here.
|
99 |
+
results = lm_eval.simple_evaluate( # call simple_evaluate
|
100 |
+
model=lm_obj,
|
101 |
+
tasks=["taskname1", "taskname2"],
|
102 |
+
num_fewshot=0,
|
103 |
+
task_manager=task_manager,
|
104 |
+
...
|
105 |
+
)
|
106 |
+
```
|
107 |
+
|
108 |
+
See the `simple_evaluate()` and `evaluate()` functions in [lm_eval/evaluator.py](../lm_eval/evaluator.py#:~:text=simple_evaluate) for a full description of all arguments available. All keyword arguments to simple_evaluate share the same role as the command-line flags described previously.
|
109 |
+
|
110 |
+
Additionally, the `evaluate()` function offers the core evaluation functionality provided by the library, but without some of the special handling and simplification + abstraction provided by `simple_evaluate()`.
|
111 |
+
|
112 |
+
As a brief example usage of `evaluate()`:
|
113 |
+
|
114 |
+
```python
|
115 |
+
import lm_eval
|
116 |
+
|
117 |
+
# suppose you've defined a custom lm_eval.api.Task subclass in your own external codebase
|
118 |
+
from my_tasks import MyTask1
|
119 |
+
...
|
120 |
+
|
121 |
+
# create your model (could be running finetuning with some custom modeling code)
|
122 |
+
my_model = initialize_my_model()
|
123 |
+
...
|
124 |
+
|
125 |
+
# instantiate an LM subclass that takes your initialized model and can run
|
126 |
+
# - `Your_LM.loglikelihood()`
|
127 |
+
# - `Your_LM.loglikelihood_rolling()`
|
128 |
+
# - `Your_LM.generate_until()`
|
129 |
+
lm_obj = Your_LM(model=my_model, batch_size=16)
|
130 |
+
|
131 |
+
# optional: the task_manager indexes tasks including ones
|
132 |
+
# specified by the user through `include_path`.
|
133 |
+
task_manager = lm_eval.tasks.TaskManager(
|
134 |
+
include_path="/path/to/custom/yaml"
|
135 |
+
)
|
136 |
+
|
137 |
+
# To get a task dict for `evaluate`
|
138 |
+
task_dict = lm_eval.tasks.get_task_dict(
|
139 |
+
[
|
140 |
+
"mmlu", # A stock task
|
141 |
+
"my_custom_task", # A custom task
|
142 |
+
{
|
143 |
+
"task": ..., # A dict that configures a task
|
144 |
+
"doc_to_text": ...,
|
145 |
+
},
|
146 |
+
MyTask1 # A task object from `lm_eval.task.Task`
|
147 |
+
],
|
148 |
+
task_manager # A task manager that allows lm_eval to
|
149 |
+
# load the task during evaluation.
|
150 |
+
# If none is provided, `get_task_dict`
|
151 |
+
# will instantiate one itself, but this
|
152 |
+
# only includes the stock tasks so users
|
153 |
+
# will need to set this if including
|
154 |
+
# custom paths is required.
|
155 |
+
)
|
156 |
+
|
157 |
+
results = evaluate(
|
158 |
+
lm=lm_obj,
|
159 |
+
task_dict=task_dict,
|
160 |
+
...
|
161 |
+
)
|
162 |
+
```
|
scripts/yans/lm-evaluation-harness/docs/model_guide.md
ADDED
@@ -0,0 +1,163 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# New Model Guide
|
2 |
+
|
3 |
+
This guide may be of special interest to users who are using the library outside of the repository, via installing the library via pypi and calling `lm_eval.evaluator.evaluate()` to evaluate an existing model.
|
4 |
+
|
5 |
+
In order to properly evaluate a given LM, we require implementation of a wrapper class subclassing the `lm_eval.api.model.LM` class, that defines how the Evaluation Harness should interface with your model. This guide walks through how to write this `LM` subclass via adding it to the library!
|
6 |
+
|
7 |
+
## Setup
|
8 |
+
|
9 |
+
To get started contributing, go ahead and fork the main repo, clone it, create a branch with the name of your model, and install the project requirements in your environment:
|
10 |
+
|
11 |
+
```sh
|
12 |
+
# After forking...
|
13 |
+
git clone https://github.com/<YOUR-USERNAME>/lm-evaluation-harness.git
|
14 |
+
cd lm-evaluation-harness
|
15 |
+
git checkout -b <model-type>
|
16 |
+
pip install -e ".[dev]"
|
17 |
+
```
|
18 |
+
|
19 |
+
Now, we'll create a new file where we'll be adding our model:
|
20 |
+
|
21 |
+
```sh
|
22 |
+
touch lm_eval/models/<my_model_filename>.py
|
23 |
+
```
|
24 |
+
|
25 |
+
**Tip: this filename should not shadow package names! For example, naming your file `anthropic.py` is disallowed since the API's name on pypi is `anthropic`, but naming it `anthropic_llms.py` works with no problems.**
|
26 |
+
|
27 |
+
## Interface
|
28 |
+
|
29 |
+
All models must subclass the `lm_eval.api.model.LM` class.
|
30 |
+
|
31 |
+
The LM class enforces a common interface via which we can extract responses from a model:
|
32 |
+
|
33 |
+
```python
|
34 |
+
class MyCustomLM(LM):
|
35 |
+
#...
|
36 |
+
def loglikelihood(self, requests: list[Instance]) -> list[tuple[float, bool]]:
|
37 |
+
#...
|
38 |
+
|
39 |
+
|
40 |
+
def loglikelihood_rolling(self, requests: list[Instance]) -> list[tuple[float, bool]]:
|
41 |
+
#...
|
42 |
+
|
43 |
+
|
44 |
+
def generate_until(self, requests: list[Instance]) -> list[str]:
|
45 |
+
#...
|
46 |
+
#...
|
47 |
+
```
|
48 |
+
Where `Instance` is a dataclass defined in [`lm_eval.api.instance`](https://github.com/EleutherAI/lm-evaluation-harness/blob/main/lm_eval/api/instance.py) with property `args` of request-dependent type signature described below.
|
49 |
+
|
50 |
+
We support three types of requests, consisting of different interactions / measurements with an autoregressive LM.
|
51 |
+
|
52 |
+
All three request types take as input `requests` of type `list[Instance]` that have a matching `Instance.request_type` to the method name.
|
53 |
+
|
54 |
+
- `generate_until`
|
55 |
+
- Each request contains `Instance.args : Tuple[str, dict]` containing 1. an input string to the LM and 2. a dictionary of keyword arguments used to control generation parameters.
|
56 |
+
- Using this input and these generation parameters, text will be sampled from the language model (typically until a maximum output length or specific stopping string sequences--for example, `{"until": ["\n\n", "."], "max_gen_toks": 128}`).
|
57 |
+
- The generated input+output text from the model will then be returned.
|
58 |
+
|
59 |
+
- `loglikelihood`
|
60 |
+
- Each request contains `Instance.args : Tuple[str, str]` containing 1. an input string to the LM and 2. a target string on which the loglikelihood of the LM producing this target, conditioned on the input, will be returned.
|
61 |
+
- Each request will have, as result, `(ll, is_greedy): Tuple[float, int]` returned, where `ll` is a floating point number representing the log probability of generating the target string conditioned on the input, and `is_greedy` being either the value `0` or `1`, with it being `1` if and only if the target string *would be generated by greedy sampling from the LM* (that is, if the target string is the *most likely* N-token string to be output by the LM given the input. )
|
62 |
+
|
63 |
+
- `loglikelihood_rolling`
|
64 |
+
- Each request contains `Instance.args : Tuple[str]`, which is an input string to the model whose *entire* loglikelihood, conditioned on purely the EOT token, will be calculated.
|
65 |
+
- This is used to evaluate *perplexity* on a data distribution.
|
66 |
+
- It should return `(ll,) : Tuple[float]` , a.k.a. solely the *loglikelihood* of producing each piece of text given no starting input.
|
67 |
+
|
68 |
+
|
69 |
+
To allow a model to be evaluated on all types of tasks, you will need to implement these three types of measurements (note that `loglikelihood_rolling` is a special case of `loglikelihood`). For a reference implementation, check out `lm_eval/models/huggingface.py` ! Additionally, check out `lm_eval.api.model.TemplateLM` for a class that abstracts away some commonly used functions across LM subclasses, or see if your model would lend itself well to subclassing the `lm_eval.models.huggingface.HFLM` class and overriding just the initialization or a couple methods!
|
70 |
+
|
71 |
+
**Tip: be careful of indexing in loglikelihood!**
|
72 |
+
|
73 |
+
|
74 |
+
LMs take in tokens in position `[0 1 2 ... N]` and output a probability distribution for token position `N+1`. We provide a simplified graphic here, excerpted from `huggingface.py`:
|
75 |
+
|
76 |
+
```
|
77 |
+
# how this all works (illustrated on a causal decoder-only setup):
|
78 |
+
# CTX CONT
|
79 |
+
# inp 0 1 2 3|4 5 6 7 8 9 <- last token is deleted by inp[:, :-1]
|
80 |
+
# model \ \
|
81 |
+
# logits 1 2 3|4 5 6 7 8 9 <- the ctx half gets tossed out by the
|
82 |
+
# cont_toks 4 5 6 7 8 9 [:, -len(continuation_enc):, :self.vocab_size] slice
|
83 |
+
```
|
84 |
+
|
85 |
+
The final token of the target is not passed into the LM, because we want the LM's predictions *up to but not past* that final target token. For more information, check out https://github.com/EleutherAI/lm-evaluation-harness/issues/942 .
|
86 |
+
|
87 |
+
## Registration
|
88 |
+
|
89 |
+
Congrats on implementing your model! Now it's time to test it out.
|
90 |
+
|
91 |
+
To make your model usable via the command line interface to `lm-eval` using `python -m lm_eval`, you'll need to tell `lm-eval` what your model's name is.
|
92 |
+
|
93 |
+
This is done via a *decorator*, `lm_eval.api.registry.register_model`. Using `register_model()`, one can both tell the package what the model's name(s) to be used are when invoking it with `python -m lm_eval --model <name>` and alert `lm-eval` to the model's existence.
|
94 |
+
|
95 |
+
```python
|
96 |
+
from lm_eval.api.registry import register_model
|
97 |
+
|
98 |
+
@register_model("<name1>", "<name2>")
|
99 |
+
class MyCustomLM(LM):
|
100 |
+
```
|
101 |
+
|
102 |
+
Using this decorator results in the class being added to an accounting of the usable LM types maintained internally to the library at `lm_eval.api.registry.MODEL_REGISTRY`. See `lm_eval.api.registry` for more detail on what sorts of registries and decorators exist in the library!
|
103 |
+
|
104 |
+
**Tip: be sure to import your model in `lm_eval/models/__init__.py!`**
|
105 |
+
|
106 |
+
## Testing
|
107 |
+
|
108 |
+
We also recommend that new model contributions be accompanied by short tests of their 3 core functionalities, at minimum. To see an example of such tests, look at https://github.com/EleutherAI/lm-evaluation-harness/blob/35bdecd379c0cefad6897e67db892f4a6026a128/tests/test_ggml.py .
|
109 |
+
|
110 |
+
## Chat Templating
|
111 |
+
|
112 |
+
Many models are fine-tuned with a [Chat Template](https://huggingface.co/docs/transformers/main/en/chat_templating) in order to enable back-and-forth interaction between a "User"'s queries and the model (often called "Assistant")'s responses. It can be desirable to evaluate fine-tuned models on evaluation tasks while wrapped in the conversational format they expect.
|
113 |
+
|
114 |
+
In order to make your model optionally compatible with a chat format, three additional methods must be implemented:
|
115 |
+
|
116 |
+
```python
|
117 |
+
class MyCustomLM(LM):
|
118 |
+
#...
|
119 |
+
@property
|
120 |
+
def tokenizer_name(self) -> str:
|
121 |
+
# should return a string denoting the name of the model's tokenizer and/or the accompanying chat template.
|
122 |
+
|
123 |
+
@property
|
124 |
+
def chat_template(self) -> str:
|
125 |
+
# should return a chat template formatting string that is used to build prompt from a user/assistant chat history.
|
126 |
+
# this will be saved in the evaluation results for reproducibility.
|
127 |
+
|
128 |
+
def apply_chat_template(self, chat_history: List[Dict[str, str]]) -> str:
|
129 |
+
# responsible for taking as input a chat history that would be fed into the model, and
|
130 |
+
# rendering it as a string that can be then tokenized and input into the model.
|
131 |
+
#...
|
132 |
+
```
|
133 |
+
|
134 |
+
- `apply_chat_template`
|
135 |
+
- This method performs the bulk of the work required for chat-formatting.
|
136 |
+
- As input, a `chat_history: List[Dict[str, str]]` is passed in. This is a transcript of a conversation of a form similar to
|
137 |
+
```
|
138 |
+
[
|
139 |
+
{"system": <user-provided system message such as "You are a helpful math-focused chatbot">},
|
140 |
+
{"user": <task example - a few-shot example 'input'>}
|
141 |
+
{"assistant": <correct response to the above example>},
|
142 |
+
# ... more few-shot examples, potentially
|
143 |
+
{"user": <test set query--response on which we will evaluate>},
|
144 |
+
]
|
145 |
+
```
|
146 |
+
which can then be converted into a string input.
|
147 |
+
- The output is a string representing this conversation that can be fed into the model.
|
148 |
+
- For example, this consists of simply calling `tokenizer.apply_chat_template` for HFLM--see the implementation there for reference.
|
149 |
+
- `tokenizer_name`
|
150 |
+
- LM Eval Harness supports [caching requests](https://github.com/EleutherAI/lm-evaluation-harness/blob/4902aaaf1f374682f95ac25fe2e13b23faddc91a/lm_eval/__main__.py#L140) that are sent to a model, for faster setup when repeating an already-performed evaluation.
|
151 |
+
- However, we don't want to use the cache of chat transcripts rendered using one chat template or system prompt to send to a model with a different template! So, we use this `lm.tokenizer_name` string to distinguish caches for a given model (and chat template) from one another.
|
152 |
+
- `chat_template`
|
153 |
+
- Chat templates are typically provided as a Jinja template string or a string formatted with str.format to include user and assistant messages in a single prompt. This template string is saved in the evaluation results to ensure reproducibility.
|
154 |
+
|
155 |
+
If not implemented for a given model type, the flags `--apply_chat_template` , `--fewshot_as_multiturn`, and `--system_instruction` cannot be used.
|
156 |
+
|
157 |
+
## Other
|
158 |
+
|
159 |
+
**Pro tip**: In order to make the Evaluation Harness overestimate total runtimes rather than underestimate it, HuggingFace models come in-built with the ability to provide responses on data points in *descending order by total input length* via `lm_eval.utils.Reorderer`. Take a look at `lm_eval.models.hf_causal.HFLM` to see how this is done, and see if you can implement it in your own model!
|
160 |
+
|
161 |
+
## Conclusion
|
162 |
+
|
163 |
+
After reading this guide, you should be able to add new model APIs or implementations to the Eval Harness library!
|
scripts/yans/lm-evaluation-harness/docs/new_task_guide.md
ADDED
@@ -0,0 +1,492 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# New Task Guide
|
2 |
+
|
3 |
+
`lm-evaluation-harness` is a framework that strives to support a wide range of zero- and few-shot evaluation tasks on autoregressive language models (LMs).
|
4 |
+
|
5 |
+
This documentation page provides a walkthrough to get started creating your own task, in `lm-eval` versions v0.4.0 and later.
|
6 |
+
|
7 |
+
A more interactive tutorial is available as a Jupyter notebook [here](https://github.com/EleutherAI/lm-evaluation-harness/blob/main/examples/lm-eval-overview.ipynb).
|
8 |
+
|
9 |
+
## Setup
|
10 |
+
|
11 |
+
If you haven't already, go ahead and fork the main repo, clone it, create a branch with the name of your task, and install the project requirements in your environment:
|
12 |
+
|
13 |
+
```sh
|
14 |
+
# After forking...
|
15 |
+
git clone https://github.com/<YOUR-USERNAME>/lm-evaluation-harness.git
|
16 |
+
cd lm-evaluation-harness
|
17 |
+
git checkout -b <task-name>
|
18 |
+
pip install -e ".[dev]"
|
19 |
+
```
|
20 |
+
|
21 |
+
In this document, we'll walk through the basics of implementing a static benchmark evaluation in two formats: a *generative* task which requires sampling text from a model, such as [`gsm8k`](https://github.com/EleutherAI/lm-evaluation-harness/blob/main/lm_eval/tasks/gsm8k/gsm8k.yaml), and a *discriminative*, or *multiple choice*, task where the model picks the most likely of several fixed answer choices, such as [`sciq`](https://github.com/EleutherAI/lm-evaluation-harness/blob/main/lm_eval/tasks/sciq/sciq.yaml).
|
22 |
+
|
23 |
+
## Creating a YAML file
|
24 |
+
|
25 |
+
To implement a new standard task, we'll need to write a YAML file which configures our task logic. We start by making a new empty YAML file. This file can have any name, but we recommend placing it in a subfolder of `lm_eval/tasks` titled by the dataset or task's shorthand name: for example,
|
26 |
+
|
27 |
+
```sh
|
28 |
+
touch lm_eval/tasks/<dataset_name>/<my_new_task_name>.yaml
|
29 |
+
```
|
30 |
+
Or, copy the template subfolder we provide from `templates/new_yaml_task`:
|
31 |
+
```sh
|
32 |
+
cp -r templates/new_yaml_task lm_eval/tasks/
|
33 |
+
```
|
34 |
+
and rename the folders and YAML file(s) as desired.
|
35 |
+
|
36 |
+
### Selecting and configuring a dataset
|
37 |
+
|
38 |
+
All data downloading and management is handled through the HuggingFace (**HF**) [`datasets`](https://github.com/huggingface/datasets) API. So, the first thing you should do is check to see if your task's dataset is already provided in their catalog [here](https://huggingface.co/datasets). If it's not in there, please consider adding it to their Hub to make it accessible to a wider user base by following their [new dataset guide](https://github.com/huggingface/datasets/blob/main/ADD_NEW_DATASET.md)
|
39 |
+
.
|
40 |
+
|
41 |
+
Once you have a HuggingFace dataset prepared for your task, we want to assign our new YAML to use this dataset:
|
42 |
+
|
43 |
+
```yaml
|
44 |
+
dataset_path: ... # the name of the dataset on the HF Hub.
|
45 |
+
dataset_name: ... # the dataset configuration to use. Leave `null` if your dataset does not require a config to be passed. See https://huggingface.co/docs/datasets/load_hub#configurations for more info.
|
46 |
+
dataset_kwargs: null # any extra keyword arguments that should be passed to the dataset constructor, e.g. `data_dir`.
|
47 |
+
```
|
48 |
+
|
49 |
+
Next, we'd like to tell our task what the dataset's train, validation, and test splits are named, if they exist:
|
50 |
+
|
51 |
+
```yaml
|
52 |
+
training_split: <split name of training set, or `null`>
|
53 |
+
validation_split: <split name of val. set, or `null`>
|
54 |
+
test_split: <split name of test set, or `null`>
|
55 |
+
```
|
56 |
+
Tests will run on the `test_split` if it is available, and otherwise evaluate on the `validation_split`.
|
57 |
+
|
58 |
+
We can also specify from which split the task should retrieve few-shot examples via:
|
59 |
+
```yaml
|
60 |
+
fewshot_split: <split name to draw fewshot examples from, or `null`>
|
61 |
+
```
|
62 |
+
or by hardcoding them, either using the following in the yaml file:
|
63 |
+
```yaml
|
64 |
+
fewshot_config:
|
65 |
+
sampler: first_n
|
66 |
+
samples: [
|
67 |
+
{<sample 1>},
|
68 |
+
{<sample 2>},
|
69 |
+
]
|
70 |
+
```
|
71 |
+
or by adding the function `list_fewshot_samples` in the associated utils.py file:
|
72 |
+
```python
|
73 |
+
def list_fewshot_samples() -> list[dict]:
|
74 |
+
return [{<sample 1>}, {<sample 2>}]
|
75 |
+
```
|
76 |
+
See `lm_eval/tasks/minerva_math/minerva_math_algebra.yaml` for an example of the latter, and `lm_eval/tasks/gsm8k/gsm8k-cot.yaml` for an example of the former.
|
77 |
+
|
78 |
+
In this case, each sample must contain the same fields as the samples in the above sets--for example, if `doc_to_text` expects an `input` field when rendering input prompts, these provided samples must include an `input` key.
|
79 |
+
|
80 |
+
If neither above options are not set, we will default to train/validation/test sets, in that order.
|
81 |
+
|
82 |
+
|
83 |
+
Finally, our dataset may not be already in the exact format we want. Maybe we have to strip whitespace and special characters via a regex from our dataset's "question" field! Or maybe we just want to rename its columns to match a convention we'll be using for our prompts.
|
84 |
+
|
85 |
+
Let's create a python file in the directory where we're writing our YAML file:
|
86 |
+
```bash
|
87 |
+
touch lm_eval/tasks/<dataset_name>/utils.py
|
88 |
+
```
|
89 |
+
Now, in `utils.py` we'll write a function to process each split of our dataset:
|
90 |
+
|
91 |
+
TODO: Change the example to one that's in the tasks/
|
92 |
+
|
93 |
+
```python
|
94 |
+
def process_docs(dataset: datasets.Dataset):
|
95 |
+
def _helper(doc):
|
96 |
+
# modifies the contents of a single
|
97 |
+
# document in our dataset.
|
98 |
+
doc["choices"] = [doc["choice1"], doc["choice2"], doc["wrong_answer"]]
|
99 |
+
doc["gold"] = doc["label"]
|
100 |
+
return doc
|
101 |
+
|
102 |
+
return dataset.map(_helper) # returns back a datasets.Dataset object
|
103 |
+
```
|
104 |
+
|
105 |
+
Now, in our YAML config file we'll use the `!function` constructor, and tell the config where our imported Python function will come from. At runtime, before doing anything else we will preprocess our dataset according to this function!
|
106 |
+
```yaml
|
107 |
+
process_docs: !function utils.process_docs
|
108 |
+
```
|
109 |
+
|
110 |
+
### Using Local Datasets
|
111 |
+
|
112 |
+
To load a local dataset for evaluation, you can specify data files in the `dataset_kwargs` field, such as the following for JSON files:
|
113 |
+
|
114 |
+
```
|
115 |
+
dataset_path: json
|
116 |
+
dataset_name: null
|
117 |
+
dataset_kwargs:
|
118 |
+
data_files: /path/to/my/json
|
119 |
+
```
|
120 |
+
Or with files already split into separate directories:
|
121 |
+
|
122 |
+
```
|
123 |
+
dataset_path: arrow
|
124 |
+
dataset_kwargs:
|
125 |
+
data_files:
|
126 |
+
train: /path/to/arrow/train/data-00000-of-00001.arrow
|
127 |
+
validation: /path/to/arrow/validation/data-00000-of-00001.arrow
|
128 |
+
```
|
129 |
+
|
130 |
+
Alternatively, if you have previously downloaded a dataset from huggingface hub (using `save_to_disk()`) and wish to use the local files, you will need to use `data_dir` under `dataset_kwargs` to point to where the directory is.
|
131 |
+
|
132 |
+
```
|
133 |
+
dataset_path: hellaswag
|
134 |
+
dataset_kwargs:
|
135 |
+
data_dir: hellaswag_local/
|
136 |
+
```
|
137 |
+
|
138 |
+
You can also set `dataset_path` as a directory path in your local system. This will assume that there is a loading script with the same name as the directory. [See datasets docs](https://huggingface.co/docs/datasets/loading#local-loading-script).
|
139 |
+
|
140 |
+
## Writing a Prompt Template
|
141 |
+
|
142 |
+
The next thing we need to do is decide what format to use when presenting the data to the LM. This is our **prompt**, where we'll define both an input and output format.
|
143 |
+
|
144 |
+
To write a prompt, users will use `doc_to_text`, `doc_to_target`, and `doc_to_choice` (Optional when certain conditions are met).
|
145 |
+
|
146 |
+
`doc_to_text` defines the input string a model will be given while `doc_to_target` and `doc_to_choice` will be used to generate the target text. `doc_to_target` can be either a text string that refers to the target string or an integer that refers to the index of the correct label. When it is set as an index, `doc_to_choice` must be also be set with the appropriate list of possible choice strings.
|
147 |
+
|
148 |
+
### Basic prompts
|
149 |
+
|
150 |
+
If a dataset is straightforward enough, users can enter the feature name directly. This assumes that no preprocessing is required. For example in [Swag](https://github.com/EleutherAI/lm-evaluation-harness/blob/1710b42d52d0f327cb0eb3cb1bfbbeca992836ca/lm_eval/tasks/swag/swag.yaml#L10-L11), `doc_to_text` and `doc_to_target` given the name of one of the feature each.
|
151 |
+
```yaml
|
152 |
+
doc_to_text: startphrase
|
153 |
+
doc_to_target: label
|
154 |
+
```
|
155 |
+
Hard-coding is also possible as is the case in [SciQ](https://github.com/EleutherAI/lm-evaluation-harness/blob/1710b42d52d0f327cb0eb3cb1bfbbeca992836ca/lm_eval/tasks/sciq/sciq.yaml#L11).
|
156 |
+
```yaml
|
157 |
+
doc_to_target: 3
|
158 |
+
```
|
159 |
+
`doc_to_choice` can be directly given a list of text as option (See [Toxigen](https://github.com/EleutherAI/lm-evaluation-harness/blob/1710b42d52d0f327cb0eb3cb1bfbbeca992836ca/lm_eval/tasks/toxigen/toxigen.yaml#L11))
|
160 |
+
```yaml
|
161 |
+
doc_to_choice: ['No', 'Yes']
|
162 |
+
```
|
163 |
+
|
164 |
+
if a dataset feature is already a list, you can set the name of the feature as `doc_to_choice` (See [Hellaswag](https://github.com/EleutherAI/lm-evaluation-harness/blob/e0eda4d3ffa10e5f65e0976161cd134bec61983a/lm_eval/tasks/hellaswag/hellaswag.yaml#L13))
|
165 |
+
```
|
166 |
+
doc_to_choice: choices
|
167 |
+
```
|
168 |
+
|
169 |
+
|
170 |
+
|
171 |
+
### Writing a prompt with Jinja 2
|
172 |
+
|
173 |
+
We support the [Jinja 2](https://jinja.palletsprojects.com/en/3.1.x/) templating language for writing prompts. In practice, this means you can take your dataset's columns and do many basic string manipulations to place each document into prompted format.
|
174 |
+
|
175 |
+
Take for example the dataset `super_glue/boolq`. As input, we'd like to use the features `passage` and `question` and string them together so that for a a sample line `doc`, the model sees something the format of:
|
176 |
+
```
|
177 |
+
doc["passage"]
|
178 |
+
Question: doc["question"]?
|
179 |
+
Answer:
|
180 |
+
```
|
181 |
+
We do this by [writing](https://github.com/EleutherAI/lm-evaluation-harness/blob/1710b42d52d0f327cb0eb3cb1bfbbeca992836ca/lm_eval/tasks/super_glue/boolq/default.yaml#L9C1-L9C61)
|
182 |
+
```yaml
|
183 |
+
doc_to_text: "{{passage}}\nQuestion: {{question}}?\nAnswer:"
|
184 |
+
```
|
185 |
+
Such that `{{passage}}` will be replaced by `doc["passage"]` and `{{question}}` with `doc["question"]` when rendering the prompt template.
|
186 |
+
|
187 |
+
Our intended output is for the model to predict a single whitespace, and then the answer to the question. We do this via:
|
188 |
+
```yaml
|
189 |
+
doc_to_target: "{{answer}}"
|
190 |
+
```
|
191 |
+
|
192 |
+
|
193 |
+
**Important**: we now add `target_delimiter` between input and target which defaults to " ", such that the full input-output string is `doc_to_target(doc) + target_delimiter + doc_to_text(doc)`. `doc_to_text` and `doc_to_target` should not contain trailing right or left whitespace, respectively.
|
194 |
+
|
195 |
+
|
196 |
+
#### Multiple choice format
|
197 |
+
|
198 |
+
For tasks which are multiple choice (a fixed, finite set of label words per each document) and evaluated via comparing loglikelihoods of all label words (the `multiple_choice` task output type) we enforce a particular convention on prompt format.
|
199 |
+
|
200 |
+
An annotated example in the case of SciQ is as follows:
|
201 |
+
|
202 |
+
```yaml
|
203 |
+
doc_to_text: "{{support.lstrip()}}\nQuestion: {{question}}\nAnswer:" # This is the input portion of the prompt for this doc. It will have " {{choice}}" appended to it as target for each choice in answer_choices.
|
204 |
+
doc_to_target: 3 # this contains the index into the answer choice list of the correct answer.
|
205 |
+
doc_to_choice: "{{[distractor1, distractor2, distractor3, correct_answer]}}"
|
206 |
+
```
|
207 |
+
Task implementers are thus able to decide what the answer choices should be for a document, and what prompt format to use.
|
208 |
+
|
209 |
+
The label index can also be sourced from a feature directly. For example in `superglue/boolq`, the label index if defined in the feature `label`. We can set `doc_to_target` as simply `label`. The options or verbalizers can be written in a the form of a list `["no", "yes"]` that will correspond to the label index.
|
210 |
+
|
211 |
+
```yaml
|
212 |
+
doc_to_text: "{{passage}}\nQuestion: {{question}}?\nAnswer:"
|
213 |
+
doc_to_target: label
|
214 |
+
doc_to_choice: ["no", "yes"]
|
215 |
+
```
|
216 |
+
|
217 |
+
### Using Python Functions for Prompts
|
218 |
+
|
219 |
+
There may be cases where the prompt we want to implement is easier expressed in Python instead of Jinja 2. For this, we can use Python helper functions that are defined in the YAML config. It should be noted that the function script must be in the same directory as the yaml.
|
220 |
+
|
221 |
+
A good example is WikiText that requires a lot of regex rules to clean the samples.
|
222 |
+
```
|
223 |
+
def wikitext_detokenizer(doc):
|
224 |
+
string = doc["page"]
|
225 |
+
# contractions
|
226 |
+
string = string.replace("s '", "s'")
|
227 |
+
string = re.sub(r"/' [0-9]/", r"/'[0-9]/", string)
|
228 |
+
...
|
229 |
+
string = string.replace(" 's", "'s")
|
230 |
+
|
231 |
+
return string
|
232 |
+
```
|
233 |
+
|
234 |
+
We can load this function in `doc_to_target` by using a `!function` operator after `doc_to_target` and followed by `<file name>.<function name>`. In the file [wikitext.yaml](https://github.com/EleutherAI/lm-evaluation-harness/blob/main/lm_eval/tasks/wikitext/wikitext.yaml) we write:
|
235 |
+
```
|
236 |
+
doc_to_target: !function preprocess_wikitext.wikitext_detokenizer
|
237 |
+
```
|
238 |
+
|
239 |
+
### Importing a Prompt from Promptsource
|
240 |
+
|
241 |
+
[Promptsource](https://github.com/bigscience-workshop/promptsource/tree/main/promptsource) is a great repository for crowdsourced prompts for many datasets. We can load these prompts easily by using the `use_prompt` argument and filling it with the format `"promptsource:<name of prompt template>"`. To use this, `doc_to_text` and `doc_to_target` should be left undefined. This will fetch the template of the dataset defined in the YAML file.
|
242 |
+
|
243 |
+
For example, For Super Glue BoolQ, if we want to use the prompt template `GPT-3 Style` we can add this to the YAML file.
|
244 |
+
```
|
245 |
+
use_prompt: "promptsource:GPT-3 Style"
|
246 |
+
```
|
247 |
+
|
248 |
+
If you would like to run evaluation on all prompt templates, you can simply call it this way.
|
249 |
+
```
|
250 |
+
use_prompt: "promptsource:*"
|
251 |
+
```
|
252 |
+
|
253 |
+
### Setting metrics
|
254 |
+
|
255 |
+
You're almost done! Now we need to choose how to score our task.
|
256 |
+
- *If this is a multiple choice task:* do you just want to check your model's accuracy in choosing the correct answer choice?
|
257 |
+
- *If this is a generation task:* do you just want to check how often your model outputs *exactly the ground-truth output string provided*?
|
258 |
+
|
259 |
+
|
260 |
+
If the answer to the above is no: you'll need to record what scoring metrics to use! Metrics can be listed in the following format:
|
261 |
+
|
262 |
+
```yaml
|
263 |
+
metric_list:
|
264 |
+
- metric: <name of the metric here>
|
265 |
+
aggregation: <name of the aggregation fn here>
|
266 |
+
higher_is_better: <true or false>
|
267 |
+
- metric: !function script.function
|
268 |
+
aggregation: ...
|
269 |
+
higher_is_better: ...
|
270 |
+
```
|
271 |
+
`aggregation` and `higher_is_better` can optionally be left out to default to the manually-set defaults if using a natively supported metric, otherwise it must be defined explicitly (for example, when using a custom metric implemented as a function).
|
272 |
+
|
273 |
+
For a full list of natively supported metrics and aggregation functions see [`docs/task_guide.md`](https://github.com/EleutherAI/lm-evaluation-harness/blob/main/docs/task_guide.md). All metrics supported in [HuggingFace Evaluate](https://github.com/huggingface/evaluate/tree/main/metrics) can also be used, and will be loaded if a given metric name is not one natively supported in `lm-eval` or `hf_evaluate` is set to `true`.
|
274 |
+
|
275 |
+
### Optional, More Advanced Setup
|
276 |
+
|
277 |
+
Some tasks may require more advanced processing logic than is described in this guide.
|
278 |
+
|
279 |
+
As a heuristic check:
|
280 |
+
* Does your task require generating multiple free-form outputs per input document?
|
281 |
+
* Does your task require complex, multi-step post-processing of generated model outputs?
|
282 |
+
* Does your task require subsetting documents on the fly based on their content?
|
283 |
+
* Do you expect to compute metrics after applying multiple such processing steps on your model outputs?
|
284 |
+
* Does your task rely on metrics that need a custom implementation?
|
285 |
+
|
286 |
+
For more detail on the task system and advanced features, see [`docs/task_guide.md`](https://github.com/EleutherAI/lm-evaluation-harness/blob/main/docs/task_guide.md) . If none of the above sound like they apply to your task, it's time to continue onto checking your task performance!
|
287 |
+
|
288 |
+
### Task name + tags (registering a task)
|
289 |
+
|
290 |
+
To test a task conveniently, it helps to *register* the task--that is, to give it a name and make the `lm-eval` library aware it exists!
|
291 |
+
|
292 |
+
If you're writing your YAML file inside the `lm_eval/tasks` folder, you just need to give your task a name! You can do this inside your YAML file:
|
293 |
+
|
294 |
+
```yaml
|
295 |
+
task: <name of the task>
|
296 |
+
```
|
297 |
+
Including a task name is mandatory.
|
298 |
+
|
299 |
+
It is often also convenient to label your task with several `tag` values, though this field is optional:
|
300 |
+
|
301 |
+
```yaml
|
302 |
+
tag:
|
303 |
+
- tag1
|
304 |
+
- tag2
|
305 |
+
```
|
306 |
+
This will add your task to the `tag1` and `tag2` tags, enabling people to know how to categorize your task, and if desired run all tasks in one of these groups at once, your task along with them.
|
307 |
+
|
308 |
+
|
309 |
+
If your task is not in the `lm_eval/tasks` folder, you'll need to tell the Eval Harness where to look for YAML files.
|
310 |
+
|
311 |
+
You can do this via the `--include_path` argument in `__main__.py`. This command will be used to initialize the `TaskManager` object which you can also use for your custom scripts.
|
312 |
+
|
313 |
+
```python
|
314 |
+
task_manager = TaskManager(args.verbosity, include_path=args.include_path)
|
315 |
+
```
|
316 |
+
|
317 |
+
Passing `--tasks /path/to/yaml/file` is also accepted.
|
318 |
+
|
319 |
+
|
320 |
+
### Advanced Group Configs
|
321 |
+
|
322 |
+
While `tag` values are helpful when you want to be able to quickly and conveniently run a set of related tasks via `--tasks my_tag_name`, often, we wish to implement more complex logic. For example, the MMLU benchmark contains 57 *subtasks* that must all be *averaged* together in order to report a final 'MMLU score'.
|
323 |
+
|
324 |
+
Groupings of tasks might also use particular variants of a task--for example, we might want to default to evaluating a task as 5-shot when called as part of a given grouping, but not have a preference for number of shots when evaluating it as a standalone.
|
325 |
+
|
326 |
+
We implement this via **groups**, which are distinct from tags. Groups can be implemented via *group config* YAML files, which are laid out similarly but slightly differently to tasks' YAML configs.
|
327 |
+
|
328 |
+
The most basic form of group can be defined via a YAML config similar to the following:
|
329 |
+
|
330 |
+
```yaml
|
331 |
+
group: nli_tasks
|
332 |
+
task:
|
333 |
+
- cb
|
334 |
+
- anli_r1
|
335 |
+
- rte
|
336 |
+
metadata:
|
337 |
+
version: 1.0
|
338 |
+
```
|
339 |
+
|
340 |
+
This will behave almost identically to a `tag` that includes these 3 tasks, but with one key distinction: we'll print the `nli_tasks` group as a row (with no associated metrics) in our table of outputs, and visually show that these 3 tasks appear under its subheader.
|
341 |
+
|
342 |
+
|
343 |
+
Now, let's assume we actually want to report an aggregate score for `nli_tasks`. We would instead use a YAML config like the following:
|
344 |
+
|
345 |
+
```yaml
|
346 |
+
group: nli_tasks
|
347 |
+
task:
|
348 |
+
- cb
|
349 |
+
- anli_r1
|
350 |
+
- rte
|
351 |
+
aggregate_metric_list:
|
352 |
+
- metric: acc
|
353 |
+
aggregation: mean
|
354 |
+
weight_by_size: true # defaults to `true`. Set this to `false` to do a "macro" average (taking each subtask's average accuracy, and summing those accuracies and dividing by 3)--by default we do a "micro" average (retain all subtasks' per-document accuracies, and take the mean over all documents' accuracies to get our aggregate mean).
|
355 |
+
metadata:
|
356 |
+
version: 1.0
|
357 |
+
```
|
358 |
+
|
359 |
+
Similar to our `metric_list` for listing out the metrics we want to calculate for a given task, we use an `aggregate_metric_list` field to specify which metric name to aggregate across subtasks, what aggregation function to use, and whether we should micro- or macro- average these metrics. See [./task_guide.md](./task_guide.md) for a full list of related sub-keys.
|
360 |
+
|
361 |
+
**[!Tip]: currently, we predominantly only support the aggregation of group metrics that use `mean` (either micro- or macro- averaged) over their subtasks. If you require even more complex aggregation rules, you may want to perform aggregation offline.**
|
362 |
+
|
363 |
+
Group configs can be fairly complex! We can do various operations, such as defining new subtask(s) inline in our group YAML, overriding an existing task's specific config value, or nesting existing groups within our
|
364 |
+
|
365 |
+
For example, let's build a config for evaluating MMLU and a few natural language inference tasks. For MMLU, we can write the name for the benchmark as a subtask written under `task`. You can configure the parameters such as `num_fewshot`. If the task being configured is a group such as `mmlu` or `super_glue`, the parameter set will be applied to all of the subtasks.
|
366 |
+
|
367 |
+
```yaml
|
368 |
+
group: nli_and_mmlu
|
369 |
+
task:
|
370 |
+
- group: nli_tasks
|
371 |
+
task:
|
372 |
+
- cb
|
373 |
+
- anli_r1
|
374 |
+
- rte
|
375 |
+
aggregate_metric_list:
|
376 |
+
- metric: acc
|
377 |
+
aggregation: mean
|
378 |
+
higher_is_better: true
|
379 |
+
- task: mmlu
|
380 |
+
num_fewshot: 2
|
381 |
+
```
|
382 |
+
|
383 |
+
### Configuring python classes
|
384 |
+
|
385 |
+
There can occasions when yaml-based tasks cannot accommodate how a task is handled. LM-Eval supports the manually implementing tasks as was previously done before `0.4.x`. To register the task, you can simply make a yaml with the name of the task in `task` and the class object in `class` using the `!function` prefix.
|
386 |
+
|
387 |
+
```yaml
|
388 |
+
task: squadv2
|
389 |
+
class: !function task.SQuAD2
|
390 |
+
```
|
391 |
+
|
392 |
+
This also applies to building group configurations with subtasks that are python classes.
|
393 |
+
|
394 |
+
```yaml
|
395 |
+
group: scrolls
|
396 |
+
task:
|
397 |
+
- task: scrolls_qasper
|
398 |
+
class: !function task.Qasper
|
399 |
+
- task: scrolls_quality
|
400 |
+
class: !function task.QuALITY
|
401 |
+
- task: scrolls_narrativeqa
|
402 |
+
class: !function task.NarrativeQA
|
403 |
+
...
|
404 |
+
```
|
405 |
+
|
406 |
+
You can also pass a custom argument to your class by accepting `config` in the custom class constructor.
|
407 |
+
Here's how to do it:
|
408 |
+
|
409 |
+
```yaml
|
410 |
+
task: 20_newsgroups
|
411 |
+
class: !function task.Unitxt
|
412 |
+
recipe: card=cards.20_newsgroups,template=templates.classification.multi_class.title
|
413 |
+
```
|
414 |
+
|
415 |
+
In this example, `recipe` is the custom argument for the `Unitxt` class.
|
416 |
+
|
417 |
+
## Beautifying Table Display
|
418 |
+
|
419 |
+
To avoid conflict, each task needs to be registered with a unique name. Because of this, slight variations of task are still counted as unique tasks and need to be named uniquely. This could be done by appending an additional naming that may refer to the variation such as in MMLU where the template used to evaluated for flan are differentiated from the default by the prefix `mmlu_flan_*`. Printing the full task names can easily clutter the results table at the end of the evaluation especially when you have a long list of tasks or are using a benchmark that comprises of many tasks. To make it more legible, you can use `task_alias` and `group_alias` to provide an alternative task name and group name that will be printed. For example in `mmlu_abstract_algebra.yaml` we set `task_alias` to `abstract_algebra`. In group configs, a `group_alias` for a group can also be set.
|
420 |
+
|
421 |
+
```
|
422 |
+
"dataset_name": "abstract_algebra"
|
423 |
+
"description": "The following are multiple choice questions (with answers) about abstract\
|
424 |
+
\ algebra.\n\n"
|
425 |
+
"include": "_default_template_yaml"
|
426 |
+
"task": "mmlu_abstract_algebra"
|
427 |
+
"task_alias": "abstract_algebra"
|
428 |
+
```
|
429 |
+
|
430 |
+
## Checking validity
|
431 |
+
|
432 |
+
After registering your task, you can now check on your data downloading and verify that the few-shot samples look as intended. Run the following command with your desired args:
|
433 |
+
|
434 |
+
```bash
|
435 |
+
python -m scripts.write_out \
|
436 |
+
--output_base_path <path> \
|
437 |
+
--tasks <your-task-name> \
|
438 |
+
--sets <train | val | test> \
|
439 |
+
--num_fewshot K \
|
440 |
+
--num_examples N \
|
441 |
+
```
|
442 |
+
|
443 |
+
Open the file specified at the `--output_base_path <path>` and ensure it passes
|
444 |
+
a simple eye test.
|
445 |
+
|
446 |
+
## Versioning
|
447 |
+
|
448 |
+
One key feature in LM Evaluation Harness is the ability to version tasks and groups--that is, mark them with a specific version number that can be bumped whenever a breaking change is made.
|
449 |
+
|
450 |
+
This version info can be provided by adding the following to your new task or group config file:
|
451 |
+
|
452 |
+
```
|
453 |
+
metadata:
|
454 |
+
version: 0
|
455 |
+
```
|
456 |
+
|
457 |
+
Now, whenever a change needs to be made to your task in the future, please increase the version number by 1 so that users can differentiate the different task iterations and versions.
|
458 |
+
|
459 |
+
If you are incrementing a task's version, please also consider adding a changelog to the task's README.md noting the date, PR number, what version you have updated to, and a one-liner describing the change.
|
460 |
+
|
461 |
+
for example,
|
462 |
+
|
463 |
+
* \[Dec 25, 2023\] (PR #999) Version 0.0 -> 1.0: Fixed a bug with answer extraction that led to underestimated performance.
|
464 |
+
|
465 |
+
## Checking performance + equivalence
|
466 |
+
|
467 |
+
It's now time to check models' performance on your task! In the evaluation harness, we intend to support a wide range of evaluation tasks and setups, but prioritize the inclusion of already-proven benchmarks following the precise evaluation setups in the literature where possible.
|
468 |
+
|
469 |
+
To enable this, we provide a checklist that should be completed when contributing a new task, to enable accurate book-keeping and to ensure that tasks added to the library are well-tested and, where applicable, precedented.
|
470 |
+
|
471 |
+
### Task Validity Checklist
|
472 |
+
|
473 |
+
The checklist is the following:
|
474 |
+
|
475 |
+
For adding novel benchmarks/datasets to the library:
|
476 |
+
* [ ] Is the task an existing benchmark in the literature?
|
477 |
+
* [ ] Have you referenced the original paper that introduced the task?
|
478 |
+
* [ ] If yes, does the original paper provide a reference implementation? If so, have you checked against the reference implementation and documented how to run such a test?
|
479 |
+
|
480 |
+
|
481 |
+
If other tasks on this dataset are already supported:
|
482 |
+
* [ ] Is the "Main" variant of this task clearly denoted?
|
483 |
+
* [ ] Have you provided a short sentence in a README on what each new variant adds / evaluates?
|
484 |
+
* [ ] Have you noted which, if any, published evaluation setups are matched by this variant?
|
485 |
+
|
486 |
+
It is recommended to include a filled-out copy of this checklist in the README.md for the subfolder you are creating, if you have created a new subfolder in `lm_eval/tasks`.
|
487 |
+
|
488 |
+
**Finally, please add a short description of your task(s), along with a link to its subfolder in lm_eval/tasks , to [`lm_eval/tasks/README.md`](https://github.com/EleutherAI/lm-evaluation-harness/blob/main/lm_eval/tasks/README.md) so that users can discover your task in the library, and follow the link to your README for more information about the variants supported, their task names, and the original source of the dataset and/or evaluation setup.**
|
489 |
+
|
490 |
+
## Submitting your task
|
491 |
+
|
492 |
+
You're all set! Now push your work and make a pull request to the `main` branch! Thanks for the contribution :). If there are any questions, please leave a message in the `#lm-thunderdome` channel on the EAI discord!
|
scripts/yans/lm-evaluation-harness/docs/task_guide.md
ADDED
@@ -0,0 +1,317 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Task Configuration
|
2 |
+
|
3 |
+
The `lm-evaluation-harness` is meant to be an extensible and flexible framework within which many different evaluation tasks can be defined. All tasks in the new version of the harness are built around a YAML configuration file format.
|
4 |
+
|
5 |
+
These YAML configuration files, along with the current codebase commit hash, are intended to be shareable such that providing the YAML config enables another researcher to precisely replicate the evaluation setup used by another, in the case that the prompt or setup differs from standard `lm-eval` task implementations.
|
6 |
+
|
7 |
+
While adding a standard evaluation task on a new dataset can be occasionally as simple as swapping out a Hugging Face dataset path in an existing file, more specialized evaluation setups also exist. Here we'll provide a crash course on the more advanced logic implementable in YAML form available to users.
|
8 |
+
|
9 |
+
If your intended task relies on features beyond what are described in this guide, we'd love to hear about it! Feel free to open an issue describing the scenario on Github, create a PR to the project with a proposed implementation, or ask in the `#lm-thunderdome` channel on the EleutherAI discord.
|
10 |
+
|
11 |
+
## Configurations
|
12 |
+
|
13 |
+
Tasks are configured via the `TaskConfig` object. Below, we describe all fields usable within the object, and their role in defining a task.
|
14 |
+
|
15 |
+
### Parameters
|
16 |
+
|
17 |
+
Task naming + registration:
|
18 |
+
- **task** (`str`, defaults to None) — name of the task.
|
19 |
+
- **task_alias** (`str`, defaults to None) - Alias of the task name that will be printed in the final table results.
|
20 |
+
- **tag** (`str`, *optional*) — name of the task tags(s) a task belongs to. Enables one to run all tasks with a specified tag name at once.
|
21 |
+
|
22 |
+
Dataset configuration options:
|
23 |
+
- **dataset_path** (`str`) — The name of the dataset as listed by HF in the datasets Hub.
|
24 |
+
- **dataset_name** (`str`, *optional*, defaults to None) — The name of what HF calls a “data instance” or sub-task of the benchmark. If your task does not contain any data instances, just leave this to default to None. (If you're familiar with the HF `datasets.load_dataset` function, these are just the first 2 arguments to it.)
|
25 |
+
- **dataset_kwargs** (`dict`, *optional*) — Auxiliary arguments that `datasets.load_dataset` accepts. This can be used to specify arguments such as `data_files` or `data_dir` if you want to use local datafiles such as json or csv.
|
26 |
+
- **training_split** (`str`, *optional*) — Split in the dataset to use as the training split.
|
27 |
+
- **validation_split** (`str`, *optional*) — Split in the dataset to use as the validation split.
|
28 |
+
- **test_split** (`str`, *optional*) — Split in the dataset to use as the test split.
|
29 |
+
- **fewshot_split** (`str`, *optional*) — Split in the dataset to draw few-shot exemplars from. assert that this not None if num_fewshot > 0.
|
30 |
+
- **process_docs** (`Callable`, *optional*) — Optionally define a function to apply to each HF dataset split, to preprocess all documents before being fed into prompt template rendering or other evaluation steps. Can be used to rename dataset columns, or to process documents into a format closer to the expected format expected by a prompt template.
|
31 |
+
|
32 |
+
Prompting / in-context formatting options:
|
33 |
+
- **use_prompt** (`str`, *optional*) — Name of prompt in promptsource to use. if defined, will overwrite doc_to_text, doc_to_target, and doc_to_choice.
|
34 |
+
- **description** (`str`, *optional*) — An optional prepended Jinja2 template or string which will be prepended to the few-shot examples passed into the model, often describing the task or providing instructions to a model, such as `"The following are questions (with answers) about {{subject}}.\n\n"`. No delimiters or spacing are inserted between the description and the first few-shot example.
|
35 |
+
- **doc_to_text** (`Union[Callable, str]`, *optional*) — Jinja2 template, string, or function to process a sample into the appropriate input for the model.
|
36 |
+
- **doc_to_target** (`Union[Callable, str]`, *optional*) — Jinja2 template, string, or function to process a sample into the appropriate target output for the model. For multiple choice tasks, this should return an index into the answer choice list of the correct answer.
|
37 |
+
- **doc_to_choice** (`Union[Callable, str]`, *optional*) — Jinja2 template, string, or function to process a sample into a list of possible string choices for `multiple_choice` tasks. Left undefined for `generate_until` tasks.
|
38 |
+
- **fewshot_delimiter** (`str`, *optional*, defaults to "\n\n") — String to insert between few-shot examples.
|
39 |
+
- **target_delimiter** (`str`, *optional*, defaults to `" "`) — String to insert between input and target output for the datapoint being tested.
|
40 |
+
|
41 |
+
Runtime configuration options:
|
42 |
+
- **num_fewshot** (`int`, *optional*, defaults to 0) — Number of few-shot examples before the input.
|
43 |
+
- **batch_size** (`int`, *optional*, defaults to 1) — Batch size.
|
44 |
+
|
45 |
+
Scoring details:
|
46 |
+
- **metric_list** (`str`, *optional*, defaults to None) — A list of metrics to use for evaluation. See docs for expected format.
|
47 |
+
- **output_type** (`str`, *optional*, defaults to "generate_until") — Selects the type of model output for the given task. Options are `generate_until`, `loglikelihood`, `loglikelihood_rolling`, and `multiple_choice`.
|
48 |
+
- **generation_kwargs** (`dict`, *optional*) — Auxiliary arguments for the `generate` function from HF transformers library. Advanced keyword arguments may not be supported for non-HF LM classes.
|
49 |
+
- **repeats** (`int`, *optional*, defaults to 1) — Number of repeated runs through model for each sample. can be used for cases such as self-consistency.
|
50 |
+
- **filter_list** (`Union[str, list]`, *optional*) — List of filters to postprocess model outputs. See below for further detail on the filter API.
|
51 |
+
- **should_decontaminate** (`bool`, *optional*, defaults to False) - Whether to decontaminate or not.
|
52 |
+
- **doc_to_decontamination_query** (`str`, *optional*) — Query for decontamination if `should_decontaminate` is True. If `should_decontaminate` is True but `doc_to_decontamination_query` is `None`, `doc_to_decontamination_query` will follow `doc_to_text`.
|
53 |
+
|
54 |
+
Other:
|
55 |
+
- **metadata** (`dict`, *optional*) — An optional field where arbitrary metadata can be passed. Most tasks should include a `version` key in this field that is used to denote the version of the yaml config. Other special metadata keys are: `num_fewshot`, to override the printed `n-shot` table column for a task.
|
56 |
+
|
57 |
+
## Filters
|
58 |
+
|
59 |
+
A key component of the `lm-evaluation-harness` library is the `Filter` object. In a typical evaluation run of the harness, we take the formatted inputs and run them through our LM, with the appropriate output type (greedy or free-form generation, or loglikelihood-based comparative scoring).
|
60 |
+
|
61 |
+
After getting scores or output text from our LM on each `Instance` or document in the dataset, we then need to feed these responses into a metric or scoring function to return scores to a user.
|
62 |
+
|
63 |
+
However, certain tasks may require more complex behavior than directly turning over model outputs to a metric function. For example, we may want to post-process our output text by truncating it or extracting a model's answer, we may want to ensemble over multiple "takes" on a different document, et cetera.
|
64 |
+
|
65 |
+
**Detailed Aside**:
|
66 |
+
We do such post-processing by operating on *responses*, which are stored after running an LM on an `Instance` from the task in `Instance.resps`.
|
67 |
+
|
68 |
+
`resps` is a `List[str]` for each instance, and we pass a `List[List[<expected return type from model>]]` to our filters that is a list of `[instance.resps for instance in instances]`.
|
69 |
+
|
70 |
+
Our filters, after completing a pipeline, must return a `List[<expected return type from model>]` which we then unpack and store each element of in `Instance.filtered_resps` for the corresponding instance. Thus, we take as input a list of returns from our model for each doc, and must return a return from our model *without it being wrapped in a list* for each doc.
|
71 |
+
|
72 |
+
**End Aside**
|
73 |
+
|
74 |
+
|
75 |
+
A full list of supported filter operations can be found in `lm_eval/filters/__init__.py`. Contributions of new filter types are welcome!
|
76 |
+
|
77 |
+
### Multiple Filter Pipelines
|
78 |
+
|
79 |
+
Tasks need not be limited to a single filter pipeline. We enable users to run multiple, distinct, filter pipelines on *the same model outputs* generated in one run on a task.
|
80 |
+
|
81 |
+
As a case study, let's look at an implementation of solving the Gsm8k math word problem benchmark in `lm_eval/tasks/gsm8k/gsm8k-cot-self-consistency.yaml`. Here, we are emulating the setup used by [Self-Consistency Improves Chain of Thought Prompting](https://arxiv.org/abs/2203.11171), in which evaluation is performed by generating N chain-of-thought outputs from a model via temperature-based sampling, then selecting the answers output by the model at the end of the chains of thought, then majority voting across all those numeric answers.
|
82 |
+
|
83 |
+
Within our YAML file:
|
84 |
+
|
85 |
+
```yaml
|
86 |
+
...
|
87 |
+
repeats: 64
|
88 |
+
filter_list:
|
89 |
+
- name: "score-first"
|
90 |
+
filter:
|
91 |
+
- function: "regex"
|
92 |
+
regex_pattern: "The answer is (\\-?[0-9\\.\\,]*[0-9]+)"
|
93 |
+
- function: "take_first"
|
94 |
+
- name: "maj@64"
|
95 |
+
filter:
|
96 |
+
- function: "regex"
|
97 |
+
regex_pattern: "The answer is (\\-?[0-9\\.\\,]*[0-9]+)"
|
98 |
+
- function: "majority_vote"
|
99 |
+
- function: "take_first"
|
100 |
+
- name: "maj@8"
|
101 |
+
filter:
|
102 |
+
- function: "take_first_k"
|
103 |
+
k: 8
|
104 |
+
- function: "regex"
|
105 |
+
regex_pattern: "The answer is (\\-?[0-9\\.\\,]*[0-9]+)"
|
106 |
+
- function: "majority_vote"
|
107 |
+
- function: "take_first"
|
108 |
+
```
|
109 |
+
|
110 |
+
We are able to provide multiple different filter pipelines, each with their own name and list of filters to apply in sequence.
|
111 |
+
|
112 |
+
Our first filter pipeline implements
|
113 |
+
- applying a regex to the model generations (extracting the number within the phrase "The answer is (number)")
|
114 |
+
- selecting only the first out of the 64 model answers
|
115 |
+
|
116 |
+
Then scoring this single answer.
|
117 |
+
|
118 |
+
```yaml
|
119 |
+
- name: "score-first"
|
120 |
+
filter:
|
121 |
+
- function: "regex"
|
122 |
+
regex_pattern: "The answer is (\\-?[0-9\\.\\,]*[0-9]+)"
|
123 |
+
- function: "take_first"
|
124 |
+
```
|
125 |
+
|
126 |
+
Our second filter pipeline, "maj@64", does majority voting across all 64 answers via:
|
127 |
+
- applying the same regex to all responses, to get the numerical answer from the model for each of the 64 responses per problem
|
128 |
+
- applying majority voting to all responses, which then returns a length-1 `[<majority answer>]` list for each
|
129 |
+
- taking the first element of this length-1 list, to then score the sole response `<majority answer>` for each document.
|
130 |
+
|
131 |
+
```yaml
|
132 |
+
- name: "maj@64"
|
133 |
+
filter:
|
134 |
+
- function: "regex"
|
135 |
+
regex_pattern: "The answer is (\\-?[0-9\\.\\,]*[0-9]+)"
|
136 |
+
- function: "majority_vote"
|
137 |
+
- function: "take_first"
|
138 |
+
```
|
139 |
+
|
140 |
+
Our final filter pipeline, "maj@8", does majority voting across the first 8 of the model's responses per document via:
|
141 |
+
- subsetting the len-64 list of responses `[answer1, answer2, ..., answer64]` to `[answer1, answer2, ..., answer8]` for each document
|
142 |
+
- performing the same sequence of filters on these new sets of 8 responses, for each document.
|
143 |
+
```yaml
|
144 |
+
- name: "maj@8"
|
145 |
+
filter:
|
146 |
+
- function: "take_first_k"
|
147 |
+
k: 8
|
148 |
+
- function: "regex"
|
149 |
+
regex_pattern: "The answer is (\\-?[0-9\\.\\,]*[0-9]+)"
|
150 |
+
- function: "majority_vote"
|
151 |
+
- function: "take_first"
|
152 |
+
```
|
153 |
+
|
154 |
+
Thus, given the 64 responses from our LM on each document, we can report metrics on these responses in these 3 different ways, as defined by our filter pipelines.
|
155 |
+
|
156 |
+
|
157 |
+
### Adding a custom filter
|
158 |
+
|
159 |
+
Just like adding a custom model with `register_model` decorator one is able to do the same with filters, for example
|
160 |
+
|
161 |
+
```python
|
162 |
+
from lm_eval.api.filter import Filter
|
163 |
+
from lm_eval.api.registry import register_filter
|
164 |
+
|
165 |
+
@register_filter("new_filter")
|
166 |
+
class NewFilter(Filter)
|
167 |
+
...
|
168 |
+
```
|
169 |
+
|
170 |
+
|
171 |
+
|
172 |
+
## Embedded Python Code
|
173 |
+
|
174 |
+
Use can use python functions for certain arguments by using the `!function` operator after the argument name followed by `<filename>.<pythonfunctionname>`. This feature can be used for the following arguments:
|
175 |
+
1. `doc_to_text`
|
176 |
+
2. `doc_to_target`
|
177 |
+
3. `doc_to_choice`
|
178 |
+
4. `aggregation` for a `metric` in `metric_list`
|
179 |
+
|
180 |
+
## (No Longer Recommended) Direct `Task` Subclassing
|
181 |
+
|
182 |
+
The prior implementation method of new tasks was to subclass `Task`. While we intend to migrate all tasks to the new YAML implementation option going forward, it remains possible to subclass the Task class and implement custom logic. For more information, see `docs/task_guide.md` in v0.3.0 of the `lm-evaluation-harness`.
|
183 |
+
|
184 |
+
|
185 |
+
## Including a Base YAML
|
186 |
+
|
187 |
+
You can base a YAML on another YAML file as a template. This can be handy when you need to just change the prompt for `doc_to_text` but keep the rest the same or change `filters` to compare which is better. Simply use `include` in the YAML file and write the name of the template you want to base from. This assumes that the base temeplate is in the same directory. Otherwise, You will need to define the full path.
|
188 |
+
```
|
189 |
+
include: <YAML filename or with full path>
|
190 |
+
...
|
191 |
+
```
|
192 |
+
You can find an example of how to use this feature at [gsm8k-cot-self-consistency.yaml](https://github.com/EleutherAI/lm-evaluation-harness/blob/main/lm_eval/tasks/gsm8k/gsm8k-cot-self-consistency.yaml) where it is based off [gsm8k-cot.yaml](https://github.com/EleutherAI/lm-evaluation-harness/blob/main/lm_eval/tasks/gsm8k/gsm8k-cot.yaml)
|
193 |
+
|
194 |
+
|
195 |
+
## Passing Arguments to Metrics
|
196 |
+
|
197 |
+
Metrics can be defined in the `metric_list` argument when building the YAML config. Multiple metrics can be listed along with any auxiliary arguments. For example, setting the [`exact_match` metric](https://github.com/huggingface/evaluate/tree/main/metrics/exact_match), auxiliary arguments such as `ignore_case`, `ignore_punctuation`, `regexes_to_ignore` can be listed as well. They will be added to the metric function as `kwargs`. Some metrics have predefined values for `aggregation` and `higher_is_better` so listing the metric name only can be sufficient.
|
198 |
+
|
199 |
+
```
|
200 |
+
metric_list:
|
201 |
+
- metric: acc
|
202 |
+
- metric: exact_match
|
203 |
+
aggregation: mean
|
204 |
+
higher_is_better: true
|
205 |
+
ignore_case: true
|
206 |
+
ignore_punctuation: false
|
207 |
+
regexes_to_ignore:
|
208 |
+
- ","
|
209 |
+
- "\\$"
|
210 |
+
```
|
211 |
+
|
212 |
+
### Natively Supported Metrics
|
213 |
+
|
214 |
+
Here we list all metrics currently supported natively in `lm-eval`:
|
215 |
+
|
216 |
+
Metrics:
|
217 |
+
* `acc` (accuracy)
|
218 |
+
* `acc_norm` (length-normalized accuracy)
|
219 |
+
* `acc_mutual_info` (baseline loglikelihood - normalized accuracy)
|
220 |
+
* `perplexity`
|
221 |
+
* `word_perplexity` (perplexity per word)
|
222 |
+
* `byte_perplexity` (perplexity per byte)
|
223 |
+
* `bits_per_byte`
|
224 |
+
* `matthews_corrcoef` (Matthews correlation coefficient)
|
225 |
+
* `f1` (F1 score)
|
226 |
+
* `bleu`
|
227 |
+
* `chrf`
|
228 |
+
* `ter`
|
229 |
+
|
230 |
+
Aggregation functions:
|
231 |
+
* `mean`
|
232 |
+
* `median`
|
233 |
+
* `perplexity`
|
234 |
+
* `weighted_perplexity`
|
235 |
+
* `bits_per_byte`
|
236 |
+
|
237 |
+
### Adding a Multiple Choice Metric
|
238 |
+
|
239 |
+
Adding a multiple choice metric has a few steps. To get it working you need to:
|
240 |
+
|
241 |
+
1. register a metric function
|
242 |
+
2. register an aggregation function
|
243 |
+
3. update the `Task` definition to make sure the correct arguments are passed
|
244 |
+
|
245 |
+
The default metric and aggregation functions are in `lm_eval/api/metrics.py`, and you can add a function there if it's for general use. The metrics are towards the bottom of the file and look like this:
|
246 |
+
|
247 |
+
|
248 |
+
@register_metric(
|
249 |
+
metric="mcc",
|
250 |
+
higher_is_better=True,
|
251 |
+
output_type="multiple_choice",
|
252 |
+
aggregation="matthews_corrcoef",
|
253 |
+
)
|
254 |
+
def mcc_fn(items): # This is a passthrough function
|
255 |
+
return items
|
256 |
+
|
257 |
+
Note that many of these are passthrough functions, and for multiple choice (at least) this function is never actually called.
|
258 |
+
|
259 |
+
Aggregation functions are defined towards the top of the file, here's an example:
|
260 |
+
|
261 |
+
@register_aggregation("matthews_corrcoef")
|
262 |
+
def matthews_corrcoef(items):
|
263 |
+
unzipped_list = list(zip(*items))
|
264 |
+
golds = unzipped_list[0]
|
265 |
+
preds = unzipped_list[1]
|
266 |
+
return sklearn.metrics.matthews_corrcoef(golds, preds)
|
267 |
+
|
268 |
+
This function returns a single numeric value. The input is defined in `Task.process_results` in `lm_eval/api/task.py`. There's a section that looks like this:
|
269 |
+
|
270 |
+
|
271 |
+
result_dict = {
|
272 |
+
**({"acc": acc} if "acc" in use_metric else {}),
|
273 |
+
**({"f1": (gold, pred)} if "f1" in use_metric else {}),
|
274 |
+
**({"mcc": (gold, pred)} if "mcc" in use_metric else {}),
|
275 |
+
**({"acc_norm": acc_norm} if "acc_norm" in use_metric else {}),
|
276 |
+
**({"exact_match": exact_match} if "exact_match" in use_metric else {}),
|
277 |
+
}
|
278 |
+
|
279 |
+
The value here determines the input to the aggregation function, though the name used matches the metric function. These metrics all have simple needs and just need the accuracy or gold and predicted values, but immediately below this there are examples of metrics with more complicated needs you can use as reference.
|
280 |
+
|
281 |
+
## Good Reference Tasks
|
282 |
+
|
283 |
+
Contributing a new task can be daunting! Luckily, much of the work has often been done for you in a different, similarly evaluated task. Good examples of task implementations to study include:
|
284 |
+
|
285 |
+
Multiple choice tasks:
|
286 |
+
- SciQ (`lm_eval/tasks/sciq/sciq.yaml`)
|
287 |
+
|
288 |
+
Corpus perplexity evaluations:
|
289 |
+
- Wikitext (`lm_eval/tasks/wikitext/wikitext.yaml`)
|
290 |
+
|
291 |
+
Generative tasks:
|
292 |
+
- GSM8k (`lm_eval/tasks/gsm8k/gsm8k.yaml`)
|
293 |
+
|
294 |
+
Tasks using complex filtering:
|
295 |
+
- GSM8k with CoT (+ with Self-Consistency): (`lm_eval/tasks/gsm8k/gsm8k-cot.yaml` ; `lm_eval/tasks/gsm8k/gsm8k-cot-self-consistency.yaml`)
|
296 |
+
|
297 |
+
# Group Configuration
|
298 |
+
|
299 |
+
When evaluating a language model, it's is not unusual to test across a number of tasks that may not be related to one another in order to assess a variety of capabilities. To this end, it may be combursome to have to list the set of tasks or add a new group name to each yaml of each individual task.
|
300 |
+
|
301 |
+
To solve this, we can create a **group** yaml config. This is a config that contains the names of the tasks that should be included in a particular group. The config consists of two main keys: a `group` key which denotes the name of the group (as it would be called from the command line, e.g. `mmlu`) and a `task` key which is where we can list the tasks. The tasks listed in `task` are the task names that have been registered. A good example of a group yaml config can be found at [../lm_eval/tasks/mmlu/default/_mmlu.yaml]. See also the [New Task Guide](./new_task_guide.md) for a more in-depth and tutorial-esque explanation of how to write complex GroupConfigs.
|
302 |
+
|
303 |
+
## Configurations
|
304 |
+
|
305 |
+
Groups are configured via the `GroupConfig` object. Below, we describe all fields usable within the object, and their role in defining a task.
|
306 |
+
|
307 |
+
### Parameters
|
308 |
+
|
309 |
+
- **group** (`str`, defaults to `None`) — name of the group. Used to invoke it from the command line.
|
310 |
+
- **group_alias** (`str`, defaults to `None`) - Alternative name for the group that will be printed in the table output.
|
311 |
+
- **task** (`Union[str, list]`, defaults to `None`) - List of tasks that constitute the group.
|
312 |
+
- **aggregate_metric_list** (`list`, defaults to `None`) - similar to `metric_list` in TaskConfigs, provide a list of configurations for metrics that should be aggregated across subtasks. Leaving empty will result in no aggregation being performed for this group. Keys for each list entry are:
|
313 |
+
- `metric: str` - the name of the metric to aggregate over (all subtasks must report a metric holding this name.)
|
314 |
+
- `aggregation: str` - what aggregation function to apply to aggregate these per-subtask metrics. **currently, only `mean` is supported.**
|
315 |
+
- `weight_by_size: bool = True` whether to perform micro- averaging (`True`) or macro- (`False`) averaging of subtasks' accuracy scores when reporting the group's metric. MMLU, for example, averages over per-document accuracies (the *micro average*), resulting in the same accuracy as if one simply concatenated all 57 subjects into a single dataset and evaluated accuracy on that dataset.
|
316 |
+
- `filter_list: Union[str, List[str]] = "none"` - what filter keys one should match on to aggregate results. For example, if trying to aggregate over the `exact_match` metric using `strict-match` filter for `bbh_cot_zeroshot`, then set this to be `filter_list: "strict-match"`.
|
317 |
+
- **metadata** (`dict`, *optional*) - As with TaskConfigs, a field where extra config metadata can be passed. set the `num_fewshot` key within this to override the printed n_shot value in a results table for your group, for example.
|
scripts/yans/lm-evaluation-harness/eval.sh
ADDED
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
lm_eval --model hf \
|
2 |
+
--model_args pretrained=/project/models/yans-quen2-0.5B/iter_0000990 \
|
3 |
+
--tasks hellaswag \
|
4 |
+
--device cuda:0 \
|
5 |
+
--batch_size 8
|
scripts/yans/lm-evaluation-harness/eval2.sh
ADDED
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
lm_eval --model hf \
|
2 |
+
--model_args pretrained=/share/pretrained_lm/Qwen/Qwen2-0.5B\
|
3 |
+
--tasks hellaswag,openbookqa,arc_easy,winogrande,hellaswag,arc_challenge,piqa,boolq \
|
4 |
+
--device cuda:0 \
|
5 |
+
--batch_size 8
|
scripts/yans/lm-evaluation-harness/eval3.sh
ADDED
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
lm_eval --model hf \
|
2 |
+
--model_args pretrained=/project/models/1_qwen2-0.5B \
|
3 |
+
--tasks hellaswag \
|
4 |
+
--device cuda:0 \
|
5 |
+
--batch_size 8
|
scripts/yans/lm-evaluation-harness/eval4.sh
ADDED
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
lm_eval --model hf \
|
2 |
+
--model_args pretrained=/project/models/1_qwen2-0.5B \
|
3 |
+
--tasks openbookqa,arc_easy,winogrande,hellaswag,arc_challenge,piqa,boolq,hellaswag \
|
4 |
+
--device cuda:0 \
|
5 |
+
--batch_size 8
|
scripts/yans/lm-evaluation-harness/examples/lm-eval-overview.ipynb
ADDED
@@ -0,0 +1,1230 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"cells": [
|
3 |
+
{
|
4 |
+
"cell_type": "markdown",
|
5 |
+
"metadata": {
|
6 |
+
"id": "Qw83KAePAhaS"
|
7 |
+
},
|
8 |
+
"source": [
|
9 |
+
"# Releasing LM-Evaluation-Harness v0.4.0"
|
10 |
+
]
|
11 |
+
},
|
12 |
+
{
|
13 |
+
"cell_type": "markdown",
|
14 |
+
"metadata": {
|
15 |
+
"id": "Z7k2vq1iAdqr"
|
16 |
+
},
|
17 |
+
"source": [
|
18 |
+
"With the vast amount of work done in the field today, it helps to have a tool that people can use easily to share their results and use to check others to ensure reported numbers are valid. The LM Evaluation Harness is one such tool the community has used extensively. We want to continue to support the community and with that in mind, we’re excited to announce a major update on the LM Evaluation Harness to further our goal for open and accessible AI research."
|
19 |
+
]
|
20 |
+
},
|
21 |
+
{
|
22 |
+
"cell_type": "markdown",
|
23 |
+
"metadata": {
|
24 |
+
"id": "0gDoM0AJAvEc"
|
25 |
+
},
|
26 |
+
"source": [
|
27 |
+
"Our refactor stems from our desires to make the following believed best practices easier to carry out. \n",
|
28 |
+
"\n",
|
29 |
+
"1. Never copy results from other papers\n",
|
30 |
+
"2. Always share your exact prompts\n",
|
31 |
+
"3. Always provide model outputs\n",
|
32 |
+
"4. Qualitatively review a small batch of outputs before running evaluation jobs at scale\n",
|
33 |
+
"\n",
|
34 |
+
"We also wanted to make the library a better experience to use and to contribute or design evaluations within. New features in the new release that serve this purpose include:\n",
|
35 |
+
"\n",
|
36 |
+
"1. Faster Evaluation Runtimes (accelerated data-parallel inference with HF Transformers + Accelerate, and commonly used or faster inference libraries such as vLLM and Llama-CPP)\n",
|
37 |
+
"2. Easier addition and sharing of new tasks (YAML-based task config formats, allowing single-file sharing of custom tasks)\n",
|
38 |
+
"3. More configurability, for more advanced workflows and easier operation with modifying prompts\n",
|
39 |
+
"4. Better logging of data at runtime and post-hoc"
|
40 |
+
]
|
41 |
+
},
|
42 |
+
{
|
43 |
+
"cell_type": "markdown",
|
44 |
+
"metadata": {
|
45 |
+
"id": "nnwsOpjda_YW"
|
46 |
+
},
|
47 |
+
"source": [
|
48 |
+
"In this notebook we will be going through a short tutorial on how things work."
|
49 |
+
]
|
50 |
+
},
|
51 |
+
{
|
52 |
+
"cell_type": "markdown",
|
53 |
+
"metadata": {
|
54 |
+
"id": "zAov81vTbL2K"
|
55 |
+
},
|
56 |
+
"source": [
|
57 |
+
"## Install LM-Eval"
|
58 |
+
]
|
59 |
+
},
|
60 |
+
{
|
61 |
+
"cell_type": "code",
|
62 |
+
"execution_count": 1,
|
63 |
+
"metadata": {
|
64 |
+
"colab": {
|
65 |
+
"base_uri": "https://localhost:8080/"
|
66 |
+
},
|
67 |
+
"id": "8hiosGzq_qZg",
|
68 |
+
"outputId": "6ab73e5e-1f54-417e-a388-07e0d870b132"
|
69 |
+
},
|
70 |
+
"outputs": [
|
71 |
+
{
|
72 |
+
"name": "stdout",
|
73 |
+
"output_type": "stream",
|
74 |
+
"text": [
|
75 |
+
"Collecting git+https://github.com/EleutherAI/lm-evaluation-harness.git@big-refactor\n",
|
76 |
+
" Cloning https://github.com/EleutherAI/lm-evaluation-harness.git (to revision big-refactor) to /tmp/pip-req-build-tnssql5s\n",
|
77 |
+
" Running command git clone --filter=blob:none --quiet https://github.com/EleutherAI/lm-evaluation-harness.git /tmp/pip-req-build-tnssql5s\n",
|
78 |
+
" Running command git checkout -b big-refactor --track origin/big-refactor\n",
|
79 |
+
" Switched to a new branch 'big-refactor'\n",
|
80 |
+
" Branch 'big-refactor' set up to track remote branch 'big-refactor' from 'origin'.\n",
|
81 |
+
" Resolved https://github.com/EleutherAI/lm-evaluation-harness.git to commit 42f486ee49b65926a444cb0620870a39a5b4b0a8\n",
|
82 |
+
" Installing build dependencies ... \u001b[?25l\u001b[?25hdone\n",
|
83 |
+
" Getting requirements to build wheel ... \u001b[?25l\u001b[?25hdone\n",
|
84 |
+
" Preparing metadata (pyproject.toml) ... \u001b[?25l\u001b[?25hdone\n",
|
85 |
+
"Collecting accelerate>=0.21.0 (from lm-eval==1.0.0)\n",
|
86 |
+
" Downloading accelerate-0.24.1-py3-none-any.whl (261 kB)\n",
|
87 |
+
"\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m261.4/261.4 kB\u001b[0m \u001b[31m4.1 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
|
88 |
+
"\u001b[?25hCollecting evaluate (from lm-eval==1.0.0)\n",
|
89 |
+
" Downloading evaluate-0.4.1-py3-none-any.whl (84 kB)\n",
|
90 |
+
"\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m84.1/84.1 kB\u001b[0m \u001b[31m5.9 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
|
91 |
+
"\u001b[?25hCollecting datasets>=2.0.0 (from lm-eval==1.0.0)\n",
|
92 |
+
" Downloading datasets-2.15.0-py3-none-any.whl (521 kB)\n",
|
93 |
+
"\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m521.2/521.2 kB\u001b[0m \u001b[31m9.5 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
|
94 |
+
"\u001b[?25hCollecting jsonlines (from lm-eval==1.0.0)\n",
|
95 |
+
" Downloading jsonlines-4.0.0-py3-none-any.whl (8.7 kB)\n",
|
96 |
+
"Requirement already satisfied: numexpr in /usr/local/lib/python3.10/dist-packages (from lm-eval==1.0.0) (2.8.7)\n",
|
97 |
+
"Collecting peft>=0.2.0 (from lm-eval==1.0.0)\n",
|
98 |
+
" Downloading peft-0.6.2-py3-none-any.whl (174 kB)\n",
|
99 |
+
"\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m174.7/174.7 kB\u001b[0m \u001b[31m7.2 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
|
100 |
+
"\u001b[?25hCollecting pybind11>=2.6.2 (from lm-eval==1.0.0)\n",
|
101 |
+
" Downloading pybind11-2.11.1-py3-none-any.whl (227 kB)\n",
|
102 |
+
"\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m227.7/227.7 kB\u001b[0m \u001b[31m12.9 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
|
103 |
+
"\u001b[?25hCollecting pytablewriter (from lm-eval==1.0.0)\n",
|
104 |
+
" Downloading pytablewriter-1.2.0-py3-none-any.whl (111 kB)\n",
|
105 |
+
"\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m111.1/111.1 kB\u001b[0m \u001b[31m8.3 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
|
106 |
+
"\u001b[?25hCollecting rouge-score>=0.0.4 (from lm-eval==1.0.0)\n",
|
107 |
+
" Downloading rouge_score-0.1.2.tar.gz (17 kB)\n",
|
108 |
+
" Preparing metadata (setup.py) ... \u001b[?25l\u001b[?25hdone\n",
|
109 |
+
"Collecting sacrebleu>=1.5.0 (from lm-eval==1.0.0)\n",
|
110 |
+
" Downloading sacrebleu-2.3.2-py3-none-any.whl (119 kB)\n",
|
111 |
+
"\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m119.7/119.7 kB\u001b[0m \u001b[31m8.7 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
|
112 |
+
"\u001b[?25hRequirement already satisfied: scikit-learn>=0.24.1 in /usr/local/lib/python3.10/dist-packages (from lm-eval==1.0.0) (1.2.2)\n",
|
113 |
+
"Collecting sqlitedict (from lm-eval==1.0.0)\n",
|
114 |
+
" Downloading sqlitedict-2.1.0.tar.gz (21 kB)\n",
|
115 |
+
" Preparing metadata (setup.py) ... \u001b[?25l\u001b[?25hdone\n",
|
116 |
+
"Requirement already satisfied: torch>=1.8 in /usr/local/lib/python3.10/dist-packages (from lm-eval==1.0.0) (2.1.0+cu118)\n",
|
117 |
+
"Collecting tqdm-multiprocess (from lm-eval==1.0.0)\n",
|
118 |
+
" Downloading tqdm_multiprocess-0.0.11-py3-none-any.whl (9.8 kB)\n",
|
119 |
+
"Requirement already satisfied: transformers>=4.1 in /usr/local/lib/python3.10/dist-packages (from lm-eval==1.0.0) (4.35.2)\n",
|
120 |
+
"Collecting zstandard (from lm-eval==1.0.0)\n",
|
121 |
+
" Downloading zstandard-0.22.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (5.4 MB)\n",
|
122 |
+
"\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m5.4/5.4 MB\u001b[0m \u001b[31m29.2 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
|
123 |
+
"\u001b[?25hRequirement already satisfied: numpy>=1.17 in /usr/local/lib/python3.10/dist-packages (from accelerate>=0.21.0->lm-eval==1.0.0) (1.23.5)\n",
|
124 |
+
"Requirement already satisfied: packaging>=20.0 in /usr/local/lib/python3.10/dist-packages (from accelerate>=0.21.0->lm-eval==1.0.0) (23.2)\n",
|
125 |
+
"Requirement already satisfied: psutil in /usr/local/lib/python3.10/dist-packages (from accelerate>=0.21.0->lm-eval==1.0.0) (5.9.5)\n",
|
126 |
+
"Requirement already satisfied: pyyaml in /usr/local/lib/python3.10/dist-packages (from accelerate>=0.21.0->lm-eval==1.0.0) (6.0.1)\n",
|
127 |
+
"Requirement already satisfied: huggingface-hub in /usr/local/lib/python3.10/dist-packages (from accelerate>=0.21.0->lm-eval==1.0.0) (0.19.4)\n",
|
128 |
+
"Requirement already satisfied: pyarrow>=8.0.0 in /usr/local/lib/python3.10/dist-packages (from datasets>=2.0.0->lm-eval==1.0.0) (9.0.0)\n",
|
129 |
+
"Collecting pyarrow-hotfix (from datasets>=2.0.0->lm-eval==1.0.0)\n",
|
130 |
+
" Downloading pyarrow_hotfix-0.6-py3-none-any.whl (7.9 kB)\n",
|
131 |
+
"Collecting dill<0.3.8,>=0.3.0 (from datasets>=2.0.0->lm-eval==1.0.0)\n",
|
132 |
+
" Downloading dill-0.3.7-py3-none-any.whl (115 kB)\n",
|
133 |
+
"\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m115.3/115.3 kB\u001b[0m \u001b[31m14.4 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
|
134 |
+
"\u001b[?25hRequirement already satisfied: pandas in /usr/local/lib/python3.10/dist-packages (from datasets>=2.0.0->lm-eval==1.0.0) (1.5.3)\n",
|
135 |
+
"Requirement already satisfied: requests>=2.19.0 in /usr/local/lib/python3.10/dist-packages (from datasets>=2.0.0->lm-eval==1.0.0) (2.31.0)\n",
|
136 |
+
"Requirement already satisfied: tqdm>=4.62.1 in /usr/local/lib/python3.10/dist-packages (from datasets>=2.0.0->lm-eval==1.0.0) (4.66.1)\n",
|
137 |
+
"Requirement already satisfied: xxhash in /usr/local/lib/python3.10/dist-packages (from datasets>=2.0.0->lm-eval==1.0.0) (3.4.1)\n",
|
138 |
+
"Collecting multiprocess (from datasets>=2.0.0->lm-eval==1.0.0)\n",
|
139 |
+
" Downloading multiprocess-0.70.15-py310-none-any.whl (134 kB)\n",
|
140 |
+
"\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m134.8/134.8 kB\u001b[0m \u001b[31m19.9 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
|
141 |
+
"\u001b[?25hRequirement already satisfied: fsspec[http]<=2023.10.0,>=2023.1.0 in /usr/local/lib/python3.10/dist-packages (from datasets>=2.0.0->lm-eval==1.0.0) (2023.6.0)\n",
|
142 |
+
"Requirement already satisfied: aiohttp in /usr/local/lib/python3.10/dist-packages (from datasets>=2.0.0->lm-eval==1.0.0) (3.8.6)\n",
|
143 |
+
"Collecting responses<0.19 (from evaluate->lm-eval==1.0.0)\n",
|
144 |
+
" Downloading responses-0.18.0-py3-none-any.whl (38 kB)\n",
|
145 |
+
"Requirement already satisfied: safetensors in /usr/local/lib/python3.10/dist-packages (from peft>=0.2.0->lm-eval==1.0.0) (0.4.0)\n",
|
146 |
+
"Requirement already satisfied: absl-py in /usr/local/lib/python3.10/dist-packages (from rouge-score>=0.0.4->lm-eval==1.0.0) (1.4.0)\n",
|
147 |
+
"Requirement already satisfied: nltk in /usr/local/lib/python3.10/dist-packages (from rouge-score>=0.0.4->lm-eval==1.0.0) (3.8.1)\n",
|
148 |
+
"Requirement already satisfied: six>=1.14.0 in /usr/local/lib/python3.10/dist-packages (from rouge-score>=0.0.4->lm-eval==1.0.0) (1.16.0)\n",
|
149 |
+
"Collecting portalocker (from sacrebleu>=1.5.0->lm-eval==1.0.0)\n",
|
150 |
+
" Downloading portalocker-2.8.2-py3-none-any.whl (17 kB)\n",
|
151 |
+
"Requirement already satisfied: regex in /usr/local/lib/python3.10/dist-packages (from sacrebleu>=1.5.0->lm-eval==1.0.0) (2023.6.3)\n",
|
152 |
+
"Requirement already satisfied: tabulate>=0.8.9 in /usr/local/lib/python3.10/dist-packages (from sacrebleu>=1.5.0->lm-eval==1.0.0) (0.9.0)\n",
|
153 |
+
"Collecting colorama (from sacrebleu>=1.5.0->lm-eval==1.0.0)\n",
|
154 |
+
" Downloading colorama-0.4.6-py2.py3-none-any.whl (25 kB)\n",
|
155 |
+
"Requirement already satisfied: lxml in /usr/local/lib/python3.10/dist-packages (from sacrebleu>=1.5.0->lm-eval==1.0.0) (4.9.3)\n",
|
156 |
+
"Requirement already satisfied: scipy>=1.3.2 in /usr/local/lib/python3.10/dist-packages (from scikit-learn>=0.24.1->lm-eval==1.0.0) (1.11.3)\n",
|
157 |
+
"Requirement already satisfied: joblib>=1.1.1 in /usr/local/lib/python3.10/dist-packages (from scikit-learn>=0.24.1->lm-eval==1.0.0) (1.3.2)\n",
|
158 |
+
"Requirement already satisfied: threadpoolctl>=2.0.0 in /usr/local/lib/python3.10/dist-packages (from scikit-learn>=0.24.1->lm-eval==1.0.0) (3.2.0)\n",
|
159 |
+
"Requirement already satisfied: filelock in /usr/local/lib/python3.10/dist-packages (from torch>=1.8->lm-eval==1.0.0) (3.13.1)\n",
|
160 |
+
"Requirement already satisfied: typing-extensions in /usr/local/lib/python3.10/dist-packages (from torch>=1.8->lm-eval==1.0.0) (4.5.0)\n",
|
161 |
+
"Requirement already satisfied: sympy in /usr/local/lib/python3.10/dist-packages (from torch>=1.8->lm-eval==1.0.0) (1.12)\n",
|
162 |
+
"Requirement already satisfied: networkx in /usr/local/lib/python3.10/dist-packages (from torch>=1.8->lm-eval==1.0.0) (3.2.1)\n",
|
163 |
+
"Requirement already satisfied: jinja2 in /usr/local/lib/python3.10/dist-packages (from torch>=1.8->lm-eval==1.0.0) (3.1.2)\n",
|
164 |
+
"Requirement already satisfied: triton==2.1.0 in /usr/local/lib/python3.10/dist-packages (from torch>=1.8->lm-eval==1.0.0) (2.1.0)\n",
|
165 |
+
"Requirement already satisfied: tokenizers<0.19,>=0.14 in /usr/local/lib/python3.10/dist-packages (from transformers>=4.1->lm-eval==1.0.0) (0.15.0)\n",
|
166 |
+
"Requirement already satisfied: attrs>=19.2.0 in /usr/local/lib/python3.10/dist-packages (from jsonlines->lm-eval==1.0.0) (23.1.0)\n",
|
167 |
+
"Requirement already satisfied: setuptools>=38.3.0 in /usr/local/lib/python3.10/dist-packages (from pytablewriter->lm-eval==1.0.0) (67.7.2)\n",
|
168 |
+
"Collecting DataProperty<2,>=1.0.1 (from pytablewriter->lm-eval==1.0.0)\n",
|
169 |
+
" Downloading DataProperty-1.0.1-py3-none-any.whl (27 kB)\n",
|
170 |
+
"Collecting mbstrdecoder<2,>=1.0.0 (from pytablewriter->lm-eval==1.0.0)\n",
|
171 |
+
" Downloading mbstrdecoder-1.1.3-py3-none-any.whl (7.8 kB)\n",
|
172 |
+
"Collecting pathvalidate<4,>=2.3.0 (from pytablewriter->lm-eval==1.0.0)\n",
|
173 |
+
" Downloading pathvalidate-3.2.0-py3-none-any.whl (23 kB)\n",
|
174 |
+
"Collecting tabledata<2,>=1.3.1 (from pytablewriter->lm-eval==1.0.0)\n",
|
175 |
+
" Downloading tabledata-1.3.3-py3-none-any.whl (11 kB)\n",
|
176 |
+
"Collecting tcolorpy<1,>=0.0.5 (from pytablewriter->lm-eval==1.0.0)\n",
|
177 |
+
" Downloading tcolorpy-0.1.4-py3-none-any.whl (7.9 kB)\n",
|
178 |
+
"Collecting typepy[datetime]<2,>=1.3.2 (from pytablewriter->lm-eval==1.0.0)\n",
|
179 |
+
" Downloading typepy-1.3.2-py3-none-any.whl (31 kB)\n",
|
180 |
+
"Requirement already satisfied: charset-normalizer<4.0,>=2.0 in /usr/local/lib/python3.10/dist-packages (from aiohttp->datasets>=2.0.0->lm-eval==1.0.0) (3.3.2)\n",
|
181 |
+
"Requirement already satisfied: multidict<7.0,>=4.5 in /usr/local/lib/python3.10/dist-packages (from aiohttp->datasets>=2.0.0->lm-eval==1.0.0) (6.0.4)\n",
|
182 |
+
"Requirement already satisfied: async-timeout<5.0,>=4.0.0a3 in /usr/local/lib/python3.10/dist-packages (from aiohttp->datasets>=2.0.0->lm-eval==1.0.0) (4.0.3)\n",
|
183 |
+
"Requirement already satisfied: yarl<2.0,>=1.0 in /usr/local/lib/python3.10/dist-packages (from aiohttp->datasets>=2.0.0->lm-eval==1.0.0) (1.9.2)\n",
|
184 |
+
"Requirement already satisfied: frozenlist>=1.1.1 in /usr/local/lib/python3.10/dist-packages (from aiohttp->datasets>=2.0.0->lm-eval==1.0.0) (1.4.0)\n",
|
185 |
+
"Requirement already satisfied: aiosignal>=1.1.2 in /usr/local/lib/python3.10/dist-packages (from aiohttp->datasets>=2.0.0->lm-eval==1.0.0) (1.3.1)\n",
|
186 |
+
"Requirement already satisfied: chardet<6,>=3.0.4 in /usr/local/lib/python3.10/dist-packages (from mbstrdecoder<2,>=1.0.0->pytablewriter->lm-eval==1.0.0) (5.2.0)\n",
|
187 |
+
"Requirement already satisfied: idna<4,>=2.5 in /usr/local/lib/python3.10/dist-packages (from requests>=2.19.0->datasets>=2.0.0->lm-eval==1.0.0) (3.4)\n",
|
188 |
+
"Requirement already satisfied: urllib3<3,>=1.21.1 in /usr/local/lib/python3.10/dist-packages (from requests>=2.19.0->datasets>=2.0.0->lm-eval==1.0.0) (2.0.7)\n",
|
189 |
+
"Requirement already satisfied: certifi>=2017.4.17 in /usr/local/lib/python3.10/dist-packages (from requests>=2.19.0->datasets>=2.0.0->lm-eval==1.0.0) (2023.7.22)\n",
|
190 |
+
"Requirement already satisfied: python-dateutil<3.0.0,>=2.8.0 in /usr/local/lib/python3.10/dist-packages (from typepy[datetime]<2,>=1.3.2->pytablewriter->lm-eval==1.0.0) (2.8.2)\n",
|
191 |
+
"Requirement already satisfied: pytz>=2018.9 in /usr/local/lib/python3.10/dist-packages (from typepy[datetime]<2,>=1.3.2->pytablewriter->lm-eval==1.0.0) (2023.3.post1)\n",
|
192 |
+
"Requirement already satisfied: MarkupSafe>=2.0 in /usr/local/lib/python3.10/dist-packages (from jinja2->torch>=1.8->lm-eval==1.0.0) (2.1.3)\n",
|
193 |
+
"Requirement already satisfied: click in /usr/local/lib/python3.10/dist-packages (from nltk->rouge-score>=0.0.4->lm-eval==1.0.0) (8.1.7)\n",
|
194 |
+
"Requirement already satisfied: mpmath>=0.19 in /usr/local/lib/python3.10/dist-packages (from sympy->torch>=1.8->lm-eval==1.0.0) (1.3.0)\n",
|
195 |
+
"Building wheels for collected packages: lm-eval, rouge-score, sqlitedict\n",
|
196 |
+
" Building wheel for lm-eval (pyproject.toml) ... \u001b[?25l\u001b[?25hdone\n",
|
197 |
+
" Created wheel for lm-eval: filename=lm_eval-1.0.0-py3-none-any.whl size=994254 sha256=88356155b19f2891981ecef948326ad6ce8ca40a6009378410ec20d0e225995a\n",
|
198 |
+
" Stored in directory: /tmp/pip-ephem-wheel-cache-9v6ye7h3/wheels/17/01/26/599c0779e9858a70a73fa8a306699b5b9a868f820c225457b0\n",
|
199 |
+
" Building wheel for rouge-score (setup.py) ... \u001b[?25l\u001b[?25hdone\n",
|
200 |
+
" Created wheel for rouge-score: filename=rouge_score-0.1.2-py3-none-any.whl size=24933 sha256=6bb0d44e4881972c43ce194e7cb65233d309758cb15f0dec54590d3d2efcfc36\n",
|
201 |
+
" Stored in directory: /root/.cache/pip/wheels/5f/dd/89/461065a73be61a532ff8599a28e9beef17985c9e9c31e541b4\n",
|
202 |
+
" Building wheel for sqlitedict (setup.py) ... \u001b[?25l\u001b[?25hdone\n",
|
203 |
+
" Created wheel for sqlitedict: filename=sqlitedict-2.1.0-py3-none-any.whl size=16863 sha256=5747f7dd73ddf3d8fbcebf51b5e4f718fabe1e94bccdf16d2f22a2e65ee7fdf4\n",
|
204 |
+
" Stored in directory: /root/.cache/pip/wheels/79/d6/e7/304e0e6cb2221022c26d8161f7c23cd4f259a9e41e8bbcfabd\n",
|
205 |
+
"Successfully built lm-eval rouge-score sqlitedict\n",
|
206 |
+
"Installing collected packages: sqlitedict, zstandard, tcolorpy, pybind11, pyarrow-hotfix, portalocker, pathvalidate, mbstrdecoder, jsonlines, dill, colorama, typepy, tqdm-multiprocess, sacrebleu, rouge-score, responses, multiprocess, accelerate, datasets, DataProperty, tabledata, peft, evaluate, pytablewriter, lm-eval\n",
|
207 |
+
"Successfully installed DataProperty-1.0.1 accelerate-0.24.1 colorama-0.4.6 datasets-2.15.0 dill-0.3.7 evaluate-0.4.1 jsonlines-4.0.0 lm-eval-1.0.0 mbstrdecoder-1.1.3 multiprocess-0.70.15 pathvalidate-3.2.0 peft-0.6.2 portalocker-2.8.2 pyarrow-hotfix-0.6 pybind11-2.11.1 pytablewriter-1.2.0 responses-0.18.0 rouge-score-0.1.2 sacrebleu-2.3.2 sqlitedict-2.1.0 tabledata-1.3.3 tcolorpy-0.1.4 tqdm-multiprocess-0.0.11 typepy-1.3.2 zstandard-0.22.0\n"
|
208 |
+
]
|
209 |
+
}
|
210 |
+
],
|
211 |
+
"source": [
|
212 |
+
"# Install LM-Eval\n",
|
213 |
+
"!pip install git+https://github.com/EleutherAI/lm-evaluation-harness.git"
|
214 |
+
]
|
215 |
+
},
|
216 |
+
{
|
217 |
+
"cell_type": "code",
|
218 |
+
"execution_count": 2,
|
219 |
+
"metadata": {
|
220 |
+
"colab": {
|
221 |
+
"base_uri": "https://localhost:8080/",
|
222 |
+
"height": 0,
|
223 |
+
"referenced_widgets": [
|
224 |
+
"a1d3a8aa016544a78e8821c8f6199e06",
|
225 |
+
"f61ed33fad754146bdd2ac9db1ba1c48",
|
226 |
+
"bfa0af6aeff344c6845e1080a878e92e",
|
227 |
+
"fd1ad9e0367d4004aae853b91c3a7617",
|
228 |
+
"6b2d90209ec14230b3d58a74ac9b83bf",
|
229 |
+
"a73f357065d34d7baf0453ae4a8d75e2",
|
230 |
+
"46f521b73fd943c081c648fd873ebc0a",
|
231 |
+
"7c5689bc13684db8a22681f41863dddd",
|
232 |
+
"48763b6233374554ae76035c0483066f",
|
233 |
+
"4986a21eb560448fa79f4b25cde48951",
|
234 |
+
"aed3acd2f2d74003b44079c333a0698e"
|
235 |
+
]
|
236 |
+
},
|
237 |
+
"id": "uyO5MaKkZyah",
|
238 |
+
"outputId": "d46e8096-5086-4e49-967e-ea33d4a2a335"
|
239 |
+
},
|
240 |
+
"outputs": [
|
241 |
+
{
|
242 |
+
"data": {
|
243 |
+
"application/vnd.jupyter.widget-view+json": {
|
244 |
+
"model_id": "a1d3a8aa016544a78e8821c8f6199e06",
|
245 |
+
"version_major": 2,
|
246 |
+
"version_minor": 0
|
247 |
+
},
|
248 |
+
"text/plain": [
|
249 |
+
"Downloading builder script: 0%| | 0.00/5.67k [00:00<?, ?B/s]"
|
250 |
+
]
|
251 |
+
},
|
252 |
+
"metadata": {},
|
253 |
+
"output_type": "display_data"
|
254 |
+
}
|
255 |
+
],
|
256 |
+
"source": [
|
257 |
+
"from lm_eval import api"
|
258 |
+
]
|
259 |
+
},
|
260 |
+
{
|
261 |
+
"cell_type": "markdown",
|
262 |
+
"metadata": {
|
263 |
+
"id": "8rfUeX6n_wkK"
|
264 |
+
},
|
265 |
+
"source": [
|
266 |
+
"## Create new evaluation tasks with config-based tasks\n",
|
267 |
+
"\n",
|
268 |
+
"Even within the same task, many works have reported numbers based on different choices of evaluation. Some report on the test sets, validation sets, or even subset of the training sets. Others have specialized prompts and verbalizers. We introduce YAMLs to allow users to easily make different variations. By leveraging the YAML configs to configure evaluations, the refactored LM-Eval takes the methods of the `Task` object and makes them configurable by setting the appropriate attributes in the config file. There, users can set the tasks they want by setting the name of the HF dataset (local tasks are also possible), the dataset splits used, and much more. Key configurations relating to prompting, such as `doc_to_text`, previously implemented as a method of the same name, are now configurable with jinja2 to allow high-level scripting to transform a HF dataset to text string as input to the model.\n",
|
269 |
+
"\n"
|
270 |
+
]
|
271 |
+
},
|
272 |
+
{
|
273 |
+
"cell_type": "markdown",
|
274 |
+
"metadata": {
|
275 |
+
"id": "HYFUhhfOSJKe"
|
276 |
+
},
|
277 |
+
"source": [
|
278 |
+
"A core-feature to LM-Eval is to configure tasks with YAML configs. With configs, you can fill preset fields to easily set up a task.\n",
|
279 |
+
"\n",
|
280 |
+
"Here, we write a demo YAML config for a multiple-choice evaluation of BoolQ:"
|
281 |
+
]
|
282 |
+
},
|
283 |
+
{
|
284 |
+
"cell_type": "code",
|
285 |
+
"execution_count": 3,
|
286 |
+
"metadata": {
|
287 |
+
"id": "bg3dGROW-V39"
|
288 |
+
},
|
289 |
+
"outputs": [],
|
290 |
+
"source": [
|
291 |
+
"YAML_boolq_string = '''\n",
|
292 |
+
"task: demo_boolq\n",
|
293 |
+
"dataset_path: super_glue\n",
|
294 |
+
"dataset_name: boolq\n",
|
295 |
+
"output_type: multiple_choice\n",
|
296 |
+
"training_split: train\n",
|
297 |
+
"validation_split: validation\n",
|
298 |
+
"doc_to_text: \"{{passage}}\\nQuestion: {{question}}?\\nAnswer:\"\n",
|
299 |
+
"doc_to_target: label\n",
|
300 |
+
"doc_to_choice: [\"no\", \"yes\"]\n",
|
301 |
+
"should_decontaminate: true\n",
|
302 |
+
"doc_to_decontamination_query: passage\n",
|
303 |
+
"metric_list:\n",
|
304 |
+
" - metric: acc\n",
|
305 |
+
"'''\n",
|
306 |
+
"with open('boolq.yaml', 'w') as f:\n",
|
307 |
+
" f.write(YAML_boolq_string)"
|
308 |
+
]
|
309 |
+
},
|
310 |
+
{
|
311 |
+
"cell_type": "markdown",
|
312 |
+
"metadata": {},
|
313 |
+
"source": [
|
314 |
+
"And we can now run evaluation on this task, by pointing to the config file we've just created:"
|
315 |
+
]
|
316 |
+
},
|
317 |
+
{
|
318 |
+
"cell_type": "code",
|
319 |
+
"execution_count": 4,
|
320 |
+
"metadata": {
|
321 |
+
"id": "LOUHK7PtQfq4"
|
322 |
+
},
|
323 |
+
"outputs": [
|
324 |
+
{
|
325 |
+
"name": "stdout",
|
326 |
+
"output_type": "stream",
|
327 |
+
"text": [
|
328 |
+
"2023-11-29:11:54:55,156 INFO [utils.py:160] NumExpr defaulting to 2 threads.\n",
|
329 |
+
"2023-11-29 11:54:55.942051: E tensorflow/compiler/xla/stream_executor/cuda/cuda_dnn.cc:9342] Unable to register cuDNN factory: Attempting to register factory for plugin cuDNN when one has already been registered\n",
|
330 |
+
"2023-11-29 11:54:55.942108: E tensorflow/compiler/xla/stream_executor/cuda/cuda_fft.cc:609] Unable to register cuFFT factory: Attempting to register factory for plugin cuFFT when one has already been registered\n",
|
331 |
+
"2023-11-29 11:54:55.942142: E tensorflow/compiler/xla/stream_executor/cuda/cuda_blas.cc:1518] Unable to register cuBLAS factory: Attempting to register factory for plugin cuBLAS when one has already been registered\n",
|
332 |
+
"2023-11-29 11:54:57.066802: W tensorflow/compiler/tf2tensorrt/utils/py_utils.cc:38] TF-TRT Warning: Could not find TensorRT\n",
|
333 |
+
"2023-11-29:11:55:00,954 INFO [__main__.py:132] Verbosity set to INFO\n",
|
334 |
+
"2023-11-29:11:55:11,038 WARNING [__main__.py:138] --limit SHOULD ONLY BE USED FOR TESTING.REAL METRICS SHOULD NOT BE COMPUTED USING LIMIT.\n",
|
335 |
+
"2023-11-29:11:55:11,038 INFO [__main__.py:143] Including path: ./\n",
|
336 |
+
"2023-11-29:11:55:11,046 INFO [__main__.py:205] Selected Tasks: ['demo_boolq']\n",
|
337 |
+
"2023-11-29:11:55:11,047 WARNING [evaluator.py:93] generation_kwargs specified through cli, these settings will be used over set parameters in yaml tasks.\n",
|
338 |
+
"2023-11-29:11:55:11,110 INFO [huggingface.py:120] Using device 'cuda'\n",
|
339 |
+
"config.json: 100% 571/571 [00:00<00:00, 2.87MB/s]\n",
|
340 |
+
"model.safetensors: 100% 5.68G/5.68G [00:32<00:00, 173MB/s]\n",
|
341 |
+
"tokenizer_config.json: 100% 396/396 [00:00<00:00, 2.06MB/s]\n",
|
342 |
+
"tokenizer.json: 100% 2.11M/2.11M [00:00<00:00, 11.6MB/s]\n",
|
343 |
+
"special_tokens_map.json: 100% 99.0/99.0 [00:00<00:00, 555kB/s]\n",
|
344 |
+
"2023-11-29:11:56:18,658 WARNING [task.py:614] [Task: demo_boolq] metric acc is defined, but aggregation is not. using default aggregation=mean\n",
|
345 |
+
"2023-11-29:11:56:18,658 WARNING [task.py:626] [Task: demo_boolq] metric acc is defined, but higher_is_better is not. using default higher_is_better=True\n",
|
346 |
+
"Downloading builder script: 100% 30.7k/30.7k [00:00<00:00, 59.0MB/s]\n",
|
347 |
+
"Downloading metadata: 100% 38.7k/38.7k [00:00<00:00, 651kB/s]\n",
|
348 |
+
"Downloading readme: 100% 14.8k/14.8k [00:00<00:00, 37.3MB/s]\n",
|
349 |
+
"Downloading data: 100% 4.12M/4.12M [00:00<00:00, 55.1MB/s]\n",
|
350 |
+
"Generating train split: 100% 9427/9427 [00:00<00:00, 15630.89 examples/s]\n",
|
351 |
+
"Generating validation split: 100% 3270/3270 [00:00<00:00, 20002.56 examples/s]\n",
|
352 |
+
"Generating test split: 100% 3245/3245 [00:00<00:00, 20866.19 examples/s]\n",
|
353 |
+
"2023-11-29:11:56:22,315 INFO [task.py:355] Building contexts for task on rank 0...\n",
|
354 |
+
"2023-11-29:11:56:22,322 INFO [evaluator.py:319] Running loglikelihood requests\n",
|
355 |
+
"100% 20/20 [00:04<00:00, 4.37it/s]\n",
|
356 |
+
"fatal: not a git repository (or any of the parent directories): .git\n",
|
357 |
+
"hf (pretrained=EleutherAI/pythia-2.8b), gen_kwargs: (), limit: 10.0, num_fewshot: None, batch_size: 1\n",
|
358 |
+
"| Tasks |Version|Filter|n-shot|Metric|Value| |Stderr|\n",
|
359 |
+
"|----------|-------|------|-----:|------|----:|---|-----:|\n",
|
360 |
+
"|demo_boolq|Yaml |none | 0|acc | 1|± | 0|\n",
|
361 |
+
"\n"
|
362 |
+
]
|
363 |
+
}
|
364 |
+
],
|
365 |
+
"source": [
|
366 |
+
"!lm_eval \\\n",
|
367 |
+
" --model hf \\\n",
|
368 |
+
" --model_args pretrained=EleutherAI/pythia-2.8b \\\n",
|
369 |
+
" --include_path ./ \\\n",
|
370 |
+
" --tasks demo_boolq \\\n",
|
371 |
+
" --limit 10\n"
|
372 |
+
]
|
373 |
+
},
|
374 |
+
{
|
375 |
+
"cell_type": "markdown",
|
376 |
+
"metadata": {
|
377 |
+
"id": "LOUHK7PtQfq4"
|
378 |
+
},
|
379 |
+
"source": [
|
380 |
+
"Often, tasks are part of a larger group used to measure different capabilities. The dynamism of the field today means new dimensions of evaluation can come about which would mix and match new and older tasks alike. In LM-Eval, We can also group tasks and call that the group name to evaluate on a set of tasks easily. In this instance, let's evaluate the tag `yes_or_no_tasks` which comprise of the tasks `demo_boolq` and `demo_cola`; tasks which are multiple choice tasks with options `yes` and `no` as the name suggests.\n",
|
381 |
+
"\n",
|
382 |
+
"<!-- making new groups is easier than ever, allowing user to work bottom-up by makiing individual tasks and linking them to a group or Top-Down, making a new group by listing existing tasks.\n",
|
383 |
+
"\n",
|
384 |
+
"We also show the aggregate across samples besides only showing the aggregation between subtasks. This may come in handy when certain groups want to be aggregated as a single task. -->\n",
|
385 |
+
"\n",
|
386 |
+
"\n"
|
387 |
+
]
|
388 |
+
},
|
389 |
+
{
|
390 |
+
"cell_type": "code",
|
391 |
+
"execution_count": 5,
|
392 |
+
"metadata": {
|
393 |
+
"id": "fthNg3ywO-kA"
|
394 |
+
},
|
395 |
+
"outputs": [],
|
396 |
+
"source": [
|
397 |
+
"YAML_cola_string = '''\n",
|
398 |
+
"tag: yes_or_no_tasks\n",
|
399 |
+
"task: demo_cola\n",
|
400 |
+
"dataset_path: glue\n",
|
401 |
+
"dataset_name: cola\n",
|
402 |
+
"output_type: multiple_choice\n",
|
403 |
+
"training_split: train\n",
|
404 |
+
"validation_split: validation\n",
|
405 |
+
"doc_to_text: \"{{sentence}}\\nQuestion: Does this sentence make sense?\\nAnswer:\"\n",
|
406 |
+
"doc_to_target: label\n",
|
407 |
+
"doc_to_choice: [\"no\", \"yes\"]\n",
|
408 |
+
"should_decontaminate: true\n",
|
409 |
+
"doc_to_decontamination_query: sentence\n",
|
410 |
+
"metric_list:\n",
|
411 |
+
" - metric: acc\n",
|
412 |
+
"'''\n",
|
413 |
+
"with open('cola.yaml', 'w') as f:\n",
|
414 |
+
" f.write(YAML_cola_string)"
|
415 |
+
]
|
416 |
+
},
|
417 |
+
{
|
418 |
+
"cell_type": "code",
|
419 |
+
"execution_count": 6,
|
420 |
+
"metadata": {
|
421 |
+
"id": "XceRKCuuDtbn"
|
422 |
+
},
|
423 |
+
"outputs": [
|
424 |
+
{
|
425 |
+
"name": "stdout",
|
426 |
+
"output_type": "stream",
|
427 |
+
"text": [
|
428 |
+
"2023-11-29:11:56:33,016 INFO [utils.py:160] NumExpr defaulting to 2 threads.\n",
|
429 |
+
"2023-11-29 11:56:33.852995: E tensorflow/compiler/xla/stream_executor/cuda/cuda_dnn.cc:9342] Unable to register cuDNN factory: Attempting to register factory for plugin cuDNN when one has already been registered\n",
|
430 |
+
"2023-11-29 11:56:33.853050: E tensorflow/compiler/xla/stream_executor/cuda/cuda_fft.cc:609] Unable to register cuFFT factory: Attempting to register factory for plugin cuFFT when one has already been registered\n",
|
431 |
+
"2023-11-29 11:56:33.853087: E tensorflow/compiler/xla/stream_executor/cuda/cuda_blas.cc:1518] Unable to register cuBLAS factory: Attempting to register factory for plugin cuBLAS when one has already been registered\n",
|
432 |
+
"2023-11-29 11:56:35.129047: W tensorflow/compiler/tf2tensorrt/utils/py_utils.cc:38] TF-TRT Warning: Could not find TensorRT\n",
|
433 |
+
"2023-11-29:11:56:38,546 INFO [__main__.py:132] Verbosity set to INFO\n",
|
434 |
+
"2023-11-29:11:56:47,509 WARNING [__main__.py:138] --limit SHOULD ONLY BE USED FOR TESTING.REAL METRICS SHOULD NOT BE COMPUTED USING LIMIT.\n",
|
435 |
+
"2023-11-29:11:56:47,509 INFO [__main__.py:143] Including path: ./\n",
|
436 |
+
"2023-11-29:11:56:47,517 INFO [__main__.py:205] Selected Tasks: ['yes_or_no_tasks']\n",
|
437 |
+
"2023-11-29:11:56:47,520 WARNING [evaluator.py:93] generation_kwargs specified through cli, these settings will be used over set parameters in yaml tasks.\n",
|
438 |
+
"2023-11-29:11:56:47,550 INFO [huggingface.py:120] Using device 'cuda'\n",
|
439 |
+
"2023-11-29:11:57:08,743 WARNING [task.py:614] [Task: demo_cola] metric acc is defined, but aggregation is not. using default aggregation=mean\n",
|
440 |
+
"2023-11-29:11:57:08,743 WARNING [task.py:626] [Task: demo_cola] metric acc is defined, but higher_is_better is not. using default higher_is_better=True\n",
|
441 |
+
"Downloading builder script: 100% 28.8k/28.8k [00:00<00:00, 52.7MB/s]\n",
|
442 |
+
"Downloading metadata: 100% 28.7k/28.7k [00:00<00:00, 51.9MB/s]\n",
|
443 |
+
"Downloading readme: 100% 27.9k/27.9k [00:00<00:00, 48.0MB/s]\n",
|
444 |
+
"Downloading data: 100% 377k/377k [00:00<00:00, 12.0MB/s]\n",
|
445 |
+
"Generating train split: 100% 8551/8551 [00:00<00:00, 19744.58 examples/s]\n",
|
446 |
+
"Generating validation split: 100% 1043/1043 [00:00<00:00, 27057.01 examples/s]\n",
|
447 |
+
"Generating test split: 100% 1063/1063 [00:00<00:00, 22705.17 examples/s]\n",
|
448 |
+
"2023-11-29:11:57:11,698 INFO [task.py:355] Building contexts for task on rank 0...\n",
|
449 |
+
"2023-11-29:11:57:11,704 INFO [evaluator.py:319] Running loglikelihood requests\n",
|
450 |
+
"100% 20/20 [00:03<00:00, 5.15it/s]\n",
|
451 |
+
"fatal: not a git repository (or any of the parent directories): .git\n",
|
452 |
+
"hf (pretrained=EleutherAI/pythia-2.8b), gen_kwargs: (), limit: 10.0, num_fewshot: None, batch_size: 1\n",
|
453 |
+
"| Tasks |Version|Filter|n-shot|Metric|Value| |Stderr|\n",
|
454 |
+
"|---------------|-------|------|-----:|------|----:|---|-----:|\n",
|
455 |
+
"|yes_or_no_tasks|N/A |none | 0|acc | 0.7|± |0.1528|\n",
|
456 |
+
"| - demo_cola |Yaml |none | 0|acc | 0.7|± |0.1528|\n",
|
457 |
+
"\n",
|
458 |
+
"| Groups |Version|Filter|n-shot|Metric|Value| |Stderr|\n",
|
459 |
+
"|---------------|-------|------|-----:|------|----:|---|-----:|\n",
|
460 |
+
"|yes_or_no_tasks|N/A |none | 0|acc | 0.7|± |0.1528|\n",
|
461 |
+
"\n"
|
462 |
+
]
|
463 |
+
}
|
464 |
+
],
|
465 |
+
"source": [
|
466 |
+
"# !accelerate launch --no_python\n",
|
467 |
+
"!lm_eval \\\n",
|
468 |
+
" --model hf \\\n",
|
469 |
+
" --model_args pretrained=EleutherAI/pythia-2.8b \\\n",
|
470 |
+
" --include_path ./ \\\n",
|
471 |
+
" --tasks yes_or_no_tasks \\\n",
|
472 |
+
" --limit 10 \\\n",
|
473 |
+
" --output output/yes_or_no_tasks/ \\\n",
|
474 |
+
" --log_samples\n"
|
475 |
+
]
|
476 |
+
},
|
477 |
+
{
|
478 |
+
"cell_type": "markdown",
|
479 |
+
"metadata": {
|
480 |
+
"id": "XceRKCuuDtbn"
|
481 |
+
},
|
482 |
+
"source": [
|
483 |
+
"## Edit Prompt Templates Quickly\n",
|
484 |
+
"\n",
|
485 |
+
"The following is a yaml made to evaluate the specific subtask of `high_school_geography` from MMLU. It uses the standard prompt where the we choose the letters from the options with most likelihood as the model's prediction."
|
486 |
+
]
|
487 |
+
},
|
488 |
+
{
|
489 |
+
"cell_type": "code",
|
490 |
+
"execution_count": 7,
|
491 |
+
"metadata": {
|
492 |
+
"id": "GTFvdt9kSlBG"
|
493 |
+
},
|
494 |
+
"outputs": [],
|
495 |
+
"source": [
|
496 |
+
"YAML_mmlu_geo_string = '''\n",
|
497 |
+
"task: demo_mmlu_high_school_geography\n",
|
498 |
+
"dataset_path: cais/mmlu\n",
|
499 |
+
"dataset_name: high_school_geography\n",
|
500 |
+
"description: \"The following are multiple choice questions (with answers) about high school geography.\\n\\n\"\n",
|
501 |
+
"test_split: test\n",
|
502 |
+
"fewshot_split: dev\n",
|
503 |
+
"fewshot_config:\n",
|
504 |
+
" sampler: first_n\n",
|
505 |
+
"output_type: multiple_choice\n",
|
506 |
+
"doc_to_text: \"{{question.strip()}}\\nA. {{choices[0]}}\\nB. {{choices[1]}}\\nC. {{choices[2]}}\\nD. {{choices[3]}}\\nAnswer:\"\n",
|
507 |
+
"doc_to_choice: [\"A\", \"B\", \"C\", \"D\"]\n",
|
508 |
+
"doc_to_target: answer\n",
|
509 |
+
"metric_list:\n",
|
510 |
+
" - metric: acc\n",
|
511 |
+
" aggregation: mean\n",
|
512 |
+
" higher_is_better: true\n",
|
513 |
+
" - metric: acc_norm\n",
|
514 |
+
" aggregation: mean\n",
|
515 |
+
" higher_is_better: true\n",
|
516 |
+
"'''\n",
|
517 |
+
"with open('mmlu_high_school_geography.yaml', 'w') as f:\n",
|
518 |
+
" f.write(YAML_mmlu_geo_string)\n"
|
519 |
+
]
|
520 |
+
},
|
521 |
+
{
|
522 |
+
"cell_type": "code",
|
523 |
+
"execution_count": 8,
|
524 |
+
"metadata": {
|
525 |
+
"id": "jyKOfCsKb-xy"
|
526 |
+
},
|
527 |
+
"outputs": [
|
528 |
+
{
|
529 |
+
"name": "stdout",
|
530 |
+
"output_type": "stream",
|
531 |
+
"text": [
|
532 |
+
"2023-11-29:11:57:23,598 INFO [utils.py:160] NumExpr defaulting to 2 threads.\n",
|
533 |
+
"2023-11-29 11:57:24.719750: E tensorflow/compiler/xla/stream_executor/cuda/cuda_dnn.cc:9342] Unable to register cuDNN factory: Attempting to register factory for plugin cuDNN when one has already been registered\n",
|
534 |
+
"2023-11-29 11:57:24.719806: E tensorflow/compiler/xla/stream_executor/cuda/cuda_fft.cc:609] Unable to register cuFFT factory: Attempting to register factory for plugin cuFFT when one has already been registered\n",
|
535 |
+
"2023-11-29 11:57:24.719847: E tensorflow/compiler/xla/stream_executor/cuda/cuda_blas.cc:1518] Unable to register cuBLAS factory: Attempting to register factory for plugin cuBLAS when one has already been registered\n",
|
536 |
+
"2023-11-29 11:57:26.656125: W tensorflow/compiler/tf2tensorrt/utils/py_utils.cc:38] TF-TRT Warning: Could not find TensorRT\n",
|
537 |
+
"2023-11-29:11:57:31,563 INFO [__main__.py:132] Verbosity set to INFO\n",
|
538 |
+
"2023-11-29:11:57:40,541 WARNING [__main__.py:138] --limit SHOULD ONLY BE USED FOR TESTING.REAL METRICS SHOULD NOT BE COMPUTED USING LIMIT.\n",
|
539 |
+
"2023-11-29:11:57:40,541 INFO [__main__.py:143] Including path: ./\n",
|
540 |
+
"2023-11-29:11:57:40,558 INFO [__main__.py:205] Selected Tasks: ['demo_mmlu_high_school_geography']\n",
|
541 |
+
"2023-11-29:11:57:40,559 WARNING [evaluator.py:93] generation_kwargs specified through cli, these settings will be used over set parameters in yaml tasks.\n",
|
542 |
+
"2023-11-29:11:57:40,589 INFO [huggingface.py:120] Using device 'cuda'\n",
|
543 |
+
"Downloading builder script: 100% 5.84k/5.84k [00:00<00:00, 17.7MB/s]\n",
|
544 |
+
"Downloading metadata: 100% 106k/106k [00:00<00:00, 892kB/s] \n",
|
545 |
+
"Downloading readme: 100% 39.7k/39.7k [00:00<00:00, 631kB/s]\n",
|
546 |
+
"Downloading data: 100% 166M/166M [00:01<00:00, 89.0MB/s]\n",
|
547 |
+
"Generating auxiliary_train split: 100% 99842/99842 [00:07<00:00, 12536.83 examples/s]\n",
|
548 |
+
"Generating test split: 100% 198/198 [00:00<00:00, 1439.20 examples/s]\n",
|
549 |
+
"Generating validation split: 100% 22/22 [00:00<00:00, 4181.76 examples/s]\n",
|
550 |
+
"Generating dev split: 100% 5/5 [00:00<00:00, 36.25 examples/s]\n",
|
551 |
+
"2023-11-29:11:58:09,798 INFO [task.py:355] Building contexts for task on rank 0...\n",
|
552 |
+
"2023-11-29:11:58:09,822 INFO [evaluator.py:319] Running loglikelihood requests\n",
|
553 |
+
"100% 40/40 [00:05<00:00, 7.86it/s]\n",
|
554 |
+
"fatal: not a git repository (or any of the parent directories): .git\n",
|
555 |
+
"hf (pretrained=EleutherAI/pythia-2.8b), gen_kwargs: (), limit: 10.0, num_fewshot: None, batch_size: 1\n",
|
556 |
+
"| Tasks |Version|Filter|n-shot| Metric |Value| |Stderr|\n",
|
557 |
+
"|-------------------------------|-------|------|-----:|--------|----:|---|-----:|\n",
|
558 |
+
"|demo_mmlu_high_school_geography|Yaml |none | 0|acc | 0.3|± |0.1528|\n",
|
559 |
+
"| | |none | 0|acc_norm| 0.3|± |0.1528|\n",
|
560 |
+
"\n"
|
561 |
+
]
|
562 |
+
}
|
563 |
+
],
|
564 |
+
"source": [
|
565 |
+
"# !accelerate launch --no_python\n",
|
566 |
+
"!lm_eval \\\n",
|
567 |
+
" --model hf \\\n",
|
568 |
+
" --model_args pretrained=EleutherAI/pythia-2.8b \\\n",
|
569 |
+
" --include_path ./ \\\n",
|
570 |
+
" --tasks demo_mmlu_high_school_geography \\\n",
|
571 |
+
" --limit 10 \\\n",
|
572 |
+
" --output output/mmlu_high_school_geography/ \\\n",
|
573 |
+
" --log_samples"
|
574 |
+
]
|
575 |
+
},
|
576 |
+
{
|
577 |
+
"cell_type": "markdown",
|
578 |
+
"metadata": {
|
579 |
+
"id": "jyKOfCsKb-xy"
|
580 |
+
},
|
581 |
+
"source": [
|
582 |
+
"We could also evaluate this task in a different way. For example, instead of observing the loglikelihood of the letters, we can instead evaluate on the choices themselves as the continuation. This is done by simply changing `doc_to_choice` from a list of letters to the corresponding `choices` field from the HF dataset. We write `\"{{choices}}\"` so that the string field is interpreted as jinja string that acquires the list from the HF dataset directly.\n",
|
583 |
+
"\n",
|
584 |
+
"Another convenient feature here is since we're only modifying the `doc_to_choice` and the rest of config is the same as the task above, we can use the above configuration as a template by using `include: mmlu_high_school_geography.yaml` to load the config from that file. We'll need to add a unique task name as to not colide with the existing yaml config we're including. For this case we'll simply name this one `mmlu_high_school_geography_continuation`. `doc_to_text` is added here just for sake of clarity."
|
585 |
+
]
|
586 |
+
},
|
587 |
+
{
|
588 |
+
"cell_type": "code",
|
589 |
+
"execution_count": 9,
|
590 |
+
"metadata": {
|
591 |
+
"id": "lqElwU54TaK-"
|
592 |
+
},
|
593 |
+
"outputs": [],
|
594 |
+
"source": [
|
595 |
+
"YAML_mmlu_geo_string = '''\n",
|
596 |
+
"include: mmlu_high_school_geography.yaml\n",
|
597 |
+
"task: demo_mmlu_high_school_geography_continuation\n",
|
598 |
+
"doc_to_text: \"{{question.strip()}}\\nA. {{choices[0]}}\\nB. {{choices[1]}}\\nC. {{choices[2]}}\\nD. {{choices[3]}}\\nAnswer:\"\n",
|
599 |
+
"doc_to_choice: \"{{choices}}\"\n",
|
600 |
+
"'''\n",
|
601 |
+
"with open('mmlu_high_school_geography_continuation.yaml', 'w') as f:\n",
|
602 |
+
" f.write(YAML_mmlu_geo_string)\n"
|
603 |
+
]
|
604 |
+
},
|
605 |
+
{
|
606 |
+
"cell_type": "code",
|
607 |
+
"execution_count": 10,
|
608 |
+
"metadata": {
|
609 |
+
"id": "-_CVnDirdy7j"
|
610 |
+
},
|
611 |
+
"outputs": [
|
612 |
+
{
|
613 |
+
"name": "stdout",
|
614 |
+
"output_type": "stream",
|
615 |
+
"text": [
|
616 |
+
"2023-11-29:11:58:21,284 INFO [utils.py:160] NumExpr defaulting to 2 threads.\n",
|
617 |
+
"2023-11-29 11:58:22.850159: E tensorflow/compiler/xla/stream_executor/cuda/cuda_dnn.cc:9342] Unable to register cuDNN factory: Attempting to register factory for plugin cuDNN when one has already been registered\n",
|
618 |
+
"2023-11-29 11:58:22.850219: E tensorflow/compiler/xla/stream_executor/cuda/cuda_fft.cc:609] Unable to register cuFFT factory: Attempting to register factory for plugin cuFFT when one has already been registered\n",
|
619 |
+
"2023-11-29 11:58:22.850254: E tensorflow/compiler/xla/stream_executor/cuda/cuda_blas.cc:1518] Unable to register cuBLAS factory: Attempting to register factory for plugin cuBLAS when one has already been registered\n",
|
620 |
+
"2023-11-29 11:58:24.948103: W tensorflow/compiler/tf2tensorrt/utils/py_utils.cc:38] TF-TRT Warning: Could not find TensorRT\n",
|
621 |
+
"2023-11-29:11:58:28,460 INFO [__main__.py:132] Verbosity set to INFO\n",
|
622 |
+
"2023-11-29:11:58:37,935 WARNING [__main__.py:138] --limit SHOULD ONLY BE USED FOR TESTING.REAL METRICS SHOULD NOT BE COMPUTED USING LIMIT.\n",
|
623 |
+
"2023-11-29:11:58:37,935 INFO [__main__.py:143] Including path: ./\n",
|
624 |
+
"2023-11-29:11:58:37,969 INFO [__main__.py:205] Selected Tasks: ['demo_mmlu_high_school_geography_continuation']\n",
|
625 |
+
"2023-11-29:11:58:37,972 WARNING [evaluator.py:93] generation_kwargs specified through cli, these settings will be used over set parameters in yaml tasks.\n",
|
626 |
+
"2023-11-29:11:58:38,008 INFO [huggingface.py:120] Using device 'cuda'\n",
|
627 |
+
"2023-11-29:11:58:59,758 INFO [task.py:355] Building contexts for task on rank 0...\n",
|
628 |
+
"2023-11-29:11:58:59,777 INFO [evaluator.py:319] Running loglikelihood requests\n",
|
629 |
+
"100% 40/40 [00:02<00:00, 16.23it/s]\n",
|
630 |
+
"fatal: not a git repository (or any of the parent directories): .git\n",
|
631 |
+
"hf (pretrained=EleutherAI/pythia-2.8b), gen_kwargs: (), limit: 10.0, num_fewshot: None, batch_size: 1\n",
|
632 |
+
"| Tasks |Version|Filter|n-shot| Metric |Value| |Stderr|\n",
|
633 |
+
"|--------------------------------------------|-------|------|-----:|--------|----:|---|-----:|\n",
|
634 |
+
"|demo_mmlu_high_school_geography_continuation|Yaml |none | 0|acc | 0.1|± |0.1000|\n",
|
635 |
+
"| | |none | 0|acc_norm| 0.2|± |0.1333|\n",
|
636 |
+
"\n"
|
637 |
+
]
|
638 |
+
}
|
639 |
+
],
|
640 |
+
"source": [
|
641 |
+
"# !accelerate launch --no_python\n",
|
642 |
+
"!lm_eval \\\n",
|
643 |
+
" --model hf \\\n",
|
644 |
+
" --model_args pretrained=EleutherAI/pythia-2.8b \\\n",
|
645 |
+
" --include_path ./ \\\n",
|
646 |
+
" --tasks demo_mmlu_high_school_geography_continuation \\\n",
|
647 |
+
" --limit 10 \\\n",
|
648 |
+
" --output output/mmlu_high_school_geography_continuation/ \\\n",
|
649 |
+
" --log_samples\n"
|
650 |
+
]
|
651 |
+
},
|
652 |
+
{
|
653 |
+
"cell_type": "markdown",
|
654 |
+
"metadata": {
|
655 |
+
"id": "-_CVnDirdy7j"
|
656 |
+
},
|
657 |
+
"source": [
|
658 |
+
"If we take a look at the samples, we can see that it is in fact evaluating the continuation based on the choices rather than the letters."
|
659 |
+
]
|
660 |
+
},
|
661 |
+
{
|
662 |
+
"cell_type": "code",
|
663 |
+
"execution_count": 11,
|
664 |
+
"metadata": {
|
665 |
+
"id": "duBDqC6PAdjL"
|
666 |
+
},
|
667 |
+
"outputs": [
|
668 |
+
{
|
669 |
+
"data": {
|
670 |
+
"application/javascript": "\n ((filepath) => {{\n if (!google.colab.kernel.accessAllowed) {{\n return;\n }}\n google.colab.files.view(filepath);\n }})(\"/content/output/mmlu_high_school_geography_continuation/pretrained__EleutherAI__pythia-2.8b_demo_mmlu_high_school_geography_continuation.jsonl\")",
|
671 |
+
"text/plain": [
|
672 |
+
"<IPython.core.display.Javascript object>"
|
673 |
+
]
|
674 |
+
},
|
675 |
+
"metadata": {},
|
676 |
+
"output_type": "display_data"
|
677 |
+
}
|
678 |
+
],
|
679 |
+
"source": [
|
680 |
+
"from google.colab import files\n",
|
681 |
+
"files.view(\"output/mmlu_high_school_geography_continuation/pretrained__EleutherAI__pythia-2.8b_demo_mmlu_high_school_geography_continuation.jsonl\")\n"
|
682 |
+
]
|
683 |
+
},
|
684 |
+
{
|
685 |
+
"cell_type": "markdown",
|
686 |
+
"metadata": {
|
687 |
+
"id": "6p0-KPwAgK5j"
|
688 |
+
},
|
689 |
+
"source": [
|
690 |
+
"## Closer Look at YAML Fields\n",
|
691 |
+
"\n",
|
692 |
+
"To prepare a task we can simply fill in a YAML config with the relevant information.\n",
|
693 |
+
"\n",
|
694 |
+
"`output_type`\n",
|
695 |
+
"The current provided evaluation types comprise of the following:\n",
|
696 |
+
"1. `loglikelihood`: Evaluates the loglikelihood of a continuation, conditioned on some input string.\n",
|
697 |
+
"2. `loglikelihood_rolling`: evaluate the loglikelihood of producing a string, conditioned on the empty string. (Used for perplexity evaluations)\n",
|
698 |
+
"3. `multiple_choice`: Evaluates loglikelihood among the a number of choices predicted by the model.\n",
|
699 |
+
"4. `greedy_until`: Model outputs greedy generation (can be configured to to use beam search and other generation-related parameters)\n",
|
700 |
+
"\n",
|
701 |
+
"The core prompt revolves around 3 fields.\n",
|
702 |
+
"1. `doc_to_text`: Denotes the prompt template that will be used as input to the model.\n",
|
703 |
+
"2. `doc_to_choice`: Available choices that will be used as continuation for the model. This is used when the `output_type` is `multiple_choice`, and otherwise can be left as `None`.\n",
|
704 |
+
"3. `doc_to_target`: When `output_type` is `multiple_choice`, this can be an index that corresponds to the correct answer, or the answer string itself (must be a subset of `doc_to_choice`). For other tasks, this is expected to be a string. You can fill this field with a feature name from the HF dataset so long as the resulting feature follows the conditioned described.\n",
|
705 |
+
"\n",
|
706 |
+
"These three fields can be expressed as strings, column names from the source dataset, or as Jinja2 templates that can use fields from the source dataset as variables.\n"
|
707 |
+
]
|
708 |
+
},
|
709 |
+
{
|
710 |
+
"cell_type": "markdown",
|
711 |
+
"metadata": {
|
712 |
+
"id": "6p0-KPwAgK5j"
|
713 |
+
},
|
714 |
+
"source": [
|
715 |
+
"## What if Jinja is not Sufficient?\n",
|
716 |
+
"\n",
|
717 |
+
"There can be times where the Jinja2 templating language is not enough to make the prompt we had in mind. There are a few ways to circumvent this limitation:\n",
|
718 |
+
"\n",
|
719 |
+
"1. Use `!function` operator for the prompt-related fields to pass a python function that takes as input the dataset row, and will output the prompt template component.\n",
|
720 |
+
"2. Perform a transformation on the dataset beforehand."
|
721 |
+
]
|
722 |
+
},
|
723 |
+
{
|
724 |
+
"cell_type": "markdown",
|
725 |
+
"metadata": {},
|
726 |
+
"source": [
|
727 |
+
"Below, we show an example of using `!function` to create `doc_to_text` from a python function:"
|
728 |
+
]
|
729 |
+
},
|
730 |
+
{
|
731 |
+
"cell_type": "code",
|
732 |
+
"execution_count": 12,
|
733 |
+
"metadata": {
|
734 |
+
"colab": {
|
735 |
+
"base_uri": "https://localhost:8080/"
|
736 |
+
},
|
737 |
+
"id": "DYZ5c0JhR1lJ",
|
738 |
+
"outputId": "ca945235-fb9e-4f17-8bfa-78e7d6ec1490"
|
739 |
+
},
|
740 |
+
"outputs": [
|
741 |
+
{
|
742 |
+
"name": "stdout",
|
743 |
+
"output_type": "stream",
|
744 |
+
"text": [
|
745 |
+
"2023-11-29:11:59:08,312 INFO [utils.py:160] NumExpr defaulting to 2 threads.\n",
|
746 |
+
"2023-11-29 11:59:09.348327: E tensorflow/compiler/xla/stream_executor/cuda/cuda_dnn.cc:9342] Unable to register cuDNN factory: Attempting to register factory for plugin cuDNN when one has already been registered\n",
|
747 |
+
"2023-11-29 11:59:09.348387: E tensorflow/compiler/xla/stream_executor/cuda/cuda_fft.cc:609] Unable to register cuFFT factory: Attempting to register factory for plugin cuFFT when one has already been registered\n",
|
748 |
+
"2023-11-29 11:59:09.348421: E tensorflow/compiler/xla/stream_executor/cuda/cuda_blas.cc:1518] Unable to register cuBLAS factory: Attempting to register factory for plugin cuBLAS when one has already been registered\n",
|
749 |
+
"2023-11-29 11:59:10.573752: W tensorflow/compiler/tf2tensorrt/utils/py_utils.cc:38] TF-TRT Warning: Could not find TensorRT\n",
|
750 |
+
"2023-11-29:11:59:14,044 INFO [__main__.py:132] Verbosity set to INFO\n",
|
751 |
+
"2023-11-29:11:59:23,654 WARNING [__main__.py:138] --limit SHOULD ONLY BE USED FOR TESTING.REAL METRICS SHOULD NOT BE COMPUTED USING LIMIT.\n",
|
752 |
+
"2023-11-29:11:59:23,654 INFO [__main__.py:143] Including path: ./\n",
|
753 |
+
"2023-11-29:11:59:23,678 INFO [__main__.py:205] Selected Tasks: ['demo_mmlu_high_school_geography_function_prompt']\n",
|
754 |
+
"2023-11-29:11:59:23,679 WARNING [evaluator.py:93] generation_kwargs specified through cli, these settings will be used over set parameters in yaml tasks.\n",
|
755 |
+
"2023-11-29:11:59:23,708 INFO [huggingface.py:120] Using device 'cuda'\n",
|
756 |
+
"2023-11-29:11:59:44,516 INFO [task.py:355] Building contexts for task on rank 0...\n",
|
757 |
+
"2023-11-29:11:59:44,524 INFO [evaluator.py:319] Running loglikelihood requests\n",
|
758 |
+
"100% 40/40 [00:02<00:00, 15.41it/s]\n",
|
759 |
+
"fatal: not a git repository (or any of the parent directories): .git\n",
|
760 |
+
"hf (pretrained=EleutherAI/pythia-2.8b), gen_kwargs: (), limit: 10.0, num_fewshot: None, batch_size: 1\n",
|
761 |
+
"| Tasks |Version|Filter|n-shot| Metric |Value| |Stderr|\n",
|
762 |
+
"|-----------------------------------------------|-------|------|-----:|--------|----:|---|-----:|\n",
|
763 |
+
"|demo_mmlu_high_school_geography_function_prompt|Yaml |none | 0|acc | 0.1|± |0.1000|\n",
|
764 |
+
"| | |none | 0|acc_norm| 0.2|± |0.1333|\n",
|
765 |
+
"\n"
|
766 |
+
]
|
767 |
+
}
|
768 |
+
],
|
769 |
+
"source": [
|
770 |
+
"YAML_mmlu_geo_string = '''\n",
|
771 |
+
"include: mmlu_high_school_geography.yaml\n",
|
772 |
+
"task: demo_mmlu_high_school_geography_function_prompt\n",
|
773 |
+
"doc_to_text: !function utils.doc_to_text\n",
|
774 |
+
"doc_to_choice: \"{{choices}}\"\n",
|
775 |
+
"'''\n",
|
776 |
+
"with open('demo_mmlu_high_school_geography_function_prompt.yaml', 'w') as f:\n",
|
777 |
+
" f.write(YAML_mmlu_geo_string)\n",
|
778 |
+
"\n",
|
779 |
+
"DOC_TO_TEXT = '''\n",
|
780 |
+
"def doc_to_text(x):\n",
|
781 |
+
" question = x[\"question\"].strip()\n",
|
782 |
+
" choices = x[\"choices\"]\n",
|
783 |
+
" option_a = choices[0]\n",
|
784 |
+
" option_b = choices[1]\n",
|
785 |
+
" option_c = choices[2]\n",
|
786 |
+
" option_d = choices[3]\n",
|
787 |
+
" return f\"{question}\\\\nA. {option_a}\\\\nB. {option_b}\\\\nC. {option_c}\\\\nD. {option_d}\\\\nAnswer:\"\n",
|
788 |
+
"'''\n",
|
789 |
+
"with open('utils.py', 'w') as f:\n",
|
790 |
+
" f.write(DOC_TO_TEXT)\n",
|
791 |
+
"\n",
|
792 |
+
"!lm_eval \\\n",
|
793 |
+
" --model hf \\\n",
|
794 |
+
" --model_args pretrained=EleutherAI/pythia-2.8b \\\n",
|
795 |
+
" --include_path ./ \\\n",
|
796 |
+
" --tasks demo_mmlu_high_school_geography_function_prompt \\\n",
|
797 |
+
" --limit 10 \\\n",
|
798 |
+
" --output output/demo_mmlu_high_school_geography_function_prompt/ \\\n",
|
799 |
+
" --log_samples\n"
|
800 |
+
]
|
801 |
+
},
|
802 |
+
{
|
803 |
+
"cell_type": "markdown",
|
804 |
+
"metadata": {},
|
805 |
+
"source": [
|
806 |
+
"Next, we'll also show how to do this via preprocessing the dataset as necessary using the `process_docs` config field:\n",
|
807 |
+
"\n",
|
808 |
+
"We will write a function that will modify each document in our evaluation dataset's split to add a field that is suitable for us to use in `doc_to_text`."
|
809 |
+
]
|
810 |
+
},
|
811 |
+
{
|
812 |
+
"cell_type": "code",
|
813 |
+
"execution_count": null,
|
814 |
+
"metadata": {},
|
815 |
+
"outputs": [],
|
816 |
+
"source": [
|
817 |
+
"YAML_mmlu_geo_string = '''\n",
|
818 |
+
"include: mmlu_high_school_geography.yaml\n",
|
819 |
+
"task: demo_mmlu_high_school_geography_function_prompt_2\n",
|
820 |
+
"process_docs: !function utils_process_docs.process_docs\n",
|
821 |
+
"doc_to_text: \"{{input}}\"\n",
|
822 |
+
"doc_to_choice: \"{{choices}}\"\n",
|
823 |
+
"'''\n",
|
824 |
+
"with open('demo_mmlu_high_school_geography_process_docs.yaml', 'w') as f:\n",
|
825 |
+
" f.write(YAML_mmlu_geo_string)\n",
|
826 |
+
"\n",
|
827 |
+
"DOC_TO_TEXT = '''\n",
|
828 |
+
"def process_docs(dataset):\n",
|
829 |
+
" def _process_doc(x):\n",
|
830 |
+
" question = x[\"question\"].strip()\n",
|
831 |
+
" choices = x[\"choices\"]\n",
|
832 |
+
" option_a = choices[0]\n",
|
833 |
+
" option_b = choices[1]\n",
|
834 |
+
" option_c = choices[2]\n",
|
835 |
+
" option_d = choices[3]\n",
|
836 |
+
" doc[\"input\"] = f\"{question}\\\\nA. {option_a}\\\\nB. {option_b}\\\\nC. {option_c}\\\\nD. {option_d}\\\\nAnswer:\"\n",
|
837 |
+
" return out_doc\n",
|
838 |
+
"\n",
|
839 |
+
" return dataset.map(_process_doc)\n",
|
840 |
+
"'''\n",
|
841 |
+
"\n",
|
842 |
+
"with open('utils_process_docs.py', 'w') as f:\n",
|
843 |
+
" f.write(DOC_TO_TEXT)\n",
|
844 |
+
"\n",
|
845 |
+
"!lm_eval \\\n",
|
846 |
+
" --model hf \\\n",
|
847 |
+
" --model_args pretrained=EleutherAI/pythia-2.8b \\\n",
|
848 |
+
" --include_path ./ \\\n",
|
849 |
+
" --tasks demo_mmlu_high_school_geography_function_prompt_2 \\\n",
|
850 |
+
" --limit 10 \\\n",
|
851 |
+
" --output output/demo_mmlu_high_school_geography_function_prompt_2/ \\\n",
|
852 |
+
" --log_samples\n"
|
853 |
+
]
|
854 |
+
},
|
855 |
+
{
|
856 |
+
"cell_type": "markdown",
|
857 |
+
"metadata": {},
|
858 |
+
"source": [
|
859 |
+
"We hope that this explainer gives you a sense of what can be done with and how to work with LM-Evaluation-Harnes v0.4.0 ! \n",
|
860 |
+
"\n",
|
861 |
+
"For more information, check out our documentation pages in the `docs/` folder, and if you have questions, please raise them in GitHub issues, or in #lm-thunderdome or #release-discussion on the EleutherAI discord server."
|
862 |
+
]
|
863 |
+
}
|
864 |
+
],
|
865 |
+
"metadata": {
|
866 |
+
"accelerator": "GPU",
|
867 |
+
"colab": {
|
868 |
+
"collapsed_sections": [
|
869 |
+
"zAov81vTbL2K"
|
870 |
+
],
|
871 |
+
"gpuType": "T4",
|
872 |
+
"provenance": []
|
873 |
+
},
|
874 |
+
"kernelspec": {
|
875 |
+
"display_name": "Python 3",
|
876 |
+
"name": "python3"
|
877 |
+
},
|
878 |
+
"language_info": {
|
879 |
+
"name": "python"
|
880 |
+
},
|
881 |
+
"widgets": {
|
882 |
+
"application/vnd.jupyter.widget-state+json": {
|
883 |
+
"46f521b73fd943c081c648fd873ebc0a": {
|
884 |
+
"model_module": "@jupyter-widgets/controls",
|
885 |
+
"model_module_version": "1.5.0",
|
886 |
+
"model_name": "DescriptionStyleModel",
|
887 |
+
"state": {
|
888 |
+
"_model_module": "@jupyter-widgets/controls",
|
889 |
+
"_model_module_version": "1.5.0",
|
890 |
+
"_model_name": "DescriptionStyleModel",
|
891 |
+
"_view_count": null,
|
892 |
+
"_view_module": "@jupyter-widgets/base",
|
893 |
+
"_view_module_version": "1.2.0",
|
894 |
+
"_view_name": "StyleView",
|
895 |
+
"description_width": ""
|
896 |
+
}
|
897 |
+
},
|
898 |
+
"48763b6233374554ae76035c0483066f": {
|
899 |
+
"model_module": "@jupyter-widgets/controls",
|
900 |
+
"model_module_version": "1.5.0",
|
901 |
+
"model_name": "ProgressStyleModel",
|
902 |
+
"state": {
|
903 |
+
"_model_module": "@jupyter-widgets/controls",
|
904 |
+
"_model_module_version": "1.5.0",
|
905 |
+
"_model_name": "ProgressStyleModel",
|
906 |
+
"_view_count": null,
|
907 |
+
"_view_module": "@jupyter-widgets/base",
|
908 |
+
"_view_module_version": "1.2.0",
|
909 |
+
"_view_name": "StyleView",
|
910 |
+
"bar_color": null,
|
911 |
+
"description_width": ""
|
912 |
+
}
|
913 |
+
},
|
914 |
+
"4986a21eb560448fa79f4b25cde48951": {
|
915 |
+
"model_module": "@jupyter-widgets/base",
|
916 |
+
"model_module_version": "1.2.0",
|
917 |
+
"model_name": "LayoutModel",
|
918 |
+
"state": {
|
919 |
+
"_model_module": "@jupyter-widgets/base",
|
920 |
+
"_model_module_version": "1.2.0",
|
921 |
+
"_model_name": "LayoutModel",
|
922 |
+
"_view_count": null,
|
923 |
+
"_view_module": "@jupyter-widgets/base",
|
924 |
+
"_view_module_version": "1.2.0",
|
925 |
+
"_view_name": "LayoutView",
|
926 |
+
"align_content": null,
|
927 |
+
"align_items": null,
|
928 |
+
"align_self": null,
|
929 |
+
"border": null,
|
930 |
+
"bottom": null,
|
931 |
+
"display": null,
|
932 |
+
"flex": null,
|
933 |
+
"flex_flow": null,
|
934 |
+
"grid_area": null,
|
935 |
+
"grid_auto_columns": null,
|
936 |
+
"grid_auto_flow": null,
|
937 |
+
"grid_auto_rows": null,
|
938 |
+
"grid_column": null,
|
939 |
+
"grid_gap": null,
|
940 |
+
"grid_row": null,
|
941 |
+
"grid_template_areas": null,
|
942 |
+
"grid_template_columns": null,
|
943 |
+
"grid_template_rows": null,
|
944 |
+
"height": null,
|
945 |
+
"justify_content": null,
|
946 |
+
"justify_items": null,
|
947 |
+
"left": null,
|
948 |
+
"margin": null,
|
949 |
+
"max_height": null,
|
950 |
+
"max_width": null,
|
951 |
+
"min_height": null,
|
952 |
+
"min_width": null,
|
953 |
+
"object_fit": null,
|
954 |
+
"object_position": null,
|
955 |
+
"order": null,
|
956 |
+
"overflow": null,
|
957 |
+
"overflow_x": null,
|
958 |
+
"overflow_y": null,
|
959 |
+
"padding": null,
|
960 |
+
"right": null,
|
961 |
+
"top": null,
|
962 |
+
"visibility": null,
|
963 |
+
"width": null
|
964 |
+
}
|
965 |
+
},
|
966 |
+
"6b2d90209ec14230b3d58a74ac9b83bf": {
|
967 |
+
"model_module": "@jupyter-widgets/base",
|
968 |
+
"model_module_version": "1.2.0",
|
969 |
+
"model_name": "LayoutModel",
|
970 |
+
"state": {
|
971 |
+
"_model_module": "@jupyter-widgets/base",
|
972 |
+
"_model_module_version": "1.2.0",
|
973 |
+
"_model_name": "LayoutModel",
|
974 |
+
"_view_count": null,
|
975 |
+
"_view_module": "@jupyter-widgets/base",
|
976 |
+
"_view_module_version": "1.2.0",
|
977 |
+
"_view_name": "LayoutView",
|
978 |
+
"align_content": null,
|
979 |
+
"align_items": null,
|
980 |
+
"align_self": null,
|
981 |
+
"border": null,
|
982 |
+
"bottom": null,
|
983 |
+
"display": null,
|
984 |
+
"flex": null,
|
985 |
+
"flex_flow": null,
|
986 |
+
"grid_area": null,
|
987 |
+
"grid_auto_columns": null,
|
988 |
+
"grid_auto_flow": null,
|
989 |
+
"grid_auto_rows": null,
|
990 |
+
"grid_column": null,
|
991 |
+
"grid_gap": null,
|
992 |
+
"grid_row": null,
|
993 |
+
"grid_template_areas": null,
|
994 |
+
"grid_template_columns": null,
|
995 |
+
"grid_template_rows": null,
|
996 |
+
"height": null,
|
997 |
+
"justify_content": null,
|
998 |
+
"justify_items": null,
|
999 |
+
"left": null,
|
1000 |
+
"margin": null,
|
1001 |
+
"max_height": null,
|
1002 |
+
"max_width": null,
|
1003 |
+
"min_height": null,
|
1004 |
+
"min_width": null,
|
1005 |
+
"object_fit": null,
|
1006 |
+
"object_position": null,
|
1007 |
+
"order": null,
|
1008 |
+
"overflow": null,
|
1009 |
+
"overflow_x": null,
|
1010 |
+
"overflow_y": null,
|
1011 |
+
"padding": null,
|
1012 |
+
"right": null,
|
1013 |
+
"top": null,
|
1014 |
+
"visibility": null,
|
1015 |
+
"width": null
|
1016 |
+
}
|
1017 |
+
},
|
1018 |
+
"7c5689bc13684db8a22681f41863dddd": {
|
1019 |
+
"model_module": "@jupyter-widgets/base",
|
1020 |
+
"model_module_version": "1.2.0",
|
1021 |
+
"model_name": "LayoutModel",
|
1022 |
+
"state": {
|
1023 |
+
"_model_module": "@jupyter-widgets/base",
|
1024 |
+
"_model_module_version": "1.2.0",
|
1025 |
+
"_model_name": "LayoutModel",
|
1026 |
+
"_view_count": null,
|
1027 |
+
"_view_module": "@jupyter-widgets/base",
|
1028 |
+
"_view_module_version": "1.2.0",
|
1029 |
+
"_view_name": "LayoutView",
|
1030 |
+
"align_content": null,
|
1031 |
+
"align_items": null,
|
1032 |
+
"align_self": null,
|
1033 |
+
"border": null,
|
1034 |
+
"bottom": null,
|
1035 |
+
"display": null,
|
1036 |
+
"flex": null,
|
1037 |
+
"flex_flow": null,
|
1038 |
+
"grid_area": null,
|
1039 |
+
"grid_auto_columns": null,
|
1040 |
+
"grid_auto_flow": null,
|
1041 |
+
"grid_auto_rows": null,
|
1042 |
+
"grid_column": null,
|
1043 |
+
"grid_gap": null,
|
1044 |
+
"grid_row": null,
|
1045 |
+
"grid_template_areas": null,
|
1046 |
+
"grid_template_columns": null,
|
1047 |
+
"grid_template_rows": null,
|
1048 |
+
"height": null,
|
1049 |
+
"justify_content": null,
|
1050 |
+
"justify_items": null,
|
1051 |
+
"left": null,
|
1052 |
+
"margin": null,
|
1053 |
+
"max_height": null,
|
1054 |
+
"max_width": null,
|
1055 |
+
"min_height": null,
|
1056 |
+
"min_width": null,
|
1057 |
+
"object_fit": null,
|
1058 |
+
"object_position": null,
|
1059 |
+
"order": null,
|
1060 |
+
"overflow": null,
|
1061 |
+
"overflow_x": null,
|
1062 |
+
"overflow_y": null,
|
1063 |
+
"padding": null,
|
1064 |
+
"right": null,
|
1065 |
+
"top": null,
|
1066 |
+
"visibility": null,
|
1067 |
+
"width": null
|
1068 |
+
}
|
1069 |
+
},
|
1070 |
+
"a1d3a8aa016544a78e8821c8f6199e06": {
|
1071 |
+
"model_module": "@jupyter-widgets/controls",
|
1072 |
+
"model_module_version": "1.5.0",
|
1073 |
+
"model_name": "HBoxModel",
|
1074 |
+
"state": {
|
1075 |
+
"_dom_classes": [],
|
1076 |
+
"_model_module": "@jupyter-widgets/controls",
|
1077 |
+
"_model_module_version": "1.5.0",
|
1078 |
+
"_model_name": "HBoxModel",
|
1079 |
+
"_view_count": null,
|
1080 |
+
"_view_module": "@jupyter-widgets/controls",
|
1081 |
+
"_view_module_version": "1.5.0",
|
1082 |
+
"_view_name": "HBoxView",
|
1083 |
+
"box_style": "",
|
1084 |
+
"children": [
|
1085 |
+
"IPY_MODEL_f61ed33fad754146bdd2ac9db1ba1c48",
|
1086 |
+
"IPY_MODEL_bfa0af6aeff344c6845e1080a878e92e",
|
1087 |
+
"IPY_MODEL_fd1ad9e0367d4004aae853b91c3a7617"
|
1088 |
+
],
|
1089 |
+
"layout": "IPY_MODEL_6b2d90209ec14230b3d58a74ac9b83bf"
|
1090 |
+
}
|
1091 |
+
},
|
1092 |
+
"a73f357065d34d7baf0453ae4a8d75e2": {
|
1093 |
+
"model_module": "@jupyter-widgets/base",
|
1094 |
+
"model_module_version": "1.2.0",
|
1095 |
+
"model_name": "LayoutModel",
|
1096 |
+
"state": {
|
1097 |
+
"_model_module": "@jupyter-widgets/base",
|
1098 |
+
"_model_module_version": "1.2.0",
|
1099 |
+
"_model_name": "LayoutModel",
|
1100 |
+
"_view_count": null,
|
1101 |
+
"_view_module": "@jupyter-widgets/base",
|
1102 |
+
"_view_module_version": "1.2.0",
|
1103 |
+
"_view_name": "LayoutView",
|
1104 |
+
"align_content": null,
|
1105 |
+
"align_items": null,
|
1106 |
+
"align_self": null,
|
1107 |
+
"border": null,
|
1108 |
+
"bottom": null,
|
1109 |
+
"display": null,
|
1110 |
+
"flex": null,
|
1111 |
+
"flex_flow": null,
|
1112 |
+
"grid_area": null,
|
1113 |
+
"grid_auto_columns": null,
|
1114 |
+
"grid_auto_flow": null,
|
1115 |
+
"grid_auto_rows": null,
|
1116 |
+
"grid_column": null,
|
1117 |
+
"grid_gap": null,
|
1118 |
+
"grid_row": null,
|
1119 |
+
"grid_template_areas": null,
|
1120 |
+
"grid_template_columns": null,
|
1121 |
+
"grid_template_rows": null,
|
1122 |
+
"height": null,
|
1123 |
+
"justify_content": null,
|
1124 |
+
"justify_items": null,
|
1125 |
+
"left": null,
|
1126 |
+
"margin": null,
|
1127 |
+
"max_height": null,
|
1128 |
+
"max_width": null,
|
1129 |
+
"min_height": null,
|
1130 |
+
"min_width": null,
|
1131 |
+
"object_fit": null,
|
1132 |
+
"object_position": null,
|
1133 |
+
"order": null,
|
1134 |
+
"overflow": null,
|
1135 |
+
"overflow_x": null,
|
1136 |
+
"overflow_y": null,
|
1137 |
+
"padding": null,
|
1138 |
+
"right": null,
|
1139 |
+
"top": null,
|
1140 |
+
"visibility": null,
|
1141 |
+
"width": null
|
1142 |
+
}
|
1143 |
+
},
|
1144 |
+
"aed3acd2f2d74003b44079c333a0698e": {
|
1145 |
+
"model_module": "@jupyter-widgets/controls",
|
1146 |
+
"model_module_version": "1.5.0",
|
1147 |
+
"model_name": "DescriptionStyleModel",
|
1148 |
+
"state": {
|
1149 |
+
"_model_module": "@jupyter-widgets/controls",
|
1150 |
+
"_model_module_version": "1.5.0",
|
1151 |
+
"_model_name": "DescriptionStyleModel",
|
1152 |
+
"_view_count": null,
|
1153 |
+
"_view_module": "@jupyter-widgets/base",
|
1154 |
+
"_view_module_version": "1.2.0",
|
1155 |
+
"_view_name": "StyleView",
|
1156 |
+
"description_width": ""
|
1157 |
+
}
|
1158 |
+
},
|
1159 |
+
"bfa0af6aeff344c6845e1080a878e92e": {
|
1160 |
+
"model_module": "@jupyter-widgets/controls",
|
1161 |
+
"model_module_version": "1.5.0",
|
1162 |
+
"model_name": "FloatProgressModel",
|
1163 |
+
"state": {
|
1164 |
+
"_dom_classes": [],
|
1165 |
+
"_model_module": "@jupyter-widgets/controls",
|
1166 |
+
"_model_module_version": "1.5.0",
|
1167 |
+
"_model_name": "FloatProgressModel",
|
1168 |
+
"_view_count": null,
|
1169 |
+
"_view_module": "@jupyter-widgets/controls",
|
1170 |
+
"_view_module_version": "1.5.0",
|
1171 |
+
"_view_name": "ProgressView",
|
1172 |
+
"bar_style": "success",
|
1173 |
+
"description": "",
|
1174 |
+
"description_tooltip": null,
|
1175 |
+
"layout": "IPY_MODEL_7c5689bc13684db8a22681f41863dddd",
|
1176 |
+
"max": 5669,
|
1177 |
+
"min": 0,
|
1178 |
+
"orientation": "horizontal",
|
1179 |
+
"style": "IPY_MODEL_48763b6233374554ae76035c0483066f",
|
1180 |
+
"value": 5669
|
1181 |
+
}
|
1182 |
+
},
|
1183 |
+
"f61ed33fad754146bdd2ac9db1ba1c48": {
|
1184 |
+
"model_module": "@jupyter-widgets/controls",
|
1185 |
+
"model_module_version": "1.5.0",
|
1186 |
+
"model_name": "HTMLModel",
|
1187 |
+
"state": {
|
1188 |
+
"_dom_classes": [],
|
1189 |
+
"_model_module": "@jupyter-widgets/controls",
|
1190 |
+
"_model_module_version": "1.5.0",
|
1191 |
+
"_model_name": "HTMLModel",
|
1192 |
+
"_view_count": null,
|
1193 |
+
"_view_module": "@jupyter-widgets/controls",
|
1194 |
+
"_view_module_version": "1.5.0",
|
1195 |
+
"_view_name": "HTMLView",
|
1196 |
+
"description": "",
|
1197 |
+
"description_tooltip": null,
|
1198 |
+
"layout": "IPY_MODEL_a73f357065d34d7baf0453ae4a8d75e2",
|
1199 |
+
"placeholder": "",
|
1200 |
+
"style": "IPY_MODEL_46f521b73fd943c081c648fd873ebc0a",
|
1201 |
+
"value": "Downloading builder script: 100%"
|
1202 |
+
}
|
1203 |
+
},
|
1204 |
+
"fd1ad9e0367d4004aae853b91c3a7617": {
|
1205 |
+
"model_module": "@jupyter-widgets/controls",
|
1206 |
+
"model_module_version": "1.5.0",
|
1207 |
+
"model_name": "HTMLModel",
|
1208 |
+
"state": {
|
1209 |
+
"_dom_classes": [],
|
1210 |
+
"_model_module": "@jupyter-widgets/controls",
|
1211 |
+
"_model_module_version": "1.5.0",
|
1212 |
+
"_model_name": "HTMLModel",
|
1213 |
+
"_view_count": null,
|
1214 |
+
"_view_module": "@jupyter-widgets/controls",
|
1215 |
+
"_view_module_version": "1.5.0",
|
1216 |
+
"_view_name": "HTMLView",
|
1217 |
+
"description": "",
|
1218 |
+
"description_tooltip": null,
|
1219 |
+
"layout": "IPY_MODEL_4986a21eb560448fa79f4b25cde48951",
|
1220 |
+
"placeholder": "",
|
1221 |
+
"style": "IPY_MODEL_aed3acd2f2d74003b44079c333a0698e",
|
1222 |
+
"value": " 5.67k/5.67k [00:00<00:00, 205kB/s]"
|
1223 |
+
}
|
1224 |
+
}
|
1225 |
+
}
|
1226 |
+
}
|
1227 |
+
},
|
1228 |
+
"nbformat": 4,
|
1229 |
+
"nbformat_minor": 0
|
1230 |
+
}
|
scripts/yans/lm-evaluation-harness/examples/visualize-wandb.ipynb
ADDED
@@ -0,0 +1,170 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"cells": [
|
3 |
+
{
|
4 |
+
"cell_type": "markdown",
|
5 |
+
"id": "fc477b96-adee-4829-a9d7-a5eb990df358",
|
6 |
+
"metadata": {},
|
7 |
+
"source": [
|
8 |
+
"# Visualizing Results in Weights and Biases\n",
|
9 |
+
"\n",
|
10 |
+
"With the Weights and Biases integration, you can now spend more time extracting deeper insights into your evaluation results. The integration is designed to streamline the process of logging and visualizing experiment results using the Weights & Biases (W&B) platform.\n",
|
11 |
+
"\n",
|
12 |
+
"The integration provide functionalities\n",
|
13 |
+
"\n",
|
14 |
+
"- to automatically log the evaluation results,\n",
|
15 |
+
"- log the samples as W&B Tables for easy visualization,\n",
|
16 |
+
"- log the `results.json` file as an artifact for version control,\n",
|
17 |
+
"- log the `<task_name>_eval_samples.json` file if the samples are logged,\n",
|
18 |
+
"- generate a comprehensive report for analysis and visualization with all the important metric,\n",
|
19 |
+
"- log task and cli configs,\n",
|
20 |
+
"- and more out of the box like the command used to run the evaluation, GPU/CPU counts, timestamp, etc.\n",
|
21 |
+
"\n",
|
22 |
+
"The integration is super easy to use with the eval harness. Let's see how!"
|
23 |
+
]
|
24 |
+
},
|
25 |
+
{
|
26 |
+
"cell_type": "code",
|
27 |
+
"execution_count": null,
|
28 |
+
"id": "3851439a-bff4-41f2-bf21-1b3d8704913b",
|
29 |
+
"metadata": {
|
30 |
+
"scrolled": true
|
31 |
+
},
|
32 |
+
"outputs": [],
|
33 |
+
"source": [
|
34 |
+
"# Install this project if you did not already have it.\n",
|
35 |
+
"# This is all that is needed to be installed to start using Weights and Biases\n",
|
36 |
+
"\n",
|
37 |
+
"!pip -qq install -e ..[wandb]"
|
38 |
+
]
|
39 |
+
},
|
40 |
+
{
|
41 |
+
"cell_type": "markdown",
|
42 |
+
"id": "8507fd7e-3b99-4a92-89fa-9eaada74ba91",
|
43 |
+
"metadata": {},
|
44 |
+
"source": [
|
45 |
+
"# Run the Eval Harness\n",
|
46 |
+
"\n",
|
47 |
+
"Run the eval harness as usual with a `wandb_args` flag. This flag is used to provide arguments for initializing a wandb run ([wandb.init](https://docs.wandb.ai/ref/python/init)) as comma separated string arguments.\n",
|
48 |
+
"\n",
|
49 |
+
"If `wandb_args` flag is used, the metrics and all other goodness will be automatically logged to Weights and Biases. In the stdout, you will find the link to the W&B run page as well as link to the generated report."
|
50 |
+
]
|
51 |
+
},
|
52 |
+
{
|
53 |
+
"cell_type": "markdown",
|
54 |
+
"id": "eec5866e-f01e-42f8-8803-9d77472ef991",
|
55 |
+
"metadata": {},
|
56 |
+
"source": [
|
57 |
+
"## Set your API Key\n",
|
58 |
+
"\n",
|
59 |
+
"Before you can use W&B, you need to authenticate your machine with an authentication key. Visit https://wandb.ai/authorize to get one."
|
60 |
+
]
|
61 |
+
},
|
62 |
+
{
|
63 |
+
"cell_type": "code",
|
64 |
+
"execution_count": null,
|
65 |
+
"id": "d824d163-71a9-4313-935d-f1d56397841c",
|
66 |
+
"metadata": {},
|
67 |
+
"outputs": [],
|
68 |
+
"source": [
|
69 |
+
"import wandb\n",
|
70 |
+
"\n",
|
71 |
+
"wandb.login()"
|
72 |
+
]
|
73 |
+
},
|
74 |
+
{
|
75 |
+
"cell_type": "markdown",
|
76 |
+
"id": "124e4a34-1547-4bed-bc09-db012bacbda6",
|
77 |
+
"metadata": {},
|
78 |
+
"source": [
|
79 |
+
"> Note that if you are using command line you can simply authenticate your machine by doing `wandb login` in your terminal. For more info check out the [documentation](https://docs.wandb.ai/quickstart#2-log-in-to-wb)."
|
80 |
+
]
|
81 |
+
},
|
82 |
+
{
|
83 |
+
"cell_type": "markdown",
|
84 |
+
"id": "abc6f6b6-179a-4aff-ada9-f380fb74df6e",
|
85 |
+
"metadata": {},
|
86 |
+
"source": [
|
87 |
+
"## Run and log to W&B"
|
88 |
+
]
|
89 |
+
},
|
90 |
+
{
|
91 |
+
"cell_type": "code",
|
92 |
+
"execution_count": null,
|
93 |
+
"id": "bd0a8130-a97b-451a-acd2-3f9885b88643",
|
94 |
+
"metadata": {},
|
95 |
+
"outputs": [],
|
96 |
+
"source": [
|
97 |
+
"!lm_eval \\\n",
|
98 |
+
" --model hf \\\n",
|
99 |
+
" --model_args pretrained=microsoft/phi-2,trust_remote_code=True \\\n",
|
100 |
+
" --tasks hellaswag,mmlu_abstract_algebra \\\n",
|
101 |
+
" --device cuda:0 \\\n",
|
102 |
+
" --batch_size 8 \\\n",
|
103 |
+
" --output_path output/phi-2 \\\n",
|
104 |
+
" --limit 10 \\\n",
|
105 |
+
" --wandb_args project=lm-eval-harness-integration \\\n",
|
106 |
+
" --log_samples"
|
107 |
+
]
|
108 |
+
},
|
109 |
+
{
|
110 |
+
"cell_type": "markdown",
|
111 |
+
"id": "e974cabdbe70b667",
|
112 |
+
"metadata": {},
|
113 |
+
"source": []
|
114 |
+
},
|
115 |
+
{
|
116 |
+
"cell_type": "markdown",
|
117 |
+
"id": "5178ca9445b844e4",
|
118 |
+
"metadata": {},
|
119 |
+
"source": [
|
120 |
+
"W&B can also be initialized programmatically for use outside the CLI to parse and log the results."
|
121 |
+
]
|
122 |
+
},
|
123 |
+
{
|
124 |
+
"cell_type": "code",
|
125 |
+
"execution_count": null,
|
126 |
+
"id": "c6a421b2cf3ddac5",
|
127 |
+
"metadata": {},
|
128 |
+
"outputs": [],
|
129 |
+
"source": [
|
130 |
+
"import lm_eval\n",
|
131 |
+
"from lm_eval.loggers import WandbLogger\n",
|
132 |
+
"\n",
|
133 |
+
"results = lm_eval.simple_evaluate(\n",
|
134 |
+
" model=\"hf\",\n",
|
135 |
+
" model_args=\"pretrained=microsoft/phi-2,trust_remote_code=True\",\n",
|
136 |
+
" tasks=\"hellaswag,mmlu_abstract_algebra\",\n",
|
137 |
+
" log_samples=True,\n",
|
138 |
+
")\n",
|
139 |
+
"\n",
|
140 |
+
"wandb_logger = WandbLogger(\n",
|
141 |
+
" project=\"lm-eval-harness-integration\", job_type=\"eval\"\n",
|
142 |
+
") # or empty if wandb.init(...) already called before\n",
|
143 |
+
"wandb_logger.post_init(results)\n",
|
144 |
+
"wandb_logger.log_eval_result()\n",
|
145 |
+
"wandb_logger.log_eval_samples(results[\"samples\"]) # if log_samples"
|
146 |
+
]
|
147 |
+
}
|
148 |
+
],
|
149 |
+
"metadata": {
|
150 |
+
"kernelspec": {
|
151 |
+
"display_name": "Python 3 (ipykernel)",
|
152 |
+
"language": "python",
|
153 |
+
"name": "python3"
|
154 |
+
},
|
155 |
+
"language_info": {
|
156 |
+
"codemirror_mode": {
|
157 |
+
"name": "ipython",
|
158 |
+
"version": 3
|
159 |
+
},
|
160 |
+
"file_extension": ".py",
|
161 |
+
"mimetype": "text/x-python",
|
162 |
+
"name": "python",
|
163 |
+
"nbconvert_exporter": "python",
|
164 |
+
"pygments_lexer": "ipython3",
|
165 |
+
"version": "3.10.12"
|
166 |
+
}
|
167 |
+
},
|
168 |
+
"nbformat": 4,
|
169 |
+
"nbformat_minor": 5
|
170 |
+
}
|
scripts/yans/lm-evaluation-harness/examples/visualize-zeno.ipynb
ADDED
@@ -0,0 +1,115 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"cells": [
|
3 |
+
{
|
4 |
+
"cell_type": "markdown",
|
5 |
+
"metadata": {},
|
6 |
+
"source": [
|
7 |
+
"# Visualizing Results in Zeno\n",
|
8 |
+
"\n",
|
9 |
+
"Benchmarking your models is the first step towards making sure your model performs well.\n",
|
10 |
+
"However, looking at the data behind the benchmark, slicing the data into subsets, and comparing models on individual instances can help you even more in evaluating and quantifying the behavior of your AI system.\n",
|
11 |
+
"\n",
|
12 |
+
"All of this can be done in [Zeno](https://zenoml.com)!\n",
|
13 |
+
"Zeno is super easy to use with the eval harness, let's explore how you can easily upload and visualize your eval results.\n"
|
14 |
+
]
|
15 |
+
},
|
16 |
+
{
|
17 |
+
"cell_type": "code",
|
18 |
+
"execution_count": null,
|
19 |
+
"metadata": {},
|
20 |
+
"outputs": [],
|
21 |
+
"source": [
|
22 |
+
"# Install this project if you did not already do that. This is all that needs to be installed for you to be able to visualize your data in Zeno!\n",
|
23 |
+
"!pip install -e ..\n",
|
24 |
+
"!pip install -e ..[zeno]"
|
25 |
+
]
|
26 |
+
},
|
27 |
+
{
|
28 |
+
"cell_type": "markdown",
|
29 |
+
"metadata": {},
|
30 |
+
"source": [
|
31 |
+
"# Run the Eval Harness\n",
|
32 |
+
"\n",
|
33 |
+
"To visualize the results, run the eval harness with the `log_samples` and `output_path` flags. We expect `output_path` to contain multiple folders that represent individual model names. You can thus run your evaluation on any number of tasks and models and upload all of the results as projects on Zeno.\n"
|
34 |
+
]
|
35 |
+
},
|
36 |
+
{
|
37 |
+
"cell_type": "code",
|
38 |
+
"execution_count": null,
|
39 |
+
"metadata": {},
|
40 |
+
"outputs": [],
|
41 |
+
"source": [
|
42 |
+
"!lm_eval \\\n",
|
43 |
+
" --model hf \\\n",
|
44 |
+
" --model_args pretrained=EleutherAI/gpt-neo-2.7B \\\n",
|
45 |
+
" --tasks hellaswag,wikitext \\\n",
|
46 |
+
" --batch_size 8 \\\n",
|
47 |
+
" --device mps \\\n",
|
48 |
+
" --log_samples \\\n",
|
49 |
+
" --output_path output/gpt-neo-2.7B \\\n",
|
50 |
+
" --limit 10"
|
51 |
+
]
|
52 |
+
},
|
53 |
+
{
|
54 |
+
"cell_type": "markdown",
|
55 |
+
"metadata": {},
|
56 |
+
"source": [
|
57 |
+
"# Set your API Key\n",
|
58 |
+
"\n",
|
59 |
+
"This is so you can be authenticated with Zeno.\n",
|
60 |
+
"If you don't already have a Zeno account, first create an account on [Zeno Hub](https://hub.zenoml.com).\n",
|
61 |
+
"After logging in to Zeno Hub, generate your API key by clicking on your profile at the bottom left to navigate to your account page.\n"
|
62 |
+
]
|
63 |
+
},
|
64 |
+
{
|
65 |
+
"cell_type": "code",
|
66 |
+
"execution_count": null,
|
67 |
+
"metadata": {},
|
68 |
+
"outputs": [],
|
69 |
+
"source": [
|
70 |
+
"%env ZENO_API_KEY=YOUR_API_KEY"
|
71 |
+
]
|
72 |
+
},
|
73 |
+
{
|
74 |
+
"cell_type": "markdown",
|
75 |
+
"metadata": {},
|
76 |
+
"source": [
|
77 |
+
"# Visualize Eval Results\n",
|
78 |
+
"\n",
|
79 |
+
"You can now use the `zeno_visualize` script to upload the results to Zeno.\n",
|
80 |
+
"\n",
|
81 |
+
"This will use all subfolders in `data_path` as different models and upload all tasks within these model folders to Zeno. If you run the eval harness on multiple tasks, the `project_name` will be used as a prefix and one project will be created per task.\n"
|
82 |
+
]
|
83 |
+
},
|
84 |
+
{
|
85 |
+
"cell_type": "code",
|
86 |
+
"execution_count": null,
|
87 |
+
"metadata": {},
|
88 |
+
"outputs": [],
|
89 |
+
"source": [
|
90 |
+
"!python ../scripts/zeno_visualize.py --data_path output --project_name \"Zeno Upload Test\""
|
91 |
+
]
|
92 |
+
}
|
93 |
+
],
|
94 |
+
"metadata": {
|
95 |
+
"kernelspec": {
|
96 |
+
"display_name": "zeno_projects",
|
97 |
+
"language": "python",
|
98 |
+
"name": "python3"
|
99 |
+
},
|
100 |
+
"language_info": {
|
101 |
+
"codemirror_mode": {
|
102 |
+
"name": "ipython",
|
103 |
+
"version": 3
|
104 |
+
},
|
105 |
+
"file_extension": ".py",
|
106 |
+
"mimetype": "text/x-python",
|
107 |
+
"name": "python",
|
108 |
+
"nbconvert_exporter": "python",
|
109 |
+
"pygments_lexer": "ipython3",
|
110 |
+
"version": "3.10.11"
|
111 |
+
}
|
112 |
+
},
|
113 |
+
"nbformat": 4,
|
114 |
+
"nbformat_minor": 2
|
115 |
+
}
|
scripts/yans/lm-evaluation-harness/ignore.txt
ADDED
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
ROUGE
|
2 |
+
rouge
|
3 |
+
nin
|
4 |
+
maka
|
5 |
+
mor
|
6 |
+
te
|
7 |
+
ond
|
8 |
+
extraversion
|
scripts/yans/lm-evaluation-harness/ja_eval.sh
ADDED
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
lm_eval --model hf \
|
2 |
+
--model_args pretrained=/share/pretrained_lm/Qwen/Qwen2-0.5B\
|
3 |
+
--tasks jaqket_v1,jaqket_v2,jaquad,jblimp,jcola,jcommonsenseqa,jnli,jsquad,marc_ja,mgsm,wikilingua_ja,xlsum_ja,xwinograd_ja\
|
4 |
+
--device cuda:0 \
|
5 |
+
--batch_size 8
|
scripts/yans/lm-evaluation-harness/ja_eval2.sh
ADDED
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
lm_eval --model hf \
|
2 |
+
--model_args pretrained=/share/pretrained_lm/Qwen/Qwen2-0.5B\
|
3 |
+
--tasks "ja/jaqket_v1" \
|
4 |
+
--device cuda:0 \
|
5 |
+
--batch_size 8
|