<jupyter_start><jupyter_text>Introduction  Getting Started with Pytorch<jupyter_code>import torch # most of the functionality required for today is here
import matplotlib.pyplot as plt
import numpy as np<jupyter_output><empty_output><jupyter_text>Define an empty tensor in PyTorch with size = 5<jupyter_code>x = 
print(x)<jupyter_output><empty_output><jupyter_text>Fill a PyTorch tensor with a certain scalar<jupyter_code># build a tensor that contains [-1,3] as its elements 
x = 
print(x)
# fill x with zeros on instantiation
x = 
print(x)
# fill x with ones on instantiation
x = 
print(x)<jupyter_output><empty_output><jupyter_text>Build a PyTorch tensor and fill it with a range between -2 and 2<jupyter_code># experiment with torch.arange
x = 
print(x)
# experiment with torch.linspace
x = 
print(x)<jupyter_output><empty_output><jupyter_text>Fill a PyTorch tensor with random numbers<jupyter_code># experiment with torch.randn 
x = 
print(x)<jupyter_output><empty_output><jupyter_text>Define a new PyTorch tensor that has the same shape as x with type float and fill it with random numbers<jupyter_code># experiment with torch.randn_like
y = 
print(y)<jupyter_output><empty_output><jupyter_text>Define a new tensor that has the same type as x, but a different size and fill it with ones.<jupyter_code>#experiment with new_ones
y = 
print(y)<jupyter_output><empty_output><jupyter_text>Find minimum value of a PyTorch tensor<jupyter_code>#Find the minimum value of the previous Pytorch tensor
x<jupyter_output><empty_output><jupyter_text>Reshape a tensor<jupyter_code># Define a tensor
initial_tensor = torch.tensor(
[
    [
        [ 1,  2,  3,  4],
        [ 5,  6,  7,  8]
    ]
    ,
    [
        [ 9, 10, 11, 12],
        [13, 14, 15, 16]
    ]
    ,
    [
        [17, 18, 19, 20],
        [21, 22, 23, 24]
    ]
])
# check the shape of initial_tensor
# update the shape and experiment with .view
reshaped_tensor = 
print(reshaped_tensor)<jupyter_output><empty_output><jupyter_text>Flatten a tensor<jupyter_code># Define a tensor
initial_tensor = torch.tensor(
[
    [
        [ 1,  2,  3,  4],
        [ 5,  6,  7,  8]
    ]
    ,
    [
        [ 9, 10, 11, 12],
        [13, 14, 15, 16]
    ]
    ,
    [
        [17, 18, 19, 20],
        [21, 22, 23, 24]
    ]
])

# flat the tensor with .view
flattened_tensor = 
print(flattened_tensor)<jupyter_output><empty_output><jupyter_text>Convert a Py list to a PyTorch tensor and vice versa<jupyter_code># List to a tensor
py_list = [1,2,3,4] 

x = 
print(x)<jupyter_output><empty_output><jupyter_text>Convert a PyTorch tensor to a Py list<jupyter_code>#Tensor to list
x = torch.randn(10)

py_list = 
print(py_list)
print(type(py_list))<jupyter_output><empty_output><jupyter_text>Multiply tensors with a scalar<jupyter_code># define a tensor
x = 

# multiply it by 2
x2 = 
print(x2)<jupyter_output><empty_output><jupyter_text>Dot product two tensorsThe dot product between vectors is defined as \\$\overrightarrow{u}=(a ,b) \quad \overrightarrow{v}=(x,y)$ \\$\overrightarrow{u} \cdot \overrightarrow{v}=ax + by $ \\ \\ Matrix representation \\$\begin{bmatrix}a & b  \\\end{bmatrix}\cdot $$\begin{bmatrix}x\\y\\\end{bmatrix}=$$\begin{bmatrix}ax + by\\\end{bmatrix}$ \\\\2 dot products between a matrix and a vector is defined as \\$\begin{bmatrix}a & b \\c & d \\\end{bmatrix}\cdot $$\begin{bmatrix}x\\y\\\end{bmatrix}=$$\begin{bmatrix}ax+by\\cx+dy\\\end{bmatrix}$<jupyter_code># define tensor a to be a vector by a defined list
a =
# define tensor b to be a vector by a defined list
b =

# compute dot product<jupyter_output><empty_output><jupyter_text>Matrix Multiplications in PyTorch$M^1$ is a $p$ x $m$ matrix and $M^2$ is a $m$ x $q$ matrix. The product of $M^1$ and $M^2$ is a $p$ x $q$ matrix \\$M^1_{pm} \cdot M^2_{mq} = M^3_{pq}$ \\ \\$M^3=[m_{ij}]$ and each element of $M^3$ is defined as \\$m_{ij}= row_i (M^1) \cdot col_j(M^2)$<jupyter_code># define M1 tensor of random integers
M1 =
# define M2 tensor of random integers
M2 =

