728x90
1. PyTorch Basic
Module: 변수, 함수, 클래스를 담고 있는 파일 (.py)
Package: 여러 Module을 묶은 것 (folder)
- numpy와 비슷한 PyTorch
import torch
a = torch.tensor([1, 2, 3, 4])
print(a)
print(type(a))
print(a.dtype) # data type
print(a.shape)
b = torch.tensor([1, 2, 3.1, 4])
print(b.dtype) # 하나라도 실수면 자동으로 실수 타입으로
print(b)
- 하나라도 실수면 자동으로 실수 타입으로 변환
tensor([1, 2, 3, 4])
<class 'torch.Tensor'>
torch.int64
torch.Size([4])
torch.float32
tensor([1.0000, 2.0000, 3.1000, 4.0000])
torch.tensor() 안의 argument는 단일 형태로 들어가야 함 (여러 개는 X)
- torch.tensor([1,2,3], [4,5,6]):
1차원 리스트 여러개(X) - torch.tensor([[1,2,3], [4,5,6]]) : 2차원 리스트 형태로 입력 필요 (O)
- torch.tensor().shape
- torch.Size([ x, y, z ]) 반환
- torch.tensor().ndim
- 차원수를 반환 (바깥에 쌓인 대괄호 [ ] 개수)
- torch.tensor().numel()
- 전체 성분의 수를 반환
A = torch.tensor([[1, 2, 3], [3, 4, 5]]) # 이 셀부터는 import torch 는 실행 했다 치고 작성
# A = torch.tensor([[1,2],[3,4,5]]) # 리스트와는 달리 이제는 행렬이라서 각 행에 해당하는 숫자의 개수가 같아야 함
print(A)
print(A.shape)
print(A.ndim) # 차원의 수
print(A.numel()) # 전체 성분의 수
tensor([[1, 2, 3],
[3, 4, 5]])
torch.Size([2, 3])
2
6
- torch.zeros(shape)
- 0을 원소로 가지는 tensor를 동일 shape으로 반환
- numpy에서는 shape 자체를 tuple 형태 (x, y)로 줘야 작동됨 : np.zeros((x, y))
- torch.zeros_like(tensor)
- 인자의 tensor와 동일한 shape을 가지고 0을 원소로 하는 tensor 반환
- torch.ones(shape)
- 1을 원소로 가지는 tensor를 동일 shape으로 반환
- torch.arange( start, end, steps)
- start부터 end까지(end 포함) 의 숫자를 step마다 반환
- steps를 float로 설정하면 소수점 가능
- torch.linspace(start, end, n)
- start부터 end까지의 (end 포함) 범위 내의 숫자를 동일한 간격으로 n개 반환
print(torch.zeros(5))
print(torch.zeros_like(A))
print(torch.ones(5))
print(torch.zeros((3, 3))) # numpy에서는 () 튜플 자체를 입력으로 줘야함
print(torch.arange(3, 10, 2)) # range랑 같은데 tensor로 만들어줌
print(torch.arange(0, 1, 0.1)) # 소수점 가능
print(torch.linspace(0, 1, 10)) # 0 에서부터 1 포함 10개로
tensor([0., 0., 0., 0., 0.])
tensor([[0, 0, 0],
[0, 0, 0]])
tensor([1., 1., 1., 1., 1.])
tensor([[0., 0., 0.],
[0., 0., 0.],
[0., 0., 0.]])
tensor([3, 5, 7, 9])
tensor([0.0000, 0.1000, 0.2000, 0.3000, 0.4000, 0.5000, 0.6000, 0.7000, 0.8000,
0.9000])
tensor([0.0000, 0.1111, 0.2222, 0.3333, 0.4444, 0.5556, 0.6667, 0.7778, 0.8889,
1.0000])
torch.tensor() 사칙 연산
torch.tensor( ) +, - , * , / , **2 : 각 원소끼리 +, - , * , / , **2
a=torch.tensor([1,2,3])
b=torch.tensor([4,5,6])
c=a+b
print(c)
tensor([5, 7, 9])
torch.tensor( ) @
- 스칼라곱(*): Hadamard product
- [n,m] * [n,m] = [n,m]
- Array간 shape이 같을 때 or Broadcasting 가능
- 각 행렬의 원소끼리의 곱을 성분으로 갖는 행렬을 반환
- Broadcasting 가능: Matrix * (column, row) Vector ONLY
- [1,m] * [n,m] = [n,m]
- [m,1] * [m,n] = [m,n]
- [m,n] * [m,1] = [m,n]
- [n,m] * [1,m] = [n,m]
- 행렬곱 (@)
- i번째 행벡터와 j번째 열벡터의 내적을 성분으로 갖는 행렬을 반환
- 2차원에서는 .dot() & @는 동일한 기능
- 3차원에서는 텐서곱(외적)을 하게 되어 내적과 달라짐
- [n,m] @ [m,k] = [m,k]
A=torch.tensor([[1,2,3],[1,2,3]])
B=torch.tensor([[4,5,6],[1,1,1]])
C=A+B
D=A-B
print(C)
print(D)
print()
print(A*B) # 곱셈은? 성분끼리의 곱! (Hadamard product)
print(A/B) # 나누기도 마찬가지
print(B**2) # 제곱도 각 성분에 대해서 해준다
tensor([[5, 7, 9],
[2, 3, 4]])
tensor([[-3, -3, -3],
[ 0, 1, 2]])
tensor([[ 4, 10, 18],
[ 1, 2, 3]])
tensor([[0.2500, 0.4000, 0.5000],
[1.0000, 2.0000, 3.0000]])
tensor([[16, 25, 36],
[ 1, 1, 1]])
A = torch.tensor([[1, 2], [3, 4]])
B = torch.tensor([[1, 2], [3, 4]])
print(A * B)
print(A @ B) # 이게 진짜 행렬 곱하기
tensor([[ 1, 4],
[ 9, 16]])
tensor([[ 7, 10],
[15, 22]])
2. PyTorch Indexing & Slicing
a = torch.tensor([1, 2, 3, 4, 5, 6, 7, 8, 9])
# 인덱싱과 슬라이싱, list할 때와 동일!
print(a[0])
print(a[1])
print(a[-1])
print(a[1:4])
print(a[7:])
print(a[:7])
print(a[:])
tensor(1)
tensor(2)
tensor(9)
tensor([2, 3, 4])
tensor([8, 9])
tensor([1, 2, 3, 4, 5, 6, 7])
tensor([1, 2, 3, 4, 5, 6, 7, 8, 9])
- Matrix Indexing & Slicing
# 행렬에 대한 인덱싱과 슬라이싱
A = torch.tensor([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
print(A[0]) # 하나만 쓰면 행에 대한 인덱싱 (리스트 속 리스트 생각)
print(A[-1])
print(A[1:])
print(A[:])
print(A[0][2])
print(A[0, 2]) # 2차원 행렬도 동일한데, 리스트와 달리 이런 것도 됨
B = [[1, 2, 3, 4], [5, 6, 7, 8]]
print(B)
print(B[0][2])
# print(B[0,2]) # error!
print(A[1, :]) # 1 행, 전부
print(A[1, 0:3:2])
print(A[:, 2]) # 전부, 2 열
print(A[:][2])
tensor([1, 2, 3])
tensor([7, 8, 9])
tensor([[4, 5, 6],
[7, 8, 9]])
tensor([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]])
tensor(3)
tensor(3)
[[1, 2, 3, 4], [5, 6, 7, 8]]
3
tensor([4, 5, 6])
tensor([4, 6])
tensor([3, 6, 9])
tensor([7, 8, 9])
- 3차원 Matrix Indexing
- torch.SIze([depth, x, y]): [x, y]가 depth만큼 쌓였다고 생각
- depth는 직교좌표계에서의 x(+-)축 방향이라고 생각하면 편하다
- rank가 높아질수록 하나씩 오른쪽으로 밀린다
- 새로운 dimension이 추가될수록 앞에다 추가된다
x행 y열 Matrix가 depth개 있다고 생각
- 3차원 Matrix Slicing
- Matrix[ channel_n, x, y]: n 번째 channel의 (x, y) 원소
# 3차원 행렬 인덱싱
A=torch.tensor([ [[0,1,2,3],[4,5,6,7],[8,9,10,11]] ,
[[12,13,14,15],[16,17,18,19],[20,21,22,23]] ])
print(A)
print(A.shape) # 대괄호가 하나 늘어나면 왼쪽에 shape 값이 추가 된다.
print(A[0,1,2])
a=torch.tensor([[[1,2,3,4]]])
print(a.shape)
tensor([[[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]],
[[12, 13, 14, 15],
[16, 17, 18, 19],
[20, 21, 22, 23]]])
torch.Size([2, 3, 4])
tensor(6)
torch.Size([1, 1, 4])
- Boolean Indexing: torch, numpy 가능 / list는 불가능
# boolean 인덱싱
a = [1, 2, 3, 4, 5, 3, 3]
print(a == 3) # 여러개 값 들어있는 리스트랑 3 달랑 하나랑 같냐? 다르다!
A = torch.tensor([[1, 2, 3, 4], [5, 3, 7, 3]])
print(A == 3) # 리스트와 달리 각 성분에 대해 비교해줌
print(A[A == 3]) # True, False가 담긴 행렬로 인덱싱 가능!!
A[A == 3] = 100
print(A) # 그러면 이런 것도 가능하다! (3과 같은 애를 100으로 바꿔줘)
A = torch.tensor([[1, 2], [3, 4], [5, 6], [7, 8]])
B = torch.tensor([True, False, False, True]) # 참고로 그냥 리스트여도 됨
print(A[B, :]) # 0행, 3행 슬라이싱
b = torch.tensor([1, 2, 3, 4])
print(b[[True, True, False, False]])
c = [1, 2, 3, 4]
# c[[True,True,False,False]] # error!
False
tensor([[False, False, True, False],
[False, True, False, True]])
tensor([3, 3, 3])
tensor([[ 1, 2, 100, 4],
[ 5, 100, 7, 100]])
tensor([[1, 2],
[7, 8]])
tensor([1, 2])
- Tensor Indexing: [ ]안에 tensor를 넣어서 해당 tensor값에 해당하는 index값을 가져와서 구성
# tensor로 인덱싱
a=torch.tensor([1,2,3,4,5])
A=a[2]
print(A)
A=a[ torch.tensor(2) ] # torch.tensor 안에다가?
print(A)
A=a[ torch.tensor([2,3,4]) ]
print(A)
A=a[ torch.tensor([[2,2,2],[3,3,3]]) ]
print(A) # 인덱싱된 애들로 2행 3열짜리 행렬을 만든다
a=[1,2,3]
# a[ [1,1,1,1,2,2,2] ] # error!
a=torch.tensor([[1,2,3],[4,5,6]])
print(a[0])
A=a[ torch.tensor([[0,1],[1,1]]) ]
print(A.shape) # 예를 들어, a[0] = tensor([1,2,3])과 같이 1차원 데이터이므로 한 차원이 뒤에 늘어나서 2,2, "3" 이 된다!
print(A) # segmentation 결과 그림 보여줄 때 사용!
tensor(3)
tensor(3)
tensor([3, 4, 5])
tensor([[3, 3, 3],
[4, 4, 4]])
tensor([1, 2, 3])
torch.Size([2, 2, 3])
tensor([[[1, 2, 3],
[4, 5, 6]],
[[4, 5, 6],
[4, 5, 6]]])
A = torch.tensor([[1, 2], [3, 4], [5, 6], [7, 8]])
print(A)
print(A.shape)
# 1. A[몇 번째 행이냐, 몇 번째 열이냐]
print(A[0, 1])
# 2. A[ tensor(bool) ] => A와 같은 shape을 가지는 tensor형 bool이 어디에 True를 가지고 있냐
print(A[torch.tensor([[False, True], [False, False], [False, False], [False, False]])])
print(A[A == 2])
# 3. A[몇 번째 값에 True가 있냐, 몇 번째 값에 True가 있냐]
print(A[[True, False, False, True], [False, True]])
# 4. A[ tensor ] # 몇 번째 것을 어떻게 쌓을거냐
print(A[torch.tensor([1, 1, 2, 2, 2])])
tensor([[1, 2],
[3, 4],
[5, 6],
[7, 8]])
torch.Size([4, 2])
tensor(2)
tensor([2])
tensor([2])
tensor([2, 8])
tensor([[3, 4],
[3, 4],
[5, 6],
[5, 6],
[5, 6]])
3. PyTorch의 여러 함수들
- torch.randn(shape): [0,1] normal distribution (정규분포)
- torch.rand(shape): [0,1] uniform distribution (균일분포)
A = torch.randn(3, 3) # Normal 의 n
B = torch.rand(3, 3) # 이건 uniform
print(A)
print(B)
print(A[A[:, 0] < 0, :]) # 0 번째 열이 음수인 행들
tensor([[-1.3709, 0.5843, -1.2137],
[-2.0791, 0.1065, -1.5772],
[-1.1093, -0.0690, 0.6163]])
tensor([[0.6800, 0.0067, 0.1807],
[0.3271, 0.7784, 0.3947],
[0.2071, 0.0730, 0.1697]])
tensor([[-1.3709, 0.5843, -1.2137],
[-2.0791, 0.1065, -1.5772],
[-1.1093, -0.0690, 0.6163]])
- Matrix A 처리
- torch.abs(A): A의 모든 원소들을 절댓값 처리
- torch.sqrt(torch.abs(A)): A의 모든 원소들을 루트 처리
- torch.exp(A): A의 모든 원소들을 e^() 처리
- torch.log(torch.abs(A)): A의 모든 원소들을 절댓값 처리
- torch.round(A): A의 모든 원소들을 반올림
- torch.round(A, decimals=n): A의 모든 원소들을 소수점 n번째까지 반올림
- torch.floor(A): 내림
- torch.ceil(A): 올림
- 단일 int형 n 처리
- torch.exp(torch.tensor(n)): e^n
- torch.log(torch.tensor(n)): log_e
- torch.log2(torch.tensor(n)): log_2
- torch.log10(torch.tensor(n)): log_10
torch.function(n)의 ( )안에 단일 int 자료형이 아니라 torch.tensor(n)가 들어가야 한다
A = torch.randn(3, 3)
print(A)
print(torch.abs(A))
print(torch.sqrt(torch.abs(A)))
print(torch.exp(A))
print(torch.log(torch.abs(A)))
print(torch.log(torch.exp(torch.tensor(1)))) # torch.exp(torch.tensor(1)) = e^1
print(torch.log10(torch.tensor(10)))
print(torch.log2(torch.tensor(2)))
print(torch.round(A)) # 반올림
print(torch.round(A, decimals=2)) # 소수점 둘째자리까지
print(torch.floor(A)) # 내림
print(torch.ceil(A)) # 올림
ensor([[ 1.7771, -0.0307, 0.6729],
[-0.4282, 0.6265, 1.4035],
[-1.0426, -0.9081, -0.8824]])
tensor([[1.7771, 0.0307, 0.6729],
[0.4282, 0.6265, 1.4035],
[1.0426, 0.9081, 0.8824]])
tensor([[1.3331, 0.1751, 0.8203],
[0.6544, 0.7915, 1.1847],
[1.0211, 0.9529, 0.9394]])
tensor([[5.9129, 0.9698, 1.9600],
[0.6517, 1.8710, 4.0694],
[0.3525, 0.4033, 0.4138]])
tensor([[ 0.5750, -3.4847, -0.3961],
[-0.8482, -0.4677, 0.3390],
[ 0.0417, -0.0964, -0.1251]])
tensor(1.0000)
tensor(1.)
tensor(1.)
tensor([[ 2., -0., 1.],
[-0., 1., 1.],
[-1., -1., -1.]])
tensor([[ 1.7800, -0.0300, 0.6700],
[-0.4300, 0.6300, 1.4000],
[-1.0400, -0.9100, -0.8800]])
tensor([[ 1., -1., 0.],
[-1., 0., 1.],
[-2., -1., -1.]])
tensor([[ 2., -0., 1.],
[-0., 1., 2.],
[-1., -0., -0.]])
torch.function(n)의 ( )안에 단일 int 자료형이 아니라 torch.tensor(n)가 들어가야 한다
- torch.sin/cos/tan/tanh(torch.tensor(n))
- torch.pi -> float형인데, tensor와 연산하면 tensor로 바꿔준다
print(torch.sin(torch.tensor(torch.pi/6))) # type(torch.pi) <- float임 만약 tensor와 연산하면 tensor로 바꿔줌
print(torch.cos(torch.tensor(torch.pi/3)))
print(torch.tan(torch.tensor(torch.pi/4)))
print(torch.tanh(torch.tensor(-10)))
type(torch.tensor(1)/6)
tensor(0.5000)
tensor(0.5000)
tensor(1.)
tensor(-1.)
torch.Tensor
- torch.nan: not a number
- torch.inf: infinity
torch.nan # not a number
print(torch.log(torch.tensor(-1)))
print(torch.isnan(torch.tensor([1, 2, torch.nan, 3, 4])))
print(torch.isinf(torch.tensor([1, 2, 3, 4, torch.inf])))
tensor(nan)
tensor([False, False, True, False, False])
tensor([False, False, False, False, True])
- torch.max/min(A, dim=n, keepdims=True): 각 n번째 dimension에서 max/min값들을 찾기 - (0, 1, 2)번째 dimension
- keepdims=True: 각 torch의 shape을 1D tensor로 바꾸는 것이 아니라 유지
- torch.argmax/argmin(A, dim=0): 각 열에서 최대값 / 최소값이 존재하는 index
- torch.argmax/argmin(A, dim=1): 각 행에서 최대값 / 최소값이 존재하는 index
- A.max/min(dim=n, keepdims=True )도 많이 사용함
dim parameter를 numpy의 axis와 동일하다고 생각하자
A = torch.randn(3, 4)
print(A)
# print(torch.max(A))
# print(torch.max(A,dim=0))
print(torch.max(A, dim=1))
# print(torch.max(A,dim=0, keepdims=True))
print(torch.max(A, dim=1, keepdims=True)) # 3 행 1열 짜리 2D tensor
# print(torch.min(A))
# print(torch.min(A,dim=0))
# print(torch.min(A,dim=1))
# print(torch.argmax(A))
# print(torch.argmax(A,dim=0)) # 각 열에서 가장 큰 애가 존재하는 인덱스
# print(torch.argmax(A,dim=1)) # 각 행에서 가장 큰 애가 존재하는 인덱스
tensor([[ 0.4694, 0.2171, 0.5325, -1.7382],
[ 0.7594, 2.4989, -1.9305, -0.1958],
[ 0.4694, -1.0361, 0.4195, -1.0108]])
torch.return_types.max(
values=tensor([0.5325, 2.4989, 0.4694]),
indices=tensor([2, 1, 0]))
torch.return_types.max(
values=tensor([[0.5325],
[2.4989],
[0.4694]]),
indices=tensor([[2],
[1],
[0]]))
- torch.sort(A, dim=n): n번째 dimension 축으로 정렬, 오름차순 정렬
- torch.sort(A, dim=n, descending=True): n번째 dimension 축으로 정렬, 내림차순 정렬
- A.sort( )도 많이 사용함
a = torch.randn(6, 1)
# print(a)
# a_sorted=torch.sort(a,dim=0)
# print(a_sorted)
# a=torch.randn(6,1)
# print(a)
# print(a.sort(dim=0))
# print(a.sort(dim=0, descending=True))
print(torch.max(a))
print(a.max())
print(torch.abs(a))
print(a.abs())
tensor(1.8071)
tensor(1.8071)
tensor([[1.8071],
[1.3107],
[0.1363],
[0.0507],
[1.4534],
[1.1825]])
tensor([[1.8071],
[1.3107],
[0.1363],
[0.0507],
[1.4534],
[1.1825]])
- torch.mean(A, dim=n): n번째 dimension 축으로 평균
- torch.sum(A, dim=n): n번째 dimension 축으로 합하기
- torch.std(A): n번째 dimension 축으로 표준편차 계산
- A.mean/sum/std(dim=n, keepdims=True)도 가능
A = torch.randn(3, 4)
print(A)
print(torch.sum(A))
print(torch.sum(A, dim=1))
print(torch.sum(A, dim=1, keepdims=True))
print(torch.mean(A))
print(torch.mean(A, dim=1))
print(torch.mean(A, dim=1, keepdims=True))
print(torch.std(A)) # standard deviation 표준 편차
print(A.sum(dim=1, keepdims=True))
print(A.mean(dim=1, keepdims=True))
print(A.std())
tensor([[-0.8894, -0.8894, 0.1072, -0.4369],
[ 0.2293, -0.0223, 0.0282, -1.5013],
[ 0.3676, 1.0860, 0.2915, -0.3097]])
tensor(-1.9394)
tensor([-2.1085, -1.2662, 1.4354])
tensor([[-2.1085],
[-1.2662],
[ 1.4354]])
tensor(-0.1616)
tensor([-0.5271, -0.3165, 0.3588])
tensor([[-0.5271],
[-0.3165],
[ 0.3588]])
tensor(0.6924)
tensor([[-2.1085],
[-1.2662],
[ 1.4354]])
tensor([[-0.5271],
[-0.3165],
[ 0.3588]])
tensor(0.6924)
- torch.randint(start, end, size): start ~ (end-1)까지의 정수들을 특정 shape으로 반환
- A.reshape(depth, x, y): x행 y열 짜리가 depth개 있는 것으로 생각
A = torch.randint(1, 5, size=(12,)) # 1부터 5미만 12개 정수 (1 차원은 (N,) 과 같이 표현)
print(A)
print(A.shape)
B = A.reshape(2, 2, 3)
print(B)
print(B.ndim) # 3 차원 행렬이다
tensor([3, 3, 3, 4, 4, 1, 3, 3, 4, 1, 2, 3])
torch.Size([12])
tensor([[[3, 3, 3],
[4, 4, 1]],
[[3, 3, 4],
[1, 2, 3]]])
3
- a.transpose(a, b): 2차원 -> (0, 1)번째 dimension의 숫자를 (a, b) index에 해당하는 숫자로 매칭
- a.permute(a, b, c): 3차원 이상 -> (0, 1, 2)번째 dimension의 숫자를 (a, b, c) index 숫자로 매칭
- a.T / a.t( ) 으로도 transpose 가능
a = torch.tensor([1, 2, 3])
b = torch.tensor([2, 2, 1])
print(torch.sum(a * b))
a = a.reshape(3, 1)
b = b.reshape(3, 1)
print(a.transpose(1, 0) @ b)
print(a.permute(1, 0) @ b)
print(a.T @ b)
print(a.t() @ b)
A = torch.randn(4, 3, 6)
print(A.permute(0, 2, 1).shape)
print(A.transpose(0, 2).shape) # transpose 는 둘끼리 자리 바꾸기만 가능
tensor(9)
tensor([[9]])
tensor([[9]])
tensor([[9]])
tensor([[9]])
torch.Size([4, 6, 3])
torch.Size([6, 3, 4])
- A.reshape(depth, x, y)
- A.reshape(-1, 1): 2차원 열벡터
- A.reshape(1, -1): 2차원 행벡터
A = torch.arange(20)
print(A)
print(A.reshape(4, 5))
print(A.reshape(4, -1).shape) # 4개 행이 될 수 있도록 열의 수를 맞춰라
print(A.reshape(2, 5, -1).shape)
print(A.reshape(2, -1, 5).shape)
print(A.reshape(1, -1).shape) # 2차원 행 벡터
print(A.reshape(-1, 1).shape) # 2차원 열 벡터
tensor([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
18, 19])
tensor([[ 0, 1, 2, 3, 4],
[ 5, 6, 7, 8, 9],
[10, 11, 12, 13, 14],
[15, 16, 17, 18, 19]])
torch.Size([4, 5])
torch.Size([2, 5, 2])
torch.Size([2, 2, 5])
torch.Size([1, 20])
torch.Size([20, 1])
x = torch.randn(2, 3, 4, 5, 6)
print(x[1, 2, :, :, :].shape)
print(x[1, 2, ...].shape) # x[1, 2, …] 는 x[1, 2, :, :, :] 와 같습니다.
print(x[:, :, :, :, 3].shape)
print(x[..., 3].shape) # x[…, 3] 는 x[:, :, :, :, 3] 와 같습니다.
print(x[1, :, :, 3, :].shape)
print(x[1, ..., 3, :].shape) # x[1, …, 3, :] 는 x[1, :, :, 3, :] 와 같습니다.
torch.Size([4, 5, 6])
torch.Size([4, 5, 6])
torch.Size([2, 3, 4, 5])
torch.Size([2, 3, 4, 5])
torch.Size([3, 4, 6])
torch.Size([3, 4, 6])
- torch.tensor( )를 합치는 함수: 각 인자가 2차원 Data 형태여야 함
- 위아래로 합치는 경우 (y방향)
vstack(vertical stack): torch.vstack([A, B])- concatenate with axis = 0: torch.cat([A, B], dim=0)
- 좌우로 합치는 경우 (x방향)
hstack(horizonal stack): torch.hstack([A, B])- concatenate with axis = 1: torch.cat([A, B], dim=1)
TIPS
- dim=0이니까 0번째 dimension(앞의 숫자)끼리 더함: (2, 3, 4) shape끼리 concat -> (4, 3, 4)
- dim=1이니까 1번째 dimension(앞의 숫자)끼리 더함: (2, 3, 4) shape끼리 concat -> (2, 6, 4)
- dim=2이니까 2번째 dimension(앞의 숫자)끼리 더함: (2, 3, 4) shape끼리 concat -> (2, 3, 8)
vstack or hstack or cat사용시 ()괄호를 두 번 이상 써야함
torch의 dim parameter는 pandas의 axis와 동일하다고 생각
A = torch.ones((2, 3, 4))
B = torch.zeros((2, 3, 4))
C = torch.vstack([A, B])
D = torch.hstack([A, B]) # v는 0번째 차원, h는 1번째 차원에 쌓는다.
E = torch.cat([A, B], dim=0)
F = torch.cat([A, B], dim=1)
G = torch.cat([A, B], dim=2)
print(C)
print(D)
print(E)
print(F)
print(G)
tensor([[[1., 1., 1., 1.],
[1., 1., 1., 1.],
[1., 1., 1., 1.]],
[[1., 1., 1., 1.],
[1., 1., 1., 1.],
[1., 1., 1., 1.]],
[[0., 0., 0., 0.],
[0., 0., 0., 0.],
[0., 0., 0., 0.]],
[[0., 0., 0., 0.],
[0., 0., 0., 0.],
[0., 0., 0., 0.]]])
tensor([[[1., 1., 1., 1.],
[1., 1., 1., 1.],
[1., 1., 1., 1.],
[0., 0., 0., 0.],
[0., 0., 0., 0.],
[0., 0., 0., 0.]],
[[1., 1., 1., 1.],
[1., 1., 1., 1.],
[1., 1., 1., 1.],
[0., 0., 0., 0.],
[0., 0., 0., 0.],
[0., 0., 0., 0.]]])
tensor([[[1., 1., 1., 1.],
[1., 1., 1., 1.],
[1., 1., 1., 1.]],
[[1., 1., 1., 1.],
[1., 1., 1., 1.],
[1., 1., 1., 1.]],
[[0., 0., 0., 0.],
[0., 0., 0., 0.],
[0., 0., 0., 0.]],
[[0., 0., 0., 0.],
[0., 0., 0., 0.],
[0., 0., 0., 0.]]])
tensor([[[1., 1., 1., 1.],
[1., 1., 1., 1.],
[1., 1., 1., 1.],
[0., 0., 0., 0.],
[0., 0., 0., 0.],
[0., 0., 0., 0.]],
[[1., 1., 1., 1.],
[1., 1., 1., 1.],
[1., 1., 1., 1.],
[0., 0., 0., 0.],
[0., 0., 0., 0.],
[0., 0., 0., 0.]]])
tensor([[[1., 1., 1., 1., 0., 0., 0., 0.],
[1., 1., 1., 1., 0., 0., 0., 0.],
[1., 1., 1., 1., 0., 0., 0., 0.]],
[[1., 1., 1., 1., 0., 0., 0., 0.],
[1., 1., 1., 1., 0., 0., 0., 0.],
[1., 1., 1., 1., 0., 0., 0., 0.]]])
- A.squeeze( ): 빈 차원(1에 해당하는 shape)을 제거
- A.unsqueeze( dim=n ): 빈 차원( 1 shape)을 지정한 dimension에 추가
A = torch.randn(1, 1, 1, 3, 1, 1, 4, 1)
# print(A)
print(A.shape)
print(A.squeeze().shape)
torch.Size([1, 1, 1, 3, 1, 1, 4, 1])
torch.Size([3, 4])
A = torch.randn(3, 4)
print(A.unsqueeze(dim=0).shape)
print(A.unsqueeze(dim=1).shape)
print(A.unsqueeze(dim=2).shape)
print(A.reshape(1, 3, 4).shape)
print(A.reshape(3, 1, 4).shape)
print(A.reshape(3, 4, 1).shape)
torch.Size([1, 3, 4])
torch.Size([3, 1, 4])
torch.Size([3, 4, 1])
torch.Size([1, 3, 4])
torch.Size([3, 1, 4])
torch.Size([3, 4, 1])
- 3차원으로 concat하고 싶을 때는 unsqueeze(dim=0)하고 concat 시킴
A = torch.ones(3, 4)
B = torch.zeros(3, 4)
A = A.unsqueeze(dim=0)
B = B.unsqueeze(dim=0)
C = torch.cat([A, B], dim=0)
print(C)
print(C.shape)
tensor([[[1., 1., 1., 1.],
[1., 1., 1., 1.],
[1., 1., 1., 1.]],
[[0., 0., 0., 0.],
[0., 0., 0., 0.],
[0., 0., 0., 0.]]])
torch.Size([2, 3, 4])
- A.clone( ): 주소는 다르고 성분값이 같은 torch.tensor( )를 생성
A = torch.tensor([[1, 2], [3, 4]])
B = A.clone()
B[0, 0] = 100
print(B)
print(A)
tensor([[100, 2],
[ 3, 4]])
tensor([[1, 2],
[3, 4]])
- torch.tensor.scatter_(dim, index, src)
- dim: scatter 할 기준이 되는 축 (2차원 기준 0이면 아래 방향, 1이면 우측 방향)
- index: scatter할 element들이 배정되는 index
- src: scatter할 source element들
- dim=0 이면 index의 shape이 (1, K) 형태여야 함 (가로로 길게 늘어져 index가 하나씩 아래로 배정)
- dim=1 이면 index의 shape이 (K, 1) 형태여야 함 (세로로 길게 늘어져 Index가 하나씩 우측으로 배정)
src = torch.arange(1, 11).reshape((2, 5))
src
>> tensor([[ 1, 2, 3, 4, 5],
[ 6, 7, 8, 9, 10]])
index = torch.tensor([[0, 1, 2, 0]])
torch.zeros(3, 5, dtype=src.dtype).scatter_(0, index, src)
>> tensor([[1, 0, 0, 4, 0],
[0, 2, 0, 0, 0],
[0, 0, 3, 0, 0]])
@(행렬곱)에 대한 심화
- (depth, a, b) @ (depth, b, c): 매 depth의 각 channel마다 (a, b) @ (b, c)의 연산 수행
- 최종 shape: (a, c)
A = torch.randn(5, 7)
B = torch.randn(7, 10)
C = A @ B
print(C.shape)
A = torch.randn(32, 5, 7)
B = torch.randn(32, 7, 10)
C = A @ B
print(C.shape)
torch.Size([5, 10])
torch.Size([32, 5, 10])
- channel 개수가 맞지 않을 경우에도 A.repeat(depth, row, column)으로 맞출 수 있음
- @ 연산 자체로 channel 개수가 맞지 않으면 알아서 맞추도록 조절해줌: 굳이 .repeat( ) 사용 X
A = torch.randn(32, 5, 7)
B = torch.randn(7, 10)
C = A @ B.repeat(32, 1, 1)
D = A @ B
print(C.shape)
print(D.shape)
print((C - D).abs().max())
torch.Size([32, 5, 10])
torch.Size([32, 5, 10])
tensor(1.1921e-06)
- A = torch.rand((2,3))
- A.repeat(3, 1, 3, 2) -> shape = (3, 1, 6, 6): 뒤로 맞춰서 각 dimension에 해당하는 숫자끼리 곱해준다
A = torch.rand(2, 3)
A_repeat = A.repeat(3, 1, 3, 2)
print(A)
print(A_repeat)
print(A_repeat.shape)
tensor([[0.5267, 0.6212, 0.3331],
[0.7578, 0.0669, 0.9889]])
tensor([[[[0.5267, 0.6212, 0.3331, 0.5267, 0.6212, 0.3331],
[0.7578, 0.0669, 0.9889, 0.7578, 0.0669, 0.9889],
[0.5267, 0.6212, 0.3331, 0.5267, 0.6212, 0.3331],
[0.7578, 0.0669, 0.9889, 0.7578, 0.0669, 0.9889],
[0.5267, 0.6212, 0.3331, 0.5267, 0.6212, 0.3331],
[0.7578, 0.0669, 0.9889, 0.7578, 0.0669, 0.9889]]],
[[[0.5267, 0.6212, 0.3331, 0.5267, 0.6212, 0.3331],
[0.7578, 0.0669, 0.9889, 0.7578, 0.0669, 0.9889],
[0.5267, 0.6212, 0.3331, 0.5267, 0.6212, 0.3331],
[0.7578, 0.0669, 0.9889, 0.7578, 0.0669, 0.9889],
[0.5267, 0.6212, 0.3331, 0.5267, 0.6212, 0.3331],
[0.7578, 0.0669, 0.9889, 0.7578, 0.0669, 0.9889]]],
[[[0.5267, 0.6212, 0.3331, 0.5267, 0.6212, 0.3331],
[0.7578, 0.0669, 0.9889, 0.7578, 0.0669, 0.9889],
[0.5267, 0.6212, 0.3331, 0.5267, 0.6212, 0.3331],
[0.7578, 0.0669, 0.9889, 0.7578, 0.0669, 0.9889],
[0.5267, 0.6212, 0.3331, 0.5267, 0.6212, 0.3331],
[0.7578, 0.0669, 0.9889, 0.7578, 0.0669, 0.9889]]]])
torch.Size([3, 1, 6, 6])
numpy <-> torch 왔다갔다 가능
- torch.tensor(ndarray): numpy -> tensor
- torch.tensor( ).numpy( ): tensor -> numpy
import numpy as np
import torch
a = np.array([1, 2, 3])
b = torch.tensor([1, 2, 3])
A = torch.tensor(a) # A=torch.from_numpy(a)
B = b.numpy() # B=np.array(b)
print(type(A))
print(type(B))
<class 'torch.Tensor'>
<class 'numpy.ndarray'>
4. Autograd w/ Deep Learning
- requires_grad=True: 미분을 하겠다는 의미 (float형으로 tensor 입력)
x = torch.tensor([1.0], requires_grad=True) # float 이여야해서 1.
print(x)
tensor([1.], requires_grad=True)
- 일반적으로 requires_grad의 default값은 False
x = torch.tensor([1.0])
print(x)
print(x.requires_grad)
x.requires_grad = True
print(x)
print(x.requires_grad)
tensor([1.])
False
tensor([1.], requires_grad=True)
True
- z.backward( ): 미분(chain rule)을 실행한 뒤 해당 tensor값을 gradient에 대입 (root tensor)
- requires_grad=True인 x에 대해, x.grad으로 $\frac{\partial z}{\partial x}$를 구함
- x.grad: 대입한 값을 저장, requires_grad=True인 속성을 지닌 변수 x에 대해 정의 (leave tensor)
- y.retain_grad( ): root tensor와 leave tensor사이 tensor의 gradient
x = torch.tensor([1.0], requires_grad=True)
y = x**2
print(y) # PowBackward0 가 붙어있다!
print(x.grad)
y.backward()
print(x.grad) # y=x**2을 미분한 2x의 x 값에 1을 대입한 gradient 값
tensor([1.], grad_fn=<PowBackward0>)
None
tensor([2.])
- 실제로 메모리에는 다 저장되어 있으며, 마지막 연산인 MulBackward0만을 표시
x = torch.tensor([1.0], requires_grad=True)
y = x**2
print(y)
# y.retain_grad() # 이걸 하면 y.grad도 볼 수 있다
z = 3 * y
print(z) # MulBackward0 가 붙어있다!
z.backward()
print(x.grad) # chain rule로 알아냄
# print(y.grad) # warning! 중간건 안된다
tensor([1.], grad_fn=<PowBackward0>)
tensor([3.], grad_fn=<MulBackward0>)
tensor([6.])
- root tensor는 .backward( )를 호출하면 지정된다
x = torch.tensor([1.0], requires_grad=True)
y = x**2
z = 3 * y
y.backward() # 이렇게하면 y에서부터 뒤로 넘어감 (backward!)
print(x.grad)
tensor([2.])
- tensor에는 마지막에 수행한 연산만 grad_fn에 표시
x = torch.tensor([1.0], requires_grad=True)
a = x**2
b = a + 1
print(b) # AddBackward0 가 붙어있다!
c = b**2
c.backward()
print(x.grad)
tensor([2.], grad_fn=<AddBackward0>)
tensor([8.])
- root tensor의 leave tensor에 대한 gradient는 vector형태로 정의 [$\frac{\partial z}{\partial x}, \frac{\partial z}{\partial y}]$
x = torch.tensor([1.0], requires_grad=True)
y = torch.tensor([1.0], requires_grad=True)
z = 2 * x**2 + y**2
print(z)
z.backward()
print(x.grad)
print(y.grad)
tensor([3.], grad_fn=<AddBackward0>)
tensor([4.])
tensor([2.])
x = torch.tensor([1.0], requires_grad=True)
y = torch.tensor([1.0], requires_grad=True)
z = y * x**2
z.backward()
print(x.grad)
print(y.grad)
tensor([2.])
tensor([1.])
x = torch.tensor([1.0, 2.0, 3.0], requires_grad=True)
y = torch.sum(x**2) # x1**2 + x2**2 + x3**2
y.backward()
print(y)
print(x.grad) # 스칼라를 벡터로 미분
tensor(14., grad_fn=<SumBackward0>)
tensor([2., 4., 6.])
- transfer learning시 일부 tensor의 gradient를 freeze할 필요가 있음: 일부분을 학습하고 싶지 않을 때
- x.requires_grad=False
- x.detach( )
x = torch.tensor([1.0], requires_grad=True)
x.requires_grad = False
# tranfer learning 할 때 필요
y = x**2
print(y)
# y.backward() # error!
tensor([1.])
x = torch.tensor([2.0], requires_grad=True)
x = x.detach() # detach도 많이 쓰이는 듯
print(x)
y = x**2
print(y)
tensor([2.])
tensor([4.])
torch.no_grad( )
- with torch.no_grad( ):
- chain rule를 위해 grad_fn을 계속 update하기 때문에 requires_grad 속성을 건드리지 않고, 잠시 grad_fn을 계산하고 싶지 않을 때 사용
- 모델 테스트 시에는 불필요하게 메모리 사용을 안해도 되기 때문
# detach 와 torch.no_grad
x = torch.tensor([1.0], requires_grad=True)
# chain rule을 위해 계속 grad_fu을 update 하니까 grad_fn 잠시 안 계산하고 싶을 때 torch.no_grad
# 모델 테스트 시에는 불필요하게 메모리 쓸 필요 없기 때문!
with torch.no_grad():
y = x**2
print(x.requires_grad)
print(y)
print(x.requires_grad)
# y.backward() # error!
y = x**2
print(y)
x = torch.tensor([1.0], requires_grad=True)
x = x.detach()
y = x**2
print(x.requires_grad)
print(y)
# y.backward() # error!
True
tensor([1.])
True
tensor([1.], grad_fn=<PowBackward0>)
False
tensor([1.])
# !pip install torchviz
# from torchviz import make_dot
x = torch.tensor([1.0, 2.0], requires_grad=True)
# make_dot(x)
# make_dot(x**2)
# make_dot(x**2+1)
make_dot((x**2 + 1) ** 2)
5. Building Neural Network
Artificial Neural Networks
- linear combination with model parameters(weight, bias) & input features
- Activation Function application
- Neural Network 형성 (선형 모델 + 활성화함수 합성)
- model = nn.Linear(a, b): 입력 노드가 a개, 출력 노드가 b개인 Layer 형성
- model(x)
- x @ model.weight + model.bias
- 위의 2개는 서로 동일
import torch
from torch import nn
x = torch.tensor([1.0])
model = nn.Linear(1, 1) # 입력 node 한 개, 출력 node 한 개인 layer 만듦
print(model.weight) # 만들면서 initialize 함
print(model.bias)
y = model(x)
print(y)
y = x @ model.weight + model.bias
print(y)
Parameter containing:
tensor([[0.5789]], requires_grad=True)
Parameter containing:
tensor([-0.1711], requires_grad=True)
tensor([0.4079], grad_fn=<ViewBackward0>)
tensor([0.4079], grad_fn=<AddBackward0>)
- model.weight (가중치) = 각 Layer 사이 Link의 개수만큼 부여
- model.bias = 뒤 Layer의 노드 개수만큼 부여
- 뒤 Layer의 각 Node연결된 link의 weight & input feature간의 선형결합의 마지막에 +bias를 하기 때문
- 각 신경(뒤 Layer의 Node)의 민감도를 조절
y_pred = X @ w1.T + w0
- 2차원 X 2차원 연산이므로 행렬곱 shape을 맞춰줘야 함
- 단일 선형회귀의 경우 X feature의 개수가 1개 이므로 w1도 1개이고, 굳이 전치행렬을 사용할 필요가 없음
- 일반적으로 다중 선형회귀의 경우 X feature의 개수가 여러 개
- 종속변수 n개, Feature가 m개 있다고 하면 가중치는 [W1, W2, W3,,,Wm] 과 같은 row vector 형태로 표현 될 수 있음
- 이 경우에는 X feature 행렬과 가중치 벡터가 내적하여 올바른 회귀식을 도출하려면 가중치 벡터에 X를 내적하면 됩니다. 이를 일반화 하기 위해서 np.dot(X, W1.T)를 적용
- 만약 반복문을 사용하여 w를 계속해서 업데이트 해야하는 경우 or w가 column vector 형태로 들어왔다면 w1.T가 아니라 w1 형태로 Transpose 하지 않는다
- X size = $N(종속변수 \:개수 = Target \:값 \: 개수) \times M(Feature \: 개수)$
- M = Feature 개수 = 가중치 개수
- y_pred size = $N \times 1$
- w0 size = $N \times 1$
- Weight(w1) size = $M \times 1$ (column vector) or $1 \times M$ (row vector)
fc1 = nn.Linear(1, 3) # fully-connected
fc2 = nn.Linear(3, 1)
print(fc1.weight)
print(fc1.bias)
print(fc2.weight)
print(fc2.bias)
x = torch.tensor([1.0])
x = fc1(x)
print(x)
x = fc2(x)
print(x)
x = torch.tensor([1.0])
y = (x @ fc1.weight.T + fc1.bias) @ fc2.weight.T + fc2.bias
# nn.Linear 는 개x채x행x열에서 "채" 형태로 (1D data) 들어오길 기대하는 녀석이다.
# 즉, 노드 하나가 곧 한 채널의 의미한다.
# 따라서, 데이터 여러개를 통과시키고 싶다면 개x채 의 형태로 줘야 함
# why T? weight도 개x채 형태로 만들기 위함!
# 일단, weight shape 개x채에서 채는 무조건 앞에 거 채널 개수와 맞추셈!
# 예를 들어, nn.Linear(2,3) 이면 앞에거 채널 개수는 2 따라서 ?x2 인데
# 두 채널 값을 가지고 3개의 노드를 만드는 거라서 3x2 가 된다!
print(y)
# input size: 1
# fc1.weight.T size: 1x3
# fc1.bias size: 3
# fc2.weight.T size: 3x1
# fc2.bias size: 1
Parameter containing:
tensor([[ 0.8150],
[-0.9966],
[-0.6715]], requires_grad=True)
Parameter containing:
tensor([ 0.1072, -0.5480, -0.7133], requires_grad=True)
Parameter containing:
tensor([[0.2026, 0.4186, 0.3714]], requires_grad=True)
Parameter containing:
tensor([0.5310], requires_grad=True)
tensor([ 0.9222, -1.5446, -1.3848], grad_fn=<ViewBackward0>)
tensor([-0.4430], grad_fn=<ViewBackward0>)
tensor([-0.4430], grad_fn=<AddBackward0>)
fc1 = nn.Linear(1, 3)
fc2 = nn.Linear(3, 1)
x = torch.tensor([1.0])
x = fc1(x)
print(x)
x = fc2(x)
print(x)
model = nn.Sequential(fc1, fc2) # layer 풀칠
x = torch.tensor([1.0])
print(model(x))
tensor([-0.9443, 1.1634, 1.3465], grad_fn=<ViewBackward0>)
tensor([0.3335], grad_fn=<ViewBackward0>)
tensor([0.3335], grad_fn=<ViewBackward0>)
model = nn.Sequential(nn.Linear(2, 5), nn.Linear(5, 10), nn.Linear(10, 3)) # 여기는 채,채
x = torch.randn(2)
print(x)
print(model(x))
x = torch.randn(1, 2)
print(x)
print(model(x))
x = torch.randn(5, 2) # 개x채 => 두 개의 채널 값(키, 몸무게)을 가지는 데이터(사람) 5개를 통과시킴
print(x)
print(model(x))
x = torch.randn(2, 3, 1, 4, 5, 2)
print(model(x).shape)
tensor([-1.0483, 0.0679])
tensor([ 0.1083, -0.0021, 0.2477], grad_fn=<ViewBackward0>)
tensor([[-0.6544, 0.5178]])
tensor([[0.1362, 0.0546, 0.2691]], grad_fn=<AddmmBackward0>)
tensor([[ 1.3875, 0.1917],
[-0.9640, -0.9576],
[-0.8920, 0.3362],
[-0.2115, 0.3072],
[ 1.9616, -0.7374]])
tensor([[-0.2517, 0.5509, -0.1686],
[-0.1104, 0.0955, 0.0207],
[ 0.1374, 0.0136, 0.2747],
[ 0.0241, 0.1729, 0.1453],
[-0.5285, 0.7542, -0.4645]], grad_fn=<AddmmBackward0>)
torch.Size([2, 3, 1, 4, 5, 3])
class MyModel(nn.Module):
def __init__(self):
super().__init__()
self.fc1 = nn.Linear(2, 5)
self.fc2 = nn.Linear(5, 10)
self.fc3 = nn.Linear(10, 3)
self.sig1 = nn.Sigmoid()
self.sig2 = nn.Sigmoid()
self.sig3 = nn.Sigmoid()
def forward(self, x):
x = self.fc1(x)
x = self.sig1(x)
x = self.fc2(x)
x = self.sig2(x)
x = self.fc3(x)
x = self.sig3(x)
return x
model = MyModel()
x = torch.randn(5, 2)
y = model(x)
print(y)
tensor([[0.5556, 0.6609, 0.4431],
[0.5609, 0.6650, 0.4349],
[0.5567, 0.6601, 0.4422],
[0.5560, 0.6641, 0.4408],
[0.5519, 0.6612, 0.4472]], grad_fn=<SigmoidBackward0>)
print(model)
print(model.fc1.weight)
print(model.fc2.bias)
MyModel(
(fc1): Linear(in_features=2, out_features=5, bias=True)
(fc2): Linear(in_features=5, out_features=10, bias=True)
(fc3): Linear(in_features=10, out_features=3, bias=True)
(sig1): Sigmoid()
(sig2): Sigmoid()
(sig3): Sigmoid()
)
Parameter containing:
tensor([[-0.0230, -0.0779],
[-0.3783, 0.3246],
[ 0.0734, -0.4013],
[ 0.2023, -0.2107],
[ 0.6938, -0.3467]], requires_grad=True)
Parameter containing:
tensor([ 0.2528, -0.0201, -0.1269, 0.1826, -0.3758, -0.2780, 0.2302, 0.0130,
0.1642, -0.1992], requires_grad=True)
class MyModel2(nn.Module):
def __init__(self):
super().__init__()
self.linear = nn.Sequential(
nn.Linear(2, 5),
nn.Sigmoid(),
nn.Linear(5, 10),
nn.Sigmoid(),
nn.Linear(10, 3),
nn.Sigmoid(),
)
def forward(self, x):
x = self.linear(x)
return x
model2 = MyModel2()
x = torch.randn(5, 2)
y = model2(x)
print(y)
tensor([[0.3737, 0.5611, 0.5887],
[0.3752, 0.5600, 0.5892],
[0.3701, 0.5614, 0.5882],
[0.3735, 0.5560, 0.5900],
[0.3759, 0.5538, 0.5908]], grad_fn=<SigmoidBackward0>)
print(model2)
print(model2.linear[0].weight)
print(model2.linear[-2].bias)
MyModel2(
(linear): Sequential(
(0): Linear(in_features=2, out_features=5, bias=True)
(1): Sigmoid()
(2): Linear(in_features=5, out_features=10, bias=True)
(3): Sigmoid()
(4): Linear(in_features=10, out_features=3, bias=True)
(5): Sigmoid()
)
)
Parameter containing:
tensor([[ 0.4657, 0.2559],
[-0.1689, 0.5652],
[-0.0281, -0.6737],
[-0.3551, 0.0041],
[-0.4229, -0.2759]], requires_grad=True)
Parameter containing:
tensor([-0.0320, 0.0278, 0.0952], requires_grad=True)
list(model.parameters())
[Parameter containing:
tensor([[-0.0230, -0.0779],
[-0.3783, 0.3246],
[ 0.0734, -0.4013],
[ 0.2023, -0.2107],
[ 0.6938, -0.3467]], requires_grad=True),
Parameter containing:
tensor([ 0.4821, -0.4036, 0.4935, 0.1563, -0.1453], requires_grad=True),
Parameter containing:
tensor([[-0.0885, -0.3311, 0.2000, 0.3462, 0.3216],
[-0.1577, 0.0815, -0.1772, -0.2174, -0.1441],
[-0.4121, 0.3176, -0.3843, 0.3263, 0.4092],
[-0.2572, -0.2538, 0.0203, -0.2639, 0.2651],
[-0.2727, 0.1193, -0.3604, 0.0095, 0.3245],
[ 0.3827, 0.3405, -0.1389, 0.2288, -0.0683],
[-0.2439, -0.0456, -0.3332, -0.1889, -0.2163],
[-0.0501, -0.3196, 0.1489, -0.2222, 0.2300],
[-0.3037, 0.0660, -0.0821, 0.2191, -0.0112],
[-0.0043, -0.3415, 0.2196, -0.0869, 0.2697]], requires_grad=True),
Parameter containing:
tensor([ 0.2528, -0.0201, -0.1269, 0.1826, -0.3758, -0.2780, 0.2302, 0.0130,
0.1642, -0.1992], requires_grad=True),
Parameter containing:
tensor([[-0.0413, -0.1143, 0.0193, -0.1682, 0.0281, 0.0677, -0.1852, 0.1426,
-0.0640, 0.2839],
[ 0.2171, 0.0431, 0.1059, 0.2208, 0.2980, 0.2468, 0.1396, -0.2420,
0.0838, 0.2388],
[-0.3150, 0.2611, -0.3127, 0.0428, 0.0946, -0.2506, 0.0969, -0.1938,
0.2093, 0.1047]], requires_grad=True),
Parameter containing:
tensor([ 0.2355, 0.0362, -0.0303], requires_grad=True)]
# 파라미터 수 구하기
num = sum([p.numel() for p in model.parameters() if p.requires_grad])
print(num)
6. Weight Initialization
# 내 필기용 : He initialization 이 공식 문서랑 다르다? => paper에 맞게 구현됐고 torch 공식 문서만 틀림
import torch
from torch import nn
Fin = 5000
Fout = 1000
w = torch.zeros(141, Fin)
nn.init.kaiming_uniform_(
w, mode="fan_in", nonlinearity="relu"
) # forward pass에서 값의 범위를 유지시켜주기 위함
print(w.std())
print(torch.sqrt(torch.tensor(2 / Fin)))
w = torch.zeros(Fout, 212)
nn.init.kaiming_uniform_(
w, mode="fan_out", nonlinearity="relu"
) # backward pass에서 값의 범위를 유지시켜주기 위함
print(w.std())
print(torch.sqrt(torch.tensor(2 / Fout)))
# CNN?
N = 32
C = 64
H = 6
W = 10
w = torch.zeros(N, C, H, W)
nn.init.kaiming_uniform_(w, mode="fan_in", nonlinearity="relu")
print(w.std())
print(torch.sqrt(torch.tensor(2 / (C * H * W))))
w = torch.zeros(N, C, H, W)
nn.init.kaiming_uniform_(w, mode="fan_out", nonlinearity="relu")
print(w.std())
print(torch.sqrt(torch.tensor(2 / (N * H * W))))
tensor(0.0200)
tensor(0.0200)
tensor(0.0448)
tensor(0.0447)
tensor(0.0228)
tensor(0.0228)
tensor(0.0322)
tensor(0.0323)
728x90