본문 바로가기

활동/SK네트웍스 Family AI 캠프 2기

SK네트웍스 Family AI 캠프 2기 : 10th week (7월 3주차)

7월 3주차부터 새로 오신 강사님의 수업을 본격적으로 들었습니다!

수업을 들으면서 '나도 강사님처럼 실력 있는 개발자가 되고 싶다...'라는 생각이 계속 떠오르더라구요.

 

그리고 학생들이 방대한 개념을 들어서 지쳐있을 때마다 CS 역사 이야기를 재미있게 풀어주시는 것도 정말 좋았어요!

GNU의 시초, 리누스 토르발즈(Linux 개발자)와 관련된 각종 tmi 등을 들으니 귀가 아주 즐거워졌습니다 ^_^

+) 전 원래 한 분야에 깊게 몰입한 사람이 덕질 토크 들려주는 것을 재밌어 하거든요ㅋㅋㅋ 소설, IT, 애니메이션, 운동, 게임 등 분야를 막론하고 열정 및 애정이 담긴 tmi를 듣는 건 늘 흥미롭더라구요ㅋㅋㅋㅋㅋ

 

게다가 가끔씩 어린 시절에 읽었던 '수학도둑' 만화책에서 나올 법한 논리 퀴즈를 내시는데 그것도 정말 재밌습니다!

어린 시절에 많이 즐기던 논리 퀴즈는 사실상 컴퓨터 알고리즘과 크게 다를 바 없다는 강사님의 철학이 마음에 듭니다👍

 

학생들과 소통하면서 함께 디버깅하는 과정도 얼마나 즐거운지 몰라요!

IT판 자체가 버전 업그레이드 주기가 짧은 분야이다 보니까, 이전에 동작한 코드가 간혹 돌아가지 않는 경우가 있는데요.

이때 학생들과의 소통을 매개로 강사님께서 시니어 개발자의 디버깅 과정을 보여주시곤 합니다.

이를 통해 학생들은 강사님께 시니어 개발자의 접근 방식을 배우고, 강사님은 학생들을 통해 외부 트렌드를 파악하십니다.

이런 수업 흐름 속에 함께 녹아들 수 있다는 것 자체가 소중하게 느껴지더라구요.

 

SK네트웍스 Family AI 캠프를 통해 귀한 가르침을 배울 수 있게 되어서 정말로 기쁩니다.

무더운 여름이라 졸음이 쏟아지는데도 불구하고, 많은 2기 학생들이 잠을 깨기 위해 일어선 자세로 수업을 듣는 이유가 다 있다니까요~

 

저도 강사님처럼 근본 있는 개발자가 되고 싶어요!

강사님처럼 취미로 Linux 오픈 소스 분석한다고 말할 정도로 실력 있는 사람이 되고 싶습니다!

 

 

● 성취

주말 특강을 통해 더 섬세하게 Git 사용하는 방법을 배웠습니다!

이전에 간단하게 Git 사용방식을 익힌 적이 있었기에, 특강 수강 여부에 대해 많은 고민을 했는데요.

그런 고민을 했던 것 자체가 무색해질 정도로 좋은 특강이었습니다.

 

특히 그동안 Git 브랜치 활용에 있어서 소극적이었는데, 이번 특강을 전환점으로 삼아서 적극적으로 사용해 보려고 합니다!

귀찮다는 이유로 main 브랜치만 사용했는데 그러면 버전 관리하는 데에 있어서 이점이 없을 것 같더라구요.

브랜치 도구의 존재 의의를 무시하면 안 되겠죠?!

이번주 가장 큰 성취 중 하나로 더 성숙한 Git 사용자가 되었다는 것을 내세우고 싶습니다!

+) 여담이지만 엔코아에서 제공하는 특강 정말 좋아요... 지난 번에 nlp, mlops 특강 열렸을 때에 둘 다 들었는데 배워 갈 내용들이 엄청 많았답니다! 초청 강사님들도 전부 기술에 진심이셔서 반응 열심히 하면 하나라도 더 알려주시려고 노력하셔서 좋았어요 :)

 

● 학습

이번 주에는 '밑바닥부터 시작하는 딥러닝2 (=밑시딥 2)'를 교재로 삼아서 공부했습니다!

요번에 공부한 밑시입 2권은 자연어에 중점을 두고 설명한 책인데요.

