독일 블루카드 발급을 받으려면 대학교 학력이 필요하다.
독일에서 대학교를 졸업했으면 졸업장 그대로 보여주면 되겠지만, 그 외에는 경우에 따라 별도의 학력 인정 절차가 필요할 수 있다.
자신이 학력 인정 절차가 필요한지 알고 싶다면 아래 과정을 따르면 된다.

<간단 설명>
- 1) Anabin에 대학교 등급이 H+ 이다
- 2) Anabin에 학위('이학사', '공학사', '법학사' 등)가 대학교와 함께 등록되어 있다

위 2가지 조건을 모두 충족하면 별도로 학력 인정을 받지 않아도 된다(고 Make it in Germany라는 웹사이트에 명시되어 있음).
(대신 학력 관련 서류 제출 시 Anabin에 등록되어 있는 내역을 함께 첨부해야 할 것임)

조건 충족이 되지 않으면 (혹은 어떤 식으로든 리스크를 줄이고 싶다면) 안전하게 학력 인정을 받는 것이 좋다.

학력 인정 필요 여부 알아보기

  1. 독일 대학 데이터베이스 Anabin 들어가기
  2. 학교 등급 확인하기
    • 2-1. 대학교 찾기
      • 좌측 사이드바 Institutionen 클릭 -> Suchen 클릭 -> Länderauswahl öffnen 클릭 -> K 클릭 -> Korea (Republik) 선택 -> LänderauswahlLänderauswahl bestätigen 클릭
      • Alle Orte 클릭 -> 본인 대학교 위치(ex. 서울) 찾아서 선택하기
      • Alle Institutionstypen 클릭 -> 본인 대학교 유형(ex. 국립 = National University) 선택하기
      • Bitte geben Sie einen Suchbegriff ein 입력란에 본인 대학교 영문명 등 키워드 입력으로 바로 찾을 수도 있음
    • 2-2. 대학교 등급 확인하기
      • 목록에 나온 본인 대학교가 H+ 인지 확인하기
      • H+가 아니라면 학력 인정이 어려울 수 있음
  3. 학위 존재 여부 확인하기
    • 여기서 말하는 학위는 단순 '학사', '석사'가 아닌 '이학사', '공학사', '법학사' 등 세분류를 말함
    • 대학교 등급이 H+ 라고 해도 Anabin에 학위까지 같이 올라와 있지 않으면 학력 인정 신청을 받아야 할 것임
    • 3-1. 학위명 찾기
      • 좌측 사이드바 Hochschulabschlüsse 클릭 -> Suchen nach Abschlüssen 클릭 -> 국가 선택
      • Alle Abschlusstypen 클릭 -> 본인 학위 과정(ex. 학사, 석사) 선택
      • Alle Studienrichtungen 클릭 -> 본인 전공(ex. 컴퓨터과학) 선택
        • 선택지를 보면 알겠지만, 한국어 발음 그대로 영어로 써있거나 한국어로 써있거나 하는 등 여러 경우가 있음
        • 어찌 되었든 본인에게 해당하는 것들 하나씩 선택해가며 확인해봐야 함
    • 3-2. 학위명과 대학교가 연결되어 있는지 확인하기
      • 목록에 찾고자 한 학위명이 나왔다면 좌측 + 버튼을 누른다
        • 같은 학위명이 여러 개가 있을 수 있으니 하나씩 들어가서 확인해봐야 함
      • 스크롤을 내려 Verleihende Institutionen 에 자신의 대학교가 있는지 확인한다
        • 학위명은 자신의 것과 일치하더라도 여기에 자신의 대학교가 연결되어 있지 않다면 학력 인정이 필요할 것임

학력 인정 필요 여부를 알았고, 인정을 받아야겠다면 아래 절차를 따르면 된다.

학력 인정 신청하기

<신청 전 알아둘 것>
1. 블루카드 신청 목적이라면 2주 내, 그 외의 일반적인 경우는 3개월 내로 처리됨
2. 서류 미비 등으로 추가적인 커뮤니케이션이 필요할 경우 위 기간은 더욱 길어질 수 있음

그러니 각자의 경우에 맞게 준비물을 잘 챙겨서 신청하는 것을 추천한다.

준비물

<주의사항>
- 모든 서류는 photocopy이어야 함 (사진 촬영이나 스캔본, 인터넷에서 바로 다운로드 받은 pdf)
- 번역되지 않은 것이어야 함 (원본, 원어 그대로 제출. 공증받지 않아도 됨 - 2024년 3월 20일 기준)

보다 구체적이고 정확한 내용은 아래 링크 참고
- Pre-Check for Statement of Comparability
- Statement of Comparability for university degrees from the Republic of Korea: Checklist
  • 졸업증명서(Degree certificate) or 학위기(Graduation certificate)
  • 학업성적증명서(Transcript of records for the entire degree program)
  • 학위 프로그램 종류 증명서(Certificate from your university stating your mode of study)
    • 졸업증명서 등에 표시되어 있지 않은 경우에만 필요
  • 졸업 논문 증명서(Certificate from your university confirming the completion of a final thesis)
    • 졸업 논문 작성했으나 졸업증명서 등에 표시되어 있지 않은 경우에만 필요
  • 이전 학교 학점 증명 관련 서류(Documents regarding transferred credit)
    • 편입 등 한 경우에 필요
  • 고등학교 졸업장(Secondary school qualification)
    • 또는 이와 동등한 자격을 나타내는 서류
  • 여권
  • 고용계약서 (블루 카드 비자 신청 시에만 필요)

 

신청 절차

  1. ZAB 사이트 접속하기 (영어가 아니면 우상단의 버튼 눌러 언어 변경하기)
  2. 계정 생성하기
    1. 우상단 My Account 버튼 클릭
    2. 이동한 사이트에서 KONTO ERSTELLEN 클릭
    3. 맨 우측 Benutzername & Passwort 클릭 후 KONTO ERSTELLEN 클릭
    4. 체크박스 클릭 후 WEITER 클릭
    5. 정보 입력 후 WEITER 클릭 -> 폰 번호, 이메일 입력 후 WEITER 클릭 -> 이메일로 인증번호 전송
    6. 이후 과정 거쳐서 계정 생성 완료하기
  3. 로그인하기
    1. ZAB 사이트 접속 후 우상단 My Account 버튼 클릭
    2. 이동한 사이트에서 ANMELDEN 클릭
    3. Benutzername & Passwort 클릭 후 WEITER MIT BENUTZERNAME UND PASSWORT 버튼 클릭
    4. 계정 정보 입력 후 엔터
    5. WEITER ZUM ANTRAG 클릭하여 ZAB 사이트로 되돌아오기
  4. 학력 인정 신청 양식 채우기
    1. 우상단 My Account 드롭다운 -> My Profile 클릭 -> 정보 채우기 (여기 미리 채워놓으면 Application page에 자동 입력됨)
    2. 상단의 STATEMENT OF COMPARABILITY 드롭다운 -> Application login page 클릭
    3. 기본 정보 확인하기 (또는 채우기)
    4. Previous Statements of Comparability 단계에서 No 클릭 (이전에 해봤다면 이 글이 필요가 없으실테니...)
    5. University degree to be evaluated 단계에서
      1. 국가(Korea (Republic))와 학위 과정(Bachelor 등) 선택하기
      2. 대학교 정보 입력하기 (중요한 것은 Anabin에서 사용되는 정보를 그대로 쓴다는 것)
        1. Name of the university degree: I Haksa (=이학사)
        2. Degree program: Haksa (=학사)
        3. Specialization: Keompyuteo Gwahak (이러면 알아서 서류 발급 시 옆에 괄호로 독일어로 된 전공명 남겨줌)
        4. Name of the university: Anabin에 올라와 있는 대학교명
        5. City of university: 대학교 위치한 도시명
        6. Period of study
          1. Start of university enrollment: 첫 학기 시작일 (ex. 2024년 1학기 = 04 03 2024)
          2. End of university enrollment: 마지막 학기 등록일(ex. 2024년 2학기 = 01 09 2024)
          3. Date the university degree was conferred: 졸업일
          4. Date the university diploma was issued: 졸업증명서 또는 학위기 발급일 (문서에 적힌 그대로)
          5. Certificate number of the university diploma: 학위등록번호
        7. Mode of study: 풀타임/파트타임 그리고 원격 교육 여부
        8. Duration of study: 4년제인 경우 4
        9. Final thesis: 졸업논문 작성 여부
        10. EU Blue Card: 학력 인정이 블루카드 신청에 필요한 경우 yes
    6. Additional university degree 단계에서 No 클릭 (한번에 여러 개가 필요한게 아니라면)
    7. Information about your secondary school qualification 단계에서
      1. Secondary school qualification required for university admission: High School Diploma 입력
        1. 그 외 경우는 각자에게 알맞은 것을 찾아 입력하기
      2. Country: Korea (Republic) 선택
      3. Date of secondary school graduation: 고등학교 졸업장에 표기된 날짜 입력하기
    8. Documents 단계에서
      1. Identity document (passport or identity card): 여권 인적사항면 나오게 찍어 올리기 (본인은 서명란까지 포함해서 찍음)
        1. 간혹 업로드가 안 되는 경우가 있는데, 사진을 제대로 안 찍었다거나 하면 그러는 것으로 추정함 (정확한 이유는 불분명)
        2. 만약 업로드가 되지 않으면 여권을 제대로 수평에 맞춰서 찍었는지, 그림자가 생기진 않았는지 등 점검해보기
      2. Proof of name change (e.g. marriage certificate): 개명 등의 이유로 성명이 변경된 적이 있을 경우 이에 대한 증빙자료 첨부하기
        1. 본인의 경우 개명을 했기에 주민등록초본(한국어)을 첨부함
        2. 또한 고등학교 졸업장과 대학교 졸업장의 이름이 다른데, 이는 신청서 마지막 즈음 메시지 남기는 곳에 설명을 하였음
      3. Employment contract or written confirmation of employment from your future employer in Germany: 고용계약서 첨부하기
    9. Documents regarding 단계에서 대학교 관련 서류 첨부하기
      1. 졸업증명서와 학업성적증명서 두 가지만 필수임
      2. Certificate from your university stating your mode of study: 별도로 제출하지 않았으나, 각자의 서류 확인하여 필요에 따라 알맞은 서류 첨부하기
      3. Certificate from your university confirming the completion of a final thesis: 나의 경우 졸업논문 대신 교내 대회 수상으로 졸업논문대체를 했기에 수상 내역(상장)을 첨부함. 이에 대한 내용은 마지막 메시지란에 설명을 남겼음
      4. Documents regarding transferred credit: 편입 등으로 학교를 옮긴 경우, 이전 학교 '학업성적증명서' 첨부하기
    10. Overview of your university degrees 단계에서
      1. 블루카드 신청을 위한 것이라면 Statement of Comparability for an EU Blue Card에 체크되어 있는지 확인하기
      2. 수수료 200유로 확인하기
    11. Consents and declarations 단계에서 체크할 것은 체크하고 yes할 것은 yes하기
    12. Please check your information 단계에서
      1. Documents regarding "Secondary school qualification" 항목을 열면 비어 있을 것임. Edit을 누른 후 이동하여 고등학교 졸업장 첨부하기
      2. 이후 Save and Next 버튼을 쭉쭉 누르면 다시 Please check your information 단계로 돌아올 것임. 이제 입력사항 전체 검토하기
      3. Message to the ZAB 입력란에는 별도로 설명이 필요한 사항에 대하여 설명 남기기
    13. 이후 Submit application (subject to a fee) 버튼을 누르면 결제 단계로 넘어감
      1. Paypal 계정이 있다면 이를 사용하는 것을 추천. 다른 옵션으로 하다가 여러 번 오류가 발생하였음.
      2. Paypal로 결제 시 주의할 점: 결제 통화가 USD로 되어 있을 수 있는데, 이를 EUR(유로)로 변경한 후 결제하기. 안 그러면 오류남.
      3. 정상적으로 결제 처리가 되었다면 이메일로 Paypal에서 보낸 결제내역이 들어올 것임
    14. 결제 완료 후 Application 상태 확인하기
나의 경우 결제 완료 후 상태를 확인해보니 여전히 Waiting for Payment라고 되어 있었음
게다가 ZAB 사이트 내 My Message 페이지를 보니 200유로를 내야 한다는 안내 메시지가 와 있었음
예상하기로는 결제 이후 ZAB 측에 실제로 입금된 후에 완전한 결제 완료 처리가 되는 것으로 보임
허나 마냥 기다리진 말고, 확실한 처리를 위해 나처럼 결제 증빙자료를 미리 전송해두는 것을 추천함
      1. My Applications 페이지로 이동하기
      2. 신청 진행 중인 항목의 우측 점 3개 버튼 클릭 -> Send message 라고 하는 버튼 클릭
      3. Category에서 Payment 선택하기
      4. Subject와 Your message는 결제 증빙자료를 전송한다는 주제로 입력하면 됨
      5. 잊지말 것: Paypal에서 보낸 결제내역 이메일을 pdf로 만들어서 메시지에 첨부하기

여기까지 하고서 기다리면 (별 문제가 없는 한) 상태가 In process라고 변경될 것이다.
진행 상황이 변경되었거나 혹은 어떠한 문제가 있는 경우 ZAB 사이트의 My Messages에 메시지가 들어올 것이니, 메일 등을 잘 확인하는 것을 추천한다.

나의 경우

3월 15일(금) 결제완료
3월 18일(월) 결제 확인 & 상태 변경(In process)
3월 20일(수) 학력 인정 서류 발급 완료

이렇게 영업일 기준 4일만에 발급이 완료되었다.

 

마무리

독일에서 대학교 학력 인정을 받는 것에 대하여 구체적인 정보가 없어서 여러 시행착오가 있었다.
몇몇 블로그를 남겨주신 분들이 있었으나, 이마저도 다소 시간이 지나간 것들이라 지금의 정책과 다른 부분들이 있었다.
이미지도 없어 다소 불친절할 수도 있을 것 같긴 한데... 그래도 본 글이 독일에서 학력 인정을 받으려고 하시는 분들에게 도움이 되길 바란다.


<참고 자료>

프롬프트 엔지니어링 / 리버스 프롬프트 엔지니어링

  • 프롬프트 엔지니어링:
    • 타겟에 대하여 순방향
    • 목표로 하는 답을 얻기 위해 질문을 던짐
    • 원하는 결과가 나올 수도 있고 안 나올 수도 있음
  • 리버스 프롬프트 엔지니어링:
    • 타겟으로부터 시작하여 역방향
    • 이미 이루어진 목표로부터 출발하여 질의응답을 가져옴
      • ex. 이미 부자인 사람이 어떻게 부자가 되었는지 그 삶을 추적하기

생성 AI의 결과물 특징

  • 생성 AI는 동일한 결과를 재생산할 수 없음
    • 난수를 통해 결과를 만들어내기 때문
    • 이 결과에 대한 분산을 줄이기 위해 필요한 것이 프롬프트 엔지니어링
    • 비유: 오은영 박사와 강형욱 조련사의 공통점 = 문제 있는 아이 혹은 개를 온순하게 만듦
      • 프롬프트 엔지니어링도 마찬가지, (결과가) 마구 날뛰는 생성 AI를 온순하게, 의도대로 작동하게 만드는 것임

Few Shot Learning

  • 기존의 딥러닝 모델: GB 단위의 데이터가 있고, 이를 학습해야 함
  • chatGPT: 상황에 맞는 예시 몇 개만 던져줘도 결과를 낼 수 있음(=few shot learning)
    • 몇 천억 또는 몇 조 개의 점(=파라미터)을 미리 찍어놓음(=pre-trained)
    • 입력받은 값이 이 점들의 사이 어딘가에 찍히면 기존에 있던 주변 점들을 이용하여 답을 유추해내는 것임

chatGPT cross check용 서비스

파이썬을 배워라

  • 파이썬 학습을 추천. 텍스트 마이닝, 정규식 등 결국 chatGPT에게 지시를 잘 내리기 위해 필요
  • 질문을 일일이 손으로 입력하는게 아니라 자동화를 해야 함. 그래서 파이썬이 필요함

