=========== [교재 - CNN] ===========
1. Resnet50
교재 : Resnet은 매우 깊은 neural network에서 발생하는 기울기 소실 문제를 해결하기 위해 Residual connections(skip connections)를 도입한 사전 훈련 모델.
- 수식 : 출력 = F(x) + x.

resnet은 Residual connections(skip connections)를 도입한거라고 했는데 예시 코드에서 어디에 해당하는거야?
🤖 제마나이 대답
# 4. 새로운 모델 구축 - forward 메서드 내부
x = self.base_model(x) # 👈 바로 이 안에서 잔차 연결이 수없이 일어납니다!
# ===================
ResNet50 (self.base_model) 영역: 이 안에는 수많은 합성곱(Convolution) 레이어와
ResNet의 핵심인 '잔차 연결(Skip Connection)' 구조가 복잡하게 들어가 있습니다.
이미지에서 중요한 특징을 뽑아내는 역할을 합니다.
(노션 코드에서는 이 ResNet50의 맨 끝에 있던 원래 출력층 레이어 2개를 잘라내고 가져왔습니다.)
사용자 추가 영역: 그 레고 블록 뒤에 global_avg_pool $\rightarrow$ flatten $\rightarrow$
fc1 $\rightarrow$ relu $\rightarrow$ fc2 $\rightarrow$ softmax를 이어 붙인 것입니다.
# ===================
#파이토치 내부 소스코드 : 잔차 연결(Residual Connection) 구조
# 파이토치 내부 ResNet의 기본 블록 (Bottleneck) 구조 예시
class Bottleneck(nn.Module):
def __init__(self, in_channels, out_channels, stride=1, downsample=None):
super(Bottleneck, self).__init__()
# ... (중간 컨볼루션 레이어 정의 생략) ...
self.downsample = downsample # 차원을 맞춰주기 위한 지름길 레이어
def forward(self, x):
# 1. 오리지널 입력값 x를 'identity'라는 변수에 따로 복사해둡니다. (지름길 준비)
identity = x
# 2. 입력값 x가 본래의 메인 레이어(합성곱층들)를 통과합니다. F(x) 계산 과정
out = self.conv1(x)
out = self.bn1(out)
out = self.relu(out)
out = self.conv2(out)
out = self.bn2(out)
out = self.relu(out)
out = self.conv3(out)
out = self.bn3(out)
# 3. 만약 입력과 출력의 차원(Shape)이 다르다면, 지름길로 가는 x의 차원도 맞춰줍니다.
if self.downsample is not None:
identity = self.downsample(x)
# ⭐️ 4. 핵심: 메인 레이어를 거쳐온 출력(out)에 오리지널 입력값(identity)을 더해줍니다!
# 이론에서 배우신 F(x) + x 가 바로 이 줄입니다.
out += identity
# 5. 더해준 결과를 최종 활성화 함수(ReLU)에 통과시킵니다.
out = self.relu(out)
return out
2. VGG16
🤖 제마나이 대답
# VGG16 내부의 실제 연산 흐름 (예시)
out = self.conv1(x)
out = self.relu1(out)
out = self.conv2(out)
out = self.relu2(out)
out = self.maxpool1(out)
# ... 이 과정을 마지막 16번째 레이어까지 정직하게 일렬로 쭉 반복합니다.
=========== [교재 - NLP] ===========
1. 정규화
교재
- 영어에서 Startupcode, startupcode , STARTUPCODE 는 같은 단어를 가리킬 수 있습니다. 하지만 대소문자가 다르면 모델은 별도의 토큰으로 처리할 수 있습니다.
- 사용이유 : 같은 의미인데 표기만 다른 표현을 하나로 통일하여 동일한 의미를 가진 토큰으로 인식하기 위해
1) 어휘사전 크기 감소, 2) 학습 효율 향상, 3) 검색 품질 개선, 4) 데이터 일관성 확보, 5) 토큰화 안정성 향상
- 사용방법 : 원문확인 -> 통일 기준 결정 -> 대소문자 통일 -> 유니코드 정규화 -> 숫자 치환 -> 공백 정규화 -> 정규화 결과 확인
- 정규화 기법 종류 : 대소문자 통일, 유니코드 정규화, 약어 확장, 숫자치환, 공백 정규화
* 참고1: 정규화는 토큰화 전에 수행한다
* 참고2: NLP에서 정규화란 "텍스트 표현을 표준 형태로 통일"하는 것.
(통계/머신러닝에서 정규화란, "숫자 데이터의 범이를 0~1 등으로 조정하는 것")
2. 문장분리
교재 : <어댑터즈는 스타트업코드에서 제공하는 개발 책 서빙 서비스입니다. 사용자는 교재를 읽고 실습을 진행할 수 있습니다. 관리자는 교재와 수강생 학습 상태를 관리할 수 있습니다.> 라는 문장은 3개로 나눌 수 있다 : 서비스소개 문장 + 사용자 기능 설명 문장 + 관리자 기능 설명 문장
- 사용이유 : 긴 텍스트를 의미 단위인 문장으로나눠, 모델이 더 명확하게 의미를 처리할 수 있도록 하기 위해
1)의미 단위 구분, 2) 입력 길이 관리, 3) 분석 정확도 향상, 4) 후속 전처리 준비, 5) 서비스 기능 연결
- 사용방법: 원문 입력 -> 문장 경계 기준 확인 -> 규칙 기반 분리 또는 라이브러리 활용 -> 분리 결과 확인
- 사용흐름 : 긴 텍스트 입력 -> 문장 끝 구두점 확인 -> 구두점 뒤 공백 기준으로 분리 -> 문장 리스트 생성
- 분리 방법 종류 : 규칙 기반 문장 분리(느낌표, 마침표, 물음표 등) , 라이브러리 기반 문장 분리(NLTK, spaCy, KSS 등)
* 참고1: 마침표가 항상 문장 끝을 의미하진 않는다 (예 Dr. 과 3.14 )
3. 토큰화
교재 : 텍스트 데이터를 의미 있는 단위(단어, 문장, 하위단어(접두사, 어근, 접미사 등) 등)로 분리하여 자연어 처리를 용이하게 하는 과정으로, 토큰화는 자연어 처리 (NLP)에서 필수적인 전처리 과정이다.
- 문장 단위 토큰화 : 텍스트를 문장별로 나누는 과정
- 단어 단위 토큰화 : 텍스트를 공백이나 구두점을 기준으로 개별 단어로 분리하는 과정
- 하위단어 단위 토큰화 : 단어보다 더 작은 단위로 텍스트를 분리하는 과정 --- 희귀 단어, 신조어, 오타와 같은 문제를 해결하기 위해 도입된 방법으로, BPE나 WordPiece 같은 알고리즘에 사용된다.
- 사용이유: 텍스트 데이터를 모델이 처리할 수 있는 최소 단위로 변환하기 위해
1) 데이터 구조화, 2)복잡한 의미 분석, 3)모델 성능 향상, 4)사전 크기 최적화, 5)희귀 단어 및 신조어 처리, 6) 다양한 언어적 패턴 대응, 7) 핵심 전처리 과정, 8) 의미적 일관성 유지
4. 원-핫 인코딩
교재 : 범주형 값을 "해당 범주 위치만 1이고 나머지는 0"인 고정 길이 벡터로 표현하는 인코딩 방식으로, 각 토큰이 서로 독립적이라는 점(순서, 크기의미가 없음)과, 값이 어떤 토큰인지가 벡터 내 위치로 명확히 드러난다는 점이 핵심이다. 다만, 벡터 길이가 어휘 크기와 같으므로 어휘가 커질수록 벡터도 커진다는 단점이 있다.
{"<PAD>": 0, "<UNK>": 1, "어댑터즈는": 2, "스타트업코드에서": 3, "제공하는": 4,
"개발": 5, "책": 6, "서빙": 7, "서비스입니다": 8}
에서
"어댑터즈는" (ID: 2) → [0, 0, 1, 0, 0, 0, 0, 0, 0]
"스타트업코드에서" (ID: 3) → [0, 0, 0, 1, 0, 0, 0, 0, 0]
"개발" (ID: 5) → [0, 0, 0, 0, 0, 1, 0, 0, 0]
- 사용이유 : 범주형 값을 순서나 크기 의미 없이 모델이 계산할 수 있는 숫자 벡터로 표현하기 위해
- 사용방법: 정수 인코딩된 토큰의 ID를 인덱스로 사용하여, 어휘 크기만큼의 벡터에서 해당 인덱스만 1로 켜고 나머지는 0으로 채우는 것.
- 예시코드:
import numpy as np
# ── 1) 어휘 사전 (이전 단계에서 구축) ──
token2id = {
"<PAD>": 0, "<UNK>": 1,
"어댑터즈는": 2, "스타트업코드에서": 3, "제공하는": 4,
"개발": 5, "책": 6, "서빙": 7, "서비스입니다": 8,
"startupcode": 9, "is": 10, "a": 11, "company": 12
}
id2token = {i: t for t, i in token2id.items()}
vocab_size = len(token2id)
print(f"어휘 크기(vocab_size): {vocab_size}")
# 예상 출력:
# 어휘 크기(vocab_size): 13
# ── 2) 원-핫 인코딩 함수 ──
def one_hot_encode(token_ids, vocab_size):
"""정수 ID 리스트를 원-핫 행렬로 변환합니다."""
one_hot_matrix = np.zeros((len(token_ids), vocab_size), dtype=int)
for i, token_id in enumerate(token_ids):
one_hot_matrix[i][token_id] = 1
return one_hot_matrix
# ── 3) 한국어 문장 원-핫 인코딩 ──
# 원문: "어댑터즈는 스타트업코드에서 제공하는 개발 책 서빙 서비스입니다."
# 전처리 후 토큰: 마침표 제거
kor_tokens = ["어댑터즈는", "스타트업코드에서", "제공하는", "개발", "책", "서빙", "서비스입니다"]
kor_ids = [token2id[t] for t in kor_tokens]
print(f"\n한국어 토큰: {kor_tokens}")
print(f"정수 인코딩: {kor_ids}")
# 예상 출력:
# 한국어 토큰: ['어댑터즈는', '스타트업코드에서', '제공하는', '개발', '책', '서빙', '서비스입니다']
# 정수 인코딩: [2, 3, 4, 5, 6, 7, 8]
kor_one_hot = one_hot_encode(kor_ids, vocab_size)
print(f"\n원-핫 행렬 형태: {kor_one_hot.shape}")
# 예상 출력:
# 원-핫 행렬 형태: (7, 13)
print("\n각 토큰의 원-핫 벡터:")
for token, vec in zip(kor_tokens, kor_one_hot):
print(f" {token:12s} → {vec.tolist()}")
# 예상 출력:
# 각 토큰의 원-핫 벡터:
# 어댑터즈는 → [0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
# 스타트업코드에서 → [0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0]
# 제공하는 → [0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0]
# 개발 → [0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0]
# 책 → [0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0]
# 서빙 → [0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0]
# 서비스입니다 → [0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0]
# ── 4) 영어 문장 원-핫 인코딩 ──
# 원문: "Startupcode is a company."
# 전처리 후 토큰: 마침표 제거
eng_tokens = ["startupcode", "is", "a", "company"]
eng_ids = [token2id[t] for t in eng_tokens]
print(f"\n영어 토큰: {eng_tokens}")
print(f"정수 인코딩: {eng_ids}")
# 예상 출력:
# 영어 토큰: ['startupcode', 'is', 'a', 'company']
# 정수 인코딩: [9, 10, 11, 12]
eng_one_hot = one_hot_encode(eng_ids, vocab_size)
print(f"\n원-핫 행렬 형태: {eng_one_hot.shape}")
# 예상 출력:
# 원-핫 행렬 형태: (4, 13)
print("\n각 토큰의 원-핫 벡터:")
for token, vec in zip(eng_tokens, eng_one_hot):
print(f" {token:12s} → {vec.tolist()}")
# 예상 출력:
# 각 토큰의 원-핫 벡터:
# startupcode → [0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0]
# is → [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0]
# a → [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0]
# company → [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]
# ── 5) 희소성 확인 ──
total_elements = kor_one_hot.size
non_zero = np.count_nonzero(kor_one_hot)
sparsity = (1 - non_zero / total_elements) * 100
print(f"\n── 희소성(Sparsity) 분석 ──")
print(f"전체 원소 수: {total_elements}")
print(f"0이 아닌 원소 수: {non_zero}")
print(f"희소율: {sparsity:.1f}%")
# 예상 출력:
# ── 희소성(Sparsity) 분석 ──
# 전체 원소 수: 91
# 0이 아닌 원소 수: 7
# 희소율: 92.3%
* 참고1: 원-핫인코딩처럼 벡터의 대부분이 0인 표현을 "희소 표현"이라고 한다. --- 희소 표현은 토큰 간의 의미적 유사도를 표현하기 어렵.
반대로, WORD2Vec이나 BERT의 임베딩처럼 벡터의 대부분 차원에 실수 값이 채워진 표현을 "밀집 표현"이라고 한다.
* 참고2: NLP 파이프라인에서는 1) 택스트 --(정수 인코딩)--> 2) 정수 시퀀스 --(원핫인코딩)--> 3) 원핫벡터 --(임베딩)--> 밀집 벡터 로 변환된다.
실제 딥러닝 모델(파이토치의 nn.Embedding)에서는 2단계와 3단계를 하나로 합쳐 정수 ID를 입력받아 곧바로 밀젭 벡터로 변환한다.
5. 단어 임베딩 (워드 임베딩)
교재 : 단어를 고정 차원의 실수 벡터로 변환하여, 단어 간의 의미적 유사성과 사용 맥락의 유사성을 반영하는 표현 방식이다. 이 벡터 표현은 단어 간의 "의미적 관계와 통계적 유사성"을 반영하여, 각 단어는 고정된 크기의 실수 벡터로 변환된다. 단어 임베딩은 원핫인코딩 방식과 달리, 단어들 간의 의미적 거리와 방향을 벡터 공간에서 표현할 수 있기 때문에 단어 간의 유사성을 더 잘 포착할 수 있다. (예 "king"과 "queen", "apple"과 "fruit" 같은 단어들이 서로 의미적으로 가까운 관계를 가지고 있다)
- 주요 단어 : 단어벡터, 차원, 임베딩 행렬, 문맥적 유사성
- 사용이유: 단어의 의미적 유사성을 반영하는 저차원 밀집 벡터로 변환해 더 나은 분석을 위해서
- 예시:
### “컴퓨터가 자연어(텍스트)를 입력받아 딥러닝 연산을 거쳐 최종 판단을 내리기까지의 전체 파이프라인(흐름)을 보여주는 최소 단위의 예제”
# 고정 예시 문장
KOR = "어댑터즈는 스타트업코드에서 제공하는 개발 책 서빙 서비스입니다."
ENG = "Startupcode is a company."
토큰화를 진행하면
# 예상 출력:
# [[ 1 2 3 4 5 6 7]
# [ 8 9 10 11 0 0 0]]
# 각 문장은 숫자 시퀀스로 변환되었으며, 길이가 다른 시퀀스는 가장 긴 문장 길이에 맞춰 뒤를 0으로 채워 동일한 길이로 맞췄습니다.
파이토치의 임베딩 레이어 사용
모델 학습 및 예측 진행
# 결과
# Embedding Output: [[0.5123], [0.4987]]
# 1. 최종 출력값은 각 문장이 '정답 클래스(1)'에 속할 확률(0~1 사이의 값)을 의미합니다.
# - 첫 번째 문장(KOR)이 정답일 확률: 약 51.2%
# - 두 번째 문장(ENG)이 정답일 확률: 약 49.8%
# 2. 단어 임베딩 벡터들이 Flatten(일렬로 펼치기)과 Linear(완전연결층) 레이어를 거치며 연산된 후,
# Sigmoid 활성화 함수를 통해 최종적으로 하나의 확률값으로 압축된 결과입니다.
# 3. 데이터 수가 적고 학습 횟수(10 Epoch)가 짧아 현재 결과는 0.5(반반) 근처의 임의의 값을 나타냅니다.
* 참고1: 단어의 길이가 어떻든 차원이 바뀌지 않는다 - 단어의 길이(글자수)는 임베딩 차원에 영향을 미치지 않는다.
*참고2: 인코딩-단어를 0과1로 이루어진 벡터로 변환하는 과정 / 임베딩-인코딩된 벡터를 실수로 이루어진 밀집 벡터로 변환하는 과정

