블록체인 소개 - (4) 스마트 컨트랙트(Smart Contract)

|

스마트 컨트랙트

블록체인을 4차 산업 혁명의 대표 기술이라고 말하는 이유에는 블록체인의 핵심 기능인 ‘스마트 컨트랙트(Smart Contract)’ 때문일 것입니다. ‘똑똑한 계약’이라고도 번역하는 스마트 컨트랙트가 과연 어떤 기술인지 살짝만 포스팅해보도록 하겠습니다.


스마트 컨트랙트의 개념

우리 주위에서 흔히 볼 수 있는 부동산 계약을 생각해봅시다.

부동산 계약은 보통 집을 파는 매도자, 집을 구매하는 매수자, 그리고 중간에서 계약을 성사시켜주고 관리해주는 중개자로 구성되어 있습니다. 정해진 날짜에 계약을 하고 계약금을 걸고, 정해진 날짜에 중도금, 잔금 등을 치르면서 집 문서를 거래합니다. 스마트 컨트랙트도 비슷합니다. 부동산 거래에서는 보통 부동산 중개업자를 포함해서 계약을 진행하지만, 스마트 컨트랙트는 중개인 없이 자동으로 거래를 성사시켜줍니다.

즉, 중개자없이 계약 당사자들끼리 자동으로 거래를 할 수 있게 해주는 것이 스마트 컨트랙트입니다.

사실 별 것이 없습니다. 스마트 컨트랙트 개념은 오래된 용어입니다. 1996년 Nick Szabo에 의해 제안된 용어이고, 지금도 이미 PC나 인터넷을 통해 제공되고 있는 서비스입니다.


스마트 컨트랙트 예시

Image

위 이미지는 (블록체인과 무관한) 아주 기본적인 스마트 컨트랙트 예시입니다. 계약서 내용을 보면 계약 내용, 당사자들 정보, 금액, 보증금 등이 있습니다. 보증금은 부동산 거래에서 계약금과 같은 역할을 하는 금액입니다. 계약 미체결시 보증금을 못 돌려받도록 해서 계약의 강제성을 갖도록 하고 있습니다.


스마트 컨트랙트의 장점

스마트 컨트랙트의 가장 큰 장점은 중개인이 없다는 점입니다. 중개인이 없다보니 비용 절감 효과가 아주 큽니다.

  • 빠르고 Realtime에 가깝다.
  • 정확도가 높다. (사람에 의해 실수하는 부분이 없다.)
  • 중개자의 수를 없애거나 줄일 수 있다.
  • 비용이 절감된다.


스마트 컨트랙트 활용 사례

스마트 컨트랙트는 블록체인이 나타나기 전부터 다양한 형태로 적용되어 왔습니다. 예를 들어 불법 복제를 막는 DRM은 스마트 컨트랙트의 초기 컨셉이라고 볼 수 있습니다. 불법 복제를 막음으로써 계약 위반을 강제적으로 방지하는 개념입니다.

옥션이나 지마켓 등 온라인 쇼핑몰에서 상품을 구매하는 것도 스마트 컨트랙트의 일종입니다. 각 마켓 서비스에서는 소비자가 금액을 지불하면 상품을 보내주거나 상품 구매 내역을 증명해줍니다.

신용 카드로 자동차를 구매했다가 구매자가 할부금을 갚지 못할 경우 자동으로 자동차 문이 안 열리게 된다거나, 할부금을 갚지 못한 전자 제품이 망가지도록 Kill Switch를 적용한 것도 스마트 컨트랙트입니다.


블록체인과 스마트 컨트랙트

블록체인에서의 스마트 컨트랙트도 위 스마트 컨트랙트와 크게 다르지 않습니다. 다만 기존에는 중앙 서버에서 계약을 관리하고 증명해야 했다면, 블록체인에서는 분산 장부를 통해 네트워크에 참여한 모든 사람들이 계약을 증명한다는 점만 다릅니다.

현실 세계의 계약이든 스마트 컨트랙트든 모두 ‘조건’과 ‘실행’으로 이루어져 있습니다. 예를 들어 부동산 거래나 물건 거래는 ‘돈을 입금하면’이라는 조건과 조건이 만족되었을 때, ‘집 문서를 전달한다’라는 실행 부분으로 구성되어 있습니다.

