프레임워크와 라이브러리의 차이
- 프레임워크
- 프레임워크는 코드를 통한 애플리케이션의 전반적인 흐름과 구조를 관리한다.
- 사용자는 프레임워크가 제공하는 ‘훅’ 또는 ‘인터페이스’에 특정 로직을 구현하거나 인자를 전달함으로써 프레임워크와 상호작용한다. 이렇게하면 프레임워크가 제공하는 일종의 ‘규칙’ 과 ‘구조’ 내에서 코드를 작성하게 된다.
- ex) PyTorch에서는 ‘loss.backward’ 를 통해 gradient를 계산할 때, 프로그래머가 일일히 미분식을 작성하지 않고, 프레임워크가 제어권을 가진 상태에서 gradient를 계산해준다.
- 라이브러리
- 라이브러리는 특정 기능을 수행하는 함수나 메서드의 모음이다. 사용자는 이러한 라이브러리를 직접 호출하여 필요한 기능을 구현한다. 라이브러리는 사용자가 코드를 통한 애플리케이션의 흐름을 직접 제어하며 필요한 부분에서만 사용된다.
딥러닝 프레임워크
- 프레임워크별 성능 비교
- Computational Graph
- Pytorch
- Define by Run
- Dynamic Computation Graph (DCG)
- autograd 실행 시점에서 그래프를 생성 및 정의
- Debug가 매우 쉬워짐. ( 코드 중간중간에 바로바로 그래프를 확인 가능 → Pythonic code )
- TensorFlow
- Define and run
- 그래프를 먼저 정의 후, 실행 시점에 데이터를 feed
- Production, Cloud, Multi GPU 에서 강점. (확장성)
- Pytorch
PyTorch
- pytorch
- numpy 구조 갖는 Tensor 객체
- autograd, 다양한 function
- Dynamic Computation Graph (DCG)
- Tensor
- 다차원 Arrays 를 표현하는 PyTorch 클래스
- 사실상 numpy의 ndarray
# 0 ~ 9까지의 element를 갖는 nd array를 생성한 후, 사이즈를 (2,5)로 변경합니다. n_array = np.arange(10).reshape(2,5) print(f"ndim : {n_array.ndim}, shape : {n_array.shape}") # nd array를 PyTorch tensor로 변환합니다. t_array = torch.FloatTensor(n_array) # 텐서의 크기 t_array.shape t_array.size() # 텐서의 차원 수 t_array.ndim # 텐서의 크기 t_array.size() # array 를 tensor로 변경 data = [[3, 5],[10, 5]] torch.Tensor(data) nd_array_ex = np.array(data) torch.from_numpy(nd_array_ex)
- nump like operations
data = [[3, 5, 20],[10, 5, 50], [1, 5, 10]]
x_data = torch.Tensor(data)
# 1번째, 2번째 행 인덱싱
x_data[1:]
x_data[:2, 1:]
# 1차원 vector로 펼칩니다.
x_data.flatten()
# x_data shape과 동일한 크기로 원소 1을 갖는 tensor 생성
torch.ones_like(x_data)
# numpy nd array로 변환
x_data.numpy()
# 텐서의 데이터 타입 구합니다.
x_data.dtype
- numpy와 다른점
# 현재 환경에서 cuda 사용이 가능하다면, tensor를 cuda 버전으로 변경
if torch.cuda.is_available():
x_data_cuda = x_data.to('cuda')
x_data.device
- view v.s. reshape
- contiquity
- view는 tensor에 메모리가 연속적으로 존재할 때만 사용할 수 있다.
- reshape는 메모리에 연속적으로 존재하지 않을 때, 새로 copy하여 차원의 크기를 변경하며 메모리에 연속적으로 tensor가 존재하는 경우에는 원래 tensor와 메모리를 공유한다.
- is_contiguous 함수를 통해 tensor가 메모리에 연속적으로 존재하는지 여부를체크할 수 있다.
- t(), permute() 와 같은 연산에서 tensor의 contiguous가 깨진다.
- copy 없이 더 빠른 연산을 수행하다는 측면에서, view를 권장한다.
- contiquity
# 원소 0을 갖는 tensor를 생성하고, view로 사이즈를 변경 후, 값을 변경합니다. view와 reshape 메서드 간 a, b의 값을 확인해보세요.
a = torch.zeros(3,2)
b = a.view(2,3)
# 1로 값을 채운다.
a.fill_(1)
a, b
'''
(tensor([[1., 1.],
[1., 1.],
[1., 1.]]),
tensor([[1., 1., 1.],
[1., 1., 1.]]))
'''
# 원소 0을 갖는 tensor를 생성하고, reshape(6)로 사이즈를 변경 후, 값을 변경합니다. view와 reshape 메서드 간 a, b의 값을 확인해보세요.
a = torch.zeros(3,2)
b = a.t().reshape(6)
# 1로 값을 채운다.
a.fill_(1)
a, b
'''
tensor([[1., 1.],
[1., 1.],
[1., 1.]]),
tensor([0., 0., 0., 0., 0., 0.])
'''
- squeeze v.s. unsqueeze
- mm v.s. matmul
- dot : 1차원 텐서 끼리의 연산에서만 사용 가능
- mm : matrix 끼리의 연산에서 사용 가능
- matmul : mat끼리의 연산 + broadcasting
A = torch.tensor([[1,2],[3,4]])
C = torch.tensor([[[1,1],[1,1]],[[1,1],[1,1]]])
torch.matmul(A,C)
'''
tensor([[[3, 3],
[7, 7]],
[[3, 3],
[7, 7]]])
'''
torch.matmul(C,A)
'''
tensor([[[4, 6],
[4, 6]],
[[4, 6],
[4, 6]]])
'''
- 그 밖의 ML/DL 을 위한 연산
- torch.nn.functional.softmax(tensor, dim=0)
- t_array.argmax(dim=1)
- torch.nn.functional.one_hot(y_label)
- torch.cartesian_prod(tensor_a, tensor_b)
- itertools.product(a,b)
PyTorch 프로젝트 구조
- jupyter notebook의 한계
- 초기 단계에서는 대화식 개발 과정이 유리 했으나.. ⇒ 학습과정과 디버깅 등 지속적인 확인
- 배포 및 공유 단계에서는 notebook 공유의 어려움 ⇒ 쉬운 재현의 어려움, 실행 순서 꼬임 (but 재현가능성 필수)
- 개발 용이성 확보와 유지보수 향상 필요 ⇒ OOP + 모듈 → Project
- Project Template
- 실행, 데이터, 모델, 설정, 로깅, 지표, 유틸리티 등 다양한 모듈들 분리하여 프로젝트 템플릿화
- 프로젝트의 여러 모듈들이 분리 돼 있어 코드를 재사용하기 편하다.
- 쉬운 코드의 재현이 가능하다.
- 추천하는 repository
- pytorch-template 으로 본 예시
- 실행, 데이터, 모델, 설정, 로깅, 지표, 유틸리티 등 다양한 모듈들 분리하여 프로젝트 템플릿화
pytorch-template/
│ # 실행
├── train.py - main script to start training
├── test.py - evaluation of trained model
│ # 설정
├── config.json - holds configuration for training
├── parse_config.py - class to handle config file and cli options
│ # 새로운 템플릿 만들 때
├── new_project.py - initialize new project with template files
│ # base-abstract module
| # 데이터를 부르거나
| # 모델 아키텍쳐 설정 하거나
| # 베이스 트리거
├── base/ - abstract base classes
│ ├── base_data_loader.py
│ ├── base_model.py
│ └── base_trainer.py
│ # data
├── data_loader/ - anything about data loading goes here
│ └── data_loaders.py
│
├── data/ - default directory for storing input data
│ # model-architecture, loss, metric
├── model/ - models, losses, and metrics
│ ├── model.py
│ ├── metric.py
│ └── loss.py
│ # 저장소 - 로그, 모델 상태
├── saved/
│ ├── models/ - trained models are saved here
│ └── log/ - default logdir for tensorboard and logging output
│ # 학습 수행
│ # 여러 설정들, 로깅하는 방법들, 모델들, 데이터 저장소
│ # 각각의 레고블록들을 연결지음
├── trainer/ - trainers
│ └── trainer.py
│ # 로깅 설정
├── logger/ - module for tensorboard visualization and logging
│ ├── visualization.py
│ ├── logger.py
│ └── logger_config.json
│ # 유틸리티
└── utils/ - small utility functions
├── util.py
└── ...
- ‘getitem’
- 인스턴스를 마치 리스트나 딕셔너리처럼 취급할 수 있다.
- ‘for’ 루프나 ‘in’ 연산자도 사용할 수 있따.
- 인자는 하나만 받고, ‘읽기 전용’으로 간주된다.
- 딕셔너리처럼 문자열을 인덱스로 사용할 수도 있다.
- ex) parse_config.py 파일에서 __getitem_이 구현됨에 따라, config에 딕셔너리처럼 접근이 가능한 것을 확일 할 수 있다.
class TestClass:
def __init__(self, items):
self.items = items
my_list = TEstClass([1,2,3,4,5])
my_list[2] # TypeError, not subscriptable
class TEstClass:
def __init__(self, items):
self.items = items
def __getitem__(self, index):
return self.items[index]
my_list = TestClass([1,2,3,4,5])
print(my_list[2]) # >>> 3
print(1 in my_list) # >>> True
for item in my_list:
print(item, end= ' ') # >>> 1 2 3 4 5
Further Reading
'TIL' 카테고리의 다른 글
[Pytorch] 네부캠 day-10 (1) | 2023.11.16 |
---|---|
[Pytorch] 부트캠 day-9 (1) | 2023.11.15 |
[Pandas1] 부트캠 day-5 (0) | 2023.11.10 |
[베이즈 정리] 부트캠 d-4 (0) | 2023.11.09 |
[Vector & Matrix] 부트캠 day-3 (0) | 2023.11.09 |