<jupyter_start><jupyter_text>In this notebook, we're going to cover some of the most fundamental concepts of tensors using TensorFlowMore specifically, we're going to:- Introduction to tensors- getting information from tensors- manipulating tensors- Tensors & Numpy- Using @tf function (a way to speed up your regular Python functions)- Using GPUs with TensorFlow (or TPUs)- Exercises to try for yourself Introduction to Tensors<jupyter_code># Import TensorFlow

import tensorflow as tf

print(tf.__version__)
# Create tensors with tf.constant()

scalar = tf.constant(7)
scalar
# Chceck the number of dimensions of a tensor(ndim stands for number of dimensions)

scalar.ndim
# Create a vector

vector = tf.constant([10,10])
vector
#Check the dimesion of our vector

vector.ndim
# Create a matrix (has more than 1 dimension)

matrix = tf.constant([[10,7],
                      [7,10]])
matrix
matrix.ndim
# Create another matrix

another_matrix = tf.constant([[17.,18.,],
                              [4.,7.],
                              [6.,7.]], dtype = tf.float16) #specify the data type with the type parameter

#stroing as float16 takes up less space

another_matrix
# What's the number dimensions of another matrix?

another_matrix.ndim
# Let's create a tensor

tensor = tf.constant([[[1,2,3], [4,5,6]], [[7,8,9], [10,11,12]], [[13,14,15], [16,17,18]]])

tensor
tensor.ndim<jupyter_output><empty_output><jupyter_text>What we've created so far:* Scaler: a single number* Vector: a number with direction( e.g wind speed & direction)* Matrix: a 2-dimensional array of numbers* Tensor: an n-dimensional array of numbers ( where n can be any number, a 0-dimaensional tensor is a scalar, a 1-dimensional tensor is a vector) Creating tensors with tf.variable<jupyter_code># Create the same tensor with tf.variabel() as above

changeable_tensor = tf.Variable([10,7])
unchangeable_tensor = tf.constant([10,7])
changeable_tensor, unchangeable_tensor
# Let's try to change one of the elements in our changeable tensor

changeable_tensor[0] = 7
changeable_tensor
# How about we try .assign()

changeable_tensor[0].assign(7)
changeable_tensor
# Let;s try to change our unchangeable tensor

unchangeable_tensor[0].assign(7)
unchangeable_tensor<jupyter_output><empty_output><jupyter_text>**Note:** Rarely in practice will you need to decisde whether to use tf.constant or tf.Variable to create tensors are Tensorflow does this for you. However, if in doubt, use tf.constant and change later if needed. Creating random tensorsRandom tensors are tensors of some arbitrary size containing random numbers<jupyter_code># Create two random (but the same) tensors

random_1 = tf.random.Generator.from_seed(42) # set seed for reproducibility
random_1 = random_1.normal(shape = (3,2))
random_2 = tf.random.Generator.from_seed(42)
random_2 = random_2.normal(shape = (3,2))

# Are they equal?
random_1, random_2, random_1 == random_2

 #Shuffle the order of elements in a tensor
# Shuffle a tensor (valuable for when you want to shuffle your data so the inherent order dosen't affect learning)

not_shuffled = tf.constant([[10,7], [3,4], [2,5]])

#Shuffle non-shuffled.tensor
tf.random.set_seed(42) #global level seed
tf.random.shuffle(not_shuffled, seed = 42) #operation level seeds<jupyter_output><empty_output><jupyter_text>Excercise:Read through Tensorflow documentation on random seed generation:https://www.tensorflow.org/api_docs/python/tf/random/set_seed and practice writing 5 random tensors<jupyter_code>#1

var = tf.constant([[[3,4],[4,3]],[[3,4], [5,6]]])

#tf.random.set_seed(3)
tf.random.shuffle(var)<jupyter_output><empty_output><jupyter_text>Other ways to make tensors<jupyter_code># Create a tensor of all ones

tf.ones([10,7])
# Create a tensor of all zeroes

tf.zeros(shape = (3,4))<jupyter_output><empty_output><jupyter_text>Turn NumPy arrays into tensorsThe main difference between NumPy arrays and TensorFlow tensors is that tensors can be run on a GPU (faster computing)<jupyter_code># You can also turn NumPy arrays into tensors

import numpy as np
numpy_A = np.arange(1,25,dtype = np.int32) # create a NumPy array between 1 and 25

numpy_A

#X = tf.constant(some_matrix) #capital for matrix or tensor
#y = tf.constant(vector) # non-capital for vector
A = tf.constant(numpy_A, shape = (2,3,4))
B = tf.constant(numpy_A)
A, B
2*3*4<jupyter_output><empty_output><jupyter_text>Getting information from TensorsWhen dealing with tensors you probably want to be awate of the gfollowing attributes:* Shape* Rank* Axis or dimestion* Size<jupyter_code># Create a rank 4 tensor

