2021년 5월 8일 토요일

node.js 기반 Visual Flow Programming 도구 소개

이 글은 텍스트 기반 코딩이 아닌 Visual Flow Programming (비쥬얼 플로우 프로그래밍) 도구를 소개한다. 여기서는 사용하기 편리한 node.js 기반 프로그래밍 도구를 공유한다. 

NoFlo
NoFlo는 Node.js 브라우저 모두에서 실행되는 JavaScript 용 흐름 기반 프로그래밍 구현이다. NoFlo 구성요소는 ES6를 포함하여 JavaScript로 변환되는 모든 언어로 작성할 수 있다. 이 시스템은 J. Paul Morrison의 저서 Flow-Based Programming(1994)에서 크게 영감을 받았다.
J. Paul Morrison

NoFlo는 웹 프레임 워크 나 UI 툴킷이 아니다. JavaScript 애플리케이션에서 데이터 흐름을 조정하고 재구성하는 방법이다. 
NoFlo는 웹 서버 및 도구 구축에서부터 GUI 애플리케이션 내부의 이벤트 조정, 로봇 구동 또는 인터넷에 연결된 예술 설치 구축에 이르기까지 모든 작업에 사용되고 있다.

NoFlo 자체는 JavaScript에서 흐름 기반 프로그램을 구현하기 위한 라이브러리이다. 설치 방법은 다음과 같으며, 소스 코드는 github에서 다운로드가능하다.
npm install noflo --save

Rete는 시각적 프로그래밍을 위한 모듈식 프레임 워크이다. Rete를 사용하면 브라우저에서 직접 노드 기반 편집기를 만들 수 있다. 사용자가 한 줄의 코드없이 편집기에서 데이터 처리 방식을 정의할 수 있다.
설치는 다음과 같다. 설명 문서는 여기를 참고하라.
npm install rete rete-vue-render-plugin rete-connection-plugin

Drawflow를 사용하면 데이터 흐름을 쉽고 빠르게 만들 수 있다.

설치는 다음과 같다. 
npm i drawflow

Reference

2021년 5월 4일 화요일

Kaolin 기반 3D 딥러닝 모델 개발 방법 소개

이 글은 카올린 Kaolin기반 3D 딥러닝 모델 개발 방법을 간략히 소개한다.

이 글은 3D 객체 인식 분류기를 개발하는 방법을 이해한다. 3D 객체 인식은 자율 주행 자동차, 로봇, AR / VR 같은 실제 애플리케이션을 개발하는 데 중요한 부분이다. 3D 데이터는 물체 / 차량을 정확하게 위치시키는 데 사용할 수 있는 깊이 정보를 제공한다.

3D 데이터 표현
포인트 클라우드는 XYZ 좌표에 의해 지정된 LiDAR와 같은 센서에서 얻은 원시 데이터이다. 이 데이터는 폴리곤 메시(mesh), 복셀(voxel) 등 다른 표현으로 변환된다.
개발 도구
Google colaboratory 일명 colab은 무료로 GPU에 액세스 할 수있는 jupyter 노트북이다. Colaboratory에서 모델을 훈련 할 때 GPU 기반 가상 머신을 사용할 수 있다. 한 번에 최대 12 시간이 주어진다. 따라서 정기적으로 데이터 또는 체크 포인트를 저장하라. colab은 완전 무료이다.

colab에는 주요 라이브러리 (NumPy, matplotlib) 및 프레임 워크 (TensorFlow, PyTorch)가 사전 설치되어 있으며, 사용자 설치를 위해 (! pip install ) 사용할 수 있다.

Kaolin- 3D 딥러닝 프레임워크
Kaolin은 3D 딥러닝 연구를 가속화하기 위해 NVIDIA 팀에서 개발한 오픈소스 PyTorch 라이브러리이다. Kaolin 프레임워크는 몇 줄의 코드로 3D 모델을 딥러닝 데이터 세트로 변환한다. kaolin은 인기있는 3D 데이터 세트를 로드하고 사전처리하는 데 쉽다.

Kaolin 프레임워크는 포인트 클라우드 데이터를 복셀 그리드로 변환하는 복잡한 3D 알고리즘, 간단한 삼각형 메시 표현을 지원한다. 카올린 프레임워크는 로봇 공학, 자율 주행 자동차, 증강 및 가상 현실과 같은 분야의 연구자들에게 도움이 된다.

이제 3D 객체 감지 분류기에서는 Kaolin 프레임 워크를 사용한다. git repo는 여기에서 찾을 수 있다. 

데이터 세트
데이터 세트는 princeton MODELNET 에서 사용할 수 있다. ModelNet10.zip 파일은 깊은 네트워크를 훈련하는 데 사용되는 10 개 카테고리에서 CAD 모델을 포함한다. 이를 통해, 3D 물체 검출 분류, 훈련 및 테스트 분할 정보를 얻을 수 있다. 

욕조, 침대, 의자, 책상, 옷장, 모니터, 침실 용 스탠드, 소파, 테이블, 화장실

3D 객체 감지 분류기
여기에서 Google Colab을 열고 런타임을 GPU로 변경하고, 다음 코드를 코랩 쥬피터 노트북에 붙여넣고 실행한다.
!pip install trimesh
import os
import glob
import trimesh
import numpy as np
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers
from matplotlib import pyplot as plt

