Scaled Dot-Product Attention

Self - Attention

Multi-Head Attention

Position-wise Feed-Forward Networks

Positional Encoding

 


 

3. Model Architecture

 

트렌스포머는 seq2seq 구조와 유사하게 , encoder / decoder 구조로 구성되어있다.

encoder와 decoder는 동일한 layer의 stack으로 N = 6 개가 쌓여있으며

각 encoder/decoder는 내부에 각 2개의 sub-layer로 구성되어있다.

 


 

3.1 Scaled Dot-Product Attention

 

attention은  Scaled Dot-Product Attention을 사용하며, 기존 attention과 동일하게 query, keys, values 를 사용한다.

여기서 query, keys, values 는 1개 시점의 값이 아니라 전체 시점에 대한 벡터이다.

 

Q  query와 K  keys의 유사도를 내적 (Dot-Product)을 통해 표현한다 .

(

* 기존에 MLP로 표현한 것과 차이가 있다.  - 이를 additive attention 이라고 한다.

additive attention은 1개의 은닉층을 가진 피드포워드 신경망을 사용해 query와 key 사이 호환성 함수를 구한다.

이 둘의 이론적 복잡도는 동일하기만 matrix 연산으로,  최적화하기에 용이해,  Dot-product를 사용한다.

)

 

softmax를 사용해서 이를 확률로 바꾸어 준다 ( 0 ~ 1 )  - attention weight matrix 

 

이후 이를 value와 곱하여 출력이 계산된다. 

 

 

여기서 key의 dimension 인 dk 가 작으면 , scaled 를 제외하고 두 개 attention 방법의 성능이 유사한데

dk가 커지면 , dot product의 크기가 커져 softmax 함수의 기울기가 급격하게 작아지기 때문

-> 따라서 root dk로 스케일링 해준다.

 


 

3.2 Multi-head Attention 

Multihead attention 수식, 2번의 Linear projection이 진행된다.

 

Transformer 구조에서는 single attention으로 dmodel 차원의 Q,K,V를 만들어 내는 대신,

h개의 multi-head Attention을 통해, linear projection을 통해 dq,dk,dv차원의 Q,K,V를 만들어내고 이를 concat한 다음 또 한번 linear projection하여 결과를 만들어낸다. 

 

멀티헤드 어텐션을 사용하므로써, h개의 head가 서로 다른 representation subspace를 반영할 수 있는 장점이 있다.

싱글 헤드 어탠션은 representation을 한개의 subspace에 대해 표현하고 averaging하므로써 다양한 subspace에서의 정보가 noisy해진다. 

 

또한, computational cost 관점에서도 차원을 dq dk dv로 줄여서 h개의 head가 처리하고 합쳐 d model로 복원하므로 single-head attention과 큰 차이가 없다.

 

 


 

3.3 Position-wise Feed-Forward Networks

Fig1을 참고하면 encoder와 decoder의 각 구조 안에서 Feed-Forward가 있는 것을 확인할 수 있다.

위의 수식과 같이 2개의 linear transformation과 ReLU로 이루어져있고,

해당 가중치는 layer 단위로는 공유하지 않지만, layer 안에서 position에 대해서는 공유한다. (CNN의 Kernel을 생각하면 편하다).

또한 각 posion에 대해 seqpartely and identically 즉 , 각 posion끼리의 정보는 섞이지 않는다.

 

차원은 512 -> 2028 -> 512의 구조를 보이며, cnn에서 1x1 kernel의 convolution 구조와 같음을 논문에서 언급하고 있다.

 


 

3.4 Positional Encoding

 

모델에서 CNN, RNN의 구조를 사용하지 않아 순서 정보가 포함되지 않아 , 각 token간 상대적인/절대적인  위치 정보를 넣어주기 위해 Positional Encoding을 사용한다.

 

주어진 input에서 positional encoding을 진행하고 input embedding에 더하는 방식으로 구현되고 , 이러한 positional encoding을 위해 학습을 통한 방식 / 고정된 방식 등 여러 방식이 존재하지만 논문에서는 아래와 같이 서로 다른 주파수를 가지는 sin/cos 함수를 사용한다.

 

위에서 pos는 position이고, i는 dimention이다. 

요약하자면, 주기함수의 특징으로써 해당 pos가 늘어나도 encoding이 가능하고, 삼각함수의 성질으로써 선형ㅇ함수로써 표현이 가능하기에 해당 encoding 방식을 사용했다고 한다. ( 학습을 통한 방식에 대비해 성능은 유사하지만 seq 길이에 대해 더 자유로운 특성)


4. Why self-attention

 

왜 해당 모델에서 self-attention을 사용했는지 설명하는 부분이다.

먼저 self-attention에 대한 정의부터 다시 짚고 넘어가자. 

Self-attention, sometimes called intra-attention is an attention mechanism relating different positions of a single sequence in order to compute a representation of the sequence.

 

모델에서는 이러한 self-attention을 attention layer라는 개념으로 일반화하여 사용하며 사용의 근거를

1. computational complexity 2. amount of computation (can parraleized) 3. path length between long-range dependencies로 설명하고 이를 기존의 rnn과 cnn과 비교한다.

 

self- attention layer는 아래와 같이 동일한 input seq에 대해 , seq안에서 어떤 token끼리 관계가 있는 방식으로 단일 input seq에 대해 Q,K,V를 계산한다.

 

위에서 생략한 3.2.3 Applications of Attention in our Model을 다시 불러오자면,

