Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add BLEU Score #222

Merged
merged 18 commits into from
Jul 11, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Small fixes
  • Loading branch information
abheesht17 committed Jul 8, 2022
commit fa2c65818ac12634c492d3f80203e417d9cf6187
39 changes: 13 additions & 26 deletions keras_nlp/metrics/bleu.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
from tensorflow import keras

from keras_nlp.utils.tensor_utils import tensor_to_list
from keras_nlp.utils.tensor_utils import tensor_to_string_list

REPLACE_SUBSTRINGS = [
("<skipped>", ""),
Expand Down Expand Up @@ -67,18 +66,19 @@ class Bleu(keras.metrics.Metric):
https://cloud.google.com/translate/automl/docs/evaluate#bleu.

Note on input shapes:
`y_pred` can be a scalar (of shape `()`), or a dense tensor of shape
`(batch_size,)` or `(batch_size, 1)`. `y_true` can either be a dense tensor
of shape `(num_references,)`, or a ragged tensor of shapes
`(batch_size, None)` or `(batch_size, None, 1)`. This is because every
sample can have multiple references.
For unbatched inputs, `y_pred` should be a tensor of shape `()`, and
`y_true` should be a tensor of shape `(num_references,)`. For batched
inputs, `y_pred` should be a tensor of shape `(batch_size,)`,
and `y_true` should be a tensor of shape `(batch_size, num_references)`. In
case of batched inputs, `y_true` can also be of shape `(batch_size, None)`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a ragged tensor with shape (batch_size, None)

in case different samples have different number of references.

Args:
tokenizer: callable. A function that takes a string `tf.RaggedTensor`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happens it you pass a tokenizer layer here, will that work? Say byte tokenizer for simplicity.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmmm, it won't work with byte tokeniser because we use tensor_to_string_list in the code. Do you want me to change that?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should either support our tokenizers or not name this argument to something else.

Tokenizer means something specific in our library now, if we use that name but don't support our tokenizer class that is a bad look.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(of any shape), and tokenizes the strings in the tensor. This
function should use TensorFlow graph ops. If the tokenizer is not
specified, the default tokenizer is used. The default tokenizer
replicates the behaviour of SacreBLEU's `"tokenizer_13a"` tokenizer
(of any shape), and tokenizes the strings in the tensor. If the
tokenizer is not specified, the default tokenizer is used. The
default tokenizer replicates the behaviour of SacreBLEU's
`"tokenizer_13a"` tokenizer
(https://github.com/mjpost/sacrebleu/blob/v2.1.0/sacrebleu/tokenizers/tokenizer_13a.py).
max_order: int. The maximum n-gram order to use. For example, if
`max_order` is set to 3, unigrams, bigrams, and trigrams will be
Expand Down Expand Up @@ -116,13 +116,6 @@ def __init__(
)

self.tokenizer = tokenizer
try:
self.tokenizer = keras.utils.register_keras_serializable(
package="keras_nlp.metrics.Bleu", name="tokenizer"
)(self.tokenizer)
except:
pass

self.max_order = max_order
self.smooth = smooth

Expand Down Expand Up @@ -287,12 +280,8 @@ def _corpus_bleu(
)

def _calculate_bleu_score(self, references, translation):
if references.dtype == tf.string:
references = tensor_to_string_list(references)
translation = tensor_to_string_list(translation)
else:
references = tensor_to_list(references)
translation = tensor_to_list(translation)
references = tensor_to_list(references)
translation = tensor_to_list(translation)

matches = self._matches.numpy()
possible_matches = self._possible_matches.numpy()
Expand Down Expand Up @@ -388,9 +377,7 @@ def get_config(self):
config = super().get_config()
config.update(
{
"tokenizer": None
if self.tokenizer is None
else keras.utils.serialize_keras_object(self.tokenizer),
"tokenizer": self.tokenizer,
"max_order": self.max_order,
"smooth": self.smooth,
}
Expand Down
7 changes: 1 addition & 6 deletions keras_nlp/metrics/bleu_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -260,13 +260,8 @@ def test_get_config(self):
)

config = bleu.get_config()
self.assertIsInstance(
keras.utils.deserialize_keras_object(
identifier=config.pop("tokenizer"), module_objects=globals()
),
ByteTokenizer,
)
expected_config_subset = {
"tokenizer": byte_tokenizer,
"max_order": 8,
"smooth": True,
}
Expand Down