Zephyrnet-logo

Een verklarende gids voor BERT Tokenizer

Datum:

Een neuraal netwerk kan alleen met cijfers werken, dus de allereerste stap is om aan elk woord enkele numerieke waarden toe te kennen. Stel dat je een woordenboek van 10000 woorden hebt, zodat je een unieke index kunt toekennen aan elk woord tot 10000. Nu kunnen alle woorden worden weergegeven door indices. En inbedding is een d-dimensionale vector voor elke index. Raadpleeg de onderstaande afbeelding voor een basisidee van het insluiten van woorden. Elk woord heeft een unieke index en een inbeddingsvector.

Laten we hier een beetje plezier hebben, denk eens na of we positionele indices toevoegen aan onze woordinbedding. Zal dit helpen? Raadpleeg de onderstaande afbeelding, wanneer we een positionele index toevoegen aan de woordinbedding (W1, W2..etc) dan zal de uiteindelijke inbedding voor de meest rechtse woorden altijd groter zijn en zal deze de originele woordinbedding domineren, zoals in dit geval als we voeg 10 toe aan W3, dan gaat de betekenis van W3 verloren. Om dit probleem op te lossen, als we de indices normaliseren met de totale lengte (deel alle indices door 10), dan zal hetzelfde woord een heel verschillende inbedding hebben voor verschillende lengtes van zinnen.

positionele inbedding

Transformers kwam met een mooi idee voor bovenstaand probleem. Ze gebruikten sinusoïdale positionele codering. De formule is hieronder geschreven, waarbij pos de positionele indices van woorden in de zinnen is, d de inbeddingsvectordimensie is en i de positie is van de indices in die inbeddingsvector. Het gebruik van Sin- en Cosinus-golven voor even en oneven indices verwijdert de dubbele inbeddingswaarden (cosinusgolf is meer dan één keer gelijk aan de sin-golf).

positionele inbedding

                                        Sinus-cosinusformule voor positionele codering

BERT-invoer inbedding

Bert invoer inbedding

Als je het originele document van BERT hebt doorgenomen, moet je bovenstaande figuur hebben gezien. Als je dat niet doet, maak je dan geen zorgen, we zijn hier om alles te verkennen. In BERT hoeven we geen sinusoïdale positionele codering te geven, het model leert zelf de positionele inbedding tijdens de trainingsfase, daarom zult u de positionele inbedding niet vinden in de standaardbibliotheek van transformatoren. BERT kwam op het slimme idee om het woord-stuk tokenizer-concept te gebruiken dat niets anders is dan het opsplitsen van enkele woorden in subwoorden. In de bovenstaande afbeelding wordt het woord 'slapen' bijvoorbeeld omgezet in 'slaap' en '##ing'. Dit idee kan vaak helpen om onbekende woorden op te splitsen in bekende woorden. Als ik bekende woorden zeg, bedoel ik de woorden die in ons vocabulaire staan. We zullen dit later zien met een praktijkvoorbeeld.

Bert Tokenizer in Transformers-bibliotheek

Vanaf dit punt gaan we alle bovenstaande inbedding verkennen met de Hugging-face tokenizer-bibliotheek. Als u tokenizer-bestanden lokaal naar uw computer wilt downloaden, gaat u naar: https://huggingface.co/bert-base-uncased/tree/main en download vocab.txt en configuratiebestanden van hier. Installeer de transformatorbibliotheek met pip.

