카테고리 보관물: Report

GANs in 50 lines of pytorch

이안 굿펠로우(Ian Goodfellow)의 GANs(Generative Adversarial Networks) 페이퍼를 파이토치로 구현한 블로그가 있어서 재현해 보았습니다.(제목과는 달리 전체 코드는 100줄이 넘습니다) 이 블로그에 있는 파이토치 소스는 랜덤하게 발생시킨 균등 분포를 정규 분포 데이터로 만들어 주는 생성기(G, Generator)와 생성기가 만든 데이터와 진짜 정규 분포를 감별하는 분류기(D, Discriminator)를 학습시키는 것입니다.

분류기에는 감별하려는 분포의 데이터 한 벌이 모두 들어가서 참, 거짓의 이진 판별을 내 놓습니다. 생성기는 한번에 하나의 데이터 포인트가 들어가서 출력값도 하나입니다. 원하는 분포를 얻기 위해서 생성기에 필요한 만큼 데이터를 계속 주입하면 됩니다. 행렬로 생각하면 분류기에는 하나의 행이 들어가고, 생성기에는 배치 효과를 위해 하나의 열 벡터가 들어갑니다.

그런데 기대한 것처럼 정규분포와 비슷한 생성기를 학습시키기가 어려웠습니다. 하이퍼파라미터 세팅에 많이 민감하여 종종 에러가 폭주하기도 했습니다. 그리고 학습이 되어도 정규분포의 모양을 가진다기 보다 평균과 표준편차만 같은 분포를 만들어 내었습니다. 즉 평균과 표준편차를 학습한 것 같은 모습니다(물론 이 코드는 결과보다 예시를 위한 것이라고 합니다만..). 그래서 생성기의 출력을 한번에 전체 분포를 얻을 수 있도록 마지막 레이어의 노드 수를 늘렸습니다. 이렇게 했더니 손쉽게 정규 분포와 비슷한 결과물을 얻었습니다만 생성기의 목적을 제대로 수행한 것인지는 확신이 서지 않네요. 🙂

전체 노트북은 깃허브에 있습니다. 코드의 중요 부분은 아래와 같습니다.

학습시키고자 하는 정규 분포는 평균이 4, 표준 편차가 1.25 입니다. 분류기는 입력 유닛이 100개이고 히든 유닛의 수는 50, 출력 노드는 하나입니다. 생성기는 100개의 입출력 유닛을 가지고 히든 유닛 수는 50개 입니다. 이 예제의 분류기, 생성기는 모두 각각 두 개의 히든 레이어를 가지고 있는데 두 개의 히든 레이어의 노드 수는 동일합니다.

data_mean = 4
data_stddev = 1.25

d_input_size = 100
d_hidden_size = 50
d_output_size = 1

g_input_size = 100
g_hidden_size = 50
g_output_size = 100

분류기와 생성기의 클래스 정의입니다.

class Discriminator(nn.Module):
    def __init__(self, input_size, hidden_size, output_size):
        super(Discriminator, self).__init__()
        self.map1 = nn.Linear(input_size, hidden_size)
        self.map2 = nn.Linear(hidden_size, hidden_size)
        self.map3 = nn.Linear(hidden_size, output_size)

    def forward(self, x):
        x = F.relu(self.map1(x))
        x = F.relu(self.map2(x))
        return F.sigmoid(self.map3(x))

class Generator(nn.Module):
    def __init__(self, input_size, hidden_size, output_size):
        super(Generator, self).__init__()
        self.map1 = nn.Linear(input_size, hidden_size)
        self.map2 = nn.Linear(hidden_size, hidden_size)
        self.map3 = nn.Linear(hidden_size, output_size)

    def forward(self, x):
        x = F.relu(self.map1(x))
        x = F.relu(self.map2(x))
        return self.map3(x)

렐루(ReLU)를 사용해서 레이어를 감싸고 분류기의 출력은 시그모이드로, 생성기의 출력은 마지막 레이어의 값을 그대로 뽑았습니다. 다음은 분류기와 생성기가 서로 학습하는 과정입니다.