블록체인에서도 마찬가지입니다. 어떤 조건이 만족지면 무엇인가를 실행하도록 블록체인내에 코드로 기록할 수 있습니다. 스크립트로 작성되어질 수 있으며, 블록체인에 기록되어 네트워크의 모든 노드들이 해당 계약을 확인하고 증명합니다. 계약의 강제성을 위해 두 계약자 모두에게 일정 금액의 보증금을 입력하기도 합니다. 게약 조건이 만족되면 블록체인내에 스크립트로 작성한 실행 내용이 자동으로 이행되어집니다.

비트코인같은 경우는 Contract Code라고 부르는 아주 작은 스크립트 정도를 작성가능하며(보통은 비트코인은 스마트 컨트랙트 기능이 없다라고도 많이 표현합니다.), 이더리움 같은 경우는 스마트 컨트랙트를 위해 Solidity라는 스크립트 언어를 제공하고 있습니다. 프로그래밍 언어이다보니 코딩하듯이 스마트 컨트랙트를 작성할 수 있습니다. 프라이빗 블록체인들의 경우는 대부분 스마트 컨트랙트 기능을 제공하고 있습니다. IBM 주도하의 하이퍼레저(Hyperledger)같은 경우는 Chaincode라는 이름으로 스마트 컨트랙트를 제공하고 있습니다.

스마트 컨트랙트를 이용하면 다음과 같은 일들을 자동으로 할 수 있습니다.

  • 정해진 금액을 입금하면, 영화 1시간 스트리밍 이용권을 제공
  • 전자 장비를 보증금을 맡기면서 빌리고 사용한 시간만큼만 제하고 다시 돌려받는 서비스

프로그래밍 언어처럼 표현되다보니 조건에 돈이나 금액이 들어가지 않더라도 다음과 같은 예시도 가능합니다.

  • 내일 날씨가 맑으면, 아침 6시에 깨워저

물론, 위 조건은 블록체인의 스마트 컨트랙트가 해결하지 못하는 나쁜 예제(Bad case)이긴 하지만 그만큼 다양하게 계약 코드를 작성할 수 있다는 의미입니다.


스마트 컨트랙트가 만능은 아님

사실 이 부분은 이번 포스팅에서 적을 내용은 아니지만 위에서 이상한 예제를 하나 들었기에 살짝 언급을 해봅니다.

‘내일 날씨가 맑으면, 아침 6시에 깨워줘’와 같은 계약은 ‘내일 날씨가 맑으면’이라는 조건이 너무 모호합니다. 블록체인은 합의 기반이다보니 모든 노드들의 날씨 정보가 같지 않으면 합의가 될 수가 없습니다. 물론, ‘내일 기상청에서 발표하는 서울 강남 지역의 일기 예보가 맑음이라고 뜨면’과 같이 구체적이고 객관적인 조건으로 이를 해결할 수는 있겠지만, 또다른 조건이 누락될 수도 있고 항상 모든 조건을 커버할 수는 없기 때문에 스마트 컨트랙트를 무조건 적용하기는 어렵습니다.

또한, ‘내가 농협 계좌로 100만원을 입금하면 비트코인으로 1BTC를 나에게 전송해줘’와 같은 계약문도 블록체인만으로 해결하기는 쉽지 않은 예제입니다. 농협 계좌로 100만원을 입금하는 일은 블록체인 외부의 작업이며, 송금의 결과도 블록체인 외부에서만 확인가능합니다. 즉 블록체인 내의 노드들이 해당 조건을 확인할 수도 없으며, 설사 농협에서 해당 기록을 조회할 수 있는 API를 제공한다고 하더라도 모든 노드에서 그 결과 확인을 위해 API 호출을 할 수도 없는 일입니다.

Keras - History 기능 사용하기

|

Keras 학습 이력 기능

Keras에서는 모델 학습을 위해 fit() 함수를 사용합니다. 이 때, 리턴값으로 학습 이력(History) 정보를 리턴합니다. 여기에는 다음과 같은 항목들이 포함되어 있습니다.