chatGPT 특징

  • 360여 개의 act as mode 존재
  • IQ 조절 가능(평균 147. 최대 190~210 정도 세팅 가능)
  • 답변 퀄리티 10점 만점 세팅 가능 but 보통 4점 수준
  • 토큰 한계: 4000개
    • openAI tokenizer를 통해 질문의 토큰 갯수 카운트 가능
  • 프롬프트 사이즈 TL;DR(Too Long; Didn't Read)
  • 인공지능 윤리를 유지함

chatGPT 사용 tip

  • 답변 iteration(더 좋은 답변을 요구하며 다시 질문)을 하면 할수록 답변은 좋아질 수밖에 없음
  • 답변이 나오면 그 결과에 대한 뒷배경에 대해서 질문하여 알아낼 필요가 있음
  • 온도(temperature - 하이퍼 파라미터 중 하나)별 다른 결과값
    • 0 ~ 1 범위(=결과값의 분산 크기)
    • 0: 보수적, 안정
    • 1: 진취적, 불안정
    • default: 0.5 / optimized: 0.8 (강연하신 교수님 기준)
  • 하이퍼 파라미터 세팅
    • 질문 입력 시 하이퍼 파라미터 세팅 가능
    • 변경 가능 하이퍼 파라미터 목록: mode, tone, maximum_length, frequency_penalty, presence_penalty, temperature
  • 사용 사례
    • 유튜브 쇼츠용 캡션 생성
    • 슬로건 생성
    • 단어 뉘앙스 확인
      • 모르겠으면 예시 들어달라고 하기(구체적인 예시 3~5개)
    • 은유적 표현
    • 알고리즘 소스코드 생성
      • act as a python intepreter 이런 식으로 명령 가능
    • 코드 해설 및 다른 언어로 변환
    • 코드 최적화

정리

  • 인공지능은 결국 함수
    • 프롬프트 = 함수 <-> 리버스 프롬프트 = 역함수
    • 인간 = 지휘자 <-> 인공지능 = 오케스트라
      • 오케스트라가 다루는 악기(인공지능)를 어느 정도 알아야 제대로 지휘를 할 수 있음
  • 프롬프트 구성
    • 주제: 생선 뼈대(명사)
    • 맥락: 생선 살점(형용사)
      • 맥락 = 배경 설명(방향과 범위)
    • 분량
    • 표현(글의 형식. ex. 에세이)
  • 지시형 프롬프트: chatGPT가 모르는 정보를 요구하면 무용지물
  • 예시형 프롬프트: 관련 정보, 예시 등을 포함하여 프롬프트 작성
    • 잘못된 정보를 줄 경우 편향이 걸릴 수 있음

<추가 자료>

'etc.' 카테고리의 다른 글

[etc.] 독일에서 한국 대학교 학력 인정 받기 (feat. ZAB)  (1) 2024.03.21
[Sum.] 좋은 개발자란?  (1) 2023.03.14

"좋은 개발자란 무엇인가?"
근 몇 개월 간 계속해서 마음속에 품고 있던 화두이다.
마침 이에 대하여 집중해서 살펴볼 시간이 있어, 같은 주제에 대하여 다른 분들의 생각이 담긴 글들을 읽어보았다.
여러 생각 및 의견 그리고 조언이 있었고, 어렴풋이나마 좋은 개발자가 어떤 개발자인지 알 수 있었다.

다만 여전히 내 스스로가 정의하는 "좋은 개발자"는 아직 분명해지지 않았다.
글을 쓰신 분들에 비하여 지식과 경험이 부족해서일까?
하여, 본 글은 나의 생각을 남기기보다는 내가 참고한 여러 글을 간단히 요약하기 위한 공간으로 사용하고자 한다.


1. 좋은 개발자란 무엇일까? by 유리

1) 컴퓨터 활용 능력
2) 프로그래밍 언어 활용 능력
3) 개발자 자신에게 주어진 비즈니스 및 그 상황에 대한 이해도와 유연성
4) 개발자로서의 방향성, 목표를 갖고 있는지의 여부


2. "내가 생각하는 좋은 개발자란?" by TADA 리드 엔지니어 MK

- "같이 일하고 싶다는 생각이 드는 사람"
- 개발 실력은 기본. 커뮤니케이션 능력과 책임감 있는 태도를 갖는 것이 중요.
- 커뮤니케이션 능력이 좋은 사람?
  - 자신의 의견만을 주장하지 않고 남의 의견도 경청할 줄 아는 사람
  - 어떤 문제가 생겼을 때 즉각적이고 투명하게 현재 상황을 알리고 같이 해결책을 찾으려는 태도를 가진 사람


3. 좋은 개발자란 무엇일까? by Evan Moon

- 기술뿐만 아니라 비즈니스나 유저에 대한 생각도 많이 하는 개발자
- 같이 일하고 싶은 사람(=좋은 개발자를 넘어 좋은 동료가 될 수 있는 사람)
  - 나와 다른 의견이든, 나보다 경력이 낮든 상관없이 상대방의 의견을 존중해 주는 태도를 가진 사람
  - 다른 사람이 감정적으로 힘들 때 프로답지 못하다고 비난하기 보다, 그 고민을 들어주고 얼른 제자리로 돌아올 수 있게 돕는 사람
  - 상대방의 감정이 이해는 안 되더라도 그 사람이 그런 감정을 느꼈다는 것을 최소한 인지할 수 있는 사람


4. Good Developer 1 | 좋은 개발자의 5가지 기준 by Code States

1) 코드의 reading과 writing
  - reading: 자신의 업무 파악 및 타인과의 커뮤니케이션에 중요
  - writing: Naming을 잘하고 이해하기 쉽게 코드를 작성하는 것
2) 빠른 생산성: 같은 시간 동안 더 많은 코드를 짜는 것
3) 원활한 커뮤니케이션:
  - "단지 사람이 좋고 나쁨을 떠나서, 대화를 하는데 숨이 턱 막히는 사람이 있고 대화를 하면 할수록 막혔던 부분이 풀리거나 새로운 아이디어를 떠오르게 하는 사람이 있다."
4) 업무 관리, 사람 관리 능력
  - 개발을 한다는 것 = task를 나눠 할당하고 기간에 맞춰 완성시키는 일
  - 업무 관리 = 자신에게 주어진 task를 스스로 관리하는 능력
  - 한국에서 개발자의 종착지는 관리자 -> 사람 관리 능력이 중요
5) 지속적인 학습


5. Good Developer 2 | 커뮤니케이션 잘하는 개발자가 되는 방법 by Code States

- 프로그래머와 개발자는 다르다.
  - 프로그래머: 컴퓨터를 이용해서 프로그램을 제작 또는 수정하는 사람(ex. 외주 프로젝트 프리랜서, 학교 과제 수행하는 컴공 학생)
  - 개발자: 회사나 조직에 소속되어 다른 사람들과 함께 일하며 개발하는 사람
- 좋은 개발자가 되기 위한 첫 번째 방법, '소통'
  - 건설적인 대화 하기
    - 문제점 (1) 대화가 끝났어도 명확한 합의점이나 결과, action item, 해결책이 나오지 않았다.
      - 해결책 (1) 대화의 목적과 목표를 분명히 하기
      - 해결책 (2) 대화가 끝난 후에는 반드시 대화에서 얻어낸 결과물들을 태스크로 전환하고 각자에게 배분하기
    - 문제점 (2) 논쟁을 하다 삼천포로 빠지고, 논쟁이 논쟁을 위한 논쟁으로 변질된다.
      - 해결책 (1) 논쟁의 지점을 분명히 하기
      - 해결책 (2) 용어를 분명히 하기(용어 통일)
  - 커뮤니케이션의 핵심은 '나 자신'
    - 커뮤니케이션을 잘 하기 위한 조건 3가지
      - 조건 (1) 자신과 상대방의 커뮤니케이션 스타일 파악하기
      - 조건 (2) 상대방이 당신에게 망설임 없이 커뮤니케이션할 수 있게 하
        - 주변에 커뮤니케이션하기 망설여지는 상대를 찾아보기 -> 이후 나 자신을 되돌아보기
        - 다른 사람에게 솔직하게 물어보기
      - 조건 (3) 동료와 친밀한 관계를 형성하고 공감하기
- 대화뿐만 아니라 협업 툴 등을 사용하여 커뮤니케이션하기
  - 자신이 하고 있는 일을 공유 & 상대방의 업무 파악하기
  - 도구를 잘 쓰는 것도 커뮤니케이션 능력 향상의 일환


6. 개발자의 생명은 커뮤니케이션 능력 by 임백준

- 프로그래머와 개발자의 차이
  - 프로그래머: 강호를 혼자 떠돌며 칼을 쓰는 무사 -> 칼솜씨가 중요
  - 개발자: 거대한 군사 조직에 속한 정규군 -> 규칙과 규율이 중요(칼솜씨도 중요)
  - 결국 개발자는 커뮤니케이션 능력이 중요
- 개발자의 커뮤니케이션 능력이란?
  - 아닌 것
    - 다른 사람들 앞에서 준비한 슬라이드를 이용해서 발표하는 능력
    - 논쟁이 벌어졌을 때 자기주장을 관철시키는 능력
    - 고객을 설득해서 특정한 제품이나 서비스를 판매하는 능력
    - 말을 아나운서처럼 또박또박 발음하는 능력
  - 맞는 것
    - 명확하지 많은 이야기 속에서 지엽적인 것을 걸러내고 본질을 파악하는 능력
    - 복잡한 논리나 추상적인 개념을 상대방이 이해할 수 있게 설명하는 능력
    - 타인의 감정을 이해하는 공감능력
- 커뮤니케이션 능력을 키울 수 있는 방법
  - 독서: 컴퓨터를 끄고, 전화를 내려놓고, 호흡이 긴 독서하기
  - 좋은 사람 만나기:
    - 만나서 감정 소모되거나 자기를 자기답게 만들어주지 않는 사람은 만날 필요가 없다.
    - 인맥관리나 사회생활 핑계대지 말기


7. 좋은 개발자가 되고 싶다면 다음 5가지 소양을 갖추세요. by F-Lab

1) 항상 의문을 제기하기
2) 긍정적으로 생각하기
3) 의사소통은 말로 하기
4) 중요한 것은 아이디어
5) 항상 겸손하기


8. 채용 전쟁에서 '슈퍼루키' 개발자를 찾는 기준 by claudia(채널톡)

- 좋은 개발자란, 빠르게 배우고 깊게 고민한 사람
  - 좋은 제품을 만들기 위해서는 변화에 빠르게 적응해야 함
- 빠르게 배우는 개발자의 특징: 몰입(Deep dive)의 경험
  - 몰입: 자신이 좋아하는 분야의 본질을 이해하기 위해 시간을 쏟고 실제로 구현한 사람
  - 좋은 개발자는 무엇이 됐든 본질적인 프로토콜을 한번 깊게 파보고 구현한 사람
    - 이런 사람은 큰 문제를 맞닥뜨렸을 때 구조적으로 핵심을 파악해서 문제를 해결함
- 좋은 개발자의 회사 선택 기준
  - 좋은 개발자 동료가 있는 곳
  - 제품 개발이 회사 성장에 핵심 영향력을 주는 곳


8. 10배 이상 뛰어난 개발자가 되는 법(요즘IT 번역글) by Michael Lin

- 초급 개발자가 저지르는 3가지 실수
  1) 사용하는 도구에 대한 연구가 없음
    - 초급 개발자가 저지르는 흔한 실수: 무작정 코딩부터 시작함
    - 자신이 알고 있는 도구만 고집하고, 이를 모든 곳에 적용하려고 함
    - 다른 대안을 찾는 데 시간을 투자하지 않음
  2) 도움을 요청하지 않음
    - 초급 개발자는 스스로 상황을 판단하고 정보를 해석할 능력이 부족함 -> 자기 혼자 고민에 빠짐
  3) 비즈니스 가치를 제공하지 않음
    - 코드: 비즈니스 목표를 달성하기 위한 수단
    - 초급 개발자들이 비즈니스 목표를 간과하는 경우
      - 신기술 적용 -> 제품 전략과 일치하지 않을 수 있음
      - 코드 리팩토링 -> 기회비용. 수익 창출을 위한 다른 기능 개발에 시간을 보낼 수 있음
      - 새 플랫폼으로 마이그레이션 -> 확실히 좋아지는 것이 있나?


각각의 글을 간단하게 요약해보았는데, 전체적으로 봤을 때 좋은 개발자를 구성하는 요소로 3가지를 들 수 있어 보인다.

1. 기술 사용 능력(코드 작성 능력, 자료구조/알고리즘 및 하드웨어에 대한 이해 등 포함)
2. 커뮤니케이션 능력
3. 비즈니스에 대한 이해

1번은 개발자로서의 기본기라고 할 수 있겠고, 어찌 보면 위 3가지 중 가장 쉽게 접근할 수 있겠다.
(난이도가 쉽다기보다는 이를 구성하는 요소들이 명확하게 드러나있음과 동시에 수준 파악이 비교적 용이하다는 생각)

3번의 비즈니스에 대한 이해는 어찌 보면 자신이 몸 담고 있는 분야에 대한 지식과 시장 상황 등을 알면 될 것처럼 보인다.
그러나 해당 분야에 대해서 어디까지 알아야 하는가(어느 정도 이해하는 수준? or 완전 전문가 수준까지?)에 대해서는 끝이 없어 보인다.
그리고 단순히 지식을 앎에 그치지 않고, 개발자로서 비즈니스 가치를 확보할 수 있는 결과물을 만들어내는 능력은 별개일 것이다.

2번의 커뮤니케이션 능력은, 당연한 말이지만, 개발자에게만 국한된 것은 아니다.
세상의 어떤 일을 하든 이 커뮤니케이션은 중요하다(심지어 혼자 일을 하더라도 스스로와의 커뮤니케이션이 필요하지 않겠는가?).
이러한 맥락에서, 나에게 있어 '커뮤니케이션 능력'에 대한 고민은 마치 "어떻게 하면 더 좋은 사람이 될 수 있을까"에 대한 길을 찾아가는 것과 같다.

아직 내 스스로 정의내린 "좋은 개발자"가 무엇인지 모르겠지만, 다른 분들의 글을 통해 얻어낸 기준으로 봤을 때 나는 과연 좋은 개발자인가 하는 의문이 든다.
- 나의 기술력은 충분히 뛰어난가?
- 나는 나의 분야에 대하여 충분히 알고, 이해하고, 이를 토대로 개발로서 가치를 전달하고 있는가?
- 나는 다른 사람들과 좋은 커뮤니케이션을 하고 있는가?
위 질문들에 대한 나의 대답은 "모르겠다"이다.
선뜻 "예"라고 하기는 좀 그렇고, 그렇다고 "아니요"라고 할 정도는 아닌 것 같고, 그 사이 어느 지점에 있는 "모르겠다"이다.
아마도, 적어도 몇 년간은 계속 "모르겠다"이지 않을까 싶다.
(그전에 나 스스로 "좋은 개발자"가 무엇인지 정의하는 게 우선이겠지만)


비록 이 글이 다른 훌륭한 개발자분들의 생각을 모아 조잡하게 요약한 글이긴 하나,
그럼에도 나와 같은 화두("좋은 개발자란?")를 가진 다른 분들이 각자의 생각을 펼침에 조금이나마 도움이 되길 빈다.


<참고 자료>
- 좋은 개발자란 무엇일까? by 유리
- "내가 생각하는 좋은 개발자란?" by TADA 리드 엔지니어 MK
- 좋은 개발자란 무엇일까? by Evan Moon
- Good Developer 1 | 좋은 개발자의 5가지 기준 by Code States
- Good Developer 2 | 커뮤니케이션 잘하는 개발자가 되는 방법 by Code States
- 개발자의 생명은 커뮤니케이션 능력 by 임백준
- 좋은 개발자가 되고 싶다면 다음 5가지 소양을 갖추세요. by F-Lab
- 채용 전쟁에서 '슈퍼루키' 개발자를 찾는 기준 by claudia(채널톡)
- 10배 이상 뛰어난 개발자가 되는 법(요즘IT 번역글) by Michael Lin

합성곱 신경망(CNN; Convolutional Neural Network)

합성곱 신경망이란?

합성곱 신경망(Convolutional neural network, CNN)은 시각적 영상을 분석하는 데 사용되는 다층의 피드-포워드적인 인공신경망의 한 종류이다. 딥 러닝에서 심층 신경망으로 분류되며, 시각적 영상 분석에 주로 적용된다. 또한 공유 가중치 구조변환 불변성 특성에 기초하여 변이 불변 또는 공간 불변 인공 신경망 (SIANN)으로도 알려져 있다. 영상 및 동영상 인식, 추천 시스템, 영상 분류, 의료 영상 분석 및 자연어 처리 등에 응용된다.

- 위키백과 (합성곱 신경망)

합성곱 신경망은 주로 영상 분석에서 많이 사용되는 신경망 구조이다.
(여기서 영상은 picture, image만을 의미한다. video는 동영상이라고 해야 한다.)

합성곱 신경망이니 합성곱이라는 것의 원리를 사용할텐데, 이게 뭘까?
합성곱을 검색해보면 두 함수가 있고, 둘 중 하나를 뒤집은 후에 곱한 결과를 적분한다고는 하는데...

