본문 바로가기
수업 공유 자료/AI, 딥러닝 주제

유전 알고리즘 4.유전 알고리즘으로 선형회귀 구현하기

by Majestyblue 2024. 1. 30.
# 개체 중 적합도가 가장 작은 2개의 객체 선택하기
def Select_appropriate(list_gen):
  list_appro = Appropriate(list_gen)
  argsort = list_appro.argsort()
  two_genlist = np.array([])
  two_genlist = np.concatenate([two_genlist, list_gen[argsort[0]]], axis=0)
  two_genlist = np.concatenate([two_genlist, list_gen[argsort[1]]], axis=0)
  two_genlist = np.reshape(two_genlist, (-1, 3))
  return two_genlist

print("유전 객체 4개")
print(gen_list)
print("각 적합도 계산")
print(Appropriate(gen_list))
genlist_two_origin = Select_appropriate(gen_list)
print("적합도가 가장 작은 2개 선택")
print(genlist_two_origin)​
# 1세대 유전체 객체 4개 생성
gen_list = np.array([])
for i in range(4):
  value = create_genome()
  gen_list = np.concatenate([gen_list, value], axis=0)

print(gen_list)
gen_list = np.reshape(gen_list, (-1, 3))
print(gen_list)

1. 선형 회귀 구현하기

유전 알고리즘으로 선형 회귀(Linear Regression)을 구현할 수 있을까? 

입력값 (1, 1, 1)에 대한 출력값은 5라고 하자. 입력값은 임의의 어떤 변수가 될 수 있다.

예를 들어 입력값 (집중도, 학습량, 스마트폰 소지 여부)에 성적 (5)의 데이터로 생각해 볼 수 있다. 이러한 상관관계를 설명할 수 있는 모델을 가정해 볼 수 있는데 입력값(x1, x2, x3)에 대한 목표값 y가 있을 때 모델 pred를 아래와 같이 생각해 볼 수 있다.

 

이 때 (w1, w2, b)를 회귀계수라고 한다. 회귀계수를 유전 알고리즘으로 찾아보자.

 

적합도를 목표값(y) - 모델 예측값(pred)의 절대값으로 설정, 적합도에 따라 회귀 계수를 선택하게 만들어 회귀 계수 학습하게 할 수 있다.

 

 

1) 목표 설정

import numpy as np
np.random.seed(220713)

input = np.array([1, 1, 1,])
target = 5

 

 

2) 유전 객체 설정

# 표준편차 sigma, 평균 mu인 정규분포에서 3개를 추출
def create_genome(sigma=2, mu=0):
    value = sigma*np.random.randn(3) + mu
    return value

print(create_genome())

3 이번엔 실수다. 정규분포에서 임의의 수 3개를 선택하자.

 

 

3)1세대 유전자 객체 4개 생성

# 1세대 유전체 객체 4개 생성
gen_list = np.array([])
for i in range(4):
  value = create_genome()
  gen_list = np.concatenate([gen_list, value], axis=0)

print(gen_list)
gen_list = np.reshape(gen_list, (-1, 3))
print(gen_list)

 

 

 

4) 적합도 함수 정의하기

# 적합도 계산
def Appropriate(list_gen):
  appro_list = np.array([])
  for gen in list_gen:
    appro = np.array([np.abs(target - np.sum(input*gen))])
    appro_list = np.concatenate([appro_list, appro], axis=0)
  return appro_list

print(Appropriate(gen_list))

 

5 - 모델 예측은 입력값(x1, x2, x3) × 회귀계수(w1, w2, b)로 계산할 수 있다. 즉, 유전자 값(gen)이 회귀 계수이다.

 

 

5) 객체 4개에 대한 적합도 계산

# 개체 중 적합도가 가장 작은 2개의 객체 선택하기
def Select_appropriate(list_gen):
  list_appro = Appropriate(list_gen)
  argsort = list_appro.argsort()
  two_genlist = np.array([])
  two_genlist = np.concatenate([two_genlist, list_gen[argsort[0]]], axis=0)
  two_genlist = np.concatenate([two_genlist, list_gen[argsort[1]]], axis=0)
  two_genlist = np.reshape(two_genlist, (-1, 3))
  return two_genlist