아래 항목들은 매 epoch 마다의 값들이 저장되어 있습니다.

  • loss : 훈련 손실값
  • acc : 훈련 정확도
  • val_loss : 검증 손실값
  • val_acc : 검증 정확도


학습 이력 확인

학습이 끝난 후 다음 코드로 쉽게 확인이 가능합니다.

hist = model.fit(X_train, Y_train, validation_data=(X_validation, Y_validation),
          epochs=30, batch_size=500)

print(hist.history['loss'])
print(hist.history['acc'])
print(hist.history['val_loss'])
print(hist.history['val_acc'])


학습 이력 그래프로 확인

matplotlibpyplot를 이용해서 각 결과를 그래프로 조회할 수 있습니다.

from keras.datasets import mnist
from keras.utils import np_utils
from keras.models import Sequential
from keras.layers import Dense

(X_train, Y_train), (X_validation, Y_validation) = mnist.load_data()

X_train = X_train.reshape(X_train.shape[0], 784).astype('float64') / 255
X_validation = X_validation.reshape(X_validation.shape[0], 784).astype('float64') / 255

Y_train = np_utils.to_categorical(Y_train, 10)
Y_validation = np_utils.to_categorical(Y_validation, 10)

model = Sequential()
model.add(Dense(512, input_dim=784, activation='relu'))
model.add(Dense(10, activation='softmax'))

model.compile(loss='categorical_crossentropy', optimizer='adam',
              metrics=['accuracy'])

hist = model.fit(X_train, Y_train, validation_data=(X_validation, Y_validation),
          epochs=30, batch_size=500)

print('\nAccuracy: {:.4f}'.format(model.evaluate(X_validation, Y_validation)[1]))


import matplotlib.pyplot as plt

fig, loss_ax = plt.subplots()
acc_ax = loss_ax.twinx()

loss_ax.plot(hist.history['loss'], 'y', label='train loss')
loss_ax.plot(hist.history['val_loss'], 'r', label='val loss')
loss_ax.set_xlabel('epoch')
loss_ax.set_ylabel('loss')
loss_ax.legend(loc='upper left')

acc_ax.plot(hist.history['acc'], 'b', label='train acc')
acc_ax.plot(hist.history['val_acc'], 'g', label='val acc')
acc_ax.set_ylabel('accuracy')
acc_ax.legend(loc='upper left')

plt.show()

Image

위와 같이 그래프로 각각의 항목들의 추이를 확인할 수 있습니다. 사실 위 경우는 학습 속도 조절을 위해 epochs 값과 batch_size 값을 임의로 조정해놓아서 과적합이 발생하는 시점을 확인할 수 없지만, 보통 epochs 값이 지나치게 클 수록 과적합이 발생하여 실제 검증 정확도 val_acc는 점점 하락하는 것을 확인할 수 있습니다.

Keras - Model.fit 옵션

|

Keras 학습 함수 fit()

Keras에서는 모델 학습을 위해 fit() 함수를 사용합니다.

model.fit(X, Y, batch_size=100, epochs=10)
  • X : 입력 데이터
  • Y : 결과(Label 값) 데이터
  • batch_size : 한 번에 학습할 때 사용하는 데이터 개수
  • epochs : 학습 데이터 반복 횟수


batch_size

batch_size는 학습할 때 문제를 몇 번 풀고 정답을 확인하는 지를 결정하는 값입니다. 만약 batch_size10이라면, 총 10개의 데이터를 학습한 다음 가중치를 1번 갱신하게 됩니다.

100문제를 풀고 가중치를 갱신하는 것과, 1문제를 풀고 가중치를 갱신하는 것은 학습 결과에 큰 차이가 있습니다. 사람이 문제집으로 공부를 하는 것과 비슷합니다. 100문제를 풀고 한 번에 채점하면서 학습하는 것과, 1문제를 풀고 채점한 다음 다음 문제를 푸는 것과 비슷합니다.

batch_size 값이 크면 클수록 여러 데이터를 기억하고 있어야 하기에 메모리가 커야 합니다. 그대신 학습 시간이 빨라집니다. batch_size 값이 작으면 학습은 꼼꼼하게 이루어질 수 있지만 학습 시간이 많이 걸립니다.


