summarize_from_feedback/task_data.py (92 lines of code) (raw):
import json
import os
from functools import partial
from glob import glob
from typing import Optional
import blobfile as bf
import torch
import summarize_from_feedback
from summarize_from_feedback import tasks
from summarize_from_feedback.datasets import jsonl_encoding, get_dataset
from summarize_from_feedback.model_layout import ModelLayout
from summarize_from_feedback.utils import even_more_itertools, blobs
def _collate_fn(raw_data, all_fields=False, device="cpu"):
context_input = torch.as_tensor(
[x["context"]["tokens"] for x in raw_data], dtype=torch.long, device=device
)
reference_input = torch.as_tensor(
[x["reference"]["tokens"] for x in raw_data], dtype=torch.long, device=device
)
input_dict = dict(context=dict(tokens=context_input), reference=dict(tokens=reference_input))
if "text" in raw_data[0]["reference"]:
input_dict["reference"]["text"] = [x["reference"]["text"] for x in raw_data]
if all_fields:
input_dict["extra_fields"] = [x["extra_fields"] for x in raw_data]
return input_dict
class _DataLoaderWrapper(torch.utils.data.IterableDataset):
"""
torch.utils.data.DataLoader behaves differently depending on the class of the iterator it is passed.
This wrapper lets us use the iterable setup.
"""
def __init__(self, dataset):
self.dataset = dataset
def __iter__(self):
return iter(self.dataset)
def torch_loader(iterable, batch_size, num_workers=1, drop_last=False, collate_fn=None):
assert num_workers in (0, 1)
loader = torch.utils.data.DataLoader(
_DataLoaderWrapper(iterable),
batch_size=batch_size,
num_workers=num_workers,
collate_fn=collate_fn,
drop_last=drop_last,
)
return iter(loader)
def get_iter_for_task(
task_H,
*,
encoder=summarize_from_feedback.encoder,
dataset_split,
batch_size,
seed,
layout: Optional[ModelLayout] = None,
repeat=True,
all_fields=False,
):
response_encoder = tasks.ResponseEncoder(task_H.response, encoder)
def map_input(raw_data):
ref_response = task_H.response.ref_format_str.format(**raw_data)
ref_tokens = response_encoder.encode_response(ref_response, allow_truncate=True)
query_info = tasks.process_query(raw_data, encoder=encoder, hparams=task_H.query)
return dict(
context=query_info,
# NOTE: tokens are truncated but text is not
reference=dict(tokens=ref_tokens, text=ref_response),
# NOTE: we remove reference to prevent mistakes, after the rm4 space bug
extra_fields={k: v for k, v in raw_data.items() if k != "reference"}
if all_fields
else dict(),
)
ds = get_dataset(
task_H.query.dataset, split=dataset_split, seed=seed, repeat=repeat, layout=layout
)
ds = map(map_input, ds)
ds = torch_loader(
ds,
num_workers=1,
batch_size=batch_size,
drop_last=True,
collate_fn=partial(_collate_fn, all_fields=all_fields),
)
return ds
def make_jsonl_samples_iter(input_path, layout: Optional[ModelLayout] = None):
"""
Makes an iterator reading examples out of all the samples.[0-9]*.jsonl files in the given path,
distributed across replicas according to the layout.
"""
if blobs.is_blob_url(input_path):
local_input_dir = blobs.download_directory_cached(input_path)
else:
local_input_dir = input_path
input_file_names = glob(os.path.join(local_input_dir, "samples.[0-9]*.jsonl"))
def all_examples():
for file_name in input_file_names:
with bf.BlobFile(file_name, "r") as f:
for line in f:
encoded_example = json.loads(line)
example = jsonl_encoding.decode_example(encoded_example)
yield example
d = all_examples()
if layout:
d = even_more_itertools.distribute(d, layout)
return d