딥러닝
지금까지 했던 모형 기반 강화학습이라 는 거는 이런 거고 그 다음에 우리가 이제 다음으로도 지금까지는 다 표 기반 강화학습을 했어요
뭔 기반이 또 많냐 하면은 지금까지는 우리가 예를 들면 V를 추정을 하면 S를 0부터 9번까지 이걸 표로 만들어서 각각의 표에 있는 숫자를 채워놨단 말이에요
Q도 마찬가지입니다
Q면은 상태가 이렇게 있고 그 다음에 우리 액션이 있으면 이걸 표로 만들어서 이 칸마다 숫자를 다 채워놨어요
이렇게 하면은 어떤 격자 공간에서는 적용이 가능한데 이제 어제도 한번 질문하셨는데 실수 형태다 그러면은 안 되겠죠
그 다음에 이게 너무 상태 공간이 크면은 그것도 조합이 너무 많기 때문에 안 됩니다
예를 들면 바둑판 같은 경우에 우리가 둘 수 있는 바둑의 개수가 2에 120승인가 그렇거든요
근데 우주에 있는 원자의 수가 2에 60승인가
그렇습니다
그래서 이걸 바둑판에 바둑둘 수 있는 모든 그 수를 다 조합을 하면은 너무 너무 많기 때문에 이거를 표 기반으로 할 수 없어요
아니 바둑판 해봐야 가로 19줄 세로 19줄인데 그럼 19 곱하기 19하면 391이라서 391개 밖에 안 되지 않나요 라고 생각하실 수 있는데 그거는 이제 한 수가 391개고 누가 첫 번째 391번째 위치 중에 하나를 두면 그 다음 사람이 둘 수 있는 390개가 있죠
이런 식으로 바둑판을 200수까지 두기 때문에 점점 해서 보통 100까지 두는 거 이렇게 하면은 이걸 다 곱하면 어마어마한 숫자가 돼요
그만큼의 상태가 있어서 이거를 표로 만들 수가 없고 그래서 우리가 무한한 시간이나 용량이 있어도 사실 무한하지도 않죠
아주 많은 시간이나 용량이 있어도 우주가 끝날 때까지 계산을 돌려도 최적정책이나 최적값의 점수를 찾을 수가 없습니다
그리고 아까 얘기 드렸듯이 상태공간이 연속이어도 표로 나타낼 수가 없어요
그래서 표 기반 강화학습은 굉장히 단순한 문제만 적용을 할 수 있다
근데 이거를 약간 바꿔서 생각하면 최대한 어쨌든 표 기반 강화학습으로 만들어서 푸실 생각을 해야 됩니다
그러니까 뭐 이런 경우가 있거든요
예를 들어 로봇으로 제어를 하는데 우리가 이거를 정말로 실수로 제어를 해야겠냐
이 생각을 좀 해 보셔야 돼요
예를 들면 로봇이 각도 하나하나를 다 하면은 우리가 이 각도는 실수죠
근데 그냥 각도로 하지 말고 로봇이 이쪽으로 팔 뻔는 경우 이쪽으로 팔 뻔는 경우 이러면은 우리가 표 기반 강화학습을 할 수 있잖아요
그럼 이거 옮기는 거 어떻게 한대요 그 정도는 그냥 모터를 코드 짜서 직접 코드 짜서 하세요
여기서 옮기는 건 알아서 하시고 그래서 1번을 먼저 해야 되냐 2번을 먼저 해야 되냐
이거는 강화학습으로 하면은 문제가 훨씬 쉬워집니다
그러니까 반드시 우리가 표 기반 강화학습을 하시는 질문이 좋은 질문인데 고급 알고리즘으로 갈수록 사실은 문제가 더 어려운 문제라서 알고리즘은 좋아지지만 문제 자체가 더 어렵기 때문에 잘 안 풀리거든요
그래서 가능하면 문제를 단순하게 바꾸시는 게 좋아요
특히 강화학습은 대체로 문제가 그냥 원래도 다 어렵습니다
그래서 우리가 표 기반 강화학습에서 딥러닝 강화학습으로 넘어갈 건데 해보시면 딥러닝 강화학습이 잘 안 돼요
여러 가지 이유로 잘 안 되기 때문에 가능하면 표 기반으로 어떻게든 바꿔서 하시는 게 좋습니다
근데 죽어도 안 되는 경우가 있죠
바둑 같은 거는 뭐 어떻 게 해도 표 기반으로 못 합니다
근데 잘 찾아보면 어떻게 할 수도 있다
카트 폴
그래서 이제 우리가 새로운 환경을 써볼 건데 보통 강화학습 수업에서 굉장히 많이 쓰는 예제가 카트 폴이라고 있거든요
그래서 이제 로봇 같은 데다 적용을 하려고 하는 건데 굉장히 쉬운 겁니다
우리 어렸을 때 많이 해보던 건데 여기 밑에 있는 카트가 있고요
여기 기둥이 있는데 폴이 있는데 여기가 경첩으로 고정이 돼 있어요
그래서 얘가 왼쪽으로 쓰러지거나 오른쪽으로 쓰러져서 그래서 얘가 왼쪽으로 쓰러지거나 오른쪽으로 쓰러져서 중심에서 12도 이상 기울면 게임이 끝입니다
게임 오버고 그래서 우리가 해야 되는 거는 이 밑에 있는 카트를 기둥이 이쪽으로 기울면 이쪽으로 밀어야 될 거고 이쪽으로 기울면 이쪽으로 밀어서 잘 균형을 잡아야 돼요
그래서 우리가 이제 네 가지 상태를 가지는데 카트의 좌표, 기둥의 각도, 카트 속도, 기둥 속도 이 네 가지 값을 가지고 이걸 입력으로 받아서 우리가 할 수 있는 거는 카트를 왼쪽으로 밀거나 오른쪽으로 밀거나 이 미는 속도는 고정입니다
우리는 매 스탭마다 왼쪽으로 밀거나 오른쪽으로 밀거나 둘 중에 하나만 할 수 있어요
그래서 종료 조건은 12도 이상 기울거나 아니면 화면 여기 가운데가 0이고 이쪽이 마이너스 2.4 이쪽 좌표가 플러스 2.4인데 이 좌표를 넘어가도 게임 오버예요
그리고 시간이 500스텝 이상 지나면 시간 종료로 스탭입니다
이렇게 되면 종료가 되고요 보상은 매 스탭 마다 주어집니다
아까는 골 때 들어가야 보상을 줬잖아요
이제는 한 스텝당 플러스 1점이니까 최대한 버텨야 됩니다
빨리 죽으면 점수가 짜죠
그래서 이 문제도 그렇게 어려운 문제는 아니에요
사실 이거 강화학습으로 그렇게 풀 필요도 없는 문제이긴 한데 항상 그렇지만 쉬운 문제를 해보는 겁니다
그래서 우리가 처음에는 무작위 정책을 가지고 할 거예요
import gymnasium as gym
import imageio
import IPython
import tqdm
# 환경
env = gym.make("CartPole-v1", render_mode="rgb_array")
# 무작위 정책
class RandomModel:
def predict(self, state, **kwargs):
return env.action_space.sample(), None
def render_episode(env, model, max_frame=1000):
state, _ = env.reset()
frames = []
done = False
for _ in tqdm.trange(max_frame): # 최대 프레임까지 진행
action, _state = model.predict(state, deterministic=True)
next_state, reward, terminated, truncated, _ = env.step(action)
if terminated or truncated:
break
state = next_state
frames.append(env.render()) # 프레임을 수집
imageio.mimsave('cartpole.gif', frames, fps=30) # 초당 30프레임으로 GIF 만들기
return IPython.display.Image('cartpole.gif') # GIF 보기
render_episode(env, RandomModel())
함수 근사
그래서 그렇게 바꿔도 되는데 이왕이면 그래도 좀 실수로 해보면 결국에는 이 4가지 숫자를 주면 어떤 다음 번에 왼쪽으로 가야 될지 오른쪽으로 가야 될지
결정하는 함수를 만들어야 되고 그럼 그 함수를 이제 우리가 근사를 해야 되는데 정확한 수학적 형태를 물론 아시는 분도 있겠지만 뭐 이렇게 계산해 보면 되겠죠
이게 그냥 각 운동이니까 계산해 보면 되는데 잘 모르면 함수를 근사를 해 야 됩니다
근사를 해야 되는데 우리가 데이터를 무한정 얻을 수 있는 게 아니기 때문에 소수의 사례로 가지고 일반화 할 수 있게 잘 근사를 해야 되고 이제 표 기반 강화학습의 경우에도 함수 근사를 잘 할 수 있으면 도움이 되는데요
왜냐하면 우리가 표 기반 강화학습을 할 때는 이 표를 채우는데 이 칸을 채우는 것과 이 칸을 채우는 건 완전 별개거든요
함수 근사인 경우는 예를 들면 우리가 이렇게 기울었을 때랑 이렇게 기울었을 때는 이쪽은 좀 각도가 크고 이쪽은 많이 기울었어도 그림을 똑같이 그렸어요
확 기울여서 이 두 가지 경우 1번, 2번 이렇게 있으면 어쨌든 둘 다 뭡니까?
둘 다 오른쪽으로 가야 되죠
만약에 우리가 어떤 학습이 잘 되어 있다면 이 사례가 이 사례에 도움이 되고 이 사례도 이 사례에 도움이 됩니다
효율성이 증가를 하죠
내가 서로 다른 경험을 했지만 비슷한 경험은 비슷한 행동을 하는데 도움이 됩니다
표는 비슷하고 말고가 없어요
이 칸은 이 칸이고 이 칸은 이 칸이어서 서로 영향이 전혀 없습니다
굉장히 그냥 칸마다 경험이 쌓여야 돼서 굉장히 효율성이 떨어질 수 있는 거죠
그다음에 이런 함수 근사는 기본적으로 지도학습에서 굉장히 많이 연구가 됐고 머신러닝에서 여러분 서점에 가셔서 딥러닝 이런 거 책 보시면 다 지도학습입니다
그러니까 우리가 강화학습 문제가 굉장히 어려운데 거기다 더 어렵게 만드는 건 뭐냐면 강화학습은 책도 잘 없어요
찾아보시면 별로 자료가 없고 자료도 맨날 다 똑같은 소리밖에 없습니다
왜냐하면 사실 똑같은 책을 벗겨서 자료를 만들기 때문에 심지어 제가 수업에서 쓰는 그림들도 다 몇 권의 책에서 그냥 이렇게 뺏긴 거 있어요
보면 그래서 책들마다 그림도 다 똑같아요
서로서로 벗겨가지고 몇 권 안 되는데 자기들끼리 벗겨가지고 그래서 책도 별로 없습니다
문제는 강화학습 공부하려면 그게 힘든 거예요
자료도 없고 근데 함수 근사는 어차피 지도학습에서 나온 거라서 그냥 지도학습 공부를 하시면 이걸 잘 할 수 있거든요
그래서 괜히 어려운 강화학습보다 이것도 쉬운 건 아니지만 공부하기 좋은 지도학습을 쓸 수 있으니까 이걸 배워서 응용을 할 수 있다
근데 강화학습에서는 지도학습에 없는 굉장히 문제들이 여러 가지 있습니다
그래서 우리가 이번 시간부터 마지막 날까지 할 거는 결국에는 다 딥러닝으로 할 건데 딥러닝 지도학습에서는 문제가 안 되던 게 강화학습에서 문제가 되는 것들이 여러 가지가 있어요
그런 문제들을 어떻게 푸느냐
이런 얘기를 좀 해볼 겁니다
그래서 일반적으로 함수 근사는 다 딥러닝으로 하고요 요즘에는 죄 딥러닝입니다
다들 딥러닝으로 하게 되죠
딥러닝
그래서 딥러닝 얘기를 좀 드리면 딥러닝은 아마도 많이들 아시겠지만 기본적으로 어떤 인공신경망 뇌 구조에서 아이디어를 따온 건데 우리 뇌 보면 유런이라는 세포가 있는데요 이 세포가 이쪽에 자극을 받으면 자극이 약할 때는 그냥 움찔?
이러고 끝나는데 자극을 일정 이상 세기로 주면 얘가 액션 포텐셜이라는 거가 되면서 전기가 막 흐릅니다
실제로 이런 식으로 전기가 흐르는 건 아니고 소줌, 포타슘 채널이 열리고 어쩌고 저쩌고 하는데 어쨌든 전기가 흘러서 다음 세포로 신호가 전달이 돼요
그래서 둘 중에 하나입니다
흥분을 해가지고 전기를 내보내거나 가만히 있거나 그래서 우리 뇌를 열어보면 그런 세포들이 많이 있는데 이거를 뇌를 염색을 해보면 세포들이 골고루 섞여 있는 게 아니라 층 지어져 있거든요
이런 다층 구조가 되어 있습니다
그래서 AI 하는 사람들이 기본적으로 생물학 이런 걸 많이 참고를 해요
그래서 참고를 하는데 물론 완전 똑같이 가진 않습니다
왜냐하면 인공지능을 하는 사람들의 목적이 생물을 그대로 모방하는 게 목적이 아니고 하여간 좀 똘똘하게 일을 잘하는 게 목적이거든요
그래서 인간을 엄청나게 흉내내려고 하진 않아요
인간하고 비슷하거나 그러면 좋은데 인간보다 잘하는 게 좋겠죠
그래서 우리가 인공신경망을 만드는데 생물학적 신경망에서 영감을 받아가지고 만든 건데 똑같이 만들려는 게 목적이 아니라 아이디어만 가져왔는데 어떤 아이디어를 가져왔냐면 기본적으로 어떤 뉴런이 있으면 뉴런이 여러 개의 입력을 받아요
여러 개의 입력을 받고 그 입력에서 다 똑같은 영향을 받는 게 아니라 어떤 입력에는 좀 민감하고 어떤 입력에는 좀 둔감하고 차이가 있어요
그리고 그 입력 값이 어떤 스레솔드 문턱이 있어서 문턱을 못 넘기면 그냥 아무 일도 없는데 문턱을 넘기면 어떤 반응을 합니다
그래서 그런 어떤 핵심 요소들에 아이디어를 따와가지고 만들게 되고요 그 다음에 아까도 말씀드렸듯이 뉴런이 층을 이루고 있는데 그걸 모방해서 이렇게 다층 형태로 모델을 만들게 됩니다
그래서 우리가 딥러닝이란 말을 쓰는데 이게 딥이라는 게 깊이 있는 학습을 한다
이런 거라기보다는 모델이 구조적으로 여러 개의 레이어 층으로 이루어져 있다
이런 거가 됩니다
그래서 모델이 이렇게 여러 개의 층으로 구성이 되어 있으면 뭐가 좋으냐 하면은 그 얘기는 좀 있다 하고 그래서 딥러닝 이전 시대하고 이후 시대에 머신 러닝이 굉장히 방식의 차이가 있는데 사실 우리가 깊이 있게 연구하시는 분들의 얘기는 좀 다르지만 이걸 응용을 해서 뭔가 산업적 응용을 하려는 사람 입장에서는 훨씬 쉬워졌다고 할 수 있는데요
왜냐하면 딥러닝 이전에는 전문가가 어떤 이 데이터를 어떻게 처리할까 라는 걸 굉장히 깊이 고민을 해서 이 모델이 처리하는데 도움이 되는 어떤 특징들을 잘 추출을 해가지고 머신 러닝 알고리즘에 넣고 돌렸습니다
근데 딥러닝 이후로는 어떻게 됐냐면 그냥 데이터를 최소한의 처리만 해가지고 그냥 딥러닝 모델을 때려 넣어요
그럼 우리가 원하는 결과가 나옵니다
그러면 어느 쪽이 더 공부를 안 해도 되겠어요
이쪽이 더 안 해도 되겠죠
그냥 잘 모릅니다
그냥 다 때려 넣고 돌리니까 잘 되네
그래서 이런 거를 중단간 학습 영어로는 end to end running이라고 하는데 이쪽 end에서 이쪽 끝에서 이쪽 끝까지가 그냥 하나의 모델로 되어 있어서 내가 손댈 거가 없다
이거예요
그래서 원데이터를 거의 그대로 넣고 이것이 가능한 이유는 뭐냐면 여기 레이어가 굉장히 많거든요
그래서 이런 레이어들이 이 데이터에서 필요한 어떤 특징들을 스스로 이 데이터는 이런 특징을 봐야 되는구나
저런 특징을 봐야 되는구나
이런 걸 스스로 학습을 합니다
그래서 이제 우 리가 사람이 예전에 일일이 해 주던 것이 이제 별로 필요가 없다
이런 거고요 그다음에 이제 그러면 레이어를 이렇게 여러 개를 쌓아놓으면 이 레이어 하나하나는 수학적으로 어떤 굉장히 단순한 함수의 형태를 띕니다
이거는 단순한 함수인데 이거를 여러 개로 겹치면 어떤 특성이 생기냐면 단순한 함수가 합쳐져서 더 복잡한 함수가 되고 더 복잡한 함수가 합쳐져서 더 복잡한 함수가 되고 이런 식으로 돼요
그래서 제가 사이트 하나 보여드리면 텐서플로우 플레이그라운드 라는 사이트가 있거든요
그래서 여기 가보면 우리가 딥러닝을 하고 놀아볼 수가 있는데 왜 이런 걸 하고 놀아야 되는지
잘 모르겠지만 빨간 점이 있고 파란 점이 있으면 얘네를 구별하는 어떤 경계선을 함수 형태로 그리고 싶거든요
그럼 대충 원 비슷하게 그리면 되겠죠
그러면 이제 우리가 원의 방정식을 알아야 되잖아요
그걸 몰라도 예를 들어서 이렇게 레이어를 만들어 놓고 이 레이어 각각이 여러 개의 뉴런으로 구성되어 있는데 각 뉴런이 하는 일은 뭐냐면 여기 마우스를 얹어 보시면 이런 어떤 직선 형태의 경계선을 만들어 주는 역할을 합니다
여러 개의 경계선을 이렇게 만들 수 있겠죠
그래서 이 플레이 버튼을 누르면 얘네가 각자 자기 역할에 맞게 튜닝이 돼요
시간이 지나면 이렇게 동그란 경계선이 생기죠
다시 해보면 지금 오른쪽 화면을 한번 잘 보세요
경계선이 서서히 움직이다가 빨간 점과 파란 점을 구별하는 경계선이 만들어지죠
하얗게 하얀색 안쪽은 파란색 하얀색 바깥쪽은 빨간색 이렇게 되는데 지금 보시면 하나하나의 경계선을 다른 걸로 해야겠다 이 정도 경계선 하 나는 이런 경계선 이런 경계선 이런 경계선 이런 경계선 이렇게 경계선이 토막토막 만들어지고 그런 경계선이 이렇게 합쳐지고 이렇게 합쳐지고 해서 이거를 다시 조합을 하면 이런 경계선이 됩니다
단순한 함수들을 조합해서 더 복잡한 함수를 만들고 더 복잡한 함수를 만들어서 더 더 복잡한 함수를 만들고 이런 식으로 하면 아무리 복잡하게 생긴 함수라도 레이어를 충분히 많이 넣고 그 레이어의 뉴런들이 충분히 많이 있으면 뭐든지 대충 비슷하게 할 수 있다
그래서 이걸 보편 근사정리라고 하는데요
보편 뭐든지 근사 대충 비슷하게 할 수 있다는 걸 수학적으로 증명이 되어 있습니다
그래서 이제 우리가 요즘에 찻 GPT 이런 GPT 모형을 보면 굉장히 복잡한 계산으로 이루어져 있는데 분석을 해보니까 98%의 계산을 뭘 하는데 쓰냐면 실제로 어떤 복잡한 모형 특유의 뭔가를 한다기보다는 어떤 다른 함수 우리가 그 함수가 뭔지 모르지만 그 무언가의 함수를 근사하는 계산을 하는 데가 98%고 그 모형 고유의 어떤 설계와 관련된 계산은 한 2% 이 정도밖에 안 된다
이런 거죠
어떻게 보면 굉장히 비율적인 방식입니다
만약에 이걸 우리가 근사를 하지 않고 수학적 형태를 원래부터 알면 그냥 근사를 할 필요 없고 정확하게 그 함수를 계산하면 되겠죠
근데 그 함수를 모르니까 단순 함수를 계속 쌓아 올리고 쌓아 올리고 쌓아 올려 가지고 근사를 하는 건데 근데 이제 문제는 뭐냐면 그러면 우리가 수학적으로 그 함수 형태를 기술할 수 있냐 못 하니까 근사를 하는 거죠 할 줄 알면 했겠죠
근데 못 해서 이렇게 근사를 한다
이런 얘기가 됩니다
그래서 우리 딥러닝이 최근에 굉장히 많이 발전을 했는데 이게 이제 어떤 뭐 알고리즘 측면에서의 발전도 있었지만 사실 굉장히 중요한 게 빅데이터, 컴퓨터 성능이 빨라진 것 이런 것들의 역할이 굉장히 큽니다
그래서 우리가 엔비디아 같은 경우에 오늘 기사 보니까 주가가 엄청 떨어졌다고 하더라고요
걔네는 맨날 올라갔다가 폭락 폭등 반복하고 있는데 요즘에 AI 위기설 이런 게 나와 가지고 어디 뉴욕타임즈에 위기설 한번 씌웠다 폭락하고 MS가 주문했다 폭등하고 뭐 하는 건지 모르겠어요
어쨌든 이런 반조체 성능의 향상 이런 것들이 굉장히 큰 역할을 했고 그다음에 이제 우리가 이걸 잘 모르는 거를 어떻게 함수를 잘 짜맞춰 가지고 근사를 하는 거기 때문에 데이터가 되게 많이 필요합니다
근데 요즘에 데이터는 사실 남아 도는 시대들 예를 들면 여러분이 인터넷에서 고양이 사진을 찾고 싶다
그럼 고양이 사진 정말 수십억 장이 있습니다
어마어마하게 많은 고양이 사진이 있겠죠
그래서 우리가 강아지 고양이 이런 거 구변하는 거 이런 AI 만들기는 너무 쉽습니다
데이터가 너무 많기 때문에 근데 이제 강화학습은 문제가 뭐냐면 딥러닝이 잘 되려면 데이터가 많아야 된다는 건데 강화학습 입장에서는 그거는 최악이거든요
왜냐하면 지도학습은 그냥 인터넷이곤 데이터 긁어모으면 돼요
강화학습은 다 뭡니까
우리가 다 시행착오를 직접 해야 되는 거잖아요
몬테카를로, T.D. 정도 데이터가 많으면 잘 된다는 얘기는 시행착오를 많이 해야 된다는 얘기라서 별로 좋지가 않죠
그래서 오늘 수업에서 보면 계속 샘플링 이피션시 효율성 문제가 계속 얘기가 되는데 왜냐하면 강화학습 자체가 되게 비효율적인 학습 방식이라서 이 효율성 문제가 굉장히 중요합니다 비효율적이니까 더 효율성이 중요합니다
지도학습 같으면 좀 비효율적이기도 해요
왜냐하면 데이터 어차피 많으니까 그래서 빅데이터와 딥러닝의 관계가 굉장히 중요하다
빅데이터가 있어야 뭔가
딥러닝을 할 수 있다
이런 얘기고 이 얘기는 이제 넘어가고 그래서 요즘에 또 한 가지 이슈는 전이학습이라는 건데 우리가 이제 채 GPT 같은 경우에 GPT 하면 여기 가운데 이름에 P가 들어가는데요 이게 이제 프리 트레이닝 이란 뜻입니다
그래서 뭐냐면 우리가 학습을 시키는데 데이터가 이제 너무 너무 많이 필요해지고 모델도 너무너무 커져서 계산도 너무너무 많고 하여간 모든 게 다 너무너무 한 상태란 말이에요
그래서 일일이 데이터를 모아서 학습시키는 게 어렵다
그래서 어떻게 하냐면 굉장히 많은 데이터로 모델 하나를 사전학습을 시킵니다
그리고 얘를 개별 문제에다가 데이터를 조금만 써서 미세조정을 해요
그러면 우리가 만약에 사전학습 시킨 문제와 미세조정을 하는 문제가 비슷하다고 하면 이때 사전학습 하나 잘 해놓으면 미세조정을 조금만 해도 써먹을 수가 있을 겁니다
이걸 이제 전이학습이라고 하고 그래서 GPT 같은 경우에 얘하고 우리가 굉장히 다양한 종류의 일을 시킬 수 있는데 그 이유는 얘가 굉장히 방대한 데이터에 사전학습이 되어 있어서 그렇습니다
그러니까 강화학습에서도 전이학습을 하려고 하는 그런 시도들이 많이 있거든요
안 그래도 데이터를 비율적으로 쓰는데 매번 새로 학습 시켜야 되면 너무 손이 많이 가잖아요
그래서 예를 들면 로봇 강화학습이다 그러면 온갖 종류의 작업에다가 다 미리 사전학습을 시켜 놓고 원하시는 작업이 그래서 뭐예요?
이거 여기서 일로 옮기는 거예요?
아니면 뭐 드는 거예요?
이걸 조립하는 거예요?
그것만 조금 몇 번 해보면 그것도 할 수 있게 이렇게 하는 것이 현재 약간 방향성이라고 할 수 있겠죠
아직까지는 그렇게 잘 되고 있지는 않은데 기술 발전이 빠르니까 쉽게 되지 않을까 곧 되지 않을까 생각이 됩니다
아마 로봇 만들거나 이런 회사들이 다 그런 쪽으로 해줄 거예요
그래서 그렇고 그래서 우리가 전이학습을 시키면 조금만 미세 조정을 해도 성능을 굉장히 낼 수가 있기 때문에 활용의 난이도가 많이 떨어진다
그래서 사전학습된 모양을 가져다 쓰기만 하면 되는데 지도학습에서는 이쪽 방향으로 많이 가고 있습니다
그래서 지도학습은 사실 옛날에는 모델을 직접 만들고 데이터 다 모아서 직접 학습시키고 이랬는데 요즘에는 사실 그렇게 일반적으로 우리가 딥러닝 수업 하면 여전히 커리큘럼을 그런 식으로 하거든요
좀 의미 없다
생각이 좀 들어요
2,3년 전부터는 전이학습을 가르쳐야 하지 않나 이런 생각을 하는데 사실 또 문제가 뭐냐면 전이학습을 하면 할 게 없거든요
왜냐하면 다 만들어진 거 가져다가 쓰기만 하니까 약간 라면 끓이는 느낌이랄까요
그런 게 있습니다
그래서 전이학습 시키는 방식은 건너가고 그래서 우리가 딥러닝을 할 때 딥러닝 프레임워크가 필요한데요 왜냐하면 딥러닝이 계산이 많기 때문에 GPU를 써야 됩니다
GPU, 아까 말씀드린 엔비디아가 GPU 만드는 회사죠
딥러닝 모델을 정의를 하려면 딥러닝 모델도 구조가 여러 가지라서 정의를 직접 해야 되는데 그러면 여러 가지 요소가 필요합니다
그런 기능들이 필요한데 그걸 다 합쳐서 딥러닝 프레임워크라는 게 제공을 해요
대표적인 게 텐서 플로우가 있고 파이터치가 있고 기타 등등이 있습니다
그래서 보통은 그냥 뭘 배우시면 되냐면 나는 잘 모르겠다 그러면 그냥 파이터치를 배우시면 됩니다 현재로서는 이게 제일 추천입니다
강추까지는 아니고 개인적으로 별로 좋아하진 않는데 이걸 배우시는 게 제일 유용할 가능성이 커요
텐서 플로우도 많이 쓰고 실제로 많이 쓰고 기업용 기능도 많아서 실제로 체험 공고 같은 데 보면 텐서 플로우도 많고 이런데 텐서 플로우가 문제가 뭐냐면 학자들이 파이터치를 많이 써요
왜냐하면 파이터치가 새로운 모델 개발하기가 좋습니다
그래서 알아두시면 좋은 사이트 중에 papers with code 라는 사이트가 있거든요
이 사이트가 뭐가 좋냐면 최신 논문들이 여기 올라오고 그 다음에 이 논문에 별이 몇 개 찍혔냐
이 논문 페이퍼가 뭐냐
그 다음에 코드를 누르면 그 코드를 어디서 받을 수 있는지 링크를 다 모아놨거든요
여기 오른쪽을 보시면은 파이터치가 많습니다
보통 파이터치에요
그래서 우리가 이걸 다 일일이 코딩하고 있자면 귀찮잖아요
근데 남이 만들어 놓은 코드 보통 이런 거는 기법을 만든 저자들이 직접 짠 코드가 많기 때문에 제일 정확하겠죠
그게 설마 논문 쓴 본인이 코드를 틀리지는 않았을 거 아니에요
그런 경우도 가끔 있습니다만 근데 그 사람이 틀렸을 수도 있지만 우리가 그 논문 보고 작성하면 더 틀릴 가능성이 높겠죠
사실 그냥 이런 코드를 쓰는 게 제일 이상적인데 이런 코드를 구해서 그냥 돌리 면 되기 때문에 그래서 이제 파이터치로 하시는 게 대부분 남들도 파이터치 쓰니까 최신 모델을 쓰고 싶으면 나도 파이터치를 쓰는 것이 제일 속편하다
이런 거고 지금도 보시면 이제 최신 지금 가장 핫한 사람들의 관심을 많이 받는 논문인데 보면은 이것도 파이터치죠
그리고 이것도 뭐 언어모델 이런 것들 이것도 파이터치고 이것도 뭐 비전인데 이것도 파이터치고 최파이터치입니다
이거는 프레임업 가능 이것도 파이터치고 이것도 파이터치고 그냥 파이터치를 쓰시면 내가 사실 정확하게 쓴다고 나는 돌릴 줄만 아시면 돼요
남이 만든 모델을 가져서 돌리지만 안 되고 사실은 이제 이런 코드에 가보면 보통 어떻게 돌리는지 되게 친절하게 써놓거든요
이렇게 설치를 해가지고 이런 식으로 해서 예를 들면은 CPU에서 돌리려면 이렇게 해라
굉장히 사람들 착합니다
이렇게 하고 뭐 GPU 없어도 잘 돌아간다
근데 메모리는 좀 있어야 된다고 다 써놓으니까 시켄대로 하면은 보통 되거든요
그래서 사실 약간 아이러니한데 딥러닝만큼 그냥 잘 몰라도 대충 할 수 있는 분야가 잘 없습니다
그래서 파이터치를 추천드리고 우리도 파이터치를 할 거예요
파이터치 자체를 깊이는 못하고요 우리 딥러닝 수업은 아닙니까
약간 돌릴 수 있는 수준으로 그 다음에 오늘 약간 기초 맛보기 정도로 해볼 겁니다
그 다음에 GPU는 뭐냐면 원래는 그래픽 처리 장치라는 건데 기본적으로 게임 같은 거 할 때 컴퓨터 그래픽 처리하던 칩인데 이 특징이 뭐냐면 단순 계산을 병렬로 실행을 합니다
계산들이 여러 개가 있으면 여러 개를 순서대로 하면 시간이 많이 걸리니까 동시다발적으로 하는 거예요
이게 가능한 이유가 기본적으로 컴퓨터 그래픽하고 딥러닝은 전부 행렬의 곱셈을 많이 하는데 행렬의 곱셈이라는 게 행렬 두 개가 이렇게 있으면 요 행하고 요 열하고 곱하고 요 행하고 요 열하고 곱하고 그래서 더하고 이런 식이잖아요
그러면 요 행하고 요 열을 곱할 때는 1번 행하고 1번 열을 곱할 때는 2번 행은 상관없어요
그러면 그 시간에 노는 이 2번 행하고 2번 열하고 곱하고 앉아있으면 되겠죠
서로 계산이 별로 상관없는 계산이 많기 때문에 한 계산하고 있는 동안 놀지 말고 다른 계산도 하고 동시다발적으로 하면 더 빨리 할 수 있습니다
그래서 최신 GPU는 코어가 몇 만 개 수준이라서 동시에 계산을 몇만 개를 할 수가 있거든요
CPU는 코어가 많다고 해봐야 10개 진짜 많으면 한 60개 이 정도거든요
그러니까 속도 차이가 엄청나게 많이 납니다
몇 백 배가 차이가 나는 거죠
그래서 GPU를 쓰는 것이 중요하다
PyTorch 설치
이런 거고 그래서 설치하는 방법은 운영체제 따라 다르고 GPU 따라 다르고 뭐 이런데 사실 여기 파이토치 홈페이지에 가시면 파이토치 홈페이지에 가시면 여기 이제 Get Started, 시작하기라고 있고 여기 가면은 자기 파이토치 버전이랑 운영체제, 언어랑 그 다음에 계산 어디 살지
이런 걸 골라라
이렇게 되어 있거든요
그래서 우리가 이제 뭐 별로 건드릴 건 없겠죠
스테이블 버전의 윈도우용의 PIP에 파이선하고 그 다음에 여기 보시면 CUDA라고 있는데 CUDA가 뭐냐면 GPU에서 계산 돌릴 때 필요한 거예요
그래서 CUDA는 또 따로 설치를 해주셔야 되거든요
근데 이거는 설치하기가 굉장히 복잡합니다
엔비디아 홈페이지에 가서 CUDA랑 CUDNN도 다운받아야 되고 이게 가입도 해야 되고 약간 뭐 엄청 어려운 건 아닌데 좀 귀찮아요
그래서 우리는 그냥 CPU 버전으로 깔겠습니다
pip install torch torchvision
설치 문제시
설치 후 임포트에 문제가 있으면 버전을 낮추면 된다.
언인스톨:
pip uninstall torch torchvision
이전 버전 설치:
pip install torch==2.3.0 torchvision==0.18.0
임포트
import torch
import torch.nn as nn
import torch.optim as optim
from torchvision import datasets, transforms
from torch.utils.data import DataLoader
MNIST 데이터
그래서 요거를 이제 데이터를 받아야 되는데 파이토치에서 이 데이터를 바로 받을 수 있는 기능이 있거든요
데이터 앱 리스트 이러면은 요 데이터를 다운로드를 자동으로 받아줍니다.
다운로드 트루 다운로드 트루 이렇게 되있죠
요것도 사이트에 있으니까 복사해 가지고 쓰시면 데이터를 자동으로 다운로드를 해줍니다
그래서 실행을 해보시면은 그 처음에 이제 이 얀루쿤 딥러닝 분야에 엄청 유명하시는데 이분 홈페이지에서 다운받으려고 하는데 홈페이지가 얼마전부터 안되더라구요.
다운이 안되면 그럼 이제 다른 사이트에 가서 똑같은 파일을 다운받습니다.
똑똑하죠?
그래서 파일을 4개를 다운받습니다
그래서 이제 왜 4개냐 하면은 이미지하고 정답 근데 그게 트레인 버전과 테스트 버전이 있어서 버전이 2개에요
그래서 이제 2 곱하기 해가지고 총 4개의 파일을 다운받습니다.
다운은 금방 될거에요
transform = transforms.ToTensor()
train_dataset = datasets.MNIST(root='./data', train=True, download=True, transform=transform)
test_dataset = datasets.MNIST(root='./data', train=False, download=True, transform=transform)
train_loader = DataLoader(train_dataset, batch_size=64, shuffle=True)
test_loader = DataLoader(test_dataset, batch_size=64, shuffle=False)
여기 i번째 이미지 그러면은 여기 정답은 오고 그림이 작게 나오는데요.
이게 가로 28 세로 28이라서 이미지가 별로 크지가 않습니다.
이렇게 5라고 나오고 숫자 5가 되죠
다른 이미지도 보고 싶으시면은 여기 i를 바꿔보시면 되요
그래서 1번 이미지가 숫자 0이고 이렇게 써요
2번이 이렇게 보면 숫자 4하고 회골은 이렇게 생겼습니다
그래서 여러개로 해보시면 되겠구요
그래서 이제 이런 이미지가 몇개가 있냐면 트레인 이미지가 6만개 트레인 이미지가 6만개 입니다.
그래서 이제 이런 이미지가 몇개가 있냐면 트레인 이미지가 6만개 입니다.
그래서 이 이미지가 몇개일까?
그래서 이제 이런 이미지가 몇개가 있냐면 트레인 이미지가 6만개, 테스트 이미지가 만개 이렇게 있습니다.
그래서 6만개로 트레이닝을 한 다음에 전혀 다른 이미지 만개로 테스트를 해서 성적을 체크를 하는 문제 이 mlist 핸드레이징 데이터의 최고 성능은 99.98%인데 왜 100%가 아니냐 하면은 0.02%가 라벨이 잘못 붙어 있거나 아니면 글씨를 너무 이상하게 써서 아무도 못 알아보는게 만개 중에 두개가 있습니다
도대체 이 숫자가 왜 그 답인지 아무도 모르는 게 몇개 있어요
그래서 그거는 절대 맞출 수가 없습니다.
맞추면 약간 이상한 거죠
그래서 두 가지 추측인데 레이블이 잘못 붙었다라는 추측과 4번을 쓰라고 했는데 7을 썼다든지 이런거라든지 설과 아니면 그냥 너무 악필이다
이런 설이 있는데 어쨌든 아무도 못 알아보기 때문에 사람도 못 알아보는 걸 뒷러닝에 맞추는 것도 좀 이상하죠
이게 뭔 글자예요?
약간 이런 게 몇개 있습니다
그래서 사실 현재로서는 거의 100%라고 할 수 있어요
그래서 이 정도 문제는 지도학습으로 100% 하는 시대가 됐다 우리도 해볼 건데 뭐 우리도 한 97, 98% 정도 나올 겁니다.
별로 어렵지 않아요
근데 이제 한 20년 전에 이걸 97, 98%로 했으면 AI 천재 이런 소리를 들었을 텐데 기술이 발전하니까 그냥 뭐 아무렇지도 않게 한 시간만 배우면 할 수 있습니다
from PIL import Image
i = 0
img, label = train_dataset[i]
img = img.squeeze().numpy() * 255
img = img.astype('uint8')
print(label)
Image.fromarray(img)
5
<PIL.Image.Image image mode=L size=28x28>
모형 정의
그래서 이제 우리가 모형을 만들 건데 파이토치에서 모형을 만드는 방법은 이때까지 많이 했던 것처럼 클래스를 정의를 해요
그래서 우리가 이제 이 딥러닝 모델이라는 거는 다 기본적으로 이렇게 여러 개의 레이어로 구성이 되어 있거든요
그래서 이 레이어들을 정의를 해줍니다
FC1, FC2, FC3 이렇게 레이어를 정의를 해주고요 이제 각각의 레이어는 어떤 모양을 가지고 있느냐 이 그림 자체가 이렇게 있으면 가로 28, 세로 28로 된 이미지예요
그래서 이 이미지를 이루는 점의 개수가 28 곱하기 28 하면 784개인가요?
그렇게 되겠죠?
계산하기 귀찮으니까 그냥 228 곱하기 28 하면 그거는 컴퓨터가 계산을 해줄 거고 그래서 그런 입력을 받아서 뭔가 출력을 할 겁니다
여기 이미지가 들어가면 이미지가 들어가면 뭔가 출력을 할 건데 이 딥러닝 모델은 이 출력의 개수가 몇 개에 든 상관이 없어요
최종 출력만 중요합니다
최종 출력만 중요하기 때문에 이거는 우리 마음대로 하면 됩니다
우리는 일단 128개로 할 건데 10개로 하셔도 되고 5개로 하셔도 되고 128개로 해도 마음대로 해야 됩니다
이 출력이 많다는 거는 뭔가 복잡한 우리가 다양한 특징을 추출을 할 수 있다는 거기 때문에 대체로 좀 유리하긴 해요
근데 너무 많으면 또 항상 그렇지만은 아까 우리 과적합 얘기를 드렸죠
너무 쓸데없는 특징을 또 뽑으면 쓸데없는 과적합이 될 수가 있습니다
그래서 이제 이건 적당한 개수를 해야 되는데 적당한 게 어떻게 안 되냐?
나중에 테스트 해보면 안 됩니다
테스트 했는데 성능이 안 나온다
그럼 너무 많이 하거나 너무 적게 한 거예요
조금씩 바꿔보시면 되고 우리가 이제 28 곱하기 28개의 입력이 들어가면 128개의 출력이 나오는 레이어가 하나 있고요 이 레이어가 FC1입니다
그다음에 FC2는 128개의 입력이 들어가서 64개의 출력이 나오는 레이어예요
그리고 마지막으로 FC3는 64개의 입력이 들어가서 10개의 출력이 나오는데 이 숫자는 고정입니다
왜 이때까지 네 마음대로 하다가 이것만 고정이냐?
왜냐하면 손글씨가 0에서 9까지 10종류밖에 없기 때문에 출력은 10개가 나와야 돼요
그래서 어떻게 되냐면 0에서 9까지 각각의 숫자의 확률들이 나옵니다
숫자 0일 확률 몇 프로 숫자 1일 확률 몇 프로 숫자 1일 확률 몇 프로 그러면 만약 그 숫자가 정답이 4다
그럼 4일 확률이 제일 높고 나 머지는 확률이 거의 0에 가까운 이런 형태가 돼야 가장 이상적인 학습을 했다고 볼 수 있겠죠
그 다음에 여기 Ford라는 함수가 있는데요 이 Ford는 뭐냐면 어떤 X 즉 이미지가 들어왔을 때 우리가 정의한 레이어들 있잖아요
그 레이어를 어떤 순서대로 통과하게 할 거냐
이거를 정의하는 대목입니다
그래서 처음에 X view-2828 이렇게 하는 게 그 레이어를 정의하는 데에 따라서 그 레이어를 정의하는 데에 따라서 그 레이어를 정의하는 데에 따라서 그 레이어를 정의하는 데에 따라서 그리고 마이너스 2828 이렇게 한 게 있는데 잠깐만요 됐다 이거는 뭐냐면 우리가 지금 가로 28 세로 28이라서 그림이 이런 형태로 돼 있는데 사각형 형태로 돼 있는데 이거를 지금 가로 28 세로 28 이 형태에서 1 곱하기 784 이런 형태로 바꿀 거예요
점의 개수는 똑같거든요
이렇게도 784개고 이렇게도 784개인데 이 형태로 왜 바꾸느냐 그러면 우리가 학교 낼 때 왜 벡터라고 배우잖아요
그러니까 매트릭스 형태인데 지금 벡터 형태로 바꾸려는 겁니다
그럼 왜 바꾸느냐 이 리니얼한 레이어가 사실은 핵렬하고 벡터의 곱을 해주거든요
그래서 곱해지는 쪽이 벡터 형태여야 돼요
모양상 그래서 이거는 사실 수학적으로 의미 있는 변화는 아니고 그냥 레이어가 하는 계산 모양에 맞춰서 그냥 맞춰주는 겁니다
아니 뭐 수학적으로 왜 의미가 없냐
이렇게 생각하실 수 있는데 숫자를 예를 들면 1, 2, 3, 4 이렇게 쓰든지 한 줄로 1, 2, 3, 4 이렇게 쓰든지 어차피 같은 숫자잖아요
배열만 바뀌었을 뿐이지
그래서 이거는 무조건 해주는 거라고 생각을 하시면 될 것 같고요 그래서 우리가 모양을 평평하게 만든 다음 에 벡터로 만든 다음에 이 X를 FC1에 넣어요
그래서 마치 함수 호출하듯이 과로해서 넣으시면 됩니다
그 결과를 RELU라는 함수에 넣습니다
RELU가 뭔지는 좀 이따 얘기 드리고요 그래서 다시 X에 덮었어요
그래서 FC1을 통과했죠
여기를 통과했습니다
이렇게 통과했고 그다음에 FC2를 통과해서 RELU를 거쳐서 다시 나옵니다
여기도 통과했죠
마지막으로 FC3을 통과한 다음에 그 다음에 그냥 리턴을 합니다
이걸 레이어를 순서대로 통과시킨 거예요
중간중간 RELU라는 것도 하나씩 통과를 시키고 그렇게 하면 출력이 됩니다
그럼 이제 우리가 이렇게 모양을 정의했는데 이미 다층입니다
레이어가 여러 개 있죠
레이어를 더 많이 만들면 모델의 성능이 더 올라갈 수 있습니다
만약에 돌려보고 성능이 좀 안 나온다
이런 레이어를 한 줄 더 복사해서 몇 개 더 추가하면 되겠죠
물론 그렇게 한다고 성능이 다 잘 오르는 건 아닌데 오를 수도 있고 아니면 안 오를 수도 있고 그래요
그래서 이걸 그림으로 그리면 이런 식인데 우리가 원의 갯수를 좀 적게 썼지만 이쪽으로 입력이 들어갑니다
그럼 이게 이미지가 되고요 이 하나하나는 이미지를 이루는 픽셀들의 해당이 되겠죠
이미지의 픽셀을 입력으로 봤고요 픽셀이 밝으면 여기 큰 숫자가 들어가고 픽셀이 어두우면 여기 어두운 숫자가 들어갑니다
보통 0에서 1 사이로 들어가거나 아니면 전천의 방식에 따라서 마이너스 1에서 플러스 1 범위의 숫자가 들어가는데 0에서 1까지이면 0이 검은색이고 1이 흰색입니다
그래서 밝을수록 숫자가 커져요
그러면 첫 번째 레이어를 거치면 128개의 출력이 이 렇게 나오겠죠
얘네를 가지고 얘네는 예를 들어 3이다
그러면 이게 어떤 부분적인 특징들로 이루어져 있잖아요
이 부분적인 특징들을 찾아내는 겁니다
그리고 그걸 가지고 64개의 특징들 예를 들어 3이다
그러면 이거랑 이런 특징이 있고 이런 특징이 있으면 얘네를 조합하면 이런 게 되겠죠
그리고 이런 특징이 있고 이런 특징이 있으면 조합하면 이런 게 되겠죠
이 두 개를 조합하면 이런 게 되겠죠
이런 식으로 부분 부분을 모아서 점점 더 큰 특징을 만들어 간다
이렇게 생각하시면 됩니다
실제로 이렇게 한다는 건 아닌데 느낌상 그런 느낌입니다
그래서 마지막에는 10개의 출력을 하게 되는 거죠
그래서 이런 거를 Linear Layer, Fully Connected Layer 또는 Dance Layer 이렇게 부르는데 모든 입력이 모든 출력에 다 영향을 미치는 그런 구조입니다
이 입력도 모든 출력에 영향을 미치고 이 입력도 모든 출력에 미치는데 이 선 하나하나가 영향을 미치긴 하지만 같은 정도로 미치는 건 아니고 어떤 선은 많이 영향을 미치고 어떤 선은 적게 영향을 미치고 그렇습니다
예를 들면 숫자 0이 있고 숫자 1이 있으면 0 같은 경우는 보통 가운데가 비었으니까 가운데가 까만색일 가능성이 커요
그러면 가운데에 있는 픽셀들은 숫자 0에 기여하는 바가 별로 없겠죠
근데 숫자 1 같은 거는 가운데 픽셀을 거의 반드시 지나가니까 여기가 밝으면 1일 가능성이 커지는 겁니다
그래서 픽셀마다 어떤 결과에 더 영향을 미치는 픽셀이 있고 적게 미치는 픽셀이 있어요
그래서 그런 것들을 학습을 해야 되는데 우리가 앞에서도 봤듯이 문제가 복잡해지면 이렇게 직선 하나로 나눌 수 가 없고 이렇게 직선 두 개를 조합을 해서 좀 더 복잡한 모양을 만들어야 됩니다
그래서 우리가 복잡한 모양을 만들어서 이런 식으로 하나의 직선으로 표현할 수 없는 이런 형태를 비선형이라고 하고 그런 비선형으로 함수를 만들어야 되는데 이거는 넘어가고요 그래서 다층 신경망을 이용해서 이런 걸 할 수 있다
class SimpleNN(nn.Module):
def __init__(self):
super(SimpleNN, self).__init__()
self.fc1 = nn.Linear(28*28, 128) # 은닉층 1
self.fc2 = nn.Linear(128, 64) # 은닉층 2
self.fc3 = nn.Linear(64, 10) # 출력층
def forward(self, x):
x = x.view(-1, 28*28) # 모양을 평평하게
x = torch.relu(self.fc1(x)) # ReLU 활성화 함수로 비선형성을 추가
x = torch.relu(self.fc2(x))
x = self.fc3(x)
return x
활성화 함수
이런 얘기고 그래서 기본적으로 리니어 레이어는 이름부터가 리니어 선형입니다
선형 레이어를 아무리 조합해도 그것만으로는 비선형이 되지 않아요
그래서 중간에 렐루가 아까 들어갔잖아요
리니어를 거쳐서 렐루를 거친 다음에 그 다음 리니어에 들어가고 이렇게 되는데 이 렐루가 하는 역할이 뭐냐면 이런 함수들을 활성화 함수라고 해서 비선형성을 도입해 주는 역할을 합니다
우리가 신경망, 뉴런에서도 보면 어떤 자극이 이렇게 들어오다가 자극이 좀 많이 들어오면 푹 하고 올라가는 이런 식으로 반응을 하는데 이제 이 렐루라든가 이런 활성화 함수가 하는 역할이 그런 어떤 비선형적인 패턴을 나타내게 하는 거예요
그래서 이제 가장 기본적인 함수 중에 하나가 시그모이드 라는 함수인데요 이 시그모이드는 어떤 마이너스 무한대에서 플러스 무한대까지의 범위를 가져서 숫자가 입력되는 값이 작아지면 작아질수록 0으로 가고 입력되는 값이 커지면 커질수록 1에 가까워지는 그런 특성을 가진 함수입니다
그래서 이걸 거치면 이렇게 S자로 휘어진 출력을 하게 되는데 이거를 우리가 주로 어떨 때 사용을 하냐면 뭔가 확률 예측을 할 때 많이 사용을 해요
왜냐하면 확률이라는 건 0에서 1 사이기 때문에 이 함수를 한번 거치고 나면 어떤 숫자든지 확률로 바꿀 수가 있습니다
이걸 이름을 시그모이드 라고 하는데 사실 정확한 이름은 로지스틱 함수고 시그모이드는 무슨 뜻이냐면 시그마가 그리스 문자로 이건데 지금 우리가 이렇게 S로 쓰는 거의 기원입니다
그리고 오이드는 뭐뭐를 닮은 이런 뜻이에요
그래서 안드로이드 스마트폰의 로고를 보시면 이렇게 생겼죠
이렇게 뚱뚱한 팔다리 닮았고 사람처럼 생겼잖아요
안드로가 사람이고 오이드가 닮은 사람 닮은 로봇 이란 뜻이에요
그다음에 여러분 잘 아시는 스테로이드 이것도 스테롤이라는 화학 물질이 있습니다
그걸 닮은 체내 물질이라고 해서 스테로이드 그래서 다 오이드가 붙으면 대충 비슷한 이런 뜻이고 S자 닮았다고 해서 시그모이드라고 부른데 이거 별자리도 아니고 이게 어딜 봐서 S자를 닮았는지 잘 모르겠습니다
어쨌든 S자로 닮았다고 하고 사실 이렇게 생긴 함수가 얘만 있는 게 아니라서 얘만 시그모이드라고 부르는 건 좀 불공평해요 사실 엄밀히 말하면 시그모이드 중에 하나라고 할 수 있는데 딥러닝 하는 사람들은 일을 대충대충 하는 경향이 있어서 이걸 다 그냥 시그모이드라고 부릅니다
그래서 정확한 이름 따위 아무도 신경 안 쓰는 거죠
그래서 이 시그모이드 함수를 은닉층 그러니까 레이어와 레이어 사이에다가 끼워 넣으면 이런 데다가 이렇게 끼워 넣으면 문제가 좀 있는데 뭐가 문제냐면 포하랑 중심이 0이 아닌 문제가 있어요
포하는 뭐냐면 양쪽 끝이 이렇게 평평하거든요
뒤에도 얘기 드리겠지만 이 신경망에서 우리가 어떤 픽셀이 어디에 영향을 주는지 그거를 파라미터라는 수치로 표현을 하는데 그 수치를 어떻게 찾냐면 파라미터가 있으면 이 파라미터를 잘 조절을 해보면 오차가 이렇게 줄어들다가 오차가 더 이상 줄지 않는 점이 있습니다
그럼 이때가 파라미터의 최적값이거든요
그래서 어떤 파라미터일 때 경사를 재봐요 미분을 해서 경사를 재면 경사가 이쪽 방향으로 있으면 파라미터를 이쪽으로 옮기면 되고 경사가 이렇게 되어 있으면 파라미터를 이쪽으로 옮기면 됩니다
그럼 이리로 가겠죠
그래서 이걸 경사하강법이라고 하는데 우리 이 경사하강법 얘기는 어제 한 번 했었죠
경사상승법을 한다
강학습에서 그때는 강학습은 보상을 최대화해야 되니까 경사상승법을 쓰고 보통 지도학습은 오차를 줄여야 되니까 경사하강법을 씁니다
그럼 어쨌든 상승을 하든 하강을 하든 그 경사 기울기가 있어야 되는데 얘네들은 보시면 이 그림을 보시면 기울기가 없어요 양쪽 끝이 평평합니다
그래서 이런 애들이 중간에 이렇게 끼어 있으면 눈치없이 중간에 끼어 있으면 얘네가 평평해가지고 기울기가 없으니까 얘를 학습을 시킬 수가 없어요
왜냐면 오차는 이쪽에서 생기거든요
우리가 데이터를 이렇게 넣으면 데이터를 이쪽으로 입력을 하면 이쪽에 출력을 하는데 출력을 해야 뭔가 오차가 생기잖아요
중간에 이렇게 평평한 애들이 끼어 있어가지고 파라미터나 어떤 출력 부분이 여기에 들어가 있으면 상관없는데 이런 데 나오면 경사가 없으니까 오차를 줄일 수가 없어요 이리로 가도 오차가 비슷하고 물론 약간의 경사는 있죠
하지만 이리로 가나 이리로 가나 오차가 비슷하니까 이걸 수정을 할 수가 없는 거죠
컴퓨터에서 숫자가 너무 작아지면 그냥 다 0이나 마찬가지거든요
그래서 이런 거를 사라지는 경사 이렇게 얘기하는데 경사가 없어져서 우리가 학습을 할 수 없다
이런 문제가 있고 그 다음에 중심이 0이 아니라는 건 뭐냐면 이 그래프가 0에서 1 사이로 가지고 무조건 출력값이 플러스입니다
그래서 미분을 하면 기울기가 또 다 플러스로 나오는 그런 문제가 생겨요
그래서 쭉 하면 부호가 다 똑같기 때문에 그 파라미터들이 있을 때 어떤 거는 기울기가 플러스고 어떤 거는 기울기가 마이너스여야 늘릴 건 늘리고 줄일 건 줄이고 이렇게 할 수 있는데 동시에 다 늘리거나 동시에 다 줄이거나 이렇게밖에 못해요
그래서 하나는 늘리고 하나는 줄여야 되면 어떻게 하면 되냐면 한 스텝에서는 얘만 늘리고 그 다음 스텝은 얘만 조금 늘렸다가 그 다음 스텝에서는 얘는 반대로 조금 줄이고 얘를 줄이면 두 스텝에 걸쳐서 얘는 결과적으로 많이 늘리고 조금 줄였으니까 요만큼 늘어날 거고 얘는 조금 줄이고 많 이 줄였으니까 뭐 이렇게 되겠죠
한 스텝으로 하려면 될 일을 두 스텝으로 해야 되니까 학습 속도가 굉장히 느려지게 됩니다
그래서 여러 가지 활성화 함수들이 나오게 되는데 옛날에는 쌍국탄젠트라는 함수를 많이 썼어요
얘도 생긴 모양은 똑같이 생겼는데 범위가 마이너스여서 플러스 1까지입니다
그래서 문제 중에 하나는 없앤 거죠
제로 센터드로 바꿨으니까 두 번째 문제는 해결을 한 건데 첫 번째 문제는 어차피 얘도 양쪽 끝이 평평한 건 똑같아서 해결이 안 됩니다
포함 문제가 똑같고 그러다가 이제 렐루 라는 함수가 나오는데 이 렐루는 굉장히 간단한 함수인데요 0을 기준으로 해서 입력값이 음수면 무조건 0이 나가고 입력값이 양수면 그대로 출력으로 나갑니다
X가 0보다 크면 출력값이 X랑 똑같아요
그래서 얘는 이제 제로 센터드는 안 되죠
똑같이 무조건 플러스로만 나옵니다
근데 기울기가 시그모이드는 이쪽도 평평하고 이쪽도 평평한데 그래도 얘는 한쪽만 평평하죠 이쪽은 안 평평하니까 그래서 확률상 절반은 다 기울기가 있으니까 거기다 심지어 기울기가 일정하니까 학습이 오히려 더 잘 됩니다
그래서 중간에 은닉층에 끼워 넣을 때는 보통 이 렐루를 써요
근데 몇 가지 단점이 있는데 여기 경사가 이쪽이 다 0이라서 시그모이드는 좀 0 근처이기라도 하지 얘는 그래도 기울기가 좀 있잖아요
얘는 아니지만 기울기가 0이란 말이에요
완전 수학적으로 용입니다
그래서 요즘에는 이렇게 완전히 평평한 거 안 쓰고 약간 이렇게 휘어있다든가 L루 이런 거 아니면 이렇게 간 다음에 약간 기울기를 준다든가 리퀴레 루 이런 식으로 약간 변형이 있습 니다
근데 우리 수업에서는 그냥 렐루 정도만 써도 잘 되기 때문에 굳이 이런 걸 쓰지는 않을 거고요
이런 식으로 중간에 은닉층을 끼워 넣는다
교차 엔트로피
그래서 교차의 트로피를 일단 얘가 뭘 하는 거냐.
손실을 계산을 하는 거예요.
또는 오차를 계산하는 거예요.
조금 더 한 단계 더 깊게 얘기하면 엔트로피 라는 게 무질소도인데 무질소라는 거는 방에 여러분이 예를 들면 옷을 정리해 놓는데 옷을 한 대다
이렇게 딱 쌓아놓고 나머지는 깨끗해야 정리가 돼 있는 거지.
옷이 여기도 한 덩어리 여기도 한 덩어리 여기도 한 덩어리 여기도 한 덩어리 이렇게 있으면 무질서한 거잖아요.
이건 무질서한 거고 이건 질서 정연한 거죠.
그러면 질서 정연하다는 거는 혼란이 낮은 거죠.
무질서한 거는 혼란이 높은 거죠.
교차 엔트로피라는 건 혼란을 측정을 하는 건데 결국 이 혼란이 손실이자 오차입니다.
그래서 이렇게 돼 있으면 혼란하지 않고 그러면 손실이 적고 오차가 적은 거고 이렇게 돼 있으면 무질서한 거고 혼란스러운 거고 손실이 크고 오차가 큰 겁니다.
그래서 우리가 정답이 예를 들면 4번인데 그럼 4번만 확률이 이렇게 불뚝 높아야지 4번도 높고 5번도 높고 6번도 높고 7번도 높고 이런 상황이면 안 된다.
교차 엔트로피는 그거를 측정을 하는 겁니다.
그래서 수식으로 보면 결국에는 사실 되게 간단한데 우리가 이제 y가 정답인 데는 1이고 정답이 아니면 0이 돼요.
그 얘기는 뭐냐면 정답이면 여기가 1이라는 거는 그냥 1 곱하기 뭐 하면 이거만 남는 거잖아요.
0이면 0 곱하기 이거 하면 이건 그냥 없어지는 거잖아요.
결국 로그 y 핫 이렇게 되는 건데 이 y 핫은 뭐냐면 우리가 이제 모델이 확률을 출렁하기 때문에 확률 값이 됩니다.
근데 로그함수가 어떻게 생겼냐면 로그함수는 이렇게 생겼어요.
이렇게 생겼는데 여기가 0이고 여기가 여기 교차하는 지점이 1입니다.
그래서 확률이라는 거는 0에서 1 사이기 때문에 사실 이 위쪽은 우리랑 해당 사항이 없고 여기 밑에만 해당 사항이 있어요.
근데 앞에 마이너스를 붙여놨기 때문에 이게 그래프가 뒤집힙니다.
그 얘기는 뭐냐 사실 별 얘기도 아닌데 이쪽으로 가면 확률이 올라가는 거잖아요.
확률이 올라가면 교차엔트로피는 떨어집니다.
그래서 별 얘기가 아닌 게 우리가 정답이 4번이면 4번의 확률이 올라가면 교차엔트로피가 떨어진다는 얘기예요.
경사하강법
그런 거고 교차엔트로피는 얘기는 길었지만 결국 정답의 확률이 높으면 교차엔트로피가 떨어진다.
그래서 우리가 손실을 감소시킨다는 건 결국 뭐냐면 정답의 확률을 높여준다.
이런 얘기입니다.
그래서 우리 손실을 감소를 시켜야 되는데 어떻게 감소시키냐.
우리가 계산을 한단 말이에요.
계산에 들어가는 수치들이 있고 그 수치를 파라미터라고 합니다.
이 파라미터를 잘 잡아주시면 되는 건데 오늘 아침에 다 씻고 나오셨죠.
샤워기로 뜨거운 물을 트셨을 건데 보통 샤워기가 구조가 요즘에 어떻게 돼 있냐면 어떤 밸브가 하나 있어서 이 밸브를 왼쪽으로 돌리면 뜨거운 물이 나오고 오른쪽으로 돌리면 찬물이 나오는데 이 사이에서 온도가 결정되는 거죠.
그래서 이 가로방향은 주로 온도를 결정하고 위로 하면 물이 좀 세게 나오고 밑으로 하면 물이 좀 약하게 나오고 그래서 이 세로방향은 강도를 결정합니다.
그래서 샤워기는 파라미터가 두 개가 있는 거예요.
온도를 결정하는 파라미터, 가로방향, 강도를 결정하는 파라미터, 세로방향.
그럼 여기에서 내가 밸브를 여기다 놓으면 차갑고 세게 나오는 거고 여기다 놓으면 뜨겁고 약하게 나오는 거죠.
그래서 여러분들이 처음에 여기서 시작을 해서 어떻게 하냐면 보통 처음에 보일러를 작동시켜야 되니까 왼쪽으로 확 꺾었다가 너무 뜨거우면 아 뜨거우고, 물이 너무 세게 나오면 약하게 하다가 너무 약하냐
이렇게 올렸다가 하잖아요.
그러니까 내가 원하는 방향으로 이 파라미터들을 조금씩 조정해 나간단 말이에요.
그게 경사하강법과 같은 논리입니다.
우리가 어떤 파라미터가 있는데 파라미터가 현재 여기인데 손실을 측정을 해요.
그럼 내가 원하는 건 손실을 줄이는 거기 때문에 손실이 줄어드는 방향, 경사를 측정을 해서 내려가는 방향으로 파라미터를 이렇게 옮겨주면 됩니다.
한번 옮겼더니 이번엔 여기에요.
또 옮겨요.
이번에는 옮겼더니 경사가 이렇게 되어있네요.
그러면 또 이리로 가는 거죠.
그래서 뜨거운 물 차가운 물, 뜨거운 물 차가운 물 이렇게 조절하다가 점점 딱 맞는 온도로 맞추듯이 어느 방향으로 파라미터를 조절해야 손실이 줄어드는지를 측정을 해서 점점 수정을 하는 겁니다.
이게 경사하강법이고 딥러닝에서 사용하는 방법입니다.
그래서 경사하강법을 쓸 때 여러 가지 고민해야 될 문제들이 있어요.
한 가지는 학습률이라는 건데 문제가 뭐냐면 우리가 다시 샤워실로 돌아가서 샤워실에서 샤워기를 너무 확 돌리면 어떻게 됩니까?
너무 뜨겁다고 너무 확 돌리면 찬물이 쏟아져서 앗 차가워 하면서 또 갑자기 뜨거운 물로 확 돌리면 앗 뜨거워 하면서 이렇게 되는 거죠.
그래서 경제학의 샤워실의 바보라는 속담 같은 말이 있는데 뭐냐면 정부가 경제정책을 쓸 때 경기가 나쁘다고 갑자기 너무 정부가 돈을 많이 풀면 어떻게 됩니까?
경제가 너무 갑자기 또 뜨거워 지죠.
그러면 또 경기를 하강시킨다고 또 정책을 경기를 진정시키는 정책을 너무 세게 시키면 어떻게 됩니까?
또 그럼 갑자기 불황이 오겠죠.
그러니까 적당히 해야 되는데 뭐든지 갑자기 너무 확 확 돌리면 경제가 작살난단 말이에요.
그래서 그걸 가지고 샤워실에 바보야 샤워실에서 물을 조금씩 온도를 조절해야지 온도를 확 확 틀면 어떡해
이런 얘기예요.
그래서 우리가 이제 뭐 한국은행이나 아니면 미국의 FED 같은 거 보면 금리 조절할 때 진짜 띡만큼씩 조절하잖아요.
그래서 맨날 미국 같은 경우 보면 기자회견 해가지고 아메리카 이코노미 스트롱 뭐 있다는 소리 하면서 금리 언제 내립니까?
그래서 우리가 예의주시하고 있다고 이딴 소리 한단 말이에요.
왜냐하면 너무 빨리 빨리 금리를 조절하면 시장이 망가질 수 있기 때문에 조금씩 조금씩 조절을 한단 말이에요.
근데 또 너무 조절을 안 하면 어떻게 됩니까?
빨리 지금 대응을 해야 되는데 중앙은행이나 정부가 대응을 안 하고 미적미적거리면 그것도 문제죠.
그래서 우리의 경사강법에서도 학습률이라는 게 있어서 우리가 여기에서 기울기가 이 방향이에요.
그러면 이만큼 조절할까?
이만큼 조절할까?
이만큼 조절할까?
가 문제가 되고 그 이만큼이라고 하는 게 학습률이 됩니다.
그래서 경제 문제와 마찬가지로 학습률을 너무 크게 가져가면 우리가 한 이만큼만 가야 여기로 갈 수 있는데 이만큼 가버리면 엉뚱한 데로 간단 말이에요.
여기서 또 이만큼 가고 이만큼 가고 그러면 수렴을 하는 게 아니라 점점 발산을 하겠죠.
그렇다고 너무 소심해 가지고 학습률을 조금씩 가져가면 세워라 네워라 하면서 수렴을 안 하게 됩니다.
그 다음에 우리가 경사강법이 가지고 있는 몇 가지 문제가 있는데 기울기를 따라 내려가다 보니까 이런 데서 출발하면 이렇게 따라 내려가서 어쨌든 학습률이 작아도 여기까지 갈 수 있는데 엉뚱하게 이런 데서 출발하면 아무리 가봐야 여기까지 밖에 못 간다는 거죠.
출발점이 나쁘면 수렴을 해봤자 고기가 고깁니다.
아니면 이런 점에 어떻게 걸려버리면 여기서는 분명히 이리로 내려가면 되는데 경사 자체는 여기가 평평하단 말이에요.
그러니까 내려가지를 못 하는 거죠.
그래서 이런 점을 안장점이라고 하는데요.
안장 모양으로 생겼다고 해서 이런 점에서도 학습이 안 되는 문제가 있습니다.
그래서 이제 이거를 극복하는 방법이 여러 가지가 있는데 한 가지에는 확률적 경사강법이라는 건데요.
우리가 경사를 구할 때 여러 개의 데이터를 이용을 해서 경사를 구합니다.
그러면 데이터가 많으면 많을수록 경사가 정확하겠죠.
반대로 말하면 데이터를 좀 줄여주면 경사가 약간 부정확하게 됩니다.
경사가 부정확하면 나쁜 거 아니에요?
나쁘죠.
나쁜데 가끔 좋을 때가 있습니다.
어떨 때 좋냐 하면 여기서 이렇게 되어 있으면 우리가 여기 시작점에서 경사를 구하면 경사가 이렇게 나와서 이 방향으로 가는 게 맞는 방향인데 결과적으로 보면 맞는 방향으로 가면 안 된단 말이에요.
그래서 제가 첫날 그런 얘기 했었죠.
가난한 사람들이 더 합리적이다.
각자는 합리적으로 행동을 하는데 그러면은 이 가난에서 못 벗어나는 거죠.
어느 순간 약간 비합리적인 행동을 하거나 뭐 이런 게 있어야 됩니다.
근데 합리적으로 하면 나는 지금 현재 상황이 최선을 다하고 있어 그러면 계속 가난한 거예요.
왜냐하면 모든 주변 환경이 가난한 거에 최적화가 되어 있기 때문에 거기서 합리적으로 행동하면 가난한 선택밖에 없습니다.
그래서 우리가 이제 보면은 일시적으로 약간 손해를 무릅 써야 되는 거죠.
여러분들도 취업 준비 하시거나 이럴 때 취준생이 뭡니까?
취준생이 일시적으로 가난한 거를 감수를 하는 거죠.
좋은 데 취직하기 위해서 수입이 없는 시기를 버티고 넘어가는 거잖아요.
근데 이제 문제는 사실 진짜로 버티고 넘어가는 거 아니고 부모님 돈으로 버티고 넘어가는 거니까 보통은.
사실 뭐 운전하는 의미에서 버티고 넘어갔는데 너무 가난해가지고 부모님도 없고 도와줄 사람도 없으면 그냥 빨리 돈 버는 게 단기적으로 합리적인 행동이죠.
그러면 좋은 데 취직을 못 하니까 계속 좋은 데 취직 못 하고 이렇게 되 니까 단기적으로는 합리적이지만 계속 빈곤한 상태에 원물로 있게 됩니다.
그래서 어쨌든 여기서 우리가 경사를 구하면 이 방향이 기울기기 때문에 이 방향으로 가는 게 합리적인데 우리가 확률적 경사항법을 쓰면 가끔 경사가 잘못 계산돼요.
그래서 이렇게 계산이 됩니다.
그럼 여기에서 이 방향으로 잘못 알고 이리로 가는 거죠.
그래서 어 하면서 이제 이쪽으로 빠지는 겁니다.
그러면은 우리가 오히려 더 나은 결과를 나올 수도 있는 거죠.
그러면 이제 이렇게 생각할 수도 있는 거죠.
아니 그럼 여기 있다가도 이리로 갈 수 있는 거 아닙니까?
아 그렇죠.
세상에 이래 그렇지만 무조건 좋은 건 아닙니다.
근데 또 이리로 갔다가도 어차피 정확하지 않으니까 또 이리로 올 수도 있는 거죠.
이리로 올 수도 있고.
그렇다.
그래서 우리가 이제 확률적 경사항법을 쓰게 되는데 그래서 우리 예제코드에서 보면은 데이터는 우리가 6만 개에요.
총 데이터는 많은데 계산은 한 번에 그 중에 64개만 가지고 하거든요.
그래서 이렇게 하는 이유가 두 가지가 있습니다.
하나는 계산을 조금씩 하니까 이제 효율적이에요.
효율성이 높고 또 하나는 계산을 조금씩 하니까 매번 매번의 계산이 조금 부정확하게 됩니다.
근데 그 부정확한 건 약간 의도적인 부정확함이에요.
그래서 살짝 부정확하게 해서 우리가 좀 더 학습을 효과적, 좋은 저런 경사항법의 단점을 운이 좋으면 극복을 해보겠다.
이런 얘기가 되는 거죠.
그래서 이제 이 숫자를 조금 늘리면 어떻게 되겠습니까?
좀 더 안정적인 학습이 되겠죠.
반대로 말하면 저런 국소 최적 우리가 이제 이렇게 있으면 이런 데 빠지기가 또 쉬워집니다.
그래서 숫자를 좀 줄여주면은 더 미친 듯이 날 테니까 이런 데 넘어갈 수도 있는 거죠.
그래서 그런 거를 이제 응용하는 거기도 해요.
근데 주의하셔야 되는 거는 이렇게 말하면 아 그럼 전체 데이터가 적어도 되는구나
이렇게 생각하실 수 있는데 전체 데이터는 많아야 됩니다.
근데 우리 한 번 한 번의 계산을 조금씩 데이터를 가지고 한다는 얘기.
그다음에 이제 여러 가지 어떤 추가적인 아이디어가 나오는데 모멘텀이라고 해가지고 우리가 예를 들면 이렇게 가다가 살짝 턱이 있어요.
그다음에 더 이렇게 깊이 빠져나가면 우리가 여기서부터 이제 가면 원래는 여기서 멈춰야 되거든요.
근데 일종의 모멘텀, 속도를 넣어서 여기까지 가면 일종의 관성으로 넘어가는 거예요.
으악 하고 그러면은 여기서 이제 계속 가겠죠.
그럼 아니 여기서도 이렇게 갈 거 아닙니까?
근데 여기서 이제 가봤자 으악 했다가 다시 으악 했다가 으악 해서 갈 테니까 여기는 어지간하면 넘지 못할 가장 깊은 골작이기 때문에 잘 안 넘어.
물론 이제 너무 모멘텀이 쎄면 이런 데도 넘어갈 수 있는데 그러면 좀 곤란하겠죠.
그렇지만은 운이 좋다면 이런 데 빠질 수 있다.
이런 거고 그래서 우리가 이제 어제 실습 코드에 보면 adam이라는 걸 쓰는데요.
다시 앞으로 가서 보면.
여기 모형학습에 보면은 optimizer는 adam 이런 걸 쓰는데 이 adam이 뭐냐면 이제 어댑티브하게 하는 거예요.
그래서 어댑티브하게 하는데 뭘 어댑티브하게 하느냐?
우리가 지금 학습률 아까 얘기를 했었거든요.
학습률이 너무 커도 안 되고 너무 작아도 안 된다.
그러면은 좀 그때 그때 좀 조정을 해 주면 되겠죠.
클 때는 크고 작을 때는 작고.
그래서 여러 가지 방법들이 나와요.
그래서 여러 가지 방법들이 나오는데 예를 들면은 내가 많이 가본 방향은 이미 많이 가봤으니까 학습률을 좀 낮추고 좀 새로운 방향으로 학습률을 높인다든가.
그래서 내가 예를 들면 이 방향은 이제 많이 가봤어요.
이 방향으로는 좀 속도를 늦추는 거죠.
학습률이 일종의 속도니까 속도를 늦추고 이 방향은 별로 안 가봤어요.
이 방향으로는 좀 빨리 가보는 거죠.
이런 식으로 가변적으로 학습률을 조정하는 방법이 있고요.
아니면은 rms 풀업이라는 것도 있는데 이것도 기본적으로 많이 가본 방향으로는 학습률을 낮추는데 그 많이 가본 거를 내가 처음부터 끝까지 많이 가본 게 아니라 최근에 많이 가본 쪽은 내가 지금 여러분이 달리기 하러 운동장 가서 막 그냥 자유롭게 달리는데 동쪽으로 너무 많이 갔다
요즘에 그러면은 약간 동쪽으로는 속도를 줄이고 남북방향으로 좀 더 속도를 줄이고 그래서 최근에 많이 가본 쪽은 좀 속도를 늦추는 이런 식입니다.
그래서 rms 풀업에다가 앞에서 얘기했던 모멘텀 내가 약간 논리가 반대긴 한데 모멘텀은 최근에 어떤 속도 같은 걸 이제 유지를 하는 거죠.
그런 거를 결합한 그래서 학습률을 적당하게 어떤 조정해 가면서 하는 방법이 이제 adam 이라는 방법이고요.
이 방법이 그 좀 학습이 쌓여야 학습률이 잘 조정이 되는데 초반에는 내가 많이 가본 방향이라는 것 자체가 없잖아요.
그래서 좀 불안정하거든요.
그래서 그런 거를 해결한 rectified adam 이라는 방법도 나와 있습니다.
그래서 이게 이제 약간 거의 최신 방법이라고 할 수 있고요.
근데 이 경사강법을 보완하는 방법은 계속 나옵니다.
요즘에 또 나온 방법이 look ahead 라고 하는데 별의별 방법이 다 나와요.
그래서 어떻게 하냐면 일종의 선발대를 보내고 선발대가 빨리 가봅니다.
선발대가 먼저 가보는데 얘가 이렇게 가봤는데 여기까지 갔어요.
그러면 우리는 여기서 이 방향으로 가면 되는구나.
근데 여기까지 가지 말고 이 중간까지만 가자
이렇게 하는 겁니다.
이런 게 좋을 때가 뭐냐면 지금 여기가 최적점인데 가끔 경사강법을 쓰다 보면은 여기로 바로 이렇게 못 가고 주변으로 이렇게 돌면서 소용돌이치면서 들어갈 때가 있거든요.
그럼 이제 굉장히 시간이 오래 걸리고 비율적이잖아요.
그래서 이제 look ahead는 선발대가 먼저 가보는 겁니다.
선발대가 이렇게 갔으면, 그럼 선발대와 이 사이로 가면은 여기가 우리가 뱅글뱅글뱅글 소용돌이를 돌고 있기 때문에 항상 원형으로 가고 있는데 이 원형에 이만큼만 가면 이 그림을 보시면 항상 더 골짜기 안쪽으로 내려가게 돼요.
그래서 그 느린 가중치랑 빠른 가중치를 두 개를 만들어 가지고 얘가 일종의 선발대 역할을 하는 겁니다.
그래서 선발대를 먼저 보내놓고, 가보니까 어때
거기야?
그러면은 트리옷이 네가 이상한 데 가 있을 테니까 나는 곧 반만 가겠어.
그러면은 나는 더 좋은 데 가겠지.
약간 이런 식의 논리로 look ahead 하는 겁니다.
미리 선발대를 가서 저기 뭐가 있는지 한번 가보는 거예요.
그래서 거기를 그냥 따라가는 게 아니라 그러면 그걸 참고해서 나는 좀 더 좋은 데로 가는 거죠.
그래서 이제 이 런 식으로 해서 더 빨리 수렴 시키는 이런 아이디어고, 그래서 그러면 이제 선발대를 누굴 보낼 거냐
뭐 이런 게 있겠죠.
그래서 이제 선발대에다가 아까 얘기했던 알 아담, 앞에 있는 맨 마지막 알고리즘이죠.
그래서 선발대로 알 아담을 보내는 방법이 있는데 그걸 이제 레인저라고 해서 이게 이제 진짜 진짜 최신입니다.
역전파 알고리즘
계산은 정방향으로 하고 업데이트할 때는 역방향으로 한다
이런 얘기를 했는데 그게 왜 그러게 되냐?
제가 가능한 수식은 얘기 안 하려고 하는데 어쨌든 미분의 연쇄규칙이라는 게 있습니다.
고등학교 때 아니면 대학교 때 배우시긴 했겠지만 기억에서 흐려진 우리가 미분을 할 때 F가 있고 F, U가 있고 F가 있고 G가 있고 X가 있고 이렇게 돼 있는 골의 함수 우리가 미분하면 이런 골이 되거든요.
그래서 우리가 기울기를 계산을 하는데 만약에 이쪽에 레이어에 있는 기울기를 계산을 하려면 이게 결국에는 합성함수라서 이 레이어, 이 레이어, 이 레이어, 이 레이어를 거쳐서 결국 이 함수, 이 함수, 이 함수를 거쳐서 어떤 출력값이 나오고 그걸 가지고 손실을 계산한단 말이에요.
그러면 이 손실에 대해서 이걸 어떻게 고쳐야 되냐?
그 기울기를 계산을 하면 이 기울기, 이 기울기, 이 기울기가 다 중간에 이렇게 보시면 끼어 들어가게 됩니다.
그래서 아까 그 몬테카르로 때 G가 보면 맨 앞에 G를 계산하려면 중간에 있는 G가 필요하고 중간에 있는 G가 필요하려면 그 다음에 있는 G가 필요하고 이런 식이 되듯이 여기서도 얘의 기울기를 계산하려면 얘의 기울기가 필요하고 얘의 기울기를 계산하려면 얘의 기울기가 필요하고 그래서 앞에 있는 기울기가, 뒤에 있는 기울기가 다 필요하기 때문에 맨 끝에 있는 기울기부터 계산해서 역순으로 계산하면 계산이 편하겠죠.
그래서 그거를 역전파 알고리즘이라고 하고 별 얘기는 아니에요.
그래서 예측을 할 때는 정순으로 계산하고 파라미터 업데이트 할 때는 역순으로 계산을 한다.
그래서 여기서 어떤 문제가 생기냐면 기본적으로 기울기를 구할 때 기울기가 다 곱하기가 되는 형태거든요.
기울기 곱하기, 기울기 곱하기, 기울기 곱하기, 뭐 이렇게 되는데 그러면 이런 기울기가 한 0.1이에요.
여기도 0.1이에요.
여기도 0.1이에요.
뭐 이런 식으로 되면 얘가 어떻게 되겠습니까?
아주 0에 가까워지겠죠.
근데 컴퓨터는 나타낼 수 있는 수의 어떤 정밀도의 한계가 있기 때문에 너무 작으면 그냥 0이 되어버립니다.
그래서 기울기가 0이라는 거는 경사가 0이니까 파라미터 업데이트가 안 되는 거죠.
내려가야 되는데 이렇게 되면 왼쪽 오른쪽 갈 수가 없잖아요.
그래서 이걸 사라지는 경사 문제라고 하고 이런 게 일어나면 학습이 더 이상 안 됩니다.
특히 우리의 오차를 역전파 시키기 때문에 이 앞쪽이 학습이 잘 안 돼요.
근데 우리의 딥러닝이라는 게 결국에는 레이어를 많이 집어 넣어가지고 어떤 함수든지 근사할 수 있다.
이거에 기대는 건데 학습이 안 되면 그게 다 소용없는 거죠.
그래서 사라지는 경사가 한 가지 굉장히 큰 문제가 되고 그래서 이걸 해결하기 위해서 여러 가지 아이디어가 나오는데 우리 어제 활성함수 얘기할 때 이렇게 생긴 활성함수를 쓰면 양쪽으로 기울기가 없어서 이거는 좀 아니고 이렇게 생긴 거를 많이 쓴다고 했죠.
렐루.
여기는 이쪽은 기울기가 없지만 그래도 이쪽이 있으니까 이거는 기울기가 여기에서만 있는데 아주 좁은 구간에서만 있는데 이거 어쨌든 절반은 기울기가 있단 말이에요.
물이 반이나 남았네
약간 이런 거죠.
그 외에도 여러 가지 방법을 쓰는데 사실 여기도 빅데이터가 중요합니다.
계속 데이터 데이터 데이터 하는데 데이터가 중요해요.
왜냐하면 기울기가 0만 아니면 그래도 조금이라도 있으면 사라지는 경사 문제에도 불구하고 어쨌든 꾸약꾸약 조금씩 학습이 된단 말이에요.
어거지로.
그래서 데이터만 많고 계산을 많이 돌리기만 하면 어쨌든 언젠가는 학습이 되기는 됩니다.
경사가 완전 0만 아니면 그래서 빅데이터가 중요해요.
모형 학습
model = SimpleNN()
criterion = nn.CrossEntropyLoss() # 손실 함수
optimizer = optim.Adam(model.parameters(), lr=0.001) # 최적화 알고리즘
num_epochs = 5
for epoch in range(num_epochs):
for images, labels in train_loader:
optimizer.zero_grad() # 경사 초기화
outputs = model(images) # 모형에 이미지 입력
loss = criterion(outputs, labels) # 손실 계산
loss.backward() # 역전파 알고리즘으로 경사 계산
optimizer.step() # 파라미터 최적화
print(f'Epoch {epoch+1}/{num_epochs}, Loss: {loss.item():.4f}')
Epoch 1/5, Loss: 0.1040
Epoch 2/5, Loss: 0.1420
Epoch 3/5, Loss: 0.0576
Epoch 4/5, Loss: 0.1996
Epoch 5/5, Loss: 0.0789
그래서 우리가 이제 모형을 학습을 시킬 수 있는데 이 학습시키는 코드가 좀 복잡해 보이는데 우리 모델을 여기서 정의를 하고요 그다음에 지도학습은 정답이 있기 때문에 정답하고 우리의 어떤 예측하고 이 차이를 계산을 해야 됩니다
근데 정답이나 예측이 그냥 수치형으로 나오면 예를 들면 얘가 49인데 얘가 48이다
그럼 이제 오차가 1 뭐 이렇게 계산하면 간단한데 지금은 확률을 맞춰야 되거든요
예를 들면 정답이 5인데 그럼 나의 예측은 0일 확률, 1일 확률, 2일 확률, 3일 확률, 4일 확률, 5일 확률, 6일, 7일, 8일, 9일 뭐 이런 식으로 확률로 나온단 말이에요
그러면 5의 확률이 가장 높다는 게 그걸 말로 하면 쉬운데 5의 확률이 가장 높다를 어떻게 수학적으로 정의를 하려고 하면 좀 어려운 문제가 됩니다
그래서 보통은 크로스 엔트로피라는 방식으로 해서 내가 원하는 거의 확률이 제일 높으냐를 계산을 해요
엔트로피라는 거는 쉽게 말하면 무질서 도라고 보통 많이 하는데 대체로 다 아시죠?
이공개 분들이 많으니까 크로스 엔트로피는 결국 뭐냐면 무질서다는 건 뭐예요?
나는 5만 확률이 좀 높았으면 좋겠는데 1도 높고 2도 높고 3도 높고 4도 높고 다 그런 확률이 높으면 골고루 높아버리면 굉장히 무질서한 거잖아요
그냥 뭔 말이 하고 싶어?
이렇게 되는 거잖아요
딱 5면 5, 3이면 3, 하나만 높아야지
그래서 내가 원하는 것만 딱 높으냐
아니면 이것저것 다 높으냐
이거를 측정하는 게 크로스 엔트로피입니다 옆에 손실함수라고 써 있는데 우리가 이 크로스 엔트로피를 이용을 해서 내가 원하는 답인지 아닌지 일종의 오차 또는 손실을 계산을 할 겁니다 시간이 좀 별로 없으니까 일단 빨리 한번 돌려보고 나중에 자세한 설명은 내일 다시 하죠
그래서 우리가 이제 이거를 경사강법을 따라서 이 경사를 따라 쭉 내려가야 되는데 경사를 따라 내려가는 방법도 여러 가지가 있어요
그래서 가장 많이 사용하는 방법 중에 아담이라는 방법이 있습니다
이 아담의 앞에 AD는 어댑티브에서 따온 거예요
그래서 이걸 내려가는데 그냥 무지성으로 내려가는 게 아니라 여러분도 이렇게 비탈길 내려갈 때 비탈길 너무 급하면 좀 조심조심 내려가고 약간 평평한 막 뛰어서 가고 이렇게 하잖아요
그렇듯이 약간 상황에 따라서 적절하게 이걸 좀 조절해 가면서 가는 거예요
여기서 너무 빨리 뛰어가면 으악 하고 굴러 떨어질 거고 여기서 천천히 가면 집에 못 가죠
그래서 이 길 따라 내려가는데 좀 어댑티브하게 내려가는 알고리즘입니다
그래서 이제 그 다음에 이 코드를 보면 여기 트레인 로더가 이제 해주는 건 뭐냐면 데이터를 이제 불러오는 역할을 해요
데이터가 양이 많으니까 한꺼번에 다 불러오지 않고 앞에 보시면은 우리가 트레인 로더 정의할 때 여기 보면 64개씩 불러와라
이렇게 정의를 해 놨거든요
데이터 많으니까 6만 개를 한꺼번에 불러오지 말고 64개씩 불러와 이렇게 시켜 놓는 거예요
그래서 여기 포문을 돌면 이미지랑 이미지의 레이블 64개, 64개씩 불러옵니다
그래서 일단 이 옵티마이저를 초기화를 해주고 그 다음에 모델에다가 이미지를 넣으면 이 모델이 확률로 예측을 할 거예요
첫 번째 이미지는 몇 번일 확률이 몇 퍼센트고 두 번째 이미지는 뭐가 몇 퍼센트 이렇게 예측을 해줘요
그럼 얘가 한 예측이랑 이건 이제 예측이고 여기 레이블이라고 돼 있는데 이게 정답입니다
정답이랑 비교를 해요
그래서 크리테리언으로 계산을 해서 만약에 내가 정답이 4번인데 예를 들어서 내가 5번의 확률을 높게 예측했다 그러면 로스가 확 커집니다 손실이 커지면 나쁜 거예요
못 차라서 근데 정답이 5인데 5의 확률이 높다 그럼 손실이 확 줄어듭니다
그래서 그런 손실을 계산을 해요
그 다음에 로스점 백워드 하면 앞에 우리가 포워드 함수를 정해서 레이어가 이렇게 있으면 이 순서대로 통과를 시키게 했잖아요
그럼 이제 역순으로 계산을 하면서 여기서 뭘 고쳐야 되고 여기서 뭘 고쳐야 되고 여기서 뭘 고쳐야 되고 여기서 뭘 고쳐야 되고를 이제 일일이 찾아낸다
그래서 이제 이걸 역전파 알고리즘이라고 해요
오차를 거꾸로 되짚어가면서 뭘 고쳐야 될지를 찾는다
그 다음에 옵티마이저 점 스텝하면 얘가 한 단계 최적화를 하게 됩니다
그래서 이거를 우리가 64개씩 불러와서 계속하면 이미지가 6만 개니까 64개씩 하면 뭐 한 대충 9000번 정도 하면 이거를 한 번 다 계산을 하겠죠
그래서 한 번 다 계산을 하면 파라미터가 딱 정확하게 나오느냐 하면 이것도 경사가 이렇게 돼 있기 때문에 내려가다가 다 못 내려갈 수도 있어요
그래서 한 5번 정도 더 계산해봐 라고 한 거예요
5번 그러면 이걸 다시 5번 반복하겠죠
그래서 전체 데이터를 한 번 다 훑는 거를 여기 보시면 에포크라는 말을 썼는데 이거는 전체 데이터를 한 번 다 훑는다
이런 얘기입니다
전체 데이터를 5번은 훑더라
우리 학교 다닐 때 뭐 요즘에도 그런지 모르지만 정석 이런 수학책 있으면 그거 뭐 3번 뗐다, 4번 뗐다
뭐 이런 얘기 하잖아요
수능 보기 전에 몇 번은 봐야 된다
뭐 이런 얘기 하잖아요
그러니까 우리가 이제 이 데이터를 5번은 공부해라
모형 평가
그래서 이제 중간 설명은 내일 다시 좀 드리도록 하고요 자세한 설명은 그래서 이제 다 돌린 다음에 우리가 이제 여기 모형 평가 이 코드를 돌리면 이제 이번에는 테스트 로더에서 테스트 데이터를 불러와서 이미지랑 레이블 불러온 다음에 이 이미지를 넣으면 아웃풋이 나올 거고 그러면 이 아웃풋들 중에 확률이 제일 높은 데가 어디냐
맥스 값이 어디냐 하면 그게 우리 예측이 되겠죠
그래서 확률을 뭐 이런 식으로 확률을 예측을 할 건데 0, 1, 2, 3, 4, 5, 6 이렇게나 할 텐데 그럼 지금 3번의 확률이 제일 높으니까 이거는 맥스가 3이라서 3번이 됩니다
그래서 이제 총 이 토탈은 우리가 지금까지 본 이미지의 총 개수고 코렉트는 우리가 예측한 거랑 정답이랑 늦는 했으니까 일치 않은 거의 개수가 됩니다
그러면 정답률이 나오겠죠
correct = 0
total = 0
with torch.no_grad(): # 경사 계산 안함(학습에 사용하지 않으므로 필요 X)
for images, labels in test_loader:
outputs = model(images) # 각 클래스의 확률 예측
_, predicted = torch.max(outputs, 1) # 확률이 가장 높은 클래스
total += labels.size(0) # 레이블 개수를 총 개수에 추가
correct += (predicted == labels).sum().item() # 예측된 클래스와 레이블이 일치하는 개수
print(f'Test Accuracy: {100 * correct / total:.2f}%')
Test Accuracy: 97.61%
그래서 이제 학습이 잘 되는지 보려면 테스트를 해보면 되겠죠
여기 모형 평가 이 코드를 사용을 해보시면 정각도가 저는 97.6%가 나왔습니다
이런 식으로 하는 것이 지도학습이다
PyTorch Lightning
!pip install lightning
모형 재정의
import torch.nn.functional as F
import pytorch_lightning as pl
from torchmetrics.classification import MulticlassAccuracy
class SimpleNN(pl.LightningModule):
def __init__(self):
super(SimpleNN, self).__init__()
self.fc1 = nn.Linear(28*28, 128) # 은닉층 1
self.fc2 = nn.Linear(128, 64) # 은닉층 2
self.fc3 = nn.Linear(64, 10) # 출력층
self.accuracy = MulticlassAccuracy(10)
def forward(self, x):
x = x.view(-1, 28*28) # 모양을 평평하게
x = torch.relu(self.fc1(x)) # ReLU 활성화 함수로 비선형성을 추가
x = torch.relu(self.fc2(x))
x = self.fc3(x)
return x
def process_batch(self, batch):
images, labels = batch
outputs = self(images)
loss = F.cross_entropy(outputs, labels)
return outputs, loss
def training_step(self, batch, batch_idx):
outputs, loss = self.process_batch(batch)
self.log('train_loss', loss)
return loss
def test_step(self, batch, batch_idx):
outputs, loss = self.process_batch(batch)
accuracy = self.accuracy(outputs, batch[1])
self.log('test_accuracy', accuracy)
return loss
def configure_optimizers(self):
optimizer = torch.optim.Adam(self.parameters(), lr=0.001)
return optimizer
학습
from pytorch_lightning import Trainer
model = SimpleNN()
trainer = Trainer(max_epochs=5)
trainer.fit(model, train_loader)
테스트
trainer.test(model, test_loader)