$$(f*g)(t) = \int_{-\infty}^{\infty} {f(\tau)g(t-\tau)d\tau} \\무슨\ 말인고?$$

그러나 이는 함수에 들어가는 값들이 연속적인 경우이고, 합성곱 신경망에서의 합성곱은 각각의 값이 따로 따로, 즉 이산적이다.
따라서 위 식은 아래와 같이 표현할 수 있을 것이다.

$$(f*g)(t) = \sum_{\tau} {f(\tau)g(t-\tau)}$$

결론적으로 간단히 말하면 짝이 맞는 숫자 둘($f(\tau)$와 $g(t-\tau)$)이 만나 곱해진 값들을 한 곳에 모아 합을 구해준다고 생각하면 된다.

아래 합성곱 신경망의 구조 및 작동 방식을 통해서 이게 구체적으로 어떻게 돌아가는 시츄에이션인지 알아보자.

합성곱 신경망의 구조 및 작동 방식

합성곱 신경망 구조

전체적인 합성곱 신경망의 구조는 위와 같다.

입력 데이터(이미지)가 들어오면 특징 추출 부분에서 합성곱 연산 및 풀링 등의 과정을 거쳐 이미지의 특징을 잡아낸다.
신경망의 초기에는 저수준, 즉 이미지의 아주 작고 세부적인 특징부터 찾는다. 그리고 층이 깊어질수록 고수준, 즉 이미지의 전체적인 특징을 찾아낸다.

특징 추출 과정

처음에는 가로, 세로, 대각선 정도의 특징부터 잡기 시작해서 점차 (사람 얼굴인 경우) 눈, 코, 입 등을 구분하고, 마지막에는 전체적인 얼굴 윤곽을 추출하는 것을 볼 수 있다.

합성곱(Convolution)

위에서 합성곱 신경망에서의 합성곱은 결국 눈이 맞아 서로 곱해진 두 숫자의 커플들을 한데 모아 합한 것이라고 하였다. 이 발칙한 상황(?)이 어떤 것인지 눈으로 확인(?)해보자.

인풋&필터

우선 5X5 사이즈의 그레이 스케일(흑백) 이미지가 있다고 해보자. 이 이미지 위를 2X2 사이즈의 필터(Convolution Filter)$^*$$^1$가 왼쪽 위부터 시작해서 몇 칸 단위$^*$$^2$로 차례차례 돌아다닌다. 한 칸씩 움직인다고 하면 가로로 네 번, 세로로 네 번 해서 총 16번 훑을 것이다.

이때 매번 움직일 때마다 필터 위의 숫자와 이들 각각의 위치에 해당하는 이미지 위의 숫자를 곱한 후, 결과를 전부 합한다.
이렇게 해서 각 결과를 계산된 자리대로 배치해서 내놓은 것을 Feature Map이라고 한다.
(이 과정에서 Filter의 가중치가 학습이 된다.)

Feature Map계산 과정

Feature Map에 활성화 함수를 적용한 결과를 Activation Map이라 하고, 여기에 편향(bias)까지 합해준 것이 합성곱 층의 최종 결과물(Output)이다.

*1 필터(Filter)와 커널(Kernel)의 차이

이미지가 그레이 스케일(채널(Channel)이 1개)인 경우 필터(Filter)는 커널(Kernel)과 같다.

1 channel input

이미지가 컬러(RGB -> 채널이 3개)인 경우 하나의 필터 안에 3개의 커널이 있다.
즉, 각 채널마다 1개의 커널이 있고, 필터는 커널의 집합이다.

3 channels input

※ 위 이미지를 보면 들어올 때(input)는 RGB의 3개 채널이지만, 나갈 때(output)는 1개의 채널로 통합된다.
여기서 주의할 것은 각 필터별로 채널이 1개씩 산출된다는 점이다.
즉, 합성곱 층에 지정된 필터가 32개라면 Feature Map의 채널은 32개가 되는 것이다.
이는 그레이 스케일도 동일하다.

*2 스트라이드(Stride)

이 '몇 칸 단위'를 의미하는 말이 스트라이드(Stride) 이다.
이는 영어로 걸음, 보폭이라는 의미를 갖고 있다.
실제 코드 작성 시 이 값을 지정하여 몇 칸 단위로 필터가 돌아다니게 할지 정한다.

패딩(Padding)

패딩

패딩은 이미지의 외곽을 어떤 값으로 둘러싸는 것을 말한다.
사람이 겨울에 패딩 점퍼를 입듯, 이미지도 패딩을 입었다고 생각하면 된다.
이미지를 우리의 몸으로, 패딩은 패딩 점퍼로 비유해보겠다.

패딩은 왜 해줄까?
만약 패딩을 해주지 않고 그대로 합성곱을 진행하면 이미지의 테두리 부분은 안쪽에 비해 연산 과정에 덜 포함된다.
이는 달리 말하면 해당 부분의 정보가 제대로 반영되지 못한다는 의미와도 같다.
겨울에 패딩을 입지 않아 차가워진 우리의 피부를 상상해보자.

여기서 패딩을 통해 바깥을 감싸면 기존에 연산에 덜 포함된 부분이 보다 많이 반영된다. 한 번 되던 것이 두 번 이상 들어오니 이전보다 훨씬 낫다고 볼 수 있다.
패딩 점퍼를 입어서 피부가 따뜻해진 듯하다.

결국 패딩은 전체 이미지의 값을 충분히 활용하기 위해서 사용한다.
이와 더불어 입력 데이터의 크기가 패딩에 의해 변하게 되면서 Feature Map의 크기도 조절 가능하다.

위 움짤을 보자. 만약 5X5 사이즈 이미지에 3X3 필터를 적용하면 3X3 Feature Map이 나올 것이다.
여기서 이미지에 패딩을 적용하여 7X7 사이즈가 되게끔 하였고, 여기에 3X3 필터를 적용하니 5X5 사이즈의 Feature Map이 나왔다.
즉, 원본 이미지의 사이즈 5X5와 동일한 크기의 Feature Map을 출력으로 얻을 수 있다.

패딩의 값으로는 보통 0을 사용하는데, 이를 제로 패딩(Zero-Padding)이라고 한다.
이렇게 이미지를 패딩으로 씌움으로써 인공 신경망이 이미지의 외곽을 인식하게끔 만드는 효과도 있다.

※ 필터 크기(Filter Size), 패딩(Padding), 스트라이드(Stride)와 Feature Map 크기의 관계

$$
N_{\text{out}} = \bigg[\frac{N_{\text{in}} + 2p - k}{s}\bigg] + 1
$$

$N_{\text{in}}$ : 입력되는 이미지의 크기(=특성 수)
$N_{\text{out}}$ : 출력되는 이미지의 크기(=특성 수)
$k$ : 합성곱에 사용되는 필터(=커널)의 크기
$p$ : 합성곱에 적용한 패딩 값
$s$ : 합성곱에 적용한 스트라이드 값

풀링(Pooling)

Pooling

풀링(pooling)을 찾아보면 일단 swimming pool의 pool이 제일 먼저 나온다.
여기서 좀 더 들어가면 웅덩이, 그리고 공동으로 이용하기 위한 자금을 모은다는 의미도 나온다.

그럼 결국 CNN에서의 풀링은 무엇일까?
CNN에서 풀링을 거치면 이미지의 주요한 특징이 갈무리된 결과를 얻을 수 있다.
위 그림에서 보여지듯 일정한 간격으로 영역을 나눈 후, 그 영역의 특징을 가장 잘 설명하는 값을 가져온다.
여기서 이 값으로 영역 내 최댓값을 갖고 올지 평균값을 갖고 올지에 따라 Max Pooling과 Average Pooling으로 구분한다.
(주로 Max Pooling이 사용된다.)

또한 풀링을 통해 결과물, 즉 다음 층으로 향하는 데이터의 입력 크기(input size)가 작아진다. 크기가 작아진 만큼 데이터가 차지하는 메모리 크기도 작아지는 효과가 있다.
동시에 파라미터 수를 줄여주는 효과도 있어 과적합을 방지할 수도 있다(Dropout 같은 느낌).

풀링 층은 따로 학습되는 가중치가 없고, 채널 수도 변하지 않는다.

완전 연결 신경망(Fully Connected Layer)

특징 추출 부분에서 충분히 특징을 추출했다면 이를 토대로 분류를 해야 한다.

분류 문제 해결을 위해서 다층 퍼셉트론 신경망으로 구성된 신경망을 구축하고, 이진 분류인지 다중 분류인지에 따라 마지막 출력층까지 만들어주면 된다.

코드 예시(Tensorflow & Keras)

(Github 통해서 확인하시려면 클릭)

10개의 클래스로 분류되는 이미지 데이터셋인 CIFAR-10을 사용하여 CNN을 어떻게 구현하는지 알아보자.

  1. 패키지 및 라이브러리 불러오기
from tensorflow.keras.datasets import cifar10
from tensorflow.keras import Sequential
from tensorflow.keras.layers import Dense, Conv2D, MaxPooling2D, Flatten
from tensorflow.keras.layers import Dense, Flatten
from tensorflow.keras.models import Sequential
from tensorflow.keras.datasets import cifar10

from sklearn.model_selection import train_test_split

import numpy as np
import tensorflow as tf
  1. 시드(seed) 고정하기
np.random.seed(42)
tf.random.set_seed(42)
  1. 데이터셋 불러오기 & 훈련 / 검증 / 테스트셋으로 나누기 & 이미지 픽셀값 정규화
(X_train, y_train), (X_test, y_test) = cifar10.load_data()
X_train = X_train.astype('float32') / 255.
X_test = X_test.astype('float32') / 255.
X_train, X_val, y_train, y_val = train_test_split(X_train, y_train, test_size=.2)
X_train.shape

(40000, 32, 32, 3)

훈련 데이터셋으로 가로 32, 세로 32 픽셀의 컬러(RGB, 3개 채널) 이미지 40000개가 있다.

  1. CNN 모델 구축
model = Sequential()

# 특징 추출 부분
# 합성곱 층(Conv2D)와 풀링 층(MaxPooling2D)를 번갈아가며 사용
model.add(Conv2D(32, (3,3), padding='same', activation='relu'))
model.add(MaxPooling2D(2,2))
model.add(Conv2D(32, (3,3), padding='same', activation='relu'))
model.add(MaxPooling2D(2,2))
model.add(Conv2D(32, (3,3), padding='same', activation='relu'))
model.add(MaxPooling2D(2,2))

# 분류기 역할의 완전 연결 신경망
# 특징 추출 부분을 거쳐온 데이터를 신경망에 입력할 수 있도록 1차원으로 변환
model.add(Flatten())
model.add(Dense(128, activation='relu'))
# 10개의 클래스 분류이므로 출력층에 10개의 노드를, 활성화 함수로 softmax를 지정
model.add(Dense(10, activation='softmax'))

Conv2D에서 반드시 지정해야 하는 첫 번째 파라미터는 필터의 수(filters), 두 번째는 필터(커널)의 크기(kernel_size)이다.
padding은 'valid' 또는 'same'로 지정 가능하다.
'valid'는 패딩을 적용하지 않아 Conv2D를 지나면 입력된 이미지의 shape이 작아진다.
'same'은 패딩을 적용하여 Conv2D 전후의 이미지 shape이 동일하게 만든다.

MaxPooling2D에서 풀링할 영역의 크기(pool_size)는 (2, 2)가 기본값이다.
strides 파라미터를 지정하여 몇 칸 단위로 움직이며 풀링을 할지 지정할 수 있다. 기본값은 None으로, 이대로 두면 pool_size와 동일하게 설정된다. 즉, 풀링 영역이 겹치지 않게 된다.

※ 한 개 층에 큰 필터 쓰기 vs. 여러 개 층에 작은 필터 쓰기

큰 필터 1개를 쓰기보다는 작은 필터 여러 개를 쓰는 것이 낫다.
학습되어야 할 가중치 파라미터의 수가 적어지고 일반적으로 더 나은 성능을 보이기 때문이다.

예를 들어 5X5와 3X3 크기 필터가 있다고 해보자.
입력 이미지의 크기가 5X5라고 했을 때 5X5 필터는 1개 층, 3X3 필터는 2개 층을 거치면 같은 결과를 얻게 된다.

5X5 vs. 3X3


그런데 5X5 필터는 학습되어야 할 가중치 파라미터의 수가 25개이고, 3X3 필터는 2개 층이므로 3 X 3 X 2 = 18개이다.
필터의 크기를 작게, 그리고 여러 층으로 만든 것이 큰 필터를 사용하는 것보다 적은 비용이 드는 것을 알 수 있다.

예외적으로 첫 번째 합성곱 층에서는 큰 크기의 필터(5X5 이상)과 2 이상의 스트라이드를 사용한다. 왜냐하면 필터 크기가 커져도 입력 이미지의 채널은 컬러인 경우 3개, 흑백인 경우 1개뿐이므로 비용이 크지 않다.
이렇게 하면 너무 많은 정보를 잃지 않고서 이미지의 차원을 줄일 수 있다.

model.summary()

model summary

Output Shape은 (행 수, 가로 픽셀 수, 세로 픽셀 수, 채널 수) 라고 생각하면 쉽다.
여기서 행(row) 수는 None으로 표시되어 있는데, 이는 특정한 숫자로 지정되지 않았음을 의미한다. 배치 사이즈처럼 32, 64 등 다양한 숫자가 올 수도 있기 때문이다.
채널 수는 각 Conv2D에서 지정한 filters의 값에 맞춰 나온 것을 볼 수 있다.

MaxPooling2D는 입력으로 들어온 이전의 Conv2D의 shape을 줄였다.
채널의 수는 입력 데이터와 동일하며, 학습되는 가중치가 없기 때문에 Param #도 0으로 표기되었다.

Flatten에서는 (4, 4, 32)의 데이터가 1차원으로 변환되었기 때문에 4 * 4 * 32=512의 shape을 갖게 되었다.

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

10개 클래스의 다중 분류 문제이므로 'loss'를 'sparse_categorical_crossentropy'로 지정했다.

model.fit(X_train, y_train,
          batch_size=128,
          validation_data=(X_val, y_val),
          epochs=10)
  1. 모델 평가
model.evaluate(X_test, y_test, verbose=2)

313/313 - 4s - loss: 0.9526 - accuracy: 0.6713 - 4s/epoch - 13ms/step
[0.9525882601737976, 0.6712999939918518]


전이 학습(Transfer Learning)이란?

MMORPG 게임을 해본 사람이라면 알겠지만, 한 계정 내에 있는 캐릭터들 간에 아이템을 옮길 수 있는 기능이 있다(없는 게임도 있다).
이를 통해 무엇을 할 수 있는가? 일단 주 캐릭터를 초집중하여 강력하게 성장시킨다. 그 과정에서 다른 클래스의 장비나 잡화소모품 등을 상당수 얻게 된다.
이렇게 주 캐릭터를 충분히 성장시킨 후, 새로운 캐릭터를 시작한다고 해보자. 여기서 새로운 캐릭터는 제로(0)부터 시작할 필요가 없다. 왜냐하면 주 캐릭터를 키우면서 쌓아 놓은 수많은 물품들이 있기 때문이다.

전이 학습도 이와 같다.
기존에 훌륭하신 교수님들이나 연구원분들께서 연구 개발하여 발표하신 모델이 있으면(주 캐릭터), 우리는 이를 그대로 가져온 후에 우리에게 필요한 부분만 붙여서 쓰면 된다(부 캐릭터).

작동 방식

일반적으로 전이 학습은 대량의 데이터를 학습해놓은 사전 학습 모델(Pre-trained Model)의 가중치를 그대로 가져온 후, 분류기(완전 연결 신경망)만 필요에 따라 추가로 설계하여 붙이는 식으로 한다.

아래는 전이 학습을 나타낸 이미지이다.

전이 학습


위쪽이 사전 학습 모델이고 아래가 새롭게 구축한 모델이다.
새로운 모델을 보면 사전 학습 모델의 'Common inner layers'는 그대로 사용하되, 기존의 분류기 부분은 떼어낸 후 용도에 맞게 새로운 분류기를 붙여주었다.

특징

1) 어떠한 데이터에도 준수한 성능
사전 학습 모델의 가중치는 대량의 데이터를 학습하여 얻어진다.
즉, 여러 데이터의 일반적인 특징을 많이 학습하였으므로 아무 데이터나 넣어도 쓸만한 성능을 보인다.

2) 좋은 결과를 신속하게 도출
일반적으로 사전 학습 가중치는 학습되지 않고 고정(freeze)한 채로 진행되기 때문에 빠르게 좋은 결과를 얻을 수 있다.

이외에도 학습 데이터의 수가 적을 때도 효과적이며, 전이 학습 없이 학습하는 것보다 훨씬 높은 정확도를 제공한다는 장점도 있다.