# NOTE: pay attention to the sizes of the matrices
# multiply
torch.
# more examples
# multiply the data tensor with itself
data = torch.randn(5)
# multiply the tensor with its transpose
data = torch.randn(2,5)<jupyter_output><empty_output><jupyter_text>Transpose a matrix in PyTorch$$A=\begin{bmatrix}a_{11} & a_{12} & ...\quad a_{1n}\\a_{21} & a_{22} & ... \quad a_{2n}\\\cdot & \cdot &\quad\cdot\\a_{m1} & a_{m2} & ... \quad a_{mn}\\\end{bmatrix}$ ;$A^T=\begin{bmatrix}a_{11} & a_{21} & ...\quad a_{m1}\\a_{12} & a_{22} & ... \quad a_{m2}\\\cdot & \cdot &\quad\cdot\\a_{1n} & a_{2n} & ... \quad a_{mn}\\\end{bmatrix}$$<jupyter_code>M1_t = torch.t(M1)
# print(M1, M1_t)
# simulate a 2D image as a random matrix with size 200x250
data = 

# build a visual feature in it by setting columns 100:120 to a constant value
data

# plot it with imshow
plt.imshow(data)
# transpose it using data.t
# replot it using imshow and see how it is rotated
plt.imshow(torch.t(data))<jupyter_output><empty_output><jupyter_text>Transpose Images Read the image provided to you, display it, transpose it, and display itagain.<jupyter_code># repeat the previous exercise with this image:
!wget "https://drive.google.com/uc?id=1DeAk2H22KadwmVmLshtbll6K-NkO5Vwb" -O 'veins.jpg'
#plot the dowloaded image using imshow
img = plt.imread('veins.png')
plt.imshow(img)
# transpose and display image<jupyter_output><empty_output><jupyter_text>Linear Algebra: Matrix Determinant<jupyter_code># define a random 2x2 tensor with randn

# compute the determinant with .det<jupyter_output><empty_output><jupyter_text>Linear Algebra: Eigenvalues<jupyter_code># define a diagonal 2x2 matrix

# data = torch.

# compute the eigenvalues and eigenvectors with torch.eig

# look at it, what do you see?<jupyter_output><empty_output><jupyter_text>Hands-on Challenge Introduction You are going to make a simple feed-forward neural network. It will be fully connected; that is each neuron will recieve inputs from all the neurons in the previous layer, and output to all the neurons in the next layer. This kind of network is also called a *multi-layer perceptron* or MLP. Such layers in PyTorch are called *linear* layers.  We will use the way Pytorch defines neural networks as our template. Your MLP will be implemented as a class with two methods: an *init* and a *forward* method.The *init* method will create the network, and the *forward* method is what is called to 'run' it; that is to send an instance of input data and recieve an output. We will also include a *reset* method to clear out all the outputs. You are recommended to define a class for layer, linearlayer and MLP since this would help to orgnaize better your code.Each layer in the network will also be defined in the same way. Another quirk of PyTorch is that it defines the neuron activation functions as a separate layer, right after its associated linear layer. **NOTE** You can use either PyTorch or numpy to implement your MLP. It is up to you which to use. Try and see if you can implement it in both!Here is the code template for the MLP itself.<jupyter_code>class layer():
    
    #layer class with only node_dim to specify
    #This is the representation of just one layer
    #we will use this as a base class for linearlayer and non-linear functions
    
    def __init__(self, node_dim):
        """
        This init should be called via super() with the number
        of nodes as an argument.
        """
        #define basics that a layer would have: input, input_grad
    
    def forward(self, x):
        #define input as x
    
    def zero_grad(self):
        #clean your input_grad

class linearlayer():
    # This could be a linear layer (with inputs and outputs)
    def __init__(self, in_dim, out_dim, bias=True):
        #You can inherit from your base class with super() builtin function.
        self.out = #Initialize your output
        self.weights = #Initialize your weights
        if bias:
            self.bias = #create tensor biases
    
    def forward(self, x):
        #pass inputs and create your output (Remember W.X + b)
    
        return #out
    def reset(self):
        #clean outputs
    
class MLP():
    
    def __init__(self):

        # The MLP will be a list with each layer as an item. 
        # The linearlayer class will calculate the outputs from inputs, weights and biases calling the forward method on it
        # just with input and output dimensions as parameters. The forward method would take the data.
        self.net = []
        
        # Construct the MLP by appending layers, example:
        # self.net.append(linearlayer(dim_in, dim_out))

    def forward(self, x):

        # Input x for each layer in the net and return the result back into x, ready as input for the next layer. 
        for layer in self.net:
            x = layer.forward(x) 

        return x

    def reset(self):
        # traverse the MLP and call each layers 'reset' method
        for layer in self.net:
            layer.reset()
            
#Let's see if it works
model = MLP()

x = np.random.random(10) #inputs

print(x)
print(model.forward(x))<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.10328638497652583, 'fraction_numerical': 0.01790588492193471, 'mean_word_length': 3.649746192893401, 'pattern_counts': {'":': 0, '<': 81, '<?xml version=': 0, '>': 81, 'https://': 1, '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': '20', 'dir': 'jupyter-structured-clean-dedup', 'id': '473637', 'license': 'MIT', 'n_tokens_mistral': 3175, 'n_tokens_neox': 2993, 'n_words': 1080, 'path': 'mathematics of deep learning/Session_01/Notebooks/Notebook1-PytorchBasics-LinearAlgebra.ipynb', 'repo_name': 'rcuevass/original-handson-packages', 'size': '9159'}