밑시딥1 책에 적힌 기본 원리를 잘 이해하고 있다면 부담 없이 따라갈 수 있답니다.

 

강사님께서 좋은 책을 기반으로 설명을 차근차근 해주셔서 정말 좋았어요 ^_^

그리고 강의자료도 체계적이어서 복습하는 용도로 적절했어요!

오늘은 복습하면서 인상 깊었던 내용 위주로 정리해보겠습니다.

 

# 동시 발생 행렬

동시 발생 행렬은 '분포 가설'을 기반으로 존재해요.

분포 가설은 특정 단어의 의미는 주변 단어(좌쪽 N개, 우쪽 N개)에 의해 형성된다고 가정해요.

이 발생 빈도를 행렬 형태로 기록한 것을 동시 발생 행렬이라 부른답니다!

 

# PMI (Pointwise Mutual Information, 상호정보량)

동시 발생 행렬은 단순하게 단어 빈도수만 센 형태라서 유의미한 관계를 나타내기 어렵다는 단점이 존재해요.

예를 들어 the와 car은 서로 높은 빈도수를 보이겠지만, the 관사 자체가 명사 앞에 자주 붙어있기 때문에 유의미한 결과로 생각하기에는 무리가 있겠지요.

 

이 문제를 해결하기 위해서 'PMI'라는 개념이 등장했어요.

PMI를 나타내는 식은 아래와 같습니다.

 

$$ PMI(x,y) = log_{2}\frac{p(x,y)}{p(x)p(y)} $$

 

이 공식을 사용하면 x, y가 유의미하게 동시발생한 케이스 위주로 수치를 계산할 수 있어요!

왜냐하면 동시발생 없이 x 또는 y가 다른 곳에서도 많이 나온 경우에는 점수를 깎도록 수식이 설계되었거든요.

 

근데 이 공식에도 단점이 있습니다.

왜냐하면 단어의 동시발생 횟수가 0일 경우에는 마이너스 무한대 상태를 보여주거든요.

 

$$ PPMI(x,y) = max(0,PMI(x,y)) $$

 

위 PPMI 공식을 사용하면, PMI 값이 음수로 나오는 케이스를 모두 0으로 변환할 수 있습니다!

 

# 어텐션(Attention)

'어텐션'은 seq2seq 모델 개선을 위해 나온 개념이에요.

이전 포스팅에서 seq2seq 모델을 언급했던 적이 있죠?

그때 seq2seq 모델을 A 도메인에서 B 도메인으로 변환할 때 많이 쓰는 모델이라 소개했어요.

한국어 문장을 영어 문장으로 번역해야 할 때 seq2seq 모델을 사용했던 것으로 압니다.

(지금은 워낙 좋은 모델들이 많이 나와서 seq2seq 모델 말고 다른 것을 쓸 것 같네요...^^;;)

 

seq2seq 모델의 단점은 고정 길이 형태로 문장을 출력한다는 것이었습니다.

근데 잘 생각해 보면... 세상의 모든 문장이 다 똑같은 길이로 출력할 필요는 없겠죠?

어떤 경우에는 짧은 문장으로 효과적인 전달을 할 수도 있으니까요!

어텐션 연구 관계자들은 중요 단어를 인식할 수만 있다면, 가변적인 길이로 문장을 출력할 수 있을 거란 생각을 했어요.

 

따라서 인코더 층의 LSTM 셀에서 학습한 전체 은닉 상태 벡터를 구한 후, 디코더가 연산하는 시점마다 부여했어요.

연구진들은 이와 같은 방식을 통해 각 시기마다 어떤 단어가 중요한지 포착하려고 노력했습니다.

 

연구 결과는 성공적이었고, 이때 나타난 어텐션 개념은 이후에 나올 트랜스포머 모델에 엄청난 영향을 끼쳤답니다!

 

# 트랜스포머(Transformer)

앞에서 어텐션 개념이 트랜스포머 모델에 큰 영향 줬다고 언급했죠?

맞아요, 트랜스포머 논문명부터 'Attention is all you need'거든요.

정말 말 그대로 어텐션 개념만 사용해서 모델을 구현했답니다!

기존 seq2seq 모델처럼 인코더/디코더가 존재하지만, 내부에 있는 LSTM을 싹 걷어냈어요.

대신에 어텐션 개념으로 모든 것을 구성했지요.

