Data_Analysis_Track_33/Python
Python_Deeplearning_pytorch_01-2(tensor 다루기)
lsc99
2023. 10. 16. 17:11
Reshape
shape 변경
- tensor객체.reshape(*shape) / view(*shape) 이용
- 변환 후 값을 변경하면 원본 배열의 값도 같이 바뀐다.
> tensor.clone(): tensor를 복제한다.
reshape
a=torch.rand(12)
a2 = a.reshape(3,4)
a3 = a.reshape((3,2,2))
a4 = a.reshape((3,2,-1)) #한 개 axis는 -1로 설정가능하고 그럼 계산해서 알아서 설정해 준다.
print(a.shape, a2.size(), a3.shape, a4.shape)
view
a5 = a.view(3,4)
a6 = a.view((3,2,2))
a7 = a.view((3,2,-1)) #한개 axis는 -1로 설정가능
print(a.shape, a5.size(), a6.shape, a7.shape)
값 변경
a5[0, 0] = 12.1
a2[0, 1] = 15.1
print(a5)
print(a2)
print(a) # 원본도 같이 변경되는 것을 확인
colne() 메소드 -> tensor 복사
# tensor복사: clone() 메소드
r = a.clone().reshape(3,4)
r[0,0] = 100.1
print(a)
print(r)
dummy 축 늘리기
- None을 이용 (numpy의 newaxis 대신 None을 사용한다.)
- unsqueeze(dim=축번호)
tensor객체[None 이용], tensor객체.unsqueeze(dim=축번호)
import torch
a = torch.tensor([[10,20],[10,20]])
print(a.shape)
a1, a2 = a[None, :], a.unsqueeze(dim=0)
print(a1.shape, a2.shape)
a3, a4 = a[:, :, None], a.unsqueeze(dim=-1)
print(a3.shape, a4.shape)
a5, a6 = a3[:,None,:], a.unsqueeze(dim=1)
print(a5.shape, a6.shape)
dummy 축 제거
- squeeze([dim=축번호]) 이용
tensor객체.squeeze(dim=축번호)
t = torch.rand(3, 1, 3, 1)
print(t.shape)
r1 = t.squeeze() #모두 제거
print(r1.shape)
r2 = t.squeeze(dim=1) # 특정 axis 제거
print(r2.shape)
r3 = t.squeeze(dim=[1,3]) # 여러 axis의 dummy 축 제거
print(r3.shape)
tensor 합치기
- torch.cat([tensorA, tensorB, ...], dim=0)
배열 a, b, c, d 생성
a = torch.arange(10).reshape(2,5)
b = torch.arange(10,20).reshape(2,5)
c = torch.arange(20,30).reshape(2,5)
d = torch.arange(10,19).reshape(3,3)
print(a)
print(b)
print(c)
print(d)
torch.cat([배열1, 배열2, ....], dim = 축번호)
torch.cat([a, b], dim=0)
torch.cat([a, b, c], dim=0)
dim or axis = 1
torch.cat([a, b], axis=1) # dim 대신 axis사용가능
torch.cat([a, b, c], axis=1)
axis = -1
torch.cat([a, b], axis=-1)
# torch.cat([a, d]) #Error
값의 위치(index) 변경
- tensor 원소의 축별 index의 위치를 바꾼다.
- tensor.transpose(axis1, axis2)
- 두 축의 자리만 변경 할 수 있다. - tensor.permute(axis1, axis2, axis3, ..)
- 두 개 이상의 축 자리를 변경한다.
transpose, permute
X = torch.arange(24).reshape(2, 3, 4)
print(X.shape)
y = X.transpose(1, 2)
print(y.shape)
z = X.permute(2, 0, 1)
print(z.shape)
tensor 연산 및 주요 함수
element-wise 연산
- tensor와 상수 연산시, tensor와 tensor간 연산시 원소별로 처리한다.
- 행렬곱 연산을 제외하고 tensor간 연산시 피연산지 tensor간에 shape이 같아야 한다.
- shape이 다를 경우 조건이 맞으면 broadcasting을 한 뒤에 연산한다. (size가 다른 축의 경우 한개의 피연산자 size가 1일 경우 복사하여 shape을 맞춘다.)
배열 a, b, c 생성
import torch
a = torch.arange(10).reshape(2,5)
b = torch.arange(10,20).reshape(2,5)
c = torch.arange(50, 55)
print(a)
print(b)
print(c)
element-wise 연산 -> 각 값에 대하여 하나씩 연산이 이루어진다.
print(a + 100)
# print(a - 100)
print(a < 5)
배열끼리의 element-wise 연산
print(a + b)
# print(a == b)
# broadcasting
print(a + c)
주요 연산함수
여러가지 연산함수
x=torch.arange(-4, 5).reshape(3,3)
print(x)
print(torch.abs(x))
# print(torch.sqrt(torch.abs(x)))
# print(torch.exp(x)) # torch.e**x
# print(torch.log(torch.abs(x)))
# print(torch.log(torch.exp(torch.tensor(1)))) # torch.log() 밑이 e인 로그계산
# print(torch.log10(torch.tensor(10))) # torch.log10() 밑이 10인 로그계산
# print(torch.log2(torch.tensor(2))) # torch.log2() 밑이 2인 로그계산
# print("=====================")
반올림, 내림, 올림
y = x + torch.randn((3,3))
# print(y)
# print(torch.round(y)) # 반올림
# print(torch.round(y, decimals=2)) # 소수점 둘째자리까지
# print(torch.floor(y)) # 내림
# print(torch.ceil(y)) # 올림
행렬곱
- @ 연산자 또는 torch.matmul(tensor1, tensor2) 함수 이용
x, y 생성
x = torch.FloatTensor([[1, 2],
[3, 4],
[5, 6]
])
y = torch.FloatTensor([[1, 2],
[1, 2],
])
x.size(), y.shape
@ or torch.matmul(tensor1, tensor2)
z1 = x @ y
z2 = torch.matmul(x, y)
print(z1.shape, z2.shape)
print(z1)
print(z2)
Batch 행렬곱(Batch matrix muliplication) - bmm()
# Batch 행렬곱(Batch matrix muliplication) - bmm()
# x, y가 가지는 3개의 2차원 배열 간에 행렬곱을 처리한다.
import torch
x = torch.FloatTensor(3,4,2)
y = torch.FloatTensor(3,2,5)
z = torch.bmm(x, y)
z.shape
torch.nan, torch.inf
- nan: Not a Number, 주로 결측치를 표현한다.
- inf: infinit 무한.
- torch.inf: 양의 무한
- -torch.inf: 음의 무한 - torch.isnan(tensor)
- 원소별 결측치 확인 - torch.isinf(tensor)
- 원소별 inf 확인
inf: infinit 무한
print(torch.inf > 10, torch.inf < 10)
print(-torch.inf < 10, -torch.inf > 10)
nan 표현, nan&inf 여부 확인
print(torch.log(torch.tensor(-1))) # nan
# print(torch.isnan(torch.tensor([1,2,torch.nan,3,4]))) # nan 여부 확인
# print(torch.isinf(torch.tensor([1,2,3,4,torch.inf]))) # inf 여부 확인
기술통계함수
tensor 생성
X=torch.randn(3,4)
print(X)
sum
print(torch.sum(X))
print(torch.sum(X, dim=1)) # 행끼리의 합
print(torch.sum(X, dim=1, keepdims=True))
mean
print(torch.mean(X))
print(torch.mean(X, dim=1)) # 행끼리의 평균
print(torch.mean(X, dim=1, keepdims=True))
std -> 표준편차
var -> 분산
print(torch.std(X)) # standard deviation 표준 편차
print(torch.var(X)) # variance
print(torch.var(X, dim=0))
max
print(torch.max(X))
print(torch.max(X, dim=0)) # return_types.max 타입객체로 반환. max값과 max값의 index를 묶어서 반환
print(torch.max(X, dim=1))
print(torch.max(X, dim=1).values, torch.max(X, dim=1).indices, sep=" || ")
print(torch.max(X, dim=0, keepdims=True)) #keepdims=True : 차원(rank)를 유지
print(torch.max(X, dim=1, keepdims=True))
min, argmax
print(torch.min(X))
print(torch.min(X, dim=0))
print(torch.min(X, dim=1))
print(torch.argmax(X))
print(torch.argmax(X, dim=0)) # 각 열에서 가장 큰 애가 존재하는 인덱스
print(torch.argmax(X, dim=1)) # 각 행에서 가장 큰 애가 존재하는 인덱스
autograd(자동미분)
- 자동 미분을 이용해 gradient를 계산하는 pytorch system.
- 딥러닝 모델에서 weight와 bias tensor들(Parameter)은 backpropagation(역전파)를 이용해 gradient를 구해서 loss가 줄어드는 방향으로 update를 하게된다.
- pytorch는 이런 미분 수행을 자동으로 처리해 준다.
- gradient(기울기)를 구한다는 것은 미분을 한다는 것을 말한다. - tensor가 미분 가능하려면 requires_grad=True 로 설정되어 있어야 한다. (default: False)
tensor가 미분 가능하려면 requires_grad=True 로 설정
x = torch.tensor([1.], requires_grad=True)
# x = torch.tensor([1.])
# x.requires_grad = True
print(x)
print(x.requires_grad)
y = x ** 2
print(y)
# 계산 결과를 담은 tensor인 y는 계산 결과와 grad_fn에 어떤 계산을 했는지 정보를 담고 있다. (PowBackward0)
# 이는 y 계산에 사용된 x가 requires_grad=True이기 때문이다.
미분&grad값 확인
# 미분 - tensor.backward() 호출
y.backward() # dy/dx gradient 계산 후 결과를 x의 grad attribute에 저장한다.
x.grad
# 도함수: y` = 2x 이고 x가 1이었으므로 grad는 2
x, y, z(3개 이상일 경우)
x = torch.tensor([1.], requires_grad=True)
y = x ** 2 # 미분: 2x
z = y * 10 # 미분: 10 ===> 2x * 10
z.backward()
print(x.grad)
편미분
## 편미분
x=torch.tensor([1.],requires_grad=True)
y=torch.tensor([1.],requires_grad=True)
z= 2*x**2 + y**2
print(z)
z.backward()
print(x.grad) #dz/dx
print(y.grad) #dz/dy
x=torch.tensor([1., 2., 3.] ,requires_grad=True)
y=torch.sum(x**2) # [x1**2 + x2**2 + x3**2]
y.backward() #[dy/dx1, dy/dx2, dy/dx3] = [2x1, 2x2, 2x3]
print(y)
print(x.grad) # 스칼라를 벡터로 미분
torch.no_grad()
- no_grad() 구문에서 연산을 할 경우 requires_grad=True로 설정되었다 하더라도 gradient를 update하지 않는다.
- 딥러닝 모델 학습이 끝나고 평가할 때는 gradient를 계산할 필요가 없기 때문에 no_grad 구문을 사용한다.
x = torch.tensor(1.0, requires_grad = True)
print(x.requires_grad)
y = x**2
print(y.requires_grad) # 연산이 결과 requires_grad도 True -> 그래야 미분이 가능하므로.
print(x.requires_grad)
print(y)
y.backward()
print(x.grad)
x = torch.tensor(1.0, requires_grad = True)
print(x.requires_grad)
with torch.no_grad():
print(x.requires_grad)
y = x**2
print(y.requires_grad)# 연산이 적용될 때 requires_grad가 False가 된다.
print(y)
print(x.requires_grad)
# y.backward()
gradient 값 초기화
x = torch.tensor(1., requires_grad=True)
y = x**2
y.backward()
print("x의 gradient값:", x.grad )
x
z = x **2
z.backward()
print("x의 gradient값:", x.grad )
x = torch.tensor(1., requires_grad=True)
y = x**2
y.backward()
x.grad
gradient 값 초기화
# gradient초기화
x.grad = torch.tensor(0.)
z = x**2
z.backward()
x.grad