<SYSTEM_TASK:>
Given the following text description, write Python code to implement the functionality described below step by step
<END_TASK>
<USER_TASK:>
Description:
 Copyright 2020 The TensorFlow Authors.
Step1:  Introduction to tensor slicing
<table class="tfo-notebook-buttons" align="left">
  <td>
    <a target="_blank" href="https
Step2:  Extract tensor slices
Perform NumPy-like tensor slicing using tf.slice.
Step3:  Alternatively, you can use a more Pythonic syntax. Note that tensor slices are evenly spaced over a start-stop range.
Step4:  <img src="images/tf_slicing/slice_1d_1.png">
Step5:  <img src="images/tf_slicing/slice_1d_2.png">
For 2-dimensional tensors,you can use something like
Step6:  <img src="images/tf_slicing/slice_2d_1.png">
You can use tf.slice on higher dimensional tensors as well.
Step7:  You can also use tf.strided_slice to extract slices of tensors by 'striding' over the tensor dimensions.
Use tf.gather to extract specific indices from a single axis of a tensor.
Step8:  <img src="images/tf_slicing/slice_1d_3.png">
tf.gather does not require indices to be evenly spaced.
Step9:  <img src="images/tf_slicing/gather_1.png">
To extract slices from multiple axes of a tensor, use tf.gather_nd. This is useful when you want to gather the elements of a matrix as opposed to just its rows or columns.
Step10:  <img src="images/tf_slicing/gather_2.png">
Step11:  Insert data into tensors
Use tf.scatter_nd to insert data at specific slices/indices of a tensor. Note that the tensor into which you insert values is zero-initialized.
Step12:  Methods like tf.scatter_nd which require zero-initialized tensors are similar to sparse tensor initializers. You can use tf.gather_nd and tf.scatter_nd to mimic the behavior of sparse tensor ops.
Consider an example where you construct a sparse tensor using these two methods in conjunction.
Step13:  <img src="images/tf_slicing/gather_nd_sparse.png">
Step14:  This is similar to
Step15:  To insert data into a tensor with pre-existing values, use tf.tensor_scatter_nd_add.
Step16:  Similarly, use tf.tensor_scatter_nd_sub to subtract values from a tensor with pre-existing values.
Step17:  Use tf.tensor_scatter_nd_min to copy element-wise minimum values from one tensor to another.
Step18:  Similarly, use tf.tensor_scatter_nd_max to copy element-wise maximum values from one tensor to another.
<ASSISTANT_TASK:>
Python Code:
#@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: Introduction to tensor slicing
<table class="tfo-notebook-buttons" align="left">
  <td>
    <a target="_blank" href="https://www.tensorflow.org/guide/tensor_slicing"><img src="https://www.tensorflow.org/images/tf_logo_32px.png" />View on TensorFlow.org</a>
  </td>
  <td>
    <a target="_blank" href="https://colab.research.google.com/github/tensorflow/docs/blob/master/site/en/guide/tensor_slicing.ipynb"><img src="https://www.tensorflow.org/images/colab_logo_32px.png" />Run in Google Colab</a>
  </td>
  <td>
    <a target="_blank" href="https://github.com/tensorflow/docs/blob/master/site/en/guide/tensor_slicing.ipynb"><img src="https://www.tensorflow.org/images/GitHub-Mark-32px.png" />View source on GitHub</a>
  </td>
  <td>
    <a href="https://storage.googleapis.com/tensorflow_docs/docs/site/en/guide/tensor_slicing.ipynb"><img src="https://www.tensorflow.org/images/download_logo_32px.png" />Download notebook</a>
  </td>
</table>
When working on ML applications such as object detection and NLP, it is sometimes necessary to work with sub-sections (slices) of tensors. For example, if your model architecture includes routing, where one layer might control which training example gets routed to the next layer. In this case, you could use tensor slicing ops to split the tensors up and put them back together in the right order.
In NLP applications, you can use tensor slicing to perform word masking while training. For example, you can generate training data from a list of sentences by choosing a word index to mask in each sentence, taking the word out as a label, and then replacing the chosen word with a mask token.  
In this guide, you will learn how to use the TensorFlow APIs to:
Extract slices from a tensor
Insert data at specific indices in a tensor
This guide assumes familiarity with tensor indexing. Read the indexing sections of the Tensor and TensorFlow NumPy guides before getting started with this guide.
Setup
End of explanation
t1 = tf.constant([0, 1, 2, 3, 4, 5, 6, 7])
print(tf.slice(t1,
               begin=[1],
               size=[3]))
Explanation: Extract tensor slices
Perform NumPy-like tensor slicing using tf.slice.
End of explanation
print(t1[1:4])
Explanation: Alternatively, you can use a more Pythonic syntax. Note that tensor slices are evenly spaced over a start-stop range.
End of explanation
print(t1[-3:])
Explanation: <img src="images/tf_slicing/slice_1d_1.png">
End of explanation
t2 = tf.constant([[0, 1, 2, 3, 4],
                  [5, 6, 7, 8, 9],
                  [10, 11, 12, 13, 14],
                  [15, 16, 17, 18, 19]])