이 발상 자체가 혁신적이었기 때문에 '트랜스포머'라고 명명한 것이랍니다!

 

요즘 핫한 gpt 모델도 트랜스포머를 개량해서 만든 것이에요.

트랜스포머 모델을 LLM 모델의 어버이라 생각해도 무방할 정도라네요!

 

● 개선

이번주에는 밑시딥 1권의 3챕터를 복습하는 시간을 가졌어요.

강사님께서도 설명해 주셨던 부분이지만, 더 깊게 공부하고 싶다는 생각 때문에 직접 코드를 구현해 봤습니다.

+) 밑시딥 1권 코드를 기반으로 했지만, 제 취향을 가미하여 살짝 변환시켰습니다!

 

# 사용 라이브러리

import numpy as np
import numpy.typing as npt
import matplotlib.pyplot as plt
from typing import Dict
import tensorflow as tf
from tensorflow import keras
from PIL import Image
import pickle

 

 

# 계단 함수(Step function)

def np_step_function(x: npt.NDArray[np.float64]) -> npt.NDArray[np.int32]:
    y = x > 0
    return y.astype(np.int32)
    
# visualization
x = np.arange(-5.0, 5.0, 0.1)
y = np_step_function(x)
plt.plot(x, y)
plt.ylim(-0.1, 1.1)
plt.title('step function')
plt.show()

 

 

# 시그모이드 함수(sigmoid function)

def np_sigmoid(x: npt.NDArray[np.float64]) -> npt.NDArray[np.float64]:
    return 1 / (1 + np.exp(-x))
    
# visualization
x = np.arange(-5.0, 5.0, 0.1)
y = np_sigmoid(x)
plt.plot(x, y)
plt.ylim(-0.1, 1.1)
plt.title('sigmoid function')
plt.show()

 

 

# ReLU (Rectified Linear Unit)

def np_relu(x: npt.NDArray[np.float64]) -> npt.NDArray[np.float64]:
    return np.maximum(0, x)
    
# visualization
x = np.arange(-5.0, 5.0, 0.1)
y = np_relu(x)
plt.plot(x, y)
plt.xlim(-6, 6)
plt.ylim(-1, 5.5)
plt.title('ReLU')
plt.show()

 

 

#  3층 신경망 구현하기

# The identity function is a activation function in regression problem.
def np_identity_function(x: npt.NDArray[np.float64]) -> npt.NDArray[np.float64]:
    return x
    
def init_network() -> Dict[str, npt.NDArray[np.float64]]:
    network = {}
    network['W1'] = np.array([[0.1, 0.3, 0.5], [0.2, 0.4, 0.6]])
    network['b1'] = np.array([0.1, 0.2, 0.3])
    network['W2'] = np.array([[0.1, 0.4], [0.2, 0.5], [0.3, 0.6]])
    network['b2'] = np.array([0.1, 0.2])
    network['W3'] = np.array([[0.1, 0.3], [0.2, 0.4]])
    network['b3'] = np.array([0.1, 0.2])

    return network


def forward(network, x):
    W1, W2, W3 = network['W1'], network['W2'], network['W3']
    b1, b2, b3 = network['b1'], network['b2'], network['b3']

    a1 = np.dot(x, W1) + b1
    z1 = np_sigmoid(a1)
    a2 = np.dot(z1, W2) + b2
    z2 = np_sigmoid(a2)
    a3 = np.dot(z2, W3) + b3
    y = np_identity_function(a3)

    return y


network = init_network()
x = np.array([1.0, 0.5])
y = forward(network, x)
print(y)  # [0.31682708 0.69627909]

 

 

좋은 코드를 보면서 공부하니까 뭔가 정화되는 기분이었어요!

역시 사이토 고키(밑시딥 시리즈 저자) 선생님의 코드는 직관적이고 깔끔해서 배울 점이 정말 많아요👍

저도 군더더기 없이 깔끔한 코드를 작성하는 개발자가 되기 위해 노력할 겁니다!

 

이제 블로그 글도 다 썼으니 얼른 정처기 공부를 하러 가야겠습니다.

이번주 금요일에 시험이라 바짝 공부해야겠네요! 홧팅~~!!!

 

+) 부족한 부분이 있으면 댓글로 말씀해 주세요! 겸허한 마음으로 더 공부하겠습니다.