Okay, everyone, welcome to the next edition of statistical methods of language technology.
As usually, we pick up where we left it last time.
And last time we talked about which actually has made a big impact on natural language
processing for the reason that it basically enables neural machine learning.
So the entire idea is to embed symbols such as words into a low dimensional as in only
a few hundred dimensions vector space.
And then once we have represented words by vectors, then we can execute any sort of numeric
machine learning such as neural networks of different variants.
What is Word2Vec?
Word2Vec is a predictive model that basically tries to put words that behave similarly in
similar parts of the vector space.
And you train it by language modeling.
So you train it by basically predicting the word given its context or by predicting the
context given a word.
And these are the two variants of Word2Vec.
So in the SIBO architecture, what you're trying to predict is a word in the middle knowing
the words around it.
And it's not positional, you just sum up the representations of these words.
And in the skip gram model, what you have is a particular word and you're trying to
predict positional contexts.
So what is basically a word that is highly probable two tokens before or two tokens after
something like that.
And yeah, we have discussed the skip gram algorithm with negative sampling in a little
bit more detail.
So how does this work?
Basically we have a particular context and we want to tune this neural network such that
it gives a high value for the true context.
So for the real word of apricot in this case.
And gives low values for words which are not apricot.
And for this we need random words that are not apricot and this is where the negative
sampling comes in and this is where you can view this a little bit like a classification
task because you have positive examples and negative examples.
And we looked a little bit into the technical details.
And yeah, then this is the overall architecture.
So basically you have a input layer which is as long as the vocabulary.
And you have an output layer which predicts a vocabulary item.
So this is also as large as the vocabulary is.
And in the middle you have a hidden representation which is much shorter.
So this is the dimensionality, 200, 300, something like this.
And in order to connect these you have weight matrices that you are learning during this
process.
So this is the weight matrix for representing the input words and this is the weight matrix
for mapping this to output words.
And usually you're interested only in this one.
Basically a mapping of a single word which is encoded kind of one hot way.
So this is the vocabulary vector and then one is one and the rest is zero.
And the weights actually that you find in this matrix from going from this word to these
hidden representations, this is the actual dense vector embedding of this particular
word.
And we talked a little bit about variance.
Yeah?
I have a question for the last slide.
So you said we have a context of four words.
So don't we need four times the input layer?
No, no.
Actually we don't.
So there are a few variants.
So basically in the SIBO world, like this one, what we do is we sum them up during training.
And what we do in the skip prem world, we randomly pick one.
So no, we don't.
We could, right?
But we don't.
And yeah, there were a few variants that we discussed last time.
And now for one thing, so this is something that actually costs a lot of over estimating
the capabilities.
I don't know if anyone has seen this.
It's quite famous.
It was like you could compute stuff like king minus man plus woman is queen.
So this sounds super attractive.
So if you have a vector space and you would be able to perform operations on vectors that
correspond to somehow semantic dimensions, and then therefore compute words that have
some sort of semantic properties and they don't have them, this would be very attractive.
And there's a 2013 paper by Mikoloff and others that actually showed this for selected examples
and also showed this for the word analogy task.
So this is kind of questions like, yeah, Paris is to France, like Prague to what country?
And then answer is Czech Republic.
If you can do this vector arithmetic and find this good candidate, then actually you can
perform the analogy task well.
And this worked for the particular test set better than the others.
I mean, to a percentage correct of like 40, which is nice.
But then people started thinking a lot about this and seeing meaning in vector directions
in these vector spaces and actually this is widely overestimated.
So I think 95% of posts that actually mention this draw the wrong conclusions.
Because this only works in the local space.
So if it works for, say, for example, hyponyms, more general terms.
So you have, I don't know, lion and zebra are animals.
And then you want to transfer this to tables and chairs are furniture, right?
So maybe you could learn the direction of lion zebra, average it to animals, and then
you would have the direction you have to go to from a representation of table or chair
in order to get furniture.
This does not work at all.
There's no regulative that actually ensures that in your vector space for subspaces of
the vector space, actually this relation holds.
Because the furniture is right here and the animals are over there.
And the directions of semantic relations within these subspaces is completely different, right?
So don't overestimate the capabilities of Word2Vec.
I mean, this is usually when new stuff comes out, people think they can answer everything
with it.
And Word2Vec actually is a great tool.
But it is not the answer to everything in the world.
Another example from this one, I mean, of course, it's a dense vector representation.
And you don't actually know why things are going on.
So yeah, France is to Paris like Germany to.
Now the question is, depending on the corpus, of course, what you train, what comes out
is either Berlin, because it's a capital city, or Munich, because it's the home of the major
football club in the country.
So I've seen Word2Vec actually proposing Munich for this analogy, just because it was
trained on too much soccer.
And you don't see that.
You don't know that, right?
Of course, post hoc you could figure it out.
And it was just my theory.
I hadn't read this corpus.
So yeah, that's like one of these downsides for dense vector representations for neural
models.
They have a lack of interpretability.
OK, and also, there was a lot of debate after thinking, OK, so what is the big difference
between Word2Vec and all the other things that we've seen so far?
So you remember the LSA?
It also did word embeddings.
Now this was a count-based model, because we count stuff, and then we do some operations
on these matrices.
This is a prediction-based model, right?
Are you trying to predict the word in context and then learn from them something?
So the question was, do we want to count, or should we predict, rather?
Is this like a fundamental difference?
And there were papers written that favored prediction.
There were papers written that were kind of sad that count-based wasn't as good as anymore.
And then in 2014, the paper came out to say, yeah, mathematically, actually, it's the same.
So for a particular weighting measure, which is point-wise mature information, weighting
of co-currents, vectors of words, you could actually show mathematically, prove that Word2Vec
approximates the LSA on the same matrix on the same corpus.
Yeah, I mean, some tricks, some shifts, some whatever, but mathematically, it's basically
the same thing.
So basically, we had Word2Vec in the community since 1990.
It was just the problem that it didn't scale, because these matrix operations are very expensive,
and Word2Vec actually approximates these.
So you could run this for a shorter time and get almost the same results.
So yeah, big impact.
But this is maybe one of these reasons why deep learning and NLP didn't make as big of
an impact as it did in other fields, such as signal processing, computer vision, speech
processing, these kind of things.
Because natural language is made out of symbols, and we have to convert them somehow into continuous
representations in order to handle them in neural networks.
And this kind of conversion has been there for quite a long time.
So these improvements that we see in NLP are rather incremental.
Neural networks are better, yes, but they're not slashing error rates in half.
They just, you know, improve a few percentage points over what we had before.
And yeah, the author of this paper actually told me once that all these advances are rather
due to parameter tuning.
So we have a lot of hyperparameters, like numbers of dimensions, how long do we train
these learning rates, then various dropouts, architecture, whatever.
And of course, we can now afford it because we have GPUs and larger computers and stuff.
But yeah, this is like the main source of improvement in NLP tasks, at least in the
early times of the neural NLP revolution.
And yeah, Omer Levy also made the point as if you basically want to fairly compare to
previous approaches, and you do a lot of hyperparameter tuning on your current approach, then you
also should do a lot of hyperparameter tuning on your baselines, otherwise it's unfair.
You can always out-tune everything.
Okay.
Yeah.
What else is there for word representations?
So there have been a few small steps and then a big leap in the past few years.
Small steps were like better address the out-of-vocabulary word problem.
So you remember we had this out-of-vocabulary problems with the potter speech tagging, and
it's very prevalent.
If you haven't seen the symbol, you don't have any information.
So the only thing you can do in Word2vec is assign a zero vector or a random vector,
but you don't have a good representation of a new word.
So there's fast text, which is an approach that basically does character-based back-off.
So it would look at the character sequences within words and try to compose an embedding
for a new word on the basis of its parts.
So this is much better than nothing.
Of course, it's not exact as if you would have a good representation of a word that
you have seen like a hundred times in your corpus.
But it's, yeah, still there's some guesswork going on for the parts, and in many cases
this is much better than not doing it.
There are approaches to use grammatical context.
So Word2vec in its original formulation uses just words around in a window, and this window
could be varied, but it's, of course, some words might be more important than others
depending on the grammatical structure.
So there's a thing called Word2vec F, which allows you to supply arbitrary contexts, and
people have used it for supplying grammatical contexts.
So the verb for the noun, the noun for the verb, the adjective modifying the noun, these
kind of things.
Then yeah, the question is, there was a question for a while.
What to do?
Should we actually allow our neural architectures to learn the embeddings from scratch, or should
we rather use pre-trained word embeddings on large corpora, which are not suited particularly
well for your task, but you could just start it off like this and then continue to tune
them because you can still adjust their weights in the lowest layer of your neural network.
But this has been more or less decided.
So pre-trained is usually much better than starting to learn from scratch because you
pull in a lot of information from different sources that you don't have for small amounts
of training data.
Then there's this whole movement about word embeddings to sense embeddings, and this is
also something that divides the community.
So what's the problem here?
If you have a word like table, it receives one embedding in Word2vec.
But table could be the data table, or it could be the table that I'm sending in front of.
And depending on how frequent one or the other sense is in the corpus, it will just be dominated
by the most frequent sense.
So the question is, do we want to have an approach that basically distinguishes these
automatically?
Say there's a table one, there's a table two, and we have two embeddings, and we have a
way of telling which one it is in context.
And yeah, one side of the community basically says, yeah, this one embedding that we have,
for example, from Word2vec, must actually be some linear combination of these two.
So it's basically in there, we don't have to explicitly state that.
And the other part says, yeah, but how can we access it?
We don't know what are the parts, maybe we need these parts explicitly for our application.
And again, this is one of these things that are application dependent.
And then the big leap, basically starting last year, was contextualized word embeddings.
So this also kind of attacks this question.
So Word2vec embeddings, or fast text embeddings, for that matter, are static in the sense that
you have a word, you always get the same embedding, and then you use it in your architecture.
But we could have some kind of a pre-layer of your neural architecture that actually
would yield different embeddings for words when they are used in different contexts.
So maybe then the data table and the furniture table get different embeddings.
This has been started with Elmo, and then BERT and GTP came out.
And these are all models that come out of large companies, for the reason that you actually
cannot really afford to train these.
Because you need a lot of, not GPUs, but TPUs, tensor processing units that have a lot of
memory that are super expensive, that only large companies actually can afford them or
very large computing labs.
And yeah, one of these I want to pick out, which is BERT.
BERT is actually right now causing the same kind of ripple through the community as Word2vec
did.
So in 2014, we Word2vec-ified everything, and now we are BERTing.
Everyone is BERTing everything.
And yeah, what is BERT?
BERT actually has been presented, when was that?
Like two weeks ago, or one and a half weeks ago, for the best paper awarded NACL.
So this is like the latest stuff I can show you in this lecture.
It wasn't even out there officially when we started this lecture.
So what is the idea behind BERT?
The idea behind BERT is basically that, again, we have a predictive language model training.
So we have input words here.
And what BERT does is masking some of these randomly.
So for example, we have here, let's stick to improvisation in this skit.
And then we masked the improvisation.
And we have some neural network that would actually try to predict what is there.
So in the end, we have a softmax over the vocabulary.
And we want to have a high value for the real word, which is improvisation.
And we want to have lower values for all the other ones.
And what is in here is not like the very simple two layer, one hidden layer input output thing.
But what is here is a stack of encoders.
And these in the BERT case go from two directions.
So this is a bidirectional LSTM that basically passes on its output to another bidirectional
LSTM.
And you do this 12 times or in the big BERT model, 24 times.
So what goes in here is basically static word embeddings.
But what happens in these LSTM layers is that for every position in a sentence, when you
run this over a sentence, you get one representation from the left, one representation going from
the right for this particular word in 12 respectively, 24 different layers.
And now this entire thing is the embedding.
So your embedding is basically made up of, so they use 512 dimensions, and times 12.
So it's a very long embedding.
And the idea is basically the more stacks you do here, the better you can summarize
what was there, and the better you can contextualize towards a particular embedding for your target
word.
So they train it with masking.
They also train it with next sentence prediction.
So these are two modes of training.
And if you want to know more about it, there's a nice recording of the speech given last
week in the NACL.
Just Google BERT presentation.
Maybe you find it.
And yeah, how would you actually use this kind of model in tasks, and why is it so wildly
important?
Yeah, if you don't want to watch the video, this is a very nice blog that explains BERT
and also other contextualized models.
So how is this actually, what is the setup?
What you do is actually you train your BERT model on some datasets, raw data, lots of
data.
Go to the internet or download Wikipedia or take books, whatever.
And the training objective is predicting the masked word, which is language modeling.
And then once you have your BERT model, which consists of all the mechanisms in order to
produce these contextualized embeddings, then you can use it in any sort of a task.
For example, you might have a task that classifies spam versus non-spam, and you would run your
message that you want to classify through the BERT model, get this vector representation
of either like a preferred thing, if you're interested in classifying BERT, or over the
entire sequence.
And in the end, you take the ends of it if you run it from both sides.
And then you run this through any sort of a classifier.
And the idea is that a lot of information about language as such is already encoded
in these layers, so that it's easy for the classifier to pick out the stuff that is relevant
for the task.
And we're entering a kind of a phase here where we can't really exactly explain what's
going on anymore.
However, we can probe it.
We can look at the resemblance of what things are going on with respect to the concepts
that we learned earlier in natural language processing.
So here's something that people did on the BERT level for syntactical parsing.
So they used these t-snee plots, which is basically putting all these huge dimensions
on just two dimensions in order to plot the representation of spans of different categories.
So these colors, you can't read it here, but some is prepositional phrase, some is
verb phrase, some is noun phrase, some is adverbial phrase, so these kind of categorial
grammar things.
And you see that, for example, in layer 11, it's not very distinctive.
It's a lot of colored dots.
In layer 12, some of these are actually coming out.
But in the first two layers, layer 1 and layer 2, the colors are kind of nicely sorted.
And this is the kind of stuff that the classifiers could pick up upon.
And this is another one, what I didn't say earlier, there's also an attention mechanism
built in that basically looks where the signal comes from.
And if you basically look at the attention head of the 11th layer, no, of the attention
head 11 in layer 2, so very low layer, right?
It hasn't stacked so much.
And there's one particular attention head, right?
Because they picked it up because it had the highest correlation.
Then you could actually read off a tree from that.
So basically you say, okay, R is the main verb, and now let's see where the attention
from this word went.
It went actually to keys, okay, which is the subject, right?
The keys to the cabinet are on the table, okay?
And interesting, then, the attention from the keys goes to the cabinet, and the cabinet
goes to the table, and that kind of resembles a dependency parse, an unlabeled dependency
parse.
It's not the exact thing.
You would draw stuff a little different, but things like on the is actually depending on
the table, or the is actually depending on the table, and the to the cabinet is kind
of subdued here, it's actually resembling dependency parsing.
And this is what we had in a few lessons back when I said, yeah, for those who still parse,
and then Tim was asking, okay, what is the alternative, yeah, maybe this, because the
information that is contained in this model is just as good or maybe more or less as good
as if you would have done a dependency parser.
And if your objective is not the exact extraction of subjects and objects for information extraction,
but if your objective is, for example, spam classification, then this is just as good
as any other parser, but you don't need it because you download BERT, and this is why
people are stopping parsing, more or less.
Okay, are there more questions on BERT?
Yeah?
Because of the bidirectional stuff, so they actually do show and do motivate that bidirectional
works better than just the next word, which is actually what Elmo does.
So they had to actually motivate that.
Okay, let's summarize dense vector representations.
So what was the core idea?
Basically, we wanted to make documents or want to make words into numbers somehow.
So we want to have real valued representations, because then we can compute with them, then
we can compare them, then we can look at their similarities, then we can use the mineral
architectures.
And the whole idea about this is that similar items should get similar representations,
because then you have a way of generalizing.
If you've seen a mouse in your training data, but not a rat, but you know that mouse and
rat is similar, then you can actually have some hypothesis on when you see a rat in the
test data.
And yeah, where these representations come from depends.
We could actually exactly compute them, we could sample them, and we could learn them
in this predictive case that we saw today.
And yeah, it's actually not as new as it sounded like, because LDA has been around for a long
time in natural language processing, but actually this contextualized embeddings make a huge
difference, because then what you do is you suddenly don't need to execute preprocessing
steps that you otherwise would have learned from training data based on static embeddings.
So stay tuned, lots of things will follow out of this, and I'm sure at some point they're
going to have some other member of the Sesame Street with even more layers and even better
contextualization capabilities.
So I'm kind of waiting for the cookie monster in this case.
So this was it for dense vector embeddings.
And in case there are no more questions, I would go for something completely different,
which is graph based methods.
Graph based methods for natural language processing.
So this is like kind of the opposite of dense vector representations, because we're trying
to encode our information in graphs.
Why would we want to do this?
Well, maybe because it's a more natural representation than vectors of like 300 numbers.
Some stuff is very obvious, like words that appear together in a sentence, connect them
as symbols in the graph.
Why not?
Yeah, with the graph, of course, I mean the thing with the nodes and the edges.
And of course, we can have all sorts of variants of these graphs.
So maybe we have edge weights, we have node labels, we have node weights, we have directed
or labeled edges, we have different types.
So for example, this could encode like a semantic hierarchy.
So this is the kind of stuff where we actually want to have a graph.
If you want to express that an animal is a concept and a dog and a cat and a mouse are
actually sub concepts of this, then this would be a typical is a relation.
And maybe you want to express that this is a translation of the English term for animal.
And therefore, you would have to just type your graph and encode it like that.
So graphs is actually very nice to encode information.
And this is also why large knowledge bases are sometimes called knowledge graphs, because
people just declaratively write down knowledge in these.
But we can also use this representation for natural language processing.
We don't have to use manually compiled graphs, we can also use automatically collected graphs.
Okay.
Yeah.
Right.
Okay.
And how to represent graphs, I mean, you all know this, but just as a short reputation.
So of course, you can just paint the graph.
So this would be the geometrical representation.
So this is a graph of nine nodes.
And you could also write it down as a set representation and basically spell out the
definition of vertices and edges, or you could use an adjacency matrix.
And the adjacency matrix actually encodes the weights between edges.
And the adjacency matrix is, yeah, could be mirrored on the diagonal for undirected graphs
for directed graphs.
It's the case of encoding like an edge from B to A, which has a weight in this case of
two which corresponds to this edge here.
Okay.
Why do we want to do this?
Yeah.
It's more intuitive.
It's also more, yeah, graspable for people.
So if you think about browsing information, about words, about documents, a graph is a
very natural thing.
People understand that, right?
So yeah.
Vector spaces of 300 dimensions are not navigatable.
You could bring them down to two dimensions, but then you lose a lot of informations.
Of course, any sort of these vector representations can be transformed into a graph.
For example, by just computing all the pair of similarities, and then you have edge weights
between these items.
The other way around is not possible.
So if you have a graph that was built from a dense vector representation by similarity,
you will not be able to directly restore the original representation.
Of course, you could do something like a graph embedding, which would give you some other
embedding which actually keeps the distances okay, but it's not going to be the same representation.
So the conversion of dense vector representation via similarity into graphs is lossy.
And what's the other reason besides intuitiveness of graphs?
Well, there's graph theory, and graph theory has been developed for a very long time, and
they have very nice graph algorithms that can be just executed on stuff, and maybe they
solve nice things.
So there are things like graph clustering.
So how do we actually find groups of nodes in a graph?
There's graph-based ranking, which is actually the core of Google as it was in 1999, which
is the page rank algorithm that we're going to talk about a little bit today as well.
And there's of course path-based algorithms, like Dijkstra algorithm, what is the shortest
path between things, and you could use this, for example, to encode semantic distances
in a wordnet-like graph, so like hierarchies that I've just shown here.
If you have like a big hierarchy like this, you could use a path-based algorithm to assign
how similar animal is to furniture, because you have to go over a lot of hops.
Maybe it's not so similar.
Maybe animal is more close to a human, because there's less hops, so the shortest path is
actually shorter.
Who has actually seen PageRank already in a lecture?
Some.
Not so many.
So this is actually how Google started.
Brennan Page invented at Stanford the PageRank algorithm.
Fun that the guy is called Page, right?
Yeah.
Random thing, there's no reason.
And yeah, then they launched it, and actually the ranking was much better than all the other
search engines.
This is why they got a lot of users.
And right now PageRank doesn't play a major role in the Google ranking algorithm no more,
but it was crucial to basically get ahead of everyone else.
So what is this idea?
Okay.
So the web is a directed graph, obviously, because you have pages, visual nodes, and
then you have links on these pages that point to other pages, so they are edges.
These edges are not weighted in the sense that you don't have any edge weights on links,
and they're directed, of course, just because you point to a page, this page doesn't know
about you.
And now the idea is some pages might be more important than others.
And of course, if you have a query, if you enter data table, whatever, as a query, then
of course some pages contain data table and some don't.
But this is not what I'm talking about.
There are pages that are more important than others even without query.
So there are pages that people would trust more, that are more important pages.
And how do you measure importance of pages?
Well, maybe a good idea is to look at how many people actually are linking to these
pages, because the more people that find this page important, the more important it is.
But maybe there's also a thing like if an important page links to another page, maybe
this is more important than some stupid whatever page links to a page.
And yeah, these are basically the elements of the page rank algorithm.
So the idea is every page has some outlinks, basically what you're linking to.
And if you have downloaded the internet, you also know the in links, which is basically
who is linking to a particular page.
And yeah, of course, you could game the system easily.
But back in 1998, there were no such things as link farms.
Who has worked in search engine optimization?
No one?
Pity.
The weird thing of fighting the Google ranking algorithm and guessing what they're doing
in order to push up pages in one way is actually of creating a lot of other pages linked to
the page that you want to push up, which is a link farm.
And of course, they have countermeasures.
But back then, they didn't have that.
And then the definition of page rank is very simple.
So this is just half of the definition.
The other half will follow in the next slide.
So what is the idea?
We have a rank of a page U. And the rank of the page U is actually the sum of the rank
of the pages V that actually link to this page.
So this link to this page divided by the number of outlinks these particular V pages
have.
So V, basically, V pages link to U. So this is a set of pages that have a link to our
page U. And every of this page basically takes its value that it has, which is this RV, and
distributes it evenly over its outgoing links.
And yeah, of course, it's a recursive equation.
But you could actually start this process off by assigning, say, the same weight to
every page, and then compute it for the first time step, then using these values for the
second time step, and then using these values for the third time step, and you do this for
a few time steps.
And after about 20 steps, this is converged on the web.
So it's not as huge and as long as you might think.
If you apply this definition like this, then there is already a problem.
Even without link forms, there are rank syncs.
A sync is where all the stuff goes, right?
So this is like an example of a rank sync.
So there's a page that links to this page, and these two circle.
So this page actually gives all this energy here.
This one gives all this energy here, and this one gives all this page rank here, and this
page rank goes here.
So they basically keep whatever they have.
But whatever comes here is actually, maybe this one has more outlinks, maybe not, is
actually pumped into this rank sync.
So the longer you iterate, the higher the rank of these get, which is not a measure
of quality.
Because they're linked in a circle, a fashion doesn't mean it's a good page.
So this is why we need some other half of the definition, and this is the damping factor.
Actually you multiply this by a D, and typical choice is 0.85, empirically, why not?
And then you add to the rank of every page, like whatever is remaining from the probability
mass, so 0.15 or something, divided by the total number of pages.
And in this way, the total mass of rank that you're distributing stays the same.
And in this way, this actually simulates to teleport from whatever page here with some
probability to some random other page.
Because you're always distributing the rest kind of evenly.
And this actually takes care of these rank things.
And the idea behind this is what is called a random surfer model.
And random surfer is actually how you would simulate page rank.
You could actually do that.
So I'm a random surfer.
I'm on a web page.
I open the web page.
I randomly click on any of these links.
And then I open another web page, and then I randomly click on any of these links, and
I continue like that.
But with some probability, which is the one minus the damping factor, I teleport to some
random other page in the web.
And this is basically how you can exit your rank sync by randomly teleporting maybe back
to this one or maybe to any other page.
This is actually expressed simply in a matrix.
So you can actually take the matrix, which is the adjacency matrix of the graph.
And you can apply an operation on it, which actually turns this into a probabilistic adjacency
matrix, or also called the stochastic version of it.
So what is the idea here?
Basically, if you have an adjacency matrix, what you want to have is if you have a node
such as f, you don't want to have any sort of weights here.
But you want to have a probability distribution over this so that you can, yeah, in a random
surfer model, randomly choose where to go.
And this is how you do it.
You basically sum it up and normalize it by this.
And this is the stochastic version of the adjacency matrix.
And then what is the operation that is actually executed?
You have a vector r, which is the rank.
The vector is as long as you have pages, because every page has its rank.
And now if you multiply the transposed of this stochastic matrix with this vector r,
then this is the first part of this definition, because then you get a new vector r.
And what you do then is you apply the damping factor here and one minus the damping factor
on a d vector.
And this d vector is where all elements are actually equal to 1 divided by n as a number
of pages, which actually realizes this recursive definition, not for single pages.
So in this definition up here, we're computing the rank for only the page u.
In this definition here, basically, we compute the page rank of all pages of the next time
step based on the page rank of all pages on the previous time step in one go, in one vector
matrix operation.
And yeah, just mathematically, why does this work?
So it's known that if we have a stochastic matrix and it is irreducible and aperiodic,
so then there exists a unique stationary distribution r.
So basically, the stationary distribution is what this thing converges to.
There's only one solution of this, because it's unique.
And what are the conditions so that this actually happens?
What are the conditions that actually in the limit of self-multiplication with this matrix,
this matrix converges into a stationary distribution of the form a diagonal one matrix times our
rank vector?
This happens if it's irreducible.
Irreducible means there's a path between all nodes.
So you can't just kick out stuff.
And aperiodic, there's no cycles like rank things.
And this is actually why the stamping factor is so important, because the stamping factor
is like a random teleportation in the random server model.
So basically, we have a path between all nodes, and there are no rank things anymore.
So this is actually not like a small hack or anything with this stamping factor D, but
it's actually a crucial element to make this entire thing converge.
And yeah, coming back to why is this now useful for Google?
Because it allowed the ranking of pages by reputation independent of GRIVI.
And in 1998, the situation was that there were still search engines like Yahoo, which
were actually not search engines back then, but web directories.
So people would sit there, catalogize, catalogize, catalog the web.
So they would actually surf around, and if they found a good page, they would actually
think about its category, just like in the library, and put it there.
And at some point, it didn't scale anymore.
And at some point, just that the query matches doesn't mean that all pages are relevant,
because there's just too many pages.
So even though the query matches these pages, and the match is fine, and everything is sorted
out well, just the order of pages is now decisive, because people are not ready to
click through hundreds of result pages.
And if you now have an element like page rank, which says, yeah, but in case you have this
page here and this page here, and they both contain the result, this is usually liked
by many people, because people link to it.
Then you put it on top, and then people spend less time searching for reasonable pages,
and this is how Google won, basically, short story.
OK, now, yeah, let's compute this.
Basically what we're doing here is nothing else than, yeah, computing the stationary
distribution, the eigenvectors of the matrix.
And what we can do here numerically is to simulate a lot of random surface.
So what we can do is we initialize all pages with the same rank, and then we compute the
new page ranks based on the previous ones, and we do this until the difference gets so
low that we're not interested in this difference anymore.
So yeah, this would be the code for page rank.
Ridiculous, if you think about it.
So you do until your difference is not significant.
Count up the time step.
Yeah, this is the rank vector of the time t, which is actually the stochastic matrix
times the rank vector of t minus 1.
And then you look at how different are these, and if this difference is small enough, you
stop.
That's it.
Of course, if you want to scale this out for gazillions of pages, you need big computers,
and this is where Bigtable and MapReduce was born, but this is a different story.
Now talking enough about search engines, why am I telling you this?
Because it's a good example that we have a graph algorithm, which is defined for graphs.
And now if you have a graph algorithm and you have a nice representation for an NLP
problem, and we can apply this graph algorithm just like any other graph algorithm and maybe
solve some nice stuff.
And this is what you're going to look at.
One place where actually PageRank was used productively in natural language processing
was multi-document summarization.
Now what is multi-document summarization?
It's basically you have a bunch of documents, and you want to have a short version of all
of them, because they're all about the same topic, and we would assume that they're already
topically sorted.
And then we have to identify sub-topics of these documents, because we of course want
to reflect the important things in this small document collection, which is topically already
centered.
And then what we can do is we can identify sentences belonging to these important sub-topics,
and then since it's multi-document, maybe it's a lot of redundancy, so maybe we want
to select the sentence that actually describes this sub-topic best, and then we can kind
of mix these sentences together, maybe in the proportions of these sub-topics, and then
we have to kind of linearize this and then, so basically we have to make sure these sentences
are not just random sentences, but they form attacks, so they have to kind of fit together
somehow.
You don't have to overlap, there shouldn't be any references to stuff that is not there
because you took it out of some text, these kind of repair steps.
And in this particular thing, we're only looking at the sub-problem 3, which is basically,
let's assume that we already have sentences that belong to a particular topic, and we
know that we want to have a sentence from this topic because it's important.
If you want to have a rough idea of how we can arrive at this point, think about topic
modeling, for example, we had topic modeling, it informs us about what is the distribution
of topics in our collection, so maybe we find the important ones, and we can use the topic
model Gibbs sampling in order to assign topics to sentences, so maybe we have a few sentences
that really, really correspond to this particular topic, now we have many of these, what do
we do?
And the idea is to use measures on the sentence similarity graph.
And for this, I need to introduce a few things.
So we have talked about PMI weighting, but we haven't talked about TF-IDF, correct?
So yeah, in the neural world, you would basically be able to run any sort of a method that actually
gives you a fixed length representation for a sentence, there's things like doc2vec or
sentence2vec or paragraph2vec, but this was invented in 2003, so it wasn't the case, so
people have resorted to the traditional ways of indexing collections, and it goes like
this.
So you have sentences, maybe three sentences, and you want to represent them numerically,
and in information retrieval, what you do is first of all, you have your vocabulary,
so these are all the different words in the entire vocabulary of all your sentences, and
then you count how often occurs any of these words in any of these sentences, and then
you get some numbers here, so seven times the same word in a sentence, wow, must be
a long sentence, it must be a word, something like that, otherwise it can't occur seven
times in a sentence.
So most of these numbers are either zero, or zero, or zero, or one, so lots of zeros,
a few ones, a few other numbers.
And then the question is, what words are more discriminative of sentences?
So what we have here is a word one, which has actually high numbers in all the sentences.
We have a word n, which has only one occurrence in one sentence, and we have a word two, which
is actually, yeah, has only one occurrence, no four occurrences in this one.
So if you want to distinguish sentences from each other, who thinks word one is a good
word for that?
Who thinks word two is a good word for that?
And who thinks word n is a good word for that?
Yeah, so kind of agreeing with your hands, so word one is not a good way of discriminating,
because they all have it, right?
And this is what expressed kind of inversely in what's called the document frequency, it's
basically in how many documents, or in how many sentences, because here we have sentences
as documents, do we see these words?
And if you have three sentences, respective documents, and we have a three here, then
this is zero informative.
So you just count the non-zeros.
And the document frequency of some words is one, some is two, and so on.
And now the question is how important is actually the frequency of the word?
Well, for searching, if you want to find sentences with word two, then you probably would want
to produce this sentence where you have a lot of word two in it, as opposed to another
sentence maybe that only has one word two in it.
And yeah, TFIDF is actually a standard rating scheme for representing documents in terms
of terms, term vectors.
And it goes like this, you basically multiply the term frequency, so how often do we have
the word per sentence?
By the inverse of the log of the document frequency, which is basically the log of the
total number of sentences divided by this TF value here.
Now if you have the same number up here, total number of sentences is three, and down here,
document frequency is three, then this is a one, and the log of the one is a zero.
This is why these guys that are everywhere get zero weights throughout.
They don't have anything to say in representing documents with the TFIDF vector, and the lower
the document frequency, the more distinctive they are, the more you can use them to distinguish
between these sentences.
And yeah, the higher the term frequency within the sentence, the more important they are.
So you multiply this together, and then you get numbers like these, and you would represent,
for example, the second sentence with a vector of the vocabulary.
So the vocabulary is long, many, and this is the TFIDF weighted feature vector for the
second document in this case.
So this is the same as a vector space model and information retrieval, standard information
retrieval model, so in case you go to lectures that use information retrieval, or in case
you come back for my winter lecture on natural language processing for the web, then we're
going to revisit this, because this is an important element for building search engines.
But here is the NLP course, and the algorithms course, and we are in the multi-document summarization,
so now let's use this in multi-document summarization in an approach which is called LexRank.
So we can use this now for the sentence similarity graph.
So you remember, we had from different documents different sentences, and we already knew that
they're kind of from the same topic.
So nothing stops us from putting these as nodes in the graph, and then representing
them with their TFIDF vectors, and then once we have them as vectors, we can, for example,
apply the cosine similarity in order to see how similar they are.
And this is this huge formula up here, this is nothing else than cosine similarity on
TFIDF vectors.
So we have a point where some of these TFIDF vectors of the two ones, and this is like
the normalization term, yeah.
And what is actually for the graph, in a graph space, what's usually something that people
do is to apply a threshold by saying, okay, if the similarity is below a certain threshold,
then maybe we don't want to introduce an edge, because the graph structure is actually informative.
And if you have a fully connected graph, it has as much structure as a graph without any
connections.
There's no structure.
There's nothing to draw from that, right, just from the graph structure itself.
So this is why sometimes it's good to basically get rid of stuff.
So you don't want your graph to be fully connected.
You don't want it to be not connected at all.
And yeah, in this paper, so this is from this 2004 paper, they also use different edge weights,
and they show them by thicker edges.
So these are edges that are actually between 0.3 and 1.0, and then these small edges are
still above 0, and maybe you want to prune them.
Maybe you don't want to prune them.
And yeah, we can use any sentence representations here.
We don't have to use TFID effectors.
It wouldn't change the overall method, because now if we have this, we can apply, yeah, measures
of importance, because you remember we want to pick the sentence that we actually want
to use for representing this topic.
And there are a few ideas what could be the most nicest best sentence.
One idea is basically to take the centroid.
Maybe we can use the average sentence.
Now what's the average sentence?
Since these sentences are represented in vectors, these are points in the vector space.
We can just compute the average vector in the vector space, and then, okay, this is
a point, but there's no sentence.
But maybe we can just take the closest sentence that we have.
Another alternative is degree centrality.
So the idea would be we want to have the sentence that covers most of the content.
Now the one that covers most of the content should actually have a lot of connections
in this graph, because it actually covers all of the kind of stuff that the others do.
So there are, so what's degree of a node is actually the number of outgoing edges, or
in going, I mean, this is symmetric, so this one has 1, 2, 3, 4, 5, 6, 7.
This one has 1, 2, 3, 4, 5, 6, 7, 8, 9.
Oh, this is better than this one.
So this would be degree centrality, and of course this also would depend maybe on the
weights.
Maybe not.
And then there's lag strength centrality, and so the idea is basically it's not sufficient
to be similar to many sentences, which would be covered by degree centrality.
It's also, like in page rank, this idea is also important to be similar to important
sentences.
And this is already the recursive definition, right?
It's important to be similar to important, so they have important two times.
So this is, yeah, basically what you could do with page rank.
This is exactly what page rank is modeling.
So what are we doing?
Yeah, we take our adjacency matrix, which now has some cosine values in it, and then
we make a stochastic matrix out of it by probably row normalizing, and then we can just throw
it into page rank, run it, and this basically gives us a ranking of sentences, because in
the page rank vector, every page or every sentence has a number, and then we can just
sort them by highest number first, and then pick this sentence as our summary sentence.
And that's it.
And yeah, when they evaluated this, they used a standard measure, a standard data set
for multi-document summarization, and yeah, so they used the rouge metric.
The rouge metric is something similar to the blue metric, and the blue metric is something
that you're going to talk about in the machine translation lecture in more details, but basically
what it does, it measures overlaps of word n-grams.
So it would compare the machine summary to a summary that people have written, and it
would compare this on the basis of how many words do they have in common, how many two
words in sequence do they have in common, how many trigrams do they have in common,
how many foregrounds do they have in common, normalize appropriately, divide through a
little bit of stuff, and then penalize too short.
Yeah, that's roughly what the measure is.
Sounds like a terrible idea, right, because it doesn't really look at the semantics, it
just looks at superficial overlap.
But if you do this for a range of different summaries, then you get at least scores that
you can compare systems against.
And yeah, when they did this on this 2004 task 4A data set of some competition, what
came out is basically that the lex rank was always the best system, and the threshold
was like 0.1, so basically in our picture here, they would not use the thin edges, but
only the ones that are a little bit thicker or the super thick ones.
What they also came back with is that, of course you can, so the original page rank
formulation doesn't have any weighting in edges, because you could now straightforwardly expand
the definition by using edge weights in your stochastic matrix and make this proportional
to the edge weights, this actually doesn't even help.
So these numbers here in this row, this is the continuous, lex rank is actually a little
lower than what you get from a thresholded, unweighted adjacency matrix, which actually
shows that actually graph structure is important.
So why have I selected this?
Because it actually takes into account this graph structure beyond local decisions.
So local decisions would be the centroid, local decision would be the degree, you just
look at how many edges it has in any sort of a thresholded graph.
And there's something extra, right?
So this extra step of computing this importance and then the page rank somehow manages to
get the entire graph structure into the solution of the problem.
And it actually also works for single document summarization on the multi-document, it's
more fun because you have more redundancies.
Is there a question?
So at the start we said that every sentence is assigned to a topic, something like this,
I think, wasn't it like that?
But isn't the goal then to find multiple sentences that have distinct topics?
Yeah, yeah, yeah, so basically this is just a sub-step, this is just a sub-step.
So we have like a multi-document summarization, we're looking at step number three and we've
taken an entire system that takes care of the rest, yeah.
So I just zoomed into this particular thing.
Okay, more questions, no?
All right, then.
Let's talk about another application.
The application will be keyword extraction and the notion that we're using is a notion
that is very old and very important in graph based NLP which is the notion of co-currents
graph.
It's a very simple idea.
So I mean we have all these words and they kind of appear together in sentences or in
like windows of five words or something.
And if they co-occur, we might as well connect them with an edge.
Do all words co-occur with all words?
Maybe they can, but maybe they will not, right?
So maybe this co-occurrence graph gives us a lot of information about, yeah, how words
are used with each other.
And yeah, so the definition of a co-occurrence graph is basically first you have to define
your context.
So what are you looking at?
Document level, sentence level, window of five, whatever.
And then whenever you find two words within this kind of unit of information, they are
said to be co-occurring.
And then if you model words as vertices and their co-occurrence as edges, you could have
weighted edges between words and you could also record how often do they co-occur in
a collection.
So there's basically a weighted graph of words.
And yeah, actually if you do this, if you make a count-based co-occurrence graph, then
what will happen is that there are these words like the a off and so on, which actually co-occur
with every word just because they are so frequent.
But again, it's kind of like this idea of this document frequency.
It's not very informative, right?
And what people do there is to run a statistical test that basically looks at, okay, so how
many experiments do I have?
So how many contexts?
Maybe how many sentences if you have a sentence-based window?
And then how often do I see a word a?
So there's a number of experiments where a takes part in.
And how often do I see word b?
And how often do I see them together?
And then I look at, is this number of experiments where a and b actually both occur higher or
lower than what I would expect taking their numbers into account of a single co-occurrence
because if you have something like a word that occurs in like 10% of sentences and another
word that occurs in 20% of sentences, then you would expect them to co-occur in 2% of
sentences if they were independent.
Now if they occur in 2% of sentences, maybe it's not very interesting.
But if they occur in, say, 5% of sentences, it's much more than 2% of sentences.
And then if the statistical test tells you, oh, yeah, this is actually a significant co-occurrence,
then it's, yeah, the notion of significant co-occurrence, which is, yeah, just the count-based
one is not usable because of the frequency distribution of words.
You can look at how this looks like.
So here is like a little bit of a radiohead lyrics, and here we have two different co-occurrence
graphs.
Unfortunately, these edges are very slim, but you have it on your PDF much better.
So what we see here is in a sentence co-occurrence definition, so every line is basically co-occurring.
What happens is that there are lines, and every line basically causes a click, right?
Because if you have a line of like five words, then every word is connected to every word.
And there are also words that are very frequent, such as a or your, which are connecting actually
a lot of clicks.
And this is a typical structure of these graphs, which is called the small-world graph structure.
Small-world graph structure is you have a small world, so everyone knows everyone within
like a friend's circle, but there are also these so-called hubs that actually, these
are the people that take part in different friend circles, and they connect these.
And it goes back to the Milgram experiment of small world where someone was sending Milgram,
he was sending letters around in the US, but you can't send them by post, you basically,
you get a letter with an address, and you should give it to the person that most likely
knows this person of your friend's circle.
And the funny thing was like over half of the letters actually reach the destination,
and if they reach the destination, they did it in like five, six steps.
Like from one US state to the other, completely unrelated.
Because there are these people that actually know a lot of people and connect a lot of
people, and if you find these, then actually the shortest path on this kind of graph is
very short.
On the other hand, the clustering coefficient, so the measure for how clicky these things
are is very high.
And this is a version for the neighboring co-occurrence where we actually only look
at the word to the left and to the right, and this is much sparser, but it also has
the same structure in the sense that words like your is actually connected to a lot of
other words.
I was talking about the significance measures, and actually I could also talk an entire lecture
about it, so there's about 150 of them that basically take these values, number of experiments,
number of figures with A, with B, and with A and B into account.
A simple one would be the joint frequency, so the significance of A and B is just how
often they occur together.
Not such a great idea, because some are more frequent than others, and this does not mean
that it's actually more surprising to see them together.
So one is point-wise mutual information, we have seen this one before, it's basically
comparing the, yeah, so you could write these as probabilities by dividing by n and then
reversing stuff, and what you're actually comparing is the probability of these occurring
together with respect to the probability of them co-occurring under independence assumption,
and then the question is, if this term is much higher than this one, then this gets
more significant, if they are the same, then there's no significance, because it's just
as expected, this is why we take the log, and so the log goes to zero if these are the
same.
Then people have noticed that this one has the problem of preferring to rare things,
so stuff like Sri Lanka, it's rare, and it only has one possible neighbour, then the
value is actually super high here, but it's a very rare term, so maybe we want to also
uprank frequent terms, and this is why we could just multiply this by the joint frequency,
and yeah, then there are super complex ones, like log-likelihood ratio, which is mathematically
related to the t-test, so actually you would get a p-value for that, saying what is the
actual probability for also rejecting the null hypothesis, and all these statistical
whatever, but practically in NLP what we use is frequency, PMI, or frequency times PMI,
which is LMI, this one is actually super correlated to this one, even though it looks much more
complex.
Yeah, and then we could look at these co-occurrence graphs, how they actually come about, so if
you look at the entire corpus would actually result into a co-occurrence graph of its entire
vocabulary, but of course you could just probe local neighbourhoods, so for example if you
probe the neighbourhood of sheep, then what you get here is goat, cows, cattle, livestock,
animals, pigs, horses, makes sense, animals occur with other animals, and this is a German
one for sausage, and it comes with other stuff you could eat, like deep-frozen pizzas and
beer, yeah, and I mean there has been a lot written about what actually the relationships
are covered here, because you kind of do this within sentences, so they should be
cinematic relations, so stuff that typically comes together in grammatical constructions,
but also what you find from, for example, enumerations is that you find a lot of animals
which are more like semantic relations, so the mix of syntactic and semantic relations
in these co-occurrence graphs, and this is like a basic notion, like there's not a lot
of stuff written about co-occurrence graphs as such, but there's a lot of work where co-occurrence
graphs are used for something, and this one use I want to talk about today is an approach called
text rank for keyword extraction, so what's the idea here? We want to find the most salient
keywords for a document, so if you want to summarise your document in five words, what would
these words be, and yeah, back in the days it was a very important thing to do, because libraries
would index their books or other documents not in a full text matter, but by keywords,
and then they would write these keywords on cards and put them in boxes, and then you could skim
through the box, and if you find like an entry there, you would know, okay, I should go and read
it or not, and it's stuff that was still in existence when I studied, and it's crazy how the
world is changing this, but yeah, keywords. Keywords are still used as like a pre-selector for
if you want to read a document, or you want to know whether you want to read it or not,
maybe you first check the keyword list, and maybe if it has an abstract, then you check the abstract,
and then if it still passes your threshold, then you can read it. Yeah, and we can also do this
with PageRank, and ideas the following. We make a co-occurrence graph, and we make an
co-occurrence graph only of the things that we're interested in, and for keywords, if you think
about the typical keywords, these are typically either nouns or noun phrases, so adjective noun,
combinations, compound noun, combinations. For example, keyword extraction is a compound noun,
right, because it has two nouns. An automatic keyword extraction would be a noun trace,
because it's an adjective automatic, and then keyword extraction. Yeah, so basically we only
care for adjectives and nouns, so for this we need a product speech tagger, I suppose, and then we
make a co-occurrence graph out of our document, which could look like this. We basically connect
nouns or adjectives if they appear together in a window of two words, of 10 words, whatever our
window is, and then we get this kind of graph, and on this graph we can apply PageRank. Why PageRank?
Yeah, because these are the important, say, concepts as named in our document,
but of course if something is named a lot, it would be neighbor of a lot of things,
and if something is neighbor of a neighbor which is named a lot, then it maybe is even more important.
So same idea again, but not on the basis of selecting sentences, but on the basis of selecting
important words, and yeah, then you need a little bit of a post-processing, so in case you have
selected things like linear and system in this case, and linear most certainly gets a high PageRank,
because it's kind of a hub. So if you would extract linear and system, then you shouldn't
do a keyword system and the keyword linear, but if you know that it appears as linear system,
then you write linear system. And to give you a kind of a feeling what comes out, so this was a
paper on linear, diophantine equations, a mathematical paper, and the human annotators
would say, oh yeah, this is about linear constraints, linear, diophantine equations,
minimal generating sets, non-strict in equations, sets of natural numbers, strict in equations,
and upper bounds. And the automatic system came back with linear constraints, linear,
diophantine equations, natural numbers, non-strict in equations, strict in equations, and upper bounds.
Not so bad, right? I mean, without reading the document, it's hard to tell what is actually
better. Usually humans are a little better, but it looks very similar, and also like keyword
assignment is a very subjective notion. So maybe this could have been done by a human as well.
Yeah, of course, you could also formally evaluate this. So what they did is vary a little bit
the parameters, the hyperparameters of the approach, and measure this on some, yeah,
collections of like scientific papers with keywords. Easy to get, you just download scientific
papers that have keywords. And so they tuned like the window size, so how many noun and adjectives
to the left and to the right should I look at? And they found for like the small windows, so like
less edges is actually better. And it's also there's no advantage to use this in a directed
fashion. So there's kind of you could assume maybe that something comes after something is different
than it comes before something, but not really. So like direction didn't, you know, take anything
into account. So they use an undirected graph, an undirected version of page rank. And they got
this number which is 36.2 f-measure, which is basically saying that around a third of the
original keywords were actually found by the computer. And of course, there might be keywords
from humans that are not even in the text, right? So it's kind of bound to what is in the text.
But the more interesting part about this one is that actually this was better than the best
supervised system at the time. So the best supervised system at the time
is, yeah, using engrams with attacks. So basically they would train a sequence classifier on, okay,
what was the keyword? I mark it in the text and then I train something that extracts keywords
just as named entities are just like part of speeches. And yeah, the system was actually
got more, but it was less precise. And now the interesting thing is like an unsupervised system.
So a system that was not even trained on keywords. It didn't ever use keywords to train the system,
right? It just gives them for evaluation. Was actually able to beat a supervised system
trained on the task. And yeah, again, the difference being that this was as an example
where a graph structure was used nicely because this kind of sequence tagging approach of just
looking in the local decision and looking, okay, is this a keyword thing because it appears in
a sentence where usually keywords appear is actually less powerful than something that
actually looks at the global structure, looks at the global structure of the document in this case
as represented by this kind of co-occurrence graph and takes the global structure into account.
So this is where graph algorithms actually shine, take the global structure of the problem into
account. Okay. Are there any questions, comments? Yep.
I'm pretty sure this dataset has been used in different, I'm not actually aware of this,
but I would assume that yes, they must have been advanced. I mean, this was like 15 years ago.
Yeah. Yeah. But it's actually, I mean, I wouldn't think there will be substantial advances on this
because I mean, it's a subjective task. So these numbers, they never will go up to 100%, right?
I don't know what is the human-human baseline. So you could check this by running humans against
each other. Maybe in this dataset, no. No, the dataset must be crawled just from the web, right?
So this would be interesting thing to try, but I don't think they have these numbers,
but I would expect maybe like a 50 or something. So yeah. But keyword extraction is something that
is on the decline because it's getting less and less important because the information access of
the aspect of this entire thing is just superseded by the whole full-text search and ranking.
So some academic papers don't even use keywords. Back in the days, they all had keywords and now
they're whole communities without keywords because why would you do that?
Okay. So maybe a little bit of a fast forward. So what are we going to do next is
graph clustering, basically looking for structure in graphs by cutting graphs apart into groups.
We're going to look at a Markov chain cluster, which is actually related to the random walker.
We're going to look at Chinese Whispers graph clustering, which is like a label
propagation algorithm and apply it to language separation. And yeah, then we're going to
revisit the distribution hypothesis and look at sense induction. So how do we actually find
the data table versus the furniture table? Okay. And with this, I would like to end as usual
with the immediate feedback and actually your feedback on the feedback made its way to the
feedback. So now you are allowed to leave a comment after you have answered this. And if
you don't leave a comment, it's also fine. But yes, please leave comments, especially if you
didn't like the lecture so much so I can know what to improve. So thank you very much for your
attention.