print(t2[:-1, 1:3])
Explanation: <img src="images/tf_slicing/slice_1d_2.png">
For 2-dimensional tensors,you can use something like:
End of explanation
t3 = tf.constant([[[1, 3, 5, 7],
                   [9, 11, 13, 15]],
                  [[17, 19, 21, 23],
                   [25, 27, 29, 31]]
                  ])
print(tf.slice(t3,
               begin=[1, 1, 0],
               size=[1, 1, 2]))
Explanation: <img src="images/tf_slicing/slice_2d_1.png">
You can use tf.slice on higher dimensional tensors as well.
End of explanation
print(tf.gather(t1,
                indices=[0, 3, 6]))
# This is similar to doing
t1[::3]
Explanation: You can also use tf.strided_slice to extract slices of tensors by 'striding' over the tensor dimensions.
Use tf.gather to extract specific indices from a single axis of a tensor.
End of explanation
alphabet = tf.constant(list('abcdefghijklmnopqrstuvwxyz'))
print(tf.gather(alphabet,
                indices=[2, 0, 19, 18]))
Explanation: <img src="images/tf_slicing/slice_1d_3.png">
tf.gather does not require indices to be evenly spaced.
End of explanation
t4 = tf.constant([[0, 5],
                  [1, 6],
                  [2, 7],
                  [3, 8],
                  [4, 9]])
print(tf.gather_nd(t4,
                   indices=[[2], [3], [0]]))
Explanation: <img src="images/tf_slicing/gather_1.png">
To extract slices from multiple axes of a tensor, use tf.gather_nd. This is useful when you want to gather the elements of a matrix as opposed to just its rows or columns.
End of explanation
t5 = np.reshape(np.arange(18), [2, 3, 3])
print(tf.gather_nd(t5,
                   indices=[[0, 0, 0], [1, 2, 1]]))
# Return a list of two matrices
print(tf.gather_nd(t5,
                   indices=[[[0, 0], [0, 2]], [[1, 0], [1, 2]]]))
# Return one matrix
print(tf.gather_nd(t5,
                   indices=[[0, 0], [0, 2], [1, 0], [1, 2]]))
Explanation: <img src="images/tf_slicing/gather_2.png">
End of explanation
t6 = tf.constant([10])
indices = tf.constant([[1], [3], [5], [7], [9]])
data = tf.constant([2, 4, 6, 8, 10])
print(tf.scatter_nd(indices=indices,
                    updates=data,
                    shape=t6))
Explanation: Insert data into tensors
Use tf.scatter_nd to insert data at specific slices/indices of a tensor. Note that the tensor into which you insert values is zero-initialized.
End of explanation
# Gather values from one tensor by specifying indices
new_indices = tf.constant([[0, 2], [2, 1], [3, 3]])
t7 = tf.gather_nd(t2, indices=new_indices)
Explanation: Methods like tf.scatter_nd which require zero-initialized tensors are similar to sparse tensor initializers. You can use tf.gather_nd and tf.scatter_nd to mimic the behavior of sparse tensor ops.
Consider an example where you construct a sparse tensor using these two methods in conjunction.
End of explanation
# Add these values into a new tensor
t8 = tf.scatter_nd(indices=new_indices, updates=t7, shape=tf.constant([4, 5]))
print(t8)
Explanation: <img src="images/tf_slicing/gather_nd_sparse.png">
End of explanation
t9 = tf.SparseTensor(indices=[[0, 2], [2, 1], [3, 3]],
                     values=[2, 11, 18],
                     dense_shape=[4, 5])
print(t9)
# Convert the sparse tensor into a dense tensor
t10 = tf.sparse.to_dense(t9)
print(t10)
Explanation: This is similar to:
End of explanation
t11 = tf.constant([[2, 7, 0],
                   [9, 0, 1],
                   [0, 3, 8]])
# Convert the tensor into a magic square by inserting numbers at appropriate indices
t12 = tf.tensor_scatter_nd_add(t11,
                               indices=[[0, 2], [1, 1], [2, 0]],
                               updates=[6, 5, 4])
print(t12)
Explanation: To insert data into a tensor with pre-existing values, use tf.tensor_scatter_nd_add.
End of explanation
# Convert the tensor into an identity matrix
t13 = tf.tensor_scatter_nd_sub(t11,
                               indices=[[0, 0], [0, 1], [1, 0], [1, 1], [1, 2], [2, 1], [2, 2]],
                               updates=[1, 7, 9, -1, 1, 3, 7])
print(t13)
Explanation: Similarly, use tf.tensor_scatter_nd_sub to subtract values from a tensor with pre-existing values.
End of explanation
t14 = tf.constant([[-2, -7, 0],
                   [-9, 0, 1],
                   [0, -3, -8]])
t15 = tf.tensor_scatter_nd_min(t14,
                               indices=[[0, 2], [1, 1], [2, 0]],
                               updates=[-6, -5, -4])
print(t15)
Explanation: Use tf.tensor_scatter_nd_min to copy element-wise minimum values from one tensor to another.
End of explanation
t16 = tf.tensor_scatter_nd_max(t14,
                               indices=[[0, 2], [1, 1], [2, 0]],
                               updates=[6, 5, 4])
print(t16)
Explanation: Similarly, use tf.tensor_scatter_nd_max to copy element-wise maximum values from one tensor to another.
End of explanation
<END_TASK>