HomeVideos

Let's build the GPT Tokenizer

Now Playing

Let's build the GPT Tokenizer

Transcript

3422 segments

0:00

hi everyone so in this video I'd like us

0:02

to cover the process of tokenization in

0:04

large language models now you see here

0:06

that I have a set face and that's

0:08

because uh tokenization is my least

0:10

favorite part of working with large

0:11

language models but unfortunately it is

0:13

necessary to understand in some detail

0:15

because it it is fairly hairy gnarly and

0:17

there's a lot of hidden foot guns to be

0:19

aware of and a lot of oddness with large

0:21

language models typically traces back to

0:24

tokenization so what is

0:26

tokenization now in my previous video

0:28

Let's Build GPT from scratch uh we

0:31

actually already did tokenization but we

0:33

did a very naive simple version of

0:35

tokenization so when you go to the

0:37

Google colab for that video uh you see

0:40

here that we loaded our training set and

0:43

our training set was this uh Shakespeare

0:45

uh data set now in the beginning the

0:48

Shakespeare data set is just a large

0:49

string in Python it's just text and so

0:52

the question is how do we plug text into

0:54

large language models and in this case

0:58

here we created a vocabulary of 65

1:01

possible characters that we saw occur in

1:03

this string these were the possible

1:05

characters and we saw that there are 65

1:07

of them and then we created a a lookup

1:10

table for converting from every possible

1:13

character a little string piece into a

1:16

token an

1:17

integer so here for example we tokenized

1:20

the string High there and we received

1:23

this sequence of

1:24

tokens and here we took the first 1,000

1:27

characters of our data set and we

1:29

encoded it into tokens and because it is

1:32

this is character level we received

1:34

1,000 tokens in a sequence so token 18

1:38

47

1:40

Etc now later we saw that the way we

1:43

plug these tokens into the language

1:45

model is by using an embedding

1:48

table and so basically if we have 65

1:51

possible tokens then this embedding

1:53

table is going to have 65 rows and

1:56

roughly speaking we're taking the

1:58

integer associated with every single

1:59

sing Le token we're using that as a

2:01

lookup into this table and we're

2:04

plucking out the corresponding row and

2:06

this row is a uh is trainable parameters

2:09

that we're going to train using back

2:10

propagation and this is the vector that

2:12

then feeds into the Transformer um and

2:15

that's how the Transformer Ser of

2:16

perceives every single

2:18

token so here we had a very naive

2:21

tokenization process that was a

2:23

character level tokenizer but in

2:25

practice in state-ofthe-art uh language

2:27

models people use a lot more complicated

2:28

schemes unfortunately

2:30

uh for constructing these uh token

2:34

vocabularies so we're not dealing on the

2:36

Character level we're dealing on chunk

2:38

level and the way these um character

2:41

chunks are constructed is using

2:43

algorithms such as for example the bik

2:45

pair in coding algorithm which we're

2:46

going to go into in detail um and cover

2:51

in this video I'd like to briefly show

2:52

you the paper that introduced a bite

2:54

level encoding as a mechanism for

2:56

tokenization in the context of large

2:58

language models and I would say that

3:00

that's probably the gpt2 paper and if

3:02

you scroll down here to the section

3:05

input representation this is where they

3:07

cover tokenization the kinds of

3:09

properties that you'd like the

3:10

tokenization to have and they conclude

3:13

here that they're going to have a

3:14

tokenizer where you have a vocabulary of

3:17

50,2 57 possible

3:20

tokens and the context size is going to

3:24

be 1,24 tokens so in the in in the

3:27

attention layer of the Transformer

3:29

neural network

3:30

every single token is attending to the

3:32

previous tokens in the sequence and it's

3:34

going to see up to 1,24 tokens so tokens

3:37

are this like fundamental unit um the

3:40

atom of uh large language models if you

3:43

will and everything is in units of

3:44

tokens everything is about tokens and

3:47

tokenization is the process for

3:48

translating strings or text into

3:51

sequences of tokens and uh vice versa

3:54

when you go into the Llama 2 paper as

3:56

well I can show you that when you search

3:58

token you're going to get get 63 hits um

4:01

and that's because tokens are again

4:03

pervasive so here they mentioned that

4:05

they trained on two trillion tokens of

4:06

data and so

4:08

on so we're going to build our own

4:11

tokenizer luckily the bite be encoding

4:13

algorithm is not uh that super

4:15

complicated and we can build it from

4:16

scratch ourselves and we'll see exactly

4:18

how this works before we dive into code

4:20

I'd like to give you a brief Taste of

4:22

some of the complexities that come from

4:24

the tokenization because I just want to

4:26

make sure that we motivate it

4:27

sufficiently for why we are doing all

4:29

this and why this is so gross so

4:32

tokenization is at the heart of a lot of

4:34

weirdness in large language models and I

4:36

would advise that you do not brush it

4:37

off a lot of the issues that may look

4:40

like just issues with the new network

4:42

architecture or the large language model

4:44

itself are actually issues with the

4:46

tokenization and fundamentally Trace uh

4:49

back to it so if you've noticed any

4:51

issues with large language models can't

4:54

you know not able to do spelling tasks

4:56

very easily that's usually due to

4:57

tokenization simple string processing

5:00

can be difficult for the large language

5:02

model to perform

5:03

natively uh non-english languages can

5:06

work much worse and to a large extent

5:08

this is due to

5:09

tokenization sometimes llms are bad at

5:11

simple arithmetic also can trace be

5:14

traced to

5:15

tokenization uh gbt2 specifically would

5:17

have had quite a bit more issues with

5:19

python than uh future versions of it due

5:22

to tokenization there's a lot of other

5:24

issues maybe you've seen weird warnings

5:25

about a trailing whites space this is a

5:27

tokenization issue um

5:30

if you had asked GPT earlier about solid

5:33

gold Magikarp and what it is you would

5:35

see the llm go totally crazy and it

5:37

would start going off about a completely

5:39

unrelated tangent topic maybe you've

5:41

been told to use yl over Json in

5:43

structure data all of that has to do

5:45

with tokenization so basically

5:47

tokenization is at the heart of many

5:49

issues I will look back around to these

5:51

at the end of the video but for now let

5:54

me just um skip over it a little bit and

5:56

let's go to this web app um the Tik

5:59

tokenizer bell.app so I have it loaded

6:02

here and what I like about this web app

6:04

is that tokenization is running a sort

6:06

of live in your browser in JavaScript so

6:09

you can just type here stuff hello world

6:11

and the whole string

6:14

rokenes so here what we see on uh the

6:18

left is a string that you put in on the

6:20

right we're currently using the gpt2

6:22

tokenizer we see that this string that I

6:24

pasted here is currently tokenizing into

6:27

300 tokens and here they are sort of uh

6:30

shown explicitly in different colors for

6:32

every single token so for example uh

6:35

this word tokenization became two tokens

6:38

the token

6:40

3,642 and

6:44

1,634 the token um space is is token 318

6:50

so be careful on the bottom you can show

6:51

white space and keep in mind that there

6:54

are spaces and uh sln new line

6:57

characters in here but you can hide them

6:59

for

7:01

clarity the token space at is token 379

7:06

the to the Token space the is 262 Etc so

7:11

you notice here that the space is part

7:12

of that uh token

7:15

chunk now so this is kind of like how

7:18

our English sentence broke up and that

7:21

seems all well and good now now here I

7:24

put in some arithmetic so we see that uh

7:26

the token 127 Plus and then token six

7:31

space 6 followed by 77 so what's

7:34

happening here is that 127 is feeding in

7:36

as a single token into the large

7:38

language model but the um number 677

7:42

will actually feed in as two separate

7:44

tokens and so the large language model

7:47

has to sort of um take account of that

7:50

and process it correctly in its Network

7:53

and see here 804 will be broken up into

7:56

two tokens and it's is all completely

7:57

arbitrary and here I have another

7:59

example of four-digit numbers and they

8:02

break up in a way that they break up and

8:03

it's totally arbitrary sometimes you

8:05

have um multiple digits single token

8:08

sometimes you have individual digits as

8:10

many tokens and it's all kind of pretty

8:12

arbitrary and coming out of the

8:14

tokenizer here's another example we have

8:17

the string egg and you see here that

8:21

this became two

8:22

tokens but for some reason when I say I

8:24

have an egg you see when it's a space

8:27

egg it's two token it's sorry it's a

8:30

single token so just egg by itself in

8:33

the beginning of a sentence is two

8:34

tokens but here as a space egg is

8:37

suddenly a single token uh for the exact

8:40

same string okay here lowercase egg

8:44

turns out to be a single token and in

8:46

particular notice that the color is

8:47

different so this is a different token

8:49

so this is case sensitive and of course

8:51

a capital egg would also be different

8:54

tokens and again um this would be two

8:57

tokens arbitrarily so so for the same

9:00

concept egg depending on if it's in the

9:02

beginning of a sentence at the end of a

9:03

sentence lowercase uppercase or mixed

9:06

all this will be uh basically very

9:08

different tokens and different IDs and

9:10

the language model has to learn from raw

9:12

data from all the internet text that

9:13

it's going to be training on that these

9:15

are actually all the exact same concept

9:17

and it has to sort of group them in the

9:19

parameters of the neural network and

9:21

understand just based on the data

9:22

patterns that these are all very similar

9:24

but maybe not almost exactly similar but

9:27

but very very similar

9:30

um after the EG demonstration here I

9:32

have um an introduction from open a eyes

9:35

chbt in Korean so manaso Pang uh Etc uh

9:41

so this is in Korean and the reason I

9:44

put this here is because you'll notice

9:47

that um non-english languages work

9:51

slightly worse in Chachi part of this is

9:54

because of course the training data set

9:55

for Chachi is much larger for English

9:58

and for everything else but the same is

9:59

true not just for the large language

10:01

model itself but also for the tokenizer

10:04

so when we train the tokenizer we're

10:05

going to see that there's a training set

10:07

as well and there's a lot more English

10:09

than non-english and what ends up

10:11

happening is that we're going to have a

10:13

lot more longer tokens for

10:16

English so how do I put this if you have

10:19

a single sentence in English and you

10:21

tokenize it you might see that it's 10

10:23

tokens or something like that but if you

10:25

translate that sentence into say Korean

10:27

or Japanese or something else you'll

10:29

typically see that the number of tokens

10:30

used is much larger and that's because

10:33

the chunks here are a lot more broken up

10:36

so we're using a lot more tokens for the

10:38

exact same thing and what this does is

10:41

it bloats up the sequence length of all

10:43

the documents so you're using up more

10:46

tokens and then in the attention of the

10:48

Transformer when these tokens try to

10:49

attend each other you are running out of

10:51

context um in the maximum context length

10:55

of that Transformer and so basically all

10:57

the non-english text is stretched out

11:01

from the perspective of the Transformer

11:03

and this just has to do with the um

11:05

trainings that used for the tokenizer

11:07

and the tokenization itself so it will

11:10

create a lot bigger tokens and a lot

11:12

larger groups in English and it will

11:14

have a lot of little boundaries for all

11:16

the other non-english text um so if we

11:19

translated this into English it would be

11:21

significantly fewer

11:23

tokens the final example I have here is

11:25

a little snippet of python for doing FS

11:28

buuz and what I'd like you to notice is

11:31

look all these individual spaces are all

11:34

separate tokens they are token

11:37

220 so uh 220 220 220 220 and then space

11:42

if is a single token and so what's going

11:45

on here is that when the Transformer is

11:46

going to consume or try to uh create

11:49

this text it needs to um handle all

11:52

these spaces individually they all feed

11:54

in one by one into the entire

11:56

Transformer in the sequence and so this

11:59

is being extremely wasteful tokenizing

12:01

it in this way and so as a result of

12:04

that gpt2 is not very good with python

12:07

and it's not anything to do with coding

12:08

or the language model itself it's just

12:10

that if he use a lot of indentation

12:12

using space in Python like we usually do

12:15

uh you just end up bloating out all the

12:17

text and it's separated across way too

12:19

much of the sequence and we are running

12:21

out of the context length in the

12:22

sequence uh that's roughly speaking

12:24

what's what's happening we're being way

12:25

too wasteful we're taking up way too

12:27

much token space now we can also scroll

12:29

up here and we can change the tokenizer

12:31

so note here that gpt2 tokenizer creates

12:34

a token count of 300 for this string

12:36

here we can change it to CL 100K base

12:39

which is the GPT for tokenizer and we

12:41

see that the token count drops to 185 so

12:44

for the exact same string we are now

12:46

roughly having the number of tokens and

12:49

roughly speaking this is because uh the

12:51

number of tokens in the GPT 4 tokenizer

12:54

is roughly double that of the number of

12:56

tokens in the gpt2 tokenizer so we went

12:58

went from roughly 50k to roughly 100K

13:01

now you can imagine that this is a good

13:03

thing because the same text is now

13:06

squished into half as many tokens so uh

13:10

this is a lot denser input to the

13:12

Transformer and in the Transformer every

13:15

single token has a finite number of

13:17

tokens before it that it's going to pay

13:18

attention to and so what this is doing

13:20

is we're roughly able to see twice as

13:23

much text as a context for what token to

13:26

predict next uh because of this change

13:29

but of course just increasing the number

13:30

of tokens is uh not strictly better

13:33

infinitely uh because as you increase

13:35

the number of tokens now your embedding

13:36

table is um sort of getting a lot larger

13:39

and also at the output we are trying to

13:41

predict the next token and there's the

13:42

soft Max there and that grows as well

13:45

we're going to go into more detail later

13:46

on this but there's some kind of a Sweet

13:48

Spot somewhere where you have a just

13:51

right number of tokens in your

13:52

vocabulary where everything is

13:53

appropriately dense and still fairly

13:56

efficient now one thing I would like you

13:58

to note specifically for the gp4

14:00

tokenizer is that the handling of the

14:03

white space for python has improved a

14:05

lot you see that here these four spaces

14:08

are represented as one single token for

14:10

the three spaces here and then the token

14:13

SPF and here seven spaces were all

14:16

grouped into a single token so we're

14:18

being a lot more efficient in how we

14:20

represent Python and this was a

14:21

deliberate Choice made by open aai when

14:23

they designed the gp4 tokenizer and they

14:27

group a lot more space into a single

14:29

character what this does is this

14:32

densifies Python and therefore we can

14:35

attend to more code before it when we're

14:38

trying to predict the next token in the

14:39

sequence and so the Improvement in the

14:42

python coding ability from gbt2 to gp4

14:45

is not just a matter of the language

14:47

model and the architecture and the

14:48

details of the optimization but a lot of

14:50

the Improvement here is also coming from

14:52

the design of the tokenizer and how it

14:54

groups characters into tokens okay so

14:56

let's now start writing some code

14:59

so remember what we want to do we want

15:01

to take strings and feed them into

15:03

language models for that we need to

15:05

somehow tokenize strings into some

15:08

integers in some fixed vocabulary and

15:12

then we will use those integers to make

15:14

a look up into a lookup table of vectors

15:16

and feed those vectors into the

15:18

Transformer as an input now the reason

15:21

this gets a little bit tricky of course

15:22

is that we don't just want to support

15:24

the simple English alphabet we want to

15:26

support different kinds of languages so

15:28

this is anango in Korean which is hello

15:31

and we also want to support many kinds

15:33

of special characters that we might find

15:34

on the internet for example

15:37

Emoji so how do we feed this text into

15:41

uh

15:42

Transformers well how's the what is this

15:44

text anyway in Python so if you go to

15:46

the documentation of a string in Python

15:49

you can see that strings are immutable

15:51

sequences of Unicode code

15:54

points okay what are Unicode code points

15:57

we can go to PDF so Unicode code points

16:01

are defined by the Unicode Consortium as

16:04

part of the Unicode standard and what

16:07

this is really is that it's just a

16:09

definition of roughly 150,000 characters

16:11

right now and roughly speaking what they

16:14

look like and what integers um represent

16:17

those characters so it says 150,000

16:19

characters across 161 scripts as of

16:22

right now so if you scroll down here you

16:24

can see that the standard is very much

16:26

alive the latest standard 15.1 in

16:28

September

16:30

2023 and basically this is just a way to

16:33

define lots of types of

16:36

characters like for example all these

16:39

characters across different scripts so

16:41

the way we can access the unic code code

16:44

Point given Single Character is by using

16:45

the or function in Python so for example

