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

Loading summary...