encoder, decoder 단에서는 위와 같은 self - attention이 사용되고, decoder의 경우에는 자기 자신을 포함하여 이전 position에 대해서만 attention 하도록 미래의 값에 대해서는 masking out하고, encoder는 이러한 과정이 없다. 

 

encoder -> decoder  attention layer에서는 self - attention이 아니라 queries들은 이전 decoder layer의 output을 , key와 value들은 이번 encoder의 output에서 나오고, input seq의 모든 position에 대해 attention을 진행한다. (전형적인 seq2seq의 attention과 같다고 생각하면 된다.)

 

 


review

지금까지 Attention all you need 를 읽고 리뷰해보았습니다. 비록 전체 논문을 읽고 분석한거는 아니지만 , vision 분야 transformer 를 이해하기 위해 배경지식으로써 읽어보았고 Vit, Swin 등의 논문을 리뷰하고 다시 돌아와 어떤 부분이 초기 자연어 처리를 위한 transformer에서 영감을 얻어 만들어졌는지 확인해 볼 계획입니다. 

 

특히 , decoder의 masking out이나, position encoding의 작동 원리와 이유에 대해서는 직관으로써 이해하고 넘어갔으나 후에 다시 돌아와 자연어 처리에 대한 지식을 겸비하여 다시 읽어보려고 합니다.

지난번에 seq2seq에 대한 기본 개념, attention에 대한 기본 개념을 이야기해 본것이 더불어 attention is all you need라고 하는 

transformer라는 모델 구조에 대해 제안한 논문을 리뷰하고, 그 안의 self - attention 등의 개념에 대해 알아보고자 한다.

자연어 처리에 대한 직접적인 지식이 필요한 것이 아니기에,

해당 논문에서 필요한 개념만 발췌독하였고 핵심에 해당되는 부분은 영여원문을 전부 첨부하였다.

 

Vaswani, A., Shazeer, N., Parmar, N., Uszkoreit, J., Jones, L., Gomez, A. N., Kaiser, Ł., & Polosukhin, I. (2017).
Attention is all you need. arXiv preprint arXiv:1706.03762.


1. Introduction 

RNN , LSTM , GRU를 활용한 , 기계 번역 언어 모델링과 같은 Sequence Modeling & Transduction 문제 해결은 SOTA의 성능을 만들어 내었고, 이후 recurrnet language model과 encoder-decoder 아키텍쳐에서의 한계점을 해결하기 위한 많은 연구들이 진행되었다.

recurrent model ( RNN )

 

->

 

Sequence Modeling : input과 output의 순서적인 특징을 학습하여 다음의 seq 토큰을 맞추는 task

Transduction : input과 output의 길이가 다른 seq라 하여도 변환하는 task ( 번역 )

 

저자가 기존의 RNN 구조의 성능을 인정함과 동시에 기존 구조의 한계점을 극복하기 위한 연구가 진행됨을 서술하는 부분이다.

recurrnet language model과 encoder-decoder 아키텍쳐와 같은 개념이 후에 등장할 것을 짐작할 수 있다.

 

 


Recurrent models (RNN) 계열은 본질적으로 입력 시퀀스의 토큰에 따라 시간축을 분해하여 , 계산을 수행한다.

전 단계의 hidden state( h t-1 )와 해당 위치에서의 input 토큰을 가지고 해당 시점의 hiddent state t를 계산할 수 있다.

이러한 순차적 특성 sequential nature은 학습 내부에서의 병렬화를 불가능하게 만든다. (GPU를 활용한 연산이 어렵다)

또한 이는 시퀀스 길이가 길어질 수록 문제가 커지며, 메모리 한계로 인하여 batch 병렬 처리도 제한되기 때문이다.

이를 해결하기 위한 다양한 방법이 논의되었지만 해결하지 못하였다.

 

->

 

RNN 구조의 본질적인 문제 "순차적 특성"으로 인한 병렬 처리 불가, 메모리 제약을 문제의 본질로 짚고 있는 것이다.

 


attention weighted map



Attention 매커니즘은 이미 다양한 Transduction, sequence modeling에서 핵심 구성요소가 되었다. 또한 Attention은

가까운 것만 잘 기억하는 RNN의 특성을 극복하여, 거리와 관계없이 (seq상의 거리) 요소간의 관계성 (token간의 의존성)을 모델링하게 해주었다. 하지만, 해당 attention은 여전히 recurrent network와 함께 사용되고 있다.

 

-> 

 

attention의 기능 ( seq 상 거리와 관계없이 연관된 요소간의 관계성을 기술 ) 과 유용함을 언급함과 동시에 이가 여전히  recurrent network와 함께 사용되는 문제점을 지적하고 있다.

 


In this work we propose the Transformer, a model architecture eschewing recurrence and instead relying entirely on an attention mechanism to draw global dependencies between input and output. The Transformer allows for significantly more parallelization and can reach a new state of the art in translation quality after being trained for as little as twelve hours on eight P100 GPUs.

 

본 연구에서는 recurrence를 제거하고, 대신에 전체적으로 attention 매커니즘을 활용하여 입력과 출력 사이 global dependencies를 기술하는 Transformer를 제안한다. Transformer는 more parallelization , 병렬화를 통해 짧은 시간의 학습만으로도 SOTA의 성능을 달성하게 되었다.

 

->

** introtuction의 중요한 부분 ! transformer 구조의 제안

기존 문제가 되었던 Recurrent models들의 순차성을 해결하기 위해 attention을 단순 RNN의 보조 도구에서 전체 모델의 백본으로 사용함으로써 해당 문제를 해결함과 동시에 병렬성을 개선

 