for epoch in range(num_epochs):
    # 분류기와 생성기의 학습 횟수가 서로 다를 수 있습니다.
    for d_index in range(d_steps):
        D.zero_grad()  # 그래디언트를 비웁니다.
        real_data = Variable(real_sampler(d_input_size)) # 정규분포
        real_decision = D(real_data) # 정규분포 판별
        real_error = loss(real_decision, Variable(torch.ones(1))) # 무조건 참이어야 합니다
        real_error.backward() # 역전파

        fake_input = Variable(fake_sampler(g_input_size)) # 균등분포
        fake_data = G(fake_input) # 생성기가 정규분포로 변조시킵니다
        fake_decision = D(fake_data) # 가짜인지 구분해야 합니다
        fake_error = loss(fake_decision, Variable(torch.zeros(1))) # 무조건 거짓이어야 합니다
        fake_error.backward()  # 역전파
        d_optimizer.step()     # 분류기 파라미터 업데이트

    # 생성기 학습 차례
    for g_index in range(g_steps):
        G.zero_grad()  # 그래디언트를 비웁니다.
        fake_input = Variable(fake_sampler(g_input_size)) # 균등분포
        fake_data = G(fake_input) # 생성기가 정규분포로 변조합니다
        fake_decision = D(fake_data) # 가짜인지 구분합니다.
        fake_error = loss(fake_decision, Variable(torch.ones(1))) # 생성기 입장에서는 분류기가 참으로 속아야 합니다.
        fake_error.backward()  # 역전파
        g_optimizer.step()     # 생성기 파라미터 업데이트

이렇게 학습시키게 되면 초기에는 평균과 표준편차가 잠시 널뛰지만 반복이 어느 시점을 넘어서면 거의 변동이 없는 상태가 됩니다. 아래 그림에서 파란색이 평균, 붉은 색이 표준편차 입니다.

gan-pytorch-1

에러는 총 세가지로 분류기가 학습할 때 계산하는 정답 분포에 대한 에러(파란)와 가짜 분포(녹색)에 대한 에러, 그리고 생성기가 학습할 때 계산하는 가짜 분포에 대한 에러(적색) 입니다. 아래 그래프에서 볼 수 있듯이 세 에러가 거의 변동이 없이 일치하고 있습니다.

gan-pytorch-2

학습이 끝난 후 만들어진 생성기로 랜덤한 균등 분포를 입력해서 정규 분포로 바꾸어 보았습니다. 눈으로 볼 때에도 구분할 수 없을 만큼 비슷했습니다. 깃허브에 있는 노트북 코드원본 코드와는 조금 다르며 코드를 간소화하기 위해 람다 함수 등을 수정했습니다.

PyTorch MNIST Example

파이토치(PyTorch)로 텐서플로우 튜토리얼에 있는 MNIST 예제를 재현해 보았습니다. 이 코드는 파이토치의 MNIST 예제를 참고했으며 주피터 노트북으로 작성되어 깃허브에 올려져 있습니다. 당연하지만 분류 결과는 텐서플로우로 만든 예제와 큰 차이가 없습니다.

파이토치는 버전 0.1.6을 사용하였습니다. 파이토치 설치는 이 포스트를 참고하세요. 파이토치는 코어 C 라이브러리를 토치(Torch)와 공유하고 있습니다. 그 외에는 모두 파이썬으로 구현되어 있으며 별도로 C API 가 없습니다. 오직 파이썬을 위해서 구현된 라이브러리이고 또 다이나믹 컴퓨테이션 그래프(Dynamic Computation Graph)를 지원하기 때문에 코드 모습이 일반 프로그래밍처럼 자연스러웠습니다.

파이토치의 예제와 유사하게 torch.nn.Module 클래스를 상속받아 모델 클래스를 만들었습니다.