16:48

I can pass in Ord of H and I can see

16:51

that for the Single Character H the unic

16:54

code code point is

16:56

104 okay um but this can be arbitr

17:00

complicated so we can take for example

17:02

our Emoji here and we can see that the

17:04

code point for this one is

17:06

128,000 or we can take

17:10

un and this is 50,000 now keep in mind

17:13

you can't plug in strings here because

17:16

you uh this doesn't have a single code

17:18

point it only takes a single uni code

17:20

code Point character and tells you its

17:23

integer so in this way we can look

17:26

up all the um characters of this

17:30

specific string and their code points so

17:32

or of X forx in this string and we get

17:36

this encoding here now see here we've

17:40

already turned the raw code points

17:42

already have integers so why can't we

17:44

simply just use these integers and not

17:46

have any tokenization at all why can't

17:48

we just use this natively as is and just

17:50

use the code Point well one reason for

17:52

that of course is that the vocabulary in

17:54

that case would be quite long so in this

17:56

case for Unicode the this is a

17:58

vocabulary of

17:59

150,000 different code points but more

18:02

worryingly than that I think the Unicode

18:05

standard is very much alive and it keeps

18:07

changing and so it's not kind of a

18:09

stable representation necessarily that

18:11

we may want to use directly so for those

18:13

reasons we need something a bit better

18:15

so to find something better we turn to

18:17

encodings so if we go to the Wikipedia

18:19

page here we see that the Unicode

18:21

consortion defines three types of

18:23

encodings utf8 UTF 16 and UTF 32 these

18:27

encoding are the way by which we can

18:30

take Unicode text and translate it into

18:33

binary data or by streams utf8 is by far

18:37

the most common uh so this is the utf8

18:39

page now this Wikipedia page is actually

18:42

quite long but what's important for our

18:44

purposes is that utf8 takes every single

18:46

Cod point and it translates it to a by

18:49

stream and this by stream is between one

18:52

to four bytes so it's a variable length

18:54

encoding so depending on the Unicode

18:56

Point according to the schema you're

18:58

going to end up with between 1 to four

18:59

bytes for each code point on top of that

19:03

there's utf8 uh

19:05

utf16 and UTF 32 UTF 32 is nice because

19:08

it is fixed length instead of variable

19:10

length but it has many other downsides

19:12

as well so the full kind of spectrum of

19:17

pros and cons of all these different

19:18

three encodings are beyond the scope of

19:20

this video I just like to point out that

19:22

I enjoyed this block post and this block

19:25

post at the end of it also has a number

19:27

of references that can be quite useful

19:29

uh one of them is uh utf8 everywhere

19:32

Manifesto um and this Manifesto

19:34

describes the reason why utf8 is

19:36

significantly preferred and a lot nicer

19:39

than the other encodings and why it is

19:41

used a lot more prominently um on the

19:45

internet one of the major advantages

19:48

just just to give you a sense is that

19:49

utf8 is the only one of these that is

19:52

backwards compatible to the much simpler

19:54

asky encoding of text um but I'm not

19:57

going to go into the full detail in this

19:58

video so suffice to say that we like the

20:01

utf8 encoding and uh let's try to take

20:03

the string and see what we get if we

20:06

encoded into

20:08

utf8 the string class in Python actually

20:10

has do encode and you can give it the

20:12

encoding which is say utf8 now we get

20:15

out of this is not very nice because

20:17

this is the bytes is a bytes object and

20:20

it's not very nice in the way that it's

20:22

printed so I personally like to take it

20:25

through list because then we actually

20:26

get the raw B

20:28

of this uh encoding so this is the raw

20:32

byes that represent this string

20:35

according to the utf8 en coding we can

20:38

also look at utf16 we get a slightly

20:40

different by stream and we here we start

20:43

to see one of the disadvantages of utf16

20:45

you see how we have zero Z something Z

20:47

something Z something we're starting to

20:49

get a sense that this is a bit of a

20:50

wasteful encoding and indeed for simple

20:53

asky characters or English characters

20:56

here uh we just have the structure of 0

20:58

something Z something and it's not

21:00

exactly nice same for UTF 32 when we

21:04

expand this we can start to get a sense

21:06

of the wastefulness of this encoding for

21:08

our purposes you see a lot of zeros

21:10

followed by

21:11

something and so uh this is not

21:14

desirable so suffice it to say that we

21:17

would like to stick with utf8 for our

21:20

purposes however if we just use utf8

21:23

naively these are by streams so that

21:26

would imply a vocabulary length of only

21:29

256 possible tokens uh but this this

21:33

vocabulary size is very very small what

21:35

this is going to do if we just were to

21:36

use it naively is that all of our text

21:39

would be stretched out over very very

21:41

long sequences of bytes and so

21:46

um what what this does is that certainly

21:49

the embeding table is going to be tiny

21:51

and the prediction at the top at the

21:52

final layer is going to be very tiny but

21:54

our sequences are very long and remember

21:56

that we have pretty finite um context

21:59

length and the attention that we can

22:01

support in a transformer for

22:02

computational reasons and so we only

22:05

have as much context length but now we

22:07

have very very long sequences and this

22:09

is just inefficient and it's not going

22:10

to allow us to attend to sufficiently

22:12

long text uh before us for the purposes

22:15

of the next token prediction task so we

22:18

don't want to use the raw bytes of the

22:21

utf8 encoding we want to be able to

22:24

support larger vocabulary size that we

22:26

can tune as a hyper

22:28

but we want to stick with the utf8

22:30

encoding of these strings so what do we

22:33

do well the answer of course is we turn

22:35

to the bite pair encoding algorithm

22:37

which will allow us to compress these

22:39

bite sequences um to a variable amount

22:42

so we'll get to that in a bit but I just

22:44

want to briefly speak to the fact that I

22:47

would love nothing more than to be able

22:49

to feed raw bite sequences into uh

22:52

language models in fact there's a paper

22:54

about how this could potentially be done

22:57

uh from Summer last last year now the

22:59

problem is you actually have to go in

23:00

and you have to modify the Transformer

23:02

architecture because as I mentioned

23:04

you're going to have a problem where the

23:06

attention will start to become extremely

23:08

expensive because the sequences are so

23:10

long and so in this paper they propose

23:13

kind of a hierarchical structuring of

23:15

the Transformer that could allow you to

23:17

just feed in raw bites and so at the end

23:20

they say together these results

23:21

establish the viability of tokenization

23:23

free autor regressive sequence modeling

23:25

at scale so tokenization free would

23:27

indeed be amazing we would just feed B

23:30

streams directly into our models but

23:32

unfortunately I don't know that this has

23:34

really been proven out yet by

23:36

sufficiently many groups and a

23:37

sufficient scale uh but something like

23:39

this at one point would be amazing and I

23:40

hope someone comes up with it but for

23:42

now we have to come back and we can't

23:44

feed this directly into language models

23:46

and we have to compress it using the B

23:48

paare encoding algorithm so let's see

23:49

how that works so as I mentioned the B

23:51

paare encoding algorithm is not all that

23:53

complicated and the Wikipedia page is

23:55

actually quite instructive as far as the

23:57

basic idea goes go what we're doing is

23:59

we have some kind of a input sequence uh

24:01

like for example here we have only four

24:03

elements in our vocabulary a b c and d

24:06

and we have a sequence of them so

24:08

instead of bytes let's say we just have

24:09

four a vocab size of

24:12

four the sequence is too long and we'd

24:14

like to compress it so what we do is

24:16

that we iteratively find the pair of uh

24:20

tokens that occur the most

24:23

frequently and then once we've

24:25

identified that pair we repl replace

24:28

that pair with just a single new token

24:30

that we append to our vocabulary so for

24:33

example here the bite pair AA occurs

24:36

most often so we mint a new token let's

24:38

call it capital Z and we replace every

24:41

single occurrence of AA by Z so now we

24:46

have two Z's here so here we took a

24:48

sequence of 11 characters with

24:51

vocabulary size four and we've converted

24:54

it to a um sequence of only nine tokens

24:58

but now with a vocabulary of five

25:00

because we have a fifth vocabulary

25:02

element that we just created and it's Z

25:04

standing for concatination of AA and we

25:07

can again repeat this process so we

25:10

again look at the sequence and identify

25:12

the pair of tokens that are most

25:15

frequent let's say that that is now AB

25:19

well we are going to replace AB with a

25:20

new token that we meant call Y so y

25:23

becomes ab and then every single

25:25

occurrence of ab is now replaced with y

25:28

so we end up with this so now we only

25:31

have 1 2 3 4 5 6 seven characters in our

25:35

sequence but we have not just um four

25:40

vocabulary elements or five but now we

25:42

have six and for the final round we

25:45

again look through the sequence find

25:47

that the phrase zy or the pair zy is

25:50

most common and replace it one more time

25:53

with another um character let's say x so

25:56

X is z y and we replace all curses of zy

25:59

and we get this following sequence so

26:02

basically after we have gone through

26:03

this process instead of having a um

26:08

sequence of

26:09

11 uh tokens with a vocabulary length of

26:13

four we now have a sequence of 1 2 3

26:18

four five tokens but our vocabulary

26:21

length now is seven and so in this way

26:25

we can iteratively compress our sequence

26:27

I we Mint new tokens so in the in the

26:30

exact same way we start we start out

26:32

with bite sequences so we have 256

26:36

vocabulary size but we're now going to

26:38

go through these and find the bite pairs

26:40

that occur the most and we're going to

26:42

iteratively start minting new tokens

26:44

appending them to our vocabulary and

26:46

replacing things and in this way we're

26:48

going to end up with a compressed

26:50

training data set and also an algorithm

26:52

for taking any arbitrary sequence and

26:55

encoding it using this uh vocabul

26:58

and also decoding it back to Strings so

27:01

let's now Implement all that so here's

27:03

what I did I went to this block post

27:05

that I enjoyed and I took the first

27:07

paragraph and I copy pasted it here into

27:10

text so this is one very long line

27:13

here now to get the tokens as I

27:15

mentioned we just take our text and we

27:17

encode it into utf8 the tokens here at

27:20

this point will be a raw bites single

27:22

stream of bytes and just so that it's

27:25

easier to work with instead of just a

27:27

bytes object I'm going to convert all

27:29

those bytes to integers and then create

27:32

a list of it just so it's easier for us

27:34

to manipulate and work with in Python

27:35

and visualize and here I'm printing all

27:38

of that so this is the original um this

27:42

is the original paragraph and its length

27:45

is

27:45

533 uh code points and then here are the

27:49

bytes encoded in ut utf8 and we see that

27:53

this has a length of 616 bytes at this

27:56

point or 616 tokens and the reason this

27:59

is more is because a lot of these simple

28:01

asky characters or simple characters

28:04

they just become a single bite but a lot

28:06

of these Unicode more complex characters

28:08

become multiple bytes up to four and so

28:11

we are expanding that

28:12

size so now what we'd like to do as a

28:14

first step of the algorithm is we'd like

28:16

to iterate over here and find the pair

28:18

of bites that occur most frequently

28:22

because we're then going to merge it so

28:24

if you are working long on a notebook on

28:25

a side then I encourage you to basically

28:27

click on the link find this notebook and

28:29

try to write that function yourself

28:31

otherwise I'm going to come here and

28:32

Implement first the function that finds

28:34

the most common pair okay so here's what

28:36

I came up with there are many different

28:38

ways to implement this but I'm calling

28:40

the function get stats it expects a list

28:42

of integers I'm using a dictionary to

28:44

keep track of basically the counts and

28:46

then this is a pythonic way to iterate

28:48

consecutive elements of this list uh

28:51

which we covered in the previous video

28:53

and then here I'm just keeping track of

28:55

just incrementing by one um for all the

28:58

pairs so if I call this on all the

29:00

tokens here then the stats comes out

29:03

here so this is the dictionary the keys

29:06

are these topples of consecutive

29:08

elements and this is the count so just

29:11

to uh print it in a slightly better way

29:14

this is one way that I like to do that

29:17

where you it's a little bit compound

29:20

here so you can pause if you like but we

29:22

iterate all all the items the items

29:25

called on dictionary returns pairs of

29:27

key value and instead I create a list

29:31

here of value key because if it's a

29:35

value key list then I can call sort on

29:37

it and by default python will uh use the

29:41

first element which in this case will be

29:43

value to sort by if it's given tles and

29:46

then reverse so it's descending and

29:48

print that so basically it looks like

29:50

101 comma 32 was the most commonly

29:53

occurring consecutive pair and it

29:55

occurred 20 times we can double check

29:58

that that makes reasonable sense so if I

30:00

just search

30:02

10132 then you see that these are the 20

30:05

occurrences of that um pair and if we'd

30:10

like to take a look at what exactly that

30:11

pair is we can use Char which is the

30:14

opposite of or in Python so we give it a

30:17

um unic code Cod point so 101 and of 32

30:22

and we see that this is e and space so

30:25

basically there's a lot of E space here

30:28

meaning that a lot of these words seem

30:29

to end with e so here's eace as an

30:32

example so there's a lot of that going

30:34

on here and this is the most common pair

30:36

so now that we've identified the most

30:38

common pair we would like to iterate

30:40

over this sequence we're going to Mint a

30:42

new token with the ID of

30:44

256 right because these tokens currently

30:47

go from Z to 255 so when we create a new

30:50

token it will have an ID of

30:52

256 and we're going to iterate over this

30:56

entire um list and every every time we

30:59

see 101 comma 32 we're going to swap

31:02

that out for

31:03

256 so let's Implement that now and feel

31:07

free to uh do that yourself as well so

31:09

first I commented uh this just so we

31:11

don't pollute uh the notebook too much

31:14

this is a nice way of in Python

31:17

obtaining the highest ranking pair so

31:20

we're basically calling the Max on this

31:23

dictionary stats and this will return

31:26

the maximum

31:27

key and then the question is how does it

31:30

rank keys so you can provide it with a

31:32

function that ranks keys and that

31:35

function is just stats. getet uh stats.

31:38

getet would basically return the value

31:41

and so we're ranking by the value and

31:42

getting the maximum key so it's 101

31:45

comma 32 as we saw now to actually merge

31:49

10132 um this is the function that I

31:51

wrote but again there are many different

31:53

versions of it so we're going to take a

31:55

list of IDs and the the pair that we

31:57

want to replace and that pair will be

31:59

replaced with the new index

32:02

idx so iterating through IDs if we find

32:05

the pair swap it out for idx so we

32:08

create this new list and then we start

32:10

at zero and then we go through this

32:12

entire list sequentially from left to

32:14

right and here we are checking for

32:17

equality at the current position with

32:19

the

32:20

pair um so here we are checking that the

32:23

pair matches now here is a bit of a

32:25

tricky condition that you have to append

32:27

if you're trying to be careful and that

32:29

is that um you don't want this here to

32:31

be out of Bounds at the very last

32:33

position when you're on the rightmost

32:35

element of this list otherwise this

32:37

would uh give you an autof bounds error

32:39

so we have to make sure that we're not

32:40

at the very very last element so uh this

32:44

would be false for that so if we find a

32:46

match we append to this new list that

32:51

replacement index and we increment the

32:53

position by two so we skip over that

32:54

entire pair but otherwise if we we

32:57

haven't found a matching pair we just

32:59

sort of copy over the um element at that

33:02

position and increment by one then

33:05

return this so here's a very small toy

33:07

example if we have a list 566 791 and we

33:10

want to replace the occurrences of 67

33:12

with 99 then calling this on that will

33:16

give us what we're asking for so here

33:18

the 67 is replaced with

33:21

99 so now I'm going to uncomment this

33:23

for our actual use case where we want to

33:27

take our tokens we want to take the top

33:29

pair here and replace it with 256 to get

33:33

tokens to if we run this we get the

33:37

following so recall that previously we

33:40

had a length 616 in this list and now we

33:45

have a length 596 right so this

33:48

decreased by 20 which makes sense

33:50

because there are 20 occurrences

33:52

moreover we can try to find 256 here and

33:55

we see plenty of occurrences on off it

33:58

and moreover just double check there

33:59

should be no occurrence of 10132 so this

34:02

is the original array plenty of them and

34:05

in the second array there are no

34:06

occurrences of 1032 so we've

34:08

successfully merged this single pair and

34:11

now we just uh iterate this so we are

34:13

going to go over the sequence again find

34:15

the most common pair and replace it so