rank_4_tensor = tf.zeros([2,3,4,5])
rank_4_tensor
rank_4_tensor[0]
rank_4_tensor.shape, rank_4_tensor.ndim, tf.size(rank_4_tensor)
2*3*4*5
# Get various attributes of our tensor
print("Datatyoe of every element:", rank_4_tensor.dtype)
print("Number of dimensions (rank):", rank_4_tensor.ndim)
print("Shape of tensor:", rank_4_tensor.shape)
print("Elements along the 0 axis:", rank_4_tensor.shape[0])
print("Elements along the last axis:", rank_4_tensor.shape[-1])
print("Total nimber of elements in our tensor:", tf.size(rank_4_tensor).numpy())
print("Total nimber of elements in our tensor:", tf.size(rank_4_tensor))<jupyter_output><empty_output><jupyter_text>Indexing tensorstensors can be indexed just like Python lists.<jupyter_code># Get the first 2 elements of each dimension

rank_4_tensor[:2,:2,:2,:2]


# Get the first element from each dimension from each index except for the final one

rank_4_tensor[:1,:1,:, :1]
# Create a rank 2 tensor (2 cimensions)

rank_2_tensor = tf.constant([[3,4], [4,6]])

rank_2_tensor.shape, rank_2_tensor.ndim
# Get the last item of each row of rank 2 tensor

rank_2_tensor[:,-1]

# Add in extra dimension to our rank 2 tensor

rank_3_tensor = rank_2_tensor[..., tf.newaxis] #means on every previous axis before new one
rank_3_tensor
# Alternative to tf.newaxis

tf.expand_dims(rank_2_tensor, axis = -1) #"-1" means expand the final axis

tf.expand_dims(rank_2_tensor, axis = 0)<jupyter_output><empty_output><jupyter_text>Manipulating tensors (tensor operations)**Basic operations** Element-wise operations<jupyter_code># You can add values to a tensor using the addition operator

tensor = tf.constant([[10,7], [3,4]])

tensor + 10
# Original tensor is unchanged

#tensor = tensor + 10
tensor
# Multiplication also works

tensor * 10
# Subtractions if you want

tensor - 10
# We can use the tensorflow built-in function too

tf.multiply(tensor, 10)

#use tf functinos when doing operations use the tf.math so that it wil run faster on GPU<jupyter_output><empty_output><jupyter_text>Matrix MultiplicationIn machine learning, matrix multiplication is one of the most common tensor operationsThere are two rules our tensors (or matrices) need to fulfill if we're going to matrix mltiply them:1. The inner dimensions must match2. The resulting matrix has the shape of the outer dimesnions<jupyter_code># Matrix multiplication in tensorflow

print(tensor)
tf.matmul(tensor, tensor)


ten = tf.constant([[1,2,5], [7,2,1],[3,3,3]])
ten2 = tf.constant([[3,5],[6,7],[1,8]])

tf.matmul(ten, ten2)
# Matrix multiplication with python operator "@"

tensor @ tensor
# Create a tensor (3,2)

X = tf.constant([[1,2],[3,4], [5,6]])
Y = tf.constant([[7,8],[9,10], [11,12]])

X, Y
# Try to matrix multiply tensors of same shape

tf.matmul(X,Y)
# In this case, the inner dimensions are [3,2], [2,3] (the 2 and 3 in the inner area)

#Let's change the shae of Y

tf.reshape(Y, shape = (2,3))
# Try to multiply X by resshaped Y

X @ tf.reshape(Y, shape = (2,3))
tf.matmul(X, tf.reshape(Y, shape = (2,3)))
# Try change the shape of X instead of Y

tf.matmul(tf.reshape(X, shape = (2,3)), Y)
# Can do the same with transpose

tf.transpose(X), tf.reshape(X, shape = (2,3))
# Try matrix multimlication with transpose rather than reshape

tf.matmul(tf.transpose(X), Y)<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.10877281947261663, 'fraction_numerical': 0.03156693711967545, 'mean_word_length': 5.321314102564102, 'pattern_counts': {'":': 0, '<': 41, '<?xml version=': 0, '>': 41, 'https://': 1, 'lorem ipsum': 0, 'www.': 1, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '10', 'dir': 'jupyter-structured-clean-dedup', 'id': '207303', 'license': 'MIT', 'n_tokens_mistral': 2702, 'n_tokens_neox': 2573, 'n_words': 883, 'path': 'mikas_tensorflow_fundamentals.ipynb', 'repo_name': 'artms-18/tensorflow_fundamentals', 'size': '7888'}