tf.random.set_seed(1234)
%matplotlib inline

#Installing kaolin
!pip install git+https://github.com/NVIDIAGameWorks/kaolin.git

import torch
from torch.utils.data import DataLoader
import kaolin as kal
from kaolin import ClassificationEngine
from kaolin.datasets import ModelNet
from kaolin.models.PointNet import PointNetClassifier
import kaolin.transforms as tfs
from torchvision.transforms import Lambda

MODELNET10 데이터 세트 다운로드한다.
#downloading the MODELNET 10 dataset
DATA_DIR = tf.keras.utils.get_file(
    "modelnet.zip",
    "http://3dvision.princeton.edu/projects/2014/3DShapeNets/ModelNet10.zip",
    extract=True,
)
DATA_DIR = os.path.join(os.path.dirname(DATA_DIR), "ModelNet10")

X, Y, Z 3D 모델 시각화한다.
#visualizing bed .off model
mesh = trimesh.load(os.path.join(DATA_DIR, "bed/train/bed_0001.off"))
mesh1= trimesh.load(os.path.join(DATA_DIR, "chair/train/chair_0001.off"))
mesh2= trimesh.load(os.path.join(DATA_DIR, "night_stand/train/night_stand_0001.off"))

mesh.show()

데이터를 로딩한다.
Kaolin은 인기있는 3D 데이터 세트 (ModelNet10)를 로드하는 편리한 기능을 제공한다. 시작하려면 몇 가지 중요한 매개 변수를 정의한다.
model_path변수는 ModelNet10 데이터 세트의 경로를 정의한다. categories변수를 사용하여 분류할 클래스를 지정한다. num_points포인트 클라우드로 변환 할 때 메시에서 샘플링할 포인트의 수이다. 마지막으로 변환 작업에 CUDA를 사용하는 경우 다중 처리 및 메모리 고정을 비활성화한다.

modelnet_path = os.path.join(os.path.dirname(DATA_DIR), "ModelNet10")
print(modelnet_path)
categories = ['chair', 'sofa', 'bed','night_stand']
num_points=1024
device='cuda'
workers = 8

#training parameters
batch_size = 12
learning_rate = 1e-3
epochs = 10

이 명령은 transform먼저 메시 표현을 포인트 클라우드로 변환한 다음 원점 중심에 오도록 정규화하고 표준 편차를 1로 정의한다. 이미지와 마찬가지로 포인트 클라우드와 같은 3D 데이터는 더 나은 분류 성능을 위해 정규화되어야 한다.

split='train'인수는 '기차'분할을로드하고 있음을 나타냅니다. rep='pointcloud'메시를로드하고 포인트 클라우드로 변환한다. transform=norm각 점 구름에 정규화 변환을 적용한다.
def to_device(inp):
    inp.to(device)
    return inp

transform = tfs.Compose([
    to_device,
    tfs.TriangleMeshToPointCloud(num_samples=num_points),
    tfs.NormalizePointCloud()
])

num_workers = 0 if device == 'cuda' else workers
pin_memory = device != 'cuda'

train_loader = DataLoader(ModelNet(modelnet_path, categories=categories,
                                   split='train', transform=transform),
                          batch_size=batch_size, shuffle=True, 
                          num_workers=num_workers, pin_memory=pin_memory)
                          
val_loader = DataLoader(ModelNet(modelnet_path, categories=categories,
                                 split='test',transform=transform),
                        batch_size=batch_size, num_workers=num_workers,
                        pin_memory=pin_memory)

PointNet을 이용해, 모델 학습을 위한 최적화 프로그램 및 손실 기준을 설정한다.
model = PointNetClassifier(num_classes=len(categories)).to(device)
optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate)
criterion = torch.nn.CrossEntropyLoss()

포인트 클라우드 분류기를 훈련한다. 대략 20분 소요된다.
for e in range(epochs):
    print(f'{"":-<10}\nEpoch: {e}\n{"":-<10}')

    train_loss = 0.
    train_accuracy = 0.

    model.train()
    for batch_idx, (data, attributes) in enumerate(tqdm(train_loader)):
        category = attributes['category'].to(device)
        pred = model(data)
        loss = criterion(pred, category.view(-1))
        train_loss += loss.item()
        loss.backward()
        optimizer.step()
        optimizer.zero_grad()

        # Compute accuracy
        pred_label = torch.argmax(pred, dim=1)
        train_accuracy += torch.mean((pred_label == category.view(-1)).float()).item()

    print('Train loss:', train_loss / len(train_loader))
    print('Train accuracy:', train_accuracy / len(train_loader))

    val_loss = 0.
    val_accuracy = 0.

    model.eval()
    with torch.no_grad():
        for batch_idx, (data, attributes) in enumerate(tqdm(val_loader)):
            category = attributes['category'].to(device)
            pred = model(data)
            loss = criterion(pred, category.view(-1))
            val_loss += loss.item()

            # Compute accuracy
            pred_label = torch.argmax(pred, dim=1)
            val_accuracy += torch.mean((pred_label == category.view(-1)).float()).item()

    print('Val loss:', val_loss / len(val_loader))
    print('Val accuracy:', val_accuracy / len(val_loader))