이미지 분류를 위한 주요 사전 학습 모델

다음은 이미지 분류를 위해 사용할 수 있는 대표적인 사전 학습 모델들이다.

1. VGG

VGG는 2014년 ILSVRC 대회에서 2등을 한 모델이다.
VGG의 구조는 2개 또는 3개의 합성곱 층 뒤에 풀링 층이 나오고 다시 2개 또는 3개의 합성곱 층과 풀링 층이 등장하는 식이다.
VGG의 종류에 따라 총 16개 또는 19개의 합성곱 층이 있고, 이 갯수에 따라 VGG-16 또는 VGG-19라고 부른다.
마지막 분류기(완전 연결 신경망) 부분은 2개의 은닉층과 출력층으로 이루어진다.

VGG

VGG의 특징은 아래와 같다.

  • 모든 합성곱 층에서 3X3 크기 필터 사용
  • 활성화 함수로 ReLU 사용하고, 가중치 초기화는 He 초기화를 사용
  • 완전 연결 신경망에서 드롭아웃(Dropout)을 사용하여 과적합 방지 & 옵티마이저로 Adam 사용

2. ResNet

ResNet은 2015년 ILSVRC 대회에서 우승한 모델이다.
우승한 모델의 신경망 층 수는 152개였고, 이외에 34개, 50개, 101개 층 등의 변종도 있다.

ResNet

ResNet의 특징은 잔차 연결(Residual Connection; Skip Connection)이다. 이는 어떤 층을 거친 출력값에 그 층에 들어왔던 입력값을 그대로 더해주는 것을 말한다.
이를 통해 깊은 층의 신경망을 훈련시킬 수 있었다.

Residual Connection

3. Inception

Inception은 2014년 ILSVRC 대회에서 우승한 모델이다.
Inception 모델의 구조에서 주목할 부분은 Inception Module인데, 이는 가로 방향으로 신경망의 층을 넓게 구성한 구조를 말한다.
이를 활용하여 크기가 다른 필터와 풀링을 병렬적으로 적용한 뒤 결과를 조합한다.

Inception

이후 Inception-v3, Inception-v4 등 여러 변종이 나왔다.

4. EfficientNet

2019년에 발표된 모델로, Compound Scaling이란 방식을 통해서 기존의 모델보다 뛰어난 성능을 끌어냈다.

먼저 Scaling이란 합성곱 신경망 모델의 깊이나 너비, 또는 입력 이미지의 크기를 조절하는 것을 뜻한다.
이들 간의 균형을 맞추는 것이 모델 성능 향상에 중요하다는 생각을 바탕으로 이들 간의 균형을 나타내보니 간단한 상수비로 구할 수 있었다고 한다. 이를 토대로 나온 것이 Compound Scaling이다.

EfficientNet

코드 예시(Tensorflow & Keras)

위의 CNN 코드 예시에서 사용된 CIFAR-10 데이터셋을 그대로 사용하되, 모델은 사전 학습 모델(VGG16)을 이용한 전이 학습 모델로 구축하는 코드이다.

  1. 패키지 및 라이브러리 불러오기
from tensorflow.keras.applications.vgg16 import VGG16
from tensorflow.keras.layers import GlobalAveragePooling2D
  1. 사전 학습 모델 불러오기
pretrained_model = VGG16(weights='imagenet', include_top=False)
  1. 사전 학습 모델 위에 분류기 추가하기

아래에 추가된 GlobalAveragePooling2d() 층은 데이터 Shape을 (None, None, None, 512) 에서 (None, 512)로 변환하는 역할을 한다.

model = Sequential()
model.add(pretrained_model)
model.add(GlobalAveragePooling2D())
model.add(Dense(128,activation='relu'))
model.add(Dense(10,activation='softmax'))
model.summary()

transfer model summary

model.compile(optimizer='adam',
              loss='sparse_categorical_crossentropy',
              metrics=['accuracy'])
model.fit(X_train, y_train,
          batch_size=128,
          validation_data=(X_val, y_val),
          epochs=10)
model.evaluate(X_test, y_test, verbose=2)

313/313 - 2s - loss: 0.7755 - accuracy: 0.7828 - 2s/epoch - 7ms/step
[0.7754948139190674, 0.782800018787384]


<참고 자료>

자연어 처리 기본 지식 및 텍스트 전처리(NLP Basic Knowledges & Text Preprocessing)

자연어 처리란?

자연어 & 자연어 처리(NLP; Natural Language Processing)

자연어(自然語, 영어: natural language 또는 ordinary language) 혹은 자연 언어는 사람들이 일상적으로 쓰는 언어를 인공적으로 만들어진 언어인 인공어와 구분하여 부르는 개념이다.

- 위키백과 (자연어)

자연어 처리(自然語處理) 또는 자연 언어 처리(自然言語處理)는 인간의 언어 현상을 컴퓨터와 같은 기계를 이용해서 묘사할 수 있도록 연구하고 이를 구현하는 인공지능의 주요 분야 중 하나다.

- 위키백과 (자연어 처리)

간단히 말하면 먼 옛날부터든 언제부터든 사람들의 의사소통을 위해 자연스럽게 형성된 언어이다. 영어, 한국어 등을 예로 들 수 있다.
반대로 인공어는 특정한 누군가가 어떤 목적을 갖고 인공적으로 만든 것이라고 볼 수 있다. 여기에는 에스페란토어, 프로그래밍 언어 등이 포함된다.

이러한 자연어를 컴퓨터로 처리하는 기술을 자연어 처리(NLP; Natural Language Processing) 라고 한다.

자연어 처리 용어

  • 말뭉치(Corpus; 코퍼스) : 자연어 연구를 위해 특정한 목적을 갖고 언어의 표본을 추출한 집합(텍스트 데이터)
  • 문장(Sentence) : 여러 개의 토큰(단어, 형태소 등)으로 구성된 문자열. 마침표, 느낌표 등의 기호로 구분
  • 문서(Document) : 문장들의 집합
  • 어휘집합(Vocabulary) : 말뭉치에 있는 모든 문장 및 문서를 토큰화한 후 중복을 제거한 토큰의 집합

토큰(token) 및 토큰화(tokenization)가 구체적으로 무엇인지는 아래 텍스트 전처리 부분에서 다루겠다.

자연어 처리로 할 수 있는 것

  1. 자연어 이해(NLU; Natural Language Understanding)
    • 분류(Classification) : 뉴스 기사 분류, 감성 분석(Positive/Negative)
    • 자연어 추론(NLI; Natural Language Inference)
    • 기계 독해(MRC; Machine Reading Comprehension), 질의 응답(QA; Question&Answering)
    • 품사 태깅(POS(Part of Speech) tagging), 개체명 인식(Named Entity Recognition) 등
  2. 자연어 생성(NLG; Natural Language Generation)
    • (특정 도메인의) 텍스트 생성
  3. NLU & NLG
    • 기계 번역(Machine Translation)
    • 요약(Summerization)
      • 추출 요약(Extractive summerization) : 문서 내에서 해당 문서를 가장 잘 요약하는 부분을 찾아내는 것 (NLU에 가까움)
      • 생성 요약(Absractive summerization) : 해당 문서를 요약하는 요약문을 생성 (NLG에 가까움)
    • 챗봇(Chatbot)
      • 특정 업무를 처리하기 위한 챗봇(TOD; Task Oriented Dialog)
      • 정해지지 않은 주제를 다루는 일반 대화 챗봇(ODD; Open Domain Dialog)
  4. 기타
    • TTS(Text to Speech) : 텍스트를 음성으로 읽기
    • STT(Speech to Text) : 음성을 텍스트로 쓰기
    • Image Captioning : 이미지를 설명하는 문장 생성

벡터화(Vectorization)

자연어와 자연어 처리가 무엇인지 알았고 무슨 일을 할 수 있는지도 알았다. 그럼 어떻게 하는 것일까?

우선 뭘 하려고 하기 전에 컴퓨터가 자연어를 이해할 수 있도록 우리 인간(human)이 친절하게 바꿔주어야 하는데, 자연어는 벡터로 만들어준다. 이를 벡터화(Vectorization) 라고 한다.

자연어를 어떤 방식으로 벡터화할지는 자연어 처리 모델 성능에 큰 영향을 미친다.
자연어를 벡터화하는 방법은 다음과 같은 것들이 있다. (자세한 내용은 각각 별도의 글에서 다룰 예정)

  • 등장 횟수 기반 단어 표현(Count-based Representation)
    • Bag of Words
    • TF-IDF
  • 분포 기반 단어 표현(Distributed Representation)
    • Word2Vec
    • fastText
    • GloVe

자, 이제 벡터화가 뭔지도 알았으니 어떻게 하는지만 알면 바로 자연어 처리를 진행할 수 있을 것만 같다!

... 그럴 것 같지만 그렇지 않다.
데이터 분석을 하고, 머신 러닝 모델을 만들고 그러기 전에 무엇을 해야 했는가? 그렇다. 데이터 전처리를 '반드시' 해야 했다.
텍스트 데이터도 그렇다.


텍스트 전처리

데이터 전처리의 중요성은 아무리 강조해도 지나치지 않을 것이다. 그런 만큼 다양한 이유가 있을 것인데, 그 중에서도 텍스트 데이터의 전처리가 필요한 이유는 무엇일까?

차원의 저주(Curse of Dimensionality)

차원의 저주란 데이터셋의 차원이 커질수록 기존의 데이터가 갖고 있는 설명력이 줄어드는 문제를 말한다.
간단하게 말하면, 데이터 개수는 그대로이고 데이터셋의 차원만 늘어나면 데이터의 밀도가 떨어져서 의미 도출이 어려워질 수도 있다.
아래 그림들을 보자.

1차원(직선) 위에 4개의 점(데이터)가 있다고 해보자.

이 상태에서 차원을 하나 올려 2차원(평면)이 되면 점 사이의 거리가 멀어진다.
(물론 데이터에 따라 차원이 올라가도 거리가 그대로일 수도 있음)

3차원이 되면 거리는 더더욱 멀어지게 된다.

물론 데이터셋의 차원이 올라간다고 해서 무조건 데이터의 의미가 줄어드는 것은 아니다. 데이터셋에 따라서 차원을 올리면 오히려 폭넓은 설명이 가능한 경우도 있다.
그러나 이 차원이 과하게 크면? 그러면 위 그림을 통해서 설명한 것처럼 데이터셋의 설명력이 떨어질 것이다.

자연어 처리에서는 전체 말뭉치에 존재하는 단어의 종류가 데이터셋의 특성, 즉 차원이 된다. 그러므로 단어의 종류를 줄여야 차원의 저주 문제를 어느 정도 해결할 수가 있다.

아래의 다양한 텍스트 전처리 방법들을 통해서 불필요하거나 중복되는 단어 제거를 통해 차원을 줄이거나, 모델의 효율적인 연산을 위해 데이터를 가공할 수 있다.

그럼 이제 텍스트 전처리 방법들에 대해서 살펴보자.

1) 토큰화(Tokenization)

토큰(token), 그리고 토큰화(Tokenization)란?

(이런게 토큰...?)

자연어 처리에서 토큰이란 주어진 말뭉치를 특정한 단위(보통 단어)로 조각조각 나눈 것을 말한다. 쉽게 말하면 말뭉치를 부숴서 얻은 조각들이다. 부수는 방식은 대충 뭉텅뭉텅 부술 수도(문장 이상의 단위), 아니면 아주 가루를 내버릴 수도 있다(철자 단위).
여기서 단어를 기준으로 말뭉치를 나누면 이를 단어 토큰화라 하고, 문장 단위면 문장 토큰화라고 한다.

전통적인 자연어 처리 방식인 횟수 기반 단어 표현(Count-based Word Representation)부터 RNN, LSTM, Transformer와 같은 진보된 신경망 기반 방식 모두 이 토큰을 이용하여 모델 학습이 이루어진다.
따라서 토큰화는 자연어 처리에서 필수적이라고 할 수 있다.

토큰화 방법

단어 토큰화라면 띄어쓰기를 기준으로 단어를 구분할 수 있을 것이고,
문장 토큰화라면 구두점이나 물음표, 느낌표 등으로 구분할 수 있을 것이다.
그러나 이런 경우는 아주 단순한 경우이고, 실제는 그리 간단하지 않다.

주의사항

  • 토큰화 기준

단어 토큰화를 한다고 했을 때, 어떤 단어 사이에 특수문자(아포스트로피('), 대시(-) 등)가 포함된 경우는 어떻게 토큰화를 해야 할까?

import tensorflow as tf
from tensorflow import keras
from tensorflow.keras.preprocessing.text import Tokenizer

sentences = [
  'I love you',
  'I love myself'
]

tokenizer = Tokenizer(num_words = 100)
tokenizer.fit_on_texts(sentences)
word_index = tokenizer.word_index
print(word_index)

{'i': 1, 'love': 2, 'you': 3, 'myself': 4}
이렇게 별다른 특수문자가 없으면 띄어쓰기만 갖고서 잘 구분이 되지만,

sentences = [
  "I'm a student",
  'Fu-sion!',
  "Don't panic!"
]

tokenizer = Tokenizer(num_words = 100)
tokenizer.fit_on_texts(sentences)
word_index = tokenizer.word_index
print(word_index)

{"i'm": 1, 'a': 2, 'student': 3, 'fu': 4, 'sion': 5, "don't": 6, 'panic': 7}
이렇게 아포스트로피나 대시가 있으면 결과가 의도와 다르게 나올 수도 있다.

따라서 이런 경우에는 어떤 기준으로 토큰화를 할지 선택해야 한다.
(Keras Tokenizer의 경우 filters 파라미터를 통해서 어떤 특수문자를 제거할지 안 할지 직접 지정할 수 있음)

  • 구두점, 특수 문자의 단순 제외

구두점이나 특수 문자를 단순히 제거해버리면 무의미한 토큰이 만들어질 수도 있다.
M.Sc(Master of Science) 또는 Ratchet&Clank(비디오 게임 제목) 같이 하나의 토큰으로 분류해야 하는 경우가 있기 때문이다.

2) 정제(Cleaning) 및 정규화(Normalization) by 내장 메소드

정제 및 정규화란?

정제는 주어진 말뭉치에서 지저분한(노이즈) 데이터를 제거하는 것이다.
정규화는 같은 의미임에도 모양이 다른 단어들을 하나의 형태로 통일시켜주는 작업이다.
쉽게 말해 불필요한 군더더기를 제거하여 데이터의 살을 빼는 작업이다.

같은 의미지만 다른 형태인 단어 통일시키기

우리나라를 영어로 표기하면 다양한 방식이 나올 수 있다. Korea, KOR, ROK 등등. 그러나 결국 이들이 의미하는 것은 대한민국이다.
이런 경우 한 가지를 딱 정해서 통일을 시켜준다.

대소문자 통합

위에서 우리나라를 표현하는 말 중 KOR이 있었다. 그런데 여기서는 KOR이라 하고, 저기서는 kor이라고 할 수도 있다.
이런 경우도 대소문자 둘 중 하나로 딱 정해서 통합시킨다.

불필요한 단어 제거(통계적 트리밍(Trimming))

머신 러닝 모델을 만들기 전에 보통 데이터 전처리를 한다.
이때 평균에 비해 과도하게 높거나 낮은 수치들을 이상치로 간주하여 제거할 때가 있다.

이와 비슷하게 텍스트 전처리에서는 말뭉치 내에서 너무 많거나 적게 등장하는 단어들은 별 의미가 없는 것으로 간주하여 제거한다.
등장 횟수가 너무 많으면 여러 문장(또는 문서)에 걸쳐서 나오는 단어이므로 문장 분류 등에 별다른 도움이 되지 않을 것이고, 너무 적으면 적은 대로 영향력이 없기 때문이다.

3) 어간 추출(Stemming) 혹은 표제어 추출(Lemmatization)

어간과 표제어란?

  • 어간(stem) : 단어의 의미가 포함된 부분으로 접사(affix) 등이 제거된 형태(어근 또는 단어 원형과 다를 수 있음)
    • 접사(affix) : 단어에 붙어 추가적인 의미를 더하는 부분
  • 표제어(Lemma) : 단어의 기본 사전형 형태

간단하게 예를 들면 wolves의 어간은 wolv이고 표제어는 wolf이다.
또 다른 예로 leaves의 어간은 leav, 표제어는 leaf이다.

즉, 어간은 단어에서 접사같은 부수적인 부분만 딱 떼어낸 것이고,
표제어는 그 단어의 근본 형태(또는 사전에서 찾을 수 있는 형태)라고 할 수 있다.

어간 추출

# NLTK 라이브러리 데이터를 다운로드받아야 아래 코드들이 실행 가능
# 이미 있는 경우는 생략해도 됩니다.
import nltk
nltk.download()
from nltk.stem import PorterStemmer

