#@title Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""
Explanation: Copyright 2020 The TensorFlow Authors.
End of explanation
"""


import tensorflow as tf
import numpy as np

"""
Explanation: テンソルの基礎
<table class="tfo-notebook-buttons" align="left">
  <td>     <a target="_blank" href="https://www.tensorflow.org/guide/tensor"><img src="https://www.tensorflow.org/images/tf_logo_32px.png">TensorFlow.org で表示</a>   </td>
  <td><a target="_blank" href="https://colab.research.google.com/github/tensorflow/docs-l10n/blob/master/site/ja/guide/tensor.ipynb"><img src="https://www.tensorflow.org/images/colab_logo_32px.png"> Google Colab で実行</a></td>
  <td>     <a target="_blank" href="https://github.com/tensorflow/docs-l10n/blob/master/site/ja/guide/tensor.ipynb"><img src="https://www.tensorflow.org/images/GitHub-Mark-32px.png">GitHub でソースを表示</a>   </td>
  <td>     <a href="https://storage.googleapis.com/tensorflow_docs/docs-l10n/site/ja/guide/tensor.ipynb"><img src="https://www.tensorflow.org/images/download_logo_32px.png">ノートブックをダウンロード</a>   </td>
</table>
End of explanation
"""


# This will be an int32 tensor by default; see "dtypes" below.
rank_0_tensor = tf.constant(4)
print(rank_0_tensor)

"""
Explanation: テンソルは dtype と呼ばれる均一型の多次元配列です。サポートされているすべての dtypes は、tf.dtypes.DType で確認できます。
NumPy で言えば、テンソルは np.arrays（のようなもの）とすることができます。
すべてのテンソルは、Python の数値や文字列と同じように不変です。つまり、テンソルのコンテンツを更新することは不可能で、新しいテンソルのみを作成できます。
基礎
基本的なテンソルを作成してみましょう。
次は、「スカラー」または「階数 0」のテンソルです。スカラーには単一の値のみが含まれ、「軸」は存在しません。
End of explanation
"""


# Let's make this a float tensor.
rank_1_tensor = tf.constant([2.0, 3.0, 4.0])
print(rank_1_tensor)

"""
Explanation: 「ベクトル」または「階数 1」テンソルは、値のリストとして考えられます。1 ベクトルは 1 つの軸です。
End of explanation
"""


# If you want to be specific, you can set the dtype (see below) at creation time
rank_2_tensor = tf.constant([[1, 2],
                             [3, 4],
                             [5, 6]], dtype=tf.float16)
print(rank_2_tensor)

"""
Explanation: 「行列」または「階数 2」テンソルには軸が 2 つあります。
End of explanation
"""


# There can be an arbitrary number of
# axes (sometimes called "dimensions")
rank_3_tensor = tf.constant([
  [[0, 1, 2, 3, 4],
   [5, 6, 7, 8, 9]],
  [[10, 11, 12, 13, 14],
   [15, 16, 17, 18, 19]],
  [[20, 21, 22, 23, 24],
   [25, 26, 27, 28, 29]],])

print(rank_3_tensor)

"""
Explanation: <table>
<tr>
  <th>スカラー, 形状: <code>[]</code> </th>
  <th>ベクトル, 形状: <code>[3]</code> </th>
  <th>行列, 形状: <code>[3, 2]</code> </th>
</tr>
<tr>
  <td>    <img src="images/tensor/scalar.png" alt="A scalar, the number 4"> </td>
  <td><img src="images/tensor/vector.png" alt="The line with 3 sections, each one containing a number."></td>
  <td>    <img src="images/tensor/matrix.png" alt="A 3x2 grid, with each cell containing a number."> </td>
</tr>
</table>

テンソルにはさらに軸がある場合があります。次は、3 軸のテンソルです。
End of explanation
"""


np.array(rank_2_tensor)

rank_2_tensor.numpy()

"""
Explanation: 3 軸以上のテンソルを視覚化する方法はたくさんあります。
<table>
<tr>
  <th colspan="3">3 軸テンソル, 形状: <code>[3, 2, 5]</code> </th>