테스트 데이터에서 훈련 된 3D 물체 감지 모델을 평가한다.
test_loader = DataLoader(ModelNet(modelnet_path, categories=categories,
                                  split='test',transform=transform),
                        shuffle=True, batch_size=15)

data, attr = next(iter(test_loader))
data = data.to('cuda')
labels = attr['category'].to('cuda')
preds = model(data)
pred_labels = torch.max(preds, axis=1)[1]

이전 val_loader와 동일한 데이터를 셔플링으로 로드하고, 샘플 배치를 가져온다. 다음으로, 시각화 기능을 사용하여 포인트 클라우드, 레이블 및 예측을 시각화한다. 결과는 색상으로 구분한다. 녹색은 정확하고 빨간색은 부정확하다.
from mpl_toolkits.mplot3d import Axes3D     # unused import necessary to have access to 3d projection # noqa: F401
import matplotlib.pyplot as plt
%matplotlib inline


def visualize_batch(pointclouds, pred_labels, labels, categories):
    batch_size = len(pointclouds)
    fig = plt.figure(figsize=(8, batch_size / 2))

    ncols = 5
    nrows = max(1, batch_size // 5)
    for idx, pc in enumerate(pointclouds):
        label = categories[labels[idx].item()]
        pred = categories[pred_labels[idx]]
        colour = 'g' if label == pred else 'r'
        pc = pc.cpu().numpy()
        ax = fig.add_subplot(nrows, ncols, idx + 1, projection='3d')
        ax.scatter(pc[:, 0], pc[:, 1], pc[:, 2], c=colour, s=2)
        ax.axis('off')
        ax.set_title('GT: {0}\nPred: {1}'.format(label, pred))

    plt.show()
visualize_batch(data, pred_labels, labels, categories)

결과

Jupyter 노트북에 업로드된 전체 코드는 여기에서 찾을 수 있다. .

레퍼런스
상세한 내용은 다음 링크를 참고한다.

2021년 4월 14일 수요일

Torch Points3d 사용 및 개발 방법

이 글은 Torch Points3d 사용 및 개발 방법을 간단히 다룬다. 

텐서플로우 3D가 릴리즈되었지만, 아직 당장 사용하기에는 불완전하다. 이런 이유로 토치에서 제공하는 포인트 클라우드 세그먼테이션, 객체 분류 및 인식 패키지를 사용해 보기로 한다.


파이썬 패키지 설치

PIP 설치는 매우 간단하다. Ubuntu, NVIDIA driver, CUDA, Tensorflow 등 개발환경이 설치되어 있다는 가정하에 다음과 같이 터미널에서 명령 입력한다.

pip install torch
pip install torch-points3d

소스 및 예제 설치
소스 및 예제 설치는 다음 링크 참고해 진행한다.
튜토리얼
튜토리얼 실행은 다음 링크를 참고해 진행한다.
부록: 도커 기반 OpenPCDet 사용

sudo docker run -it -v /path/to/data/on/host:/usr/src/OpenPCDet/data/kitti --rm --gpus all opheliayuan/pcdet:3.0 nvidia-smi


레퍼런스

이 글은 아래 링크를 참고한다.

이 패키지는 다음 기술이 포함되어 있다.
  • PointNet from Charles R. Qi et al.: PointNet: Deep Learning on Point Sets for 3D Classification and Segmentation (CVPR 2017)
  • PointNet++ from Charles from Charles R. Qi et al.: PointNet++: Deep Hierarchical Feature Learning on Point Sets in a Metric Space
  • RSConv from Yongcheng Liu et al.: Relation-Shape Convolutional Neural Network for Point Cloud Analysis (CVPR 2019)
  • RandLA-Net from Qingyong Hu et al.: RandLA-Net: Efficient Semantic Segmentation of Large-Scale Point Clouds
  • PointCNN from Yangyan Li et al.: PointCNN: Convolution On X-Transformed Points (NIPS 2018)
  • KPConv from Hugues Thomas et al.: KPConv: Flexible and Deformable Convolution for Point Clouds (ICCV 2019)
  • MinkowskiEngine from Christopher Choy et al.: 4D Spatio-Temporal ConvNets: Minkowski Convolutional Neural Networks (CVPR19)
  • VoteNet from Charles R. Qi et al.: Deep Hough Voting for 3D Object Detection in Point Clouds (ICCV 19)
  • FCGF from Christopher Choy et al.: Fully Convolutional Geometric Features (ICCV'19)
  • PointGroup from Li Jiang et al.: PointGroup: Dual-Set Point Grouping for 3D Instance Segmentation
  • PPNet (PosPool) from Ze Liu et al.: A Closer Look at Local Aggregation Operators in Point Cloud Analysis (ECCV 2020)
  • TorchSparse from Haotian Tang et al: Searching Efficient 3D Architectures with Sparse Point-Voxel Convolution
  • PVCNN model for semantic segmentation from Zhijian Liu et al:Point-Voxel CNN for Efficient 3D Deep Learning
  • MS-SVConv from Sofiane Horache et al: 3D Point Cloud Registration with Multi-Scale Architecture and Self-supervised Fine-tuning

2021년 4월 13일 화요일

딥러닝 기반 실시간 객체 인식 YOLO v5 설치 및 사용기

이 글은 우분투 20.04기반 YOLO v5 설치 및 사용 방법을 간단히 기술한다. YOLO v5는 PyTorch기반으로 동작하며, 기존 YOLO v3보다 객체 인식 속도 및 품질이 크게 개선되었다. 

YOLO v5 성능

2020년 불과 몇 개월 사이에 YOLO v4, YOLO v5 및 PP-YOLO라는 세 가지 주요 버전의 YOLO가 릴리즈되었다. YOLO v5는 YOLO 개발자가 개발한 것이 아니기에 사람들사이에서 논쟁거리가 있었다. 하지만, 결론적으로 여러가지 성능향상이 있었기에, 많은 사람들이 v5 버전을 사용하고 있다. 참고로, 욜로 버전 역사는 다음과 같다.
  • Joseph Redmon의 YOLO 버전
버전 1: 통합 된 실시간 객체 감지(2016)
버전 2: 더 좋고, 더 빠르고, 더 강력함(2017)
버전 3: 점진적 개선(2018)
  • Joseph Redmon의 컴퓨터 비전 연구 중단 발표(2020.2)
  • Alexey Bochkovskiy의 YOLO 버전
버전 4: Darknet 기반 Tesla V100에서 65FPS의 실시간 속도. COCO 데이터 세트에서 43.5%의 AP값 획득
  • Glenn Jocher의 YOLO 버전(2020.5)
버전 5: Darknet의 포크가 아닌, PyTorch 구현. 모자이크 데이터 확대 및 자동 학습 경계 상자 앵커가 포함됨. Tesla P100에서, 이미지 당 0.007 초 객체 예측. 평균 140 FPS 주장.
YOLO v4 성능

개발환경 설치

다음 순서로 개발 환경을 설치한다.

이제, 텐서플로우나 케라스 예제 코드가 쥬피터 노트북에서 제대로 실행되면 환경 설정 성공한 것이다.
import tensorflow as tf
print(tf.reduce_sum(tf.random.normal([1000, 1000])))

import tensorflow as tf
print("# GPUs Available: ", len(tf.config.experimental.list_physical_devices('GPU')))


YOLO v5 설치
버전5는 원 개발자가 아닌 PyTorch로 YOLO개발했던 개발자가 맡아 진행한 것이다. 그러므로, PyTorch를 사용한다. 이에 대한 상세한 스토리는 여기를 참고한다. 다음을 참고해 욜로 버전5를 설치한다.
이제 YOLO 설치 폴더에서 다음 명령을 입력한다.

다음과 같이 객체 인식 처리가 되면 성공한 것이다.


주요 코드 분석
주요 코드를 분석해 본다. 동작은 다음과 같다. 
import torch.distributed as dist #파이토치 임포트
import torch.nn as nn
...
from models.yolo import Model  # 욜로 모델 임포트

def train(hyp, opt, device, tb_writer=None):
    # 설정
    if rank in [-1, 0]:
        opt.hyp = hyp  # 하이퍼 파라메터 추가
        run_id = torch.load(weights).get('wandb_id') if weights.endswith('.pt') and os.path.isfile(weights) else None
        if wandb_logger.wandb:
            weights, epochs, hyp = opt.weights, opt.epochs, opt.hyp  # WandbLogger might update weights, epochs if resuming

    nc = 1 if opt.single_cls else int(data_dict['nc'])  # 클래스 수
    names = ['item'] if opt.single_cls and len(data_dict['names']) != 1 else data_dict['names']  # class names

    # 모델 정의
    pretrained = weights.endswith('.pt')
    if pretrained:
        with torch_distributed_zero_first(rank):
            attempt_download(weights)  # download if not found locally
        ckpt = torch.load(weights, map_location=device)  # 체크 모델 로드
        model = Model(opt.cfg or ckpt['model'].yaml, ch=3, nc=nc, anchors=hyp.get('anchors')).to(device)  # create
        model.load_state_dict(state_dict, strict=False)  # 모델 로딩
    else:
        model = Model(opt.cfg, ch=3, nc=nc, anchors=hyp.get('anchors')).to(device)  # create
    train_path = data_dict['train']
    test_path = data_dict['val']

    # 최적화
    nbs = 64  # nominal batch size
    accumulate = max(round(nbs / total_batch_size), 1)  # accumulate loss before optimizing
    hyp['weight_decay'] *= total_batch_size * accumulate / nbs  # scale weight_decay

    pg0, pg1, pg2 = [], [], []  # optimizer parameter groups

    if opt.adam:  # 최적화 함수
        optimizer = optim.Adam(pg0, lr=hyp['lr0'], betas=(hyp['momentum'], 0.999))  # adjust beta1 to momentum
    else:
        optimizer = optim.SGD(pg0, lr=hyp['lr0'], momentum=hyp['momentum'], nesterov=True)

    if opt.linear_lr:
        lf = lambda x: (1 - x / (epochs - 1)) * (1.0 - hyp['lrf']) + hyp['lrf']  # linear
    else:
        lf = one_cycle(1, hyp['lrf'], epochs)  # cosine 1->hyp['lrf']
    scheduler = lr_scheduler.LambdaLR(optimizer, lr_lambda=lf)
    # plot_lr_scheduler(optimizer, scheduler, epochs)

    # EMA
    ema = ModelEMA(model) if rank in [-1, 0] else None

    start_epoch, best_fitness = 0, 0.0
    if pretrained:
        # Epochs
        start_epoch = ckpt['epoch'] + 1
        if opt.resume:
            assert start_epoch > 0, '%s training to %g epochs is finished, nothing to resume.' % (weights, epochs)

        del ckpt, state_dict

    # Image sizes
    imgsz, imgsz_test = [check_img_size(x, gs) for x in opt.img_size]  # verify imgsz are gs-multiples

    # 모델 파라메터
    hyp['box'] *= 3. / nl  # scale to layers
    hyp['cls'] *= nc / 80. * 3. / nl  # scale to classes and layers
    hyp['obj'] *= (imgsz / 640) ** 2 * 3. / nl  # scale to image size and layers
    hyp['label_smoothing'] = opt.label_smoothing
    model.nc = nc  # attach number of classes to model
    model.hyp = hyp  # attach hyperparameters to model
    model.gr = 1.0  # iou loss ratio (obj_loss = 1.0 or iou)
    model.class_weights = labels_to_class_weights(dataset.labels, nc).to(device) * nc  # attach class weights
    model.names = names

    for epoch in range(start_epoch, epochs):  # epoch 
        model.train()  # 모델 훈련

        for i, (imgs, targets, paths, _) in pbar:  # 배치 -------------------------------------------------------------
            ni = i + nb * epoch  # number integrated batches (since train start)
            imgs = imgs.to(device, non_blocking=True).float() / 255.0  # uint8 to float32, 0-255 to 0.0-1.0


detect.py 주요 코드는 다음과 같다. 
def detect(save_img=False):
    source, weights, view_img, save_txt, imgsz = opt.source, opt.weights, opt.view_img, opt.save_txt, opt.img_size
    save_img = not opt.nosave and not source.endswith('.txt')  # save inference images
    webcam = source.isnumeric() or source.endswith('.txt') or source.lower().startswith(
        ('rtsp://', 'rtmp://', 'http://', 'https://'))

    # 초기화
    device = select_device(opt.device)
    half = device.type != 'cpu'  # half precision only supported on CUDA

    # 모델 로드
    model = attempt_load(weights, map_location=device)  # load FP32 model
    stride = int(model.stride.max())  # model stride
    imgsz = check_img_size(imgsz, s=stride)  # check img_size

    # 클래스 이름 및 색상 
    names = model.module.names if hasattr(model, 'module') else model.names
    colors = [[random.randint(0, 255) for _ in range(3)] for _ in names]

    # 예측 실행
    if device.type != 'cpu':
        model(torch.zeros(1, 3, imgsz, imgsz).to(device).type_as(next(model.parameters())))  # run once
    t0 = time.time()
    for path, img, im0s, vid_cap in dataset:
        img = torch.from_numpy(img).to(device)
        img = img.half() if half else img.float()  # uint8 to fp16/32
        img /= 255.0  # 0 - 255 to 0.0 - 1.0
        if img.ndimension() == 3:
            img = img.unsqueeze(0)

        # Inference
        t1 = time_synchronized()
        pred = model(img, augment=opt.augment)[0]

        # Apply Classifier
        if classify:
            pred = apply_classifier(pred, modelc, img, im0s)  # 객체 인식 예측

        # 객체 탐지 프로세스
        for i, det in enumerate(pred):  # detections per image
            p = Path(p)  # to Path
            save_path = str(save_dir / p.name)  # img.jpg
            gn = torch.tensor(im0.shape)[[1, 0, 1, 0]]  # normalization gain whwh
            if len(det):
                # Rescale boxes from img_size to im0 size
                det[:, :4] = scale_coords(img.shape[2:], det[:, :4], im0.shape).round()

            # Stream results
            if view_img:
                cv2.imshow(str(p), im0)
                cv2.waitKey(1)  # 1 millisecond

if __name__ == '__main__':
    parser = argparse.ArgumentParser()  # 객체 탐지 예측 파라메터 정의
    parser.add_argument('--weights', nargs='+', type=str, default='yolov5s.pt', help='model.pt path(s)')
    parser.add_argument('--source', type=str, default='data/images', help='source')  # file/folder, 0 for webcam
    parser.add_argument('--img-size', type=int, default=640, help='inference size (pixels)')
    parser.add_argument('--conf-thres', type=float, default=0.25, help='object confidence threshold')
    parser.add_argument('--iou-thres', type=float, default=0.45, help='IOU threshold for NMS')
    parser.add_argument('--device', default='', help='cuda device, i.e. 0 or 0,1,2,3 or cpu')
    parser.add_argument('--view-img', action='store_true', help='display results')
    parser.add_argument('--save-txt', action='store_true', help='save results to *.txt')
    parser.add_argument('--save-conf', action='store_true', help='save confidences in --save-txt labels')
    parser.add_argument('--nosave', action='store_true', help='do not save images/videos')
    parser.add_argument('--classes', nargs='+', type=int, help='filter by class: --class 0, or --class 0 2 3')
    parser.add_argument('--agnostic-nms', action='store_true', help='class-agnostic NMS')
    parser.add_argument('--augment', action='store_true', help='augmented inference')
    parser.add_argument('--update', action='store_true', help='update all models')
    parser.add_argument('--project', default='runs/detect', help='save results to project/name')
    parser.add_argument('--name', default='exp', help='save results to project/name')
    parser.add_argument('--exist-ok', action='store_true', help='existing project/name ok, do not increment')
    opt = parser.parse_args()
    print(opt)
    check_requirements(exclude=('pycocotools', 'thop'))

    with torch.no_grad():
        if opt.update:  # update all models (to fix SourceChangeWarning)
            for opt.weights in ['yolov5s.pt', 'yolov5m.pt', 'yolov5l.pt', 'yolov5x.pt']:  # 가중치에 따른 예측
                detect()
                strip_optimizer(opt.weights)
        else:
            detect()

마무리
YOLO v5는 실행 속도 측면에서 분명한 이점이 있다. YOLO v5 모델은 작은 개체를 감지하는 데 더 나은 성능을 보이면서, 빠르게 실행된다. 다음은 다른 딥러닝 모델과 성능 차이를 나타낸다.


간단한 AWS EC2 클라우드 서비스 사용, 터미널 접속 및 웹서버 개발

이 글은 간단한 AWS EC2 클라우드 서비스 사용 방법을 정리한것이다. 이 글은 아마존 AWS EC2 클라우드 서비스 사용, 터미널 접속 및 웹서버 개발을 보여준다.

AWS 서비스 신청 및 인스턴스 생성

AWS에서 EC2 서비스 신청한 후, 서비스에서 적당한 인스턴스를 선택하여 생성한다. 

이런 모든 작업은 다음 AWS 데쉬보드의 각 메뉴에서 제공해준다. 


데쉬보드 메뉴 리스트(왼쪽)에서 인스턴스 메뉴 선택하고, 아래 화면에서 인스턴스 시작 버튼을 선택한다.

다음과 같이 이미 저장된 인스턴스 이미지들이 리스트된다. 이 글에서는 우분투 18.04 이미지를 인스턴스로 생성한다. 생성 시 순서는 화면을 읽어보며 따라가면 된다. 인스턴스 생성시 보안키를 생성할 수 있다. 보안키 파일 pem파일을 생성하고 다운로드받아 보관한다.

인스턴스 실행하면, 자동으로 해당 이미지가 아마존 서버에 로딩되고, 운영체제가 실행된다. 네트워크는 자동으로 아마존에서 제공되는 공개IP와 연결된다. 

터미널 접속 및 패키지 설치

실행 후, 인스턴스에 관련 패키지를 설치하기 위하여, 명령창을 관리자 모드로 실행한다. 명령창에서 ssh 터미널을 다음과 같이 실행한다. 

ssh -i "???.pem" ubuntu@ec2-##-##-##-###.ap-northeast-2.compute.amazonaws.com

???부분은 인스턴스 시작 시 생성되는 보안키 파일이다. ###은 해당 인스턴스의 공개 DNS주소이다. 이 주소는 다음과 같이 인스턴스 데쉬보드의 인스턴스에 연결 메뉴에서 얻을 수 있다. pem은 인스턴스 생성 시 다운로드받은 보안키 파일명 경로이다. pem 설정 뒤에 있는 부분은 인스턴스 접속 DNS 공개 주소이다.  

실행하면 다음과 같이 ssh 터미널에 접속된다. 혹시, "Permissions for 'private-key' are too open" 에러 발생 시 pem파일 속성에서 불필요한 파생 계정을 삭제하고 실행한다(상세 내용 참고).


이제 원격으로 접속된 아마존 서버에 기본적인 node.js 등 설치하여 사용한다(설치 참고).
sudo apt-get install npm

간단한 웹서버 코딩 및 실행
다음과 같이 express를 설치한다. 
npm install express

다음과 같이 js 파일을 생성한다. 
nano server.js

다음과 같이 코딩한다.
const express = require('express')
const app = express()
const port = 3000

app.get('/', (req, res) => {
  res.send('Hello World!')
})

app.listen(port, () => {
  console.log(`Example app listening at http://localhost:${port}`)
})

3000번 포트에서 접속 가능하도록, AWS 인스턴스 데쉬보드 보안 탭에서 보안그룹 링크를 클릭하여, 방화벽의 인바우드 규칙을 다음과 같이 설정한다(참고. 아마존 CORS 설정).

이제 노드 서버를 실행해보고, 외부 네트워크에서 접속되는 지 확인한다(참고. 터미널 종료 후 서비스 계속 실행 방법).
screen
node server.js &

다음과 같이 각자 공개 DNS 주소에 접속되면 성공한 것이다.

마무리
AWS 서비스는 서버, 운영체제, 네트워크 설치 노가다를 크게 줄여준다. 이런 것들은 해본 사람도 설치에만 몇일 이상이 걸린다. AWS는 가입 후 AWS에서 제공하는 콘솔 데쉬보드에서 몇번의 클릭으로 웹서버, 데이터베이스서버, 딥러닝 패키지, IoT 패키지 등 이미지를 서버에 업로드해 실행시킨다. AWS의 가장 큰 단점은 비싼 비용과, AWS에 너무 특화된 서비스이다. 특히, 데이터 저장소, 네트워크 밴드폭 사용 비용 등이 비싼데, 아무 생각없이 신청했다가는 요금 포탄 맞을 수 있으니 주의가 필요하다.


2021년 4월 10일 토요일

가장 쉬운 Ubuntu 18.04 NVIDIA driver, CUDA and Tensorflow installation

이 글은 Ubuntu 18.04 NVIDIA driver, CUDA and Tensorflow 설치 방법에 대한 것을 간략히 정리한 것이다. 그동안 18.04 버전 설치 테크트리가 약간 변경되어 다시 재정리한다. 다만, 딥러닝 등 최신 라이브러리 사용 목적이라면 우분투 20.04를 권장한다.
  • Ubuntu 18.04 설치 이미지 부팅 가능 USB 만들기
  • Install Ubuntu 18.04. 만약, 화면이 안보이거나 멈추면 GRUB에서 NOMODESET 추가 후 설치 진행
  • Booting Ubuntu
  • Ubuntu에서 Terminal을 열어 아래 명령어 입력 실행함 
    • ubuntu-drivers devices
    • sudo ubuntu-drivers autoinstall
    • reboot
    • nvidia-smi
  • Install CUDA 10.2 and 11.2 or 11.0. 주의: 이 단계에서 GPU 드라이버 재 설치하면 안됨.
  • Install cuDNN SDK 8.0.4
  • Install Tensorflow
  • Install Keras
  • Install Jupyter Notebook
  • reboot
이제, 다음과 같이 딥러닝 예제들이 정상 실행되면 성공한 것이다.
결과

참고로, Ubuntu 18.04 현재 버전은 ROS 설치를 완벽히 지원하지 않는다. 디펜던시 에러가 발생하므로 주의한다.

2021년 4월 8일 목요일

대체불가능 토큰 NFT 개념과 직접 만들어보기

이 글은 대체불가능 토큰 NFT 만드는 방법을 간략히 설명한다. 

최근, 언론에 작가 비플이 NFT 기술을 접목해 만든 이미지 파일 한 점이 2021.11 미국 뉴욕 크리스티 경매에서 약 780억원에 낙찰된것으로 알려지면서 NFT에 대한 관심이 많아지고 있다. 비플 말고도, 트레버 존슨의 '비트코인 천라'라는 작품들 중 하나는 428만원에 거래되는 등 거래량도 늘어나고 있다. 엘론 머스크의 아내이자 가수인 그라임스도 대체불가능한 토큰(NFT)으로 20분 만에 65억을 벌었다. 

이 글은 NFT 개념과 만드는 방법을 간략히 이야기한다.

Everydays: The first 5000 days (NFT)
The Bitcoin Angel

머리말
대체 불가능한 토큰 (NFT) 은 독립형 암호화 토큰 유형이다. 대체 불가능한 토큰은 검증 가능한 디지털 컨텐츠 희소성을 보장하는 데 사용될 수 있다. 

비트코인은 1BT가 동일한 가치를 보장해, 코인 간 서로 대체가 가능한 토큰인 반면, NFT는 각 토큰이 서로 다른 가치를 저장할 수 있다. 서로 다른 가치를 토큰이 가지므로, 토큰끼리는 서로 대체 불가능하다. NFT는 1 토큰 당 가치가 모두 다르다. 

NFT도 물론 블록체인속에 저장 및 기록되어, 소유권 확인 및 추적, 거래 내역 등을 지원한다. NFT는 어떤 종류의 고유한 항목이 필요한 산업에 유용 할 수 있다. 예를 들어 예술 작품이나 사용자의 고유한 업적을 식별하는 데 사용된다. 

다른 지갑에 두 개의 비트 코인이 있다면 완전히 동일하다. 두 개의 NFT는 내부 값이나 토큰 특이성에서 개별적으로 서로 같지 않다. 구별은 대체 불가능한 토큰에 할당된 해시값으로 처리한다. 

블록 체인 세계에 구축되고있는 금융 시스템은 큰 단점이 있다. 예를 들어, 부동산 자산은 산업 요구 사항에 따라 설정된 자산별 복잡성 및 보안 요구사항으로 인해 블록 체인에서 디지털 정보로 완전히 표현할 수 없는 경우가 많다. 기존 자금 조달 프로세스(IPO), 블록 체인 산업(ICO, IEO, STO)에 대해서도 마찬가지이다. 

현재 시가 총액은 아직 매우 적다. 자산에 대한 현물 가격이 부족하기 때문에, 암호 화폐 시장에 비해 측정하기가 더 어렵다. 2차 거래량(peer-to-peer)을 기준으로 월별 수치는 $2-3백만에 가깝다. 2018년 크립토 키티(CryptoKitties)의 광고 이후 NFT와 상호 작용하는 사용자의 수는 느리지만 지속적으로 증가하고 있다.

Standard를 통해 개발자는 자산별로 동작을 프로그래밍하고, NFT를 기반으로 하는 자산의 기능과 상호작용하는 방법에 대한 자세한 지침을 설정할 수 있다.
NFT 개발방법

이런 표준 및 코딩 없이도 NFT 생성을 지원하는 서비스를 사용해, 자신의 컨텐츠를 NFT화할 수 있다. 다음은 NFT 지원 서비스 웹사이트이다.
  • Opensea: 암호화된 디지털 아이템 판매 마켓
  • Mintable: 블록체인 아이템 판매 마켓
  • SuperRare: 디지털 예술품 소장 및 거래 

NFT 표준 개념
이 표준은 CryptoKitties에서 처음 사용되었다. ERC-721은 대체 불가능한 디지털 자산 생성을위한 최초의 규약이다. 언급된 표준의 가장 큰 이점은 개발자가 간단히 OpenZeppelin도구를 통해 ERC-721호환 계약을 작성할 수 있다는 것이다. 이 규약은 계정 간의 가치를 교환하는 다음과 같은 인터페이스를 구현해야 한다.

    function balanceOf(address _owner) external view returns (uint256);
    function ownerOf(uint256 _tokenId) external view returns (address);
    function safeTransferFrom(address _from, address _to, uint256 _tokenId, bytes data) external payable;
    function safeTransferFrom(address _from, address _to, uint256 _tokenId) external payable;
    function transferFrom(address _from, address _to, uint256 _tokenId) external payable;
    function approve(address _approved, uint256 _tokenId) external payable;
    function setApprovalForAll(address _operator, bool _approved) external;
    function getApproved(uint256 _tokenId) external view returns (address);
    function isApprovedForAll(address _owner, address _operator) external view returns (bool);

ERC-721은 transferFrom 메소드를 사용하여 이러한 자산을 전송하는 방법도 제공한다.
여기에서 ERC-721 에 대한 자세한 내용 (기술 사양 포함)을 확인할 수 있다.

ERC-1155
ERC-1155를 개발 한 Enjin 팀은 NFT 에 반 대체성에 대한 아이디어를 가져 왔다. 표준은 단일 자산이 아닌 여러 자산 그룹을 나타낼 수 있다.  
여기에서 ERC-1155 에 대한 자세한 내용을 확인할 수 있다 .

Non-Ethereum Standards
블록 체인 중 하나인 FLOW는 NFT 프로젝트에 개방되어 있으며 이미 NBA , UFC 및 기타 유명 기업과 제휴하여 이러한 브랜드의 팬들을 위한 공동 독점 NFT 아이템을 개발했다. 여기에서 FLOW 블록 체인으로 NFT를 만드는 방법에 대해 자세히 알아볼 수 있다 .

직접 만들어보는 NFT
원래는 NFT를 만들기 위해서, 이더리움 가스(GAS)나 이더(ETH)를 구입해 비용을 지불해야 한다. 하지만, Mintable에 NFT를 생성하면, 가스를 지불하지 않고도 작업을 시작할 수 있다. 

전체 NFT 개발 순서는 다음과 같다.

전자지갑 개설(은행계좌 개설) - 지갑 연결 및 생성 - 판매 아이템 등록 - 아이템 판매

다음과 같이 서비스 무료 계정을 생성한다. 이메일 주소로 전송된 인증 코드를 입력한다.

이제, MetaMask 지갑을 만들자. 크롬에서 여기를 클릭해, 브라우저 확장을 설치한다.

새로운 MetaMask 지갑을 시작한다.

지갑을 설정하려면 비밀번호를 제출해야한다. 그 답례로 12 개의 무작위 단어 목록 인 "시드 문구"를 받게된다. 어딘가에 적어 둔다. 이후, 다음을 클릭해, 해당 시드 문구를 확인해야 한다. 통과하면 다음 메시지를 만나게 된다.

그리고, 보유한 이더(ETH)를 확인할 수 있다.

이제, Mintable로 돌아가서“Mint an item”을 클릭한다. 

지갑에 NFT가 이미 존재하는지 (존재하지 않음) 또는 새 지갑을 생성하는지 (현재 존재 함)를 선택하라는 메시지가 표시된다. 

Mintable은 기본적으로 가스없는 NFT로 설정된다. 여기서 원하는 것을 업로드 할 수 있으며, 판매 또는 양도 될때까지 블록 체인에 들어 가지 않는다(물론, 수수료가 발생하지 않는다). 만약, 예전 방식으로 작업을 수행하려면 슬라이더를 클릭하고, 고급 모드로 이동하여 트랜잭션 모델을 선택할 수 있다(대신 수수료 지급해야 함).

다음과 같이 MetaMask와 지갑을 연결한다.

이제, 다음과 같이, 자신의 컨텐츠를 NFT로 생성할 수 있는 아이템 작성 및 판매 화면이 보일것이다. 

이제, 가치가 있는 자신의 컨텐츠를 업로드하고, 개별 파일이 있다면 추가하면 된다. 그 결과 다음과 같이 대체불가능한 토큰으로 처리된 작품이 등록된다. 여기서는 강선우가 작업 디자인한 The Beatles 패러디 작품을 등록해 보았다. 그 결과는 다음과 같다.
마무리
NFT의 모든 규약을 마스터하고, NFT를 만들수도 있지만, 그렇지 않고, 이를 지원하는 서비스를 이용해 만들 수도 있다. NFT는 아직 초기 단계이므로, 여러가지 이슈가 있다. NFT를 판매할 때는 비용 구조를 완벽히 이해해야 한다. 판매 시 가스 수수료, 거래 수수료 등을 지급해야 한다. 이런 부분을 이해하지 않고, 진행하면 손해를 볼 수도 있다. 

현재 NFT로 팔리는 것은 상상을 초월한다. TZCOLORS는 색상도 판매하고 있는 데, 1111XTZ는 한화 500만원에 팔리기도 했다. 앞으로 NFT는 어느 정도로 성장할지는 확실치 않지만, 사람들이 많은 관심을 가지리라는 것은 예상할 수 있다.

레퍼런스