class MnistModel(nn.Module):
    def __init__(self):
        super(MnistModel, self).__init__()
        # input is 28x28
        # padding=2 for same padding
        self.conv1 = nn.Conv2d(1, 32, 5, padding=2)
        # feature map size is 14*14 by pooling
        # padding=2 for same padding
        self.conv2 = nn.Conv2d(32, 64, 5, padding=2)
        # feature map size is 7*7 by pooling
        self.fc1 = nn.Linear(64*7*7, 1024)
        self.fc2 = nn.Linear(1024, 10)
        
    def forward(self, x):
        x = F.max_pool2d(F.relu(self.conv1(x)), 2)
        x = F.max_pool2d(F.relu(self.conv2(x)), 2)
        x = x.view(-1, 64*7*7)   # reshape Variable
        x = F.relu(self.fc1(x))
        x = F.dropout(x, training=self.training)
        x = self.fc2(x)
        return F.log_softmax(x)
    
model = MnistModel()

Module 를 상속받은 클래스는 뉴럴 네트워크의 정방향 계산을 수행하는 forward() 메소드를 구현해야만 합니다. 이 forward() 메소드는 model 오브젝트를 데이터와 함께 호출하면 자동으로 실행이됩니다.

풀링과 활성화 함수들은 torch.nn.functional 아래에 있고 함수처럼 불러서 사용할 수 있습니다. 이런 함수들은 Conv2d 클래스처럼 유사하게 forward(), backward() 메소드를 가진 클래스를 감싸고 있는 형태입니다. 최종 loss 에서 backward() 함수가 호출되면 거꾸로 짚어가면서 역방향 계산이 연쇄적으로 일어납니다. Conv2d 함수의 파라미터에서 볼 수 있듯이 패딩과 스트라이드를 명시적으로 지정해 주어야 합니다. 콘볼루션의 패딩 계산은 이 포스트를 참고하세요.

Linear 함수는 일반적인 완전연결(fully connected) 레이어를 의미하는 것으로 이것뿐만 아니라 많은 요소들이 토치의 네이밍을 따르고 있는 것 같습니다. 아마도 토치를 썼던 사람은 쉽게 사용할 수 있을 것 같습니다.

model.train()
train_loss = []
train_accu = []
i = 0
for epoch in range(15):
    for data, target in train_loader:
        data, target = Variable(data), Variable(target)
        optimizer.zero_grad()
        output = model(data)
        loss = F.nll_loss(output, target)
        loss.backward()    # calc gradients
        train_loss.append(loss.data[0])
        optimizer.step()   # update gradients
        prediction = output.data.max(1)[1]   # first column has actual prob.
        accuracy = prediction.eq(target.data).sum()/batch_size*100
        train_accu.append(accuracy)
        if i % 1000 == 0:
            print('Train Step: {}\tLoss: {:.3f}\tAccuracy: {:.3f}'.format(i, loss.data[0], accuracy))
        i += 1

모델을 학습시키는 부분도 직관적입니다. Negative Log Likelihood를 의미하는 nll_loss 함수에 출력과 타겟값을 넣고 loss.backward() 를 호출한 다음 optimizer.step() 으로 파라미터를 업데이트 합니다. 여기서 target 은 원-핫-인코딩이 아닌 타겟 레이블을 그대로 넣습니다. loss 와 accuracy 를 리스트에 저장하여 맷플롯립으로 그래프를 그렸습니다.

pytorch-mnist-loss

loss

pytorch-mnist-accuracy

accuracy

모델을 훈련할 땐 model.train() , 테스트할 땐 model.eval() 함수를 호출하면 Module 클래스의 훈련 상태 여부를 바꾸게 되며 이는 dropout 같은 함수가 드롭아웃을 적용할지 안할지를 결정하게 만듭니다.

model.eval()
correct = 0
for data, target in test_loader:
    data, target = Variable(data, volatile=True), Variable(target)
    output = model(data)
    prediction = output.data.max(1)[1]
    correct += prediction.eq(target.data).sum()

print('Test set: Accuracy: {:.2f}%'.format(100. * correct / len(test_loader.dataset)))

