Process a specified number of lines from each .jsonl.zst file in the input directory and save encoded tokens to an HDF5 file. Args: input_dir (str): Directory containing input .jsonl.zst files. output_file (str): Path to the output HDF5 file. tokenizer_name (str
(input_dir: str, output_file: str, tokenizer_name: str, max_data: Optional[int] = None)
| 8 | from typing import Optional |
| 9 | |
| 10 | def process_files(input_dir: str, output_file: str, tokenizer_name: str, max_data: Optional[int] = None) -> None: |
| 11 | """ |
| 12 | Process a specified number of lines from each .jsonl.zst file in the input directory |
| 13 | and save encoded tokens to an HDF5 file. |
| 14 | |
| 15 | Args: |
| 16 | input_dir (str): Directory containing input .jsonl.zst files. |
| 17 | output_file (str): Path to the output HDF5 file. |
| 18 | tokenizer_name (str): Name of the tiktoken tokenizer to use (e.g., 'r50k_base'). |
| 19 | max_data (int, optional): Maximum number of lines to process from each file. |
| 20 | If None, process all lines. |
| 21 | """ |
| 22 | # Print processing strategy based on max_data |
| 23 | if max_data is not None: |
| 24 | print(f"You have chosen max_data = {max_data}. Processing only the top {max_data} JSON objects from each file.") |
| 25 | else: |
| 26 | print("Processing all available JSON objects from each file.") |
| 27 | |
| 28 | # Load the tokenizer using the provided tokenizer name |
| 29 | enc = tiktoken.get_encoding(tokenizer_name) |
| 30 | |
| 31 | # Create an HDF5 file for output |
| 32 | with h5py.File(output_file, 'w') as out_f: |
| 33 | # Initialize the dataset for storing tokenized data |
| 34 | dataset = out_f.create_dataset('tokens', (0,), maxshape=(None,), dtype='i') |
| 35 | start_index = 0 # Track the starting index for the next batch of tokens |
| 36 | |
| 37 | # Process each .jsonl.zst file in the input directory |
| 38 | for filename in sorted(os.listdir(input_dir)): |
| 39 | if filename.endswith(".jsonl.zst"): # Only process .jsonl.zst files |
| 40 | in_file = os.path.join(input_dir, filename) |
| 41 | print(f"Processing: {in_file}") |
| 42 | |
| 43 | processed_lines = 0 # Counter for processed lines in the current file |
| 44 | |
| 45 | # Open the compressed .jsonl.zst file for reading |
| 46 | with zstd.open(in_file, 'rt', encoding='utf-8') as in_f: |
| 47 | # Iterate over each line in the file |
| 48 | for line in tqdm(in_f, desc=f"Processing {filename}", total=max_data if max_data is not None else None): |
| 49 | try: |
| 50 | # Parse the line as JSON |
| 51 | data = json.loads(line) |
| 52 | text = data.get('text') # Extract the 'text' field from the JSON object |
| 53 | |
| 54 | if text: |
| 55 | # Tokenize the text and append an end-of-text token |
| 56 | encoded = enc.encode(text + "<|endoftext|>", allowed_special={'<|endoftext|>'}) |
| 57 | encoded_len = len(encoded) |
| 58 | |
| 59 | # Resize the dataset to accommodate new tokens |
| 60 | end_index = start_index + encoded_len |
| 61 | dataset.resize(dataset.shape[0] + encoded_len, axis=0) |
| 62 | |
| 63 | # Store the encoded tokens in the dataset |
| 64 | dataset[start_index:end_index] = encoded |
| 65 | start_index = end_index # Update the start index |
| 66 | else: |
| 67 | # Warn if 'text' key is missing in the JSON object |