강의 출처: https://www.youtube.com/watch?v=k60oT_8lyFw&list=LL&index=1&t=4103s
텐서의 조작(manipulations)
인덱싱(Indexing): NumPy처럼 인덱싱 형태로 사용가능
x = torch.Tensor([[1,2],#0위치
[3,4]])#1위치
print(x)
print(x[0,0])
print(x[0,1])
print(x[1,0])
print(x[1,1])
print(x[:, 0])
print(x[:, 1])
print(x[0:, ])
print(x[1:, ])
tensor([[1., 2.], [3., 4.]])
tensor(1.)
tensor(2.)
tensor(3.)
tensor(4.)
tensor([1., 3.])
tensor([2., 4.])
tensor([[1., 2.], [3., 4.]])
tensor([[3., 4.]])
view: 텐서의 크기(size)나 모양(shape)을 변경
- 기본적으로 변경 전과 후에 텐서 안의 원소 개수가 유지되어야 함
- -1로 설정되면 계산을 통해 해당 크기값을 유추
x = torch.randn(4,5)
print(x)
y = x.view(20) #flat하게 20개가 연달아 나타나는 형태
print(y)
z = x.view(5,-1) #행5개, 전체 숫자에 대해 자동으로 계산
print(z)
tensor([[-0.7728, -0.2897, 0.4124, 0.5375, -0.1071],
[-0.9390, 0.2011, 1.2789, 0.4421, -0.5015],
[-1.1650, -0.0090, -0.8004, -1.2330, -0.6752],
[ 2.1249, -0.1179, 1.3059, -0.7011, -0.9007]])
tensor([-0.7728, -0.2897, 0.4124, 0.5375, -0.1071, -0.9390,
0.2011, 1.2789, 0.4421, -0.5015, -1.1650, -0.0090, -0.8004, -1.2330, -0.6752,
2.1249, -0.1179, 1.3059, -0.7011, -0.9007])
tensor([[-0.7728, -0.2897, 0.4124, 0.5375],
[-0.1071, -0.9390, 0.2011, 1.2789],
[ 0.4421, -0.5015, -1.1650, -0.0090],
[-0.8004, -1.2330, -0.6752, 2.1249],
[-0.1179, 1.3059, -0.7011, -0.9007]])
item: 텐서에 값이 단 하나라도 존재하면 숫자값을 얻을 수 있음
x= torch.randn(1)
print(x)
print(x.item())
print(x.dtype)
tensor([1.2774])
1.277359962463379
torch.float32
스칼라값 하나만 존재해야 item() 사용 가능,x에 두개 들어가 있기 때문에 error
x= torch.randn(2)
print(x)
print(x.item()) #2개하면 error, x에 두개들어가있음
print(x.dtype)
tensor([0.0611, 1.4374])
RuntimeError: a Tensor with 2 elements cannot be converted to Scalar
squeeze: 차원을 축소(제거)
tensor = torch.rand(1,3,3) #3차원
print(tensor)
print(tensor.shape)
tensor([[[0.0392, 0.7365, 0.6342],
[0.0100, 0.8090, 0.9958],
[0.7539, 0.5699, 0.7608]]])
torch.Size([1, 3, 3])
t = tensor.squeeze()
print(t)
print(t.shape) #2개 차원으로 줄임
tensor([[0.0392, 0.7365, 0.6342],
[0.0100, 0.8090, 0.9958],
[0.7539, 0.5699, 0.7608]])
torch.Size([3, 3])
unsqueeze: 차원을 증가(생성)
t= torch.rand(3,3)
print(t)
print(t.shape)
tensor([[0.5524, 0.1440, 0.4846],
[0.2184, 0.9014, 0.7250],
[0.3931, 0.5965, 0.5375]])
torch.Size([3, 3])
tensor = t.unsqueeze(dim=0)#첫번째 차원을 기준으로 늘리기
print(tensor)
print(tensor.shape)
tensor([[[0.5524, 0.1440, 0.4846],
[0.2184, 0.9014, 0.7250],
[0.3931, 0.5965, 0.5375]]])
torch.Size([1, 3, 3])
tensor = t.unsqueeze(dim=2) #뒤에 추가가됨
print(tensor)
print(tensor.shape)
tensor([[[0.5524],
[0.1440],
[0.4846]],
[[0.2184],
[0.9014],
[0.7250]],
[[0.3931],
[0.5965],
[0.5375]]])
torch.Size([3, 3, 1])
stack 텐서간 결합
x = torch.FloatTensor([1,4])
print(x)
y = torch.FloatTensor([2,5])
print(y)
z = torch.FloatTensor([3,6])
print(z)
print(torch.stack([x,y,z])) #모든 텐서를 결합
tensor([1., 4.])
tensor([2., 5.])
tensor([3., 6.])
tensor([[1., 4.],
[2., 5.],
[3., 6.]])
cat: 텐서를 결합하는 메소드(concatenate)
- 넘파이의 stack과 유사하지만, 쌓을 dim이 존재해야함
- 해당 차원을 늘려준 후 결합
a = torch.randn(1,3,3)
print(a)
b = torch.randn(1,3,3)
print(b)
c = torch.cat((a,b),dim = 0)#기준이 첫번째 차원
print(c)
print(c.size()) #
tensor([[[-1.7695, -0.2903, 0.4430],
[ 0.3225, 0.1929, -1.0278],
[-0.0181, -0.9933, -0.5745]]])
tensor([[[-1.3281, -0.4906, 0.9417],
[ 0.2281, -1.8169, -1.2794],
[ 0.3738, 0.5299, 0.6709]]])
tensor([[[-1.7695, -0.2903, 0.4430],
[ 0.3225, 0.1929, -1.0278],
[-0.0181, -0.9933, -0.5745]],
[[-1.3281, -0.4906, 0.9417],
[ 0.2281, -1.8169, -1.2794],
[ 0.3738, 0.5299, 0.6709]]])
torch.Size([2, 3, 3])
c = torch.cat((a,b),dim = 1)#기준이 두번째 차원
print(c)
print(c.size())
tensor([[[-1.7695, -0.2903, 0.4430],
[ 0.3225, 0.1929, -1.0278],
[-0.0181, -0.9933, -0.5745],
[-1.3281, -0.4906, 0.9417],
[ 0.2281, -1.8169, -1.2794],
[ 0.3738, 0.5299, 0.6709]]]) torch.Size([1, 6, 3])
c = torch.cat((a,b),dim = 2)#기준이 세번째 차원
print(c)
print(c.size())
tensor([[[-1.7695, -0.2903, 0.4430, -1.3281, -0.4906, 0.9417],
[ 0.3225, 0.1929, -1.0278, 0.2281, -1.8169, -1.2794],
[-0.0181, -0.9933, -0.5745, 0.3738, 0.5299, 0.6709]]])
torch.Size([1, 3, 6])
chunk: 텐서를 여러 개로 나눌 때 사용 (몇 개로 나눌 것인가?)
tensor = torch.rand(3,6)
print(tensor)
t1,t2,t3 = torch.chunk(tensor,3,dim =1) #3개로 나누기
print(t1)
print(t2)
print(t3)
tensor([[0.8200, 0.7136, 0.2481, 0.1293, 0.3285, 0.0107],
[0.1430, 0.7973, 0.2399, 0.2357, 0.9373, 0.7700],
[0.7829, 0.3611, 0.1083, 0.1073, 0.1682, 0.2560]])
tensor([[0.8200, 0.7136], [0.1430, 0.7973], [0.7829, 0.3611]])
tensor([[0.2481, 0.1293], [0.2399, 0.2357], [0.1083, 0.1073]])
tensor([[0.3285, 0.0107], [0.9373, 0.7700], [0.1682, 0.2560]])
split: chunk와 동일한 기능이지만 조금 다름 (텐서의 크기는 몇인가?)
tensor = torch.rand(3,6)
t1,t2 = torch.split(tensor,3,dim =1) #텐서의 크기가 3씩 나눠지도록
print(tensor)
print(t1)
print(t2)
tensor([[0.2841, 0.3690, 0.0738, 0.0565, 0.3440, 0.4109],
[0.9499, 0.1583, 0.8721, 0.4317, 0.8453, 0.0869],
[0.8356, 0.8379, 0.9858, 0.3761, 0.5226, 0.8162]])
tensor([[0.2841, 0.3690, 0.0738],
[0.9499, 0.1583, 0.8721],
[0.8356, 0.8379, 0.9858]])
tensor([[0.0565, 0.3440, 0.4109],
[0.4317, 0.8453, 0.0869],
[0.3761, 0.5226, 0.8162]])
torch ↔ numpy
- Torch Tensor(텐서)를 NumPy array(배열)로 변환 가능
- numpy()
- from_numpy()
- Tensor가 CPU상에 있다면 NumPy 배열은 메모리 공간을 공유하므로 하나가 변하면, 다른 하나도 변함
a= torch.ones(7)#7개의 1
print(a)
tensor([1., 1., 1., 1., 1., 1., 1.])
b = a.numpy()
print(b)
[1. 1. 1. 1. 1. 1. 1.]
a.add_(1)
print(a)
print(b) #넘파이 배열은 메모리 공간을 공유하기 떄문에 변함
tensor([2., 2., 2., 2., 2., 2., 2.])
[2. 2. 2. 2. 2. 2. 2.]
import numpy as np
a = np.ones(7)
b = torch.from_numpy(a)
np.add(a,1,out=a)
print(a) #토치도 메모리 share
print(b)
[2. 2. 2. 2. 2. 2. 2.]
tensor([2., 2., 2., 2., 2., 2., 2.], dtype=torch.float64)
Autograd(자동미분)
- torch.autograd 패키지는 Tensor의 모든 연산에 대해 자동 미분 제공
- 이는 코드를 어떻게 작성하여 실행하느냐에 따라 역전파가 정의된다는 뜻
- backprop를 위해 미분값을 자동으로 계산
기록을 추적하는 것을 중단하게 하려면, .detach()를 호출하여 연산기록으로부터 분리
a = torch.randn(3,3)
a = a*3
print(a)
print(a.requires_grad)
tensor([[-1.3718, 1.7448, 1.0506],
[-3.1201, 1.7568, 0.3226],
[ 0.7433, -0.6466, -0.6436]])
False
requires_grad_(...)는 기존 텐서의 requires_grad 값을 바꿔치기(in-place)하여 변경
grad_fn: 미분값을 계산한 함수에 대한 정보 저장 (어떤 함수에 대해서 backprop 했는지)
a.requires_grad_(True) #뒤의 _언더바는 inplace 연산
print(a.requires_grad)
b = (a*a).sum() #텐서곱합
print(b)
print(b.grad_fn)#sumbackward -> sum 한것을 기록에 남김
True
tensor(20.3401, grad_fn=<SumBackward0>)
<SumBackward0 object at 0x7ab839d532e0>
기울기(Gradient)
x = torch.ones(3,3,requires_grad=True)
print(x)
tensor([[1., 1., 1.],
[1., 1., 1.],
[1., 1., 1.]], requires_grad=True)
y = x+5
print(y)
tensor([[6., 6., 6.], [6., 6., 6.], [6., 6., 6.]], grad_fn=<AddBackward0>)
z = y*y
out = z.mean()
print(z,out) #z값에는 곱한 정보가 들어감 ,out에는 mean 정보
tensor([[36., 36., 36.],
[36., 36., 36.],
[36., 36., 36.]], grad_fn=<MulBackward0>) tensor(36., grad_fn=<MeanBackward0>)
계산이 완료된 후, .backward()를 호출하면 자동으로 역전파 계산이 가능하고, .grad 속성에 누적됨
print(out)
out.backward()
tensor(36., grad_fn=<MeanBackward0>)
grad: data가 거쳐온 layer에 대한 미분값 저장
print(x) #3*3
print(x.grad)#실제 미분값
tensor([[1., 1., 1.],
[1., 1., 1.],
[1., 1., 1.]], requires_grad=True)
tensor([[1.3333, 1.3333, 1.3333],
[1.3333, 1.3333, 1.3333],
[1.3333, 1.3333, 1.3333]])
x= torch.randn(3,requires_grad=True)
y= x *2
while y.data.norm()<1000:
y = y*2
print(y)
tensor([-1124.7004, 940.4333, 186.3925], grad_fn=<MulBackward0>)
v = torch.tensor([0.1,1.0,0.0001],dtype=torch.float)
y.backward(v)
print(x.grad)#v기준으로 계산 #1시간 8분
tensor([5.1200e+01, 5.1200e+02, 5.1200e-02])
with torch.no_grad()를 사용하여 기울기의 업데이트를 하지 않음
기록을 추적하는 것을 방지하기 위해 코드 블럭을 with torch.no_grad()로 감싸면 기울기 계산은 필요없지만, requires_grad=True로 설정되어 학습 가능한 매개변수를 갖는 모델을 평가(evaluate)할 때 유용 (평가 시 업데이트 하지 않기 때문)
print(x.requires_grad)
print((x **2).requires_grad)
with torch.no_grad():#기울기 계산 하지 않기
print((x**2).requires_grad)
True
True
False
detach(): 내용물(content)은 같지만 require_grad가 다른 새로운 Tensor를 가져올 때
print(x.requires_grad)
y = x.detach()
print(y.requires_grad)
print(x.eq(y).all())
True
False
tensor(True)
자동 미분 흐름 예제
a = torch.ones(2,2)
print(a)
tensor([[1., 1.], [1., 1.]])
a= torch.ones(2,2,requires_grad=True)
print(a)
tensor([[1., 1.], [1., 1.]], requires_grad=True)
print(a.data)
print(a.grad) #초기화된 상태
print(a.grad_fn)
tensor([[1., 1.], [1., 1.]])
None
None
b = a +2
b = a+2
print(b)
tensor([[3., 3.], [3., 3.]], grad_fn=<AddBackward0>)
c = b^2
c= b**2
print(c)
tensor([[9., 9.], [9., 9.]], grad_fn=<PowBackward0>)
out = c.sum()
print(out) #9*4
out.backward() #sumbackward
tensor(36., grad_fn=<SumBackward0>)
a의 grad_fn이 None인 이유는 직접적으로 계산한 부분이 없었기 때문
print(a.data)
print(a.grad)
print(a.grad_fn) #a값에서 반영이 된것이 없음
tensor([[1., 1.], [1., 1.]])
tensor([[6., 6.], [6., 6.]])
None
print(b.data)
print(b.grad)
print(b.grad_fn)
tensor([[3., 3.], [3., 3.]])
None
<AddBackward0 object at 0x7e8126137e20>
print(c.data)
print(c.grad)
print(c.grad_fn)
tensor([[9., 9.], [9., 9.]])
None
<PowBackward0 object at 0x7e81261a9780>
print(out.data)
print(out.grad)
print(out.grad_fn)
tensor(36.)
None
<SumBackward0 object at 0x7e81261a91b0>
'Python' 카테고리의 다른 글
pytorch 이미지 모델링 II (1) | 2024.02.26 |
---|---|
pytorch 이미지 모델링 (0) | 2024.02.25 |
pytorch 기본 문법 I (1) | 2024.02.24 |
Window 11 python tensorflow gpu 설치 (0) | 2023.11.12 |
서울시 공공자전거 이용현황 분석 (0) | 2023.04.04 |