</tr>
<tr>
</tr>
<tr>
  <td>    <img src="images/tensor/3-axis_numpy.png"> </td>
  <td>    <img src="images/tensor/3-axis_front.png"> </td>
  <td>    <img src="images/tensor/3-axis_block.png"> </td>
</tr>
</table>

np.array または tensor.numpy メソッドを使用して、テンソルを NumPy 配列に変換できます。
End of explanation
"""


a = tf.constant([[1, 2],
                 [3, 4]])
b = tf.constant([[1, 1],
                 [1, 1]]) # Could have also said `tf.ones([2,2])`

print(tf.add(a, b), "\n")
print(tf.multiply(a, b), "\n")
print(tf.matmul(a, b), "\n")

print(a + b, "\n") # element-wise addition
print(a * b, "\n") # element-wise multiplication
print(a @ b, "\n") # matrix multiplication

"""
Explanation: テンソルには、通常、浮動小数点型や整数型が含まれますが、次のようなほかの型も含まれます。

複素数
文字列

基本の tf.Tensor クラスには、「矩形」を成すテンソルが必要です。つまり各要素は、各軸に沿って同じサイズになります。ただし、次のように、異なる形状を処理できる特殊なテンソルもあります。

不規則（以下の RaggedTensor を参照）
スパース（以下の SparseTensor を参照）

テンソルには、加算、要素ごとの乗算、および行列の乗算などの基本的な計算を実行できます。
End of explanation
"""


c = tf.constant([[4.0, 5.0], [10.0, 1.0]])

# Find the largest value
print(tf.reduce_max(c))
# Find the index of the largest value
print(tf.argmax(c))
# Compute the softmax
print(tf.nn.softmax(c))

"""
Explanation: テンソルはあらゆる種類の演算に使用されます。
End of explanation
"""


rank_4_tensor = tf.zeros([3, 2, 4, 5])

"""
Explanation: 形状について
テンソルには形状があり、次のような用語が使用されます。

形状: テンソルの各軸の長さ（要素の数）。
階数: テンソルの軸数。スカラーは階数 0、ベクトルは階数 1、行列は階数 2 となります。
軸または次元: テンソルの特定の次元。
サイズ: テンソル内の項目の総数。生成された形状ベクトル。

注意: 「2 次元のテンソル」と記述されることもありますが、階数 2 のテンソルは、通常 2 次元形状ではありません。
テンソルと tf.TensorShape オブジェクトには、次にアクセスするための便利なプロパティがあります。
End of explanation
"""


print("Type of every element:", rank_4_tensor.dtype)
print("Number of axes:", rank_4_tensor.ndim)
print("Shape of tensor:", rank_4_tensor.shape)
print("Elements along axis 0 of tensor:", rank_4_tensor.shape[0])
print("Elements along the last axis of tensor:", rank_4_tensor.shape[-1])
print("Total number of elements (3*2*4*5): ", tf.size(rank_4_tensor).numpy())

"""
Explanation: <table>
<tr>
  <th colspan="2">階数 4 テンソル, 形状: <code>[3, 2, 4, 5]</code> </th>
</tr>
<tr>
  <td> <img src="images/tensor/shape.png" alt="A tensor shape is like a vector."> </td>
<td> <img src="images/tensor/4-axis_block.png" alt="A 4-axis tensor"> </td>
  </tr>
</table>
End of explanation
"""


rank_1_tensor = tf.constant([0, 1, 1, 2, 3, 5, 8, 13, 21, 34])
print(rank_1_tensor.numpy())

"""
Explanation: 軸は通常、そのインデックスで参照されますが、それぞれの意味を常に把握しておく必要があります。多くの場合、軸はグローバルからローカルに順序付けられています。バッチ軸を先頭に、空間次元、そして最後に各位置の特徴量が続きます。こうすることで、特徴ベクトルは連続したメモリ領域となります。
<table>
<tr>
<th>典型的な軸の順序</th>
</tr>
<tr>
    <td> <img src="images/tensor/shape2.png" alt="Keep track of what each axis is. A 4-axis tensor might be: Batch, Width, Height, Features"> </td>
</tr>
</table>