2. Background

RNN의 순차성을 개선하기 위해 CNN 구조에서의 접근도 있었다. (CNN 구조는 병렬처리에 용이함)

그러나, 기존 CNN애서 멀리 떨어진 두 위치끼리 상호작용하려면 여러 레이어를 거쳐야하는 문제가 있었다. ( RNN과 같은 거리 의존성 존재) . 결과적으로 CNN을 활용한 접근은 장거리 의존성 학습에 있어서의 어려움이 있었다.

 

 

.. 이에 관련한 transformer의 해결방법 간략하게 소개

Self-attention, sometimes called intra-attention is an attention mechanism relating different positions of a single sequence in order to compute a representation of the sequence

 

****

self-attention은 한개 sequence상의 여러 다른 위치간의 관계를 서술하는 방식으로 seq를 표현하는 attention 매커니즘이다. 해당 방법은 다양한 분야에 있어서 이미 성공적인 성능을 보여주는데 기여하였다.

 

To the best of our knowledge, however, the Transformer is the first transduction model relying entirely on self-attention to compute representations of its input and output without using sequence-aligned RNNs or convolution.

 

Transforemer는 RNN이나 CNN에 의존하지 않은 체 , self-attention에만 의존한 최초의 transduction 모델이다.

 

In the Transformer this is reduced to a constant number of operations, albeit at the cost of reduced effective resolution due to averaging attention-weighted positions, an effect we counteract with Multi-Head Attention as described in section 3.2.

트랜스포머의 attention weight를 활용한 계산때문에 정보의 소실이 일어나지만, 3.2에서 나오는 Multi-Head Attention으로 극복한다.

 

-> 

 

해당 논문의 method에서 사용할 주요 요소들을 저자가 간략하게 소개한다.

첫번째로 거리 의존성을 해결하는 self - attention. 

두번째로 attention weight로 인한 가중합계산으로  해상도가 저하되는 것을 multi - head attention을 통해 극복한다는 것이다.

( attention 된 부분이 표시된 weight mat를 정보 행렬에 곱하면 정보가 섞이는 문제가 생김 -> noise 발생 , 이를 multi - head 다양한 관점에서의 attention을 동시에 행함으로써 극복한다는 것이다 . )

 


RNN에서의 거리 의존성, 병렬처리의 어려움을 단지 self-attention 구조만을 쓰는 것으로 해결했다는 것을 논문 제목 그대로 표현하였다.

Attention is all you need !

Attention is all you need를 읽기에 앞서 간단한 자연어 처리 , RNN , seq2seq 구조, attention에 대한 사전지식을 공부했습니다.


 

1. RNN , Seq2Seq

attention, transformer란 애초에 자연어 처리를 목적으로 하여 만들어진 개념이기에 해당 분야에 대한 기본지식이 필요하다. 

기본적으로 RNN이란 , CNN과 같은 신경망에서 순차적인 정보를 이해하지 못하는 것을 해결하기 위해 만들어진 기법이다.

(sung kim 거이 끝부분에서 한번 배웠는데 스터디원들과 다같이 이해는 안되었지만 어물쩍 넘어간 기억이 난다)

그림에서 볼 수 있는 것 과 같이 상대 h ( 표면적으로는 안보인다고 하여 hidden state h라고 부른다. 대충 deep learning의 hidden state같은 개념 )를 다음 시점으로 넘겨주고 그 다음 시점에서는 이전 시점에서 받은 h와 input x를 참조하여 output o를 만들어 내는 것을 알 수 있다 .

 

좌측 그림은 해당 과정을 재귀적으로 표현한 것이고, 우측은 그냥 해당 과정을 펼쳐놓은 것이다.

 

수식을 통해 이해해보자(perflexcity의 도움을 얻었다),

위 node로 표현된 그림에서 v,w,u를 연결해주는 부분에 각각 가중치가 붙어있다.

CNN과 같이 RNN 또한, 원하는 성능을 만들어내기 위한 해당 가중치를 얻는 것이 학습의 목적이 되는 것으로 생각할 수 있었다.

(정확하게는 RNN 단독으로는 backprop을 통한 학습이 어려워 후에 LSTM 등 보완된 구조가 제안되었다고 한다)

 

 

RNN에서 유의깊게 봐야 할 것은 해당 모델은 seqence 즉, 순서가 있는 것을 처리하는 모델이라는 점이다.

이어서 관련이 있는 seq2seq를 봐보자.

 

seq2seq 란 RNN을 활용하여 번역을 하는 것과 같은 task를 처리하는 모델을 말한다.

왜 seq2seq인가 하면 "나는 모니터입니다." 를 "I'm monitor" 로 바꾸어 주는 모델을 생각해보면 입력도 순서가 있는 순서가 입력 seqence  출력 또한 순서가 있는 출력 seqence 임을 알 수 있다. 따라서 seq2seq이다.

 

기본적으로 seq2seq 모델은 encoder - decoder 구조를 띈다.

encoder는 input seqence의 "의미"를 context vector로 압축한다.

그리고 decoder는 context vector를 사용해 출력 문장을 한개 토큰씩 생성한다.

 

Encoder가 만든 문장의 전체 의미 " context vector" 를 참조하고, 이전에 decoder 자기 자신이 만든 state( hidden state)를 참조하여 다음에 생성할 토큰 (output)을 생성하는 것이다.

 