ps = PorterStemmer()
words = ["wolf", "wolves", "leaf", "leaves"]

print([ps.stem(word) for  word  in  words])

['wolf', 'wolv', 'leaf', 'leav']
보이는 것처럼 군더더기 부분만 딱 자르고 남은 부분 그대로 내보낸다.

표제어 추출

from nltk.stem import WordNetLemmatizer

lt= WordNetLemmatizer()
words = ["wolf", "wolves", "leaf", "leaves"]

print([lt.lemmatize(word) for word in words])

['wolf', 'wolf', 'leaf', 'leaf']
보이는 것처럼 단어의 사전형 형태를 찾아서 내보낸다.

주의사항

  • 다양한 라이브러리, 다양한 알고리즘

자연어 처리에 쓰이는 다양한 라이브러리가 있고, 각각의 내부에는 다양한 어간 추출 및 표제어 추출 알고리즘이 있다.
따라서 사용 전에 작동 방식을 이해하고 사용해야 할 것이다.

  • 연산 속도 : 어간 추출 > 표제어 추출

어간 추출은 단순한 꼬리 자르기이고, 표제어 추출은 근본을 찾아오는 작업이므로 일반적으로 어간 추출이 더 빠르다.
그러나 어간 추출의 결과는 실제로 존재하지 않는 단어일 수도 있으므로 상황에 맞게 어간 추출 또는 표제어 추출을 선택해야 한다.

4) 불용어(Stopword) 처리

불용어란?

불용-어 不用語

인터넷 검색 시 검색 용어로 사용하지 않는 단어. 관사, 전치사, 조사, 접속사 등은 검색 색인 단어로 의미가 없는 단어이다. 그러나, 각 검색 엔진마다 그 내용은 다를 수도 있다.

- 네이버 국어사전

위에서 불필요한 단어 중 말뭉치에서 너무 많이 등장하는 단어들도 제거 대상이라고 하였다. 여기에 대부분 포함되는 것이 바로 불용어이다.

영어에서는 a, the 및 in, on, at 등의 전치사 등등이 해당된다.
아래 링크를 통해서 각 언어별 불용어 목록을 확인할 수 있다.
언어별 불용어 목록

불용어 확인

자연어 처리 라이브러리를 통해서 불용어를 확인 및 처리할 수 있다.
여기서는 spaCy 라이브러리를 사용해보겠다.

import spacy
from spacy.tokenizer import Tokenizer

nlp = spacy.load("en_core_web_sm")

# 불용어 10개만 확인
print([stopword  for  stopword  in  nlp.Defaults.stop_words][:10])

['along', 'using', 'hence', 'serious', 'see', 'yours', 'beyond', 'myself', 'is', 'yourselves']

불용어 처리

text = "I'm the best. You're the best. We're the best."

sentence = nlp(text)

token_list = []
for token in sentence:
    # 토큰이 불용어와 구두점이 아니면 저장
    if (token.is_stop == False) & (token.is_punct == False):
        token_list.append(token.text)

token_list

['best', 'best', 'best']

sws  =  nlp.Defaults.stop_words
sw  = ["i", "'m", "the", "you", "'re", "we" ]
is_sw  = [word  in  sws  for  word  in  sw]

is_sw

[True, True, True, True, True, True]

불용어를 제외하고 남은 토큰('best')만 출력된 것을 볼 수 있다.


<참고 자료>

인공 신경망의 학습 과정(Learning Process of ANN)

(인공 신경망을 모르신다면 이 링크 먼저 보시는게 좋아요! 인공 신경망)

인공 신경망은 어떻게 학습할까?

인공 신경망 학습 과정

위 이미지(속칭 움짤)는 인공 신경망의 학습 과정을 나타낸 것이다.
먼저 움짤이 보여주는 순서대로 인공 신경망의 학습 과정을 말로 풀어보자.

① : 데이터 입력(입력층) -> 가중치-편향 연산 & 활성화 함수 연산 반복 수행(은닉층)
② : ①의 연산 결과(예측값) 출력(출력층)
③ : 예측값과 실제 값의 차이 계산 by 손실 함수
④ : ③의 계산 결과에 따라 가중치 갱신 by 경사 하강법
⑤ : 기준 만족할 때까지 ①~④ 과정 반복
(기준 : 학습 횟수, 성능 평가 점수 등 사용자 지정 요소)

여기서 ①, ②가 이루어지는 과정을 순전파(Forward Propagation),
③은 손실 계산 (또는 그냥 손실 함수 그 자체),
④는 역전파(Backward Propagation)라고 한다.

그리고 ①부터 ④까지 한 번 수행된 것을 두고 iteration 또는 epoch라고 하는데, 이는 학습시키는 데이터의 단위(=배치 사이즈(batch size))에 따라 다르다.
만약 데이터가 잘게 나뉘어서 조각조각 학습되었다면 하나의 조각이 위 과정을 한 번 수행했을 때 이를 1 iteration이라고 한다.
그리고 잘게 나뉘었든 통짜든 전체 데이터 뭉치가 한 번 위 과정을 거쳤다면 이를 1 epoch라고 한다.
자세한 내용은 아래에서 다루겠다.

※ 참고 : iteration과 epoch의 의미

iteration
the process of doing something again and again, usually to improve it, or one of the times you do it

epoch
a long period of time, especially one in which there are new developments and great change

- Cambridge English Dictionary

그럼 구체적으로 인공 신경망의 각 학습 과정에서 무슨 일이 벌어지고 있는지 들여다 보자.

순전파(Forward Propagation; Feed Forward)

순전파와 역전파를 순(順)과 역(逆), 전파(傳播)로 나누어서 보자.
전파(傳播)는 무언가를 널리 전달하여 퍼지게 하는 것이다.
순(順)은 순한 또는 순응한다는 뜻이고 역은 거꾸로, 거스른다는 뜻이다.

그럼 무엇을 전파하는 것인가? 간단하다. 입력받은 값이다.
자, 무언가가 들어왔다. 그럼 나갈 곳도 있어야 하는게 순리이다(월급이 들어오면 기다렸다는 듯이 카드값이 나가듯...).
따라서 순전파는 들어온 값이 나가는 방향으로 자연스럽게 퍼져가는 것이다.
반대로 역전파는 나갈 곳에서 나가지 않고 거꾸로 들어온 방향으로 거슬러 가는 것이다.

인공 신경망에서의 순전파도 똑같은 이치이다.

1) 이전 단계(입력층 또는 이전 은닉층)에서 값이 들어온다.
2) 이에 대해 가중치-편향 연산을 수행한다.
3) 그리고 가중합으로 얻은 값을 활성화 함수를 통해 다음 층으로 전달한다.

손실 함수(Loss Function)

연습생(입력층)부터 시작해 하드 트레이닝(순전파)을 거쳐온 $x_1$(입력값)이 마침내 최종 오디션(출력층)에 도달하였다.
이제 세상에 나를 드러내기만 하면 된...다고 생각하던 찰나, 대표님(손실 함수 J)이 말한다.
"응 아직 아니야, 돌아가~ 돌아가는 길에 스타일이랑 컨셉 싹 고쳐서 다시 트레이닝 해달라고 해~ 너 아직 데뷔 못해~"

손실 함수는 순전파를 통해 출력층에 도달한 값, 즉 신경망의 예측값을 실제 데이터의 타겟 값과 비교하여 그 차이를 계산한다.
차이를 계산하는 방법은 다양한데, Keras 기준으로 자주 사용되는 몇 가지는 다음과 같다.

  • binary_crossentropy
  • categorical_crossentropy$^*$$^1$
  • sparse_categorical_crossentropy$^*$$^1$
  • 그 외 mean_squared_error, mean_absolute_error 등

차이 계산을 마쳤으면 그 차이를 줄이기 위해서 먼 길을 험난하게 거쳐온 출력값들을 가차없이 되돌려보낸다.

그냥 보내는가? 아니다. 왔던 길 되돌아가면서 각 길목 담당자(노드)한테 다음 번에 더 잘 할 수 있게 개선 좀 하라고 하며 돌려보낸다.

역전파(Backward Propagation; Backpropagation)

"트레이너(노래 담당 - 노드)님, 대표님이 저 다시 하래요. 근데 스타일이랑 컨셉 싹 다 고치래요."
"그래? 그럼 창법을 두성으로 바꾸자!"
"트레이너(댄스 담당 - 노드)님, 대표님이 저 다시 하래요. 근데 스타일이랑 컨셉 싹 다 고치래요."
"그래? 그럼 힙합 스타일로 가자!"
"트레이너님", "트레이너님", "트레이너님" ...
... 모든 트레이너와 스타일 및 컨셉 논의를 마치고서 $x_1$은 다시 연습생이 되어야 한다.

자, 손실 함수한테 퇴짜맞고서 이제 왔던 길을 되돌아가려고 한다.
그런데 그냥 터덜터덜 가면 안 되고, 가는 길목 길목 담당자마다 만나서 개선해야 한다 말하고 실제로 개선까지 같이 해야 되돌아갈 수 있다!

역전파는 손실 함수를 통해서 얻은 손실 정보를 출력층부터 입력층까지 전달하여 매 단계 가중치가 어떻게 조정되어야 할지 구하는 과정이다.

그럼 이 가중치는 어떻게 조정을 하는가?
이때 사용되는 방법이 바로 경사 하강법(GD; Gradient Descent)이다.

경사 하강법(GD; Gradient Descent)

"$x_1$. 어디 가니?"
"앗, GD 선배님! 저 대표님에게 퇴짜맞아서 다시 처음으로 되돌아가는 중입니다..."
"그렇군. 다음 번에 또 퇴짜맞으면 안 되잖아, 그렇지?"
"네 맞아요! 근데 저 어떻게 해야할지 모르겠어요..."
"걱정마! 내가 너에게 또 퇴짜맞지 않도록 가이드를 해주지!"
"!!!"

경사 하강법은 역전파 과정에서 손실 함수의 값을 줄이기 위한 방법 중의 하나이다.
우선 손실 함수를 표현한 그래프를 보자.

가로축은 가중치, 세로축은 손실 함수 값이다.
손실 함수의 값을 줄이기 위해서는 맨 아래에 위치한 최소값을 향해서 가야 할텐데, 어떻게 도달할 수 있을까?
간단하다. 손실 함수의 기울기가 작아지는 방향으로 가중치를 갱신하는 것이다.

기울기는 어떻게 구하지?
간단하다. 손실 함수를 미분한 함수, 즉 손실 함수의 도함수가 바로 기울기이다.
따라서 손실 함수의 도함수를 계산하여 이 값이 작아지도록 가중치를 조정한다.

그럼 구체적으로 가중치 갱신 과정을 알아보자.


가중치 갱신 과정


위 이미지는 $i$번째 가중치인 $\theta_i$가 갱신되는 모습을 수식으로 표현한 것이다.
$\eta$는 경사를 얼마나 큰 보폭으로 내려갈지 결정하는 것이고,
$\theta_{i,j}$의 $j$는 iteration을 의미한다.
$J(\theta)$는 가중치 $\theta$에 대한 손실 함수이며,
$\partial$는 편미분 기호이다.

해당 가중치에 대한 손실 함수의 기울기는 손실 함수를 해당 가중치로 편미분한 $\frac{\partial J(\theta)}{\partial \theta_{i, j}}$로 표현된다.

기울기가 작아지는 방향으로 가중치를 움직여야 하므로 기울기 값에 음의 부호(-)를 붙인다. 이러면 양수 기울기는 음수로, 음수 기울기는 양수가 되어 매 갱신마다 가중치가 손실 함수의 최소값에 가까워지도록 만든다.

가중치 조정 결과


역전파 편미분 계산 과정 with 연쇄 법칙(Chain Rule)

위에서 가중치 $\theta_{i, j}$에 대한 손실 함수의 기울기는 $\frac{\partial J(\theta)}{\partial \theta_{i, j}}$인 것을 확인했다. 근데 이건 또 어떻게 구하지?
여기서 편미분과 함께 연쇄 법칙이 사용된다.

먼저 가중치, 이전 입력값, 편향과 현재 입력값, 그리고 출력값의 손실 함수로 이루어진 그래프를 그려보자.

$wx+b$가 활성화 함수 $Z$를 거쳐서 출력값 $y$가 되었고, y는 손실 함수에 전해져 손실 함수값 J가 나왔다.
$\partial w$, $\partial Z$, $\partial y$, $\partial J$는 $w$, $Z$, $y$, $J$ 각각을 미분한 것을 의미한다.

여기서 가중치에 대한 손실 함수의 미분값(기울기)는 $\frac{\partial J}{\partial w}$로 나타낼 수 있는데, 이를 한 번에 계산할 수가 없다.
왜냐하면 $J$와 $w$ 사이에 여러 가지 계산 과정이 자리를 잡고 있기 때문이다. 따라서 중간 보스 격파 후에 최종 보스를 깨듯이 이 각각의 단계를 순차적으로 깨야 한다. 이 과정은 아래와 같이 표현된다.

$$\frac{\partial J}{\partial w} = \frac{\partial J}{\partial y} \cdot \frac{\partial y}{\partial Z} \cdot \frac{\partial Z}{\partial w}$$

이런 식으로 $\partial J$와 $\partial w$의 중간에 위치한 노드도 미분 과정에 포함시켜 이어붙이는 것이다. 이러한 계산 방식을 연쇄 법칙(Chain Rule)이라고 한다.

※ 손실 함수를 왜 J라고 표시할까?

명확한 출처는 찾지 못했으나, 인터넷 상에 올라온 의견들을 보면 오래 전부터 미적분학에서 사용했다거나, 'Jacobian'에서 따왔다거나, Loss에서 L을 거울에 비추듯 뒤집은 것이라는 등의 내용이 있었다.
(확실한 내용을 아시는 분께서는 코멘트 남겨주시면 감사하겠습니다!)


옵티마이저(Optimizer)

"감사합니다, GD 선배님! 덕분에 제 스타일이랑 컨셉도 저에게 딱 맞게 다 바꿨어요! 근데 저뿐만 아니라 저랑 비슷한 처지인 친구들이 산더미인데, 혹시..."
"아, 그러면 나 말고 나보다 빠릿빠릿한 친구가 있거든? 그 친구한테 가봐. 이름은 SGD야."

위에서 경사 하강법을 통해서 손실 함수의 기울기를 계산하여 가중치를 갱신한다는 것을 알았다.
허나 경사 하강법은 모든 입력 데이터에 대해서 손실 함수의 기울기를 계산하기 때문에, 데이터가 커질 경우에는 계산 과정이 상당히 오래 걸리게 된다.
이 문제를 각자 나름의 방법으로 최적화하는 친구들이 있으니, 이 친구들을 묶어서 옵티마이저라고 한다.

단순하게 말하자면, 가파른 경사길을 어떤 방식으로 내려올 것인지 지정하는 것이다.
후딱 빠르게 내려갈지, 천천히 주변을 살필지, 보폭을 크게 혹은 작게 할지 등등.

우선 너무 꼼꼼한 나머지 대량의 데이터에는 굼떠버리는 GD를 대신하여 신속함(달리 말하면 성급함)을 미덕으로 삼는 SGD(Stochastic Gradient Descent)를 먼저 만나보자.

1) 확률적 경사 하강법(SGD; Stochastic Gradient Descent)

"(연습생 그룹) 안녕하세요 SGD 선배님, 잘 부탁드립니다!"
"왔구나? 오케이, 일단 너 하나 먼저 가자!"
"에?"
(잠시 뒤)
"우선 한 번 됐고, 이런 식으로 하나씩 돌아가면서 다들 어떻게 할지 각을 재보자!"
'(연습생 그룹) 뭔가... 불안하다... !'

확률적 경사 하강법은 전체 데이터에서 하나의 데이터만 뽑아서 손실 계산 및 역전파 과정을 수행하는 방식이다.
즉, 한 번의 iteration마다 1개의 데이터만 사용하는 것이다.

데이터를 1개만 쓰다 보니 가중치를 업데이트하는 속도는 매우 빠르다.
문제는 1개만 쓰기 때문에 학습 과정에서 경사 하강이 이리 갔다 저리 갔다 불안불안 불안정한 모습을 보인다.

전부 다 투입시키자니 한 세월이 가고,
그렇다고 하나씩 보내서 빨리 빨리 하려니 가는 애들마다 이랬다 저랬다 난리라서 불안하고...
그러면 적당히 작은 그룹으로 나눠서 보내면 전부 다 보내는 것보다는 빠르고, 하나만 보내는 것보다는 덜 왔다 갔다 하지 않을까?

그래서 나온 방법이 미니 배치 경사 하강법(Mini-batch GD)이다.

2) 미니 배치 경사 하강법(Mini-batch GD)