최종결과는 99.29%를 얻었습니다. 전체 코드는 깃허브에서 확인할 수 있습니다.

[Review]Introduction to ML with Python

catIntroduction to ML with Python은 사이킷런(scikit-learn) 0.18 버전이 출시된 후 가장 먼저 나온(작년 10월 출간) 파이썬 머신러닝 책입니다. 이전 포스트에서도 잠깐 언급한 적이 있지만 사이킷런 0.18 버전에는 피드포워드(feed-forward) 뉴럴 네트워크 클래스가 추가되었습니다. 그래서 이 책에도 이와 관련된 섹션이 추가되어 있네요. 이 책의 저자 중 한명인 앤디(Andreas C. Muller)는 뉴욕 대학교의 리서치 엔지니어이면서 사이킷런의 핵심 개발자입니다. 머신러닝 PhD로서 머신러닝에 대해서 잘 알고 있을  뿐만 아니라 사이킷런에 대해서 누구보다도 잘 알고 있음은 두말할 필요가 없습니다.

머신러닝의 실용서와 이론서의 측면을 모두 담은 책은 쉽게 보기 힘듭니다. 특히나 여러 종류의 알고리즘에 걸쳐서라면 더욱 그렇습니다. 이 책은 후자 보다는 전자에 무게를 실었습니다. 수식은 과감히 덮고 가능하면 직관적으로 이해할 수 있도록 배려했으며 무엇보다도 상당히 많은 종류의 알고리즘을 설명하고 사이킷런으로 예시를 보여주고 있습니다. 이 책을 번역서로 내기 위해 제가 번역 작업을 진행하고 있고 대략 70% 정도 진척이 되었습니다. 전체 내용을 가늠하실 수 있도록 챕터별 내용을 요약했습니다.

계속 읽기

역전파, 직접 짜봐야 하나요?

OpenAI의 안드레이 카패시(Andrej Karpathy)가 얼마전 ‘Yes you should understood backprop‘란 글을 미디엄 사이트에 올렸습니다. 안드레이는 OpenAI에 오기 전에 스탠포드 대학에서 PhD 학생으로 근무했고 CS231n 강의를 진행했습니다. 이 강의는 영상과 강의 노트 모두 인터넷에 공개되어 있어 인공지능에 관심있는 연구자나 학생들에게 인기가 많습니다. 그런데 학생들이 가끔 CS231n 의 숙제에 불평을 하는 경우가 있는 모양입니다. 텐서플로우 같은 라이브러리가 역전파 알고리즘을 모두 자동으로 처리해 주는 데 굳이 numpy 로 정방향(forward pass), 역방향(backward pass, backpropagation) 코드를 직접 구현하는 숙제를 할 필요가 있느냐고 말이죠.

역전파 코드를 직접 만들어 봐야할 이유가 지적 호기심이나 더 나은 역전파 알고리즘을 만들기 위해서가 아니라 역전파를 알아야 뉴럴 네트워크를 만들 때 오류를 범하지 않고 디버깅을 하는데 도움을 주기 때문입니다. 안드레이는 역전파가 불완전한 추상화(leaky abstraction)라고 말하고 있습니다. 불완전한 추상화 또는 누수 추상화는 조엘 스폴스키의 블로그를 통해서 알려졌었습니다. 한마디로 구멍이 많다는거죠!

계속 읽기

해커가 알려주는 뉴럴 네트워크

이 글은 스탠포드 대학의 Ph.D 학생이었고 현재 OpenAI 연구원인 안드레이 카패시(Andrej Karpathy)가 블로그에 쓴 ‘Hacker’s guide to Neural Networks‘를 저자의 동의하에 번역한 것입니다. 글 서두에 저자가 밝혔듯이 원래 이 글은 좀 더 길게 연재될 예정이었지만 스탠포드 대학의 CS231n 강의를 진행하면서 두개의 챕터만 쓰여진 채 중단된 상태입니다.

