---
# System prepended metadata

title: Pytorch ML 코드 중심으로 알아보기

---

# Pytorch ML 코드 중심으로 알아보기
### tensor dimension
![](https://i.imgur.com/ZLA7GZe.png)
### tensor initialization
```python
ndarray = [[1,2],[3,4]]
tensor_1 = torch.tensor(ndarray)     # ndarray -> tensor
nparray = np.array(ndarray)          # ndarray -> numpy
tensor_2 = torch.from_numpy(nparray) # numpy -> tensor
tensor_3 = torch.ones_like(tensor_1) # tensor -> tensor (차원: 동일, 값: 1)
tensor_3 = torch.rand_like(tensor_1) # tensor -> tensor (차원: 동일, 값: random)

shape = (2,2)      # 차원 모양
torch.rand(shape)  # shape 모양의 random 값 tensor
torch.ones(shape)  # shape 모양의 모든값이 1인 tensor
torch.zeros(shape) # shape 모양의 모든값이 random인 tensor
```
### tensor 특성
- bridge: numpy와 tensor는 동일한 memory 공간을 공유
    ```python
    tensor = torch.tensor([1,1])
    tensor_np = tensor.numpy()
    tensor.add_(1) # = tensor([2,2])
    print(tensor_np) # = [2,2]
    ```
- broadcasting: dimension이 다른 두 tensor간 연산이 가능하도록 조정
    ```python
    m1 = torch.FloatTensor([[1, 2]])
    m2 = torch.FloatTensor([3]) # m2: [3] -> [3,3]
    print(m1 + m2) # = tensor([[4., 5.]])

    m1 = torch.FloatTensor([[1, 2]])   # m1: [[1,2]] -> [[1,2],[1,2]]
    m2 = torch.FloatTensor([[3], [4]]) # m2: [3],[4] -> [[3, 3],[4, 4]]
    print(m1 + m2) # = tensor([4., 5.],[5., 6.]])
    ```
### tensor 주요 함수
- tensor를 GPU로 옴기기
    ```python
    if torch.cuda.is_available():
        tensor = tensor.to('cuda')
    ```
- 행/열 값 변경
    ```python
    tensor[:,0] = 0 # 1번째 column값 전부 0
    tensor[0,:] = 0 # 1번째 row값 전부 0
    tensor.add_(1)  # 모든 element에 1을 더함
    ```
- 합치기
    ```python
    tensor_a, tensor_b # shape (3,2) tensors
    torch.cat([tensor_a, tensor_b)], dim=0) # result shape (6,4)
    torch.stack([tensor_a, tensor_b)], dim=0) # result shape (2,3,4)
    ```
- 덧샘
    ```python
    tensor = torch.FloatTensor([[1, 2], [3, 4]])
    tensor.sum() # = tensor(10.)
    tensor.sum(dim=0)  # = tensor([4., 6.]) 밖에서 부터 첫번째 차원
    tensor.sum(dim=1)  # = tensor([3., 7.]) 밖에서 부터 두번째 차원
    tensor.sum(dim=-1) # = tensor([3., 7.]) 안쪽에서 부터 첫번째 차원
    tensor.sum(dim=-2) # = tensor([4., 6.]) 안쪽에서 부터 두번째 차원
    ```
- 곱샘
    ```python
    tensor = torch.tensor([1,1])
    tensor.mul(tensor)      # = tensor([1, 1]) element-wise product
    tensor * tensor         # = tensor([1, 1]) element-wise product
    tensor.matmul(tensor.T) # = tensor(2)      matrix multiplcation
    tensor @ tensor.T       # = tensor(2)      matrix multiplcation
    ```
- 평균
    ```python
    tensor = torch.FloatTensor([[1, 2], [3, 4]])
    tensor.mean() # = tensor(2.5000)
    t.mean(dim=0) # = tensor([2., 3.])
    t.mean(dim=1) # = tensor([1.5000, 3.5000])
    ```
- 최대값
    ```python
    tensor = torch.FloatTensor([[1, 2], [3, 4]])
    tensor.max()         # = tensor(4.)
    tensor.max(dim=0)    # = (tensor([3., 4.]), tensor([1, 1]))
    tensor.max(dim=0)[0] # = tensor([3., 4.]) dim=0 기준 max 값
    tensor.max(dim=0)[1] # = tensor([1, 1])   dim=0 기준 argmax 값 (각 index)
    ```
- dimension 변경
    ```python
    tensor_a.shape              # = torch.Size([1, 2, 3])
    tensor_a.view(-1,3).shape   # = torch.Size([2,3])  1 * 2 * 3 = ? * 3
    tensor_a.view(-1,2,3).shape # = torch.Size([1,2,3])  1 * 2 * 3 = ? * 2 * 3
    
    tensor_b.shape              # = torch.Size([1,2,1,2])
    tensor_b.squeeze().shape    # = torch.Size([2,2]) 값이 1인 차원을 제거
    
    tensor_c.shape              # = torch.Size([2,2])
    tensor_c.unsqueeze(0).shape # = torch.Size([1,2,2]) 0번째 위치에 차원 추가
    tensor_c.unsqueeze(1).shape # = torch.Size([2,1,2]) 1번째 위치에 차원 추가
    ```
- type casting
    ```python
    lt = torch.LongTensor([1, 2, 3, 4])
    lt.float() # = tensor([1., 2., 3., 4.])
    
    bt = torch.BoolTensor([True, False, False, True])
    bt.byte()  # = tensor([1, 0, 0, 1], dtype=torch.uint8)
    ```
- 덮어쓰기
    ```python
    x = torch.FloatTensor([[1, 2], [3, 4]])
    x.mul(2.)  # = tensor([[2, 4], [6, 8]])
    x          # = tensor([[1, 2], [3, 4]]) x 변수는 변하지 않음
    x.mul_(2.) # = tensor([[2, 4], [6, 8]]) 함수 뒤에 _를 사용하면 변수 덮어쓰기
    x          # = tensor([[2, 4], [6, 8]])
    ```
- 난수 발생 seed 설정
    ```python
    torch.manual_seed(3)     # 3번째 random seed
    for i in range(1,3):
        print(torch.rand(1)) # tensor([0.0043]) , tensor([0.1056])
    ```
### linear regression
```python
x_train = torch.FloatTensor([[1], [2], [3]]) # 공부에 투자한 시간 1,2,3 시간
y_train = torch.FloatTensor([[2], [4], [6]]) # 시험 성적 2,4,6 점

# W의 차원은 x의 개수에 비례한다. x가 3개면 W는 (3,1)이 된다.
# 지금 x의 개수는 시간이라는 변수 1개이며 총 3개의 데이터가 있으니 W의 차원은 1이 된다.
W = torch.zeros(1, requires_grad=True) # requires_grad는 학습되는 값을 추적하기 위함
b = torch.zeros(1, requires_grad=True)

optimizer = optim.SGD([W, b], lr=0.01)

nb_epochs = 1999 # 원하는만큼 경사 하강법을 반복
for epoch in range(nb_epochs + 1):
    
    hypothesis = x_train.matmul(W) + b # H(x) = Wx + b x_train.matmul(W) + b
    cost = torch.mean((hypothesis - y_train) ** 2) # cost = avg((H(x) - y)^2)

    optimizer.zero_grad() # optimizer의 기울기는 누적되는 특징 때문에 0으로 초기화
    cost.backward()       # 비용함수 미분하여 gradient 계산
    optimizer.step()      # W와 b 업데이트

    if epoch % 100 == 0:  # 100번마다 로그 출력
        print('Epoch {:4d}/{} W: {:.3f}, b: {:.3f} Cost: {:.6f}'.format(
            epoch, nb_epochs, W.item(), b.item(), cost.item()
        ))
```