그림 5-1. 5장 머신러닝 모델 실험과 개발의 구성요소와 도구들 (머신러닝 실험 환경, 메타데이터 저장소, 소스코드 리포지토리, 분산 학습)
이번 장에서는 MLOps 시스템 내에서 머신러닝 모델의 실험과 개발에 필요한 도구들을 살펴봅니다. 특히, 효과적인 머신러닝 실험을 위한 대화형 도구인 JupyterLab에 주목합니다. 또한, MLOps 환경에서 JupyterLab을 중앙화된 방식으로 운영하는 JupyterHub의 설치 및 설정 과정을 안내합니다.
이어서, 머신러닝 실험 과정에서 생성되는 다양한 메타데이터의 관리의 중요성을 강조하며, 이를 위한 MLFlow Tracking의 역할과 사용법을 탐구합니다. MLFlow를 통해 머신러닝 실험 데이터의 추적과 관리를 어떻게 하는지 예시를 통해 알아보겠습니다.
또한, 머신러닝 실험과 개발에 사용한 소스코드 버전 관리 도구인 Github과 GitLab에 대해서도 알아보고, 이들의 활용 방법을 소개합니다. 마지막으로, 분산 학습을 위한 도구들에 대해 알아보면서 이 장을 마무리합니다.
5.1 머신러닝 실험 환경
머신러닝 실험은 소프트웨어 개발과 마찬가지로 물리적으로는 대부분 로컬 환경, 즉, 여러분이 사용 중인 노트북이나 데스크탑에서 이루어집니다. SQL 클러이언트 프로그램, VSCode와 같은 코드 에디터, Python 인터프리터, 각종 머신러닝 관련 Python 패키지등 모두 머신러닝 실험과 개발에 사용하는 필수 도구들 입니다. 이 장에서는 데이터 분석 및 머신러닝 실험과 개발에 널리 사용되는 대화형 도구인 JupyterLab에 주목합니다.
JupyterLab은 Jupyter Notebook을 기반으로 한 확장 버전으로, 웹 기반의 강력한 인터랙티브 개발 환경을 제공합니다. 이 환경은 코드 작성, 데이터 시각화, 문서화 및 파일 관리를 통합적으로 수행할 수 있는 인터페이스를 통해 복잡한 데이터 과학 및 머신러닝 프로젝트에 최적화되어 있습니다.
또한, JupyterLab을 MLOps 인프라 환경에 통합하여 중앙화된 서비스로 제공하는 방법에 대해서도 논의합니다. 이를 위해 JupyterHub를 쿠버네티스 클러스터에 설치 및 설정하는 과정을 자세히 살펴보겠습니다.
5.1.1 JupyterLab
그림 5-2. JupyterLab 실행 화면
JupyterLab은 데이터 과학 및 머신러닝 분야에서 널리 사용되는 인터랙티브한 웹 기반 개발 환경입니다. Jupyter Notebook의 직접적인 후속작으로 개발되었으며, 사용자에게 훨씬 더 풍부한 기능과 유연한 작업 공간을 제공합니다. JupyterLab에서 사용자는 코드를 작성하고 실행할 뿐만 아니라 데이터를 시각화하고, 결과를 문서화할 수 있습니다. 이 환경은 코드, 시각적 출력, 그리고 서식 있는 텍스트를 동시에 볼 수 있는 인터페이스를 제공함으로써, 데이터 과학자와 개발자가 보다 효과적으로 작업을 수행할 수 있도록 합니다.
JupyterLab의 주요 강점은 그 확장성과 통합성에 있습니다. 사용자는 다양한 머신러닝 프레임워크와 데이터 처리 라이브러리를 쉽게 통합할 수 있으며, 추가적인 확장 기능을 통해 맞춤화된 작업 환경을 구성할 수 있습니다. 또한, JupyterLab은 파일 탐색기, 리치 텍스트 에디터, 터미널 등 다양한 도구를 내장하고 있어, 하나의 플랫폼에서 전체 데이터 과학 및 머신러닝 워크플로우를 관리할 수 있습니다. 이를 통해 사용자는 코드 작성, 데이터 분석, 시각화 및 결과 공유 등의 작업을 원활하게 진행할 수 있습니다.
Docker로 실행하기 (추천)
아래와 같이 docker를 사용하여 JupyterLab을 실행 할 수 있습니다.
$ docker run -it --rm -p 8888:8888 -v "${PWD}":/home/jovyan/work quay.io/jupyter/scipy-notebook:2023-11-17
웹 브라우저에서 http://localhost:8888/ 접속하면, Password or token: 을 입력하는 페이지가 나옵니다. docker 실행시 출력한 아래와 같은 콘슬 메세지의 출력한 토큰을 복사하여 입력합니다. (또는 콘솔에 출력된 URL로 바로 접속)
이 글을 읽으시는 대부분의 독자분들은 JupyterLab이나 Jupyter Notebook 사용법은 이미 익숙하실거라 생각합니다. JupyterLab에 대해 생소하시거나 자세한 사용법을 알고싶으신 분은 JupyterLab User Guide 문서를 참고하시기 바랍니다. 사실, Jupyter Notebook 코드 블록에서 Shift + Enter 단축키로 Python 코드를 실행하는 것만 알아도 충분합니다. 간단한 딥러닝 모델을 학습하고, 결과를 시각화하는 예제 노트북을 살펴보면서 이 절을 마무리 하겠습니다.
PyTorch 이미지 분류 모델 학습 및 TensorBoard 시각화 예제
JupyterLab에서 Python Notebook을 하나 띄워서 간단한 딥러닝 예제를 실행해 봅시다. 아래 코드 블록들은 Jupyter Notebook의 코드 블록 하나와 매핑 됩니다.
TensorBoard에 정보를 작성하는 핵심 객체인 SummaryWriter를 정의합니다.
from torch.utils.tensorboard import SummaryWriter
# default `log_dir` is "runs" - we'll be more specific here
writer = SummaryWriter('runs/fashion_mnist_experiment_1')
TensorBoard 확장을 실행 합니다. SummaryWriter 객체에 기록된 값들은 이곳에 시각화되어 볼 수 있습니다.
%tensorboard --logdir=runs --host 0.0.0.0
이미지 그리드로 학습 데이터 샘플을 시각화하고, TensorBoard에 추가합니다.
# get some random training images
dataiter = iter(trainloader)
images, labels = next(dataiter)
# create grid of images
img_grid = torchvision.utils.make_grid(images)
# show images
matplotlib_imshow(img_grid, one_channel=True)
# write to tensorboard
writer.add_image('four_fashion_mnist_images', img_grid)
모델 아키텍처를 TensorBoard에 추가합니다. TensorBoard GRAPHS 탭에서 시각화된 모델 아키텍처를 확인 할 수 있습니다.
writer.add_graph(net, images)
writer.close()
add_embedding 메서드로 고차원 데이터의 저차원 표현을 시각화할 수 있습니다. TensorBoard 우측 상단 INACTIVE 메뉴에서 PROJECTOR 메뉴에서 확인 할 수 있습니다.
# helper function
def select_n_random(data, labels, n=100):
'''
Selects n random datapoints and their corresponding labels from a dataset
'''
assert len(data) == len(labels)
perm = torch.randperm(len(data))
return data[perm][:n], labels[perm][:n]
# select random images and their target indices
images, labels = select_n_random(trainset.data, trainset.targets)
# get the class labels for each image
class_labels = [classes[lab] for lab in labels]
# log embeddings
features = images.view(-1, 28 * 28)
writer.add_embedding(features,
metadata=class_labels,
label_img=images.unsqueeze(1))
writer.close()
add_figure메소드로샘플 이미지 예측 결과와 실제 값을 보여주는 것을 TensorBoard에 추가합니다. (TensorBoard IMAGES 탭에서 확인) add_scalar메소드로 모델 학습 loss 값을 TensorBoard에 기록합니다. (TensorBoard SCALARS 탭에서 확인)
# helper functions
def images_to_probs(net, images):
'''
Generates predictions and corresponding probabilities from a trained
network and a list of images
'''
output = net(images)
# convert output probabilities to predicted class
_, preds_tensor = torch.max(output, 1)
preds = np.squeeze(preds_tensor.numpy())
return preds, [F.softmax(el, dim=0)[i].item() for i, el in zip(preds, output)]
def plot_classes_preds(net, images, labels):
'''
Generates matplotlib Figure using a trained network, along with images
and labels from a batch, that shows the network's top prediction along
with its probability, alongside the actual label, coloring this
information based on whether the prediction was correct or not.
Uses the "images_to_probs" function.
'''
preds, probs = images_to_probs(net, images)
# plot the images in the batch, along with predicted and true labels
fig = plt.figure(figsize=(12, 48))
for idx in np.arange(4):
ax = fig.add_subplot(1, 4, idx+1, xticks=[], yticks=[])
matplotlib_imshow(images[idx], one_channel=True)
ax.set_title("{0}, {1:.1f}%\n(label: {2})".format(
classes[preds[idx]],
probs[idx] * 100.0,
classes[labels[idx]]),
color=("green" if preds[idx]==labels[idx].item() else "red"))
return fig
running_loss = 0.0
for epoch in range(1): # loop over the dataset multiple times
for i, data in enumerate(trainloader, 0):
# get the inputs; data is a list of [inputs, labels]
inputs, labels = data
# zero the parameter gradients
optimizer.zero_grad()
# forward + backward + optimize
outputs = net(inputs)
loss = criterion(outputs, labels)
loss.backward()
optimizer.step()
running_loss += loss.item()
if i % 1000 == 999: # every 1000 mini-batches...
# ...log the running loss
writer.add_scalar('training loss',
running_loss / 1000,
epoch * len(trainloader) + i)
# ...log a Matplotlib Figure showing the model's predictions on a
# random mini-batch
writer.add_figure('predictions vs. actuals',
plot_classes_preds(net, inputs, labels),
global_step=epoch * len(trainloader) + i)
running_loss = 0.0
print('Finished Training')
로컬 JupyterLab 환경에서 머신러닝 실험을 진행하면 다양한 패키지 설치가 필요합니다. 하지만 이 과정은 시간 소모가 크며, 버전 충돌이나 환경 설정 문제를 야기할 수 있습니다. 이런 문제는 특히 여러 사람이 동일한 프로젝트에 참여하는 경우 더욱 심각해집니다. 이때 모든 팀원이 동일한 환경을 유지하는 것이 필수적입니다. 이러한 문제를 해결하기 위해 JupyterLab 환경을 중앙화된 MLOps 인프라로 통합하는 것이 좋습니다. JupyterHub를 도입하면 MLOps 인프라에서 필요한 모든 패키지와 환경을 효율적으로 관리할 수 있으며, 이를 통해 모든 팀원이 일관된 작업 환경에서 협업할 수 있게 됩니다.
JupyterHub는 여러 사용자가 JupyterLab 환경을 공유하고 사용할 수 있도록 하는 서버 소프트웨어입니다. 이 플랫폼은 개별 사용자에게 개인화된 Jupyter Notebook 환경을 제공하면서도 중앙 집중식 서버에서 모든 사용자를 관리할 수 있는 기능을 갖추고 있습니다. 대학, 연구소, 기업 등 다양한 조직에서 교육이나 협업 프로젝트를 진행할 때 효과적인 환경을 제공합니다. JupyterHub는 사용자별로 격리된 작업 공간을 제공하며, 이는 안정성과 보안을 강화하는 데 기여합니다.
JupyterHub의 또 다른 주요 장점은 설치 및 환경 구성의 간소화입니다. 관리자는 서버에 필요한 라이브러리와 도구를 한 번에 설치하고 구성함으로써, 사용자 각자가 동일한 작업을 반복하는 수고를 덜 수 있습니다. 이러한 중앙화된 관리는 프로젝트의 효율성을 크게 향상시키며, 팀 구성원 간의 일관된 작업 환경을 제공합니다. 또한, JupyterHub는 확장성이 뛰어나 다양한 인증 옵션, 사용자별 자원 할당 등을 지원하여 규모가 큰 조직의 요구사항을 충족시키는데 적합합니다.