이 글은 최대한 이론을 배제하고 머신러닝과 뉴럴 네트워크를 처음 접하는 사람들을 위해 직관적 이해를 돕기 위해 쓰여졌습니다. 그래서인지 단 두 챕터만으로도 많은 사람들에게 크게 환영받고 있는 것 같습니다. 언제 다시 글이 이어질지는 모르겠습니다만 혹시라도 내용이 추가된다면 업데이트 하도록 하겠습니다.

조금 더 전문적이고 폭 넓은 내용을 담고 있는 것은 저자가 추천하는 CS231n 강의 노트입니다. 이 강의 노트의 번역은 AIKorea 블로그나 해현용님의 블로그에서 읽을 수 있습니다.

아래 글에 포함된 코드의 파이썬 버전은 여기에 있습니다.

해커가 알려주는 뉴럴 네트워크

1장: 실수치 회로

기본적인 구조: 하나의 게이트로 된 회로

중첩된 구조: 여러개의 게이트로 된 회로

예제: 단일 뉴런

역전파 고수되기

2장: 머신 러닝

이진 분류

전통적인 방법: 손실 함수

DNN for YouTube Recommendations

youtube-recomm-1

출처: DNN for YouTube Recomm. 페이퍼

이번달에 열리는 10th ACM Conference on Recommender Systems에 맞춰 구글 리서치에서 사용자에게 유투브 동영상을 추천하는 시스템에 대한 개괄적인 소개를 담은 페이퍼(pdf)를 공개하였습니다. 페이퍼의 내용으로 미루어 보아 유투브의 추천 시스템은 구글 브레인팀에서 텐서플로우를 이용하여 구축한 것 같습니다.

유투브에서는 추천을 위해 수백만개의 동영상을 수백개의 후보로 좁히고 이를 바탕으로 다시 사용자에게 추천할 영상을 고르는 두 단계로 구성되어 있습니다. 두 단계 모두 몇단계의 ReLU(Rectified Linear Unit) 활성화 함수를 가진 완전 연결(fully connected) 레이어로 구성되어 있습니다. 후보자를 생성하는 첫 단계는 소프트맥스 함수를 이용한 분류(Classification) 문제로 변환하여 생각하였습니다. 사용된 훈련 데이터는 전체 유투브 동영상 시청 데이터를 기반으로 하고 있고 갯수는 수천억건에 이릅니다.

youtube-recomm-2

출처: DNN for YouTube Recomm. 페이퍼

학습에 필요한 데이터를 추출할 때 효과적인 학습을 위해 워드 임베딩에서 사용하는 네거티브 샘플링(negative sampling)을 기법을 이용하였고 소수의 유저가 일으키는 대량의 트래픽으로 학습이 오염되지 않게 하기 위해 사용자마다 고정된 양의 샘플을 추출했습니다. 이렇게 유투브 트래픽으로 뉴럴 네트워크를 학습시키면 이 모델은 매트릭스 인수분해(matrix factorization) 부담으로 실제 적용이 어려운 user-user 협업 필터링을 간접적으로 구현하는 효과를 가집니다.

youtube-recomm-3

출처: DNN for YouTube Recomm. 페이퍼

첫번째 네트워크에서 학습된 모델을 사용하여 사용자에게 맞는 후보 영상을 고르기 위해 해싱기법을 사용하는 Nearest Neighbor 근사 알고리즘을 사용하였습니다. 네트워크의 입력은 그림에서 볼 수 있듯이 비디오 시청 데이터, 사용자 검색어, 지역, 영상이 제공된 기간, 성별 등 많은 특성들을 사용하고 있습니다. 특별히 가변 길이의 시청 데이터를 언어 모델링에서 사용하는 임베딩 방법을 사용하여 압축(dense representation)하여 입력으로 사용하였습니다.