6. word2vec
교재 : 단어가 함께 등장하는 문맥 패턴을 학습하여, 각 단어를 실수 벡터로 표현한느 단어 임베딩 기법으로, 단어 간의 의미적 관계를 벡터 연산을 통해 반영하는 것이 목표이다. 예를 들어, "king"과 "queen" 같은 단어는 벡터 공간에서 가까운 위치에 있게 되며, "man"과 "woman" 역시 유사한 벡터 관계를 가진다.
- 학습 방법 종류 : skip-gram, CBOW
- 사용이유: 단어 간 의미적 유사성을 반영하기 위해
7. RNN (Recurrent Neural Network)
교재 : 이전 시점의 hidden state를 다음 시점 계산에 다시 사용하며 순차 데이터를 처리하는 순환구조의 인공 신경망


- w: 가중치(weight)로, 입력과 이전 상태가 얼마나 반영될지를 결정하는 학습 가능한 파라미터
- 𝓧: 입력 값(input) 또는 입력 벡터
- t: 시간(time) 또는 시점(time step)을 나타내는 인덱스
- x_t: 현재 시점의 입력 벡터
- h_{t-1}: 이전 시점의 hidden state
- h_t: 현재 시점의 hidden state
- W_h, W_x: 학습 가능한 가중치 행렬
- f: 활성화 함수
- 사용이유: 이전 시점의 정보를 현재 계산에 반영해 순차 데이터의 시간적 패턴과 종속성을 학습하기 위해 사용
1) 기억능력, 2)시퀀스 데이터 처리, 3) 시간적 패턴 학습, 4) 연속적인 데이터, 5)종속성 모델링, 6) 다양한 응용 분야
* 참고1: rnn의 가장 큰 단점은 "기울기 소실(vanishing gradient)이다.
-- 시퀀스 길이가 길어지거나 반복 계산이 많은 시간 단계로 전개될수록 두드러진다.
-- 원인 : rnn의 학습 과정에서 역전파를 통해 기울기가 전파되는데, 각 시점에서 기울기를 계산할 때 기울기가 연속적으로 작어지거나 커질 수 있다. 특히 시퀀스가 길어질수록 기울기가 지수적으로 감소하는 경향이 있어, 초기 단계의 정보가 뒤로 갈수록 거의 무시가 된다.
* 참고2: RNN의 시초는 SRN(simple recurrent network)
* 참고3: 순환연결이 가능한 이유는 가중치를 공유하기 때문이다
* 참고4: 가중치 행렬 -- 다차원 입력을 새로운 표현 공간으로 선형 변형하여, 모델이 데이터의 복잡한 패턴을 학습할 수 있도록 하기 위해 사용하며, 가중치 행렬의 초깃값은 보통 난수로 설정한다. 가중치 행렬은 모든 시점에서 공유된다.
1) W_x (입력 가중치) -- 현재 입력 반영 : 현재 시점에 새로 들어온 정보를 얼마나 어떤 방식으로 반영할지 결정
2) W_h (순환 가중치) -- 이전 기억 이어받기 : 이전 시점까지 축적된 문맥 정볼르 얼마나 어떤 방식으로 유지할지 결정
3) W_y (출력 가중치) -- 현재 기억으로 출력 만들기
- 사용방법: 입력벡터에 가중치 행렬을 곱하고, 편향을 더한 뒤 활성화 함수를 적용하여 변환된 벡터를 생성.

