Skip to content

Commit cf166c4

Browse files
authored
Add dataset adapter for loading dolly15k_multilingual dataset (#3660)
Dataset: [argilla/databricks-dolly-15k-curated-multilingual](https://huggingface.co/datasets/argilla/databricks-dolly-15k-curated-multilingual)
1 parent 2cc90ff commit cf166c4

3 files changed

Lines changed: 83 additions & 33 deletions

File tree

model/model_training/custom_datasets/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
SODA,
1919
AlpacaGpt4,
2020
DatabricksDolly15k,
21+
Dolly15kMultilingual,
2122
GPTeacher_Roleplay,
2223
JokeExplaination,
2324
QADataset,
@@ -175,6 +176,8 @@ def get_one_dataset(
175176
train, eval = load_hellaswag()
176177
elif dataset_name == "dolly15k":
177178
dataset = DatabricksDolly15k(cache_dir=data_path, mode=mode, **kwargs)
179+
elif dataset_name == "dolly15k_multilingual":
180+
dataset = Dolly15kMultilingual(cache_dir=data_path, mode=mode, **kwargs)
178181
elif dataset_name == "alpaca_gpt4":
179182
dataset = AlpacaGpt4(cache_dir=data_path, mode=mode, **kwargs)
180183
elif dataset_name == "red_pajama":

model/model_training/custom_datasets/qa_datasets.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -601,6 +601,43 @@ def __getitem__(self, index: int) -> DatasetEntry:
601601
return dialogue
602602

603603

604+
class Dolly15kMultilingual(Dataset):
605+
def __init__(self, cache_dir: str | Path, mode: str = "sft") -> None:
606+
super().__init__()
607+
self.rows = []
608+
self.citation_regex = re.compile(r"\[[a-zA-Z]\]") # removes citations in the form of e.g. [a] or [A]
609+
if mode not in ("sft", "rl"):
610+
raise NotImplementedError(f"Currently only the modes 'sft' and 'rl' are implemented. Received {mode}.")
611+
self.mode = mode
612+
splits = load_dataset("argilla/databricks-dolly-15k-curated-multilingual", cache_dir=cache_dir)
613+
for lang in ("en", "de", "es", "fr"):
614+
data = splits[lang]
615+
for line in data:
616+
if (c := self._process_instruction(line, lang=lang)) is not None:
617+
self.rows.append(c)
618+
619+
def _process_instruction(self, row: dict[str, str], lang: str) -> DatasetEntry | None:
620+
context = re_reference_remove.sub("", row["context"])
621+
# further remove references
622+
context = context.replace("[citation needed]", "")
623+
context = self.citation_regex.sub("", context)
624+
if _filter_by_words(row["instruction"]) and _filter_by_words(row["response"]):
625+
return create_dataset_entry_qa(
626+
mode=self.mode,
627+
questions=[row["instruction"]],
628+
answers=[row["response"]],
629+
context=context,
630+
lang=lang,
631+
)
632+
633+
def __len__(self) -> int:
634+
return len(self.rows)
635+
636+
def __getitem__(self, index: int) -> DatasetEntry:
637+
dialogue = self.rows[index]
638+
return dialogue
639+
640+
604641
class AlpacaGpt4(Dataset):
605642
def __init__(self, cache_dir: str | Path, mode: str = "sft") -> None:
606643
super().__init__()

model/pretokenizer/pretokenize.py

Lines changed: 43 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ class IntRole(IntEnum):
1919
System = 0
2020
Prompter = 1
2121
Assistant = 2
22+
Context = 3
2223

2324

2425
class Encoder(object):
@@ -72,6 +73,9 @@ def format_sft_entry(entry: DatasetEntrySft) -> tuple[list[str], list[int]]:
7273
turns.append(f"<|im_start|>system\n{entry.system_message}<|im_end|>\n")
7374
roles.append(IntRole.System.value) # 0
7475
for m in entry.conversation:
76+
if m.context:
77+
turns.append(f"<|im_start|>context\n{m.context}<|im_end|>\n")
78+
roles.append(IntRole.Context.value) # 3
7579
if m.role == Role.prompter:
7680
turns.append(f"<|im_start|>user\n{m.text}<|im_end|>\n")
7781
roles.append(IntRole.Prompter.value) # 1
@@ -90,6 +94,21 @@ def format_conversation(messages) -> str:
9094
return format_pairs(messages)
9195

9296

97+
def get_dataset_name(d: Dataset):
98+
if isinstance(d, Subset):
99+
inner = d
100+
while isinstance(inner, Subset):
101+
inner = inner.dataset
102+
name = f"Subset of {type(inner).__name__}"
103+
if hasattr(inner, "name"):
104+
name += f" ({inner.name})"
105+
else:
106+
name = type(d).__name__
107+
if hasattr(d, "name"):
108+
name += f" ({d.name})"
109+
return name
110+
111+
93112
class TokenStats:
94113
def __init__(self, name: str, total_samples: int, fraction: float = 1):
95114
self.name = name
@@ -156,17 +175,7 @@ def tokenize_dataset(
156175

157176
for i in range(len(datasets)):
158177
d = datasets[i]
159-
if isinstance(d, Subset):
160-
if hasattr(d.dataset, "name"):
161-
name = d.dataset.name
162-
else:
163-
name = f"Subset of {type(d.dataset).__name__}"
164-
else:
165-
if hasattr(d, "name"):
166-
name = d.name
167-
else:
168-
name = type(d).__name__
169-
178+
name = get_dataset_name(d)
170179
frac = 1
171180
if dataset_target_sizes:
172181
frac = fractions[i]
@@ -257,20 +266,28 @@ def tokenize_dataset(
257266
if jsonl_file:
258267
jsonl_file.close()
259268

260-
print(f"\n# Stats for {full_prefix}*\n")
269+
per_dataset_stats.append(total_stats)
261270

262-
for stats in per_dataset_stats:
263-
print(f"## Stats for '{stats.name}' ({stats.total_samples} samples ({stats.fraction:.1%}))")
264-
print("-----------------")
265-
print(
266-
f" Accepted: {stats.accepted_samples}/{stats.processed_samples} ({stats.accepted_samples/stats.processed_samples:.1%})"
267-
)
268-
print(f" Accepted tokens: {stats.accepted_tokens}")
269-
print(f" Skipped: {stats.skipped_samples} ({stats.skipped_samples/stats.processed_samples:.1%})")
270-
print(f" Min tokens per sample: {stats.min_tokens}")
271-
print(f" Max tokens per sample: {stats.max_tokens}")
272-
print(f" Avg tokens per sample: {stats.accepted_tokens/stats.accepted_samples}")
273-
print("-----------------\n")
271+
stats_path = Path(full_prefix + "_stats.txt")
272+
with stats_path.open("w", encoding="UTF-8") as stats_file:
273+
for f in (None, stats_file):
274+
print(f"\n# Stats for {full_prefix}*\n", file=f)
275+
276+
for stats in per_dataset_stats:
277+
print(f"## Stats for '{stats.name}' ({stats.total_samples} samples ({stats.fraction:.1%}))", file=f)
278+
print("-----------------", file=f)
279+
print(
280+
f" Accepted: {stats.accepted_samples}/{stats.processed_samples} ({stats.accepted_samples/stats.processed_samples:.1%})",
281+
file=f,
282+
)
283+
print(f" Accepted tokens: {stats.accepted_tokens}", file=f)
284+
print(
285+
f" Skipped: {stats.skipped_samples} ({stats.skipped_samples/stats.processed_samples:.1%})", file=f
286+
)
287+
print(f" Min tokens per sample: {stats.min_tokens}", file=f)
288+
print(f" Max tokens per sample: {stats.max_tokens}", file=f)
289+
print(f" Avg tokens per sample: {stats.accepted_tokens/stats.accepted_samples}", file=f)
290+
print("-----------------\n", file=f)
274291

275292

276293
def parse_args():
@@ -381,20 +398,13 @@ def main():
381398
print("Training dataset sizes (before sampling):")
382399
total = len(train)
383400
for d in train.datasets:
384-
if isinstance(d, Subset):
385-
name = f"Subset of {type(d.dataset).__name__}"
386-
if hasattr(d.dataset, "name"):
387-
name += f" ({d.dataset.name})"
388-
else:
389-
name = type(d).__name__
390-
if hasattr(d, "name"):
391-
name += f" ({d.name})"
401+
name = get_dataset_name(d)
392402
print(f"{name}: {len(d)} ({len(d) / total:.2%})")
393403

394404
output_dir.mkdir(parents=True, exist_ok=True)
395405

396406
fn = output_dir / "special_tokens.json"
397-
with fn.open("w") as f:
407+
with fn.open("w", encoding="UTF-8") as f:
398408
json.dump(encoder.special_tokens, f)
399409

400410
val = ConcatDataset(evals.values())

0 commit comments

Comments
 (0)