epochs

학습 데이터 전체셋을 몇 번 학습하는지를 의미합니다. 동일한 학습 데이터라고 하더라도 여러 번 학습할 수록 학습 효과는 커집니다. 하지만, 너무 많이 했을 경우 모델의 가중치가 학습 데이터에 지나치게 최적화되는 과적합(Overfitting) 현상이 발생합니다.

다양한 학습 데이터를 이용해서 학습하는 것이 제일 좋지만, 현실적으로 학습 데이터를 다량으로 획득하는 것이 어렵기 떄문에 동일 데이터를 반복해서 학습하는 것은 피하기 어렵습니다. 따라서 과적합이 발생하지 않는 적절한 학습 횟수를 찾는 것도 딥러닝이 가진 숙제 중 하나입니다.

Keras - CNN(Convolution Neural Network) 예제

|

CNN on Keras

Keras에서 CNN을 적용한 예제 코드입니다. MNIST 손글씨 데이터를 이용했으며, GPU 가속이 없는 상태에서는 수행 속도가 무척 느립니다.


예제 코드

from keras.datasets import mnist
from keras.utils import np_utils
from keras.models import Sequential
from keras.layers import Dense, Conv2D, MaxPooling2D, Dropout, Flatten
from keras.callbacks import ModelCheckpoint, EarlyStopping

import matplotlib.pyplot as plt
import os
import numpy

MODEL_SAVE_FOLDER_PATH = './model/'

if not os.path.exists(MODEL_SAVE_FOLDER_PATH):
  os.mkdir(MODEL_SAVE_FOLDER_PATH)

model_path = MODEL_SAVE_FOLDER_PATH + 'mnist-' + '{epoch:02d}-{val_loss:.4f}.hdf5'

cb_checkpoint = ModelCheckpoint(filepath=model_path, monitor='val_loss',
                                verbose=1, save_best_only=True)

cb_early_stopping = EarlyStopping(monitor='val_loss', patience=10)

(X_train, Y_train), (X_validation, Y_validation) = mnist.load_data()

X_train = X_train.reshape(X_train.shape[0], 28, 28, 1).astype('float32') / 255
X_validation = X_validation.reshape(X_validation.shape[0], 28, 28, 1).astype('float32') / 255

Y_train = np_utils.to_categorical(Y_train, 10)
Y_validation = np_utils.to_categorical(Y_validation, 10)