(자꾸 토큰이라는 단어가 사용되는데, token은 모델이 처리하는 최소 단위의 simbol이라고 보면 된다.

때에 따라서 단어가 될 수 있고, 음절이나 숫자, 코드, 로봇의 행동 <MOVE> ,<TURN>등이 될 수 있다. 조합되는 기호의 단위 즉 가장 작은 퍼즐의 단위라고 보면된다. )

 

이러한 seq2seq 방법에서의 문제점은 초기 encoder가 input을 압축해 생성한 context vector가 input의 길이가 길어지는 경우 context vector가 해당 input을 전부 표현하지 못하거나, 중요한 정보가 소실되는 경우가 생긴다. 이를 해결하기 위해 나온게 attention이다.

 


2. attention

이전 seq2seq에서는 하나의 context vector로 문장 전체의 의미를 표현하려고 하다 보니, 정보의 손실과 표현의 한계가 발생하는 문제가 생겼었다. 

다시 정리하면 encoder에서 나온 하나의 context vector를 사용해, 각 time(state)마다

이전의 state + 전체 문장의 한 개 context vector를 사용해 decoder에서 각 token을 생성해낸다.

 

여기서 attention 기법을 사용하면,

각 time step 마다

input sequence의 가공된 정보를 재참조한다. (context vector)

그런데 , 이 context vector는 단순히 이전 seq2seq에서 문장을 하나의 벡터로 다 표현한 context vector 가 아니라 

해당 time step에서 주목할 부분에 대한 고려 attention을 참조해서 encoder에서 input seqence를 가공한 

context vector이다.

 

정리하면, 매 step에서 전체 input 문장의 의미를 담은 축약본을 참고하는 것이 아닌,

해당 step에서 input 문장서 중요한 부분을 중심적으로 attention한 의미 표현 context vector를 참조한다는 것이다.

 

encoder의 hidden state와 decoder의 현재 state를 참조해 e를 만들어 낸다. (encoder의 각 state에 집중하는 정도 - scaler)

이에 대해 softmax 해주어 0~1 사이 확률값으로 만들어준다 (attention weights)

해당 확률값과 encoder의 hidden state를 weighted sum하여 해당 시점의 context vector를 만든다.

 

<encoder hidden state + decoder의 현재 state > -> e 부분은 MLP를 통해 구현 

전체 과정은 backprop이 가능하여 학습이 가능하도록 한다.

 


git/github 기초

좋은 유튜브 강의를 발견하여 기록 겸 리뷰해본당

https://youtu.be/9MTlFHmyjks?si=AxBwAc9kPT00nMcc


1. git을 설치해 준다

https://git-scm.com/

 

Git

 

git-scm.com

리눅스 유져는 터미널에 

sudo apt update
sudo apt install git

하면 된다.

 


 

 

2. git을 사용할 폴더를 만들어 준다. 

mkdir backbone_project

 


 

3. 

git을 사용하는 터미널을 git bash라고 한다 . mac에서는 자동설치가 되지 않고 window에서는 자동설치된다.

window에서 git bash를 열면 리눅스 명령어를 사용가능하다. 

리눅스는 git bash를 쓸 필요가 없다 그냥 터미널에 기본 명령어 입력하듯이 하면 된다. (cool)

 

기존 리눅스 명령어를 하듯이 git 명령어는 앞에 git을 붙이고 사용하는게 git 명령어이다.

 

 


 

4. 기본적인 git 명령어 예시를 봐보자.

 

>> 최초 설정간 필요한 명령어

git config --global user.name "Your Name"
git config --global user.email "YourEmail@example.com"

 

1. 커밋을 누가 했는지 이름

2. 유져의 이메일 

 

커밋을 했을 때 누가 했는지 정보를 남기기에 해당 정보를 기입하는 명령어이다. 

 

확인 

git config --global --list

 

>>두고두고 쓰는 명령어

 

git init 

현재 위치한 디렉토리를 git 저장소로 초기화한다.

 

git clone <원격 저장소 주소>

git clone https://github.com/user/project.git

 

github와 같은 곳에 올라와있는 it을 복사한다.

 

 


 

5. git의 관리영역 구조

 

git은 

1. working directory 

2. Staging Area 

3. Repository 

 

3개 영역으로 나누어 관리된다.

 

사실상 들어보니 1. 이 유져가 직접 작업하는 공간이고 2.3.은 git이 관리를 위한 가상의 공간이다.

정해진 명령어만 잘 입력해서 쓰면 된다.

 

git은 git 디렉토리의 수정사항을 tracking한다. 

tracking과 수정사항의 유무에 따라 파일을 아래와 같이 분류한다.

 

untracked file : 추적 X

unmodified file : 추적 O 수정 X

modified file : 추적 O 수정 O

 

문서는 1 -> 2 -> 3의 순서로 이동하며 버젼이 저장된다고 보면 된다.

2 -> 3 을 commit이라고 하고, 해당 내용들이 기억된다.

 


 

6. 관련한 명령어를 알아보자

 

git status 

git 프로젝트 상태 확인

 

git add 

1->2로 이동

git add . 하면 전부 이동

git add file.txt. 하면 특정 파일만 이동

 

git commit -m "커밋 메시지"

커밋 메시지에는 어떤 수정사항이 있었는지 간단히 적는다.

 

git log 

commit 이력 확인

 


 

7. .gitignore 

깃 디렉토리 내 수정 이력에서 제외하고 싶은 문서가 잇다면 이를 tracking에서 완전히 제외할 수 있다.

해당 이름의 파일을 만들고 tracking에서 제외하고 싶은 파일의 이름을 해당 파일 안에 넣으면 된다.

 

