segment-any-text / wtpsplit

Toolkit to segment text into sentences or other semantic units in a robust, efficient and adaptable way.
MIT License
624 stars 36 forks source link

CUDA device error when segmenting Greek text #121

Closed ayalda closed 1 week ago

ayalda commented 1 week ago

Hello.

I am using Kaggle to segment English to Greek text from the Aya dataset on Huggingface. I will likely try using wtpsplit for numerous languages, but am currently unable to get it consistently working.

This specific text was erroring with a CUDA error: device-side assert triggered:

Η σχολιασμός του DNA ή η σχολιασμός του γονιδιώματος είναι η διαδικασία αναγνώρισης των τοποθεσιών των γονιδίων και όλων των περιοχών κωδικοποίησης σε ένα γονιδίωμα και καθορισμού του τι κάνουν αυτά τα γονίδια. Μια σημείωση (ανεξάρτητα από το πλαίσιο) είναι μια σημείωση που προστίθεται ως εξήγηση ή σχόλιο. Μόλις το γονιδίωμα είναι αλληλουχία, πρέπει να σημειωθεί για να έχει νόημα. Τα γονίδια σε ένα ευκαρυωτικό γονιδίωμα μπορούν να σχολιαστούν χρησιμοποιώντας διάφορα εργαλεία σχολιασμού όπως το FINDER. Ένας σύγχρονος αγωγός σχολιασμού μπορεί να υποστηρίξει μια φιλική προς το χρήστη διεπαφή ιστού και την περιέκτηση λογισμικού όπως το MOSGA. Οι σύγχρονοι αγωγοί σχολιασμού για τα γονιδιώματα των προκαρυωτικών είναι οι Bakta, Prokka και PGAP. Για την αναφορά του DNA, μια προηγουμένως άγνωστη αντιπροσώπευση αλληλουχίας γενετικού υλικού εμπλουτίζεται με πληροφορίες που σχετίζονται με τη γονιδιωματική θέση στα όρια εντρονίου-εξονίου, ρυθμιστικές αλληλουχίες, επαναλήψεις, ονόματα γονιδίων και προϊόντα πρωτεϊνών. Αυτή η σημείωση αποθηκεύεται σε γονιδιωματικές βάσεις δεδομένων όπως Mouse Genome Informatics, FlyBase και WormBase. Εκπαιδευτικό υλικό για ορισμένες πτυχές της βιολογικής σχολιασμού από την κατασκήνωση σχολιασμού Gene Ontology του 2006 και παρόμοιες εκδηλώσεις είναι διαθέσιμα στην ιστοσελίδα Gene Ontology. Το Εθνικό Κέντρο Βιοϊατρικής Οντολογίας αναπτύσσει εργαλεία για την αυτοματοποιημένη σχολιασμό των αρχείων βάσης δεδομένων με βάση τις γραπτές περιγραφές αυτών των αρχείων. Ως γενική μέθοδος, το dcGO διαθέτει μια αυτοματοποιημένη διαδικασία για στατιστικά συμπεράσματα σχετικά με συσχετισμούς μεταξύ όρων οντολογίας και τομέων πρωτεϊνών ή συνδυασμών τομέων από τις υπάρχουσες σημειώσεις σε επίπεδο γονιδίων/πρωτεϊνών.

I managed to locate the offending text: γονιδίων/πρωτεϊνών (the last word in the text), which when replaced to γονιδίων / πρωτεϊνών (added spaces around the slash), ran through fine.

Now I am running the next dataset and I am getting the same error. Could this have to do with the tokenization of the text or the vocabulary not able to process specific parts of the text?

On Kaggle I get the following error:

/usr/local/src/pytorch/aten/src/ATen/native/cuda/Indexing.cu:1292: indexSelectLargeIndex: block: [194,0,0], thread: [0,0,0] Assertion `srcIndex < srcSelectDimSize` failed.

Then, after the error occurs, the model is left in CUDA memory and the only way to unload it is to restart the kernel.

Hopefully this is a simple fix or just something that I am doing wrong. Thank you!

I pasted the code from my notebook below.