"한 명씩 보내니까 너무 이랬다 저랬다 하네?
그럼 이제부터는 그룹 단위로 가서 맞춰보자!"

전체 데이터를 작게 쪼개어서 학습 과정에 보내는 방식이다.
어느 정도의 크기로 나누는가에 따라 학습 속도나 가중치 갱신의 최적점 도달 등의 결과가 달라진다.
여기서 데이터를 나누어주는 크기를 배치 사이즈(Batch size) 라고 한다.

  • 배치 사이즈(Batch size)
    • 미니 배치 경사 하강법에서 사용하는 미니 배치의 크기
    • 일반적으로 2의 배수로 설정
    • 메모리 용량에 여유가 있다면 가능한 한 큰 배치 사이즈를 쓰는 것이 안정적인 학습 진행에 유리함

배치 사이즈가 작을 때

배치 사이즈가 작아질수록 경사 하강법의 가중치 갱신이 불안정해진다. 이로 인해 최적점 도달에 많은 iteration이 필요해진다.

하지만 동시에 불안정, 즉 노이즈(noise)가 많기 때문에 지역 최적점(Local Minima)에서 빠져나와 전역 최적점(Global Minima)에 도달할 확률이 높아진다는 장점도 있다.

배치 사이즈가 클 때

배치 사이즈가 커질수록 가중치 갱신이 안정적이므로 최적점 도달에 비교적 적은 iteration만 필요해진다.

그러나 배치 사이즈를 너무 크게 설정하면 메모리 용량을 초과해버리는 Out-of-Memory 문제가 발생할 수도 있으므로 적당한 배치 사이즈를 설정해야 한다.

데이터 수와 배치 사이즈, iteration의 관계
$$
\text{# of Data = Batch size} \times \text{Iteration}
$$
순전파부터 역전파까지, 즉 가중치를 한 번 갱신하는 단위가 iteration이다. 그리고 미니 배치 경사 하강법에서는 배치 사이즈 단위로 iteration을 진행한다.

따라서 전체 데이터의 수는 배치 사이즈와 iteration을 곱한 값이라고 할 수 있다.

3) 그 외 옵티마이저들

GD와 SGD, Mini-batch GD 이후로 아래와 같이 다양한 옵티마이저들이 나왔다.

각각이 가진 특징을 간단한 비유로 표현해보겠다.

  • Momentum : 가던 방향으로 더 빨리 잘 가게 밀어주기
  • AdaGrad : 모르는 곳은 휙휙 둘러보고, 아는 곳은 자세하게 들여다 보기
  • RMSProp : 매 발걸음마다 내가 가는 이 길이 맞는지 아닌지 점검하며 가기
  • AdaDelta : AdaGrad의 개선 버전. 자세히 보는건 좋은데 멈추진 말고 계속 가면서 보기
  • Adam : AdaGrad와 RMSProp의 퓨-전(fusion). AdaGrad처럼 상황에 따라 보폭 조절하고, RMSProp처럼 제대로 가고 있는지 봐가면서 움직이기

이 중에서 Adam이 현재 가장 널리 사용되는 옵티마이저이다.
그렇다고 모든 상황에서 만능은 아니므로, 다루는 데이터의 성질과 해결할 문제 등을 고려하여 옵티마이저를 선택해야 할 것이다.


*1 categorical_crossentropy VS sparse_categorical_crossentropy

categorical_crossentropy와 sparse_categorical_crossentropy 모두 이름에서 알 수 있듯이 분류 문제를 위한 손실 함수로 쓰인다.
그럼 저 sparse가 붙고 안 붙고의 차이는 무엇인가?

우선 TensorFlow API 문서에 나온 예시를 보자.

# categorical_crossentropy
y_true = [[0, 1, 0], [0, 0, 1]]
y_pred = [[0.05, 0.95, 0], [0.1, 0.8, 0.1]]
loss = tf.keras.losses.categorical_crossentropy(y_true, y_pred)
assert loss.shape == (2,)
loss.numpy()

array([0.0513, 2.303], dtype=float32)

# sparse_categorical_crossentropy
y_true = [1, 2]
y_pred = [[0.05, 0.95, 0], [0.1, 0.8, 0.1]]
loss = tf.keras.losses.sparse_categorical_crossentropy(y_true, y_pred)
assert loss.shape == (2,)
loss.numpy()

array([0.0513, 2.303], dtype=float32)

위 예시 모두 3개의 클래스가 있고, 실제 타겟값은 1번 클래스와 2번 클래스를 의미한다.
여기서 둘의 표현 방식이 달라진다. categorical_crossentropy는 타겟값이 One-hot Encoding 되어 있는 반면에 sparse_categorical_crossentropy는 정수값이 그대로 있다.

그럼 각각 어떤 때에 사용해야 할까?

우선 sparse_categorical_crossentropy는 하나의 타겟 특성만 있는 경우 사용하면 될 것이다.
한 개의 타겟 특성 내에 여러 개의 클래스가 있는 경우이다.
예) Fashion MNIST

categorical_crossentropy는 타겟 특성이 One-hot Encoding되어 여러 개로 나누어졌거나 타겟 값이 여러 특성에 동시에 속할 수 있는 혹은 타겟 값이 여러 특성에 걸친 확률값인 경우 사용하는게 좋을 것이다.
예) One-hot Encoding : [1,0,0], [0,1,0], [0,0,1]
여러 특성에 걸친 경우 : [0.5, 0.3, 0.2]


<참고 자료>

활성화 함수(Activation Function)

(인공 신경망을 모르신다면 이 링크 먼저 보시는게 좋아요! 인공 신경망)

활성화 함수가 뭐지?

In artificial neural networks, the activation function of a node defines the output of that node given an input or set of inputs. A standard integrated circuit can be seen as a digital network of activation functions that can be "ON" (1) or "OFF" (0), depending on input. This is similar to the linear perceptron in neural networks. However, only nonlinear activation functions allow such networks to compute nontrivial problems using only a small number of nodes, and such activation functions are called nonlinearities.

Wikipedia (Activation function)

활성화 함수는 각 노드에서 가중치-편향 연산을 거친 입력값을 다음 단계로 줄지 말지, 주면 어떻게 줄지 결정하는 일종의 문지기 역할을 한다.

활성화 함수의 역할은 두 가지가 있다.

1) 가중치-편향 연산의 결과값(가중합)을 그대로 내보내면 너무 크거나 작을 수 있다.
활성화 함수는 이를 0에서 1 또는 -1에서 1 사이의 값 등으로 바꿔준다(활성화 함수 유형에 따라 다름. 전부 다 상하한의 제한이 있는 것은 아님).

2) 가중치-편향 연산 결과에 비선형성을 부여한다(비선형적인 활성화 함수인 경우. 특별한 경우가 아니라면 비선형성을 가진 활성화 함수만 사용함$^*$$^1$).

활성화 함수에는 여러 유형이 있는데, 그중에서 많이 알려졌거나 주로 쓰이는 것들만 들여다 보려고 한다.


활성화 함수의 유형

1) 계단 함수(Step function)

$$\begin{cases}
0 & \text{if } x < 0\\
1 & \text{if } x \geq 0
\end{cases}
$$

이름대로 생긴 함수다.
0보다 작으면 0, 0 이상이면 1인 모 아니면 도 방식의 가장 간단한 활성화 함수이다.

문제는 인공 신경망의 학습 과정 중 역전파(backpropagation)라는 것이 있는데, 이때 활성화 함수의 미분이 필요하다.
그런데 계단 함수를 미분하니 임계값(0)에서는 미분값이 무한대가 되고 나머지는 0이다. 이는 역전파 과정에서 무의미하므로 계단 함수는 쓰이지 않는다.


2) 시그모이드 함수(Sigmoid function)

Sigmoid


$$\sigma(x) = \frac{1}{1+e^{-x}}$$

로지스틱 회귀에서도 사용되는 함수이다.
받아들인 값을 0 ~ 1 사이의 값으로 바꿔준다.

위의 계단 함수는 무의미한 미분 결과를 가진 것에 반해, 시그모이드 함수는 모든 $x$ 값에 대하여 미분이 가능하다(즉, 미분값(기울기)이 존재한다).

허나 이 친구도 계단 함수처럼 역전파 과정에서 문제점이 있다.
시그모이드 함수를 미분했을 때 미분값은 최대 0.25이다. 그런데 층이 여러 개라면?
2개 층이면 0.250.25=0.0625,
3개 층이면 0.250.250.25=0.015625 ...
매번 최대치로 잡는다고 해도 미분값이 훅훅 작아져버린다.
즉, 시그모이드 함수로 구성된 신경망에서 역전파 과정을 거치면 층이 갈수록 미분값이 작아져서 결국 학습이 제대로 되질 않는다(이를 기울기 소실$^
$$^2$이라고 함).

이런 이유로 신경망의 은닉층에서 활성화 함수로 시그모이드를 사용하지 않는다.
대신 이진 분류 문제의 출력층에서 사용된다(예측 결과가 1일 확률을 0~1 사이의 확률값으로 표현).


3) ReLU 함수(Rectified Linear Unit function)

ReLU


$$\begin{cases}0 & \text{if } x \leq 0 \\ x & \text{if } x > 0\end{cases}$$

앞의 두 친구가 역전파에서 불합격 통보를 받고 탈락했다.
그래서 나온 친구가 바로 ReLU다.

이미지에서 보이는 것처럼 0 이하의 값은 모두 0으로, 그 외에는 들어온 값 그대로 보내주는 방식이다.
미분을 해도 양수 쪽에서는 기울기가 1이므로 역전파 과정에서 시그모이드 함수처럼 신경망의 층이 갈수록 값이 소실되는 문제도 없다.
그래서 신경망의 은닉층에서 주로 사용되는 활성화 함수이다.

그러나 이 친구도 완벽하진 않다. 그래프에서 볼 수 있듯이 ReLU 함수는 신경망 학습 과정에서 양수만 보내주고 음수는 전부 0으로 처리한다. 이로 인해 음수 가중치를 가진 노드들은 싹 다 무시해버리는, 이른바 dying ReLU 문제가 있다.

그래서 이 죽어버린 아이들을 살리기 위해 아래와 같은 ReLU 변종들이 나왔다.


3-1) Leaky ReLU 함수(Leaky ReLU function)

Leaky ReLU


$$\begin{cases}0.01x & \text{if } x < 0 \\ x & \text{if } x \geq 0\end{cases}$$

leaky, 즉 라면 냄비 바닥이 살짝 구멍 뚫려 국물이 조금 샌 것처럼 0 이하의 값에도 아주 약간의 기울기를 부여한 것이다.
보통의 ReLU에서 다 죽던 음수 가중치들에게 산소 호흡기를 던져준 느낌으로 보면 된다.


3-2) PReLU 함수(Parametric ReLU function)

PReLU


$$\begin{cases}\alpha x & \text{if } x < 0 \\ x & \text{if } x \geq 0\end{cases}\\ \text{with parameter }\alpha \text{ }(\alpha \leq 1)$$
($\alpha$는 학습되는 값으로, 계속해서 갱신됨)

Parametric이라는 말처럼 $\alpha$라는 값을 통해 0 이하의 값에 기울기를 부여하는 것이다.
Keras에서 PReLU를 사용할 경우, $\alpha$는 스스로 학습되는 값이다. 여기에 특정한 제약 등을 적용할 수 있다.


3-3) ELU 함수(Exponential Linear Unit)

ELU


$$\begin{cases}\alpha (e^x -1) & \text{if } x \leq 0 \\ x & \text{if } x > 0\end{cases}\\ \text{with parameter } \alpha \text{ }(\alpha \geq 0)$$
($\alpha$는 학습되는 값으로, 계속해서 갱신됨)

0 이하 부분이 지수함수 형태로 되어 있는 ReLU 함수다.
PReLU와 마찬가지로 $\alpha$가 있다.


4) Softmax 함수(Softmax function)

$$
\begin{bmatrix}z_1 \\ z_2 \\ z_3 \\ \cdots \\ z_k \end{bmatrix}=>
S(z_i) = \frac{e^{z_i}}{\sum_{j=1}^{k}{e^{z_j}}} =>
\begin{bmatrix}p_1 \\ p_2 \\ p_3 \\ \cdots \\ p_k \end{bmatrix}\\
(\text{for } i = 1, \cdots, k)
$$

여자친구가 물어본다. 오늘 저녁 뭐 먹지? 메뉴 세 가지만 말해봐 !
그럼 나는 대답한다. 치킨, 초밥, 김밥 !
그럼 여자친구는 답한다. 오늘은 김밥이다 !

소프트맥스 함수는 선택 가능한 옵션 여러 개를 받아서 각각이 최종 정답일 확률값을 내보낸다.
조금 더 구체적으로 말하면, k개의 원소를 가진 벡터(k차원 벡터)를 입력받은 후 각각에 대한 확률값을 가진 벡터를 출력한다.
확률이므로 출력된 벡터의 원소를 합하면 1이다.

위 이야기에서 치킨, 초밥, 김밥을 말했을 때 여자친구가 머릿속에서 "치킨은 30%, 초밥은 10%, 김밥은 60%"라고 생각했다고 해보자.
이를 신경망 모델에 대입해보면 각 클래스(입력 - [치킨, 초밥, 김밥])에 대한 확률값(출력)은 0.3, 0.1, 0.6이고 모델은 최종 결과로 '김밥'이라는 결과를 내보내는 것이라고 할 수 있다.

물론 신경망이 자기 스스로 생각해서 저녁에 뭐 먹을지 답을 내는 것은 아니고, 위의 소프트맥스 함수의 수식에 따라 계산값을 도출하여 답을 낸다.

이러한 특징을 갖고 있기에 소프트맥스 함수는 다중 분류 문제를 위한 신경망 학습 과정 중 출력층에서 사용된다.


*1 왜 비선형적인 활성화 함수만 사용되나?

인공 신경망의 학습 과정에서 가중치-편향 연산만 수행하게 될 경우 각각의 노드의 결과값은 Wx+b 형태가 된다(W : 가중치 행렬 / x : 입력값 / b : 편향).
만약 신경망의 층이 아무리 여러 겹으로 쌓인다 하여도 활성화 함수에서 비선형성을 부여하지 않으면 결국은 직선 형태에서 벗어나질 못한다.

$l(x) = ax+b$ 라고 하면
$$l(l(l(x))) = l^3(x) \\= a(a(ax+b)+b)+b \\= a^3x+a^2b+ab+b$$
$a^3=c$, $a^2b+ab+b=d$라고 하면
$l^3(x) = cx+d$, 직선이다. 3겹이든, 페스츄리 겹겹이 만큼이든.

이렇게 되면 여러 층을 쌓는 이점도 상실될 뿐만 아니라 XOR 등의 복잡한 문제 해결이 불가능해진다.
이런 이유로 인해 비선형적인 활성화 함수를 통해서 가중치-편향 연산 결과에 비선형성을 부여하는 것이다.


*2 기울기 소실

인공 신경망 학습 과정 중 역전파에서는 활성화 함수의 미분값을 매 층마다 곱하게 된다. 그런데 이 미분값이 1 미만의 소수인 경우, 여러 번 곱해지다보면 0으로 수렴하여 신경망의 학습이 제대로 이루어질 수가 없다.

시그모이드 도함수 그래프


위 그래프는 시그모이드 함수를 미분한 함수의 그래프이다. 보이는 것처럼 최댓값이 0.25이다.
이 상태로는 층이 많아지면 많아질수록 역전파를 거치면서 기울기 값이 0을 향해 낙하하므로 시그모이드 함수를 은닉층의 활성화 함수로는 사용할 수가 없는 것이다.