34:17

let me now write a y Loop that uses

34:19

these functions to do this um sort of

34:21

iteratively and how many times do we do

34:24

it four well that's totally up to us as

34:26

a hyper parameter

34:27

the more um steps we take the larger

34:30

will be our vocabulary and the shorter

34:33

will be our sequence and there is some

34:35

sweet spot that we usually find works

34:37

the best in practice and so this is kind

34:39

of a hyperparameter and we tune it and

34:41

we find good vocabulary sizes as an

34:44

example gp4 currently uses roughly

34:46

100,000 tokens and um bpark that those

34:49

are reasonable numbers currently instead

34:51

the are large language models so let me

34:53

now write uh putting putting it all

34:55

together and uh iterating these steps

34:58

okay now before we dive into the Y loop

35:00

I wanted to add one more cell here where

35:03

I went to the block post and instead of

35:04

grabbing just the first paragraph or two

35:07

I took the entire block post and I

35:08

stretched it out in a single line and

35:10

basically just using longer text will

35:12

allow us to have more representative

35:13

statistics for the bite Pairs and we'll

35:16

just get a more sensible results out of

35:18

it because it's longer text um so here

35:21

we have the raw text we encode it into

35:24

bytes using the utf8 encoding

35:27

and then here as before we are just

35:30

changing it into a list of integers in

35:31

Python just so it's easier to work with

35:33

instead of the raw byes objects and then

35:36

this is the code that I came up with uh

35:40

to actually do the merging in Loop these

35:44

two functions here are identical to what

35:45

we had above I only included them here

35:48

just so that you have the point of

35:49

reference here so uh these two are

35:53

identical and then this is the new code

35:55

that I added so the first first thing we

35:57

want to do is we want to decide on the

35:58

final vocabulary size that we want our

36:01

tokenizer to have and as I mentioned

36:02

this is a hyper parameter and you set it

36:04

in some way depending on your best

36:06

performance so let's say for us we're

36:08

going to use 276 because that way we're

36:10

going to be doing exactly 20

36:13

merges and uh 20 merges because we

36:15

already have

36:16

256 tokens for the raw bytes and to

36:20

reach 276 we have to do 20 merges uh to

36:23

add 20 new

36:25

tokens here uh this is uh one way in

36:28

Python to just create a copy of a list

36:31

so I'm taking the tokens list and by

36:33

wrapping it in a list python will

36:35

construct a new list of all the

36:37

individual elements so this is just a

36:38

copy

36:39

operation then here I'm creating a

36:42

merges uh dictionary so this merges

36:44

dictionary is going to maintain

36:46

basically the child one child two

36:49

mapping to a new uh token and so what

36:52

we're going to be building up here is a

36:53

binary tree of merges but actually it's

36:56

not exactly a tree because a tree would

36:59

have a single root node with a bunch of

37:01

leaves for us we're starting with the

37:03

leaves on the bottom which are the

37:05

individual bites those are the starting

37:06

256 tokens and then we're starting to

37:09

like merge two of them at a time and so

37:11

it's not a tree it's more like a forest

37:14

um uh as we merge these elements

37:18

so for 20 merges we're going to find the

37:22

most commonly occurring pair we're going

37:25

to Mint a new token integer for it so I

37:28

here will start at zero so we'll going

37:30

to start at 256 we're going to print

37:32

that we're merging it and we're going to

37:34

replace all of the occurrences of that

37:36

pair with the new new lied token and

37:39

we're going to record that this pair of

37:42

integers merged into this new

37:45

integer so running this gives us the

37:49

following

37:51

output so we did 20 merges and for

37:54

example the first merge was exactly as

37:56

before the

37:58

10132 um tokens merging into a new token

38:01

2556 now keep in mind that the

38:04

individual uh tokens 101 and 32 can

38:06

still occur in the sequence after

38:08

merging it's only when they occur

38:10

exactly consecutively that that becomes

38:12

256

38:13

now um and in particular the other thing

38:16

to notice here is that the token 256

38:19

which is the newly minted token is also

38:21

eligible for merging so here on the

38:23

bottom the 20th merge was a merge of 25

38:26

and 259 becoming

38:28

275 so every time we replace these

38:31

tokens they become eligible for merging

38:33

in the next round of data ration so

38:35

that's why we're building up a small

38:37

sort of binary Forest instead of a

38:38

single individual

38:40

tree one thing we can take a look at as

38:42

well is we can take a look at the

38:44

compression ratio that we've achieved so

38:46

in particular we started off with this

38:48

tokens list um so we started off with

38:51

24,000 bytes and after merging 20 times

38:56

uh we now have only

38:58

19,000 um tokens and so therefore the

39:01

compression ratio simply just dividing

39:03

the two is roughly 1.27 so that's the

39:06

amount of compression we were able to

39:07

achieve of this text with only 20

39:10

merges um and of course the more

39:13

vocabulary elements you add uh the

39:15

greater the compression ratio here would

39:19

be finally so that's kind of like um the

39:23

training of the tokenizer if you will

39:25

now 1 Point I wanted to make is that and

39:28

maybe this is a diagram that can help um

39:31

kind of illustrate is that tokenizer is

39:33

a completely separate object from the

39:34

large language model itself so

39:37

everything in this lecture we're not

39:38

really touching the llm itself uh we're

39:40

just training the tokenizer this is a

39:41

completely separate pre-processing stage

39:43

usually so the tokenizer will have its

39:46

own training set just like a large

39:47

language model has a potentially

39:49

different training set so the tokenizer

39:52

has a training set of documents on which

39:53

you're going to train the

39:54

tokenizer and then and um we're

39:57

performing The Bite pair encoding

39:58

algorithm as we saw above to train the

40:01

vocabulary of this

40:02

tokenizer so it has its own training set

40:04

it is a pre-processing stage that you

40:06

would run a single time in the beginning

40:09

um and the tokenizer is trained using

40:11

bipar coding algorithm once you have the

40:14

tokenizer once it's trained and you have

40:16

the vocabulary and you have the merges

40:19

uh we can do both encoding and decoding

40:22

so these two arrows here so the

40:24

tokenizer is a translation layer between

40:27

raw text which is as we saw the sequence

40:30

of Unicode code points it can take raw

40:32

text and turn it into a token sequence

40:35

and vice versa it can take a token

40:37

sequence and translate it back into raw

40:40

text so now that we have trained uh

40:43

tokenizer and we have these merges we

40:45

are going to turn to how we can do the

40:47

encoding and the decoding step if you

40:49

give me text here are the tokens and

40:51

vice versa if you give me tokens here's

40:53

the text once we have that we can

40:55

translate between these two Realms and

40:57

then the language model is going to be

40:58

trained as a step two afterwards and

41:01

typically in a in a sort of a

41:03

state-of-the-art application you might

41:05

take all of your training data for the

41:06

language model and you might run it

41:08

through the tokenizer and sort of

41:10

translate everything into a massive

41:11

token sequence and then you can throw

41:13

away the raw text you're just left with

41:15

the tokens themselves and those are

41:17

stored on disk and that is what the

41:19

large language model is actually reading

41:21

when it's training on them so this one

41:23

approach that you can take as a single

41:24

massive pre-processing step a

41:26

stage um so yeah basically I think the

41:30

most important thing I want to get

41:31

across is that this is completely

41:32

separate stage it usually has its own

41:34

entire uh training set you may want to

41:36

have those training sets be different

41:38

between the tokenizer and the logge

41:39

language model so for example when

41:41

you're training the tokenizer as I

41:43

mentioned we don't just care about the

41:45

performance of English text we care

41:46

about uh multi many different languages

41:49

and we also care about code or not code

41:51

so you may want to look into different

41:53

kinds of mixtures of different kinds of

41:55

languages and different amounts of code

41:57

and things like that because the amount

42:00

of different language that you have in

42:01

your tokenizer training set will

42:03

determine how many merges of it there

42:06

will be and therefore that determines

42:08

the density with which uh this type of

42:11

data is um sort of has in the token

42:15

space and so roughly speaking

42:17

intuitively if you add some amount of

42:19

data like say you have a ton of Japanese

42:21

data in your uh tokenizer training set

42:24

then that means that more Japanese

42:25

tokens will get merged

42:26

and therefore Japanese will have shorter

42:28

sequences uh and that's going to be

42:30

beneficial for the large language model

42:32

which has a finite context length on

42:34

which it can work on in in the token

42:36

space uh so hopefully that makes sense

42:39

so we're now going to turn to encoding

42:41

and decoding now that we have trained a

42:43

tokenizer so we have our merges and now

42:46

how do we do encoding and decoding okay

42:48

so let's begin with decoding which is

42:50

this Arrow over here so given a token

42:52

sequence let's go through the tokenizer

42:54

to get back a python string object so

42:57

the raw text so this is the function

42:59

that we' like to implement um we're

43:01

given the list of integers and we want

43:03

to return a python string if you'd like

43:05

uh try to implement this function

43:06

yourself it's a fun exercise otherwise

43:08

I'm going to start uh pasting in my own

43:11

solution so there are many different

43:13

ways to do it um here's one way I will

43:16

create an uh kind of pre-processing

43:18

variable that I will call

43:21

vocab and vocab is a mapping or a

43:24

dictionary in Python for from the token

43:27

uh ID to the bytes object for that token

43:31

so we begin with the raw bytes for

43:33

tokens from 0 to 255 and then we go in

43:36

order of all the merges and we sort of

43:39

uh populate this vocab list by doing an

43:42

addition here so this is the basically

43:45

the bytes representation of the first

43:47

child followed by the second one and

43:50

remember these are bytes objects so this

43:52

addition here is an addition of two

43:54

bytes objects just concatenation

43:57

so that's what we get

43:58

here one tricky thing to be careful with

44:01

by the way is that I'm iterating a

44:02

dictionary in Python using a DOT items

44:06

and uh it really matters that this runs

44:08

in the order in which we inserted items

44:11

into the merous dictionary luckily

44:13

starting with python 3.7 this is

44:15

guaranteed to be the case but before

44:17

python 3.7 this iteration may have been

44:19

out of order with respect to how we

44:20

inserted elements into merges and this

44:23

may not have worked but we are using an

44:25

um modern python so we're okay and then

44:28

here uh given the IDS the first thing

44:31

we're going to do is get the

44:35

tokens so the way I implemented this

44:37

here is I'm taking I'm iterating over

44:39

all the IDS I'm using vocap to look up

44:41

their bytes and then here this is one

44:44

way in Python to concatenate all these

44:46

bytes together to create our tokens and

44:49

then these tokens here at this point are

44:51

raw bytes so I have to decode using UTF

44:56

F now back into python strings so

44:59

previously we called that encode on a

45:01

string object to get the bytes and now

45:03

we're doing it Opposite we're taking the

45:05

bytes and calling a decode on the bytes

45:07

object to get a string in Python and

45:11

then we can return

45:13

text so um this is how we can do it now

45:16

this actually has a um issue um in the

45:20

way I implemented it and this could

45:22

actually throw an error so try to think

45:24

figure out why this code could actually

45:26

result in an error if we plug in um uh

45:30

some sequence of IDs that is

45:32

unlucky so let me demonstrate the issue

45:35

when I try to decode just something like

45:37

97 I am going to get letter A here back

45:41

so nothing too crazy happening but when

45:44

I try to decode 128 as a single element

45:48

the token 128 is what in string or in

45:51

Python object uni Cod decoder utfa can't

45:55

Decode by um 0x8 which is this in HEX in

46:00

position zero invalid start bite what

46:01

does that mean well to understand what

46:03

this means we have to go back to our

46:04

utf8 page uh that I briefly showed

46:07

earlier and this is Wikipedia utf8 and

46:10

basically there's a specific schema that

46:13

utfa bytes take so in particular if you

46:16

have a multi-te object for some of the

46:19

Unicode characters they have to have

46:21

this special sort of envelope in how the

46:24

encoding works and so what's happening

46:26

here is that invalid start pite that's

46:30

because

46:31

128 the binary representation of it is

46:33

one followed by all zeros so we have one

46:37

and then all zero and we see here that

46:39

that doesn't conform to the format

46:41

because one followed by all zero just

46:42

doesn't fit any of these rules so to

46:44

speak so it's an invalid start bite

46:47

which is byte one this one must have a

46:50

one following it and then a zero

46:52

following it and then the content of

46:54

your uni codee in x here so basically we

46:57

don't um exactly follow the utf8

46:59

standard and this cannot be decoded and

47:02

so the way to fix this um is to

47:06

use this errors equals in bytes. decode

47:11

function of python and by default errors

47:13

is strict so we will throw an error if

47:17

um it's not valid utf8 bytes encoding

47:20

but there are many different things that

47:21

you could put here on error handling

47:23

this is the full list of all the errors

47:25

that you can use and in particular

47:27

instead of strict let's change it to

47:29

replace and that will replace uh with

47:32

this special marker this replacement

47:35

character so errors equals replace and

47:40

now we just get that character

47:43

back so basically not every single by

47:46

sequence is valid

47:48

utf8 and if it happens that your large

47:51

language model for example predicts your

47:53

tokens in a bad manner then they might

47:56

not fall into valid utf8 and then we

48:00

won't be able to decode them so the

48:02

standard practice is to basically uh use

48:05

errors equals replace and this is what

48:07

you will also find in the openai um code

48:10

that they released as well but basically

48:12

whenever you see um this kind of a

48:14

character in your output in that case uh

48:16

something went wrong and the LM output

48:18

not was not valid uh sort of sequence of

48:21

tokens okay and now we're going to go

48:23

the other way so we are going to

48:25

implement

48:26

this Arrow right here where we are going

48:27

to be given a string and we want to

48:29

encode it into

48:31

tokens so this is the signature of the

48:33

function that we're interested in and um

48:36

this should basically print a list of

48:38

integers of the tokens so again uh try

48:41

to maybe implement this yourself if

48:43

you'd like a fun exercise uh and pause

48:45

here otherwise I'm going to start

48:46

putting in my

48:47

solution so again there are many ways to

48:50

do this so um this is one of the ways

48:53

that sort of I came came up with so the

48:57

first thing we're going to do is we are

48:59

going

49:00

to uh take our text encode it into utf8

49:03

to get the raw bytes and then as before

49:05

we're going to call list on the bytes

49:07

object to get a list of integers of

49:10

those bytes so those are the starting

49:12

tokens those are the raw bytes of our

49:14

sequence but now of course according to

49:16

the merges dictionary above and recall

49:19

this was the

49:21

merges some of the bytes may be merged

49:23

according to this lookup in addition to

49:26

that remember that the merges was built

49:28

from top to bottom and this is sort of

49:29

the order in which we inserted stuff

49:31

into merges and so we prefer to do all

49:34

these merges in the beginning before we

49:36

do these merges later because um for

49:39

example this merge over here relies on

49:40

the 256 which got merged here so we have

49:44

to go in the order from top to bottom

49:46

sort of if we are going to be merging

49:48

anything now we expect to be doing a few

49:51

merges so we're going to be doing W

49:54

true um and now we want to find a pair

49:58

of byes that is consecutive that we are

50:00

allowed to merge according to this in

50:03

order to reuse some of the functionality

50:05

that we've already written I'm going to

50:06

reuse the function uh get

50:09

stats so recall that get stats uh will

50:12

give us the we'll basically count up how

50:14

many times every single pair occurs in

50:16

our sequence of tokens and return that

50:18

as a dictionary and the dictionary was a

50:22

mapping from all the different uh by

50:25

pairs to the number of times that they

50:27

occur right um at this point we don't

50:30

actually care how many times they occur

50:32

in the sequence we only care what the

50:34

raw pairs are in that sequence and so

50:36

I'm only going to be using basically the

50:38

keys of the dictionary I only care about

50:40

the set of possible merge candidates if

50:42

that makes

50:43

sense now we want to identify the pair

50:46

that we're going to be merging at this

50:47

stage of the loop so what do we want we

50:50

want to find the pair or like the a key

50:53

inside stats that has the lowest index

50:57

in the merges uh dictionary because we

50:59

want to do all the early merges before

51:01

we work our way to the late

51:03

merges so again there are many different

51:05

ways to implement this but I'm going to

51:07

do something a little bit fancy

51:11

here so I'm going to be using the Min

51:14

over an iterator in Python when you call

51:16

Min on an iterator and stats here as a

51:18

dictionary we're going to be iterating

51:20