LANG = "Greek"
sat = SaT("sat-3l")
tokenizer = XLMRobertaTokenizer.from_pretrained("xlm-roberta-base")  # Ensure tokenizer is properly initialized
sat.half().to("cuda")
for dataset in segmentation_map:
    DATASET_NAME = dataset["dataset_name"]

    if DATASET_NAME == 'translated_soda' or DATASET_NAME == 'translated_xlel_wd':
        PATH_NAME = f"/kaggle/input/{DATASET_NAME}_{LANG}_aligned.csv"
    else:
        PATH_NAME = f"/kaggle/input/{DATASET_NAME}_{LANG}_aligned.xlsx"
    ROWS_TO_SEGMENT = ["targets_x", "targets_y", "inputs_x", "inputs_y"]
    SEGMENT_THRESHOLD = 400

    if ".csv" in PATH_NAME:
        df = pd.read_csv(PATH_NAME)
    elif ".xlsx" in PATH_NAME:
        print(f"reading {PATH_NAME}")
        df = pd.read_excel(PATH_NAME)

    if dataset['combine']:
        df['inputs_x'] = df['inputs_x'].astype(str) + df['targets_x'].astype(str)
        df['inputs_y'] = df['inputs_y'].astype(str) + df['targets_y'].astype(str)

    def process_segments(dataframe, row_names, threshold, segmenter, tokenizer, combine=False):
        complete_elements = {name: [] for name in row_names}
        if combine:
            row_names = ["inputs_x", "inputs_y"]
        for idx, row in dataframe.iterrows():
            skip_row = False
            for name in row_names:
                text = str(row[name])
                text = text.replace('/', ' / ')
                if len(text) > threshold:
                    try:
                        inputs = tokenizer(text, return_tensors="pt", padding=True, truncation=True)
                        input_ids = inputs["input_ids"].squeeze().tolist()
                        max_id = tokenizer.vocab_size - 1
                        if any(id > max_id for id in input_ids):
                            print(f"Error: Token ID {id} in row {idx} exceeds vocab size {max_id}. Skipping row {idx}.")
                            skip_row = True
                            break
                        print(f"{idx}: {text[:20]}")
                        for segment in segmenter.split(text):
                            print(f"{idx}: {segment[:20]}")
                            complete_elements[name].append(segment)
                    except Exception as e:
                        print(f"Error processing row {idx}: {e}")
                        skip_row = True
                else:
                    complete_elements[name].append(text)
                if skip_row:
                    break
            if skip_row:
                for name in row_names:
                    if name in complete_elements:
                        complete_elements[name] = complete_elements[name][:-len(row_names)]
        return complete_elements

    results = process_segments(df, ROWS_TO_SEGMENT, SEGMENT_THRESHOLD, sat, tokenizer, dataset['combine'])

    if dataset['combine'] or not dataset['use_outputs']:
        final_complete_x = results["inputs_x"]
        final_complete_y = results["inputs_y"]
    elif dataset['use_inputs'] and dataset['use_outputs']:
        final_complete_x = results["targets_x"] + results["inputs_x"]
        final_complete_y = results["targets_y"] + results["inputs_y"]
    else:
        final_complete_x = results["targets_x"]
        final_complete_y = results["targets_y"]

    print('Completed dataset', dataset["dataset_name"])

    df1 = pd.DataFrame(final_complete_x, columns=[LANG])
    df2 = pd.DataFrame(final_complete_y, columns=['English'])

    if not os.path.exists(f"/kaggle/working/{LANG}/excel"):
        os.makedirs(f"/kaggle/working/{LANG}/excel")

    if not os.path.exists(f"/kaggle/working/{LANG}/txt"):
        os.makedirs(f"/kaggle/working/{LANG}/txt")

    df1.to_excel(f"/kaggle/working/{LANG}/excel/{LANG}_{DATASET_NAME}_segmented.xlsx", index=False)
    df2.to_excel(f"/kaggle/working/{LANG}/excel/ENG_{DATASET_NAME}_segmented.xlsx", index=False)

    input_files = [f"/kaggle/working/{LANG}/excel/{LANG}_{DATASET_NAME}_segmented.xlsx", f"/kaggle/working/{LANG}/excel/ENG_{DATASET_NAME}_segmented.xlsx"]
    output_files = [f"/kaggle/working/{LANG}/txt/{LANG}_{DATASET_NAME}_segmented.txt", f"/kaggle/working/{LANG}/txt/ENG_{DATASET_NAME}_segmented.txt"]

    for input_file, output_file in zip(input_files, output_files):
        df = pd.read_excel(input_file)
        columns_to_extract = df.columns
        extracted_data = df[columns_to_extract]

        with open(output_file, 'w', encoding='utf-8') as file:
            for index, row in extracted_data.iterrows():
                line = '\t'.join(map(lambda x: str(x).replace('\n', ' ').replace('  ', ' '), row.values))
                file.write(line + '\n')

    os.remove(f"/kaggle/working/{LANG}/excel/{LANG}_{DATASET_NAME}_segmented.xlsx")
    os.remove(f"/kaggle/working/{LANG}/excel/ENG_{DATASET_NAME}_segmented.xlsx")
markus583 commented 1 week ago

Hi, thanks for finding this! We just pushed version 2.0.5 which fixes the issue. Please just upgrade. :)