leideng's picture
download
raw
11.8 kB
# Copyright (c) 2024, NVIDIA CORPORATION. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
Prepare prediction jsonl with field `pred` .
dataset jsonl:
{
"index" int,
"input": str,
"outputs": [str],
}
prediction jsonl:
{
"index" int,
"input": str,
"outputs": [str],
"pred": str,
}
"""
import argparse
import json
import yaml
import os
import sys
import threading
import importlib
import math
import time
from tqdm import tqdm
from pathlib import Path
import traceback
from nemo.collections.asr.parts.utils.manifest_utils import read_manifest
SERVER_TYPES = (
'trtllm',
'vllm',
'sglang',
'openai',
'gemini',
'hf',
'mamba',
)
class ServerAction(argparse.Action):
def __call__(self, parser, namespace, values, option_string=None):
namespace.server_type = values
parser = argparse.ArgumentParser()
# Data
parser.add_argument("--data_dir", type=Path, required=True, help='path to load the dataset jsonl files')
parser.add_argument("--save_dir", type=Path, required=True, help='path to save the prediction jsonl files')
parser.add_argument("--benchmark", type=str, default='synthetic', help='Options: [synthetic]')
parser.add_argument("--task", type=str, required=True, help='Options: tasks in benchmark')
parser.add_argument("--subset", type=str, default='validation', help='Options: validation or test')
parser.add_argument("--chunk_idx", type=int, default=0, help='index of current split chunk')
parser.add_argument("--chunk_amount", type=int, default=1, help='size of split chunk')
# Server
parser.add_argument("--server_type", default='nemo', action=ServerAction, choices=SERVER_TYPES)
parser.add_argument("--server_host", type=str, default='127.0.0.1')
parser.add_argument("--server_port", type=str, default='5000')
parser.add_argument("--ssh_server", type=str)
parser.add_argument("--ssh_key_path", type=str)
parser.add_argument("--model_name_or_path", type=str, default='gpt-3.5-turbo',
help='supported models from OpenAI or HF (provide a key or a local path to the checkpoint)')
# Inference
parser.add_argument("--temperature", type=float, default=1.0)
parser.add_argument("--top_k", type=int, default=32)
parser.add_argument("--top_p", type=float, default=1.0)
parser.add_argument("--random_seed", type=int, default=0)
parser.add_argument("--stop_words", type=str, default='')
parser.add_argument("--sliding_window_size", type=int)
parser.add_argument("--threads", type=int, default=4)
parser.add_argument("--batch_size", type=int, default=1)
args = parser.parse_args()
args.stop_words = list(filter(None, args.stop_words.split(',')))
if args.server_type == 'hf' or args.server_type == 'gemini':
args.threads = 1
def get_llm(tokens_to_generate):
if args.server_type == 'trtllm':
from client_wrappers import TRTLLMClient
llm = TRTLLMClient(
server_host=args.server_host,
server_port=args.server_port,
ssh_server=args.ssh_server,
ssh_key_path=args.ssh_key_path,
temperature=args.temperature,
top_k=args.top_k,
top_p=args.top_p,
random_seed=args.random_seed,
stop=args.stop_words,
tokens_to_generate=tokens_to_generate,
max_attention_window_size=args.sliding_window_size,
)
elif args.server_type == 'vllm':
from client_wrappers import VLLMClient
llm = VLLMClient(
server_host=args.server_host,
server_port=args.server_port,
ssh_server=args.ssh_server,
ssh_key_path=args.ssh_key_path,
temperature=args.temperature,
top_k=args.top_k,
top_p=args.top_p,
random_seed=args.random_seed,
stop=args.stop_words,
tokens_to_generate=tokens_to_generate,
)
elif args.server_type == 'sglang':
from client_wrappers import SGLClient
llm = SGLClient(
server_host=args.server_host,
server_port=args.server_port,
ssh_server=args.ssh_server,
ssh_key_path=args.ssh_key_path,
temperature=args.temperature,
top_k=args.top_k,
top_p=args.top_p,
random_seed=args.random_seed,
stop=args.stop_words,
tokens_to_generate=tokens_to_generate,
)
elif args.server_type == 'openai':
from client_wrappers import OpenAIClient
llm = OpenAIClient(
model_name=args.model_name_or_path,
temperature=args.temperature,
top_k=args.top_k,
top_p=args.top_p,
random_seed=args.random_seed,
stop=args.stop_words,
tokens_to_generate=tokens_to_generate,
)
elif args.server_type == 'gemini':
from client_wrappers import GeminiClient
llm = GeminiClient(
model_name=args.model_name_or_path,
temperature=args.temperature,
top_k=args.top_k,
top_p=args.top_p,
random_seed=args.random_seed,
stop=args.stop_words,
tokens_to_generate=tokens_to_generate,
)
elif args.server_type == 'hf':
from model_wrappers import HuggingFaceModel
llm = HuggingFaceModel(
name_or_path=args.model_name_or_path,
do_sample=args.temperature > 0,
repetition_penalty=1,
temperature=args.temperature,
top_k=args.top_k,
top_p=args.top_p,
stop=args.stop_words,
max_new_tokens=tokens_to_generate,
)
elif args.server_type == 'mamba':
from model_wrappers import MambaModel
# mamba uses its own generation function, do not pass in do_sample
# https://github.com/state-spaces/mamba/blob/009bec5ee37f586844a3fc89c040a9c1a9d8badf/mamba_ssm/utils/generation.py#L121
llm = MambaModel(
name_or_path=args.model_name_or_path,
repetition_penalty=1,
temperature=args.temperature,
top_k=args.top_k,
top_p=args.top_p,
stop=args.stop_words,
max_new_tokens=tokens_to_generate,
)
else:
raise RuntimeError(f'Unsupported server type {args.server_type}')
return llm
def main():
start_time = time.time()
curr_folder = os.path.dirname(os.path.abspath(__file__))
try:
sys.path.append(os.path.dirname(curr_folder))
module = importlib.import_module(f"data.{args.benchmark}.constants")
except ImportError:
print(f"Module data.{args.benchmark}.constants not found.")
tasks_base = module.TASKS
with open(os.path.join(curr_folder, f"../{args.benchmark}.yaml"), "r") as f:
tasks_customized = yaml.safe_load(f)
if args.task not in tasks_customized:
raise ValueError(f'{args.task} is not found in config_tasks.yaml')
config = tasks_customized.get(args.task)
config.update(tasks_base[config['task']])
task_file = args.data_dir / args.task / f'{args.subset}.jsonl'
if args.chunk_amount > 1:
pred_file = args.save_dir / f'{args.task}-{args.chunk_idx}.jsonl'
else:
pred_file = args.save_dir / f'{args.task}.jsonl'
print(f'Predict {args.task} \nfrom {task_file}\nto {pred_file}')
pred_file.parent.mkdir(parents=True, exist_ok=True)
# Load data
if os.path.exists(pred_file):
pred_index = [sample['index'] for sample in read_manifest(pred_file)]
data = [sample for sample in read_manifest(task_file) if sample['index'] not in pred_index]
else:
data = read_manifest(task_file)
# Load api
llm = get_llm(config['tokens_to_generate'])
def get_output(idx_list, index_list, input_list, outputs_list, others_list, truncation_list, length_list):
nonlocal llm
while True:
try:
pred_list = llm.process_batch(prompts=input_list)
break
except Exception as e:
traceback.print_exc()
zipped_iter = zip(pred_list, idx_list, index_list, input_list,
outputs_list, others_list, truncation_list, length_list)
for pred, idx, index, input, outputs, others, truncation, length in zipped_iter:
if isinstance(pred['text'], str):
pred_text = pred['text']
elif len(pred['text']) > 0:
pred_text = pred['text'][0]
else:
pred_text = ''
outputs_parallel[idx] = {
'index': index,
'pred': pred_text,
'input': input,
'outputs': outputs,
'others': others,
'truncation': truncation,
'length': length,
}
threads = []
outputs_parallel = [{} for _ in range(len(data))]
batched_data = []
batch = []
for idx, data_point in enumerate(data):
data_point['idx'] = idx
if len(batch) >= args.batch_size:
batched_data.append(batch)
batch = []
batch.append(data_point)
if len(batch):
batched_data.append(batch)
# setting buffering=1 to force to dump the output after every line, so that we can see intermediate generations
with open(pred_file, 'at', encoding="utf-8", buffering=1) as fout:
# the data is processed sequentially, so we can store the start and end of current processing window
start_idx = 0 # window: [start_idx, end_idx]
for batch_idx, batch in tqdm(enumerate(batched_data), total=len(batched_data)):
idx_list = [data_point['idx'] for data_point in batch]
end_idx = idx_list[-1] # the data in a batch is ordered
thread = threading.Thread(
target=get_output,
kwargs=dict(
idx_list=idx_list,
index_list=[data_point['index'] for data_point in batch],
input_list=[data_point['input'] for data_point in batch],
outputs_list=[data_point['outputs'] for data_point in batch],
others_list=[data_point.get('others', {}) for data_point in batch],
truncation_list=[data_point.get('truncation', -1) for data_point in batch],
length_list=[data_point.get('length', -1) for data_point in batch],
),
)
thread.start()
threads.append(thread)
is_last_batch = (batch_idx == len(batched_data) - 1)
if (len(threads) == args.threads) or is_last_batch:
for thread in threads:
thread.join()
threads = []
# dump the results in current processing window on disk
for idx in range(start_idx, end_idx + 1):
if len(outputs_parallel[idx]) > 0:
fout.write(json.dumps(outputs_parallel[idx]) + '\n')
start_idx = end_idx + 1
print(f"Used time: {round((time.time() - start_time) / 60, 1)} minutes")
if __name__ == '__main__':
main()

Xet Storage Details

Size:
11.8 kB
·
Xet hash:
a2c501c3c2299de87a2475040a535da4404a85d306845f9fbe48a79eab3aaf15

Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.