Xem trên TensorFlow.org | Chạy trong Google Colab | Xem nguồn trên GitHub | Tải xuống sổ ghi chép |
Giới thiệu
Các mô hình NLP thường xử lý các ngôn ngữ khác nhau với các bộ ký tự khác nhau. Unicode là một hệ thống mã hóa tiêu chuẩn được sử dụng để đại diện cho các nhân vật trong hầu hết các ngôn ngữ. Nhân vật mỗi Unicode được mã hóa bằng một số nguyên duy nhất điểm mã giữa 0
và 0x10FFFF
. Một Unicode chuỗi là một chuỗi các số không hay nhiều điểm mã.
Hướng dẫn này chỉ ra cách biểu diễn các chuỗi Unicode trong TensorFlow và thao tác với chúng bằng cách sử dụng các mã Unicode tương đương với các mã chuỗi chuẩn. Nó phân tách các chuỗi Unicode thành các mã thông báo dựa trên việc phát hiện tập lệnh.
import tensorflow as tf
import numpy as np
Các tf.string
kiểu dữ liệu
Các cơ bản TensorFlow tf.string
dtype
phép bạn xây dựng tensors các chuỗi byte. Chuỗi Unicode là utf-8 mã hóa theo mặc định.
tf.constant(u"Thanks 😊")
<tf.Tensor: shape=(), dtype=string, numpy=b'Thanks \xf0\x9f\x98\x8a'>
Một tf.string
xử lý tensor byte chuỗi như đơn vị nguyên tử. Điều này cho phép nó lưu trữ các chuỗi byte có độ dài khác nhau. Chiều dài chuỗi không được bao gồm trong kích thước tensor.
tf.constant([u"You're", u"welcome!"]).shape
TensorShape([2])
Nếu bạn sử dụng Python để chuỗi xây dựng, lưu ý rằng literals chuỗi là Unicode được mã hóa theo mặc định.
Biểu diễn Unicode
Có hai cách tiêu chuẩn để biểu diễn một chuỗi Unicode trong TensorFlow:
-
string
vô hướng - nơi chuỗi các điểm mã được mã hóa bằng cách sử dụng biết mã hóa ký tự . -
int32
vector - nơi mỗi vị trí chứa một điểm mã duy nhất.
Ví dụ, ba giá trị sau tất cả đại diện cho chuỗi Unicode "语言处理"
(mà có nghĩa là "xử lý ngôn ngữ" trong tiếng Trung Quốc):
# Unicode string, represented as a UTF-8 encoded string scalar.
text_utf8 = tf.constant(u"语言处理")
text_utf8
<tf.Tensor: shape=(), dtype=string, numpy=b'\xe8\xaf\xad\xe8\xa8\x80\xe5\xa4\x84\xe7\x90\x86'>
# Unicode string, represented as a UTF-16-BE encoded string scalar.
text_utf16be = tf.constant(u"语言处理".encode("UTF-16-BE"))
text_utf16be
<tf.Tensor: shape=(), dtype=string, numpy=b'\x8b\xed\x8a\x00Y\x04t\x06'>
# Unicode string, represented as a vector of Unicode code points.
text_chars = tf.constant([ord(char) for char in u"语言处理"])
text_chars
<tf.Tensor: shape=(4,), dtype=int32, numpy=array([35821, 35328, 22788, 29702], dtype=int32)>
Chuyển đổi giữa các đại diện
TensorFlow cung cấp các hoạt động để chuyển đổi giữa các biểu diễn khác nhau này:
-
tf.strings.unicode_decode
: Chuyển đổi một chuỗi vô hướng được mã hóa với một vector của điểm mã. -
tf.strings.unicode_encode
: Chuyển đổi một vector của điểm mã để một chuỗi vô hướng được mã hóa. -
tf.strings.unicode_transcode
: Chuyển đổi một chuỗi vô hướng được mã hóa để mã hóa khác nhau.
tf.strings.unicode_decode(text_utf8,
input_encoding='UTF-8')
<tf.Tensor: shape=(4,), dtype=int32, numpy=array([35821, 35328, 22788, 29702], dtype=int32)>
tf.strings.unicode_encode(text_chars,
output_encoding='UTF-8')
<tf.Tensor: shape=(), dtype=string, numpy=b'\xe8\xaf\xad\xe8\xa8\x80\xe5\xa4\x84\xe7\x90\x86'>
tf.strings.unicode_transcode(text_utf8,
input_encoding='UTF8',
output_encoding='UTF-16-BE')
<tf.Tensor: shape=(), dtype=string, numpy=b'\x8b\xed\x8a\x00Y\x04t\x06'>
Kích thước lô
Khi giải mã nhiều chuỗi, số ký tự trong mỗi chuỗi có thể không bằng nhau. Kết quả trả về là một tf.RaggedTensor
, nơi chiều dài chiều trong cùng khác nhau tùy thuộc vào số lượng ký tự trong mỗi chuỗi.
# A batch of Unicode strings, each represented as a UTF8-encoded string.
batch_utf8 = [s.encode('UTF-8') for s in
[u'hÃllo', u'What is the weather tomorrow', u'Göödnight', u'😊']]
batch_chars_ragged = tf.strings.unicode_decode(batch_utf8,
input_encoding='UTF-8')
for sentence_chars in batch_chars_ragged.to_list():
print(sentence_chars)
[104, 195, 108, 108, 111] [87, 104, 97, 116, 32, 105, 115, 32, 116, 104, 101, 32, 119, 101, 97, 116, 104, 101, 114, 32, 116, 111, 109, 111, 114, 114, 111, 119] [71, 246, 246, 100, 110, 105, 103, 104, 116] [128522]
Bạn có thể sử dụng này tf.RaggedTensor
trực tiếp, hoặc chuyển nó sang một dày đặc tf.Tensor
với đệm hoặc một tf.SparseTensor
bằng cách sử dụng phương pháp tf.RaggedTensor.to_tensor
và tf.RaggedTensor.to_sparse
.
batch_chars_padded = batch_chars_ragged.to_tensor(default_value=-1)
print(batch_chars_padded.numpy())
[[ 104 195 108 108 111 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1] [ 87 104 97 116 32 105 115 32 116 104 101 32 119 101 97 116 104 101 114 32 116 111 109 111 114 114 111 119] [ 71 246 246 100 110 105 103 104 116 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1] [128522 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1]]
batch_chars_sparse = batch_chars_ragged.to_sparse()
nrows, ncols = batch_chars_sparse.dense_shape.numpy()
elements = [['_' for i in range(ncols)] for j in range(nrows)]
for (row, col), value in zip(batch_chars_sparse.indices.numpy(), batch_chars_sparse.values.numpy()):
elements[row][col] = str(value)
# max_width = max(len(value) for row in elements for value in row)
value_lengths = []
for row in elements:
for value in row:
value_lengths.append(len(value))
max_width = max(value_lengths)
print('[%s]' % '\n '.join(
'[%s]' % ', '.join(value.rjust(max_width) for value in row)
for row in elements))
[[ 104, 195, 108, 108, 111, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _] [ 87, 104, 97, 116, 32, 105, 115, 32, 116, 104, 101, 32, 119, 101, 97, 116, 104, 101, 114, 32, 116, 111, 109, 111, 114, 114, 111, 119] [ 71, 246, 246, 100, 110, 105, 103, 104, 116, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _] [128522, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _]]
Khi mã hóa nhiều chuỗi với độ dài tương tự, sử dụng một tf.Tensor
như đầu vào.
tf.strings.unicode_encode([[99, 97, 116], [100, 111, 103], [99, 111, 119]],
output_encoding='UTF-8')
<tf.Tensor: shape=(3,), dtype=string, numpy=array([b'cat', b'dog', b'cow'], dtype=object)>
Khi mã hóa nhiều chuỗi có chiều dài khác nhau, sử dụng một tf.RaggedTensor
như đầu vào.
tf.strings.unicode_encode(batch_chars_ragged, output_encoding='UTF-8')
<tf.Tensor: shape=(4,), dtype=string, numpy= array([b'h\xc3\x83llo', b'What is the weather tomorrow', b'G\xc3\xb6\xc3\xb6dnight', b'\xf0\x9f\x98\x8a'], dtype=object)>
Nếu bạn có một tensor với nhiều chuỗi trong định dạng đệm hoặc thưa thớt, chuyển đổi nó lần đầu tiên vào một tf.RaggedTensor
trước khi gọi tf.strings.unicode_encode
.
tf.strings.unicode_encode(
tf.RaggedTensor.from_sparse(batch_chars_sparse),
output_encoding='UTF-8')
<tf.Tensor: shape=(4,), dtype=string, numpy= array([b'h\xc3\x83llo', b'What is the weather tomorrow', b'G\xc3\xb6\xc3\xb6dnight', b'\xf0\x9f\x98\x8a'], dtype=object)>
tf.strings.unicode_encode(
tf.RaggedTensor.from_tensor(batch_chars_padded, padding=-1),
output_encoding='UTF-8')
<tf.Tensor: shape=(4,), dtype=string, numpy= array([b'h\xc3\x83llo', b'What is the weather tomorrow', b'G\xc3\xb6\xc3\xb6dnight', b'\xf0\x9f\x98\x8a'], dtype=object)>
Hoạt động Unicode
Độ dài ký tự
Sử dụng các unit
tham số của tf.strings.length
op để chỉ cách độ dài vật cần được tính. unit
mặc định là "BYTE"
, nhưng nó có thể được thiết lập để các giá trị khác, chẳng hạn như "UTF8_CHAR"
hoặc "UTF16_CHAR"
, để xác định số lượng codepoints Unicode trong mỗi chuỗi được mã hóa.
# Note that the final character takes up 4 bytes in UTF8.
thanks = u'Thanks 😊'.encode('UTF-8')
num_bytes = tf.strings.length(thanks).numpy()
num_chars = tf.strings.length(thanks, unit='UTF8_CHAR').numpy()
print('{} bytes; {} UTF-8 characters'.format(num_bytes, num_chars))
11 bytes; 8 UTF-8 characters
Chuỗi ký tự con
Các tf.strings.substr
op chấp nhận unit
tham số, và sử dụng nó để xác định loại offsets các pos
và len
paremeters chứa.
# Here, unit='BYTE' (default). Returns a single byte with len=1
tf.strings.substr(thanks, pos=7, len=1).numpy()
b'\xf0'
# Specifying unit='UTF8_CHAR', returns a single 4 byte character in this case
print(tf.strings.substr(thanks, pos=7, len=1, unit='UTF8_CHAR').numpy())
b'\xf0\x9f\x98\x8a'
Chia chuỗi Unicode
Các tf.strings.unicode_split
hoạt động chia tách chuỗi unicode vào chuỗi con của các nhân vật cá nhân.
tf.strings.unicode_split(thanks, 'UTF-8').numpy()
array([b'T', b'h', b'a', b'n', b'k', b's', b' ', b'\xf0\x9f\x98\x8a'], dtype=object)
Hiệu số byte cho các ký tự
Để sắp xếp các tensor nhân vật được tạo ra bởi tf.strings.unicode_decode
với chuỗi gốc, nó là hữu ích để biết bù đắp cho nơi mà mỗi nhân vật bắt đầu. Phương pháp tf.strings.unicode_decode_with_offsets
cũng tương tự như unicode_decode
, ngoại trừ việc nó trả về một tensor thứ hai chứa đầu bù đắp của mỗi nhân vật.
codepoints, offsets = tf.strings.unicode_decode_with_offsets(u'🎈🎉🎊', 'UTF-8')
for (codepoint, offset) in zip(codepoints.numpy(), offsets.numpy()):
print('At byte offset {}: codepoint {}'.format(offset, codepoint))
At byte offset 0: codepoint 127880 At byte offset 4: codepoint 127881 At byte offset 8: codepoint 127882
Tập lệnh Unicode
Mỗi mã Unicode điểm thuộc về một bộ sưu tập duy nhất của codepoints biết đến như một kịch bản . Chữ viết của một ký tự rất hữu ích trong việc xác định ngôn ngữ mà nhân vật có thể sử dụng. Ví dụ: khi biết rằng 'Б' là trong hệ thống chữ viết Kirin cho biết rằng văn bản hiện đại chứa ký tự đó có thể là từ ngôn ngữ Slav như tiếng Nga hoặc tiếng Ukraina.
TensorFlow cung cấp tf.strings.unicode_script
hoạt động để xác định kịch bản một dụng điểm mã nhất định. Các mã kịch bản là int32
giá trị tương ứng với các thành phần quốc tế Unicode (ICU) UScriptCode
giá trị.
uscript = tf.strings.unicode_script([33464, 1041]) # ['芸', 'Б']
print(uscript.numpy()) # [17, 8] == [USCRIPT_HAN, USCRIPT_CYRILLIC]
[17 8]
Các tf.strings.unicode_script
hoạt động cũng có thể được áp dụng cho đa chiều tf.Tensor
s hoặc tf.RaggedTensor
s của codepoints:
print(tf.strings.unicode_script(batch_chars_ragged))
<tf.RaggedTensor [[25, 25, 25, 25, 25], [25, 25, 25, 25, 0, 25, 25, 0, 25, 25, 25, 0, 25, 25, 25, 25, 25, 25, 25, 0, 25, 25, 25, 25, 25, 25, 25, 25], [25, 25, 25, 25, 25, 25, 25, 25, 25], [0]]>
Ví dụ: Phân đoạn đơn giản
Phân đoạn là nhiệm vụ chia nhỏ văn bản thành các đơn vị giống như từ. Điều này thường dễ dàng khi các ký tự khoảng trắng được sử dụng để phân tách các từ, nhưng một số ngôn ngữ (như tiếng Trung và tiếng Nhật) không sử dụng dấu cách và một số ngôn ngữ (như tiếng Đức) chứa các hợp chất dài phải được tách ra để phân tích ý nghĩa của chúng. Trong văn bản web, các ngôn ngữ và chữ viết khác nhau thường được trộn lẫn với nhau, như trong "NY 株 価" (Sở giao dịch chứng khoán New York).
Chúng tôi có thể thực hiện phân đoạn rất thô (mà không thực hiện bất kỳ mô hình ML nào) bằng cách sử dụng các thay đổi trong tập lệnh để ước lượng ranh giới từ. Điều này sẽ hoạt động đối với các chuỗi như ví dụ "NY 株 価" ở trên. Nó cũng sẽ hoạt động đối với hầu hết các ngôn ngữ sử dụng dấu cách, vì các ký tự khoảng trắng của các tập lệnh khác nhau đều được phân loại là USCRIPT_COMMON, một mã tập lệnh đặc biệt khác với mã của bất kỳ văn bản thực tế nào.
# dtype: string; shape: [num_sentences]
#
# The sentences to process. Edit this line to try out different inputs!
sentence_texts = [u'Hello, world.', u'世界こんにちは']
Đầu tiên, hãy giải mã các câu thành các điểm mã ký tự và tìm mã nhận dạng tập lệnh cho mỗi ký tự.
# dtype: int32; shape: [num_sentences, (num_chars_per_sentence)]
#
# sentence_char_codepoint[i, j] is the codepoint for the j'th character in
# the i'th sentence.
sentence_char_codepoint = tf.strings.unicode_decode(sentence_texts, 'UTF-8')
print(sentence_char_codepoint)
# dtype: int32; shape: [num_sentences, (num_chars_per_sentence)]
#
# sentence_char_scripts[i, j] is the Unicode script of the j'th character in
# the i'th sentence.
sentence_char_script = tf.strings.unicode_script(sentence_char_codepoint)
print(sentence_char_script)
<tf.RaggedTensor [[72, 101, 108, 108, 111, 44, 32, 119, 111, 114, 108, 100, 46], [19990, 30028, 12371, 12435, 12395, 12385, 12399]]> <tf.RaggedTensor [[25, 25, 25, 25, 25, 0, 0, 25, 25, 25, 25, 25, 0], [17, 17, 20, 20, 20, 20, 20]]>
Sử dụng các mã nhận dạng tập lệnh để xác định vị trí các ranh giới từ sẽ được thêm vào. Thêm ranh giới từ ở đầu mỗi câu và cho mỗi ký tự có chữ viết khác với ký tự trước đó.
# dtype: bool; shape: [num_sentences, (num_chars_per_sentence)]
#
# sentence_char_starts_word[i, j] is True if the j'th character in the i'th
# sentence is the start of a word.
sentence_char_starts_word = tf.concat(
[tf.fill([sentence_char_script.nrows(), 1], True),
tf.not_equal(sentence_char_script[:, 1:], sentence_char_script[:, :-1])],
axis=1)
# dtype: int64; shape: [num_words]
#
# word_starts[i] is the index of the character that starts the i'th word (in
# the flattened list of characters from all sentences).
word_starts = tf.squeeze(tf.where(sentence_char_starts_word.values), axis=1)
print(word_starts)
tf.Tensor([ 0 5 7 12 13 15], shape=(6,), dtype=int64)
Sau đó bạn có thể sử dụng những hiệu số bắt đầu xây dựng một RaggedTensor
chứa danh sách các từ từ tất cả các lô.
# dtype: int32; shape: [num_words, (num_chars_per_word)]
#
# word_char_codepoint[i, j] is the codepoint for the j'th character in the
# i'th word.
word_char_codepoint = tf.RaggedTensor.from_row_starts(
values=sentence_char_codepoint.values,
row_starts=word_starts)
print(word_char_codepoint)
<tf.RaggedTensor [[72, 101, 108, 108, 111], [44, 32], [119, 111, 114, 108, 100], [46], [19990, 30028], [12371, 12435, 12395, 12385, 12399]]>
Để kết thúc, phân khúc từ codepoints RaggedTensor
trở thành câu và mã hóa thành UTF 8-strings cho dễ đọc.
# dtype: int64; shape: [num_sentences]
#
# sentence_num_words[i] is the number of words in the i'th sentence.
sentence_num_words = tf.reduce_sum(
tf.cast(sentence_char_starts_word, tf.int64),
axis=1)
# dtype: int32; shape: [num_sentences, (num_words_per_sentence), (num_chars_per_word)]
#
# sentence_word_char_codepoint[i, j, k] is the codepoint for the k'th character
# in the j'th word in the i'th sentence.
sentence_word_char_codepoint = tf.RaggedTensor.from_row_lengths(
values=word_char_codepoint,
row_lengths=sentence_num_words)
print(sentence_word_char_codepoint)
tf.strings.unicode_encode(sentence_word_char_codepoint, 'UTF-8').to_list()
<tf.RaggedTensor [[[72, 101, 108, 108, 111], [44, 32], [119, 111, 114, 108, 100], [46]], [[19990, 30028], [12371, 12435, 12395, 12385, 12399]]]> [[b'Hello', b', ', b'world', b'.'], [b'\xe4\xb8\x96\xe7\x95\x8c', b'\xe3\x81\x93\xe3\x82\x93\xe3\x81\xab\xe3\x81\xa1\xe3\x81\xaf']]