# 4-6-1-3. Single layer neural networks solution

so features times weights.

So these tensors, they work basically the same as NumPy arrays,

if you’ve used NumPy before.

So, when you multiply features times weights,

it’ll just take the first element from each one, multiply them together,

take the second element and multiply them together and so

on and give you back a new tensor,

where there’s element by element multiplication.

So, from that we can do torch.sum to sum it all up into one value,

add our bias term and then pass it through the activation function and then we get Y.

So, we can also do this where we do features times weights again,

and this creates another tensor,

but tensors have a method.sum,

where you just take a tensor do.sum and then it sums up all the values in that tensor.

So, we can either do it this way or we do torch.sum,

or we can just take this method,

this sum method of a tensor and some upper values that way.

Again, pass it through our our activation function.

So, here what we’re doing, we’re doing

this element wise multiplication and taking the sum in two separate operations.

We’re doing this multiplication and then we’re doing the sum.

But you can actually do this in the same operation using matrix multiplication.

So, in general, you’re going to be wanting to

use matrix multiplications most of the time,

since they’re the more efficient and

these linear algebra operations have been accelerated using modern libraries,

such as CUDA that run on GPUs.

To do matrix multiplication in PyTorch with our two tensors features and weights,

we can use one of two methods.

So, either torch.mm or torch.matmul.

So, torch.mm, so matrix multiplication is more

simple and more strict about the tensors that you pass in.

So, torch.matmul, it actually supports broadcasting.

So, if you put in tensors that have weird sizes,

weird shapes, then you could get an output that you’re not expecting.

So, what I tend to use torch.mm more often,

so that it does what I expect basically,

and then if I get something wrong it’s going throw an error instead of just

doing it and continuing the calculations.

So, however, if we actually try to use

torch.mm with features and weights, we’ll get an error.

So, here we see RuntimeError, size mismatch.

So, what this means is that we passed in our two tensors to torch.mm,

but there’s a mismatch in the sizes and it can’t actually do

the matrix multiplication and it lists out the sizes here.

So, the first tensor,

M1 is one by five and the second tensor is one by five also.

So, if you remember from your linear algebra classes or if you studied it recently,

when you’re doing matrix multiplication,

the first matrix has to have a number of

columns that’s equal to the number of rows in the second matrix.

So, really what we need is we need our weights tensor,

our weights matrix to be five by one instead of one by five.

To checkout the shape of tensors,

as you’re building your networks,

you want to use tensor.shape.

So, this is something you’re going to be using all the time in PyTorch,

but also in TensorFlow and in other deep learning frameworks So,

most of the errors you’re going to see when you’re building networks and

just a lot of the difficulty when it comes to

designing the architecture of neural networks is getting

the shapes of your tensors to work right together.

So, what that means is that a large part of debugging,

you’re actually going to be trying to look at

the shape of your tensors as they’re going through your network.

So, remember this, tensor.shape.

So, for reshaping tensors,

there are three, in general,

three different options to choose from.

So, we have these methods;

reshape, resize, and view.

The way these all work, in general,

is that you take your tensor

weights.reshape and then pass in the new shape that you want.

So, in this case,

you want to change our weights to be a five by one matrix,

so we’d say.reshape and then five comma one.

So, reshape here, what it will do is it’s going to

return a new tensor with the same data as weights.

So, the same data that’s sitting in memory at those addresses in memory.

So, it’s going to basically just create

a new tensor that has the shape that you requested,

but the actual data in memory isn’t being changed.

But that’s only sometimes.

Sometimes it does return a clone and what that means is that it actually

copies the data to another part of memory and then returns

you a tensor on top of that part of the memory.

As you can imagine when it actually does that,

when it’s copying the data that’s less efficient than if you had

just changed the shape of your tensor without cloning the data.

To do something like that,

we can use resize, where there’s underscore at the end.

The underscore means that this method is an in-place operation.

So, when it’s in-place,

that basically means that you’re just not touching the data

at all and all you’re doing is changing

the tensor that’s sitting on top of that addressed data in memory.

The problem with the resize method is that if you request

a shape that has more or less elements than the original tensor,

then you can actually cut off,

you can actually lose some of the data that you had or you can

create this spurious data from uninitialized memory.

So instead, what you typically want is

that you want a method that’s going to return an error

if you changed the shape from

the original number of elements to a different number of elements.

So, we can actually do that with.view.

So.view is the one that I use the most,

and basically what it does it just returns a new tensor

with the same data in memory as weights.

This is just all the time, 100 percent of the time,

all it’s going to do is return a new tensor without

messing with any of the data in memory.

If you tried to get a new size,

a new shape for your tensor with a different number of elements,

it’ll return an error.

So, you are basically using.view,

you’re ensuring that you will always get

the same number of elements when you change the shape of your weights.

So, this is why I typically use when I’m reshaping tensors.

So, with all that out of the way,

if you want to reshape weights to have five rows and one column,

then you can use something like weights.view (5, 1), right.

So, now, that you have seen how you can change

the shape of a tensor and also do matrix multiplication,

so this time I want you to calculate the output of