이 시스템은 유투부의 홈페이지에 맞춤 동영상 영역에 나타나는 항목을 결정합니다. 사용자는 시리즈를 본다거나 한 종류의 영상을 지속적으로 보는 경향이 있습니다. 예를 들면 지금 ‘테일러 스위프트’를 검색했다고 해서 홈페이지의 추천 영역을 테일러 스위프트와 관련있는 것으로 바꾸어 버리는 것이 A/B 테스트 결과 더 좋지 않았습니다. 따라서 시청이 어느 정도 완료된(hold out) 영상까지의 데이터만 추론에 사용합니다(테일러 스위프트 뮤직비디오를 다 시청하니 바로 맞춤 동영상 영역에 테일러 스위프트의 영상이 추천되었습니다).

이와 비슷한 맥락으로 유투브의 추천 시스템은 ‘좋아요’나 ‘싫어요’ 같은 명확한 사용자의 액션 뿐만 아니라 시청 완료 같은 겉으로 드러나지 않는 사용자의 액션을 함께 사용합니다. 이는 전자의 데이터가 너무 드물기(sparse) 때문입니다.

 

youtube-recomm-4

출처: DNN for YouTube Recomm. 페이퍼

두번째 네트워크는 수백개의 후보 가운데 사용자의 디바이스에 노출할 동영상을 결정하는 모델(ranking model)을 학습시킵니다. 이 모델은 동영상을 클릭할 확률을 예측하는 것이 아니라 동영상의 기대 시청 시간을 예측하는 로지스틱 회귀 분석입니다. 이는 동영상을 시청하지는 않고 클릭만 이리 저리 누르는 사람들이 있기 때문에 시청 시간을 모델링 하는 것이 더 좋은 성과를 냅니다. 두번째 모델도 A/B 테스트를 통해 지속적으로 실시간 튜닝이 됩니다.

두번째 네트워크도 수백개의 입력을 사용하여 완전 연결 ReLU 레이어를 쌓아서 구성하며 주된 학습 재료는 비디오 노출 데이터와 사용자가 시청한 데이터입니다. 이 때 사용자와 비디오 데이터를 적절하게 가공하기 위해 각각 상당한 피처 엔지니어링이 불가피 합니다.

이 페이퍼는 뉴럴 네트워크 뿐만이 아니라 추천 시스템과 동영상 사이트의 특징들을 이해해야 해서 읽기 어려웠던 것 같습니다. 부족한 부분은 댓글로 채워주세요.

Decoupled Neural Interfaces using Synthetic Gradients[1608.05343] Summary

지난 주 딥마인드에서 내놓은 이 페이퍼는 이전 포스트에서 잠깐 언급했듯이 뉴럴 네트워크의 레이어간의 데이터 주입과 그래디언트 업데이트를 비동기적으로 처리하는 방식을 제안하고 있습니다. 이전에 이런 방식과 유사한 연구가 있었는지 배경 지식을 구하기는 힘들었지만 분명한 것은 이 페이퍼가 여러 사람에게 큰 관심을 끌고 있다는 점입니다.

뉴럴 네트워크의 한 레이어에서 데이터를 처리할 때 다른 레이어가 작업을 하지 않은 상태를 멈춰(locking)있다고 표현할 수 있습니다. 특히 레이어간의 연산이 다른 디바이스에 할당되어 있는 경우에는 물리적으로도 멈춰있는 형태가 됩니다. 이렇게 멈춰있게 되는 경우는 에러 그래디언트(gradient)를 역전파시킬 때도 마찬가지 입니다. 체인 룰(chain rule)의 특성상 이전 레이어에서 그래디언트가 전달되지 않으면 하위 레이어는 대기 상태에 있습니다. 이런 레이어간의 동기성은 거대한 뉴럴 네트워크의 학습 속도에 영향을 미치므로 레이어간의 데이터 전달을 비동기적으로 처리하는 모델을 제안하고 있습니다.