インデックス作成
単軸のインデックス作成
TensorFlow は、Python でのリストまたは文字列のインデックス作成と同様の標準的な Python インデックス作成ルールや NumPy インデックス作成の基本ルールを使用しています。

インデックスは 0 から開始
負のインデックスは後ろ側から逆順に数える
スライスにコロン : を使用 - start:stop:step
End of explanation
"""


print("First:", rank_1_tensor[0].numpy())
print("Second:", rank_1_tensor[1].numpy())
print("Last:", rank_1_tensor[-1].numpy())

"""
Explanation: スカラーを使用してインデックスを作成すると、軸が削除されます。
End of explanation
"""


print("Everything:", rank_1_tensor[:].numpy())
print("Before 4:", rank_1_tensor[:4].numpy())
print("From 4 to the end:", rank_1_tensor[4:].numpy())
print("From 2, before 7:", rank_1_tensor[2:7].numpy())
print("Every other item:", rank_1_tensor[::2].numpy())
print("Reversed:", rank_1_tensor[::-1].numpy())

"""
Explanation: : スライスを使用してインデックスを作成すると、軸が維持されます。
End of explanation
"""


print(rank_2_tensor.numpy())

"""
Explanation: 多軸のインデックス作成
階数の高いテンソルは、複数のインデックスを渡してインデックス化されます。
単軸とまったく同じルールが各軸に個別に適用されます。
End of explanation
"""


# Pull out a single value from a 2-rank tensor
print(rank_2_tensor[1, 1].numpy())

"""
Explanation: 各インデックスに整数を渡すと、結果はスカラーになります。
End of explanation
"""


# Get row and column tensors
print("Second row:", rank_2_tensor[1, :].numpy())
print("Second column:", rank_2_tensor[:, 1].numpy())
print("Last row:", rank_2_tensor[-1, :].numpy())
print("First item in last column:", rank_2_tensor[0, -1].numpy())
print("Skip the first row:")
print(rank_2_tensor[1:, :].numpy(), "\n")

"""
Explanation: 整数とスライスを任意に組み合わせてインデックスを作成することができます。
End of explanation
"""


print(rank_3_tensor[:, :, 4])

"""
Explanation: 次は、3 軸テンソルを使用した例です。
End of explanation
"""


# Shape returns a `TensorShape` object that shows the size along each axis
x = tf.constant([[1], [2], [3]])
print(x.shape)

# You can convert this object into a Python list, too
print(x.shape.as_list())

"""
Explanation: <table>
<tr>
<th colspan="2">バッチ内の各例のすべての位置で最後の特徴量を選択する</th>
</tr>
<tr>
    <td> <img src="images/tensor/index1.png" alt="A 3x2x5 tensor with all the values at the index-4 of the last axis selected."> </td>
      <td> <img src="images/tensor/index2.png" alt="The selected values packed into a 2-axis tensor."> </td>
</tr>
</table>

