AI/DL

[책] PyTorch를 활용한 머신러닝/딥러닝 철저 입문

민사민서 2024. 8. 29. 13:29

사실 코드 보면서 무작정 부딪히다보면 익숙해지긴하는데.. 인턴 초기엔 책도 읽어보았숨니다

(사실 torch lightning을 거의 사용하긴 했는데)

 

PyTorch 함수들

텐서 생성

  • torch.from_numpy(ndarray)
    • NumPy 배열을 텐서로 변환한다
  • torch.utils.data.TensorDataset(data_tensor, target_tensor)
    • 설명변수와 목적변수를 합쳐 인덱스 붙이고 하나의 data 집합으로
  • torch.utils.data.DataLoader(dataset, batch_size = 16, shuffle=True)
    • 데이터집합을 원하는 크기의 미니배치로 나누어 읽음

신경망 구성

  • torch.nn.Modules
    • 신경망 모듈 기본 클래스
  • torch.nn.Linear(in, out, bias=True)
    • 입력 데이터에 대한 선형변환 계산 (y = Ax + b)
    • 바이어스 학습 여부?
  • torch.nn.functional.relu(input)
    • ReLU 함수
  • torch.nn.functional.log_softmax(input)
    • log softmax 함수
  • torch.nn.Conv2d(in_channels, out_channels, kernel_size, stride=1, padding=0, bias=True
    • 합성곱층
    • 입력 이미치 채널 수 / 연산 후 채널 수 / 필터(커널) 크기 / stride(기본 1) / 제로패딩 여부(기본은 하지 x) / bias 학습 여부 (기본은 함)
  • torch.nn.Max_Pool2d(kernel_size, stride=None, padding=0)
    • 2차원 최대 풀링 연산, 풀링 영역 크기 / 풀링 stride(기본값은 kernel_size) / 제로패딩 여부 (기본은 하지 x)

모델 학습

  • torch.nn.CrossEntropy
    • 교차 엔트로피 함수를 구현한 클래스
  • torch.optim.SGD(params, lr=<object object>)
    • 확률적 경사하강법 구현한 클래스, 학습률 설정 가능
  • torch.autograd.Variable(data)
    • 텐서를 래핑, 계산과정 기록
  • torch.autograd.backward(variables)
    • 경사의 합을 구함
  • torch.optim.Adam(params, lr=0.001)
    • ADAM 적용, 최적화 대상이 될 파라미터 그룹 / 학습

 

05. 신경망 실전 활용

퍼셉트론 알고리즘: 선형 분리 불가능

  • 활성화함수로 step function 사용

신경망: 퍼셉트론을 여러개 조합, 비선형적인 문제 풀 수 있음

  • (중간층) 활성화함수로 시그모이드 함수, ReLU함수, 쌍곡선함수
  • (출력층) 분류 문제면 소프트맥스 함수, 회귀 문제면 항등함수

입력층부터 출력층까지 순서대로 전달된다 = FP = Forward Propagation

신경망 모형 학습

  • 분류 문제: 교차 엔트로피 / 회귀 문제: 제곱 오차
  • 경사하강법(GD) 사용
    • 배치학습 (가중치 업데이트 시 모든 데이터 사용)
    • 미니배치학습 (일부 배치만 사용, 국소최적해 빠지는 것 방지)
  • 확률적 경사하강법 (SGD, 미니배치학습)

출력층에서 입력층으로 오차 거슬러 올라가며 전달 = BP = 오차 역전파

 

06. 다층 퍼셉트론 실전 활용

DNN(Deep Neural NW) = 심층신경망

  • 중간층을 여러 층으로 늘림
  • 다층 퍼셉트론(Multilayer perceptron, MLP)라고 볼 수 있음
  • 지도 학습 알고리즘 ⇒ 입력 데이터 = 설명변수 + 목적변수

사전학습(pre-training) 거침

  • 학습 이전 단계에 노드 간 연결 가중치 조정
  • 자기부호화기(AutoEncoder, AE) 알고리즘?

자기부호화기 (AE)

  • 입력층과 출력층 노드 수 동일
  • 비지도 학습 ⇒ 입력이 설명변수만으로 구성
  • FP, BP 반복하며 출력값과 입력값 비슷해지도록 (재현되도록) 학습 + 모형 생성
  • AE를 통한 사전학습을 통해 다층 퍼셉트론 한 층씩 쌓아올림

최적화 기법으로 SGD(확률적 경사하강법) 대신

  • Adam 많이 사용 ⇒ 학습 도중 학습률 자동 조정
  • 가중치 감쇠 (가중치 값 발산 방지)
  • 배치 정규화 (각 층 노드 값을 표준화하여 속도 개선)

과적합(overfitting) 주의 ⇒ MLP 층 수 많아지면 지나치게 최적화

  • dropout (각 층의 노드 중 일정 비율 무효화)

뉴스기사 학습시켜 카테고리 분류시킨다면?

일단 문장 형태소분석 후 단어별로 분절해야 함 (불필요한 문자 제거)

추출한 단어 목록을 ‘수치화’ 해야 함

단어-문서 행렬, 어떤 문서에서 사용된 단어의 출현 빈도 수 파악 가능

단어의 출현 빈도값 TF * 역문서 빈도 IDF ⇒ 사용

  • 자주 등장하는 단어는 TF 높을 것
  • 특정 (소수) 문서에만 등장하는 단어일수록 IDF 높을 것
def forward(self, x):
	x = F.relu(self.fc1(x))
	x = self.fc2(x)
	x = F.relu(self.fc3(x))
	x = self.fc4(x)
	return x

 

07. 합성곱 신경망 실전 활용

CNN (합성곱신경망) = MLP 중 이미지 데이터에 특화된 것

입력층 - 중간층 - 출력층

대신 중간층: 합성곱층 + 풀링층 + 전결합층 으로 구성

합성곱층 ⇒ 입력 데이터에 필터 적용해 특징값 추출

풀링층 ⇒ 데이터 다운샘플링, 중요도 높은 특징값만 압축

특징맵 개수(사이즈) 줄어듦 ⇒ 입력 데이터 zero-padding 적용

 

장점?

  1. FP / BP 교대로 반복하면서 신경망 가중치 최적화 = 특징값 역할 대신
  2. 특징점 위치 변동 고려 가능, 합성곱 필터로 추출 + 폴링으로 특징 남김 ⇒ 위치 / 방향 달라도 인식 가능
def forward(self, x):
	x = F.max_pool2d(F.relu(self.conv1(x)), 2)
	x = F.max_pool2d(F.relu(self.conv2(x)), 2)
	x = x.view(-1, 256)
	x = F.relu(self.fc1(x))
	x = self.fc2(x)
	return F.log_softmax(x)

합성곱층 입력 채널 개수 3개(컬러 채널일 경우), 생략되는 위치 없도록 stride는 1로

풀링층 모두 영역 크기 2인 최대 풀링 수행 (중첩되지 않도록)

 

07. Q learning 실전 활용

정답이 있는 데이터 집합을 사용해 모형을 학습시키는 것이 아닌

  • 컴퓨터가 스스로 학습해 모형 구축하는 강화학습 (RL)
  • 딥러닝 적용한 강화학습

Q러닝 = 어떤 환경 내에서 agent가 취하는 행동의 가치(Q값) 학습

장기적 관점에서 큰 보상 얻도록 Q값 수정해 나감

# 신경망 구성
class Net(nn.Module):
	def __init__(self):
		super(Net, self).__init__()
		self.fc1 = nn.Linear(16, 64)
		self.fc2 = nn.Linear(64, 64)
		self.fc3 = nn.Linear(64, 96)
		self.fc4 = nn.Linear(96, 96)
		self.fc5 = nn.Linear(96, 64)
		self.fc6 = nn.Linear(64, 64)
		self.fc7 = nn.Linear(64, 4)
		
	def forward(self, x):
		x = Variable(x)
		x = F.relu(self.fc1(x))
		x = F.relu(self.fc2(x))
		x = F.relu(self.fc3(x))
		x = F.relu(self.fc4(x))
		x = F.relu(self.fc5(x))
		x = F.relu(self.fc6(x))
		x = self.fc7(x)
		return x
		
	# instance 생성
	model = Net()
# one-hot 벡터를 tensor로 변환
def onehot2tensor(state):
	tmp = np.zeros(16)
	tmp[state] = 1
	vector = np.array(tmp, dtype='float32')
	tensor = torch.from_numpy(vector).float()
	return tensor
	
# 모형에 입력
def applymodel(tensor):
	output_tensor = model(tensor)
	output_array = output_tensor.data.numpy()
	return output_tensor, output_array
# 총 보상
total_reward = 0.0
# 오차함수 객체 생성
criterion = nn.MSELoss()
# 최적화 담당할 객체 생성
optimizer = optim.Adam(model.parameters(), lr=0.01)

# 게임 시작
for i_episode in range(10000):
	# 초기화
	observation = env.reset()
	episode_reward = 0.0
	
	# 오차 누적
	total_loss = 0.0
	
	for t in range(100):
		# 한 턴 실행 후의 위치를 현재 위치로 잡음
		curr_state = observation
		
		# 경사 초기화
		optimizer.zero_grad()
		
		# onehot 벡터를 텐서로 변환
		current_tensor = onehot2tensor(curr_state)
		current_output_tensor, current_output_array = applymodel(current_tensor)
		
		# 행동 선택
		if np.random.rand() < 0.1:
			# 무작위 선택
			action = env.action_space.sample()
		else:
			# Q 값 최대가 되도록
			action = np.argmax(current_output_array)
		
		# 1턴 실행
		observation, reward, done, info = env.step(action)
		
		# onehot 벡터를 텐서로 변환 + 모델 입력
		observation_tensor = onehot2tensor(observation)
		observation_output_tensor, observation_output_array = applymodel(observation_tensor)
		
		# Q값 업데이트
		q = reward + 0.99 * np.max(observation_output_array)
		q_array = np.copy(current_output_array)
		q_array[action] = q
		q_variable = Variable(torch.Tensor(q_array))
		
		# 오차 계산
		loss = criterion(current_output_tensor, q_variable)
		# 역전파 계산
		loss.backward()
		# 가중치 업데이트
		optimizer.step()
		# 오차 누적 계산
		total_loss += loss.data[0]
		
		if done:
			# 현재 게임 보상 누적 계산
			episode_reward += reward
	
	total_reward += episode_reward
	if (i_episode+1) % 1000 == 0:
		print ~~