여기서 제안하는 방법은 한 레이어에서 데이터가 처리된 후 그 다음 레이어를 통과해 마지막 레이어에서 에러가 계산되어 역전파 되기를 기다리지 않고 데이터가 처리되자 마자 가짜 그래디언트(synthetic gradient)를 업데이트 하는 것입니다. 가짜 그래디언트로 레이어의 파라메타(가중치)가 업데이트 되면 다음 미니배치 데이터를 받아 들일 수 있게 됩니다. 가짜 그래디언트는 진짜 그래디언트가 앞 레이어로 부터 전달되면 이 값을 이용하여 보다 좋은 가짜 그래디언트를 만들기 위해 학습합니다. 즉 가짜 그래디언트를 위한 소규모의 뉴럴 네트워크가 레이어 사이 사이에 위치해 있습니다. 아래 그림은 이런 그래디언트의 비동기적인 업데이트 과정을 잘 보여 주고 있습니다.

계속 읽기

Reinforce Pong at Gym

한달 전에 스탠포드 비전 랩의 안드레이 카패시(Andrej Karpathy)가 블로그에 강화학습에 대한 글인 ‘Deep Reinforcement Learning: Pong from Pixels‘를 올렸었습니다. 조금 늦었지만 블로그의 글을 따라가 보려고 합니다. 안드레이는 스탠포드 뿐만이 아니라 구글과 OpenAI에서도 여러 프로젝트에 참여했고 강화학습과 관련된 여러 도서를 읽고 관련 강의도 들었다고 합니다. 강화학습을 쉽게 소개하기 위해 글을 썼다고 하는데 말처럼 쉽지는 않은 것 같습니다.

OpenAI 짐(Gym)은 강화학습 알고리즘을 훈련시키고 평가할 수 있는 프레임워크입니다. 짐에 포함된 퐁(Pong) 게임은 아타리(Atari) 2600에 포함된 간단한 컴퓨터 게임의 시뮬레이션 버전입니다. 두사람이 오른쪽과 왼쪽에 있는 자기 막대를 움직여 공을 받아 넘겨야 하고 상대방이 놓쳐서 화면 옆으로 사라지면 점수를 1점 얻게 됩니다(이를 편의상 한 판이라고 부르겠습니다). 이렇게 점수를 획득하여 가장 먼저 21점을 얻는 쪽이 이기는 게임입니다. 짐에서는 화면의 왼쪽 편이 하드 코딩되어 있는 컴퓨터 에이전트이고 오른쪽 편이 강화학습을 통해 우리가 학습시켜야할 에이전트입니다.

짐 라이브러리에서는 공이 위치가 이동되었을 때를 한 스텝(step)이라고 표현합니다. 게임 화면에서 공이 이동할 때 마다 스크린샷을 찍는다고 생각하면 비슷합니다. 매 스텝마다 짐은 우리에게 리워드(reward)를 줍니다. 이겼을 때는 1, 졌을 때는 -1, 이도저도 아닌 공이 게임 판 위를 여전히 돌아다니고 있는 중간에는 0을 리턴합니다. 우리는 매 스텝마다 막대의 위치를 위로 올릴 것인지(UP), 아래로 내릴 것인지(DOWN)를 결정하여 짐 라이브러리에 전달합니다. 게임을 이길 수 있도록 막대의 위치를 제어하는 것이 우리가 풀어야 할 숙제입니다.

계속 읽기

인공지능과 법적쟁점

얼마전 소프트웨어정책연구소 SPRi 에서 ‘인공지능과 법적쟁점‘ 이라는 리포트를 공개했습니다. 이 리포트에서는 인공지능을 활용하여 발생하는 문제가 현행 법적 체계 안에서 수용될 수 있는지를 검토하고 인공지능이 일으킨 사고나 창작물에 대한 법적 쟁점을 다루었습니다.

구체적으로 보면 인공지능 에이전트가 기사를 대신해서 쓰는 경우가 한 예입니다. 이미 해외에서는 간단한 사고, 사건 보도류의 기사를 인공지능 에이전트가 대신하여 작성하는 것으로 알려져 있습니다. 그렇다면 이런 기사의 저작권이 누구(인공지능 에이전트, 언론사, 인공지능 개발사)에게 있으며 어떤 법으로 보호를 해야하는 지 명확하지가 않습니다. 따라서 이런 상황에 대응할 수 있는 가이드라인과 법제도 개선이 필요하다고 언급하고 있습니다.