model = Sequential()
model.add(Conv2D(32, kernel_size=(3, 3), input_shape=(28, 28, 1), activation='relu'))
model.add(Conv2D(64, (3, 3), activation='relu'))
model.add(MaxPooling2D(pool_size=2))
model.add(Dropout(0.25))
model.add(Flatten())
model.add(Dense(128, activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(10, activation='softmax'))

model.compile(loss='categorical_crossentropy',
              optimizer='adam',
              metrics=['accuracy'])

history = model.fit(X_train, Y_train,
                    validation_data=(X_validation, Y_validation),
                    epochs=3, batch_size=200, verbose=0,
                    callbacks=[cb_checkpoint, cb_early_stopping])

print('\nAccuracy: {:.4f}'.format(model.evaluate(X_validation, Y_validation)[1]))

y_vloss = history.history['val_loss']
y_loss = history.history['loss']

x_len = numpy.arange(len(y_loss))
plt.plot(x_len, y_loss, marker='.', c='blue', label="Train-set Loss")
plt.plot(x_len, y_vloss, marker='.', c='red', label="Validation-set Loss")

plt.legend(loc='upper right')
plt.grid()
plt.xlabel('epoch')
plt.ylabel('loss')
plt.show()


예제 코드 설명

Keras에서 Convolution Layer를 추가하는 코드는 다음과 같습니다.

model.add(Conv2D(32, kernel_size=(3, 3), input_shape=(28, 28, 1), activation='relu'))

Conv2D() 함수의 인자로

  • 첫 번째 숫자인 32는 32개의 필터를 적용하겠다는 의미입니다.
  • kernel_size는 필터의 크기를 의미합니다.
  • input_shape는 (행, 열, 색상)을 의미합니다. 흑백의 경우 1의 값을 가집니다. RGB의 경우 3의 값을 가집니다.


model.add(MaxPooling2D(pool_size=2))

MaxPooling2D는 풀링 기법 중 가장 많이 사용하는 맥스 풀링을 적용하는 함수입니다. 맥스 풀링은 정해진 영역 안에서 가장 큰 값만 남기고 나머지는 버리는 방식입니다. pool_size는 풀링 윈도우 크기이며 2의 값은 전체 크기를 절반으로 줄입니다.

model.add(Dropout(0.25))

Dropout()는 특정 노드에 학습이 지나치게 몰리는 것을 방지하기 위해 랜덤하게 일부 노드를 꺼주는 역할을 합니다. Dropout을 통해 과적합을 조금 더 효과적으로 회피할 수 있습니다.

model.add(Flatten())

지금까지 작업했던 이미지는 2차원 배열인데, Flattern() 함수를 통해 1차원 배열로 바꿔줄 수 있습니다.


실행 결과

Image

실행 결과입니다. 현재 사용하고 있는 노트PC의 GPU 성능이 낮아 GPU 가속을 받을 수 없는 상황이라 epoch 값을 3으로 했더니 위와 같은 결과가 나왔습니다. 환경이 좋은데서는 epoch 값을 더 늘려서 좀 더 성능이 좋은 모델을 얻을 수 있을 것입니다.

CNN(Convolution Neural Network)

|

여기를 보면 좀 더 자세한 내용을 볼 수 있습니다.

CNN

CNN(Convoluion Neural Network)은 딥러닝에서 이미지 인식의 꽃이라고 불릴 정도로 강력한 성능을 가진 기법입니다.

CNN은 입력된 이미지에서 특징을 좀 더 잘 뽑아내기 위해서 그 위에 필터(마스크, 윈도우, 커널 등으로 불려짐)를 입히는 기법입니다. 그 이후 풀링(Pooling)이라고 불리우는 다운 샘플링(Down-sampling) 과정을 거쳐 신경망에 데이터를 입력합니다.

Image


이미지 인식

사람은 이미지를 눈으로 보고 바로 인식을 할 수 있지만, 컴퓨터는 이미지를 각 픽셀에 입력되어 있는 숫자값들의 배열로 인식합니다.

Image


필터 사용

아래 그림처럼 포토샵 등에서 다양한 필터를 적용해서 이미지를 변형하는 것을 보신 경험이 있을겁니다. 어떤 필터는 이미지를 더 부드럽게 만들기도 하고, 어떤 필터는 더 날카롭게, 경계면을 뚜렷하게 만드는 필터들도 있습니다.

Image

CNN에서도 이미지 인식을 보다 잘할 수 있도록 필터를 사용합니다.

Image

원본 이미지와 필터간 합성곱(Convolution) 연산을 통해 새로운 Layer를 생성하고, 이를 Convolution Layer라고 합니다. 이러한 필터를 여러 개 사용할 경우 여러 개의 Convolution이 만들어집니다.


필터 사용 예제

필터를 이용해서 원본 이미지와 Convolution 연산을 하는 예제를 살펴보겠습니다.

Image

위 이미지와 같은 필터가 있다고 가정합니다.

Image

그리고 위 이미지에서 노란색 박스 부분을 필터로 검출하게 되면 아래와 같은 결과가 나오게 됩니다.

Image

위 이미지의 아랫 부분에 Multiplication and Summation 결과를 보면 상당히 큰 크기의 값이 도출되는 것을 알 수 있습니다.

Image

만약 위 그림처럼 필터와 비슷한 부분이 거의 없는 영역에 Convolution 계산을 하면 아랫쪽의 계산 결과처럼 0이 나왔음을 확인할 수 있습니다.

이렇게 필터를 이용하면 이미지에서 특징점들을 쉽게 찾아낼 수 있습니다.


딥러닝에 Convolution을 적용

Image

딥러닝에 Convolution을 적용하면 위 그림과 같은 구조가 됩니다. 각 Layer에서 Convolution 연산을 한 후 Activation Function을 거쳐 다음 Layer에서 또 Convolution 연산을 하는 계층 형태로 되어 있습니다.