(참고 : 시그모이드 함수를 $f(x)$라고 하면
$$f'(x) = f(x)(1-f(x))$$이다.
$x=0$일 때 기울기가 최대이므로 $$f'(0) = \frac{1}{2}*(1-\frac{1}{2}) = 0.25$$이다.)


<참고 자료>

인공 신경망(ANN; Artificial Neural Network)

인공 신경망이 뭐지?

인공신경망(人工神經網, 영어: artificial neural network, ANN)은 기계학습과 인지과학에서 생물학의 신경망(동물의 중추신경계중 특히 뇌)에서 영감을 얻은 통계학적 학습 알고리즘이다. 인공신경망은 시냅스의 결합으로 네트워크를 형성한 인공 뉴런(노드)이 학습을 통해 시냅스의 결합 세기를 변화시켜, 문제 해결 능력을 가지는 모델 전반을 가리킨다. 좁은 의미에서는 오차역전파법을 이용한 다층 퍼셉트론을 가리키는 경우도 있지만, 이것은 잘못된 용법으로, 인공신경망은 이에 국한되지 않는다.

- 위키백과 (인공 신경망)

인공 신경망은 생물의 신경계가 작동하는 방식을 모방하여 만든 머신 러닝 모델이라고 볼 수 있다.

우리의 신경계는 수많은 신경 세포, 즉 뉴런(neuron)으로 이루어져 있다. 일반적인 뉴런의 구조는 아래와 같이 생겼다.

일반적인 뉴런의 구조


간단하게 설명하자면, 뉴런은 수상돌기를 통해 신호를 받아들인 후 신경세포체와 축삭을 거쳐서 다른 뉴런으로 신호를 전달한다.

우리 몸의 신경계가 뉴런으로 구성되듯이 인공 신경망을 이루는 가장 작은 단위가 있는데, 이를 퍼셉트론(perceptron)이라고 한다.

퍼셉트론(perceptron)

위에서 뉴런이 '수상돌기 -> 신경세포체/축삭 -> 다음 뉴런의 수상돌기'라는 과정을 거쳐서 신호를 전달하는 것을 보았다. 퍼셉트론도 이와 비슷한 구조를 갖고 있다.

먼저 여러 개의 입력값을 받는다. 각각의 입력값에는 신호의 세기, 즉 가중치가 부여되어 있다. 각각의 입력값과 가중치가 곱해진 값을 합한 후, 이에 편향을 더해준다(가중치-편향 연산). 이를 식으로 나타내면 아래와 같다.
$$w_1x_1 + w_2x_2+ b$$
위에서는 입력값이 2개뿐이다. 만약 입력값이 n개라고 하면 식이 어떻게 될까?
$$\sum_{k=1}^{n}w_kx_k + b\\
= (w_1x_1+w_2x_2+...+w_nx_n) + b\\
= \begin{bmatrix}w_1&w_2&\cdots&w_n\end{bmatrix}\begin{bmatrix}x_1\\x_2\\...\\x_n\end{bmatrix} + b\\
=Wx + b$$
각각의 입력값과 가중치가 곱해지는 연산을 벡터로 표현하였고, 그 결과 $Wx+b$와 같은 형태가 되었다(여기서 $W$는 가중치 행렬$^*$$^1$이라고 함).
어디서 많이 보던 모양이다. 그렇다. 일차 함수, 직선이다!

그렇다. 직선이다. 그게 뭐 특별한건가?
특별하다. 왜냐하면 이대로는 복잡한 문제 해결이 불가능하다.
어떤 복잡한 문제인가? XOR 이라고 하는 문제가 있다.

XOR (배타적 논리합)

XOR을 알기 위해서는 먼저 AND, NAND, OR와 같은 논리 게이트가 어떻게 작동하는 것들인지 이해해야 한다.

1) AND
두 명의 사람이 있고, 저녁에 치킨을 먹을지 말지 고민 중이다.
둘 모두 치킨을 먹는다고 할 때에만 먹는(1) 경우다.

AND GATE

2) NAND
이는 AND의 반대, Not AND라서 NAND이다.

NAND GATE

2) OR
이는 둘 중 한 명이라도 치킨 먹자! 라고 하면 치킨을 먹는 경우다.

OR GATE

3) XOR
둘 다 먹자고 하면 안 먹고, 둘 다 안 먹자고 하면 안 먹는데 둘 중 하나만 먹자고 하면 먹는 이상한 경우다. 둘 모두 먹으면 둘 다 살이 찌니까 한 명만 먹기로 하는 결정인걸까? 확실히 단순하지는 않다.

XOR GATE

XOR이 어떤 식으로 작동하는지 보았다. 이번에는 위 논리 게이트의 Output들이 직선을 통해 어떤 식으로 분류되는지 보자.

논리 게이트 Output 분류


AND와 OR의 경우 하나의 직선으로 0과 1의 Output들이 깔끔하게 분류가 된다. 그런데 XOR은? 이래서 아까 위에서 나온 Wx+b의 직선 형태로는 XOR 문제를 해결할 수가 없다.

자, 직선으로는 답이 안나온다. 그럼 어떻게 하지?
일단 휘게 만든다. 뭘로? 활성화 함수로.

활성화 함수(Activation Function)

활성화 함수. 이름대로 자기가 받은 신호를 잘 살려서 내보내주는 역할을 한다. 마치 아이돌 연습생을 잘 트레이닝해서 데뷔를 시키는 프로듀서와도 같다.

잘 살려서 내보내주는 역할이란 무엇인가? 여기에는 두 가지가 있다.

1) 가중합(가중치*입력값 들의 합, Wx)이 계산되고 나면 값이 너무 커지거나 작아질 수가 있다. 이때 활성화 함수를 통해서 이 값을 0에서 1 또는 -1에서 1 사이의 값 등으로 바꿔준다(활성화 함수 유형에 따라 다름. 전부 다 상하한의 제한이 있는 것은 아님).
아이돌 연습생의 과도한 똘끼(?)를 진정시켜 마음을 가다듬게 해준다고 보면 되겠다.

2) 비선형성을 가진 활성화 함수를 통해서 Wx+b를 휘게 만들어준다.
연습생이 이상한 고집 부리지 않게끔 유연한 사고방식을 심어준다고 생각하면 될 것 같다.

(구체적인 활성화 함수 내용은 다음 링크 참고 : 활성화 함수)

자, 우리 연습생의 똘끼도 진정시켰고, 이상한 고집도 안 부리게끔 만들었다. 이제 세상으로 내보내보려고 한다.
잠깐, 그 전에 잘 하는지 한번 보자.

### XOR 문제 구성 ###
import numpy as np
import matplotlib.pyplot as plt
np.random.seed(0)

x11 = np.random.uniform(low=0, high=5, size=(50,))
x12 = np.random.uniform(low=10, high=15, size=(50,))
x21 = np.random.uniform(low=0, high=5, size=(50,))
x22 = np.random.uniform(low=10, high=15, size=(50,))


x1 = np.append(x11, x12)
x2 = np.append(x21, x22)

y11 = np.random.uniform(low=10, high=15, size=(50,))
y12 = np.random.uniform(low=0, high=5, size=(50,))
y21 = np.random.uniform(low=0, high=5, size=(50,))
y22 = np.random.uniform(low=10, high=15, size=(50,))

y1 = np.append(y11, y12)
y2 = np.append(y21, y22)

x_1 = np.vstack([x1, y1]).T
x_2 = np.vstack([x2, y2]).T
y_1 = np.ones_like(x_1[:, 0])
y_2 = np.zeros_like(x_2[:, 0])
x = np.vstack([x_1, x_2])
y = np.hstack([y_1, y_2])


fig, ax = plt.subplots(figsize = (12,5))
ax.plot(x_1[:, 0], x_1[:,1], 'bo')
ax.plot(x_2[:,0], x_2[:,1], 'ro')
ax.grid()

XOR problem

### XOR 문제 해결시켜보기(단층 퍼셉트론) ###
import tensorflow as tf

model = tf.keras.models.Sequential([
    # 한 개의 층으로만 구성
    tf.keras.layers.Dense(1, input_dim=2, activation='sigmoid')
])

model.compile(optimizer='sgd',
              loss='binary_crossentropy',
              metrics=['accuracy'])

model.fit(x, y, epochs=1000, verbose=0)

preds = model.predict(x)
preds_1d = preds.flatten()
pred_class = np.where(preds_1d > 0.5, 1 , 0)

y_true = x[pred_class==1]
y_false = x[pred_class==0]

fig, ax = plt.subplots(figsize = (12,5))
ax.plot(y_true[:, 0], y_true[:,1], 'bo')
ax.plot(y_false[:,0], y_false[:,1], 'ro')
ax.grid()

XOR problem solution failed

큰일이다. 이 친구가 혼자서 해내지 못한다.
솔로 데뷔가 힘들 것 같은데... 그렇다면 다른 연습생들과 묶어서 그룹으로 데뷔를 시켜야 할까?

### XOR 문제 해결시켜보기(다층 퍼셉트론) ###
model = tf.keras.models.Sequential([
    # 여러 개의 층으로 구성
    tf.keras.layers.Dense(8, input_dim=2, activation='sigmoid'),
    tf.keras.layers.Dense(1, activation='sigmoid')
])

model.compile(optimizer='sgd',
              loss='binary_crossentropy',
              metrics=['accuracy'])

model.fit(x, y, epochs=1000, verbose=0)

preds = model.predict(x)
preds_1d = preds.flatten()
pred_class = np.where(preds_1d > 0.5, 1 , 0)

y_true = x[pred_class==1]
y_false = x[pred_class==0]

fig, ax = plt.subplots(figsize = (12,5))
ax.plot(y_true[:, 0], y_true[:,1], 'bo')
ax.plot(y_false[:,0], y_false[:,1], 'ro')
ax.grid()

XOR problem solution successed

다른 연습생들과 함께 그룹으로 묶으니 이제 복잡한 문제도 자기들끼리 척척 잘 해결한다!
이제는 믿고 데뷔를 시킬 수 있을 것 같다.

이렇게 여러 층의 퍼셉트론으로 구축한 신경망을 다층 퍼셉트론 신경망(MLP; Multi Layer Perceptron)이라고 한다.


인공 신경망은 어떻게 생긴 것이지?

인공 신경망의 가장 기본이 되는 단위인 퍼셉트론 하나부터 시작해서 퍼셉트론 여러 개가 여러 층으로 모인 다층 퍼셉트론 신경망까지 살펴봤다.
이번에는 인공 신경망의 전체적인 그림을 보자.

인공 신경망

인공 신경망은 위 그림처럼 생겼다. 그림 속 각각의 원은 노드(node)라고 하며, 전체는 크게 세 부분 - 입력층(Input Layer), 은닉층(Hidden Layers), 출력층(Output Layer)으로 나누어진다.

1) 입력층(Input Layer)

  • 데이터셋이 입력되는 층
  • 데이터셋의 특성(feature) 개수에 맞춰 입력층의 노드 수가 결정됨
  • 어떤 계산 없이 입력값의 전달만 수행 -> 신경망 층수(깊이, depth)에 포함되지 않음

2) 은닉층(Hidden Layers)

  • 입력층에서 들어온 값이 가중치-편향 연산 및 활성화 함수를 거쳐가는 층
  • 일반적으로 입력층과 출력층 사이에 있는 층임
  • 사용자가 계산 결과를 볼 수 없으므로 은닉(hidden)층이라 함
  • 입력 데이터셋의 특성 수와 관계없이 노드 수 구성 가능
    ※ 딥 러닝 : 2개 이상의 은닉층을 가진 신경망

3) 출력층(Output Layer)

  • 은닉층의 연산을 마친 값이 출력되는 층
  • 해결할 문제에 따라 출력층의 노드 수가 결정됨
  노드 수 결과 값 활성화 함수
이진 분류 1
(∵0 또는 1의
값 1개)
0~1 사이의 확률값 Sigmoid
다중 분류 레이블(타겟)
클래스 수
각 클래스별 0~1
사이의 확률값
Softmax
회귀 출력값의
특성(타겟) 수
타겟 값 일반적으로는
지정 X

 

인공 신경망 구현 예시(Tensorflow & Keras)

1) 데이터 불러오기

입력 데이터 샘플과 Features : 1077 샘플 x 69 Features (변수)
데이터 label: 다운증후군 (1), 정상군 (2)

(데이터는 다운증후군과 정상군 마우스 피질의 핵 분획에서 검출 가능한 신호를 생성하는 69 개 단백질의 발현 수준으로 구성되어 있습니다.
라벨로는 다운증후군 1, 정상군 2로 할당되어 있습니다.)

import pandas as pd
df = pd.read_excel("https://ds-lecture-data.s3.ap-northeast-2.amazonaws.com/MouseProtein/mouse_protein_X.xls", header=None)
df_label = pd.read_excel("https://ds-lecture-data.s3.ap-northeast-2.amazonaws.com/MouseProtein/mouse_protein_label.xls", header=None)

2) 라벨 값 변경

# 기존에 다운증후군(1), 정상군(2)였던 값을 정상군(0), 다운증후군(1)로 변경
df_label = df_label.replace(2, 0).iloc[:, 0].values
df_label.astype(object)

3) 훈련 / 테스트 데이터셋 나누기

from sklearn.model_selection import train_test_split

X_train, X_test, y_train, y_test = train_test_split(df, df_label, test_size=0.2, random_state=42)

4) 신경망 모델 구성

# 모델 초기화
model = tf.keras.models.Sequential([
    tf.keras.layers.Dense(128, input_dim=69, activation='relu'),
    tf.keras.layers.Dense(128, activation='relu'),
    tf.keras.layers.Dense(1, activation='sigmoid')
])
# Dense : 각각의 신경망 층을 나타냄
# 맨 처음과 마지막이 입력층과 출력층, 그 사이는 은닉층
# 각 층 맨 앞의 숫자(128, 128, 1)는 해당 층의 노드 수임
# input_dim : 입력 데이터 특성 수(input_shape=(69,) 이렇게도 입력 가능)
# activation : 해당 층의 노드들이 사용할 활성화 함수 지정
# keras 모델 초기화 후에는 compile 과정을 거쳐야 함
model.compile(optimizer='sgd',
              loss='binary_crossentropy',
              metrics=['accuracy'])
# optimizer : 손실 함수의 최소값을 찾는 방법 지정
# loss : 손실 함수 종류 지정
# metrics : 훈련 시 평가 지표 지정
# 모델 훈련시키기
model.fit(X_train, y_train, epochs=500)
# epochs : 전체 데이터셋을 한 번 훈련한 것이 1 epoch임
# epochs=500 이라는 것은 전체 데이터셋에 대해 훈련을 500번 진행한다는 의미

Epoch 1/500
27/27 [==============================] - 0s 876us/step - loss: 0.6981 - accuracy: 0.5017
Epoch 2/500
27/27 [==============================] - 0s 778us/step - loss: 0.6906 - accuracy: 0.5296
Epoch 3/500
27/27 [==============================] - 0s 815us/step - loss: 0.6804 - accuracy: 0.5935
...
Epoch 499/500
27/27 [==============================] - 0s 852us/step - loss: 0.0252 - accuracy: 0.9988
Epoch 500/500
27/27 [==============================] - 0s 852us/step - loss: 0.0287 - accuracy: 0.9954

# 테스트셋을 통한 모델 평가
model.evaluate(X_test, y_test, verbose=2)
# verbose : 결과 출력의 단계 설정
# auto - 대부분 1로 지정됨
# 0 - 출력 없음
# 1 - 진행 상황 출력(프로그레스바 포함)
# 2 - 진행 상황 출력(프로그레스바 제외, 1에 비해 간소화)

7/7 - 0s - loss: 0.0478 - accuracy: 0.9861
[0.04781070724129677, 0.9861111044883728]


*1 가중치 행렬(Weight Matrix)
위에서는 퍼셉트론 하나라서 행렬이라기보다는 벡터였다.
하지만 아래와 같이 퍼셉트론 여러 개로 구성된 신경망이라면?

가중치 행렬


이렇게 되면 가중치 연산은 (편향은 없다 하면)
$$(w_1x_1+w_3x_1+w_5x_1+w_2x_2+w_4x_2+w_6x_2)\\
= \begin{bmatrix}x_1&x_2\end{bmatrix}\begin{bmatrix}w_1&w_3&w_5\\w_2&w_4&w_6\end{bmatrix} = \begin{bmatrix}y_1&y_2&y_3\end{bmatrix}$$
이렇게 되고, 결과를 정리해서 표현하면 $y = Wx$ 라고 할 수 있다.
여기서 입력값의 벡터 $x$와 출력값의 벡터 $y$를 이어주는 행렬 $W$를 가중치 행렬이라고 한다.

코드 상에서 가중치 행렬의 형태는 어떻게 알 수 있을까?

model = tf.keras.models.Sequential([
    tf.keras.layers.Dense(10, activation='relu', input_shape=100), # 은닉층
    tf.keras.layers.Dense(1, activation='sigmoid') # 출력층
])

입력 데이터의 특성이 100개이므로 입력층 노드 수는 100, 은닉층의 노드 수는 10이므로 둘 사이의 가중치 행렬 형태는 (100, 10)이다.
같은 원리로 은닉층과 출력층 사이에서는 (10, 1)이 된다.


<참고 자료>

데이터베이스 언어 (Database Language)

데이터베이스 언어란?

데이터베이스 언어(영어: Database Language)는 컴퓨터의 데이터베이스 작업을 위한 컴퓨터 언어이다. 데이터베이스 언어를 사용하여 데이터베이스 사용자 및 응용 프로그램 소프트웨어는 데이터베이스에 액세스 할 수 있다. 데이터베이스를 취급하는 기능 중 검색(질의)가 중요하기 때문에, 통례는 (데이터베이스) 쿼리 언어라고도 불린다. 그러나 데이터베이스 언어 및 질의 언어는 개념적으로 겹치는 부분도 있지만, 동의어는 아니다.

