<jupyter_start><jupyter_text><jupyter_code>import tensorflow as tf
print(tf.__version__)
#teste
#Creating first tensor (using tf.constant())
#Not commonly used (tensors are usually obtained from transforming other data into tensors)
scalar = tf.constant(7)
scalar
#Check the number of dimensions 
#ndim -> number of dimensions
scalar.ndim
#Create a vector
vector = tf.constant([10,10])
vector
#Checking the dimension
vector.ndim
#Create a matrix
matrix = tf.constant([[10,7],
                     [7,10]])
matrix
#Check the dimensions
matrix.ndim
#Create another matrix with different data type
another_matrix = tf.constant([[10.,7.],
                              [3.,2.],
                              [8.,9.]],dtype = tf.float16)
another_matrix
#Checking the dimensions 
another_matrix.ndim
#Creating a tensor (a n-dimensional array of numbers, with n being any natural number)
tensor = tf.constant([[[1,2,3],
                       [4,5,6]],
                       [[7,8,9],
                        [10,11,12]],
                        [[13,14,15],
                         [16,17,18]]])
tensor
tensor.ndim
#Creating tensors wit tf.variable
changeable_tensor = tf.Variable([10,7])
unchangeable_tensor = tf.constant([10,7])
changeable_tensor,unchangeable_tensor
#Trying to change elements from our tensors
#changeable_tensor[0]=7 returns an error
changeable_tensor[0].assign(7)
changeable_tensor
#Trying to change on the constant tensor
#unchangeable_tensor[0].assign(7) 
#Returns an error<jupyter_output><empty_output><jupyter_text>Creating Random tensors<jupyter_code># Create two random (but equal) tensors
random_1 = tf.random.Generator.from_seed(42)
random_1 = random_1.normal(shape = (3,2))
random_1
random_2 = tf.random.Generator.from_seed(42)
random_2 = random_2.normal(shape=(3,2))
random_2<jupyter_output><empty_output><jupyter_text>Shuffle the order of elements in a tensor<jupyter_code>#Valuable to shuffle the data so the order doesn't impact the learning
not_shuffled = tf.constant([[10,7],
                           [3,4],
                           [2,5]])
tf.random.shuffle(not_shuffled) #Shuffles along the first dimension                           
tf.random.set_seed(42) #Global-level seed
tf.random.shuffle(not_shuffled, seed = 42) # Operation-level seed<jupyter_output><empty_output><jupyter_text>Creating tensors from NumPy<jupyter_code>tf.ones([10,7]) #Similar to numpy ones function
tf.zeros(shape=(3,4)) #Similar to numpy zeros function
import numpy as np

numpy_A = np.arange(1,25,dtype=np.int32)
numpy_A
A = tf.constant(numpy_A,shape=(2,3,4))#New shape must align with number of elements (24 = 2*3*4)
B = tf.constant(numpy_A)
A,B<jupyter_output><empty_output><jupyter_text>Getting information from tensors<jupyter_code>#Create a rank 4 tensor
rank_4_tensor = tf.zeros(shape=[2,3,4,5])
rank_4_tensor
rank_4_tensor.shape,rank_4_tensor.ndim,tf.size(rank_4_tensor)
#Get various attributes of our tensor
print('Datatype of every element: ',rank_4_tensor.dtype)
print('Rank of tensor: ',rank_4_tensor.ndim)
print('Shape:',rank_4_tensor.shape)
print('Elements along 0 axis:',rank_4_tensor.shape[0])
print('Elements along the last axis:', rank_4_tensor.shape[-1])
print('Total numbers of elements:',tf.size(rank_4_tensor).numpy())#.numpy extracts only the number from tf.tensor object<jupyter_output>Datatype of every element:  <dtype: 'float32'>
Rank of tensor:  4
Shape: (2, 3, 4, 5)
Elements along 0 axis: 2
Elements along the last axis: 5
Total numbers of elements: 120<jupyter_text>Indexing tensorsTensors can be indexed like Python lists<jupyter_code>#Get the first 2 elements from each dimension
rank_4_tensor[:2,:2,:2,:2]
#Get the first dimension from each dimension from each index except the final one
rank_4_tensor[:1,:1,:1,:]
#Create a rank 2 tensor
rank_2_tensor = tf.constant([[10,7],
                             [3,4]])
rank_2_tensor.shape,rank_2_tensor.ndim
#Get last item of each of our rank 2 tensor
rank_2_tensor[:,-1]
#Add in extra dimension to our rank 2 tensor
rank_3_tensor = rank_2_tensor[...,tf.newaxis] #... -> select all previous axes (substitutes :,:)
rank_3_tensor
#Alternative to tf.newaxis
tf.expand_dims(rank_2_tensor,axis=-1)#-1 means expand the last axis
tf.expand_dims(rank_2_tensor,axis=0)#expand the 0-axis<jupyter_output><empty_output><jupyter_text>Manipulating tensors**Basic operations**<jupyter_code>tensor = tf.constant([[10,7],[3,4]])
tensor + 10 #Mantains the original tensor intact (tensor = tensor + 10 would overwrite)
tensor*10
tensor - 10
# We can use the tensorflow built-in funtion too
tf.multiply(tensor,10) # Using the tensorflow version enables GPU-acceleration<jupyter_output><empty_output><jupyter_text>**Matrix multiplication**<jupyter_code>tf.matmul(tensor,tensor)
tensor*tensor #Element-wise multiplication
# Matrix multplication with Python operator @
tensor@tensor
#Creating tensors with different shapes
X = tf.constant ([[1,2],
                  [3,4],
                  [5,6]])