テンソル内の複数の個別の要素にインデックス作成を適用する方法については、テンソルのスライスガイドをご覧ください。
形状の操作
テンソルの形状変更は非常に便利です。
End of explanation
"""


# You can reshape a tensor to a new shape.
# Note that you're passing in a list
reshaped = tf.reshape(x, [1, 3])

print(x.shape)
print(reshaped.shape)

"""
Explanation: テンソルを新しい形状に変更できます。<code>tf.reshape</code> 演算は、基盤のデータを複製する必要がないため、素早く簡単に行えます。
End of explanation
"""


print(rank_3_tensor)

"""
Explanation: データはレイアウトをメモリに維持したまま、同じデータにポイントする新しいテンソルが要求された形状で作成されます。TensorFlow は C 形式の「行優先」メモリ順序付けを使用しており、右端のインデックスの増分は、メモリ内の 1 ステップに相当します。
End of explanation
"""


# A `-1` passed in the `shape` argument says "Whatever fits".
print(tf.reshape(rank_3_tensor, [-1]))

"""
Explanation: テンソルをフラット化すると、どの順序でメモリにレイアウトされているかを確認できます。
End of explanation
"""


print(tf.reshape(rank_3_tensor, [3*2, 5]), "\n")
print(tf.reshape(rank_3_tensor, [3, -1]))

"""
Explanation: 通常、tf.reshape の唯一合理的な使用は、隣接する軸を結合または分割する（または 1 を追加/削除する）ことです。
この 3x2x5 のテンソルでは、スライスは混合しないため、(3x2)x5 または 3x(2x5) に形状を変更するのが合理的です。
End of explanation
"""


# Bad examples: don't do this

# You can't reorder axes with reshape.
print(tf.reshape(rank_3_tensor, [2, 3, 5]), "\n") 

# This is a mess
print(tf.reshape(rank_3_tensor, [5, 6]), "\n")

# This doesn't work at all
try:
  tf.reshape(rank_3_tensor, [7, -1])
except Exception as e:
  print(f"{type(e).__name__}: {e}")

"""
Explanation: <table>
<th colspan="3"> 形状変更の成功例。</th>
<tr>
  <td> <img src="images/tensor/reshape-before.png" alt="A 3x2x5 tensor"> </td>
  <td>   <img src="images/tensor/reshape-good1.png" alt="The same data reshaped to (3x2)x5"> </td>
  <td> <img src="images/tensor/reshape-good2.png" alt="The same data reshaped to 3x(2x5)"> </td>
</tr>
</table>

形状変更は要素の総数が等しい新しい形状で「機能」しますが、軸の順を守らなければ役に立ちません。
tf.reshape では軸の交換は機能しないため、それを行うには tf.transpose が必要です。
End of explanation
"""


the_f64_tensor = tf.constant([2.2, 3.3, 4.4], dtype=tf.float64)
the_f16_tensor = tf.cast(the_f64_tensor, dtype=tf.float16)
# Now, cast to an uint8 and lose the decimal precision
the_u8_tensor = tf.cast(the_f16_tensor, dtype=tf.uint8)
print(the_u8_tensor)

"""
Explanation: <table>
<th colspan="3">形状変更の失敗例。</th>
<tr>
  <td> <img src="https://github.com/tensorflow/docs-l10n/blob/master/site/ja/guide/images/tensor/reshape-bad.png?raw=true" alt="You can't reorder axes, use tf.transpose for that"> </td>
  <td> <img src="images/tensor/reshape-bad4.png" alt="Anything that mixes the slices of data together is probably wrong."> </td>
  <td> <img src="images/tensor/reshape-bad2.png" alt="The new shape must fit exactly."> </td>
</tr>
</table>

不完全に指定された形状を実行することができます。その形状には None（軸の長さが不明）が含まれているか、形状が None（テンソルの階数が不明）であるかのいずれかです。
tf.RaggedTensor を除き、このような形状は TensorFlow の象徴的なグラフ構築 API のコンテキストでのみ発生します。

tf.function
Keras 関数型 API

DTypes をさらに詳しく
tf.Tensor のデータ型を検査するには、Tensor.dtype プロパティを使用します。
Python オブジェクトから tf.Tensor を作成する場合、オプションとしてデータ型を指定できます。
指定しない場合は、TensorFlow によってデータを表すデータ型が選択されます。TensorFlow は Python の整数値を tf.int32 と Python 浮動小数点数を tf.float32 に変換します。そうでない場合は、TensorFlow は NumPy が配列に変換する場合と同じルールを使用します。
型から型にキャストすることができます。
End of explanation
"""


x = tf.constant([1, 2, 3])

y = tf.constant(2)
z = tf.constant([2, 2, 2])
# All of these are the same computation
print(tf.multiply(x, 2))
print(x * y)
print(x * z)

"""
Explanation: ブロードキャスト
ブロードキャストは、NumPy の相当する機能から得た概念です。簡単に言えば、ある条件下において、より小さなテンソルに複合演算を実行する場合、より大きなテンソルに適合するように自動的に「引き延ばされる」ということです。
最も単純で一般的な事例としては、テンソルをスカラーに加算または乗算する場合が挙げられます。その場合、スカラーはもう片方の引数と同じ形状になるようにブロードキャストされます。
End of explanation
"""


# These are the same computations
x = tf.reshape(x,[3,1])
y = tf.range(1, 5)
print(x, "\n")
print(y, "\n")
print(tf.multiply(x, y))

"""
Explanation: 同様に、長さ 1 の軸を別の引数に一致するように引き延ばすことができます。両方の引数を同一の計算で引き延ばすことができます。
この場合、3x1 の行列は、要素ごとに 1x4 の行列と乗算され、3x4 の行列が生成されます。最初の 1 はオプションであることに注意してください。形状 y は [4] です。
End of explanation
"""


x_stretch = tf.constant([[1, 1, 1, 1],
                         [2, 2, 2, 2],
                         [3, 3, 3, 3]])

y_stretch = tf.constant([[1, 2, 3, 4],
                         [1, 2, 3, 4],
                         [1, 2, 3, 4]])

print(x_stretch * y_stretch)  # Again, operator overloading

"""
Explanation: <table>
<tr>
  <th>ブロードキャストの加算: <code>[3, 1]</code> 掛け <code>[1, 4]</code> により、<code>[3,4]</code> を生成</th>