this little neural network using matrix multiplication.

이제 이것이 이 운동에 대한 나의 솔루션입니다.

이 작고 단순한 신경망의 출력을 계산할 때.

그래서, 우리가 하고 싶은 것은 우리의 특징을 우리의 가중치로 곱하는 것임을 기억하십시오.

so는 가중치를 곱한 것을 특징으로 합니다.

따라서 이 텐서는 기본적으로 NumPy 배열과 동일하게 작동합니다.

이전에 NumPy를 사용한 적이 있다면.

따라서 특성에 가중치를 곱하면

각 요소에서 첫 번째 요소를 가져와 함께 곱합니다.

두 번째 요소를 가져 와서 함께 곱하십시오.

새로운 텐서를 돌려주고,

요소별 곱셈이 있는 곳입니다.

그래서 우리는 그 모든 것을 하나의 값으로 요약하기 위해 torch.sum을 할 수 있습니다.

편향 항을 추가한 다음 활성화 함수를 통해 전달하면 Y를 얻습니다.

따라서 특성 곱하기 가중치를 다시 수행하는 경우에도 이 작업을 수행할 수 있습니다.

이것은 또 다른 텐서를 생성합니다.

하지만 텐서에는 method.sum이 있습니다.

여기서 텐서 do.sum을 취하면 해당 텐서의 모든 값을 합산합니다.

따라서 우리는 이 방법을 사용하거나 torch.sum을 수행할 수 있습니다.

또는 이 방법을 사용할 수 있습니다.

텐서의 이 합계 방법과 그런 식으로 일부 상위 값.

다시 활성화 함수를 통해 전달합니다.

자, 여기서 우리가 하는 일, 우리가 하고 있는 일

이 요소 현명한 곱셈과 두 개의 개별 연산에서 합을 취합니다.

우리는 이 곱셈을 하고 그 다음 합을 합니다.

그러나 실제로는 행렬 곱셈을 사용하여 동일한 연산에서 이 작업을 수행할 수 있습니다.

따라서 일반적으로 다음을 원할 것입니다.

대부분의 경우 행렬 곱셈을 사용합니다.

더 효율적이고

이러한 선형 대수 연산은 최신 라이브러리를 사용하여 가속화되었습니다.

GPU에서 실행되는 CUDA와 같은.

두 개의 텐서 기능과 가중치를 사용하여 PyTorch에서 행렬 곱셈을 수행하려면

우리는 두 가지 방법 중 하나를 사용할 수 있습니다.

따라서 torch.mm 또는 torch.matmul 중 하나입니다.

그래서, 토치.mm, 그래서 행렬 곱셈은 더

전달하는 텐서에 대해 간단하고 더 엄격합니다.

그래서, torch.matmul은 실제로 방송을 지원합니다.

따라서 이상한 크기의 텐서를 넣으면

이상한 모양을 만들면 예상하지 못한 결과를 얻을 수 있습니다.

그래서 내가 torch.mm를 더 자주 사용하는 경향이 있습니다.

기본적으로 내가 기대하는 대로 작동하도록

그리고 내가 뭔가 잘못되면 그냥 오류가 발생하는 대신 오류가 발생합니다.

하고 계산을 계속합니다.

그러나 실제로 사용하려고 하면

토치.mm에 기능과 가중치가 있으면 오류가 발생합니다.

따라서 여기에서 RuntimeError, 크기 불일치가 표시됩니다.

이것이 의미하는 바는 우리가 두 개의 텐서를torch.mm에 전달했다는 것입니다.

그러나 크기가 일치하지 않으며 실제로 할 수 없습니다.

행렬 곱셈은 여기에 크기를 나열합니다.

따라서 첫 번째 텐서는

M1은 1×5이고 두 번째 텐서도 1×5입니다.

따라서 선형 대수 수업에서 기억하거나 최근에 공부했다면,

행렬 곱셈을 할 때

첫 번째 행렬은

두 번째 행렬의 행 수와 동일한 열입니다.

그래서, 정말로 우리에게 필요한 것은 우리의 가중치 텐서가 필요하다는 것입니다.

우리의 가중치 행렬은 1×5 대신 5×1이 되도록 합니다.

텐서의 모양을 확인하려면

네트워크를 구축할 때

tensor.shape를 사용하고 싶습니다.

이것은 PyTorch에서 항상 사용하게 될 것입니다.

TensorFlow 및 기타 딥 러닝 프레임워크에서도

네트워크를 구축할 때 보게 될 대부분의 오류와

단지 많은 어려움을 겪을 때

신경망 아키텍처를 설계하는 것은

텐서의 모양이 함께 작동하도록 합니다.

이것이 의미하는 바는 디버깅의 많은 부분이

당신은 실제로 보려고 할 것입니다

네트워크를 통과하는 텐서의 모양.

그러니 tensor.shape를 기억하세요.

따라서 텐서를 재구성하려면

일반적으로 세 가지가 있습니다.

선택할 수있는 세 가지 다른 옵션.

그래서 우리는 이러한 방법을 가지고 있습니다.