동물보호법은 동물의 권리를 인정하는 것은 아니고 동물이 받을 수 있는 고통에 대해 사회의 인식이 높아진 것으로 이해해야 합니다. 이렇게 생명에 대한 존중으로서 동물에 대한 사회적 인식이 높아지고 있지만 민법에 의해 동물은 물건에 포함되어 권리의 주체가 아니고 보호받거나 관리되어야 할 대상이라고 합니다.  즉 동물의 소유권은 해당 동물의 소유자에게 귀속됩니다. 인공지능을 물건으로 간주한다면 소유권은 해당 인공지능의 소유자에게 있습니다. 법적 주체는 사람과 법인으로 한정되어 있으므로 인공지능이 일으킨 문제에 대한 책임은 그 소유자에게 돌아갈 가능성이 높습니다.

계속 읽기

TensorFlow White Paper[1603.04467] Summary

텐서플로우 백서(White Paper)라고도 불려진 텐서플로우의 첫번째 페이퍼 ‘TensorFlow: Large-Scale Machine Learning on Heterogeneous Distributed Systems‘[1603.04467]를 요약해서 정리해 보았습니다. 아직 읽지 않은 분들에게 도움이 되었으면 합니다. 부족한 부분이 있다면 댓글로 보완해 주세요.

소개

2011년에 구글 브레인 팀이 조직되어 딥 뉴럴 네트워크(deep neural network)에 대한 연구를 시작하였고 딥 뉴럴 네트워크 시스템인 디스트빌리프(DistBelief)를 개발했습니다. 구글은 디스트빌리프를 비감독학습(unsupervised learning), 언어[1, 2], 이미지인식[1, 2], 비디오분류, 음성인식[1, 2, 3], 보행자감지, 바둑, 시퀀스예측, 강화학습(reinforcement learning)과 그외[1, 2] 여러 분야에 사용해왔습니다. 구글 안의 50개가 넘는 팀과 알파벳 자회사들이 디스트빌리프를 이용해 다양한 제품에 딥 뉴럴 네트워크를 적용해왔습니다. 여기에는 검색, 광고, 음성인식시스템[1, 2, 3], 구글포토, 지도, 스트리트뷰, 번역, 유투브 등이 포함됩니다. 이러한 경험을 바탕으로 차세대 대규모 머신러닝 시스템인 텐서플로우(TensorFlow)를 개발했습니다.

텐서플로우는 상태 정보를 가지는 데이터플로우(dataflow) 그래프로 컴퓨터의 계산을 표현합니다. 안드로이드, iOS 같은 모바일 환경에서 추론(inference) 시스템을 만들수도 있고 한개 또는 여러개의 GPU를 가진 단일 서버에서는 중간 규모의 훈련(training)과 추론 시스템을 구축할 수 있습니다. 또는 수천개의 GPU가 탑재된 수백대의 서버에서 운영될 수도 있습니다. 텐서플로우를 이용하면 학습 시스템은 대규모로 하면서 실제 서비스는 소형화하여 운영할 수 있습니다.

텐서플로우는 매우 빠른 성능과 유연한 구조를 가지고 있어 새로운 모델을 빠르게 실험해 볼 수 있고 실제 서비스에도 안정적으로 사용할 수 있습니다. 디스트빌리프와 비교해 볼 때 텐서플로우의 프로그래밍 방식이 더 유연하고 성능은 더 뛰어납니다. 구글 내부의 여러 팀들이 이미 디스트빌리프에서 텐서플로우로 전환했습니다. 텐서플로우는 딥 뉴럴 네트워크를 만드는 데 사용되는 것이 일반적이지만 다른 머신러닝 알고리즘을 적용하거나 수치 계산 용으로도 사용할 수 있어서 다양한 산업 분야에 폭 넓게 활용될 수 있습니다. 텐서플로우는 2015년 11월 아파치 2.0 오픈소스 라이센스로 공개되었고 www.tensorflow.org에서 다운받을 수 있습니다.

계속 읽기