파이썬이 이용할 수 있는 모듈의 버전은 1개뿐이다.
하지만, 여러 버전을 이용해야 할 필요성이 존재한다. ex) tensorflow 1.0 vs 2.0
이러한 경우에는 가상환경을 활용하면 된다.
독립된 작업 공간으로, 각 공간 별로 모듈의 버전 다르게 설치 가능하다.
pip install virtualenv # virtualenv 설치
virtualenv [가상환경 이름] # 가상환경 생성
virtualenv [가상환경 이름] -- python=3.6 # 파이썬 버전 지정
call [가상환경 이름]/scripts/activate # 가상환경 실행
deactivate # 가상환경 종료
virtualenv [가상환경 이름] # 가상환경 생성
virtualenv [가상환경 이름] -- python=3.6 # 파이썬 버전 지정
source [가상환경 이름]/bin/activate # 가상환경 실행
deactivate # 가상환경 종료
conda create [가상환경 이름] # 가상환경 생성
conda create [가상환경 이름] pandas torch # 가상환경에 패키지 설치
conda create [가상환경 이름] python=3.6 # 파이썬 버전 지정
activate [가상환경 이름] # 가상환경 실행
deactivate # 가상환경 종료
conda create [가상환경 이름] # 가상환경 생성
conda create [가상환경 이름] pandas torch # 가상환경에 패키지 설치
conda create [가상환경 이름] python=3.6 # 파이썬 버전 지정
source activate [가상환경 이름] # 가상환경 실행
source deactivate # 가상환경 종료
모듈 별로 다른 버전이 아니라 각 프로그래밍 버전 및 개발 환경 자체를 독립적인 공간으로 활용해 관리할 수 있는 컨테이너 오픈소스 가상화 플랫폼
딥러닝의 경우 각 레이어의 노드 수가 증가할수록, 깊이가 깊어질수록 파라미터 수는 급격히 증가한다.
이렇게 많은 수의 파라미터를 이용해 설계할 때는 CPU보다 GPU가 훨씬 계산 속도가 빠르다.
GPU를 설치한 후, 파이썬에서 인식할 수 있도록 하기 위해 CUDA 사용
GPU에서 병렬처리를 수행하는 알고리즘을 각종 프로그래밍 언어에 사용할 수 있도록 해주는 GPGPU기술
딥러닝 모델을 위한 GPU 가속화 라이브러리의 기초 요소와 같은 일반적인 루틴을 빠르게 이행할 수 있도록 해주는 라이브러리
torch.tensor()
을 이용해 데이터 정의
상수(하나의 값을 표현할 때 1개의 수치로 표현)
scalar1 = torch.tensor([1])
scalar2 = torch.tensor([3])
scalar1 + scalar2 # 덧셈
scalar1 - scalar2 # 뺄셈
scalar1 * scalar2 # 곱셈
scalar1 / scalar2 # 나눗셈
torch.add(scalar1, scalar2) # 덧셈
torch.sub(scalar1, scalar2) # 뺄셈
torch.mul(scalar1, scalar2) # 곱셈
torch.div(scalar1, scalar2) # 나눗셈
하나의 값을 표현할 때 2개 이상의 수치로 표현
vector1 = torch.tensor([1,2,3])
vector2 = torch.tensor([4,5,6])
torch.dot(vector1, vector2) # torch.dot()은 벡터 내적 계산만 가능
torch.matmul(vector1, vector2)
2개 이상의 벡터 값을 통합해 구성된 값
matrix1 = torch.tensor([[1,2],[3,4]])
matrix2 = torch.tensor([[5,6],[7,8]])
torch.matmul(matrix1, matrix2)
torch.mm(matrix1, matrix2) # torch.mm()은 행렬에서만 수행 가능
2차원 이상의 배열
tensor1 = torch.tensor([[[1,2],[3,4]],[[5,6],[7,8]]])
tensor2 = torch.tensor([[[9,10],[11,12]],[[13,14],[15,16]]])
torch.matmul(tensor1, tensor2)
pytorch에서는 tensor을 다루는 방법이 numpy와 유사
t = torch.tensor([[1,2,3], [4,5,6],
[7,8,9],[10,11,12]])
t.dim() # tensor의 차원 수 반환
t.shape # tensor의 형상 반환
t.size() # shape와 같은 기능
사칙연산 시에는 shape이 일치해야 하는데, 그렇지 않더라도 자동적으로 shape을 맞춰 계산하는 것
ex1)
m1 = torch.tensor([[1,2]])
m2 = torch.tensor([3]) # [3] -> [[3,3]]
m1+m2
ex2)
m1 = torch.tensor([[1,2]]) # [[1,2]] -> [[1,2],[1,2]]
m2 = torch.tensor([[3],[4]]) # [[3],[4]] -> [[3,3],[4,4]]
m1+m2
mean은 LongTensor에는 잘 수행하지 못하므로 FloatTensor 활용
t = torch.FloatTensor([[1,2],[3,4]])
t.mean() # 원소 전체의 평균
t.mean(dim=0) # 각 dimension 0(행)을 고정하고 나머지의 평균
t.mean(dim=1) # 각 dimension 1(열)을 고정하고 나머지의 평균
t.mean(dim=-1) # 마지막 dimension을 고정하고 나머지의 평균
t = torch.tensor([[1,2],[3,4]])
t.sum()
t.sum(dim=0)
t.sum(dim=1)
t.sum(dim=-1)
t = torch.tensor([[1,2],[3,4]])
t.max()
t.max(dim=0)
t.max(dim=1)
t.max(dim=-1) # dim을 주면 argmax도 같이 내보내준다.
t.argmax() # max인 값의 위치(index)
형상(shape) 바꿔줌, np.reshape()과 같은 역할 수행
t = torch.tensor([[[0,1,2],[3,4,5]],
[[6,7,8],[9,10,11]]])
t.view([-1,3]) # -1을 인자로 줄 시, 나머지에 맞춰 shape 바꿔줌
# (2,2,3) -> (4,3) # 원소들의 곱이 동일하면 view 사용 가능
1차원으로 바꿔줌
t = torch.tensor([[0],[1],[2]])
t.squeeze() # (3,1) -> (3,)
squeeze를 반대로 수행함
t = torch.tensor([0,1,2])
t.unsqueeze(0) # dim=0, dimension 0에 1 입력해 view 수행 # (3,) -> (1,3)
t.unsqueeze(1) # dim=1, dimension 1에 1 입력해 view 수행 # (3,) -> (3,1)
tensor type 변환
lt = torch.LongTensor([1,2,3,4])
lt.float() # FloatTensor로 변환
bt = torch.ByteTensor([True, False, False, True])
bt.long() # LongTensor로 변환
bt.float() # FloatTensor로 변환
x = torch.tensor([[1,2],[3,4]])
y = torch.tensor([[5,6],[7,8]])
torch.cat([x,y], dim=0) # dim 0이 늘어남
torch.cat([x,y], dim=1) # dim 1이 늘어남
concatenate 편리하게 이용
x = torch.tensor([1,4])
y = torch.tensor([2,5])
z = torch.tensor([3,6])
torch.stack([x,y,z]) # dim=0, dimension 0(행)으로 쌓는다.
torch.stack([x,y,z], dim=1) # dim=1, dimension 1(열)으로 쌓는다.
concatenate으로 같은 결과 도출하려면 아래 코드 실행해야 함.
torch.cat([x.unsqueeze(0), y.unsqueeze(0), z.unsqueeze(0)], dim=0)
torch.cat([x.unsqueeze(1), y.unsqueeze(1), z.unsqueeze(1)], dim=1)
x = torch.tensor([[0,1,2],[2,1,0]])
torch.ones_like(x) # 똑같은 shape로 영행렬 만듦
# device를 통일해서 수행해야 error 안나기 때문에 사용
torch.zeros_like(x)
x = torch.tensor([[1,2],[3,4]])
x.mul(2) # 실행결과가 변수에 저장되지 않는다.
x.mul_(2) # _ 추가 시, 메모리에 새로 선언하지 않고 정답값에 바로 넣음
파이토치를 이용해 코드를 작성할 때, 오차역전파법을 이용해 파라미터를 업데이트하는 방법은 Autograd방식으로 쉽게 구현할 수 있도록 설정
if torch.cuda.is_available(): # GPU를 이용해 계산할 수 있는지 파악(True, False 반환)
DEVICE = torch.device('cuda') # cuda 장비 사용
else:
DEVICE = torch.device('cpu') # cpu 장비 사용
BATCH_SIZE = 64 # 파라미터를 업데이트할 때 한번에 계산되는 데이터 개수
# BATCH_SIZE 만큼 데이터를 이용해 output 계산하고 이에 대한 오차 계산
# 오차 평균해 역전파법 적용하고 파라미터 업데이트
INPUT_SIZE = 1000 # Input의 크기(데이터 1개의 크기)이자 입력층의 노드 수
# Input Size 크기를 갖는 데이터 Batch_Size개 이용
HIDDEN_SIZE = 100 # 다수의 파라미터를 이용해 계산한 결과에 한번 더 계산되는 파라미터 수, 은닉층 노드 수
OUTPUT_SIZE = 10 # 최종으로 출력되는 값의 벡터 크기
# 비교하고자 하는 레이블의 크기와 동일하게 설정(원핫인코딩 이용하기 때문)
torch.randn
: 평균이 0, 표준편차가 1인 정규분포에서 샘플링한 값
x
: input, y
: output, w1
: 가중치1, w2
: 가중치2
x = torch.randn(BATCH_SIZE, INPUT_SIZE, # 크기가 input_size인 데이터 batch_size개 생성
device = DEVICE, # 위에서 정의한 도구(CUDA/CPU) 사용
dtype = torch.float, # 데이터 형식 실수로 설정
requires_grad = False) # 학습(파라미터 업데이트)이 필요없으므로 gradient 계산 필요 없음
y = torch.randn(BATCH_SIZE, OUTPUT_SIZE, # 크기가 output_size인 데이터 batch_size개 생성
device = DEVICE,
dtype = torch.float,
requires_grad = False) # 학습(파라미터 업데이트)이 필요없으므로 gradient 계산 필요 없음
w1 = torch.randn(INPUT_SIZE, HIDDEN_SIZE, # x와 행렬곱을 통해 (hidden_size, batch_size)를 만들어야 하므로 다음과 같은 형상
device = DEVICE,
dtype = torch.float,
requires_grad = True) # 학습(파라미터 업데이트)이 필요하므로 gradient 계산 필요
w2 = torch.randn(HIDDEN_SIZE, OUTPUT_SIZE, # 은닉층 (hidden_size, batch_size)와 행렬곱을 통해 output(output_size, batch_size)를 만들어야 하므로 다음과 같은 형상
device = DEVICE,
dtype = torch.float,
requires_grad = True) # 학습(파라미터 업데이트)이 필요하므로 gradient 계산 필요
learning_rate = 1e-6 # 학습률(gradient에 따른 학습 정도) 결정
for t in range(1, 501): # 500번 학습(epochs=500)
y_pred = x.mm(w1).clamp(min=0).mm(w2) # torch.mm()을 사용해 가중치와 행렬곱 적용 후, clamp(min=0)로 활성화 함수 적용(ReLU와 같은 역할)
loss = (y_pred - y).pow(2).sum() # 오차 계산
if t % 100 == 0: # 100번째 반복마다
print(f"Iteration: {t}\t Loss: {loss.item()}") # 반복 횟수 및 오차 표시
loss.backward() # 오차역전파법 수행
with torch.no_grad(): # gradient 계산 결과 이용해 파라미터 업데이트할 때는 gradient값 고정
w1 -= learning_rate * w1.grad # 가중치 업데이트
w2 -= learning_rate * w2.grad # 가중치 업데이트
w1.grad.zero_() # gradient를 통해 파라미터 업데이트 했으므로 다시 학습을 위해 graident 0으로 초기화
w2.grad.zero_()
참고
모두를 위한 딥러닝 시즌2 Lab 1-1, 1-2
파이썬 딥러닝 파이토치 (이경택, 방성수, 안상준)