* 참고5: 그레디언트 폭발 -- 역전파 과정에서 기울기 값이 반복적으로 곱해지면서 급격히 커지는 현상으로, 기울기 값이 과도하게 커지면서 가중치가 한 번에 과도하게 변경되어 학습이 불안정해진다. (파라미터값이 매우 큰 수로 발산하거나, 손실값이 값자기 NaN이 되는 경우가 생긴다. -- 이런 문제를 완화하기 위해 기울기 클리핑(gradient clipping)을 사용하여 일정 범위를 넘는 기울기를 강제로 제한한다.
장기의존성 문제랑 기울기 소실이 뭐가 다른거야? 같은거 아냐?
🤖 제마나이 대답
장기 의존성 문제 (Long-Term Dependency) | 기울기 소실 (Vanishing Gradient)
오래전(멀리 떨어진) 입력 정보를 현재 예측에 반영하지 못하는 현상 | 역전파 과정에서 앞쪽 레이어로 갈수록 미분값(기울기)이 0에 가깝게 작아지는 수학적 원인
"시퀀스 데이터(텍스트, 시계열)가 가진 구조적 한계"| 인공신경망의 학습 메커니즘에서 발생하는 연산의 문제
현상을 지칭, 문제가 있다는게 아님 | 원인
==> """기울기 소실 때문에 오래전 정보를 기억 못 하는 장기 의존성 문제가 발생했다.""",
8. LSTM(Long Short-Term Memory)
교재 : 장기의존성을 안정적으로 학습하도록 설계된 순환 신경망으로, cell state와 게이트를 사용해 중요한 정보는 유지하고 덜 중요한 정보는 줄이면서 시간 축을 따라 정볼르 더 안정적으로 전달한다. RNN이 hidden state 하나만으로 정보를 전달하는 것과 달리 LSTM은 별도의 cell state를 유지하여 정보가 시간에 따라 사라지지 않도록 설계되어있다.


- W: 가중치(weight), 학습 가능한 파라미터
- σ: 시그모이드 함수 (0~1 사이 값 출력)
- t: 시간(time step)
- xₜ: 현재 시점의 입력 벡터
- hₜ₋₁: 이전 시점의 hidden state
- cₜ₋₁: 이전 시점의 cell state
- fₜ: forget gate (이전 정보를 얼마나 유지할지 결정)
- iₜ: input gate (새로운 정보를 얼마나 저장할지 결정)
- oₜ: output gate (얼마나 외부로 출력할지 결정)
- cₜ: 현재 시점의 cell state (장기 메모리)
- hₜ: 현재 시점의 hidden state
- ⊙는 원소별 곱(element-wise multiplication)
- +는 이전 기억과 새로운 후보 정보를 더해 셀 상태를 갱신하는 연산
- 위 수평선은 장기 메모리 통로
- LSTM 동작 개념 : 1) 이전 정보를 얼마나 잊을지 (forget gate), 2) 새로운 정보를 얼마나 저장할지 (input gate), 3) 현재 상태를 얼마나 출력할지 (output gate) 이 3가지를 선택하는 구조이다.
1. 정규화
교재 :
resnet은 Residual connections를 도입한거라고 했는데 예시 코드에서 어디에 해당하는거야?
🤖 제마나이 대답
'카테부 4기 판교 ai 실무 > 수업내용 & 과제' 카테고리의 다른 글
| [6주차 과제] #1 ai hub 와 코랩, 그리고 ngrok (0) | 2026.06.21 |
|---|---|
| 0513 ~ 0516 키워드 (0) | 2026.05.19 |
| 0518 정규수업2 (0) | 2026.05.18 |
| 0514 심화수업1 (0) | 2026.05.16 |
| 0513 정규수업1 (0) | 2026.05.16 |