예를 들어 password나 민감한 개인정보등이 들어간 파일을 git상에 올라가지 않는 것을 원한다면 쓰는 기능이다.

 

 

8. git log 읽기

 

 

요상한 문자열이 커밋 해시라고 한다 : 커밋의 고유값 , 각 커밋의 주민번호 같은 느낌이다.

우측에 HEAD -> master 는 각각

HEAD 현재 작업중인 브랜치를 가리키는 포인터 (참조자)이고

여기서 master는 브랜치명인데, 기존 저장소에서 분기된 저장소의 복사본인 '브랜치' 이름이다 여기서는 master라 master라고 뜬거다. 

아직 두 개념이 제대로는 안나왔으니 쓰르륵하고 지나가자.

 

 

아래 커밋한 작업자의 정보

아래아래는 날짜와 시간

아래아래아래는 커밋을 할때 남긴 메시지이다. git commit -m " 여기에 쓴 메시지 "

 

9. 관련한 명령어를 학습해보자.

 

git log -p

커밋의 변경사항도 같이 출력하는 옵션

 

git log --oneline

log 한줄 요약본

 

git checkout 커밋해시 

문서의 내용을 특정 커밋의 내용으로 되돌리는 명령어

옛날 버전으로 돌아가기 

 

git reflog 

HEAD 포인터의 참조이력을 출력하는 명령어

 

요거를 사용해서 이전 커밋으로 돌아갔다가 relog로 다시 원래 커밋으로 돌아가는 예제는 꼭 해보는게 좋겠다. 

 

 


10. 실수관리하기 

 

 

git reset fail.txt

 

1. working directory

2. Staging Area 

3. Repository 

에서 2->1로 초기화 즉 add 한 특정 파일을 없세준당.

 

git reset  --soft  해시

git reset  --mixed 해시

git reset  --hard 해시

 

 

commit 한것을 되돌리기 할 수 있다. 3개의 옵션에 따라 얼마나 초기화할건지 달라지는데 

soft는 해당 커밋을 취소하고 변경사항은 2.에서 머무른다. (commit한 것 add로 돌아감)

hard는 커밋취소 add도 없어지고 1.에서 수정하던것도 실제로 변경되서 되돌아간다. 

즉 1. working directory 도한 이동한 커밋의 상태로 변경되어 돌아간다. 

mixed는 커밋취소 add취소 1.은 변경없다.

 

git revert 해시

git revert는 특정 커밋의 수정사항을 되돌리면서 되돌린 것 또한 커밋으로 남긴다.

1. 2.의 변화없이 3.의 변화만 있다.

 

해당 명령어를 기반으로 추천되는 실수 대응은 아래와 같다.

 

1. 스테이징 (add 실수)

git reset 파일명

 

2. 커밋 실수 여기서 HEAD^는 직전 커밋을 의미 HEAD~1도 동일

git reset --soft HEAD^     // 커밋만 취소 → 내용은 staging 유지
git reset --mixed HEAD^    // 커밋 취소 + add 취소
git reset --hard HEAD^     // 커밋 취소 + add 취소 + 파일 원상복귀

 

3. 커밋 실수인데 되돌리되 이를 기록하기 (젤 많이 씀)

git revet 커밋해시

 


11. 브랜치

 

전체 코드를 통째로 복사해서 원래 코드와는 상관없이 독립적으로 개발하는 것이 브랜치이다.

나무가 자라다 가지가 뿅하고 나오는 것과 같다.

깃이 처음 git init 하면 master라는 기본 브랜치가 있는데 (기본 브랜치가 main 인 경우도 있다. 단지 이름일 뿐이라 상관 X)

여러 브랜치를 분기해가며 작업할 수 있다.

또한 분기해서 자라나던 것을 병합하는 merge라는 기능 도 있다. 

 

git branch 

현재 브랜치 목록을 보는 명령어

 

git branch 브랜치이름

새로운 브랜치를 생성하는 깃 명령어

 

git checkout 브랜치이름

작업중인 브랜치를 변경하는 깃 명령어

 

git merge 브랜치이름

현재 브랜치에 다른 브랜치의 내용을 합치는 깃 명령어

 

여기서 merge의 경우에는 자동으로 합칠 수 있는 경우에는 자동 merge가 되지만

같은 줄 같은 블록을 서로 다르게 두 branch가 수정한 경우에는 충돌이 발생한다.

이런 경우에 직접 표시된 <<<< >>>>> ===== 

을 직접 선택하고 제거해야 한다. 대충 === 을 경계로 어떤 브런치에서 온 내용인지 표시해준다.

 

 


 

 

12. github

지금까지 local git을 사용하여 버전관리를 하는 방법을 배웠는데, 이를 사용해 흔히 아는 github와 연동하는 방법을 알아보자.

그래피컬한 GUI를 적용하기도 하고 편하다. 온라인에 원격 저장소를 만들어 관리할 수 있다.

 

 

1. working directory

2. Staging Area 

3. Repository 

GIT 의 3개 구조에서 끝에 4. GIT HUB REPO가 추가된다고 보면 된다.

 

관련한 명령어를 알아보자.

 

git remote -v

현재 깃에 저장된 원격 git 저장소를 확인하는 명령어

 

git remote add 원격저장소이름 원격저장소 주소

git을 github repo와 연결하고 별칭을 등록하는 깃 명령어

 

git push 

3.을 4로 이동

 

git pull 

4.를 3으로 가져와 자동 병합하는 명령어

 


github에서 repo를 만드는 창이다.

그냥 repo이름 

아래 privite public 선택