Y = tf.constant ([[7,8],
                  [9,10],
                  [11,12]])
#tf.matmul(X,Y) returns an error due to shape incompatibility 
X,Y
#Reshaping tensors to enable the dot multiplication
tf.matmul(tf.reshape(X,shape=(2,3)),Y)
#Different reshapes generate different results
tf.matmul(X,tf.reshape(Y,shape=(2,3)))<jupyter_output><empty_output><jupyter_text>In general transposing is used to adapt the tensors instead of reshaping<jupyter_code>#Can do the same with transpose with different results as well
tf.transpose(X),tf.reshape(X,shape=(2,3))
tf.matmul(tf.transpose(X),Y)
tf.tensordot(tf.transpose(X),Y,axes=1)<jupyter_output><empty_output><jupyter_text>Changing the datatype of tensors<jupyter_code>#Create a new tensor with default datatype (float32 or int32)
B = tf.constant([1.7,7.4])
B.dtype
C = tf.constant([7,10])
C.dtype
#Convert from 32 bits to 16 bit (reduced precision)
B = tf.cast(B,dtype=tf.float16) #faster computation on hardware
B<jupyter_output><empty_output><jupyter_text>Aggregating tensorsCondensing multiple values down to a smaller amount of values* Minimum * Maximum* Mean* Sum<jupyter_code>#Get the absolute values

D = tf.constant([-7,-10])
D
tf.abs(D) #[-7,10] --> [7,10]
E = tf.constant(np.random.randint(0,100,size = 50))
E
tf.size(E),E.shape,E.ndim
tf.reduce_min(E)#Minimum value
tf.reduce_max(E)#Maximum
tf.reduce_mean(E)#Mean
tf.reduce_sum(E)#Sum
import tensorflow_probability as tfp
tfp.stats.variance(E),tf.math.reduce_variance(tf.cast(E,dtype=tf.float32)) #Both return variance
#Standard deviation (needs tensor as a float)
tf.math.reduce_std(tf.cast(E,dtype=tf.float32))<jupyter_output><empty_output><jupyter_text>Find the positional maximum and minimumUseful when finding the maximum prediction probabilities<jupyter_code>tf.random.set_seed(42)
F = tf.random.uniform(shape=[50])
F
#Find the positional maximum
tf.argmax(F), F[tf.argmax(F)]
#Find the positional minimum
tf.argmin(F),F[tf.argmin(F)]<jupyter_output><empty_output><jupyter_text>Squeezing a tensor (Removing all single dimension)<jupyter_code>tf.random.set_seed(42)
G = tf.constant(tf.random.uniform(shape=[50]),shape=(1,1,1,1,50))
G
G.shape
G_squeezed = tf.squeeze(G)
G_squeezed<jupyter_output><empty_output><jupyter_text>One-hot encoding tensors<jupyter_code>#Create a list of indices
some_list = [0,1,2,3]#Ex: red, green, blue purple
#One hot encoding
tf.one_hot(some_list,depth = 4)
#Specify custom values for one hot encoding (not very useful for real life usage)

tf.one_hot(some_list,depth=4,on_value='yeppers',off_value='nope')<jupyter_output><empty_output><jupyter_text>Squaring, log, sqrt<jupyter_code>H=tf.range(1,10)
H
tf.square(H)#Square
tf.sqrt(tf.cast(H,tf.float32))#Requires float dtype
tf.math.log(tf.cast(H,dtype = tf.float32))#Calculates log of values (requires float type)<jupyter_output><empty_output><jupyter_text>Tensors and numpyTensorflow interacts beautifully with NumPy arrays<jupyter_code>J = tf.constant(np.array([3.,7.,10.]))
J
np.array(J),type(np.array(J)),type(J.numpy())
#The default types of each are slightly different
numpy_J = tf.constant(np.array([3.,7.,10.]))
tensor_J = tf.constant([3.,7.,10.])
#Check the types
numpy_J.dtype,tensor_J.dtype<jupyter_output><empty_output><jupyter_text>Finding access to GPUs<jupyter_code>tf.config.list_physical_devices()
!nvidia-smi #Check which gpu is available<jupyter_output>NVIDIA-SMI has failed because it couldn't communicate with the NVIDIA driver. Make sure that the latest NVIDIA driver is installed and running.
{'fraction_non_alphanumeric': 0.12286085211849404, 'fraction_numerical': 0.033046146583264484, 'mean_word_length': 5.3144560357675115, 'pattern_counts': {'":': 0, '<': 68, '<?xml version=': 0, '>': 71, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, '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': '17', 'dir': 'jupyter-structured-clean-dedup', 'id': '485510', 'license': 'MIT', 'n_tokens_mistral': 3073, 'n_tokens_neox': 2915, 'n_words': 708, 'path': '00_tensorflow_fundamentals_edit.ipynb', 'repo_name': 'spadao/tensorflow-deep-learning', 'size': '8473'}