</tr>
<tr>
  <td> <img src="images/tensor/broadcasting.png" alt="Adding a 3x1 matrix to a 4x1 matrix results in a 3x4 matrix"> </td>
</tr>
</table>

次は、ブロードキャストを使用しない同一の演算です。
End of explanation
"""


print(tf.broadcast_to(tf.constant([1, 2, 3]), [3, 3]))

"""
Explanation: ブロードキャスト演算によってメモリ内の拡張したテンソルが実体化されることがないため、ほとんどの場合、ブロードキャストは時間と空間係数の両方です。
tf.broadcast_to を使用して、ブロードキャストがどのようなものであるかを確認します。
End of explanation
"""


ragged_list = [
    [0, 1, 2, 3],
    [4, 5],
    [6, 7, 8],
    [9]]

try:
  tensor = tf.constant(ragged_list)
except Exception as e:
  print(f"{type(e).__name__}: {e}")

"""
Explanation: たとえば数学的演算とは異なり、broadcast_to はメモリを節約する上で特に何も行いません。ここでは、テンソルの実体化が行われています。
さらに複雑化することができます。Jake VanderPlas の書籍『Python Data Science Handbook』のこのセクションでは、ブロードキャストのコツがさらに紹介されています（やはり NumPy で）。
tf.convert_to_tensor
tf.matmul や tf.reshape といったほとんどの演算は、クラス tf.Tensor の引数を取りますが、上記の例では、テンソルのような形状の Python オブジェクトを渡すことがよくあります。
すべてではありませんが、ほとんどの演算は、非テンソル引数に対して convert_to_tensor を呼び出します。変換のレジストリがあり、NumPy の ndarray、TensorShape、Python リスト、tf.Variable といったほとんどのオブジェクトクラスは、自動的に変換されます。
詳細について、または、テンソルに自動変換する独自の型がある場合は、tf.register_tensor_conversion_function を参照してください。
不規則なテンソル
軸に合わせて要素の数が変化するテンソルは「不規則」と呼ばれています。不規則なデータには、tf.ragged.RaggedTensor を使用してください。
たとえば、次の形状は通常のテンソルとして表現することはできません。
<table>
<tr>
  <th>`tf.RaggedTensor`, 形状: <code>[4, None]</code> </th>
</tr>
<tr>
  <td> <img src="images/tensor/ragged.png" alt="A 2-axis ragged tensor, each row can have a different length."> </td>