the keys of this dictionary in Python so

51:24

we're looking at all the pairs inside

51:27

stats um which are all the consecutive

51:29

Pairs and we're going to be taking the

51:32

consecutive pair inside tokens that has

51:34

the minimum what the Min takes a key

51:38

which gives us the function that is

51:40

going to return a value over which we're

51:42

going to do the Min and the one we care

51:44

about is we're we care about taking

51:46

merges and basically getting um that

51:50

pairs

51:52

index so basically for any pair inside

51:57

stats we are going to be looking into

51:59

merges at what index it has and we want

52:03

to get the pair with the Min number so

52:05

as an example if there's a pair 101 and

52:07

32 we definitely want to get that pair

52:10

uh we want to identify it here and

52:11

return it and pair would become 10132 if

52:15

it

52:15

occurs and the reason that I'm putting a

52:17

float INF here as a fall back is that in

52:21

the get function when we call uh when we

52:24

basically consider a pair that doesn't

52:26

occur in the merges then that pair is

52:29

not eligible to be merged right so if in

52:31

the token sequence there's some pair

52:33

that is not a merging pair it cannot be

52:35

merged then uh it doesn't actually occur

52:38

here and it doesn't have an index and uh

52:40

it cannot be merged which we will denote

52:42

as float INF and the reason Infinity is

52:45

nice here is because for sure we're

52:46

guaranteed that it's not going to

52:48

participate in the list of candidates

52:50

when we do the men so uh so this is one

52:53

way to do it so B basically long story

52:55

short this Returns the most eligible

52:58

merging candidate pair uh that occurs in

53:01

the tokens now one thing to be careful

53:04

with here is this uh function here might

53:07

fail in the following way if there's

53:09

nothing to merge then uh uh then there's

53:13

nothing in merges um that satisfi that

53:16

is satisfied anymore there's nothing to

53:18

merge everything just returns float imps

53:21

and then the pair I think will just

53:23

become the very first element of stats

53:26

um but this pair is not actually a

53:28

mergeable pair it just becomes the first

53:31

pair inside stats arbitrarily because

53:33

all of these pairs evaluate to float in

53:36

for the merging Criterion so basically

53:38

it could be that this this doesn't look

53:40

succeed because there's no more merging

53:41

pairs so if this pair is not in merges

53:44

that was returned then this is a signal

53:46

for us that actually there was nothing

53:48

to merge no single pair can be merged

53:50

anymore in that case we will break

53:53

out um nothing else can be

53:57

merged you may come up with a different

53:59

implementation by the way this is kind

54:01

of like really trying hard in

54:03

Python um but really we're just trying

54:05

to find a pair that can be merged with

54:07

the lowest index

54:09

here now if we did find a pair that is

54:13

inside merges with the lowest index then

54:16

we can merge it

54:19

so we're going to look into the merger

54:22

dictionary for that pair to look up the

54:24

index and we're going to now merge that

54:27

into that index so we're going to do

54:29

tokens equals and we're going to

54:32

replace the original tokens we're going

54:34

to be replacing the pair pair and we're

54:36

going to be replacing it with index idx

54:38

and this returns a new list of tokens

54:41

where every occurrence of pair is

54:43

replaced with idx so we're doing a merge

54:46

and we're going to be continuing this

54:47

until eventually nothing can be merged

54:49

we'll come out here and we'll break out

54:51

and here we just return

54:53

tokens and so that that's the

54:55

implementation I think so hopefully this

54:57

runs okay cool um yeah and this looks uh

55:02

reasonable so for example 32 is a space

55:04

in asky so that's here um so this looks

55:09

like it worked great okay so let's wrap

55:11

up this section of the video at least I

55:13

wanted to point out that this is not

55:14

quite the right implementation just yet

55:16

because we are leaving out a special

55:17

case so in particular if uh we try to do

55:20

this this would give us an error and the

55:23

issue is that um if we only have a

55:25

single character or an empty string then

55:28

stats is empty and that causes an issue

55:29

inside Min so one way to fight this is

55:32

if L of tokens is at least two because

55:36

if it's less than two it's just a single

55:37

token or no tokens then let's just uh

55:40

there's nothing to merge so we just

55:41

return so that would fix uh that

55:44

case Okay and then second I have a few

55:48

test cases here for us as well so first

55:50

let's make sure uh about or let's note

55:53

the following if we take a string and we

55:56

try to encode it and then decode it back

55:58

you'd expect to get the same string back

56:00

right is that true for all

56:04

strings so I think uh so here it is the

56:07

case and I think in general this is

56:08

probably the case um but notice that

56:12

going backwards is not is not you're not

56:14

going to have an identity going

56:15

backwards because as I mentioned us not

56:19

all token sequences are valid utf8 uh

56:22

sort of by streams and so so therefore

56:25

you're some of them can't even be

56:27

decodable um so this only goes in One

56:30

Direction but for that one direction we

56:32

can check uh here if we take the

56:34

training text which is the text that we

56:36

train to tokenizer around we can make

56:38

sure that when we encode and decode we

56:39

get the same thing back which is true

56:41

and here I took some validation data so

56:43

I went to I think this web page and I

56:45

grabbed some text so this is text that

56:47

the tokenizer has not seen and we can

56:49

make sure that this also works um okay

56:52

so that gives us some confidence that

56:53

this was correctly implemented

56:56

so those are the basics of the bite pair

56:58

encoding algorithm we saw how we can uh

57:00

take some training set train a tokenizer

57:03

the parameters of this tokenizer really

57:05

are just this dictionary of merges and

57:08

that basically creates the little binary

57:09

Forest on top of raw

57:11

bites once we have this the merges table

57:14

we can both encode and decode between

57:16

raw text and token sequences so that's

57:19

the the simplest setting of The

57:21

tokenizer what we're going to do now

57:23

though is we're going to look at some of

57:24

the St the art lar language models and

57:26

the kinds of tokenizers that they use

57:28

and we're going to see that this picture

57:29

complexifies very quickly so we're going

57:31

to go through the details of this comp

57:34

complexification one at a time so let's

57:37

kick things off by looking at the GPD

57:39

Series so in particular I have the gpt2

57:41

paper here um and this paper is from

57:44

2019 or so so 5 years ago and let's

57:48

scroll down to input representation this

57:51

is where they talk about the tokenizer

57:52

that they're using for gpd2 now this is

57:55

all fairly readable so I encourage you

57:57

to pause and um read this yourself but

58:00

this is where they motivate the use of

58:02

the bite pair encoding algorithm on the

58:04

bite level representation of utf8

58:07

encoding so this is where they motivate

58:09

it and they talk about the vocabulary

58:11

sizes and everything now everything here

58:13

is exactly as we've covered it so far

58:15

but things start to depart around here

58:18

so what they mention is that they don't

58:20

just apply the naive algorithm as we

58:22

have done it and in particular here's a

58:25

example suppose that you have common

58:27

words like dog what will happen is that

58:29

dog of course occurs very frequently in

58:31

the text and it occurs right next to all

58:34

kinds of punctuation as an example so

58:36

doc dot dog exclamation mark dog

58:39

question mark Etc and naively you might

58:42

imagine that the BP algorithm could

58:43

merge these to be single tokens and then

58:45

you end up with lots of tokens that are

58:47

just like dog with a slightly different

58:49

punctuation and so it feels like you're

58:50

clustering things that shouldn't be

58:52

clustered you're combining kind of

58:53

semantics with

58:55

uation and this uh feels suboptimal and

58:58

indeed they also say that this is

59:00

suboptimal according to some of the

59:02

experiments so what they want to do is

59:04

they want to top down in a manual way

59:06

enforce that some types of um characters

59:09

should never be merged together um so

59:12

they want to enforce these merging rules

59:14

on top of the bite PA encoding algorithm

59:17

so let's take a look um at their code

59:19

and see how they actually enforce this

59:21

and what kinds of mergy they actually do

59:23

perform so I have to to tab open here

59:25

for gpt2 under open AI on GitHub and

59:29

when we go to

59:30

Source there is an encoder thatp now I

59:34

don't personally love that they call it

59:35

encoder dopy because this is the

59:37

tokenizer and the tokenizer can do both

59:39

encode and decode uh so it feels kind of

59:41

awkward to me that it's called encoder

59:43

but that is the tokenizer and there's a

59:45

lot going on here and we're going to

59:47

step through it in detail at one point

59:49

for now I just want to focus on this

59:51

part here the create a rigix pattern

59:54

here that looks very complicated and

59:56

we're going to go through it in a bit uh

59:58

but this is the core part that allows

60:00

them to enforce rules uh for what parts

60:04

of the text Will Never Be merged for

60:05

sure now notice that re. compile here is

60:08

a little bit misleading because we're

60:10

not just doing import re which is the

60:12

python re module we're doing import reex

60:14

as re and reex is a python package that

60:17

you can install P install r x and it's

60:20

basically an extension of re so it's a

60:22

bit more powerful

60:23

re um

60:26

so let's take a look at this pattern and

60:28

what it's doing and why this is actually

60:30

doing the separation that they are

60:32

looking for okay so I've copy pasted the

60:34

pattern here to our jupit notebook where

60:37

we left off and let's take this pattern

60:39

for a spin so in the exact same way that

60:42

their code does we're going to call an

60:44

re. findall for this pattern on any

60:47

arbitrary string that we are interested

60:49

so this is the string that we want to

60:50

encode into tokens um to feed into n llm

60:55

like gpt2 so what exactly is this doing

60:59

well re. findall will take this pattern

61:01

and try to match it against a

61:02

string um the way this works is that you

61:06

are going from left to right in the

61:07

string and you're trying to match the

61:10

pattern and R.F find all will get all

61:13

the occurrences and organize them into a

61:16

list now when you look at the um when

61:19

you look at this pattern first of all

61:20

notice that this is a raw string um and

61:23

then these are three double quotes just

61:26

to start the string so really the string

61:28

itself this is the pattern itself

61:31

right and notice that it's made up of a

61:34

lot of ores so see these vertical bars

61:36

those are ores in reg X and so you go

61:40

from left to right in this pattern and

61:41

try to match it against the string

61:43

wherever you are so we have hello and

61:46

we're going to try to match it well it's

61:48

not apostrophe s it's not apostrophe t

61:50

or any of these but it is an optional

61:53

space followed by- P of uh sorry SL P of

61:58

L one or more times what is/ P of L it

62:02

is coming to some documentation that I

62:04

found um there might be other sources as

62:08

well uh SLP is a letter any kind of

62:11

letter from any language and hello is

62:15

made up of letters h e l Etc so optional

62:19

space followed by a bunch of letters one

62:21

or more letters is going to match hello

62:24

but then the match ends because a white

62:27

space is not a letter so from there on

62:31

begins a new sort of attempt to match

62:33

against the string again and starting in

62:36

here we're going to skip over all of

62:38

these again until we get to the exact

62:40

same Point again and we see that there's

62:42

an optional space this is the optional

62:44

space followed by a bunch of letters one

62:46

or more of them and so that matches so

62:48

when we run this we get a list of two

62:52

elements hello and then space world

62:55

so how are you if we add more letters we

62:58

would just get them like this now what

63:01

is this doing and why is this important

63:03

we are taking our string and instead of

63:05

directly encoding it um for

63:09

tokenization we are first splitting it

63:11

up and when you actually step through

63:13

the code and we'll do that in a bit more

63:15

detail what really is doing on a high

63:17

level is that it first splits your text

63:20

into a list of texts just like this one

63:24

and all these elements of this list are

63:26

processed independently by the tokenizer

63:29

and all of the results of that

63:30

processing are simply

63:32

concatenated so hello world oh I I

63:35

missed how hello world how are you we

63:39

have five elements of list all of these

63:41

will independent

63:44

independently go from text to a token

63:47

sequence and then that token sequence is

63:49

going to be concatenated it's all going

63:50

to be joined up and roughly speaking

63:54

what that does is you're only ever

63:56

finding merges between the elements of

63:58

this list so you can only ever consider

64:00

merges within every one of these

64:01

elements in

64:03

individually and um after you've done

64:06

all the possible merging for all of

64:07

these elements individually the results

64:09

of all that will be joined um by

64:13

concatenation and so you are basically

64:16

what what you're doing effectively is

64:18

you are never going to be merging this e

64:21

with this space because they are now

64:23

parts of the separate elements of this

64:25

list and so you are saying we are never

64:27

going to merge

64:28

eace um because we're breaking it up in

64:32

this way so basically using this regx

64:35

pattern to Chunk Up the text is just one

64:37

way of enforcing that some merges are

64:41

not to happen and we're going to go into

64:43

more of this text and we'll see that

64:45

what this is trying to do on a high

64:46

level is we're trying to not merge

64:48

across letters across numbers across

64:50

punctuation and so on so let's see in

64:53

more detail how that works so let's

64:54

continue now we have/ P ofn if you go to

64:58

the documentation SLP of n is any kind

65:01

of numeric character in any script so

65:04

it's numbers so we have an optional

65:06

space followed by numbers and those

65:08

would be separated out so letters and

65:10

numbers are being separated so if I do

65:12

Hello World 123 how are you then world

65:15

will stop matching here because one is

65:17

not a letter anymore but one is a number

65:20

so this group will match for that and

65:22

we'll get it as a separate entity

65:26

uh let's see how these apostrophes work

65:28

so here if we have

65:31

um uh Slash V or I mean apostrophe V as

65:35

an example then apostrophe here is not a

65:38

letter or a

65:39

number so hello will stop matching and

65:42

then we will exactly match this with

65:44

that so that will come out as a separate

65:48

thing so why are they doing the

65:50

apostrophes here honestly I think that

65:52

these are just like very common

65:53

apostrophes p uh that are used um

65:56

typically I don't love that they've done

65:59

this

66:00

because uh let me show you what happens

66:03

when you have uh some Unicode

66:05

apostrophes like for example you can

66:07

have if you have house then this will be

66:10

separated out because of this matching

66:13

but if you use the Unicode apostrophe

66:15

like

66:16

this then suddenly this does not work

66:19

and so this apostrophe will actually

66:21

become its own thing now and so so um

66:24

it's basically hardcoded for this

66:26

specific kind of apostrophe and uh

66:29

otherwise they become completely

66:31

separate tokens in addition to this you

66:34

can go to the gpt2 docs and here when

66:38

they Define the pattern they say should

66:40

have added re. ignore case so BP merges

66:43

can happen for capitalized versions of

66:44

contractions so what they're pointing

66:46

out is that you see how this is

66:47

apostrophe and then lowercase letters

66:50

well because they didn't do re. ignore

66:52

case then then um these rules will not

66:56

separate out the apostrophes if it's

66:58

uppercase so

67:01

house would be like this but if I did

67:06

house if I'm uppercase then notice

67:10

suddenly the apostrophe comes by

67:12

itself so the tokenization will work

67:15

differently in uppercase and lower case

67:17

inconsistently separating out these

67:19

apostrophes so it feels extremely gnarly

67:21

and slightly gross um but that's that's

67:24

how that works okay so let's come back

67:27

after trying to match a bunch of

67:28

apostrophe Expressions by the way the

67:30

other issue here is that these are quite

67:32

language specific probably so I don't

67:34

know that all the languages for example

67:35

use or don't use apostrophes but that

67:37

would be inconsistently tokenized as a

67:39

result then we try to match letters then

67:42

we try to match numbers and then if that

67:44

doesn't work we fall back to here and

67:47

what this is saying is again optional

67:49

space followed by something that is not

67:50

a letter number or a space in one or

67:53

more of that so what this is doing

67:55

effectively is this is trying to match

67:57

punctuation roughly speaking not letters

67:59

and not numbers so this group will try

68:02

to trigger for that so if I do something

68:04

like this then these parts here are not

68:08

letters or numbers but they will

68:09

actually they are uh they will actually

68:12

get caught here and so they become its

68:14

own group so we've separated out the

68:17

punctuation and finally this um this is

68:20

also a little bit confusing so this is

68:22

matching white space but this is using a

68:25

negative look ahead assertion in regex

68:29

so what this is doing is it's matching

68:30

wh space up to but not including the

68:33

last Whit space

68:35

character why is this important um this

68:37

is pretty subtle I think so you see how

68:40

the white space is always included at

68:41

the beginning of the word so um space r

68:45

space u Etc suppose we have a lot of

68:48

spaces

68:49

here what's going to happen here is that