from transformers import BertTokenizer tokenizer = BertTokenizer.from_pretrained(//path to tokenizers) sample = 'waar is de Himalaya op de wereldkaart?' encoding = tokenizer.encode(sample) print(encoding) print(tokenizer.convert_ids_to_tokens(encoding))uitgang 1: [101, 2073, 2003, 26779, 1999, 1996, 2088, 4949, 1029, 102] uitgang 2: ['[CLS]', 'waar', 'is', 'himalaya's', 'in', 'de', 'wereld', 'kaart', '?', '[SEP]']

In de bovenstaande code hebben we simpelweg de codeerfunctie genoemd en wat we in output1 krijgen, zijn indices van de invoertokens uit het vocab-bestand en output2 is het omgekeerde, een door mensen leesbare token van de input_ids. Naast de invoertokens hebben we ook 2 speciale tokens gekregen '[CLS]' en '[SEP]'. Het BERT-model is zo ontworpen dat de zin moet beginnen met de [CLS]-token en eindigen met de [SEP]-token. Als we aan het beantwoorden van vragen of taalvertaling werken, moeten we [SEP]-token tussen de twee zinnen gebruiken om scheiding te maken, maar dankzij de Hugging-face-bibliotheek doet de tokenizer-bibliotheek het voor ons. Laten we nu een beetje met dit voorbeeld spelen en het woord ' veranderenHimalaya's naar 'Himalaya's en kijk wat er daarna gebeurt.

sample = 'waar is Himalaya op de wereldkaart?' encoding = tokenizer.encode(sample) print(encoding) print(tokenizer.convert_ids_to_tokens(encoding))
uitgang 1: [101, 2073, 2003, 26779, 2015, 1999, 1996, 2088, 4949, 1029, 102] uitgang 2: ['[CLS]', 'where', 'is', 'himalayas', '# #s', 'in', 'de', 'wereld', 'kaart', '?', '[SEP]']

Is het je opgevallen in het bovenstaande voorbeeld, de tokenizer brengt het woord 'Himalaya is terug uit het donker. Op deze manier kan het de meeste onbekende woorden verwerken en de nauwkeurigheid van het model verbeteren. Laten we nu wat meer graven en nog een functie van de tokenizer-bibliotheek verkennen en het concept opnieuw begrijpen met een vraag-antwoordvoorbeeld. Ik gebruik vraagbeantwoordende gegevens omdat het twee invoerparen van reeksen heeft (vraag en context) aan de andere kant heeft classificatie slechts één reeks.

q1 = 'Wie was Tony Stark?' c1 = 'Anthony Edward Stark bekend als Tony Stark is een fictief personage in Avengers' encoding = tokenizer.encode_plus( q1, c1) voor sleutel, waarde in encoding.items(): print( '{} : {}'.format( key, value ) ) output: input_ids: [101, 2040, 2001, 4116, 9762, 1029, 102, 4938, 3487, 9762, 2124, 2004, 4116, 9762, 2003, 1037, 7214, 2839, 1999, 14936, 102] token_type_ids: [0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] attention_mask: [ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]

Hier gebruiken we de coderen_plus functie van de bibliotheek en het resulteerde in drie verschillende woordenboeken, de eerste is input_ids: we hebben dit in een eerder voorbeeld gezien, hier is het enige verschil dat we één (vraag en antwoord) paar behandelen als een enkele invoer en we krijgen een [ SEP] token tussen de vraag en het antwoord. Token_type_ids zijn nullen voor de eerste zin en 0 voor de tweede zin. Onthoud dat als we een classificatietaak doen, de token_type_ids daar niet nuttig zullen zijn omdat de invoerreeks niet gepaard is (alleen nullen zijn daar in wezen niet vereist). Om attention_mask te begrijpen, moeten we gegevens in batches verwerken. In een batch kunnen we verschillende invoerlengtes hebben. Het model vereiste altijd invoergegevens in rechthoekig formaat, als we gegevens in een batch doorgeven. Als we bijvoorbeeld een batchgrootte = 1 hebben, ziet de batch eruit als de onderstaande afbeelding.

transformator

Uit de bovenstaande afbeelding kun je visualiseren wat ik hierboven net zei. We moeten dezelfde lengte maken voor alle monsters in een batch. In dat proces moet een opvulwaarde worden toegevoegd aan de rechterkant van de tokens in kortere zinnen en om ervoor te zorgen dat het model niet naar die opgevulde waarden kijkt, wordt een aandachtsmasker gebruikt met de waarde nul. Laten we een echt gegevensprobleem hebben voor dezelfde vraag die gegevens beantwoordt.

q1 = 'Wie was Tony Stark?' c1 = 'Anthony Edward Stark bekend als Tony Stark is een fictief personage in Avengers' q2 = 'Wie was Tony in Marvel' c2 = 'Tony Stark is een fictief personage in Marvel Avengers' encoding = tokenizer([q1,q2], [ c1,c2]) voor sleutel, waarde in encoding.items(): print('1- {}: {}'.format(key, value)) output: input_ids: [[101, 2040, 2001, 4116, 9762 , 1029, 102, 4938, 3487, 9762, 2124, 2004, 4116, 9762, 2003, 1037, 7214, 2839, 1999, 14936, 102], [101, 2040, 2001, 4116, 1999, 8348, 102, 4116 , 9762, 2003, 1037, 7214, 2839, 1999, 8348, 14936, 102]] token_type_ids: [[0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]] aandachtsmasker: [[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]]

In de bovenstaande code hebben we twee lijsten gemaakt, de eerste lijst bevat alle vragen en de tweede lijst bevat alle contexten. Deze keer ontvingen we twee lijsten voor elk woordenboek (input_ids, token_type_ids en attention_mask). Als je hebt waargenomen, is de grootte van beide lijsten nog steeds verschillend. Dit gebeurde omdat we opvulling niet als argument gebruikten.

encoding = tokenizer([q1,q2], [c1,c2],padding=True) voor sleutel, waarde in encoding.items(): print('1- {}: {}'.format(key, value)) output: input_ids: [[101, 2040, 2001, 4116, 9762, 1029, 102, 4938, 3487, 9762, 2124, 2004, 4116, 9762, 2003, 1037, 7214, 2839, 1999, 14936, 102], [ 101, 2040, 2001, 4116, 1999, 8348, 102, 4116, 9762, 2003, 1037, 7214, 2839, 1999, 8348, 14936, 102, 0, 0, 0, 0]] token_type_ids: [[0, 0 , 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 0, 0, 0 , 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0]] aandachtsmasker: [[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0]]

Na het toevoegen van het opvulargument kregen we nul opvullingen voor kortere zinnen en alles blijft hetzelfde. Hier komt het belang van attention_mask, het model zal alleen focussen waar de maskering is ingesteld op true of 1. Hetzelfde kan worden bereikt met een andere functie van de tokenizer-bibliotheek, het enige verschil is dat u een lijst moet maken van een paar van een vraag en een context zoals hieronder-

En we zullen de uitvoer voor de bovenstaande code hetzelfde krijgen als in het vorige voorbeeld. Evenzo vereisten verschillende BERT-varianten verschillende invoerinbedding. DistilBERT gebruikt bijvoorbeeld geen token_type_ids, het verkleint de lagen met een factor twee. Deze veranderingen maakten het model veel sneller dan BERT met een klein beetje compromis om te scoren. Laten we een voorbeeld van een DistilBERT-tokenizer bekijken

PlatoAi. Web3 opnieuw uitgevonden. Gegevensintelligentie versterkt.
Klik hier om toegang te krijgen.

Bron: https://www.analyticsvidhya.com/blog/2021/09/an-explanatory-guide-to-bert-tokenizer/

spot_img

Laatste intelligentie

spot_img