{ "cells": [ { "cell_type": "markdown", "metadata": { "id": "oL9KopJirB2g" }, "source": [ "##### Copyright 2018 The TensorFlow Authors." ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "cellView": "form", "execution": { "iopub.execute_input": "2022-12-15T01:12:12.776064Z", "iopub.status.busy": "2022-12-15T01:12:12.775508Z", "iopub.status.idle": "2022-12-15T01:12:12.779648Z", "shell.execute_reply": "2022-12-15T01:12:12.779064Z" }, "id": "SKaX3Hd3ra6C" }, "outputs": [], "source": [ "#@title Licensed under the Apache License, Version 2.0 (the \"License\");\n", "# you may not use this file except in compliance with the License.\n", "# You may obtain a copy of the License at\n", "#\n", "# https://www.apache.org/licenses/LICENSE-2.0\n", "#\n", "# Unless required by applicable law or agreed to in writing, software\n", "# distributed under the License is distributed on an \"AS IS\" BASIS,\n", "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n", "# See the License for the specific language governing permissions and\n", "# limitations under the License." ] }, { "cell_type": "markdown", "metadata": { "id": "AXH1bmUctMld" }, "source": [ "# Unicode 文字列\n", "\n", "\n", " \n", " \n", " \n", " \n", "
\n", " View on TensorFlow.org\n", " \n", " Run in Google Colab\n", " \n", " View source on GitHub\n", " \n", " Download notebook\n", "
" ] }, { "cell_type": "markdown", "metadata": { "id": "pBjKi-NuLuu-" }, "source": [ "Note: これらのドキュメントは私たちTensorFlowコミュニティが翻訳したものです。コミュニティによる 翻訳は**ベストエフォート**であるため、この翻訳が正確であることや[英語の公式ドキュメント](https://www.tensorflow.org/?hl=en)の 最新の状態を反映したものであることを保証することはできません。 この翻訳の品質を向上させるためのご意見をお持ちの方は、GitHubリポジトリ[tensorflow/docs](https://github.com/tensorflow/docs)にプルリクエストをお送りください。 コミュニティによる翻訳やレビューに参加していただける方は、 [docs-ja@tensorflow.org メーリングリスト](https://groups.google.com/a/tensorflow.org/forum/#!forum/docs-ja)にご連絡ください。" ] }, { "cell_type": "markdown", "metadata": { "id": "Af1825RvY12H" }, "source": [ "## はじめに\n", "\n", "自然言語モデルは、しばしば異なる文字セットを使った異なる言語を扱います。 *Unicode*は、ほぼすべての言語で文字表示に使われている標準的なエンコードの仕組みです。各文字は、`0` から`0x10FFFF`までの一意の整数の [コードポイント(符号位置)](https://ja.wikipedia.org/wiki/%E7%AC%A6%E5%8F%B7%E7%82%B9) を使ってエンコードされます。1つの *Unicode文字列*は、ゼロ個以上のコードポイントのシーケンスです。\n", "\n", "このチュートリアルでは、TensorFlow での Unicode文字列の表現方法と、どうやって Unicode で標準的な文字列操作と同様の操作を行うかについて示します。また、スクリプト検出にもとづいて Unicode 文字列をトークンに分解します。" ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "execution": { "iopub.execute_input": "2022-12-15T01:12:12.783186Z", "iopub.status.busy": "2022-12-15T01:12:12.782953Z", "iopub.status.idle": "2022-12-15T01:12:14.819459Z", "shell.execute_reply": "2022-12-15T01:12:14.818649Z" }, "id": "OIKHl5Lvn4gh" }, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "2022-12-15 01:12:13.773684: W tensorflow/compiler/xla/stream_executor/platform/default/dso_loader.cc:64] Could not load dynamic library 'libnvinfer.so.7'; dlerror: libnvinfer.so.7: cannot open shared object file: No such file or directory\n", "2022-12-15 01:12:13.773778: W tensorflow/compiler/xla/stream_executor/platform/default/dso_loader.cc:64] Could not load dynamic library 'libnvinfer_plugin.so.7'; dlerror: libnvinfer_plugin.so.7: cannot open shared object file: No such file or directory\n", "2022-12-15 01:12:13.773788: W tensorflow/compiler/tf2tensorrt/utils/py_utils.cc:38] TF-TRT Warning: Cannot dlopen some TensorRT libraries. If you would like to use Nvidia GPU with TensorRT, please make sure the missing libraries mentioned above are installed properly.\n" ] } ], "source": [ "import tensorflow as tf" ] }, { "cell_type": "markdown", "metadata": { "id": "IL02urquDLZT" }, "source": [ "## `tf.string` データ型\n", "\n", "標準的な TensorFlow の`tf.string`型は、バイト列のテンソルを作ります。また、Unicode文字列はデフォルトでは utf-8 でエンコードされます。" ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "execution": { "iopub.execute_input": "2022-12-15T01:12:14.824029Z", "iopub.status.busy": "2022-12-15T01:12:14.823171Z", "iopub.status.idle": "2022-12-15T01:12:18.363736Z", "shell.execute_reply": "2022-12-15T01:12:18.363061Z" }, "id": "3yo-Qv6ntaFr" }, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "tf.constant(u\"Thanks 😊\")" ] }, { "cell_type": "markdown", "metadata": { "id": "VRTWK-pGnxNb" }, "source": [ "バイト列が最小限の単位として扱われるため、`tf.string` 型のテンソルは可変長のバイト文字列を保持できます。また、文字列長はテンソルの次元には含まれません。" ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "execution": { "iopub.execute_input": "2022-12-15T01:12:18.367942Z", "iopub.status.busy": "2022-12-15T01:12:18.367354Z", "iopub.status.idle": "2022-12-15T01:12:18.372284Z", "shell.execute_reply": "2022-12-15T01:12:18.371651Z" }, "id": "eyINCmTztyyS" }, "outputs": [ { "data": { "text/plain": [ "TensorShape([2])" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "tf.constant([u\"You're\", u\"welcome!\"]).shape" ] }, { "cell_type": "markdown", "metadata": { "id": "jvnHXc5w_-g6" }, "source": [ "注 : Pythonを使って文字列を構成するとき、v2.x系とv3.x系では Unicode の扱いが異なります。v2.x系では、Unicode文字列は上記のようにプレフィックス \"u\" で明示します。v3.x系では、デフォルトで Unicode としてエンコードされます。" ] }, { "cell_type": "markdown", "metadata": { "id": "NYyIwTTu6tn8" }, "source": [ "## Unicode 表現\n", "\n", "TensorFlow での Unicode文字列表現は、2つの標準的な方法があります:\n", "\n", "* `string` スカラー — コードポイントのシーケンスは既知の [文字符合化方式](https://ja.wikipedia.org/wiki/%E6%96%87%E5%AD%97%E7%AC%A6%E5%8F%B7%E5%8C%96%E6%96%B9%E5%BC%8F) でエンコードされる\n", "* `int32` ベクトル — 各文字には単一のコードポイントが入る\n", "\n", "たとえば、以下3つはすべて Unicode文字列 `\"语言処理 \"`(中国語で「言語処理」を意味します)を表します。" ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "execution": { "iopub.execute_input": "2022-12-15T01:12:18.375695Z", "iopub.status.busy": "2022-12-15T01:12:18.375209Z", "iopub.status.idle": "2022-12-15T01:12:18.379828Z", "shell.execute_reply": "2022-12-15T01:12:18.379209Z" }, "id": "cjQIkfJWvC_u" }, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Unicode文字列。UTF-8にエンコードされた文字列スカラーとして表される\n", "text_utf8 = tf.constant(u\"语言处理\")\n", "text_utf8" ] }, { "cell_type": "code", "execution_count": 6, "metadata": { "execution": { "iopub.execute_input": "2022-12-15T01:12:18.383402Z", "iopub.status.busy": "2022-12-15T01:12:18.382800Z", "iopub.status.idle": "2022-12-15T01:12:18.387885Z", "shell.execute_reply": "2022-12-15T01:12:18.387298Z" }, "id": "yQqcUECcvF2r" }, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Unicode文字列。UTF-16-BEにエンコードされた文字列スカラーとして表される\n", "text_utf16be = tf.constant(u\"语言处理\".encode(\"UTF-16-BE\"))\n", "text_utf16be" ] }, { "cell_type": "code", "execution_count": 7, "metadata": { "execution": { "iopub.execute_input": "2022-12-15T01:12:18.390829Z", "iopub.status.busy": "2022-12-15T01:12:18.390339Z", "iopub.status.idle": "2022-12-15T01:12:18.396490Z", "shell.execute_reply": "2022-12-15T01:12:18.395942Z" }, "id": "ExdBr1t7vMuS" }, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Unicode文字列。Unicodeコードポイントのベクトルとして表される\n", "text_chars = tf.constant([ord(char) for char in u\"语言处理\"])\n", "text_chars" ] }, { "cell_type": "markdown", "metadata": { "id": "aSLBp5zG1FNb" }, "source": [ "### Unicode 表現間の変換\n", "\n", "TensorFlowでは、これらの異なる Unicode 表現間で変換する方法を用意しています。\n", "\n", "* `tf.strings.unicode_decode`:エンコードされた文字列スカラーを、コードポイントのベクトルに変換します。\n", "* `tf.strings.unicode_encode`:コードポイントのベクトルを、エンコードされた文字列スカラーに変換します。\n", "* `tf.strings.unicode_transcode`:エンコードされた文字列スカラーを、別の文字コードに再エンコードします。" ] }, { "cell_type": "code", "execution_count": 8, "metadata": { "execution": { "iopub.execute_input": "2022-12-15T01:12:18.399718Z", "iopub.status.busy": "2022-12-15T01:12:18.399130Z", "iopub.status.idle": "2022-12-15T01:12:18.406897Z", "shell.execute_reply": "2022-12-15T01:12:18.406346Z" }, "id": "qb-UQ_oLpAJg" }, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "tf.strings.unicode_decode(text_utf8,\n", " input_encoding='UTF-8')" ] }, { "cell_type": "code", "execution_count": 9, "metadata": { "execution": { "iopub.execute_input": "2022-12-15T01:12:18.410070Z", "iopub.status.busy": "2022-12-15T01:12:18.409466Z", "iopub.status.idle": "2022-12-15T01:12:18.420752Z", "shell.execute_reply": "2022-12-15T01:12:18.420194Z" }, "id": "kEBUcunnp-9n" }, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "tf.strings.unicode_encode(text_chars,\n", " output_encoding='UTF-8')" ] }, { "cell_type": "code", "execution_count": 10, "metadata": { "execution": { "iopub.execute_input": "2022-12-15T01:12:18.424028Z", "iopub.status.busy": "2022-12-15T01:12:18.423340Z", "iopub.status.idle": "2022-12-15T01:12:18.428595Z", "shell.execute_reply": "2022-12-15T01:12:18.427971Z" }, "id": "0MLhWcLZrph-" }, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "tf.strings.unicode_transcode(text_utf8,\n", " input_encoding='UTF8',\n", " output_encoding='UTF-16-BE')" ] }, { "cell_type": "markdown", "metadata": { "id": "-97__BLzsodr" }, "source": [ "### バッチの次元\n", "\n", "複数の文字列をデコードする場合、各文字列の文字数が等しくない場合があります。返される結果は[`tf.RaggedTensor`](../../guide/ragged_tensor.ipynb)であり、最も内側の次元の長さは各文字列の文字数によって異なります。:" ] }, { "cell_type": "code", "execution_count": 11, "metadata": { "execution": { "iopub.execute_input": "2022-12-15T01:12:18.431929Z", "iopub.status.busy": "2022-12-15T01:12:18.431467Z", "iopub.status.idle": "2022-12-15T01:12:18.437420Z", "shell.execute_reply": "2022-12-15T01:12:18.436793Z" }, "id": "N2jVzPymr_Mm" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[104, 195, 108, 108, 111]\n", "[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]\n", "[71, 246, 246, 100, 110, 105, 103, 104, 116]\n", "[128522]\n" ] } ], "source": [ "# Unicode文字列のバッチ。それぞれが、UTF8にエンコードされた文字列として表される\n", "batch_utf8 = [s.encode('UTF-8') for s in\n", " [u'hÃllo', u'What is the weather tomorrow', u'Göödnight', u'😊']]\n", "batch_chars_ragged = tf.strings.unicode_decode(batch_utf8,\n", " input_encoding='UTF-8')\n", "for sentence_chars in batch_chars_ragged.to_list():\n", " print(sentence_chars)" ] }, { "cell_type": "markdown", "metadata": { "id": "XBcscZtonorZ" }, "source": [ "この `tf.RaggedTensor` を直接使用することも、`tf.RaggedTensor.to_tensor` メソッドを使ってパディングを追加した密な `tf.Tensor` に変換するか、あるいは `tf.RaggedTensor.to_sparse` メソッドを使って `tf.SparseTensor` に変換することもできます。" ] }, { "cell_type": "code", "execution_count": 12, "metadata": { "execution": { "iopub.execute_input": "2022-12-15T01:12:18.440884Z", "iopub.status.busy": "2022-12-15T01:12:18.440397Z", "iopub.status.idle": "2022-12-15T01:12:18.448088Z", "shell.execute_reply": "2022-12-15T01:12:18.447398Z" }, "id": "yz17yeSMsUid" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[[ 104 195 108 108 111 -1 -1 -1 -1 -1\n", " -1 -1 -1 -1 -1 -1 -1 -1 -1 -1\n", " -1 -1 -1 -1 -1 -1 -1 -1]\n", " [ 87 104 97 116 32 105 115 32 116 104\n", " 101 32 119 101 97 116 104 101 114 32\n", " 116 111 109 111 114 114 111 119]\n", " [ 71 246 246 100 110 105 103 104 116 -1\n", " -1 -1 -1 -1 -1 -1 -1 -1 -1 -1\n", " -1 -1 -1 -1 -1 -1 -1 -1]\n", " [128522 -1 -1 -1 -1 -1 -1 -1 -1 -1\n", " -1 -1 -1 -1 -1 -1 -1 -1 -1 -1\n", " -1 -1 -1 -1 -1 -1 -1 -1]]\n" ] } ], "source": [ "batch_chars_padded = batch_chars_ragged.to_tensor(default_value=-1)\n", "print(batch_chars_padded.numpy())" ] }, { "cell_type": "code", "execution_count": 13, "metadata": { "execution": { "iopub.execute_input": "2022-12-15T01:12:18.451464Z", "iopub.status.busy": "2022-12-15T01:12:18.450942Z", "iopub.status.idle": "2022-12-15T01:12:18.455771Z", "shell.execute_reply": "2022-12-15T01:12:18.455027Z" }, "id": "kBjsPQp3rhfm" }, "outputs": [], "source": [ "batch_chars_sparse = batch_chars_ragged.to_sparse()" ] }, { "cell_type": "markdown", "metadata": { "id": "5Knn5d2vlaSa" }, "source": [ "同じ長さの複数の文字列をエンコードする場合、`tf.Tensor` を入力値として使用できます。" ] }, { "cell_type": "code", "execution_count": 14, "metadata": { "execution": { "iopub.execute_input": "2022-12-15T01:12:18.459468Z", "iopub.status.busy": "2022-12-15T01:12:18.458773Z", "iopub.status.idle": "2022-12-15T01:12:18.482224Z", "shell.execute_reply": "2022-12-15T01:12:18.481463Z" }, "id": "_lP62YUAwjK9" }, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "source": [ "tf.strings.unicode_encode([[99, 97, 116], [100, 111, 103], [ 99, 111, 119]],\n", " output_encoding='UTF-8')" ] }, { "cell_type": "markdown", "metadata": { "id": "OWvHCR-tN6fE" }, "source": [ "可変長の複数の文字列をエンコードする場合、`tf.RaggedTensor` を入力値として使用する必要があります。" ] }, { "cell_type": "code", "execution_count": 15, "metadata": { "execution": { "iopub.execute_input": "2022-12-15T01:12:18.486305Z", "iopub.status.busy": "2022-12-15T01:12:18.485511Z", "iopub.status.idle": "2022-12-15T01:12:18.491030Z", "shell.execute_reply": "2022-12-15T01:12:18.490399Z" }, "id": "d7GtOtrltaMl" }, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 15, "metadata": {}, "output_type": "execute_result" } ], "source": [ "tf.strings.unicode_encode(batch_chars_ragged, output_encoding='UTF-8')" ] }, { "cell_type": "markdown", "metadata": { "id": "X0lsFTJENl37" }, "source": [ "パディングされた、あるいはスパースな複数の文字列を含むテンソルがある場合は、`unicode_encode` を呼び出す前に `tf.RaggedTensor` に変換します。" ] }, { "cell_type": "code", "execution_count": 16, "metadata": { "execution": { "iopub.execute_input": "2022-12-15T01:12:18.494684Z", "iopub.status.busy": "2022-12-15T01:12:18.494044Z", "iopub.status.idle": "2022-12-15T01:12:18.538041Z", "shell.execute_reply": "2022-12-15T01:12:18.537344Z" }, "id": "R2bYCYl0u-Ue" }, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" } ], "source": [ "tf.strings.unicode_encode(\n", " tf.RaggedTensor.from_sparse(batch_chars_sparse),\n", " output_encoding='UTF-8')" ] }, { "cell_type": "code", "execution_count": 17, "metadata": { "execution": { "iopub.execute_input": "2022-12-15T01:12:18.541574Z", "iopub.status.busy": "2022-12-15T01:12:18.540915Z", "iopub.status.idle": "2022-12-15T01:12:18.584743Z", "shell.execute_reply": "2022-12-15T01:12:18.584016Z" }, "id": "UlV2znh_u_zm" }, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ "tf.strings.unicode_encode(\n", " tf.RaggedTensor.from_tensor(batch_chars_padded, padding=-1),\n", " output_encoding='UTF-8')" ] }, { "cell_type": "markdown", "metadata": { "id": "Nps-h5lToJZq" }, "source": [ "## Unicode 操作" ] }, { "cell_type": "markdown", "metadata": { "id": "NkmtsA_yvMB0" }, "source": [ "### 文字列長\n", "\n", "`tf.strings.length` は、文字列長をどう計算するかを示す `unit` パラメーターが使えます。`unit` のデフォルトは `\"BYTE\"` ですが、`\"UTF8_CHAR\"` や `\"UTF16_CHAR\"` など他の値に設定して、エンコードされた `string` 文字列のUnicodeコードポイントの数を決めることができます。" ] }, { "cell_type": "code", "execution_count": 18, "metadata": { "execution": { "iopub.execute_input": "2022-12-15T01:12:18.588588Z", "iopub.status.busy": "2022-12-15T01:12:18.588031Z", "iopub.status.idle": "2022-12-15T01:12:18.594680Z", "shell.execute_reply": "2022-12-15T01:12:18.594028Z" }, "id": "1ZzMe59mvLHr" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "11 bytes; 8 UTF-8 characters\n" ] } ], "source": [ "# 最後の絵文字は、UTF8で4バイトを占めることに注意する\n", "thanks = u'Thanks 😊'.encode('UTF-8')\n", "num_bytes = tf.strings.length(thanks).numpy()\n", "num_chars = tf.strings.length(thanks, unit='UTF8_CHAR').numpy()\n", "print('{} bytes; {} UTF-8 characters'.format(num_bytes, num_chars))" ] }, { "cell_type": "markdown", "metadata": { "id": "fHG85gxlvVU0" }, "source": [ "### 部分文字列\n", "\n", "同様に、 `tf.strings.substr` では \" `unit`\" パラメーターを使い、かつ \"`pos`\" および \"`len`\" パラメーターを指定することで、オフセットの種類を決めることができます。" ] }, { "cell_type": "code", "execution_count": 19, "metadata": { "execution": { "iopub.execute_input": "2022-12-15T01:12:18.598245Z", "iopub.status.busy": "2022-12-15T01:12:18.597617Z", "iopub.status.idle": "2022-12-15T01:12:18.603588Z", "shell.execute_reply": "2022-12-15T01:12:18.602947Z" }, "id": "WlWRLV-4xWYq" }, "outputs": [ { "data": { "text/plain": [ "b'\\xf0'" ] }, "execution_count": 19, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# デフォルト: unit='BYTE'. len=1 の場合、1バイトを返す\n", "tf.strings.substr(thanks, pos=7, len=1).numpy()" ] }, { "cell_type": "code", "execution_count": 20, "metadata": { "execution": { "iopub.execute_input": "2022-12-15T01:12:18.606857Z", "iopub.status.busy": "2022-12-15T01:12:18.606257Z", "iopub.status.idle": "2022-12-15T01:12:18.611162Z", "shell.execute_reply": "2022-12-15T01:12:18.610575Z" }, "id": "JfNUVDPwxkCS" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "b'\\xf0\\x9f\\x98\\x8a'\n" ] } ], "source": [ "# unit = 'UTF8_CHAR' を指定すると、単一の文字(この場合は4バイト)が返される\n", "print(tf.strings.substr(thanks, pos=7, len=1, unit='UTF8_CHAR').numpy())" ] }, { "cell_type": "markdown", "metadata": { "id": "zJUEsVSyeIa3" }, "source": [ "### Unicode文字列を分割する\n", "\n", "`tf.strings.unicode_split` は、Unicode文字列を個々の文字に分割します。" ] }, { "cell_type": "code", "execution_count": 21, "metadata": { "execution": { "iopub.execute_input": "2022-12-15T01:12:18.614438Z", "iopub.status.busy": "2022-12-15T01:12:18.614045Z", "iopub.status.idle": "2022-12-15T01:12:18.624034Z", "shell.execute_reply": "2022-12-15T01:12:18.623421Z" }, "id": "dDjkh5G1ejMt" }, "outputs": [ { "data": { "text/plain": [ "array([b'T', b'h', b'a', b'n', b'k', b's', b' ', b'\\xf0\\x9f\\x98\\x8a'],\n", " dtype=object)" ] }, "execution_count": 21, "metadata": {}, "output_type": "execute_result" } ], "source": [ "tf.strings.unicode_split(thanks, 'UTF-8').numpy()" ] }, { "cell_type": "markdown", "metadata": { "id": "HQqEEZEbdG9O" }, "source": [ "### 文字のバイトオフセット\n", "\n", "`tf.strings.unicode_decode` によって生成された文字テンソルを元の文字列に戻すには、各文字の開始位置のオフセットを知ることが役立ちます。`tf.strings.unicode_decode_with_offsets`メソッド は `unicode_decode` に似ていますが、各文字の開始オフセットを含む2番目のテンソルを返す点が異なります。" ] }, { "cell_type": "code", "execution_count": 22, "metadata": { "execution": { "iopub.execute_input": "2022-12-15T01:12:18.627437Z", "iopub.status.busy": "2022-12-15T01:12:18.626835Z", "iopub.status.idle": "2022-12-15T01:12:18.632570Z", "shell.execute_reply": "2022-12-15T01:12:18.631953Z" }, "id": "Cug7cmwYdowd" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "At byte offset 0: codepoint 127880\n", "At byte offset 4: codepoint 127881\n", "At byte offset 8: codepoint 127882\n" ] } ], "source": [ "codepoints, offsets = tf.strings.unicode_decode_with_offsets(u\"🎈🎉🎊\", 'UTF-8')\n", "\n", "for (codepoint, offset) in zip(codepoints.numpy(), offsets.numpy()):\n", " print(\"At byte offset {}: codepoint {}\".format(offset, codepoint))" ] }, { "cell_type": "markdown", "metadata": { "id": "2ZnCNxOvx66T" }, "source": [ "## Unicode スクリプト" ] }, { "cell_type": "markdown", "metadata": { "id": "nRRHqkqNyGZ6" }, "source": [ "各Unicodeコードポイントは、[スクリプト](https://en.wikipedia.org/wiki/Script_%28Unicode%29) として知られる単一のコードポイント集合に属しています。文字スクリプトは、その文字がどの言語なのかを判断するのに役立ちます。たとえば、「Б」がキリル文字であることがわかれば、その文字を含むテキストはロシア語やウクライナ語などのスラブ言語である可能性が高いことがわかります。\n", "\n", "TensorFlowは、あるコードポイントがどのスクリプトかを返す `tf.strings.unicode_script` を提供しています。戻り値のスクリプトコードは、[International Components for Unicode](http://site.icu-project.org/home) (ICU) の [`UScriptCode`](http://icu-project.org/apiref/icu4c/uscript_8h.html) に対応する `int32` 値になります。" ] }, { "cell_type": "code", "execution_count": 23, "metadata": { "execution": { "iopub.execute_input": "2022-12-15T01:12:18.636148Z", "iopub.status.busy": "2022-12-15T01:12:18.635531Z", "iopub.status.idle": "2022-12-15T01:12:18.640304Z", "shell.execute_reply": "2022-12-15T01:12:18.639702Z" }, "id": "K7DeYHrRyFPy" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[17 8]\n" ] } ], "source": [ "uscript = tf.strings.unicode_script([33464, 1041]) # ['芸', 'Б']\n", "\n", "print(uscript.numpy()) # [17, 8] == [USCRIPT_HAN, USCRIPT_CYRILLIC]" ] }, { "cell_type": "markdown", "metadata": { "id": "2fW992a1lIY6" }, "source": [ "`tf.strings.unicode_script` は、多次元のコードポイントの `tf.Tensors` や ` tf.RaggedTensor` にも適用できます。:" ] }, { "cell_type": "code", "execution_count": 24, "metadata": { "execution": { "iopub.execute_input": "2022-12-15T01:12:18.643590Z", "iopub.status.busy": "2022-12-15T01:12:18.642971Z", "iopub.status.idle": "2022-12-15T01:12:18.647128Z", "shell.execute_reply": "2022-12-15T01:12:18.646493Z" }, "id": "uR7b8meLlFnp" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n" ] } ], "source": [ "print(tf.strings.unicode_script(batch_chars_ragged))" ] }, { "cell_type": "markdown", "metadata": { "id": "mx7HEFpBzEsB" }, "source": [ "## 例:シンプルなセグメンテーション\n", "\n", "セグメンテーションは、テキストを単語のような粒度に分割するタスクです。これは、スペース文字を使用して単語を区切れる場合には簡単に行えますが、一部の言語(中国語や日本語など)はスペースを使いませんし、また、一部の言語(ドイツ語など)には、意味を解析するために分ける必要がある、単語を結合した長い複合語があります。Webテキストでは、「NY株価」(ニューヨーク株価)のように、異なる言語とスクリプトがしばしば混在しています。\n", "\n", "単語の境界を推定してスクリプトを変更することにより、(MLモデルを実装せずに)非常に大まかなセグメンテーションを実行できます。これは、上記の「NY株価」の例のような文字列に対して機能します。さまざまな言語のスペース文字はすべて、実際のテキストとは異なる特別なスクリプトコードである USCRIPT_COMMON として分類されるため、スペースを使用するほとんどの言語でも機能します。" ] }, { "cell_type": "code", "execution_count": 25, "metadata": { "execution": { "iopub.execute_input": "2022-12-15T01:12:18.650379Z", "iopub.status.busy": "2022-12-15T01:12:18.649881Z", "iopub.status.idle": "2022-12-15T01:12:18.653145Z", "shell.execute_reply": "2022-12-15T01:12:18.652503Z" }, "id": "grsvFiC4BoPb" }, "outputs": [], "source": [ "# dtype: string; shape: [num_sentences]\n", "#\n", "# 処理する文章。この行を編集して、さまざまな入力を試してみてください!\n", "sentence_texts = [u'Hello, world.', u'世界こんにちは']" ] }, { "cell_type": "markdown", "metadata": { "id": "CapnbShuGU8i" }, "source": [ "最初に、文章を文字ごとのコードポイントにデコードし、それから各文字のスクリプトコード(識別子)を調べます。" ] }, { "cell_type": "code", "execution_count": 26, "metadata": { "execution": { "iopub.execute_input": "2022-12-15T01:12:18.656719Z", "iopub.status.busy": "2022-12-15T01:12:18.656072Z", "iopub.status.idle": "2022-12-15T01:12:18.661626Z", "shell.execute_reply": "2022-12-15T01:12:18.661002Z" }, "id": "ReQVcDQh1MB8" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "\n" ] } ], "source": [ "# dtype: int32; shape: [num_sentences, (num_chars_per_sentence)]\n", "#\n", "# sentence_char_codepoint[i, j] は、i番目の文のn番目の文字のコードポイント\n", "sentence_char_codepoint = tf.strings.unicode_decode(sentence_texts, 'UTF-8')\n", "print(sentence_char_codepoint)\n", "\n", "# dtype: int32; shape: [num_sentences, (num_chars_per_sentence)]\n", "#\n", "# sentence_char_scripts[i, j] は、i番目の文のn番目の文字のスクリプトコード\n", "sentence_char_script = tf.strings.unicode_script(sentence_char_codepoint)\n", "print(sentence_char_script)" ] }, { "cell_type": "markdown", "metadata": { "id": "O2fapF5UGcUc" }, "source": [ "次に、これらのスクリプトコードを使って、単語の境界を追加すべき場所を決めます。前の文字とスクリプトコードが異なるそれぞれの文字の先頭に、単語の境界を追加します。:" ] }, { "cell_type": "code", "execution_count": 27, "metadata": { "execution": { "iopub.execute_input": "2022-12-15T01:12:18.664978Z", "iopub.status.busy": "2022-12-15T01:12:18.664460Z", "iopub.status.idle": "2022-12-15T01:12:18.734061Z", "shell.execute_reply": "2022-12-15T01:12:18.733411Z" }, "id": "7v5W6MOr1Rlc" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "tf.Tensor([ 0 5 7 12 13 15], shape=(6,), dtype=int64)\n" ] } ], "source": [ "# dtype: bool; shape: [num_sentences, (num_chars_per_sentence)]\n", "#\n", "# sentence_char_starts_word[i, j] は、i番目の文のn番目の文字が単語の始まりである場合にTrue\n", "sentence_char_starts_word = tf.concat(\n", " [tf.fill([sentence_char_script.nrows(), 1], True),\n", " tf.not_equal(sentence_char_script[:, 1:], sentence_char_script[:, :-1])],\n", " axis=1)\n", "\n", "# dtype: int64; shape: [num_words]\n", "#\n", "# word_starts[i] は、i番目の単語の始まりである文字のインデックス\n", "# (すべての文がフラット化された文字リスト)\n", "word_starts = tf.squeeze(tf.where(sentence_char_starts_word.values), axis=1)\n", "print(word_starts)" ] }, { "cell_type": "markdown", "metadata": { "id": "LAwh-1QkGuC9" }, "source": [ "そして、これらの目印(開始オフセット)を使って、各単語ごとの文字リストを含む `RaggedTensor` を作成します。:" ] }, { "cell_type": "code", "execution_count": 28, "metadata": { "execution": { "iopub.execute_input": "2022-12-15T01:12:18.737822Z", "iopub.status.busy": "2022-12-15T01:12:18.737077Z", "iopub.status.idle": "2022-12-15T01:12:18.747404Z", "shell.execute_reply": "2022-12-15T01:12:18.746812Z" }, "id": "bNiA1O_eBBCL" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n" ] } ], "source": [ "# dtype: int32; shape: [num_words, (num_chars_per_word)]\n", "#\n", "# word_char_codepoint[i, j] は、i番目の単語のn番目の文字のコードポイント\n", "word_char_codepoint = tf.RaggedTensor.from_row_starts(\n", " values=sentence_char_codepoint.values,\n", " row_starts=word_starts)\n", "print(word_char_codepoint)" ] }, { "cell_type": "markdown", "metadata": { "id": "66a2ZnYmG2ao" }, "source": [ "最後に、`RaggedTensor` をコードポイント単位でセグメント化して、文章に戻します。:" ] }, { "cell_type": "code", "execution_count": 29, "metadata": { "execution": { "iopub.execute_input": "2022-12-15T01:12:18.750762Z", "iopub.status.busy": "2022-12-15T01:12:18.750289Z", "iopub.status.idle": "2022-12-15T01:12:18.767615Z", "shell.execute_reply": "2022-12-15T01:12:18.766971Z" }, "id": "NCfwcqLSEjZb" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n" ] } ], "source": [ "# dtype: int64; shape: [num_sentences]\n", "#\n", "# sentence_num_words[i] は、i番目の文の単語数\n", "sentence_num_words = tf.reduce_sum(\n", " tf.cast(sentence_char_starts_word, tf.int64),\n", " axis=1)\n", "\n", "# dtype: int32; shape: [num_sentences, (num_words_per_sentence), (num_chars_per_word)]\n", "#\n", "# sentence_word_char_codepoint[i, j, k] は、i番目の文のn番目の単語のk番目の文字のコードポイント\n", "sentence_word_char_codepoint = tf.RaggedTensor.from_row_lengths(\n", " values=word_char_codepoint,\n", " row_lengths=sentence_num_words)\n", "print(sentence_word_char_codepoint)" ] }, { "cell_type": "markdown", "metadata": { "id": "xWaX8WcbHyqY" }, "source": [ "最終的な結果を見やすくするために、UTF-8文字列にエンコードします。:" ] }, { "cell_type": "code", "execution_count": 30, "metadata": { "execution": { "iopub.execute_input": "2022-12-15T01:12:18.771005Z", "iopub.status.busy": "2022-12-15T01:12:18.770438Z", "iopub.status.idle": "2022-12-15T01:12:18.775315Z", "shell.execute_reply": "2022-12-15T01:12:18.774725Z" }, "id": "HSivquOgFr3C" }, "outputs": [ { "data": { "text/plain": [ "[[b'Hello', b', ', b'world', b'.'],\n", " [b'\\xe4\\xb8\\x96\\xe7\\x95\\x8c',\n", " b'\\xe3\\x81\\x93\\xe3\\x82\\x93\\xe3\\x81\\xab\\xe3\\x81\\xa1\\xe3\\x81\\xaf']]" ] }, "execution_count": 30, "metadata": {}, "output_type": "execute_result" } ], "source": [ "tf.strings.unicode_encode(sentence_word_char_codepoint, 'UTF-8').to_list()" ] } ], "metadata": { "colab": { "collapsed_sections": [ "oL9KopJirB2g" ], "name": "unicode.ipynb", "toc_visible": true }, "kernelspec": { "display_name": "Python 3", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.9.16" } }, "nbformat": 4, "nbformat_minor": 0 }