68:52

these spaces up to not including the

68:54

last character will get caught by this

68:57

and what that will do is it will

68:59

separate out the spaces up to but not

69:01

including the last character so that the

69:03

last character can come here and join

69:05

with the um space you and the reason

69:09

that's nice is because space you is the

69:11

common token so if I didn't have these

69:13

Extra Spaces here you would just have

69:15

space you and if I add tokens if I add

69:18

spaces we still have a space view but

69:20

now we have all this extra white space

69:22

so basically the GB to tokenizer really

69:24

likes to have a space letters or numbers

69:27

um and it it preens these spaces and

69:30

this is just something that it is

69:31

consistent about so that's what that is

69:33

for and then finally we have all the the

69:36

last fallback is um whites space

69:38

characters uh so um that would be

69:42

just um if that doesn't get caught then

69:46

this thing will catch any trailing

69:48

spaces and so on I wanted to show one

69:50

more real world example here so if we

69:53

have this string which is a piece of

69:54

python code and then we try to split it

69:56

up then this is the kind of output we

69:58

get so you'll notice that the list has

70:00

many elements here and that's because we

70:02

are splitting up fairly often uh every

70:05

time sort of a category

70:07

changes um so there will never be any

70:09

merges Within These

70:10

elements and um that's what you are

70:13

seeing here now you might think that in

70:16

order to train the

70:17

tokenizer uh open AI has used this to

70:21

split up text into chunks and then run

70:23

just a BP algorithm within all the

70:25

chunks but that is not exactly what

70:27

happened and the reason is the following

70:30

notice that we have the spaces here uh

70:33

those Spaces end up being entire

70:35

elements but these spaces never actually

70:38

end up being merged by by open Ai and

70:40

the way you can tell is that if you copy

70:42

paste the exact same chunk here into Tik

70:44

token U Tik tokenizer you see that all

70:47

the spaces are kept independent and

70:49

they're all token

70:51

220 so I think opena at some point Point

70:53

en Force some rule that these spaces

70:56

would never be merged and so um there's

70:59

some additional rules on top of just

71:01

chunking and bpe that open ey is not uh

71:04

clear about now the training code for

71:06

the gpt2 tokenizer was never released so

71:08

all we have is uh the code that I've

71:10

already shown you but this code here

71:13

that they've released is only the

71:14

inference code for the tokens so this is

71:17

not the training code you can't give it

71:19

a piece of text and training tokenizer

71:21

this is just the inference code which

71:23

Tak takes the merges that we have up

71:25

above and applies them to a new piece of

71:28

text and so we don't know exactly how

71:30

opening ey trained um train the

71:32

tokenizer but it wasn't as simple as

71:34

chunk it up and BP it uh whatever it was

71:38

next I wanted to introduce you to the

71:40

Tik token library from openai which is

71:42

the official library for tokenization

71:44

from openai so this is Tik token bip

71:48

install P to Tik token and then um you

71:51

can do the tokenization in inference

71:54

this is again not training code this is

71:55

only inference code for

71:57

tokenization um I wanted to show you how

72:00

you would use it quite simple and

72:02

running this just gives us the gpt2

72:04

tokens or the GPT 4 tokens so this is

72:06

the tokenizer use for GPT 4 and so in

72:09

particular we see that the Whit space in

72:11

gpt2 remains unmerged but in GPT 4 uh

72:14

these Whit spaces merge as we also saw

72:17

in this one where here they're all

72:19

unmerged but if we go down to GPT 4 uh

72:22

they become merged

72:25

um now in the

72:27

gp4 uh tokenizer they changed the

72:31

regular expression that they use to

72:33

Chunk Up text so the way to see this is

72:35

that if you come to your the Tik token

72:38

uh library and then you go to this file

72:41

Tik token X openi public this is where

72:44

sort of like the definition of all these

72:45

different tokenizers that openi

72:46

maintains is and so uh necessarily to do

72:50

the inference they had to publish some

72:51

of the details about the strings

72:53

so this is the string that we already

72:55

saw for gpt2 it is slightly different

72:58

but it is actually equivalent uh to what

73:00

we discussed here so this pattern that

73:02

we discussed is equivalent to this

73:04

pattern this one just executes a little

73:07

bit faster so here you see a little bit

73:09

of a slightly different definition but

73:10

otherwise it's the same we're going to

73:12

go into special tokens in a bit and then

73:15

if you scroll down to CL 100k this is

73:18

the GPT 4 tokenizer you see that the

73:20

pattern has changed um and this is kind

73:23

of like the main the major change in

73:26

addition to a bunch of other special

73:27

tokens which I'll go into in a bit again

73:30

now some I'm not going to actually go

73:31

into the full detail of the pattern

73:33

change because honestly this is my

73:35

numbing uh I would just advise that you

73:37

pull out chat GPT and the regex

73:39

documentation and just step through it

73:42

but really the major changes are number

73:44

one you see this eye here that means

73:48

that the um case sensitivity this is

73:51

case insensitive match and so the

73:53

comment that we saw earlier on oh we

73:56

should have used re. uppercase uh

73:58

basically we're now going to be matching

74:01

these apostrophe s apostrophe D

74:04

apostrophe M Etc uh we're going to be

74:06

matching them both in lowercase and in

74:08

uppercase so that's fixed there's a

74:11

bunch of different like handling of the

74:12

whites space that I'm not going to go

74:14

into the full details of and then one

74:16

more thing here is you will notice that

74:18

when they match the numbers they only

74:20

match one to three numbers so so they

74:23

will never merge

74:26

numbers that are in low in more than

74:28

three digits only up to three digits of

74:31

numbers will ever be merged and uh

74:34

that's one change that they made as well

74:36

to prevent uh tokens that are very very

74:38

long number

74:40

sequences uh but again we don't really

74:42

know why they do any of this stuff uh

74:44

because none of this is documented and

74:46

uh it's just we just get the pattern so

74:49

um yeah it is what it is but those are

74:51

some of the changes that gp4 has made

74:54

and of course the vocabulary size went

74:56

from roughly 50k to roughly

74:58

100K the next thing I would like to do

75:00

very briefly is to take you through the

75:02

gpt2 encoder dopy that openi has

75:05

released uh this is the file that I

75:07

already mentioned to you briefly now

75:09

this file is uh fairly short and should

75:12

be relatively understandable to you at

75:14

this point um starting at the bottom

75:17

here they are loading two files encoder

75:21

Json and vocab bpe and they do some

75:24

light processing on it and then they

75:25

call this encoder object which is the

75:27

tokenizer now if you'd like to inspect

75:30

these two files which together

75:31

constitute their saved tokenizer then

75:34

you can do that with a piece of code

75:36

like

75:36

this um this is where you can download

75:39

these two files and you can inspect them

75:40

if you'd like and what you will find is

75:42

that this encoder as they call it in

75:45

their code is exactly equivalent to our

75:47

vocab so remember here where we have

75:51

this vocab object which allowed us us to

75:53

decode very efficiently and basically it

75:56

took us from the integer to the byes uh

76:00

for that integer so our vocab is exactly

76:03

their encoder and then their vocab bpe

76:07

confusingly is actually are merges so

76:11

their BP merges which is based on the

76:14

data inside vocab bpe ends up being

76:16

equivalent to our merges so uh basically

76:20

they are saving and loading the two uh

76:24

variables that for us are also critical

76:26

the merges variable and the vocab

76:28

variable using just these two variables

76:31

you can represent a tokenizer and you

76:32

can both do encoding and decoding once

76:34

you've trained this

76:36

tokenizer now the only thing that um is

76:40

actually slightly confusing inside what

76:42

opening ey does here is that in addition

76:44

to this encoder and a decoder they also

76:46

have something called a bite encoder and

76:48

a bite decoder and this is actually

76:51

unfortunately just

76:53

kind of a spirous implementation detail

76:55

and isn't actually deep or interesting

76:57

in any way so I'm going to skip the

76:59

discussion of it but what opening ey

77:01

does here for reasons that I don't fully

77:02

understand is that not only have they

77:05

this tokenizer which can encode and

77:06

decode but they have a whole separate

77:08

layer here in addition that is used

77:10

serially with the tokenizer and so you

77:12

first do um bite encode and then encode

77:16

and then you do decode and then bite

77:17

decode so that's the loop and they are

77:20

just stacked serial on top of each other

77:22

and and it's not that interesting so I

77:24

won't cover it and you can step through

77:25

it if you'd like otherwise this file if

77:28

you ignore the bite encoder and the bite

77:30

decoder will be algorithmically very

77:31

familiar with you and the meat of it

77:33

here is the what they call bpe function

77:37

and you should recognize this Loop here

77:39

which is very similar to our own y Loop

77:41

where they're trying to identify the

77:43

Byram uh a pair that they should be

77:46

merging next and then here just like we

77:49

had they have a for Loop trying to merge

77:50

this pair uh so they will go over all of

77:53

the sequence and they will merge the

77:55

pair whenever they find it and they keep

77:57

repeating that until they run out of

77:59

possible merges in the in the text so

78:02

that's the meat of this file and uh

78:04

there's an encode and a decode function

78:06

just like we have implemented it so long

78:08

story short what I want you to take away

78:09

at this point is that unfortunately it's

78:11

a little bit of a messy code that they

78:13

have but algorithmically it is identical

78:15

to what we've built up above and what

78:17

we've built up above if you understand

78:19

it is algorithmically what is necessary

78:21

to actually build a BP to organizer

78:23

train it and then both encode and decode

78:26

the next topic I would like to turn to

78:28

is that of special tokens so in addition

78:30

to tokens that are coming from you know

78:32

raw bytes and the BP merges we can

78:35

insert all kinds of tokens that we are

78:36

going to use to delimit different parts

78:38

of the data or introduced to create a

78:41

special structure of the token streams

78:44

so in uh if you look at this encoder

78:47

object from open AIS gpd2 right here we

78:50

mentioned this is very similar to our

78:52

vocab you'll notice that the length of

78:54

this is

78:58

50257 and as I mentioned it's mapping uh

79:01

and it's inverted from the mapping of

79:03

our vocab our vocab goes from integer to

79:06

string and they go the other way around

79:08

for no amazing reason um but the thing

79:11

to note here is that this the mapping

79:13

table here is

79:15

50257 where does that number come from

79:18

where what are the tokens as I mentioned

79:20

there are 256 raw bite token

79:24

tokens and then opena actually did

79:27

50,000

79:28

merges so those become the other tokens

79:32

but this would have been

79:34

50256 so what is the 57th token and

79:37

there is basically one special

79:40

token and that one special token you can

79:43

see is called end of text so this is a

79:47

special token and it's the very last

79:49

token and this token is used to delimit

79:52

documents ments in the training set so

79:55

when we're creating the training data we

79:57

have all these documents and we tokenize

79:59

them and we get a stream of tokens those

80:01

tokens only range from Z to

80:05

50256 and then in between those

80:07

documents we put special end of text

80:10

token and we insert that token in

80:12

between documents and we are using this

80:15

as a signal to the language model that

80:18

the document has ended and what follows

80:20

is going to be unrelated to the document

80:23

previously that said the language model

80:25

has to learn this from data it it needs

80:27

to learn that this token usually means

80:29

that it should wipe its sort of memory

80:31

of what came before and what came before

80:34

this token is not actually informative

80:35

to what comes next but we are expecting

80:37

the language model to just like learn

80:39

this but we're giving it the Special

80:40

sort of the limiter of these documents

80:44

we can go here to Tech tokenizer and um

80:46

this the gpt2 tokenizer uh our code that

80:49

we've been playing with before so we can

80:51

add here right hello world world how are

80:53

you and we're getting different tokens

80:55

but now you can see what if what happens

80:58

if I put end of text you see how until I

81:02

finished it these are all different

81:03

tokens end of

81:06

text still set different tokens and now

81:08

when I finish it suddenly we get token

81:13

50256 and the reason this works is

81:15

because this didn't actually go through

81:18

the bpe merges instead the code that

81:21

actually outposted tokens has special

81:25

case instructions for handling special

81:28

tokens um we did not see these special

81:30

instructions for handling special tokens

81:32

in the encoder dopy it's absent there

81:36

but if you go to Tech token Library

81:38

which is uh implemented in Rust you will

81:40

find all kinds of special case handling

81:42

for these special tokens that you can

81:44

register uh create adds to the

81:47

vocabulary and then it looks for them

81:49

and it uh whenever it sees these special

81:50

tokens like this it will actually come

81:53

in and swap in that special token so

81:56

these things are outside of the typical

81:58

algorithm of uh B PA en

82:00

coding so these special tokens are used

82:02

pervasively uh not just in uh basically

82:05

base language modeling of predicting the

82:07

next token in the sequence but

82:09

especially when it gets to later to the

82:10

fine tuning stage and all of the chat uh

82:13

gbt sort of aspects of it uh because we

82:15

don't just want to Del limit documents

82:16

we want to delimit entire conversations

82:18

between an assistant and a user so if I

82:21

refresh this sck tokenizer page the

82:24

default example that they have here is

82:26

using not sort of base model encoders

82:30

but ftuned model uh sort of tokenizers

82:33

um so for example using the GPT 3.5

82:35

turbo scheme these here are all special

82:38

tokens I am start I end Etc uh this is

82:43

short for Imaginary mcore start by the

82:46

way but you can see here that there's a

82:49

sort of start and end of every single

82:51

message and there can be many other

82:52

other tokens lots of tokens um in use to

82:56

delimit these conversations and kind of

82:58

keep track of the flow of the messages

83:00

here now we can go back to the Tik token

83:03

library and here when you scroll to the

83:06

bottom they talk about how you can

83:08

extend tick token and I can you can

83:10

create basically you can Fork uh the um

83:13

CL 100K base tokenizers in gp4 and for

83:17

example you can extend it by adding more

83:18

special tokens and these are totally up

83:20

to you you can come up with any

83:21

arbitrary tokens and add them with the

83:23

new ID afterwards and the tikken library

83:26

will uh correctly swap them out uh when

83:29

it sees this in the

83:31

strings now we can also go back to this

83:34

file which we've looked at previously

83:37

and I mentioned that the gpt2 in Tik

83:39

toen open

83:41

I.P we have the vocabulary we have the

83:44

pattern for splitting and then here we

83:46

are registering the single special token

83:48

in gpd2 which was the end of text token

83:50

and we saw that it has this ID

83:53

in GPT 4 when they defy this here you

83:56

see that the pattern has changed as

83:57

we've discussed but also the special

83:59

tokens have changed in this tokenizer so

84:01

we of course have the end of text just

84:03

like in gpd2 but we also see three sorry

84:06

four additional tokens here Thim prefix

84:09

middle and suffix what is fim fim is

84:12

short for fill in the middle and if

84:14

you'd like to learn more about this idea

84:17

it comes from this paper um and I'm not

84:20

going to go into detail in this video

84:21

it's beyond this video and then there's

84:23

one additional uh serve token here so

84:27

that's that encoding as well so it's

84:29

very common basically to train a

84:31

language model and then if you'd like uh

84:34

you can add special tokens now when you

84:37

add special tokens you of course have to

84:39

um do some model surgery to the

84:41

Transformer and all the parameters

84:43

involved in that Transformer because you

84:45

are basically adding an integer and you

84:47

want to make sure that for example your

84:48

embedding Matrix for the vocabulary

84:50

tokens has to be extended by adding a

84:53

row and typically this row would be

84:54

initialized uh with small random numbers

84:56

or something like that because we need

84:58

to have a vector that now stands for

85:01

that token in addition to that you have

85:03

to go to the final layer of the

85:04

Transformer and you have to make sure

85:05

that that projection at the very end

85:07

into the classifier uh is extended by

85:09

one as well so basically there's some

85:11

model surgery involved that you have to

85:13

couple with the tokenization changes if

85:16

you are going to add special tokens but

85:18

this is a very common operation that

85:20

people do especially if they'd like to

85:21

fine tune the model for example taking

85:23

it from a base model to a chat model

85:26

like chat

85:27

GPT okay so at this point you should

85:29

have everything you need in order to

85:31

build your own gp4 tokenizer now in the

85:33

process of developing this lecture I've

85:35

done that and I published the code under

85:37

this repository

85:38

MBP so MBP looks like this right now as

85:42

I'm recording but uh the MBP repository

85:45

will probably change quite a bit because

85:46

I intend to continue working on it um in