나머지는 신경쓸필요가 아직은 없다.

 

중요하게 봐야할 부분은 해당 내가 만든 repo의 주소이다.

 

git remote add 원격저장소이름 원격저장소 주소

 

해당 주소를 위의 우측에 적어서 연결하면 된다.

 

(base) choi@choi-Victus-by-HP-Gaming-Laptop-16-s1xxx:~/backbone_project$ git remote add backbone https://github.com/helloimsuhyun/backbone_repo.git
(base) choi@choi-Victus-by-HP-Gaming-Laptop-16-s1xxx:~/backbone_project$ git remote -v
backbone https://github.com/helloimsuhyun/backbone_repo.git (fetch)
backbone https://github.com/helloimsuhyun/backbone_repo.git (push)

 

이제 내 로컬 git의 파일을 업로드해보자

 

이 전에 초기 설정이 필요하다.

 

git push -u origin main

 

내가 정확히 어떤 저장소에 어떤 브랜치에 push를 할 것이다 라는 것을 지정하는 작업이다. (초기 1회만 하면 됨, 이후에는 git push 만 해줘도 됨)

origin 저장소에 main 브랜치에 push한다는 뜻 여기서 origin은 

git remote add 원격저장소이름 원격저장소 주소 여기에서 지정한 원격저장소 이름이다.

 

(base) choi@choi-Victus-by-HP-Gaming-Laptop-16-s1xxx:~/backbone_project$ git push -u backbone master 
Username for 'https://github.com': 
Password for 'https://helloimsuhyun@github.com': 

 

** 여기서 유져네임과 비밀번호를 요구하는데 비밀번호가 github 패스워드가 아니라는 함정이 있다.

뭐 토큰을 받아서 항상 복붙해서 쓰는 방식인데 매우 귀찮다 SSH 키를 만들어 내 컴퓨터와 GIT사이이를 연결해주면 비번없이도 로그인 가능 

 

1. ssh-keygen -t ed25519 -C "helloimsuhyun" 

내 컴퓨터에서 SSH 키 생성

 

2. cat ~/.ssh/id_ed25519.pub

출력되는 문자열을 복사

생성된 SSH key를 github SSH and GPG keys에 등록 ssh key 

3. 

git remote set-url origin git@github.com:username/repository.git

과 같이 SSH를 받아서 remote로 이제 ssh로 연결하겠다 선언하면 된다.

 

정리 

1. 내 git local을 repo에 연결하는 경우

git remote add origin git@github.com:username/repository.git

 

2.이미 github에 있는 repo를 가져와서 한는 경우

git clone git@github.com:username/repository.git

(remote안해도 연결되어 있음)

 

3. URL 방식으로 연결되어 있는 것 SSH방식으로 변경

git remote set-url origin git@github.com:username/repository.git

 

 

 

1. binary prediction and sigmoid

추론값의 결과가 0 또는 1로 나타나는, 이진 모델binary classification 모델에 쓰이는 sigmoid함수에 대해 알아보자.

sigmoid

정의역이 실수 전체이고, 치역이 0 과 1 사이인 sigmoid 함수는 답이 True / False 형태로 나오는 문제에 적용하기 좋다.

정의역에서 -4 또는 4 밖으로 벗어나는 값을 가지면 함숫값이 0 또는 1에 근사하는 모습을 볼 수 있다.

 

또한 해당 함수는 값이 0~1 사이의 값으로 나온다는 점에서, 추론값이 확률로 필요할 때 쓰이기도 한다.

 

2. Logistic Regression(로지스틱 회귀)

로지스틱 회귀란, 선형 모델에 simoid함수를 결합하여 사용한 모델이라고 볼 수 있다.

사건의 발생 여부 (이진 분류)를 단순 선형 모델로 표현하는 경우, 새로운 값의 추가가 기존 분류 모델에 큰 영향을 미칠 수 있다.

기존의 선형 모델을 분류에 더 적합하게 완만한 곡선으로 나타내여, 이를 방지하는 것이다. 

로지스틱 회귀의 이진 분류

 

치역에서 0.5를 기준으로 TURE / FALSE를 결정한다. 아래에 로지스틱 회귀와 관련한 설명 블로그를 추가한다.

https://itstory1592.tistory.com/8

 

2. Binary Cross Entropy Loss(이진 교차 엔트로피 loss)

모델의 출력이 0~1인 확률값으로 나오므로 기존에 쓰던 MSE Loss 의 대안인 Binary Cross Entropy Loss를 사용한다.

\[
\mathcal{L}(y, \hat{y}) = - \left[ y \cdot \log(\hat{y}) + (1 - y) \cdot \log(1 - \hat{y}) \right]
\]

 

loss의 기본적인 원리는 모델의 예측값이 참에 가깝다면 loss가 작고, 참에서 멀어질 수록 loss가 큰 것을 이용한 것이다.

dataset에서 y의 값이 0 또는 1 인 점에 주목해며, 해당 식을 봐보자. 해당 식에서 y가 0또는1임에 따라 덧셈 기준 좌항과 우항이 활성화 되고, 나머지 항은 없어지는 것을 볼 수 있다.

 

  • y (참값) - 1인 경우 > -log(?)안에 y_pred 가 들어감 > log(y_pred) > y_pred가 1에 가까울 수록 loss 작음
  • y (참값) - 0인 경우 > log(1-?)안에 y_pred 가 들어감 > log(y_pred) > y_pred가 0에 가까울 수록 loss 작음

 