모양을 변경하고 크기를 조정하고 볼 수 있습니다.

일반적으로 이러한 모든 작동 방식은

그것은 당신이 당신의 텐서를 가져 간다는 것입니다

weights.reshape를 선택한 다음 원하는 새 모양을 전달합니다.

따라서 이 경우,

가중치를 5×1 행렬로 변경하고 싶습니다.

그래서 우리는 .reshape를 말한 다음 5개의 쉼표를 1이라고 말할 것입니다.

자, 여기에서 모양을 바꾸면 다음과 같이 됩니다.

가중치와 동일한 데이터를 가진 새 텐서를 반환합니다.

따라서 메모리의 해당 주소에서 메모리에 있는 동일한 데이터입니다.

기본적으로

요청한 모양의 새 텐서,

그러나 메모리의 실제 데이터는 변경되지 않습니다.

그러나 그것은 가끔일 뿐입니다.

때로는 클론을 반환하며 이것이 의미하는 바는 실제로

데이터를 메모리의 다른 부분에 복사한 다음 반환

당신은 메모리의 그 부분 위에 있는 텐서입니다.

실제로 그렇게 할 때 상상할 수 있듯이,

데이터를 복사할 때

데이터를 복제하지 않고 텐서의 모양을 변경했습니다.

그런 일을 하려면,

끝에 밑줄이 있는 크기 조정을 사용할 수 있습니다.

밑줄은 이 메서드가 제자리 작업임을 의미합니다.

그래서 그것이 제자리에 있을 때,

그것은 기본적으로 당신이 데이터를 건드리지 않는다는 것을 의미합니다

당신이하고있는 모든 것이 바뀌고 있습니다.

메모리의 주소 지정된 데이터 위에 있는 텐서입니다.

크기 조정 방법의 문제는 요청하는 경우

원래 텐서보다 많거나 적은 요소가 있는 모양,

그러면 실제로 차단할 수 있습니다.

당신은 실제로 당신이 가지고 있던 데이터의 일부를 잃을 수 있습니다.

초기화되지 않은 메모리에서 이 가짜 데이터를 만듭니다.

따라서 일반적으로 원하는 것은

오류를 반환할 메서드를 원한다는 것

모양을 변경한 경우

요소의 원래 수를 다른 수의 요소로 변경합니다.

따라서 실제로 .view를 사용하여 그렇게 할 수 있습니다.

그래서.view는 내가 가장 많이 사용하는 것,

기본적으로 수행하는 작업은 새 텐서를 반환합니다.

메모리에 있는 동일한 데이터를 가중치로 사용합니다.

이것은 항상, 10

하지 않고 새 텐서를 반환하기만 하면 됩니다.

메모리에 있는 모든 데이터를 엉망으로 만듭니다.

새로운 크기를 얻으려고 했다면,

요소 수가 다른 텐서의 새로운 모양,

그것은 오류를 반환합니다.

따라서 기본적으로 .view를 사용하고 있습니다.

당신은 당신이 항상 얻을 것이라고 확신합니다

가중치의 모양을 변경할 때 동일한 수의 요소.

이것이 내가 텐서를 재구성할 때 일반적으로 사용하는 이유입니다.

그래서, 그 모든 것을 제외하고,

5개의 행과 1개의 열로 가중치를 변경하려면

그런 다음 weights.view (5, 1)와 같은 것을 사용할 수 있습니다.

자, 이제 어떻게 변화할 수 있는지 알아보았습니다.

텐서의 모양과 행렬 곱셈을 수행합니다.

그래서 이번에는 출력을 계산하기를 원합니다.

행렬 곱셈을 사용하는 이 작은 신경망.

# First, import PyTorch
import torch

def activation(x):
""" Sigmoid activation function

Arguments
---------
x: torch.Tensor
"""
return 1/(1+torch.exp(-x))

### Generate some data
torch.manual_seed(7) # Set the random seed so things are predictable

# Features are 5 random normal variables
features = torch.randn((1, 5))
# True weights for our data, random normal variables again
weights = torch.randn_like(features)
# and a true bias term
bias = torch.randn((1, 1))

### Solution

# Now, make our labels from our data and true weights

y = activation(torch.sum(features * weights) + bias)
y = activation((features * weights).sum() + bias)

## Solution

y = activation(torch.mm(features, weights.view(5,1)) + bias)

### Generate some data
torch.manual_seed(7) # Set the random seed so things are predictable

# Features are 3 random normal variables
features = torch.randn((1, 3))

# Define the size of each layer in our network
n_input = features.shape[1]     # Number of input units, must match number of input features
n_hidden = 2                    # Number of hidden units
n_output = 1                    # Number of output units

# Weights for inputs to hidden layer
W1 = torch.randn(n_input, n_hidden)
# Weights for hidden layer to output layer
W2 = torch.randn(n_hidden, n_output)

# and bias terms for hidden and output layers
B1 = torch.randn((1, n_hidden))
B2 = torch.randn((1, n_output))

### Solution

h = activation(torch.mm(features, W1) + B1)
output = activation(torch.mm(h, W2) + B2)
print(output)