85:49

addition to the MBP repository I've

85:51

published the this uh exercise

85:53

progression that you can follow so if

85:55

you go to exercise. MD here uh this is

85:58

sort of me breaking up the task ahead of

86:01

you into four steps that sort of uh

86:03

build up to what can be a gp4 tokenizer

86:06

and so feel free to follow these steps

86:08

exactly and follow a little bit of the

86:10

guidance that I've laid out here and

86:12

anytime you feel stuck just reference

86:14

the MBP repository here so either the

86:17

tests could be useful or the MBP

86:20

repository itself I try to keep the code

86:22

fairly clean and understandable and so

86:26

um feel free to reference it whenever um

86:28

you get

86:30

stuck uh in addition to that basically

86:32

once you write it you should be able to

86:34

reproduce this behavior from Tech token

86:36

so getting the gb4 tokenizer you can

86:39

take uh you can encode the string and

86:41

you should get these tokens and then you

86:43

can encode and decode the exact same

86:44

string to recover it and in addition to

86:47

all that you should be able to implement

86:48

your own train function uh which Tik

86:50

token Library does not provide it's it's

86:52

again only inference code but you could

86:54

write your own train MBP does it as well

86:57

and that will allow you to train your

86:59

own token

87:00

vocabularies so here are some of the

87:02

code inside M be mean bpe uh shows the

87:06

token vocabularies that you might obtain

87:08

so on the left uh here we have the GPT 4

87:12

merges uh so the first 256 are raw

87:15

individual bytes and then here I am

87:17

visualizing the merges that gp4

87:19

performed during its training so the

87:21

very first merge that gp4 did was merge

87:24

two spaces into a single token for you

87:27

know two spaces and that is a token 256

87:30

and so this is the order in which things

87:32

merged during gb4 training and this is

87:34

the merge order that um we obtain in MBP

87:39

by training a tokenizer and in this case

87:41

I trained it on a Wikipedia page of

87:43

Taylor Swift uh not because I'm a Swifty

87:45

but because that is one of the longest

87:47

um Wikipedia Pages apparently that's

87:49

available but she is pretty cool and

87:54

um what was I going to say yeah so you

87:56

can compare these two uh vocabularies

87:59

and so as an example um here GPT for

88:04

merged I in to become in and we've done

88:06

the exact same thing on this token 259

88:10

here space t becomes space t and that

88:13

happened for us a little bit later as

88:14

well so the difference here is again to

88:16

my understanding only a difference of

88:18

the training set so as an example

88:20

because I see a lot of white space I

88:22

supect that gp4 probably had a lot of

88:23

python code in its training set I'm not

88:25

sure uh for the

88:27

tokenizer and uh here we see much less

88:30

of that of course in the Wikipedia page

88:32

so roughly speaking they look the same

88:34

and they look the same because they're

88:35

running the same algorithm and when you

88:38

train your own you're probably going to

88:39

get something similar depending on what

88:41

you train it on okay so we are now going

88:43

to move on from tick token and the way

88:45

that open AI tokenizes its strings and

88:47

we're going to discuss one more very

88:49

commonly used library for working with

88:51

tokenization inlm

88:52

and that is sentence piece so sentence

88:55

piece is very commonly used in language

88:58

models because unlike Tik token it can

89:00

do both training and inference and is

89:02

quite efficient at both it supports a

89:04

number of algorithms for training uh

89:06

vocabularies but one of them is the B

89:09

pair en coding algorithm that we've been

89:10

looking at so it supports it now

89:13

sentence piece is used both by llama and

89:15

mistal series and many other models as

89:18

well it is on GitHub under Google

89:20

sentence piece

89:22

and the big difference with sentence

89:24

piece and we're going to look at example

89:26

because this is kind of hard and subtle

89:27

to explain is that they think different

89:31

about the order of operations here so in

89:35

the case of Tik token we first take our

89:38

code points in the string we encode them

89:41

using mutf to bytes and then we're

89:42

merging bytes it's fairly

89:44

straightforward for sentence piece um it

89:48

works directly on the level of the code

89:50

points themselves so so it looks at

89:52

whatever code points are available in

89:53

your training set and then it starts

89:55

merging those code points and um the bpe

89:59

is running on the level of code

90:01

points and if you happen to run out of

90:04

code points so there are maybe some rare

90:06

uh code points that just don't come up

90:08

too often and the Rarity is determined

90:09

by this character coverage hyper

90:11

parameter then these uh code points will

90:14

either get mapped to a special unknown

90:16

token like ank or if you have the bite

90:19

foldback option turned on then that will

90:22

take those rare Cod points it will

90:23

encode them using utf8 and then the

90:26

individual bytes of that encoding will

90:27

be translated into tokens and there are

90:30

these special bite tokens that basically

90:32

get added to the vocabulary so it uses

90:35

BP on on the code points and then it

90:38

falls back to bytes for rare Cod points

90:41

um and so that's kind of like difference

90:44

personally I find the Tik token we

90:45

significantly cleaner uh but it's kind

90:47

of like a subtle but pretty major

90:48

difference between the way they approach

90:50

tokenization let's work with with a

90:52

concrete example because otherwise this

90:54

is kind of hard to um to get your head

90:56

around so let's work with a concrete

90:59

example this is how we can import

91:01

sentence piece and then here we're going

91:03

to take I think I took like the

91:05

description of sentence piece and I just

91:06

created like a little toy data set it

91:08

really likes to have a file so I created

91:10

a toy. txt file with this

91:13

content now what's kind of a little bit

91:15

crazy about sentence piece is that

91:16

there's a ton of options and

91:18

configurations and the reason this is so

91:20

is because sentence piece has been

91:22

around I think for a while and it really

91:23

tries to handle a large diversity of

91:25

things and um because it's been around I

91:28

think it has quite a bit of accumulated

91:30

historical baggage uh as well and so in

91:33

particular there's like a ton of

91:35

configuration arguments this is not even

91:36

all of it you can go to here to see all

91:39

the training

91:40

options um and uh there's also quite

91:44

useful documentation when you look at

91:45

the raw Proto buff uh that is used to

91:48

represent the trainer spec and so on um

91:52

many of these options are irrelevant to

91:54

us so maybe to point out one example Das

91:56

Das shrinking Factor uh this shrinking

91:59

factor is not used in the B pair en

92:01

coding algorithm so this is just an

92:03

argument that is irrelevant to us um it

92:05

applies to a different training

92:09

algorithm now what I tried to do here is

92:11

I tried to set up sentence piece in a

92:13

way that is very very similar as far as

92:15

I can tell to maybe identical hopefully

92:18

to the way that llama 2 was strained so

92:22

the way they trained their own um their

92:25

own tokenizer and the way I did this was

92:27

basically you can take the tokenizer

92:28

model file that meta released and you

92:31

can um open it using the Proto protuff

92:35

uh sort of file that you can generate

92:38

and then you can inspect all the options

92:39

and I tried to copy over all the options

92:41

that looked relevant so here we set up

92:43

the input it's raw text in this file

92:46

here's going to be the output so it's

92:48

going to be for talk 400. model and

92:50

vocab

92:52

we're saying that we're going to use the

92:53

BP algorithm and we want to Bap size of

92:56

400 then there's a ton of configurations

92:58

here

93:01

for um for basically pre-processing and

93:05

normalization rules as they're called

93:07

normalization used to be very prevalent

93:09

I would say before llms in natural

93:11

language processing so in machine

93:12

translation and uh text classification

93:14

and so on you want to normalize and

93:16

simplify the text and you want to turn

93:18

it all lowercase and you want to remove

93:19

all double whites space Etc

93:22

and in language models we prefer not to

93:23

do any of it or at least that is my

93:25

preference as a deep learning person you

93:26

want to not touch your data you want to

93:28

keep the raw data as much as possible um

93:31

in a raw

93:33

form so you're basically trying to turn

93:35

off a lot of this if you can the other

93:38

thing that sentence piece does is that

93:39

it has this concept of sentences so

93:43

sentence piece it's back it's kind of

93:45

like was developed I think early in the

93:46

days where there was um an idea that

93:50

they you're training a tokenizer on a

93:51

bunch of independent sentences so it has

93:54

a lot of like how many sentences you're

93:56

going to train on what is the maximum

93:58

sentence length

94:00

um shuffling sentences and so for it

94:03

sentences are kind of like the

94:04

individual training examples but again

94:06

in the context of llms I find that this

94:08

is like a very spous and weird

94:10

distinction like sentences are just like

94:13

don't touch the raw data sentences

94:15

happen to exist but in raw data sets

94:18

there are a lot of like inet like what

94:20

exactly is a sentence what isn't a

94:22

sentence um and so I think like it's

94:25

really hard to Define what an actual

94:26

sentence is if you really like dig into

94:28

it and there could be different concepts

94:30

of it in different languages or

94:32

something like that so why even

94:33

introduce the concept it it doesn't

94:35

honestly make sense to me I would just

94:36

prefer to treat a file as a giant uh

94:39

stream of

94:40

bytes it has a lot of treatment around

94:42

rare word characters and when I say word

94:45

I mean code points we're going to come

94:46

back to this in a second and it has a

94:48

lot of other rules for um basically

94:51

splitting digits splitting white space

94:54

and numbers and how you deal with that

94:56

so these are some kind of like merge

94:58

rules so I think this is a little bit

95:00

equivalent to tick token using the

95:02

regular expression to split up

95:04

categories there's like kind of

95:07

equivalence of it if you squint T it in

95:09

sentence piece where you can also for

95:10

example split up split up the digits uh

95:14

and uh so

95:15

on there's a few more things here that

95:18

I'll come back to in a bit and then

95:19

there are some special tokens that you

95:20

can indicate and it hardcodes the UN

95:23

token the beginning of sentence end of

95:25

sentence and a pad token um and the UN

95:29

token must exist for my understanding

95:32

and then some some things so we can

95:34

train and when when I press train it's

95:37

going to create this file talk 400.

95:40

model and talk 400. wab I can then load

95:43

the model file and I can inspect the

95:45

vocabulary off it and so we trained

95:48

vocab size 400 on this text here and

95:53

these are the individual pieces the

95:55

individual tokens that sentence piece

95:56

will create so in the beginning we see

95:58

that we have the an token uh with the ID

96:02

zero then we have the beginning of

96:04

sequence end of sequence one and two and

96:07

then we said that the pad ID is negative

96:09

1 so we chose not to use it so there's

96:12

no pad ID

96:13

here then these are individual bite

96:16

tokens so here we saw that bite fallback

96:20

in llama was turned on so it's true so

96:23

what follows are going to be the 256

96:26

bite

96:27

tokens and these are their

96:31

IDs and then at the bottom after the

96:35

bite tokens come the

96:37

merges and these are the parent nodes in

96:40

the merges so we're not seeing the

96:42

children we're just seeing the parents

96:43

and their

96:44

ID and then after the

96:47

merges comes eventually the individual

96:50

tokens and their IDs and so these are

96:53

the individual tokens so these are the

96:55

individual code Point tokens if you will

96:58

and they come at the end so that is the

97:00

ordering with which sentence piece sort

97:01

of like represents its vocabularies it

97:03

starts with special tokens then the bike

97:06

tokens then the merge tokens and then

97:08

the individual codo tokens and all these

97:11

raw codepoint to tokens are the ones

97:14

that it encountered in the training

97:16

set so those individual code points are

97:19

all the the entire set of code points

97:22

that occurred

97:24

here so those all get put in there and

97:27

then those that are extremely rare as

97:29

determined by character coverage so if a

97:31

code Point occurred only a single time

97:32

out of like a million um sentences or

97:35

something like that then it would be

97:37

ignored and it would not be added to our

97:40

uh

97:41

vocabulary once we have a vocabulary we

97:43

can encode into IDs and we can um sort

97:46

of get a

97:47

list and then here I am also decoding

97:50

the indiv idual tokens back into little

97:54

pieces as they call it so let's take a

97:56

look at what happened here hello space

98:01

on so these are the token IDs we got

98:04

back and when we look here uh a few

98:07

things sort of uh jump to mind number

98:11

one take a look at these characters the

98:14

Korean characters of course were not

98:15

part of the training set so sentence

98:18

piece is encountering code points that

98:19

it has not seen during training time and

98:22

those code points do not have a token

98:24

associated with them so suddenly these

98:26

are un tokens unknown tokens but because

98:30

bite fall back as true instead sentence

98:33

piece falls back to bytes and so it

98:36

takes this it encodes it with utf8 and

98:39

then it uses these tokens to represent

98:43

uh those bytes and that's what we are

98:45

getting sort of here this is the utf8 uh

98:49

encoding and in this shifted by three uh

98:52

because of these um special tokens here

98:56

that have IDs earlier on so that's what

98:58

happened here now one more thing that um

99:02

well first before I go on with respect

99:05

to the bitef back let me remove bite

99:08

foldback if this is false what's going

99:10

to happen let's

99:12

retrain so the first thing that happened

99:14

is all the bite tokens disappeared right

99:17

and now we just have the merges and we

99:19

have a lot more merges now because we

99:20

have a lot more space because we're not

99:21

taking up space in the wab size uh with

99:25

all the

99:25

bytes and now if we encode

99:29

this we get a zero so this entire string

99:33

here suddenly there's no bitef back so

99:35

this is unknown and unknown is an and so

99:39

this is zero because the an token is

99:42

token zero and you have to keep in mind

99:44

that this would feed into your uh

99:46

language model so what is a language

99:48

model supposed to do when all kinds of

99:49

different things that are unrecognized

99:52

because they're rare just end up mapping

99:54

into Unk it's not exactly the property

99:56

that you want so that's why I think

99:57

llama correctly uh used by fallback true

100:02

uh because we definitely want to feed

100:03

these um unknown or rare code points

100:06

into the model and some uh some manner

100:08

the next thing I want to show you is the

100:10

following notice here when we are

100:12

decoding all the individual tokens you

100:14

see how spaces uh space here ends up

100:18

being this um bold underline I'm not

100:21

100% sure by the way why sentence piece

100:23

switches whites space into these bold

100:25

underscore characters maybe it's for

100:27

visualization I'm not 100% sure why that

100:29

happens uh but notice this why do we

100:32

have an extra space in the front of

100:37

hello um what where is this coming from

100:40

well it's coming from this option

100:43

here

100:45

um add dummy prefix is true and when you

100:48

go to the

100:49

documentation add D whites space at the

100:51

beginning of text in order to treat

100:53

World in world and hello world in the

100:55

exact same way so what this is trying to

100:57

do is the

100:59

following if we go back to our tick

101:02

tokenizer world as uh token by itself

101:06

has a different ID than space world so

101:10

we have this is 1917 but this is 14 Etc

101:14

so these are two different tokens for

101:16

the language model and the language

101:17

model has to learn from data that they

101:18

are actually kind of like a very similar

101:20

concept so to the language model in the

101:23

Tik token World um basically words in

101:26

the beginning of sentences and words in

101:27

the middle of sentences actually look

101:29

completely different um and it has to

101:32

learned that they are roughly the same

101:34

so this add dami prefix is trying to

101:36

fight that a little bit and the way that

101:38

works is that it basically

101:41

uh adds a dummy prefix so for as a as a

101:46

part of pre-processing it will take the

101:49

string and it will add a space it will

101:51

do this and that's done in an effort to

101:54

make this world and that world the same

101:57

they will both be space world so that's

102:00

one other kind of pre-processing option

102:02

that is turned on and llama 2 also uh

102:05

uses this option and that's I think

102:07

everything that I want to say for my

102:08

preview of sentence piece and how it is

102:10

different um maybe here what I've done

102:13

is I just uh put in the Raw protocol

102:16

buffer representation basically of the

102:19

tokenizer the too trained so feel free

102:22

to sort of Step through this and if you

102:24

would like uh your tokenization to look

102:27

identical to that of the meta uh llama 2

102:30

then you would be copy pasting these

102:31

settings as I tried to do up above and

102:34

uh yeah that's I think that's it for

102:36

this section I think my summary for

102:38

sentence piece from all of this is

102:40

number one I think that there's a lot of

102:42

historical baggage in sentence piece a

102:44

lot of Concepts that I think are

102:45

slightly confusing and I think

102:47

potentially um contain foot guns like

102:49

this concept of a sentence and it's

102:50

maximum length and stuff like that um

102:53

otherwise it is fairly commonly used in

