From 57d2852bc32dc406d72081221ae26f3f3540e06b Mon Sep 17 00:00:00 2001 From: Sangwoo Han Date: Mon, 20 Jan 2020 22:15:34 +0900 Subject: [PATCH] Add tutorial (usage) --- tutorial/pytorch-tutorial.py | 105 ++++++++++++++++++++++++++++++++ tutorial/requirements.txt | 2 + tutorial/tf-tutorial.py | 26 ++++++++ tutorial/tutorial.md | 112 +++++++++++++++++++++++++++++++++++ 4 files changed, 245 insertions(+) create mode 100644 tutorial/pytorch-tutorial.py create mode 100644 tutorial/requirements.txt create mode 100644 tutorial/tf-tutorial.py create mode 100644 tutorial/tutorial.md diff --git a/tutorial/pytorch-tutorial.py b/tutorial/pytorch-tutorial.py new file mode 100644 index 0000000..f381de9 --- /dev/null +++ b/tutorial/pytorch-tutorial.py @@ -0,0 +1,105 @@ +from argparse import ArgumentParser + +import torch +import torch.nn as nn +import torch.nn.functional as F +import torch.optim as optim +import torchvision +import torchvision.transforms as transforms + +parser = ArgumentParser() +parser.add_argument("--no-cuda", action="store_true", default=False) +args = parser.parse_args() + +device = torch.device("cpu" if args.no_cuda else "cuda") +dataloader_kwargs = {"pin_memory": True} + +transform = transforms.Compose( + [transforms.ToTensor(), transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))] +) + +trainset = torchvision.datasets.CIFAR10( + root="/data", train=True, download=True, transform=transform +) +trainloader = torch.utils.data.DataLoader( + trainset, batch_size=32, shuffle=True, num_workers=2, pin_memory=True, +) + +testset = torchvision.datasets.CIFAR10( + root="/data", train=False, download=True, transform=transform +) +testloader = torch.utils.data.DataLoader( + testset, batch_size=128, shuffle=False, num_workers=2, pin_memory=True, +) + +classes = ( + "plane", + "car", + "bird", + "cat", + "deer", + "dog", + "frog", + "horse", + "ship", + "truck", +) + + +class Net(nn.Module): + def __init__(self): + super(Net, self).__init__() + self.conv1 = nn.Conv2d(3, 6, 5) + self.pool = nn.MaxPool2d(2, 2) + self.conv2 = nn.Conv2d(6, 16, 5) + self.fc1 = nn.Linear(16 * 5 * 5, 120) + self.fc2 = nn.Linear(120, 84) + self.fc3 = nn.Linear(84, 10) + + def forward(self, x): + x = self.pool(F.relu(self.conv1(x))) + x = self.pool(F.relu(self.conv2(x))) + x = x.view(-1, 16 * 5 * 5) + x = F.relu(self.fc1(x)) + x = F.relu(self.fc2(x)) + x = self.fc3(x) + return x + + +net = nn.DataParallel(Net().to(device)) + + +criterion = nn.CrossEntropyLoss() +optimizer = optim.Adam(net.parameters(), lr=0.001) + +for epoch in range(2): + + running_loss = 0.0 + for i, data in enumerate(trainloader, 0): + inputs, labels = data[0].to(device), data[1].to(device) + + optimizer.zero_grad() + outputs = net(inputs) + loss = criterion(outputs, labels) + loss.backward() + optimizer.step() + + running_loss += loss.item() + if i % 10 == 0: + print("[%d, %5d] loss: %.3f" % (epoch + 1, i + 1, running_loss / 10)) + running_loss = 0.0 + +print("Finished Training") + +correct = 0 +total = 0 + +with torch.no_grad(): + for data in testloader: + images, labels = data[0].to(device), data[1].to(device) + outputs = net(images) + _, predicted = torch.max(outputs.data, 1) + total += labels.size(0) + correct += (predicted == labels).sum().item() + +print('Accuracy of the network on the 10000 test images: {:.2%}'.format(correct / total)) diff --git a/tutorial/requirements.txt b/tutorial/requirements.txt new file mode 100644 index 0000000..057643c --- /dev/null +++ b/tutorial/requirements.txt @@ -0,0 +1,2 @@ +torchvision==0.5.0 +openpyxl==3.0.3 diff --git a/tutorial/tf-tutorial.py b/tutorial/tf-tutorial.py new file mode 100644 index 0000000..4f25ac2 --- /dev/null +++ b/tutorial/tf-tutorial.py @@ -0,0 +1,26 @@ +import tensorflow as tf +from tensorflow import keras + + +fashion_mnist = keras.datasets.fashion_mnist +(train_images, train_labels), (test_images, test_labels) = fashion_mnist.load_data() +train_images = train_images / 255.0 +test_images = test_images / 255.0 + +model = keras.Sequential( + [ + keras.layers.Flatten(input_shape=(28, 28)), + keras.layers.Dense(128, activation="relu"), + keras.layers.Dense(10, activation="softmax"), + ] +) + +model.compile( + optimizer="adam", loss="sparse_categorical_crossentropy", metrics=["accuracy"] +) + +model.fit(train_images, train_labels, epochs=5) + +test_loss, test_acc = model.evaluate(test_images, test_labels, verbose=2) + +print("\nTest Accuracy:", test_acc) diff --git a/tutorial/tutorial.md b/tutorial/tutorial.md new file mode 100644 index 0000000..a832629 --- /dev/null +++ b/tutorial/tutorial.md @@ -0,0 +1,112 @@ +# Docker Guide (사용법) + +github 주소는 [여기](https://github.com/uoo723/docker-guide) + +## 1. 목적 + +공용서버 등과 같이 여러 사람들이 공용으로 리소스를 사용하는 환경에서는 각자가 연구 개발한 코드의 의존성이 +다양하기 때문에 사용하는 패키지 등의 버전이 충돌할 수 있다. Python을 사용한다면 conda와 같은 프로그램을 +사용하여 Python 버전 및 패키지 버전을 python 가상환경을 구성하여 관리할 수 있지만, 그 외에 cuda와 같이 +다양한 버전을 관리할 수 있는 매커니즘을 제공하지 않은 경우 불가피하게 기존 버전을 제거하고 새로운 버전의 +패키지를 설치해야 하는 번거로움이 발생하게 되게 된다. 또한 이전 버전에서 돌려야 하는 코드가 설치된 버전의 +의존성에 대해 동작하지 않을 수 있다. + +따라서 이러한 문제를 피하기 위해 os level의 가상환경 구성이 요구된다. 따라서 이를 가능하도록 하는 +Docker를 이용하여 각자의 코드 환경이 독립적으로 구성할 수 있도록 한다. + +## 2. Docker Hub + +[Docker Hub](https://hub.docker.com/)는 docker image를 공유할 수 있는 repository이고, +기존의 image를 사용하여 미리 만들어진 환경을 그대로 사용할 수 있으며, 자신이 만든 docker image를 +올릴 수도 있다. 이번 튜토리얼에서는 기존 official image로도 충분히 원하는 환경을 구성할 수 있으므로 +Docker image를 생상하는 방법은 생략한다. + +## 3. Tensorflow + +tensorflow에서 제공하는 official [image](https://hub.docker.com/r/tensorflow/tensorflow)를 +사용하여 tensorflow 코드 동작 환경을 구성하는 방법. + +### 3-1. TL;DR + +```bash +$ docker run --rm -it --gpus all -v $(pwd):/src -w /src --name tf tensorflow/tensorflow:2.0.0-gpu-py3 python tf-tutorial.py +``` + +### 3-2. 명령어 구성 + +* docker run [options] [image] [command] + +#### 3-2-1. 옵션 설명 + +* --rm: 도커 컨테이너 생성 후 실행이 완료되면 컨테이너 삭제 +* -it: 컨테이너와의 interactive 모드 활성 (키보드 입력) +* --gpus [all | num_of_gpu]: 컨테이너에서 사용할 gpu 갯수를 지정 all이면 모든 gpu 사용 +* -v [src]:[dst]: 컨테이너 내에서 작성한 코드에 접근하기 위해 호스트의 src위치와 컨테이너의 dst의 + 위치를 맵핑하여야 한다. +* -w [working_dir]: 컨테이너의 working directory 지정 +* --name [container_name]: 컨테이너 이름을 지정 + +#### 3-2-2. 올바른 버전의 image 선택 + +\[image_name]:[tag] + +* `image_name`은 tensorflow/tensorflow +* `tag`는 image 버전 등을 표기하기 위한 용도로, 제공하는 image마다 tag를 다는 규칙은 다르다. +* `tensorflow`이미지 같은 경우 [version][|-gpu][|-py3]로 구성되며 전체 사용가능 `tag` + 리스트는 [다음](https://hub.docker.com/r/tensorflow/tensorflow/tags)에서 확인 가능하다. + +## 4. Pytorch + +pytorch에서 제공하는 official [image](https://hub.docker.com/r/tensorflow/tensorflow)를 +사용하여 pytorch 코드 동작 환경을 구성하는 방법. + +### 4-1. TL;DR + +```bash +$ docker run --rm -it --gpus all -v $(pwd):/src -w /src pytorch/pytorch:1.2-cuda10.0-cudnn7-runtime python pytorch-tutorial.py +``` + +나머지 설명은 [3. Tensorflow](#3.\ Tensorflow)와 동일 + +### 5. 기타 의존성 python 패키지 설치 + +코드 실행시 부가적으로 필요한 python 패키지는 `requirements.txt` 파일에 명시하여 docker 컨테이너 +실행시 자동으로 설치하도록 한다. + +#### requirements.txt + +```txt +torchvision==0.5.0 +openpyxl==3.0.3 +``` + +#### python 패키지 설치 후에 코드 실행 + +```bash +$ docker run --rm -it --gpus all -v $(pwd):/src -w /src pytorch/pytorch:1.2-cuda10.0-cudnn7-runtime /bin/bash -c 'pip install -r requirements.txt && python pytorch-tutorial.py' +``` + +매번 코드 수정 후 테스트하게 될 때 (code development cycle) 위의 명령을 다시 실행하는 경우 처음부터 패키지를 +다운받아 설치하는 과정을 거치는데, 패키지의 사이즈가 큰 경우에는 다운로드 받는 시간으로 인해 낭비되는 시간이 생기므로 +pip cache directory를 호스트 시스템에 마운트하여 다운받는 시간을 단축한다. + +#### Docker volume 생성하기 + +```bash +$ docker volume create pip_cache +$ docker volume ls # volume 리스트 확인 +``` + +#### Docker container 실행시 pip cache directory 마운트 + +```bash +$ docker run --rm -it --gpus all \ +-v $(pwd):/src \ +-v pip_cache:/pip_cache \ +-w /src \ +pytorch/pytorch:1.2-cuda10.0-cudnn7-runtime \ +/bin/bash -c \ +'pip install --cache-dir /pip_cache -r requirements.txt && python pytorch-tutorial.py' +``` + +다음 실행시에는 disk에 cache된 패키지를 설치하게 된다.