2008년 현재 가장 대중적 데이터베이스 언어는 관계 데이터베이스의 데이터베이스 언어 SQL이다.

- 위키백과 (데이터베이스 언어)

데이터베이스 언어란 데이터베이스를 다루기 위한 명령어의 모음이라고 할 수 있다.
데이터베이스를 어떠한 목적을 갖고서 다루는가에 따라서 데이터 정의 언어(DDL), 데이터 조작 언어(DML), 데이터 제어 언어(DCL) 그리고 트랜잭션 제어 언어(TCL)로 구분한다.


1) 데이터 정의 언어 (DDL; Data Definition Language)

데이터 정의 언어(영어: data definition language, DDL)는 컴퓨터 사용자 또는 응용 프로그램 소프트웨어가 컴퓨터의 데이터를 정의하는 컴퓨터 언어 또는 컴퓨터 언어 요소이다. ...(중략)...

SQL의 데이터 정의 언어의 문장은 관계형 데이터베이스의 구조를 정의한다. SQL에 의해 정의되는 관계형 데이터베이스의 구조는 쌍(행), 속성(열), 관계(테이블), 인덱스 파일 위치 등 데이터베이스 고유의 특성을 포함한다.

- 위키백과 (데이터 정의 언어)

데이터 정의 언어는 데이터베이스의 구조, 즉 테이블을 다루기 위한 명령어들이다.
데이터 정의 언어에는 CREATE, ALTER, DROP, TRUNCATE가 있다.

  1. CREATE
  • 새로운 테이블을 생성하기 위한 명령어
CREATE TABLE Employee (
    id INTEGER PRIMARY KEY,
    last_name VARCHAR(75) NOT NULL,
    first_name VARCHAR(50) NULL,
    date_of_birth DATE NULL
);

  1. ALTER
  • 주로 기존에 존재하는 테이블의 컬럼 정보를 변경하기 위한 명령어
  • 테이블명 변경도 가능
-- 컬럼 추가
ALTER TABLE Employee ADD address TEXT;

-- 컬럼 추가 (특정 컬럼 뒤에 위치하기)
ALTER  TABLE Employee ADD COLUMN mid_name VARCHAR(32) DEFAULT NULL AFTER last_name;

-- 컬럼 설정 변경
ALTER TABLE Employee MODIFY COLUMN first_name CHAR(55) NOT NULL;

-- 컬럼명 및 설정 동시에 변경 (컬럼명만 변경 가능)
ALTER TABLE Employee CHANGE COLUMN first_name 1st_name VARCHAR(32) NULL;

-- 컬럼 제거
ALTER TABLE Employee DROP COLUMN address;

-- 테이블명 변경
ALTER TABLE Employee RENAME TO Employee_new;

  1. DROP
  • 데이터베이스 또는 테이블을 삭제하기 위한 명령어
-- 테이블 제거
DROP TABLE Employee_new;

-- 데이터베이스 제거
DROP DATABASE Company;

  1. TRUNCATE
  • 테이블 자체가 아닌 테이블 내부에 있는 레코드 전체를 삭제하기 위한 명령어
TRUNCATE TABLE Employee;

2) 데이터 조작 언어 (DML; Data Manipulation Language)

데이터 조작 언어(영어: Data Manipulation Language, DML)은 데이터베이스 사용자 또는 응용 프로그램 소프트웨어가 컴퓨터 데이터베이스에 대해 데이터 검색, 등록, 삭제, 갱신을 위한 데이터베이스 언어 또는 데이터베이스 언어 요소이다.

2007년 현재 가장 대중적 데이터 조작 언어는 SQL 데이터 조작 언어이다. SQL은 관계형 데이터베이스에 대해 검색 및 업데이트 등의 데이터 조작을 위해 사용된다.

- 위키백과 (데이터 조작 언어)

데이터 조작 언어는 테이블 내에 저장되는 데이터를 관리하기 위한 명령어들이다.
데이터 조작 언어에는 INSERT, UPDATE, DELETE, SELECT가 있다.

  1. INSERT
  • 테이블에 데이터를 입력하기 위한 명령어
INSERT INTO Employee (id, last_name, first_name, date_of_birth) VALUES (1, 'Doe', 'John', DATE_FORMAT(NOW(), '%Y-%m-%d'));

  1. UPDATE
  • 테이블 내 데이터를 수정하기 위한 명령어
  • 수정하려는 테이블과 컬럼, 그리고 수정되는 값을 넣음
  • WHERE 등의 조건을 이용하여 특정 레코드의 값만 수정 가능
UPDATE Employee SET first_name = 'updated';

-- WHERE 조건 추가
UPDATE Employee SET first_name = 'Mike' WHERE id = 2;

  1. DELETE
  • 테이블 내 레코드를 삭제하기 위한 명령어
  • WHERE 등의 조건이 없으면 전체 레코드가 삭제됨
  • DDL 중 TRUNCATE와의 차이점으로, TRUNCATE는 명령어를 실행하면 작업이 자동으로 확정(AUTO COMMIT)이 되나, DELETE는 작업을 취소(ROLLBACK) 가능
-- 전체 레코드 삭제
DELETE FROM Employee;

-- WHERE 조건을 추가하여 일부 레코드만 삭제
DELETE FROM Employee WHERE id = 2;

  1. SELECT
  • 테이블에 저장된 데이터를 조회하기 위한 명령어
  • SELECT 뒤에 조회하려는 컬럼명을 입력하여 특정 컬럼만 조회 가능(전체 컬럼 조회는 애스터리스크(*)를 입력)
  • 컬럼명 입력 시 AS 키워드를 통해 별명(Alias)을 부여하여 출력되는 컬럼명 변경 가능
  • WHERE, GROUP BY, JOIN 등의 조건을 이용하여 원하는 데이터 조회 가능
-- 아무 조건이 없으므로 테이블 내 모든 레코드를 조회
SELECT * FROM Employee;

-- WHERE 조건을 통해 특정 레코드만 조회
SELECT * FROM Employee WHERE id = 1;

-- last_name 컬럼의 별명을 LN으로 지정
-- 데이터 조회 시 last_name의 컬럼명이 LN으로 출력됨
SELECT last_name AS LN FROM Employee;

3) 데이터 제어 언어 (DCL; Data Control Language)

데이터 제어 언어(영어: Data Control Language, DCL)는 데이터베이스에서 데이터에 대한 액세스를 제어하기 위한 데이터베이스 언어 또는 데이터베이스 언어 요소이다.
권한 부여(GRANT)와 박탈(REVOKE)이 있으며, 설정할 수 있는 권한으로는 연결(CONNECT), 질의(SELECT), 자료 삽입(INSERT), 갱신(UPDATE), 삭제(DELETE) 등이 있다.

- 위키백과 (데이터 제어 언어)

데이터 제어 언어는 데이터베이스의 유저를 생성하고 권한을 제어하기 위한 명령어들이다.
주요 데이터 제어 언어에는 GRANT, REVOKE가 있다.
데이터 제어 언어로 설정 가능한 권한으로는 아래와 같은 것들이 있다.

  • CONNECT : 데이터베이스에 연결할 수 있는 권한
  • SELECT : 데이터베이스의 데이터를 조회할 수 있는 권한
  • INSERT : 데이터베이스의 데이터를 등록할 수 있는 권한
  • UPDATE : 데이터베이스의 데이터를 수정할 수 있는 권한
  • DELETE : 데이터베이스의 데이터를 삭제할 수 있는 권한
  1. GRANT
  • 특정한 데이터베이스 유저에게 어떠한 작업을 수행할 권한을 부여하는 명령어
  • 모든 권한을 부여하려면 ALL PRIVILEGES를 권한 자리에 입력
  • 특정 테이블이 아닌 모든 테이블에 대해 권한을 부여하려면 애스터리스크(*)를 테이블명 자리에 입력(모든 DB, 모든 테이블이라면 둘 다 애스터리스크 입력)
GRANT SELECT,INSERT,UPDATE,DELETE ON Company.Employee TO User1;

-- Company 데이터베이스의 모든 테이블에 대하여 모든 권한 부여
GRANT ALL PRIVILEGES ON Company.* TO User1;

  1. REVOKE
  • 특정한 데이터베이스 유저에게 부여되어 있던 특정 권한을 박탈하는 명령어
  • 모든 권한을 박탈하려면 권한 자리에 ALL을 입력
REVOKE INSERT ON Company.Employee FROM User1;

-- 모든 권한 박탈하기
REVOKE ALL ON Company.Employee FROM User1;

4) 트랜잭션 제어 언어 (TCL; Transaction Control Language)

Transaction Control Language commands are used to manage transactions in the database. These are used to manage the changes made by DML-statements. It also allows statements to be grouped together into logical transactions.

- GeeksforGeeks (SQL | DDL, DML, TCL and DCL)

트랜잭션 제어 언어란 트랜잭션을 조작하기 위한 명령어들이다.
트랜잭션 제어 언어에는 COMMIT, ROLLBACK, SAVEPOINT가 있다.
트랜잭션 제어 언어를 사용하기 위해서는 먼저 트랜잭션을 시작(START TRANSACTION)해야 한다.

(트랜잭션에 대해 보다 자세한 설명을 원하시면 [DB] 데이터베이스 트랜잭션(Database Transaction) 참고 바랍니다!)

  1. COMMIT
  • 트랜잭션 수행 결과를 확정하기 위한 명령어
START TRANSACTION; -- 트랜잭션 시작
INSERT INTO Employee (id, last_name, first_name, date_of_birth) VALUES (3, 'Blue', 'Coral', DATE_FORMAT(NOW(), '%Y-%m-%d'));
UPDATE Employee SET first_name = 'Mike' WHERE id = 3;

COMMIT; -- 이후 데이터를 조회하면 추가된 데이터를 확인할 수 있다

  1. ROLLBACK
  • 트랜잭션 수행 결과를 취소하기 위한 명령어
  • 트랜잭션이 ROLLBACK으로 끝나면 데이터베이스는 트랜잭션이 시작되기 이전 상태로 되돌아감
START TRANSACTION; -- 트랜잭션 시작
INSERT INTO Employee (id, last_name, first_name, date_of_birth) VALUES (4, 'Red', 'Strong', DATE_FORMAT(NOW(), '%Y-%m-%d'));
UPDATE Employee SET first_name = 'Mike' WHERE id = 4;

ROLLBACK; -- 이후 데이터를 조회 시 트랜잭션 시작 이전 상태로 되돌아간 것을 확인할 수 있다

  1. SAVEPOINT
  • 트랜잭션 수행 결과의 일부는 남겨 두고, 일부는 취소하려는 등의 경우에 사용하는 명령어
  • ROLLBACK TO [SAVEPOINT 명칭] 명령어를 통해서 사용됨
  • SAVEPOINT 이전 지점까지의 트랜잭션 수행 결과는 남기고, 이후의 수행 결과는 ROLLBACK됨
START TRANSACTION; -- 트랜잭션 시작
INSERT INTO Employee (id, last_name, first_name, date_of_birth) VALUES (5, 'America', 'Captain', DATE_FORMAT(NOW(), '%Y-%m-%d'));

SAVEPOINT SVPT1; -- SAVEPOINT 지정

INSERT INTO Employee (id, last_name, first_name, date_of_birth) VALUES (6, 'Beans', 'Chris', DATE_FORMAT(NOW(), '%Y-%m-%d'));

ROLLBACK TO SVPT1; -- 이후 데이터를 조회 시 Captain America는 남아 있고 Chris Beans는 없어진 것을 확인할 수 있다

<참고 자료>

데이터베이스 스키마(Database Schema) feat. 데이터베이스 사상(Database Mapping)

스키마(schema)는 계획이나 도식(圖式)을 가리키는 영어 낱말 ... (중략) ...

데이터베이스 스키마는 자료를 저장하는 구조와 표현법을 정의한 것을 뜻하는 전산학 용어이다. ...(중략)...

스키마(schema, 도식)는 인공지능, 인지과학, 언어학 등에서 공통으로 사용하는 개념으로 지식을 표상하는 구조를 말한다.

- 위키백과 (스키마)


데이터베이스 스키마가 뭐지?

컴퓨터 과학에서 데이터베이스 스키마(database schema)는 데이터베이스에서 자료의 구조, 자료의 표현 방법, 자료 간의 관계를 형식 언어로 정의한 구조이다. 데이터베이스 관리 시스템(DBMS)이 주어진 설정에 따라 데이터베이스 스키마를 생성하며, 데이터베이스 사용자가 자료를 저장, 조회, 삭제, 변경할 때 DBMS는 자신이 생성한 데이터베이스 스키마를 참조하여 명령을 수행한다.

스키마는 3층 구조로 되어있다.

  • 외부 스키마(External Schema) : 프로그래머나 사용자의 입장에서 데이터베이스의 모습으로 조직의 일부분을 정의한 것
  • 개념 스키마(Conceptual Schema) : 모든 응용 시스템과 사용자들이 필요로하는 데이터를 통합한 조직 전체의 데이터베이스 구조를 논리적으로 정의한 것
  • 내부 스키마(Internal Schema) : 전체 데이터베이스의 물리적 저장 형태를 기술하는 것

데이터베이스 스키마란 데이터베이스가 어떤 구조로 구성되어 있는지를 보여주는 것이다. 데이터베이스에 대한 청사진 또는 설계 도면이라고 봐도 좋다.

데이터베이스 스키마는 각기 다른 관점을 지닌 사용자에 따라 아래와 같이 3층 구조로 나누어진다. 이 구조를 ANSI/SPARC 구조라고도 한다.

  • 외부 스키마(=서브 스키마)
  • 개념 스키마
  • 내부 스키마(=저장 스키마)

또한 3개 층으로 나누어진 데이터베이스 스키마들의 상호 변환을 위해 사상(Mapping)이라는 과정이 있다. 이는 데이터의 독립성$^*1$을 실현한다.

*1 데이터의 독립성?
데이터베이스 스키마 한 계층의 변화가 다른 계층의 변화 없이 이루어지는 것을 의미한다.

  • 외부/개념 사상(External / Conceptual Mapping)
  • 개념/내부 사상(Conceptual / Internal Mapping)


데이터베이스 스키마 알아보기

1) 외부 스키마 (External Schema)

  • 응용 프로그래머 및 일반 사용자 관점의 스키마
  • 사용자가 관심 있는 데이터베이스의 일부만 기술하고 나머지는 은폐
  • 하나의 데이터베이스 시스템은 여러 개의 응용 시스템을 지원하기에 여러 개의 외부 스키마가 존재
  • 보통 전체 데이터베이스의 한 논리적 부분이 되기에 '서브 스키마'라고도 함

2) 개념 스키마 (Conceptual Schema)

  • 기관 또는 조직 관점의 스키마
  • 물리적 저장 구조의 세부 사항은 은폐하고, 저장된 데이터의 종류 및 관계 등을 나타냄
  • 모든 응용 프로그램이나 사용자가 필요로 하는 데이터베이스 구조를 전체적이고 종합적인 관점에서 기술하므로 하나만 존재

3) 내부 스키마 (Internal Schema)

  • 시스템 프로그래머 및 시스템 설계자 관점의 스키마
  • 물리적 저장 장치 입장에서 저장 레코드 형식, 인덱스 유무, 저장 필드의 표현 방법, 저장 레코드의 물리적 순서 등 데이터가 실제로 어떻게 저장되는지 나타냄
  • 하나만 존재하며, 개념 스키마에 대한 저장 구조를 정의한 것이므로 '저장 스키마'라고도 함
  • 명칭에 '물리적'이 포함되긴 하나, 그 구조만 나타낼 뿐 실제 물리적 장치에 기록을 하는 단계는 아님

데이터베이스 사상 알아보기

1) 외부/개념 사상 (External / Conceptual Mapping)

  • 특정한 외부 스키마와 개념 스키마 사이의 대응 관계를 정의함
  • 논리적 데이터 독립성 실현
    • 개념 스키마가 달라져도 사상의 변경을 통해 외부 스키마에 영향을 주지 않음
    • ∴ 응용 프로그램 또는 사용자가 보는 뷰(View)의 변경 없이 개념 스키마 변경이 가능

2) 개념/내부 사상 (Conceptual / Internal Mapping)

  • 개념 스키마와 내부 스키마 사이의 대응 관계를 정의함
  • 물리적 데이터 독립성 실현
    • 다른 저장 매체로의 이동이나 파일 구조 변경 등의 물리적 변화에 대해 내부 스키마를 정확하게 변경시키면 개념 스키마에 영향을 미치지 않음
    • ∴ 응용 프로그램에도 영향을 미치지 않음

<참고 자료>

 

+ Recent posts