102:55

the industry um because it is efficient

102:58

and can do both training and inference

103:01

uh it has a few quirks like for example

103:02

un token must exist and the way the bite

103:05

fallbacks are done and so on I don't

103:06

find particularly elegant and

103:08

unfortunately I have to say it's not

103:09

very well documented so it took me a lot

103:11

of time working with this myself um and

103:14

just visualizing things and trying to

103:16

really understand what is happening here

103:17

because uh the documentation

103:19

unfortunately is in my opion not not

103:21

super amazing but it is a very nice repo

103:24

that is available to you if you'd like

103:26

to train your own tokenizer right now

103:28

okay let me now switch gears again as

103:29

we're starting to slowly wrap up here I

103:31

want to revisit this issue in a bit more

103:33

detail of how we should set the vocap

103:35

size and what are some of the

103:36

considerations around it so for this I'd

103:39

like to go back to the model

103:40

architecture that we developed in the

103:42

last video when we built the GPT from

103:44

scratch so this here was uh the file

103:47

that we built in the previous video and

103:49

we defined the Transformer model and and

103:51

let's specifically look at Bap size and

103:52

where it appears in this file so here we

103:55

Define the voap size uh at this time it

103:58

was 65 or something like that extremely

103:59

small number so this will grow much

104:02

larger you'll see that Bap size doesn't

104:04

come up too much in most of these layers

104:06

the only place that it comes up to is in

104:08

exactly these two places here so when we

104:11

Define the language model there's the

104:13

token embedding table which is this

104:15

two-dimensional array where the vocap

104:18

size is basically the number of rows and

104:21

uh each vocabulary element each token

104:23

has a vector that we're going to train

104:25

using back propagation that Vector is of

104:27

size and embed which is number of

104:29

channels in the Transformer and

104:31

basically as voap size increases this

104:33

embedding table as I mentioned earlier

104:35

is going to also grow we're going to be

104:37

adding rows in addition to that at the

104:39

end of the Transformer there's this LM

104:41

head layer which is a linear layer and

104:44

you'll notice that that layer is used at

104:46

the very end to produce the logits uh

104:48

which become the probabilities for the

104:49

next token in sequence and so

104:51

intuitively we're trying to produce a

104:53

probability for every single token that

104:56

might come next at every point in time

104:58

of that Transformer and if we have more

105:01

and more tokens we need to produce more

105:02

and more probabilities so every single

105:04

token is going to introduce an

105:06

additional dot product that we have to

105:08

do here in this linear layer for this

105:10

final layer in a

105:11

Transformer so why can't vocap size be

105:14

infinite why can't we grow to Infinity

105:16

well number one your token embedding

105:18

table is going to grow uh your linear

105:21

layer is going to grow so we're going to

105:23

be doing a lot more computation here

105:25

because this LM head layer will become

105:26

more computational expensive number two

105:29

because we have more parameters we could

105:30

be worried that we are going to be under

105:33

trining some of these

105:35

parameters so intuitively if you have a

105:37

very large vocabulary size say we have a

105:38

million uh tokens then every one of

105:41

these tokens is going to come up more

105:42

and more rarely in the training data

105:45

because there's a lot more other tokens

105:46

all over the place and so we're going to

105:48

be seeing fewer and fewer examples uh

105:51

for each individual token and you might

105:53

be worried that basically the vectors

105:55

associated with every token will be

105:56

undertrained as a result because they

105:58

just don't come up too often and they

105:59

don't participate in the forward

106:00

backward pass in addition to that as

106:03

your vocab size grows you're going to

106:04

start shrinking your sequences a lot

106:07

right and that's really nice because

106:09

that means that we're going to be

106:10

attending to more and more text so

106:12

that's nice but also you might be

106:13

worrying that two large of chunks are

106:15

being squished into single tokens and so

106:18

the model just doesn't have as much of

106:20

time to think per sort of um some number

106:25

of characters in the text or you can

106:26

think about it that way right so

106:28

basically we're squishing too much

106:29

information into a single token and then

106:31

the forward pass of the Transformer is

106:33

not enough to actually process that

106:34

information appropriately and so these

106:36

are some of the considerations you're

106:37

thinking about when you're designing the

106:38

vocab size as I mentioned this is mostly

106:40

an empirical hyperparameter and it seems

106:42

like in state-of-the-art architectures

106:44

today this is usually in the high 10,000

106:46

or somewhere around 100,000 today and

106:49

the next consideration I want to briefly

106:50

talk about is what if we want to take a

106:53

pre-trained model and we want to extend

106:55

the vocap size and this is done fairly

106:57

commonly actually so for example when

106:58

you're doing fine-tuning for cha GPT um

107:02

a lot more new special tokens get

107:03

introduced on top of the base model to

107:05

maintain the metadata and all the

107:08

structure of conversation objects

107:09

between a user and an assistant so that

107:11

takes a lot of special tokens you might

107:14

also try to throw in more special tokens

107:15

for example for using the browser or any

107:17

other tool and so it's very tempting to

107:20

add a lot of tokens for all kinds of

107:22

special functionality so if you want to

107:24

be adding a token that's totally

107:25

possible Right all we have to do is we

107:27

have to resize this embedding so we have

107:29

to add rows we would initialize these uh

107:32

parameters from scratch to be small

107:34

random numbers and then we have to

107:36

extend the weight inside this linear uh

107:39

so we have to start making dot products

107:41

um with the associated parameters as

107:43

well to basically calculate the

107:44

probabilities for these new tokens so

107:46

both of these are just a resizing

107:48

operation it's a very mild

107:50

model surgery and can be done fairly

107:52

easily and it's quite common that

107:54

basically you would freeze the base

107:55

model you introduce these new parameters

107:57

and then you only train these new

107:58

parameters to introduce new tokens into

108:00

the architecture um and so you can

108:03

freeze arbitrary parts of it or you can

108:04

train arbitrary parts of it and that's

108:06

totally up to you but basically minor

108:08

surgery required if you'd like to

108:10

introduce new tokens and finally I'd

108:11

like to mention that actually there's an

108:13

entire design space of applications in

108:15

terms of introducing new tokens into a

108:17

vocabulary that go Way Beyond just

108:19

adding special tokens and special new

108:21

functionality so just to give you a

108:23

sense of the design space but this could

108:24

be an entire video just by itself uh

108:26

this is a paper on learning to compress

108:28

prompts with what they called uh gist

108:31

tokens and the rough idea is suppose

108:33

that you're using language models in a

108:34

setting that requires very long prompts

108:37

while these long prompts just slow

108:38

everything down because you have to

108:39

encode them and then you have to use

108:41

them and then you're tending over them

108:43

and it's just um you know heavy to have

108:45

very large prompts so instead what they

108:47

do here in this paper is they introduce

108:50

new tokens and um imagine basically

108:54

having a few new tokens you put them in

108:56

a sequence and then you train the model

108:59

by distillation so you are keeping the

109:01

entire model Frozen and you're only

109:03

training the representations of the new

109:05

tokens their embeddings and you're

109:06

optimizing over the new tokens such that

109:09

the behavior of the language model is

109:11

identical uh to the model that has a

109:15

very long prompt that works for you and

109:17

so it's a compression technique of

109:19

compressing that very long prompt into

109:20

those few new gist tokens and so you can

109:23

train this and then at test time you can

109:25

discard your old prompt and just swap in

109:26

those tokens and they sort of like uh

109:28

stand in for that very long prompt and

109:31

have an almost identical performance and

109:33

so this is one um technique and a class

109:36

of parameter efficient fine-tuning

109:38

techniques where most of the model is

109:39

basically fixed and there's no training

109:41

of the model weights there's no training

109:43

of Laura or anything like that of new

109:45

parameters the the parameters that

109:47

you're training are now just the uh

109:49

token embeddings so that's just one

109:51

example but this could again be like an

109:52

entire video but just to give you a

109:54

sense that there's a whole design space

109:55

here that is potentially worth exploring

109:57

in the future the next thing I want to

109:59

briefly address is that I think recently

110:01

there's a lot of momentum in how you

110:03

actually could construct Transformers

110:05

that can simultaneously process not just

110:06

text as the input modality but a lot of

110:08

other modalities so be it images videos

110:11

audio Etc and how do you feed in all

110:14

these modalities and potentially predict

110:16

these modalities from a Transformer uh

110:18

do you have to change the architecture

110:19

in some fundamental way and I think what

110:21

a lot of people are starting to converge

110:23

towards is that you're not changing the

110:24

architecture you stick with the

110:25

Transformer you just kind of tokenize

110:27

your input domains and then call the day

110:29

and pretend it's just text tokens and

110:31

just do everything else identical in an

110:33

identical manner so here for example

110:36

there was a early paper that has nice

110:37

graphic for how you can take an image

110:39

and you can chunc at it into

110:42

integers um and these sometimes uh so

110:45

these will basically become the tokens

110:46

of images as an example and uh these

110:49

tokens can be uh hard tokens where you

110:52

force them to be integers they can also

110:53

be soft tokens where you uh sort of

110:57

don't require uh these to be discrete

111:00

but you do Force these representations

111:02

to go through bottlenecks like in Auto

111:04

encoders uh also in this paper that came

111:06

out from open a SORA which I think

111:08

really um uh blew the mind of many

111:11

people and inspired a lot of people in

111:13

terms of what's possible they have a

111:15

Graphic here and they talk briefly about

111:16

how llms have text tokens Sora has

111:20

visual patches so again they came up

111:22

with a way to chunc a videos into

111:24

basically tokens when they own

111:26

vocabularies and then you can either

111:28

process discrete tokens say with autog

111:30

regressive models or even soft tokens

111:32

with diffusion models and uh all of that

111:35

is sort of uh being actively worked on

111:38

designed on and is beyond the scope of

111:39

this video but just something I wanted

111:40

to mention briefly okay now that we have

111:42

come quite deep into the tokenization

111:45

algorithm and we understand a lot more

111:46

about how it works let's loop back

111:48

around to the beginning of this video

111:50

and go through some of these bullet

111:51

points and really see why they happen so

111:54

first of all why can't my llm spell

111:56

words very well or do other spell

111:58

related

112:00

tasks so fundamentally this is because

112:02

as we saw these characters are chunked

112:05

up into tokens and some of these tokens

112:07

are actually fairly long so as an

112:10

example I went to the gp4 vocabulary and

112:12

I looked at uh one of the longer tokens

112:15

so that default style turns out to be a

112:17

single individual token so that's a lot

112:19

of characters for a single token so my

112:22

suspicion is that there's just too much

112:23

crammed into this single token and my

112:26

suspicion was that the model should not

112:27

be very good at tasks related to

112:30

spelling of this uh single token so I

112:34

asked how many letters L are there in

112:37

the word default style and of course my

112:41

prompt is intentionally done that way

112:44

and you see how default style will be a

112:45

single token so this is what the model

112:47

sees so my suspicion is that it wouldn't

112:49

be very good at this and indeed it is

112:51

not it doesn't actually know how many

112:53

L's are in there it thinks there are

112:54

three and actually there are four if I'm

112:57

not getting this wrong myself so that

112:59

didn't go extremely well let's look look

113:02

at another kind of uh character level

113:04

task so for example here I asked uh gp4

113:08

to reverse the string default style and

113:11

they tried to use a code interpreter and

113:13

I stopped it and I said just do it just

113:15

try it and uh it gave me jumble so it

113:19

doesn't actually really know how to

113:21

reverse this string going from right to

113:23

left uh so it gave a wrong result so

113:26

again like working with this working

113:28

hypothesis that maybe this is due to the

113:30

tokenization I tried a different

113:31

approach I said okay let's reverse the

113:34

exact same string but take the following

113:36

approach step one just print out every

113:38

single character separated by spaces and

113:40

then as a step two reverse that list and

113:43

it again Tred to use a tool but when I

113:44

stopped it it uh first uh produced all

113:47

the characters and that was actually

113:48

correct and then It reversed them and

113:50

that was correct once it had this so

113:53

somehow it can't reverse it directly but

113:54

when you go just first uh you know

113:57

listing it out in order it can do that

113:59

somehow and then it can once it's uh

114:01

broken up this way this becomes all

114:03

these individual characters and so now

114:06

this is much easier for it to see these

114:07

individual tokens and reverse them and

114:10

print them out so that is kind of

114:13

interesting so let's continue now why

114:16

are llms worse at uh non-english langu

114:20

and I briefly covered this already but

114:22

basically um it's not only that the

114:24

language model sees less non-english

114:27

data during training of the model

114:28

parameters but also the tokenizer is not

114:31

um is not sufficiently trained on

114:34

non-english data and so here for example

114:37

hello how are you is five tokens and its

114:40

translation is 15 tokens so this is a

114:42

three times blow up and so for example

114:45

anang is uh just hello basically in

114:48

Korean and that end up being three

114:50

tokens I'm actually kind of surprised by

114:51

that because that is a very common

114:53

phrase there just the typical greeting

114:55

of like hello and that ends up being

114:57

three tokens whereas our hello is a

114:58

single token and so basically everything

115:00

is a lot more bloated and diffuse and

115:02

this is I think partly the reason that

115:04

the model Works worse on other

115:07

languages uh coming back why is LM bad

115:10

at simple arithmetic um that has to do

115:13

with the tokenization of numbers and so

115:17

um you'll notice that for example

115:19

addition is very sort of

115:20

like uh there's an algorithm that is

115:23

like character level for doing addition

115:25

so for example here we would first add

115:27

the ones and then the tens and then the

115:29

hundreds you have to refer to specific

115:31

parts of these digits but uh these

115:34

numbers are represented completely

115:36

arbitrarily based on whatever happened

115:37

to merge or not merge during the

115:39

tokenization process there's an entire

115:41

blog post about this that I think is

115:42

quite good integer tokenization is

115:44

insane and this person basically

115:46

systematically explores the tokenization

115:48

of numbers in I believe this is gpt2 and

115:52

so they notice that for example for the

115:53

for um four-digit numbers you can take a

115:57

look at whether it is uh a single token

116:00

or whether it is two tokens that is a 1

116:02

three or a 2 two or a 31 combination and

116:04

so all the different numbers are all the

116:06

different combinations and you can

116:08

imagine this is all completely

116:09

arbitrarily so and the model

116:11

unfortunately sometimes sees uh four um

116:14

a token for for all four digits

116:16

sometimes for three sometimes for two

116:18

sometimes for one and it's in an

116:20

arbitrary uh Manner and so this is

116:22

definitely a headwind if you will for

116:25

the language model and it's kind of

116:26

incredible that it can kind of do it and

116:27

deal with it but it's also kind of not

116:30

ideal and so that's why for example we

116:32

saw that meta when they train the Llama

116:34

2 algorithm and they use sentence piece

116:36

they make sure to split up all the um

116:39

all the digits as an example for uh

116:42

llama 2 and this is partly to improve a

116:44

simple arithmetic kind of

116:46

performance and finally why is gpt2 not

116:50

as good in Python again this is partly a

116:52

modeling issue on in the architecture

116:54

and the data set and the strength of the

116:56

model but it's also partially

116:58

tokenization because as we saw here with

117:00

the simple python example the encoding

117:03

efficiency of the tokenizer for handling

117:05

spaces in Python is terrible and every

117:07

single space is an individual token and

117:09

this dramatically reduces the context

117:11

length that the model can attend to

117:12

cross so that's almost like a

117:14

tokenization bug for gpd2 and that was

117:16

later fixed with gp4 okay so here's

117:20

another fun one my llm abruptly halts

117:22

when it sees the string end of text so

117:25

here's um here's a very strange Behavior

117:28

print a string end of text is what I

117:30

told jt4 and it says could you please

117:32

specify the string and I'm I'm telling

117:35

it give me end of text and it seems like

117:37

there's an issue it's not seeing end of

117:39

text and then I give it end of text is

117:41

the string and then here's a string and

117:44

then it just doesn't print it so

117:45

obviously something is breaking here

117:47

with respect to the handling of the

117:48

special token and I don't actually know

117:50

what open ey is doing under the hood

117:52

here and whether they are potentially

117:54

parsing this as an um as an actual token

117:58

instead of this just being uh end of

118:01

text um as like individual sort of

118:04

pieces of it without the special token

118:06

handling logic and so it might be that

118:09

someone when they're calling do encode

118:11

uh they are passing in the allowed

118:13

special and they are allowing end of

118:16