print("유전 객체 4개")
print(gen_list)
print("각 적합도 계산")
print(Appropriate(gen_list))
genlist_two_origin = Select_appropriate(gen_list)
print("적합도가 가장 작은 2개 선택")
print(genlist_two_origin)

 

 

 

6) 감수 분열을 이용한 교차 구현

# 감수분열은 부모 유전자를 나누고 뒤집은 것으로 하자
# 번식은 부모 유전자에 감수분열된 값을 더한 것으로 한다.
def intersect_genorm(list_gen):
  temp_list = list_gen.copy()
  temp_list = temp_list/2 # 2로 나눔
  temp_list = temp_list[::-1] # 뒤집어줌

  copy_list = list_gen.copy()
  copy_list[0] = copy_list[0] + temp_list[0]
  copy_list[1] = copy_list[1] + temp_list[1]
  return copy_list

print("두번째 자리 교차 전")
print(genlist_two_origin)

intersect_gen = intersect_genorm(genlist_two_origin) # 두 번째 자리 교차
print("두번째 자리 교차 후")
print(intersect_gen)

 

 

 

7) 객체 2+ 객체 2개 구현하기

# 4개의 객체 중 적합도가 가장 작은 유전 객체 2개 + 유전 객체 2개 교차 구현한 것 합치기
def combine_genome(list_1, list_2):
  return np.concatenate((list_1, list_2), axis=0)

combine_gen = combine_genome(genlist_two_origin, intersect_gen)
print("1세대 두번째 자리 교차 전 + 교차 후")
print(combine_gen)

 

 

 

8) 돌연변이 구현하기

# 확률적 돌연변이, 확률에 따라 돌연변이가 발생하도록 한다.
def Mutation(list_gen, prob=1):
  event = np.random.choice((0, 1), p=[1-prob, prob])
  if event == True:
    mutant_list = np.array([])
    for i in range(2):
      value = create_genome()
      mutant_list = np.concatenate([mutant_list, value], axis=0)
    
    mutant_list = np.reshape(mutant_list, (-1, 3))
    return mutant_list
  else:
    return list_gen

print('부모 객체')
print(genlist_two_origin)
print('before Mutation : 정상적인 교차로 인한 자식 생성')
print(intersect_gen)
print('after Mutaion : 자식 생성 중 돌연변이 발생')
print(Mutation(genlist_two_origin))

6-8 : 돌연변이 조건에 해당하면 유전물질을 아예 새로 생성하는 것으로 하자

 

 

 

9) 반복 훈련을 위한 객체 4개 생성하기

# 1세대 유전체 객체 4개 생성
gen_list = np.array([])
for i in range(4):
  value = create_genome()
  gen_list = np.concatenate([gen_list, value], axis=0)

genlist_four = np.reshape(gen_list, (-1, 3))
genlist_two_origin= Select_appropriate(genlist_four)
print('genlist_two_origin')
print( genlist_two_origin)
print('적합도')
print(Appropriate(genlist_two_origin))

 

 

 

10) 반복 훈련하기

epochs = 3000
for epoch in range(epochs):
  # 부모 세대가지 합쳐 4개 중 적합도가 가장 큰 2개 선택
  genlist_two= Select_appropriate(genlist_four)
  # 유전자 교차(자손 번식)
  intersect_gen = intersect_genorm(genlist_two)
  # 돌연변이 진입, 조건이 해당하면 돌연변이 발생
  intersect_gen = Mutation(intersect_gen, prob=0.3)
  # 부모세대와 자식세대를 합쳐 4개로 만듦
  genlist_four = combine_genome(genlist_two, intersect_gen) 

genlist_last_two= Select_appropriate(genlist_four)
print('genlist_last_two')
print(genlist_last_two)
print('적합도')
print(Appropriate(genlist_last_two))