</tr>
</table>
End of explanation
"""


ragged_tensor = tf.ragged.constant(ragged_list)
print(ragged_tensor)

"""
Explanation: 代わりに、tf.ragged.constant を使用して tf.RaggedTensor を作成します。
End of explanation
"""


print(ragged_tensor.shape)

"""
Explanation: tf.RaggedTensor の形状には不明な長さの軸が含まれます。
End of explanation
"""


# Tensors can be strings, too here is a scalar string.
scalar_string_tensor = tf.constant("Gray wolf")
print(scalar_string_tensor)

"""
Explanation: 文字列型テンソル
tf.string は dtype であるため、テンソルで文字列（可変長バイト配列）としてデータを表すことができます。
文字列はアトミックであり、Python 文字列のようにインデックスを作成することはできません。文字列の長さはテンソルの軸の 1 つではありません。これらを操作するための関数については、tf.strings を参照してください。
次はスカラー文字列のテンソルです。
End of explanation
"""


# If you have three string tensors of different lengths, this is OK.
tensor_of_strings = tf.constant(["Gray wolf",
                                 "Quick brown fox",
                                 "Lazy dog"])
# Note that the shape is (3,). The string length is not included.
print(tensor_of_strings)

"""
Explanation: そして、ベクトルの文字列です。
<table>
<tr>
  <th>文字列ベクトル, 形状: <code>[3,]</code> </th>
</tr>
<tr>
  <td> <img src="images/tensor/strings.png" alt="The string length is not one of the tensor's axes."> </td>
</tr>
</table>
End of explanation
"""


tf.constant("🥳👍")

"""
Explanation: 上記の出力では、プレフィクス b は tf.string dtype が unicode 文字列でなくバイト文字列であることを示します。TensorFlow での Unicode テキストの使用については、「Unicode チュートリアル」 を参照してください。
Unicode 文字を渡した場合、utf-8 で暗号化されます。
End of explanation
"""


# You can use split to split a string into a set of tensors
print(tf.strings.split(scalar_string_tensor, sep=" "))

# ...but it turns into a `RaggedTensor` if you split up a tensor of strings,
# as each string might be split into a different number of parts.
print(tf.strings.split(tensor_of_strings))

"""
Explanation: 文字列の基本的な関数は、tf.strings.split などの tf.strings を使って見つけることができます。
End of explanation
"""


text = tf.constant("1 10 100")
print(tf.strings.to_number(tf.strings.split(text, " ")))

"""
Explanation: <table>
<tr>
  <th> 3 文字列分割, 形状: <code>[3, None]</code> </th>
</tr>
<tr>
  <td> <img src="images/tensor/string-split.png" alt="Splitting multiple strings returns a tf.RaggedTensor"> </td>
</tr>
</table>

また、tf.string.to_number も利用できます。
End of explanation
"""


byte_strings = tf.strings.bytes_split(tf.constant("Duck"))
byte_ints = tf.io.decode_raw(tf.constant("Duck"), tf.uint8)
print("Byte strings:", byte_strings)
print("Bytes:", byte_ints)

# Or split it up as unicode and then decode it
unicode_bytes = tf.constant("アヒル 🦆")
unicode_char_bytes = tf.strings.unicode_split(unicode_bytes, "UTF-8")
unicode_values = tf.strings.unicode_decode(unicode_bytes, "UTF-8")

print("\nUnicode bytes:", unicode_bytes)
print("\nUnicode chars:", unicode_char_bytes)
print("\nUnicode values:", unicode_values)

"""
Explanation: tf.cast を使用して文字列テンソルを数値に変換することはできませんが、バイトに変換してから数字に変換することができます。
End of explanation
"""


# Sparse tensors store values by index in a memory-efficient manner
sparse_tensor = tf.sparse.SparseTensor(indices=[[0, 0], [1, 2]],
                                       values=[1, 2],
                                       dense_shape=[3, 4])
print(sparse_tensor, "\n")

# You can convert sparse tensors to dense
print(tf.sparse.to_dense(sparse_tensor))

"""
Explanation: TensorFlow ではすべての生のバイトに、tf.string dtype が使用されています。tf.io モジュールには、画像の解読や csv の解析など、データとバイトを変換する関数が含まれています。
スパーステンソル
非常に広い埋め込みスペースであるかのうように、データがスパースである場合があります。TensorFlow は、スパースデータを効率的に保管できるように、tf.sparse.SparseTensor と関連する演算をサポートしています。
<table>
<tr>
  <th>`tf.SparseTensor`, 形状: <code>[3, 4]</code> </th>
</tr>
<tr>
  <td> <img src="images/tensor/sparse.png" alt="An 3x4 grid, with values in only two of the cells."> </td>
</tr>
</table>
End of explanation
"""