text as a special character in the user

118:18

prompt but the user prompt of course is

118:20

is a sort of um attacker controlled text

118:23

so you would hope that they don't really

118:25

parse or use special tokens or you know

118:28

from that kind of input but it appears

118:30

that there's something definitely going

118:31

wrong here and um so your knowledge of

118:34

these special tokens ends up being in a

118:36

tax surface potentially and so if you'd

118:38

like to confuse llms then just um try to

118:43

give them some special tokens and see if

118:44

you're breaking something by chance okay

118:46

so this next one is a really fun one uh

118:49

the trailing whites space issue so if

118:52

you come to playground and uh we come

118:56

here to GPT 3.5 turbo instruct so this

118:58

is not a chat model this is a completion

119:00

model so think of it more like it's a

119:02

lot more closer to a base model it does

119:05

completion it will continue the token

119:07

sequence so here's a tagline for ice

119:09

cream shop and we want to continue the

119:11

sequence and so we can submit and get a

119:14

bunch of tokens okay no problem but now

119:18

suppose I do this but instead of

119:20

pressing submit here I do here's a

119:23

tagline for ice cream shop space so I

119:26

have a space here before I click

119:28

submit we get a warning your text ends

119:31

in a trail Ling space which causes worse

119:33

performance due to how API splits text

119:35

into tokens so what's happening here it

119:38

still gave us a uh sort of completion

119:40

here but let's take a look at what's

119:42

happening so here's a tagline for an ice

119:44

cream shop and then what does this look

119:48

like in the actual actual training data

119:50

suppose you found the completion in the

119:52

training document somewhere on the

119:53

internet and the llm trained on this

119:55

data so maybe it's something like oh

119:58

yeah maybe that's the tagline that's a

120:00

terrible tagline but notice here that

120:02

when I create o you see that because

120:05

there's the the space character is

120:07

always a prefix to these tokens in GPT

120:11

so it's not an O token it's a space o

120:13

token the space is part of the O and

120:16

together they are token 8840 that's

120:19

that's space o so what's What's

120:21

Happening Here is that when I just have

120:24

it like this and I let it complete the

120:27

next token it can sample the space o

120:30

token but instead if I have this and I

120:32

add my space then what I'm doing here

120:34

when I incode this string is I have

120:37

basically here's a t line for an ice

120:39

cream uh shop and this space at the very

120:42

end becomes a token

120:44

220 and so we've added token 220 and

120:47

this token otherwise would be part of

120:49

the tagline because if there actually is

120:51

a tagline here so space o is the token

120:55

and so this is suddenly a of

120:57

distribution for the model because this

120:59

space is part of the next token but

121:01

we're putting it here like this and the

121:04

model has seen very very little data of

121:07

actual Space by itself and we're asking

121:10

it to complete the sequence like add in

121:11

more tokens but the problem is that

121:13

we've sort of begun the first token and

121:16

now it's been split up and now we're out

121:18

of this distribution and now arbitrary

121:20

bad things happen and it's just a very

121:23

rare example for it to see something

121:24

like that and uh that's why we get the

121:26

warning so the fundamental issue here is

121:29

of course that um the llm is on top of

121:32

these tokens and these tokens are text

121:34

chunks they're not characters in a way

121:36

you and I would think of them they are

121:38

these are the atoms of what the LM is

121:40

seeing and there's a bunch of weird

121:41

stuff that comes out of it let's go back

121:43

to our default cell style I bet you that

121:48

the model has never in its training set

121:49

seen default cell sta without Le in

121:54

there it's always seen this as a single

121:56

group because uh this is some kind of a

121:59

function in um I'm guess I don't

122:02

actually know what this is part of this

122:03

is some kind of API but I bet you that

122:05

it's never seen this combination of

122:07

tokens uh in its training data because

122:10

or I think it would be extremely rare so

122:12

I took this and I copy pasted it here

122:14

and I had I tried to complete from it

122:17

and the it immediately gave me a big

122:19

error and it said the model predicted to

122:21

completion that begins with a stop

122:22

sequence resulting in no output consider

122:24

adjusting your prompt or stop sequences

122:26

so what happened here when I clicked

122:27

submit is that immediately the model

122:30

emitted and sort of like end of text

122:32

token I think or something like that it

122:34

basically predicted the stop sequence

122:36

immediately so it had no completion and

122:38

so this is why I'm getting a warning

122:40

again because we're off the data

122:42

distribution and the model is just uh

122:45

predicting just totally arbitrary things

122:47

it's just really confused basically this

122:49

is uh this is giving it brain damage

122:50

it's never seen this before it's shocked

122:53

and it's predicting end of text or

122:54

something I tried it again here and it

122:57

in this case it completed it but then

122:59

for some reason this request May violate

123:01

our usage policies this was

123:03

flagged um basically something just like

123:06

goes wrong and there's something like

123:07

Jank you can just feel the Jank because

123:09

the model is like extremely unhappy with

123:11

just this and it doesn't know how to

123:12

complete it because it's never occurred

123:14

in training set in a training set it

123:16

always appears like this and becomes a

123:18

single token

123:20

so these kinds of issues where tokens

123:21

are either you sort of like complete the

123:24

first character of the next token or you

123:26

are sort of you have long tokens that

123:28

you then have just some of the

123:29

characters off all of these are kind of

123:32

like issues with partial tokens is how I

123:35

would describe it and if you actually

123:37

dig into the T token

123:39

repository go to the rust code and

123:41

search for

123:44

unstable and you'll see um en code

123:47

unstable native unstable token tokens

123:49

and a lot of like special case handling

123:51

none of this stuff about unstable tokens

123:53

is documented anywhere but there's a ton

123:55

of code dealing with unstable tokens and

123:58

unstable tokens is exactly kind of like

124:00

what I'm describing here what you would

124:02

like out of a completion API is

124:05

something a lot more fancy like if we're

124:06

putting in default cell sta if we're

124:08

asking for the next token sequence we're

124:10

not actually trying to append the next

124:12

token exactly after this list we're

124:14

actually trying to append we're trying

124:16

to consider lots of tokens um

124:19

that if we were or I guess like we're

124:22

trying to search over characters that if

124:25

we retened would be of high probability

124:28

if that makes sense um so that we can

124:30

actually add a single individual

124:32

character uh instead of just like adding

124:34

the next full token that comes after

124:36

this partial token list so I this is

124:39

very tricky to describe and I invite you

124:41

to maybe like look through this it ends

124:43

up being extremely gnarly and hairy kind

124:44

of topic it and it comes from

124:46

tokenization fundamentally so um maybe I

124:49

can even spend an entire video talking

124:50

about unstable tokens sometime in the

124:52

future okay and I'm really saving the

124:54

best for last my favorite one by far is

124:56

the solid gold

124:59

Magikarp and it just okay so this comes

125:01

from this blog post uh solid gold

125:03

Magikarp and uh this is um internet

125:07

famous now for those of us in llms and

125:10

basically I I would advise you to uh

125:11

read this block Post in full but

125:13

basically what this person was doing is

125:16

this person went to the um

125:19

token embedding stable and clustered the

125:22

tokens based on their embedding

125:24

representation and this person noticed

125:27

that there's a cluster of tokens that

125:29

look really strange so there's a cluster

125:31

here at rot e stream Fame solid gold

125:34

Magikarp Signet message like really

125:36

weird tokens in uh basically in this

125:39

embedding cluster and so what are these

125:42

tokens and where do they even come from

125:43

like what is solid gold magikarpet makes

125:45

no sense and then they found bunch of

125:48

these

125:50

tokens and then they notice that

125:52

actually the plot thickens here because

125:53

if you ask the model about these tokens

125:56

like you ask it uh some very benign

125:58

question like please can you repeat back

126:00

to me the string sold gold Magikarp uh

126:02

then you get a variety of basically

126:04

totally broken llm Behavior so either

126:07

you get evasion so I'm sorry I can't

126:09

hear you or you get a bunch of

126:11

hallucinations as a response um you can

126:14

even get back like insults so you ask it

126:17

uh about streamer bot it uh tells the

126:20

and the model actually just calls you

126:22

names uh or it kind of comes up with

126:24

like weird humor like you're actually

126:26

breaking the model by asking about these

126:28

very simple strings like at Roth and

126:30

sold gold Magikarp so like what the hell

126:32

is happening and there's a variety of

126:34

here documented behaviors uh there's a

126:37

bunch of tokens not just so good

126:38

Magikarp that have that kind of a

126:40

behavior and so basically there's a

126:42

bunch of like trigger words and if you

126:44

ask the model about these trigger words

126:46

or you just include them in your prompt

126:48

the model goes haywire and has all kinds

126:50

of uh really Strange Behaviors including

126:52

sort of ones that violate typical safety

126:54

guidelines uh and the alignment of the

126:57

model like it's swearing back at you so

126:59

what is happening here and how can this

127:01

possibly be true well this again comes

127:04

down to tokenization so what's happening

127:06

here is that sold gold Magikarp if you

127:08

actually dig into it is a Reddit user so

127:11

there's a u Sol gold

127:14

Magikarp and probably what happened here

127:16

even though I I don't know that this has

127:18

been like really definitively explored

127:20

but what is thought to have happened is

127:23

that the tokenization data set was very

127:25

different from the training data set for

127:28

the actual language model so in the

127:29

tokenization data set there was a ton of

127:31

redded data potentially where the user

127:34

solid gold Magikarp was mentioned in the

127:36

text because solid gold Magikarp was a

127:39

very common um sort of uh person who

127:41

would post a lot uh this would be a

127:43

string that occurs many times in a

127:45

tokenization data set because it occurs

127:48

many times in a tokenization data set

127:50

these tokens would end up getting merged

127:51

to the single individual token for that

127:53

single Reddit user sold gold Magikarp so

127:56

they would have a dedicated token in a

127:58

vocabulary of was it 50,000 tokens in

128:00

gpd2 that is devoted to that Reddit user

128:04

and then what happens is the

128:05

tokenization data set has those strings

128:08

but then later when you train the model

128:10

the language model itself um this data

128:13

from Reddit was not present and so

128:16

therefore in the entire training set for

128:18

the language model sold gold Magikarp

128:21

never occurs that token never appears in

128:24

the training set for the actual language

128:25

model later so this token never gets

128:28

activated it's initialized at random in

128:31

the beginning of optimization then you

128:32

have forward backward passes and updates

128:34

to the model and this token is just

128:36

never updated in the embedding table

128:37

that row Vector never gets sampled it

128:40

never gets used so it never gets trained

128:42

and it's completely untrained it's kind

128:43

of like unallocated memory in a typical

128:46

binary program written in C or something

128:48

like that that so it's unallocated

128:50

memory and then at test time if you

128:51

evoke this token then you're basically

128:54

plucking out a row of the embedding

128:55

table that is completely untrained and

128:57

that feeds into a Transformer and

128:58

creates undefined behavior and that's

129:00

what we're seeing here this completely

129:02

undefined never before seen in a

129:03

training behavior and so any of these

129:06

kind of like weird tokens would evoke

129:08

this Behavior because fundamentally the

129:09

model is um is uh uh out of sample out

129:14

of distribution okay and the very last

129:16

thing I wanted to just briefly mention

129:18

point out although I think a lot of

129:19

people are quite aware of this is that

129:21

different kinds of formats and different

129:23

representations and different languages

129:25

and so on might be more or less

129:26

efficient with GPD tokenizers uh or any

129:29

tokenizers for any other L for that

129:31

matter so for example Json is actually

129:33

really dense in tokens and yaml is a lot

129:36

more efficient in tokens um so for

129:39

example this are these are the same in

129:41

Json and in yaml the Json is

129:44

116 and the yaml is 99 so quite a bit of

129:48

an Improvement and so in the token

129:51

economy where we are paying uh per token

129:53

in many ways and you are paying in the

129:55

context length and you're paying in um

129:57

dollar amount for uh the cost of

129:59

processing all this kind of structured

130:01

data when you have to um so prefer to

130:03

use theal over Json and in general kind

130:06

of like the tokenization density is

130:07

something that you have to um sort of

130:09

care about and worry about at all times

130:11

and try to find efficient encoding

130:13

schemes and spend a lot of time in tick

130:15

tokenizer and measure the different

130:16

token efficiencies of different formats

130:18

and settings and so on okay so that

130:21

concludes my fairly long video on

130:23

tokenization I know it's a try I know

130:25

it's annoying I know it's irritating I

130:28

personally really dislike the stage what

130:30

I do have to say at this point is don't

130:32

brush it off there's a lot of foot guns

130:34

sharp edges here security issues uh AI

130:38

safety issues as we saw plugging in

130:39

unallocated memory into uh language

130:42

models so um it's worth understanding

130:45

this stage um that said I will say that

130:48

eternal glory goes to anyone who can get

130:50

rid of it uh I showed you one possible

130:52

paper that tried to uh do that and I

130:54

think I hope a lot more can follow over

130:57

time and my final recommendations for

130:59

the application right now are if you can

131:01

reuse the GPT 4 tokens and the

131:03

vocabulary uh in your application then

131:05

that's something you should consider and

131:06

just use Tech token because it is very

131:07

efficient and nice library for inference

131:11

for bpe I also really like the bite

131:13

level BP that uh Tik toen and openi uses

131:17

uh if you for some reason want to train

131:19

your own vocabulary from scratch um then

131:22

I would use uh the bpe with sentence

131:25

piece um oops as I mentioned I'm not a

131:28

huge fan of sentence piece I don't like

131:30

its uh bite fallback and I don't like

131:33

that it's doing BP on unic code code

131:35

points I think it's uh it also has like

131:37

a million settings and I think there's a

131:39

lot of foot gonss here and I think it's

131:40

really easy to Mis calibrate them and

131:42

you end up cropping your sentences or

131:43

something like that uh because of some

131:45

type of parameter that you don't fully

131:47

understand so so be very careful with

131:49

the settings try to copy paste exactly

131:51

maybe where what meta did or basically

131:54

spend a lot of time looking at all the

131:56

hyper parameters and go through the code

131:57

of sentence piece and make sure that you

131:59

have this correct um but even if you

132:02

have all the settings correct I still

132:03

think that the algorithm is kind of

132:04

inferior to what's happening here and

132:07

maybe the best if you really need to

132:09

train your vocabulary maybe the best

132:11

thing is to just wait for M bpe to

132:13

becomes as efficient as possible and uh

132:16

that's something that maybe I hope to

132:18

work on and at some point maybe we can

132:20

be training basically really what we

132:22

want is we want tick token but training

132:24

code and that is the ideal thing that

132:27

currently does not exist and MBP is um

132:31

is in implementation of it but currently

132:33

it's in Python so that's currently what

132:35

I have to say for uh tokenization there

132:38

might be an advanced video that has even

132:40

drier and even more detailed in the

132:41

future but for now I think we're going

132:43

to leave things off here and uh I hope

132:46

that was helpful bye

132:54

and uh they increase this contact size

132:56

from gpt1 of 512 uh to 1024 and GPT 4

133:02

two the

133:05

next okay next I would like us to

133:07

briefly walk through the code from open

133:09

AI on the gpt2 encoded

133:15

ATP I'm sorry I'm gonna sneeze

133:19

and then what's Happening Here

133:21

is this is a spous layer that I will

133:24

explain in a

133:26

bit What's Happening Here

133:33

is

Interactive Summary

Tokenization is a fundamental yet complex process in large language models (LLMs) that converts raw text into sequences of integer tokens, which LLMs can then process. While initial approaches used simple character-level tokenization, modern LLMs primarily rely on sophisticated algorithms like Byte Pair Encoding (BPE). BPE iteratively merges frequently occurring byte or code point pairs to create a more efficient and dense token vocabulary. Tokenization profoundly impacts an LLM's performance, influencing its ability in tasks such as spelling, arithmetic, and processing non-English languages. Different tokenizers, like OpenAI's GPT series (TikToken) and models using SentencePiece (e.g., Llama 2), employ unique strategies, including regular expressions and handling of special tokens, to optimize token density and manage various text patterns. Many observed "weirdnesses" or limitations in LLMs, such as the "Solid Gold Magikarp" phenomenon or issues with code indentation, often stem from the specific design and training data of their tokenizers. Choosing an optimal vocabulary size and integrating special tokens are crucial design considerations, directly affecting computational cost, model training, and contextual understanding.

Suggested questions

9 ready-made prompts