Binary Cross Entropy Loss
log 함수 - 해당 loss계산시에는 정의역이 sigmoid의 치역이므로 0~1인점을 고려해야 한다.

 

3. Code 

sigmoid 모델을 사용한 로지스틱 회귀 torch 구현 코드이다.

기존 선형 회귀 모델에서 model class 정의, loss function 의 종류만 다르다.

import torch

x_data = torch.tensor([[1.0],[2.0],[3.0],[4.0]])
y_data = torch.tensor([[0.],[0.],[1.],[1.]])


class Model(torch.nn.Module):
   def __init__(self):
      super().__init__()
      self.linear = torch.nn.Linear(1,1)

   def forward(self,x):
      y_pred = torch.nn.functional.sigmoid(self.linear(x))
      return y_pred

model = Model()
criterion = torch.nn.BCELoss(reduction='mean')
optimizer = torch.optim.SGD(model.parameters(), lr = 0.01)

with torch.no_grad():
   hour_var = torch.tensor([[7.0]])
   temp = model(hour_var)
   print(" 학습 전 7.0에 대한 추론값 ", temp.item())
   print(f'Prediction before 7.0 hours of training: {hour_var.item():.4f} | Above 50%: { temp.item() > 0.5}')

for epoch in range(100):

   y_pred = model(x_data)
   loss = criterion(y_pred,y_data)
   print("epoch loss",epoch, loss.item())
 
   optimizer.zero_grad()
   loss.backward() 
   optimizer.step()
 

with torch.no_grad():
   hour_var = torch.tensor([[7.0]])
   temp = model(hour_var)
   print(" 학습 후 7.0에 대한 추론값 ", temp.item())
   print(f'Prediction after 7.0 hours of training: {hour_var.item():.4f} | Above 50%: { temp.item() > 0.5}')







냠냠 선형회귀

1. in pytorch rhythm 

앞서 했던 과정들을 torch 코드를 짜는 방식으로 실제 코드를 짜는 것을 배워보는 강의이다. torch 에서는 아래와 같은 절차로 학습을 진행한다.

 

  1. Design model using class
  2. construct loss and optimizer
  3. Training cycle (forward, backward, update)

전체 코드를 한줄한줄 분석해보자.

 

Design model using class

모델 디자인 전, 우선적으로 dataset을 정의한다.

import torch

x_data = torch.tensor([[1.0], [2.0], [3.0]])
y_data = torch.tensor([[2.0], [4.0], [6.0]])

 

import torch : torch 라이브러리를 불러옴

x_data = torch.tensor([[1.0], [2.0], [3.0]])
y_data = torch.tensor([[2.0], [4.0], [6.0]])

 

tensor를 형성, 3*1의 텐서이다.

 

(+)

텐서의 크기 분석을 위해 .shape를 많이 사용한다. 

print(x_data.shape

 

torch.Size 객체 반환

위위 경우에는 torch.Size([3,1]) 반환 3행 1열 (행렬)

 

+ 만약 이미지를 텐서로 만들었을 때는?

[batch_size, channels, height, width] > [B,C,H,W]

B batch는 B개의 이미지 

channel 한개 이미지의 3가지 색상 채널(ex RGB) 등으로 쓰임

 

class Model(torch.nn.Module):

torch.nn.Module을 상속받아 torch model로 동작, 클래스 이름은 자유

class Model(torch.nn.Module):
     def __init__(self):
          super().__init__()
          self.linear = torch.nn.Linear(1, 1) # One in and one out

 

  • 생성자 __init__ : 클래스 Model을 인스턴스 하였을 때, 자동적으로 실행되는 함수
  • super().__init__() : 부모 클래스인 torch.nn.Module의 초기화를 진행(부모 클래스의 __init__ 을 실행한다는 말과 같음)
  • self.linear = torch.nn.Linear(1,1) : 선형 레이어 (y = w*x+ b)를 생성
    • 원형은 torch.nn.Linear(in_features=1, out_features=1) 
    • torch 내부에서 자동으로 weight와 bias를 학습 대상으로 만듬 (requires_grad=True)
def forward(self, x):

   y_pred = self.linear(x)
   return y_pred

 

  • def forward(self,x) : torch.nn.module을 상속한 클래스는 반드시 foward()매서드를 정의해야 한다.
  • 해당 매서드는 모델이 입력을 받아 출력을 계산하는 방법을 정의한다.
  • 모델을 호출할 떄, model(x)라고 쓰면 자동적으로 model.foward(x)가 호출된다. (추론)

   y_pred = self.linear(x)

 

  • 위에 __init 에서 정의한 레이어에 입력 x를 전달, 레이어를 통과한 값이 변수에 저장된다
   return y_pred
  • 추론값 return

해당 과정 전체 코드

import torch

x_data = torch.tensor([[1.0], [2.0], [3.0]])
y_data = torch.tensor([[2.0], [4.0], [6.0]])

print(x_data.shape) # 결과: torch.Size([2, 2])

class Model(torch.nn.Module):
   def __init__(self):
      super().__init__()
      self.linear = torch.nn.Linear(1, 1) # One in and one out

   def forward(self, x):

      y_pred = self.linear(x)
      return y_pred

construct loss and optimizer

#model
model = Model()
criterion = torch.nn.MSELoss(reduction='sum')
optimizer = torch.optim.SGD(model.parameters(), lr=0.01)

 

  • model = Model()  위에서 정의한 모델 클래스를 인스턴스한다.
  • criterion 손실함수(loss function)을 의미하는 이름
  • optimizer 모델의 파라미터 (가중치 등)을 업데이트하는 알고리즘을 말함

criterion = torch.nn.MSELoss(reduction='sum')

  • critertion 손실 함수 객체, criterion = torch.nn.MSELoss(reduction='sum') > MSE를 사용
  • retuction = 'sum' 오차들을 모두 더한 값을 사용
  • MSRLoss의 옵션 reduction='mean' : 우리가 생각하는 MSE (기본값)
  • MSRLoss의 옵션 reduction='sum' : 오차 제곱의 합
  • MSRLoss의 옵션 reduction='none' : 각 요소별 개별 loss를 텐서 형태로 반환 

optimizer = torch.optim.SGD(model.parameters(), lr=0.01)

  • optimizer 파라미터를 업데이트하는 알고리즘 객체
  • SGD (Stochastic Gradient Descent) 확률적 경사 하강법을 사용
    • model.parameters() : 모델에서 업데이트 할 파라미터들, nn.Model을 상속받은 객체가 .parameters() 매서드를 가짐, 모델 내에서 자동으로 학습 가능한 모든 파라미터(weight, bias)를 수집하여 반환
    • lr = 0.01 : learnning rate

Training cycle (forward, backward, update)

for epoch in range(500):
   # 1) Forward pass
   y_pred = model(x_data)

   # 2) Compute and print loss
   loss = criterion(y_pred, y_data)
   print(f'Epoch: {epoch} | Loss: {loss.item()} ')

   optimizer.zero_grad()
   loss.backward()
   optimizer.step()

 

추가로 저번 시간에 했던 학습 부분 코드와 비교하며 알아보자

 

for epoch in range(100) :
   for x_val, y_val in zip(x_data, y_data) :
   l = loss(x_val, y_val)
   l.backward() # back propagation
   with torch.no_grad():
   w -= rl * w.grad # l.grad = d_loss / d_w
   w.grad.zero_()
   print ("\t loss grad w ", l, w.grad, w)

 

1) forward pass

y_pred = model(x_data)

  • 객체 model(x)를 호출하면, 자동적으로 model.foward(x) 매소드가 호출되어 추론값을 return한다.
  • input 3*1 tensor , output 3*1 tensor

loss = criterion(y_pred, y_data)

  • criterion 객체를 이용 , loss를 계산한다.

 

2) Backward

optimizer.zero_grad()

  • 기울기 초기화, 저번 포스트에서도 확인했지만, torch는 grad를 누적합 하기 때문에 초기화를 해줘야 한다

loss.backward()

  • loss에 대해 모델 파라미터의 grad를 계산, back - propagation , 결과는 .grad에 저장
  • 각 파라미터에 대해 dL / dparm 구해놓음

3) update

optimizer.step()

  • 가중치 (파라미터) 를 업데이트하는 알고리즘 객체인 optimizer로 파라미터를 update
  • 여기에서는 SDG 확률적 경사 하강법으로 업데이트하는 부분
  • 어떤 파라미터를 업데이트하는지는 optimizer 객체 선언시에 model.parameters()로 이미 넣어져 있음
  • 저번 포스트의 코드에서는 각각의 데이터를 for문으로 각각 하나하나 기울기를 계산해, 가중치를 업데이트했지만, 만약 데이터셋이 많아지는 경우 해당 방법은 시간이 매우 오래 걸림, 여기 torch의  SGD를 사용할 떄는 batch (데이터 포인터들의 묶음, 여러개의 데이터포인트 뭉치) 를 같이 넣어 동시에 기울기를 구함

 

추론, 검증

 

# After training
with torch.no_grad():
   hour_var = torch.tensor([[4.0]])
   y_pred = model(hour_var)
   print("Prediction (after training)", 4, model(hour_var).item())

 

with torch.no_grad():

추론 및 검증에서는 autograd 쓸 이유 없음 > 기능끄기

 y_pred = model(hour_var)

임의로 설정한 input인 hour_var 텐서로 output을 추론 y_pred에 저장

   print("Prediction (after training)", 4, model(hour_var).item())

model(hour_var).item()

결과인 텐서의 요소가 하나기에 .item()을 사용해 순수한 숫자 float로 변형

(tensor는 자체 객체라 출력, 외부 함수와 호환 힘들 떄 있다. 추가로 item은 요소가 하나일때만 사용가능)

 

 

전체 코드 

수업에서 사용한 코드를 살짝쿵 수정했는데 거이 같다. (복붙과정에서 들여쓰기는 날라갔는데 귀찮아서 그냥 냅둠)

import torch

x_data = torch.tensor([[1.0], [2.0], [3.0]])
y_data = torch.tensor([[2.0], [4.0], [6.0]])

print(x_data.shape) # 결과: torch.Size([2, 2])

class Model(torch.nn.Module):
def __init__(self):
super().__init__()
self.linear = torch.nn.Linear(1, 1) # One in and one out

def forward(self, x):

y_pred = self.linear(x)
return y_pred


#model
model = Model()
criterion = torch.nn.MSELoss(reduction='sum')
optimizer = torch.optim.SGD(model.parameters(), lr=0.01)

# Training loop
for epoch in range(500):

y_pred = model(x_data)
print("train pred", y_pred)
loss = criterion(y_pred, y_data)
print(f'Epoch: {epoch} | Loss: {loss.item()} ')

optimizer.zero_grad()
loss.backward()
optimizer.step()


# After training
with torch.no_grad():
hour_var = torch.tensor([[4.0]])
y_pred = model(hour_var)
print("Prediction (after training)", 4, model(hour_var).item())

+ Recent posts