유전 알고리즘 예제 | 01-3 Dimensionality Reduction – Genetic Algorithm 최근 답변 186개

당신은 주제를 찾고 있습니까 “유전 알고리즘 예제 – 01-3 Dimensionality Reduction – Genetic Algorithm“? 다음 카테고리의 웹사이트 https://you.charoenmotorcycles.com 에서 귀하의 모든 질문에 답변해 드립니다: https://you.charoenmotorcycles.com/blog. 바로 아래에서 답을 찾을 수 있습니다. 작성자 고려대학교 산업경영공학부 DSBA 연구실 이(가) 작성한 기사에는 조회수 2,246회 및 좋아요 32개 개의 좋아요가 있습니다.

Table of Contents

유전 알고리즘 예제 주제에 대한 동영상 보기

여기에서 이 주제에 대한 비디오를 시청하십시오. 주의 깊게 살펴보고 읽고 있는 내용에 대한 피드백을 제공하세요!

d여기에서 01-3 Dimensionality Reduction – Genetic Algorithm – 유전 알고리즘 예제 주제에 대한 세부정보를 참조하세요

고려대학교 일반대학원 산업경영공학과
비즈니스 애널리틱스
1장: Dimensionality Reduction
Part 3: 변수 선택 기법: 유전 알고리즘
https://github.com/pilsung-kang/Business-Analytics-IME654-

유전 알고리즘 예제 주제에 대한 자세한 내용은 여기를 참조하세요.

basic genetic algorithm / 유전 알고리즘 입문 (예제) – Medium

유전 알고리즘은 개체들이 모인 집단에서 시작합니다. 각 개체(노드)는 1과 0에 의한 바이너리 형태(무조건은 아니지만 바이너리로 표현되는 것이 …

+ 자세한 내용은 여기를 클릭하십시오

Source: medium.com

Date Published: 11/3/2021

View: 479

[ Genetic Algorithm ] 유전 알고리즘을 통해 비밀번호를 뚫어보자!

그렇다면 파이썬으로 유전 알고리즘을 구현해보자. 함수가 많아서 함수 하나하나씩 잘라서 설명을 해보려고 한다. 우선 비밀번호는 문자열을 사용하고 …

+ 여기에 표시

Source: tasddc.tistory.com

Date Published: 4/14/2022

View: 8107

[최적화/전역 최적화] 유전 알고리즘 (Genetic Algorithm)

유전 알고리즘에서 가장 많이 이용되는 방법은 어떠한 규칙도 없이 단순히 임의의 값으로 염색체를 생성하는 것이다. 예를 들어, 자바로 작성된 [코드 1] …

+ 여기에 더 보기

Source: untitledtblog.tistory.com

Date Published: 7/1/2022

View: 9570

유전 알고리즘(Generic Algorithm in Python) 파이썬으로 풀기

1. 정의. 유전 알고리즘(Genetic Algorithm)은 자연세계의 진화과정에 기초한 계산모델로, 존 홀랜드(John Holland)에 …

+ 여기에 표시

Source: koreapy.tistory.com

Date Published: 3/5/2021

View: 2024

유전 알고리즘 – GIL’s LAB

유전 알고리즘은 자연계의 진화 체계를 모방한 메타휴리스틱 알고리즘으로 … 최적화 문제를 소개하는 과정에서 나왔던 예제를 유전 알고리즘을 통해 …

+ 자세한 내용은 여기를 클릭하십시오

Source: gils-lab.tistory.com

Date Published: 9/19/2022

View: 1154

유전 알고리즘 가지고 놀기 – Blog4Study

예제 링크: https://github.com/Kcrong/Simple-Genetic-Algorithm. 유전 알고리즘이란,. “유전 알고리즘(Genetic Algorithm)은 자연세계의 진화과정에 …

+ 자세한 내용은 여기를 클릭하십시오

Source: blog.devkcr.org

Date Published: 5/30/2021

View: 355

유전 알고리즘 (Genetic Algorithm) – 네이버 블로그

유전 알고리즘 (Genetic Algorithm) … 0. 유전 알고리즘이란? 생물학적 진화에 바탕을 둔 통계적 탐색 알고리즘 집합이다. 쉽게 말하면 그냥 유전을 …

+ 여기에 더 보기

Source: m.blog.naver.com

Date Published: 5/4/2021

View: 551

유전자 알고리즘 실습 – 날도의 잡다한 기술 블로그

유전 알고리즘은 생물체가 환경에 적응하며 진화하는 모습을 모방하여, … 이번엔 비교적 간단한 예제를 파이썬으로 실습을 진행할 계획이다.

+ 여기에 더 보기

Source: naldo627.github.io

Date Published: 6/17/2022

View: 9893

유전 알고리즘 (Genetic algorithm) – BioinformaticsAndMe

유전 알고리즘(GA)은 존 홀랜드(John Holland)가 다윈 진화론의 적자생존에 기반하여 개발한 최적화 연산 방법(1975).

+ 자세한 내용은 여기를 클릭하십시오

Source: bioinformaticsandme.tistory.com

Date Published: 1/16/2022

View: 9871

Matlab을 이용한 유전 알고리즘(Genetic Algorithm) 예제

지난 포스트에서는 유전 알고리즘이 어떤 의미를 가지며, 어떤 연산으로 이루어지는지에 대해 알아보았다. 이번 포스트에서는 지난 번에 다루었던 …

+ 자세한 내용은 여기를 클릭하십시오

Source: synapticlab.co.kr

Date Published: 6/2/2022

View: 8318

주제와 관련된 이미지 유전 알고리즘 예제

주제와 관련된 더 많은 사진을 참조하십시오 01-3 Dimensionality Reduction – Genetic Algorithm. 댓글에서 더 많은 관련 이미지를 보거나 필요한 경우 더 많은 관련 기사를 볼 수 있습니다.

01-3 Dimensionality Reduction - Genetic Algorithm
01-3 Dimensionality Reduction – Genetic Algorithm

주제에 대한 기사 평가 유전 알고리즘 예제

  • Author: 고려대학교 산업경영공학부 DSBA 연구실
  • Views: 조회수 2,246회
  • Likes: 좋아요 32개
  • Date Published: 2020. 9. 3.
  • Video Url link: https://www.youtube.com/watch?v=yUW8yg4_j6w

[ Genetic Algorithm ] 유전 알고리즘을 통해 비밀번호를 뚫어보자!

이번 포스팅에서는 유전 알고리즘을 통해 비밀번호를 찾는 알고리즘이다.

그전에 유전 알고리즘에 대해서 간략하게 설명을 하자면 다음과 같다.

말 그대로 유전 즉, 세대가 존재한다는 뜻이다. 이게 무슨 뜻이냐…

우선 랜덤으로 최초의 아이들을 생성한다.

그리고 그 생성된 아이들을 가지고 fitness (성능)을 측정한다.

성능을 측정할 때 적절한 점수를 부여하여 만약 점수가 높다면 해당 아이들을 선발해 낸다.

그리고 선발된 아이들을 교배하여 다음 세대를 만들어낸다.

그 과정에서 돌연변이도 추가하여 다음 세대를 만들어 내고 또 태어난 자식들을 가지고 성능을 측정하여

위의 과정을 계속 반복하여 수 세대를 걸쳐서 답을 도출해 내는 것이 유전 알고리즘이다.

그렇다면 파이썬으로 유전 알고리즘을 구현해보자.

함수가 많아서 함수 하나하나씩 잘라서 설명을 해보려고 한다.

우선 비밀번호는 문자열을 사용하고 길이가 최소 2 ~ 최대 10 정도로 적당하게 설정한다.

그리고 랜덤으로 아스키코드의 문자와 숫자를 생성해야 하기 때문에 random과 string을 import 한다.

전역 최적화] 유전 알고리즘 (Genetic Algorithm)

1. 소개

유전 알고리즘은 생물체가 환경에 적응하면서 진화해가는 모습을 모방하여 최적해를 찾아내는 검색 방법이다. 유전 알고리즘은 이론적으로 전역 최적점을 찾을 수 있으며, 수학적으로 명확하게 정의되지 않은 문제에도 적용할 수 있기 때문에 매우 유용하게 이용된다. 일반적으로 유전 알고리즘에 대해 알고리즘이라는 표현을 이용하지만, 유전 알고리즘은 특정한 문제를 풀기 위한 알고리즘이라기 보다는 최적화 문제를 풀기 위한 방법론에 가깝다. 즉, 모든 문제에 적용 가능한 하나의 알고리즘이나 소스 코드가 있는 것이 아니기 때문에 유전 알고리즘의 원리를 이해하고, 이를 자신이 원하는 문제에 적용할 수 있도록 하는 것이 중요하다. 유전 알고리즘을 정의하기 위해 아래와 같은 개념들을 정의한다.

염색체 (chromosome) : 생물학적으로는 유전 물질을 담고 있는 하나의 집합을 의미하며, 유전 알고리즘에는 하나의 해 (solution)를 표현한다. 어떠한 문제의 해를 염색체로 인코딩 (encoding)하는 것에 대한 예시는 [5. 예제] 항목에서 자세하게 서술한다.

유전자 (gene) : 염색체를 구성하는 요소로써, 하나의 유전 정보를 나타낸다. 어떠한 염색체가 [A B C]라면, 이 염색체에는 각각 A, B 그리고 C의 값을 갖는 3개의 gene이 존재한다.

자손 (offspring) : 특정 시간 $t$에 존재했던 염색체들로부터 생성된 염색체를 $t$에 존재했던 염색체들의 자손이라고 한다. 자손은 이전 세대와 비슷한 유전 정보를 갖는다.

적합도 (fitness) : 어떠한 염색체가 갖고 있는 고유값으로써, 해당 문제에 대해 염색체가 표현하는 해가 얼마나 적합한지를 나타낸다. 적합도에 대한 예시는 [5. 예제] 항목에서 자세하게 서술한다.

2. 알고리즘 구조

유전 알고리즘은 $t$에 존재하는 염색체들의 집합으로부터 적합도가 가장 좋은 염색체를 선택하고, 선택된 해의 방향으로 검색을 반복하면서 최적해를 찾아가는 구조로 동작한다. 유전 알고리즘의 동작을 단계별로 표현하면 아래와 같다.

1) 초기 염색체의 집합 생성

2) 초기 염색체들에 대한 적합도 계산

3) 현재 염색체들로부터 자손들을 생성

4) 생성된 자손들의 적합도 계산

5) 종료 조건 판별

6-1) 종료 조건이 거짓인 경우, (3)으로 이동하여 반복

6-2) 종료 조건이 참인 경우, 알고리즘을 종료

유전 알고리즘의 구조는 매우 간단하다. 그러나 (3)의 자손들을 생성하는 단계에서 알고리즘의 성능을 향상시키기 위한 몇가지 기법들이 적용되기 때문에 다음 항목에서 이러한 기법들에 설명한다.

3. 연산 정의

유전 알고리즘을 어떠한 문제에 적용하기 위해서는 총 5개의 아래와 같은 연산을 정의해야 한다.

초기 염색체를 생성하는 연산

적합도를 계산하는 연산

적합도를 기준으로 염색체를 선택하는 연산

선택된 염색체들로부터 자손을 생성하는 연산

돌연변이 (mutation) 연산

각각의 연산에 대해서는 아래에 자세히 설명한다. 그러나 아래의 설명은 유전 알고리즘에서 일반적으로 이용되는 하나의 예시일뿐이며, 필요에 따라서는 해결하고자 하는 문제에 맞는 연산으로 대체할 수 있다.

3.1. 초기 염색체 생성 연산

초기에는 이전 염색체가 존재하지 않기 때문에 선택된 염색체들로부터 자손을 생성할 수가 없다. 따라서, 초기 염색체를 생성하는 연산을 별도로 정의해야 한다. 유전 알고리즘에서 가장 많이 이용되는 방법은 어떠한 규칙도 없이 단순히 임의의 값으로 염색체를 생성하는 것이다. 예를 들어, 자바로 작성된 [코드 1]과 같은 소스 코드는 유전 알고리즘의 초기 염색체 생성 연산으로 이용될 수 있다.

1 2 3 4 5 6 Random rand = new Random (); int [] chromosome = new int [SIZE_CHROMOSOME]; for ( int i = 0 ; i < SIZE_CHROMOSOME; i + + ) { chromosome[i] = rand.nextInt(MAX_VAL_GENE); } Colored by Color Scripter cs [코드 1] 초기 염색체 생성 연산의 예시. [코드 1]에서는 어떠한 염색체에 단순히 [0, MAX_VAL_GENE) 사이의 값을 임의로 할당하고 있다. 3.2. 적합도를 계산하는 연산 염색체에 표현된 정보를 기반으로 적합도를 계산하는 연산이다. 이 연산은 해결하고자 하는 문제에 매우 종속적이므로, 다음의 [5. 예제]에서 자세하게 설명한다. 3.3. 적합도를 기준으로 염색체를 선택하는 연산 자손을 생성하기 위한 두 개의 부모 염색체를 선택할 때는 단순히 적합도가 가장 높은 두 개의 염색체를 선택할 수도 있다. 그러나 이러한 방법은 염색체의 다양성을 크게 훼손시키기 때문에 전역 최적해를 찾기에는 부적합하다. 이러한 문제점을 해결하기 위해 유전 알고리즘에서는 일반적으로 룰렛 휠 선택 (roulette wheel selection) 방법을 이용한다. 룰렛 휠 선택의 개념은 매우 간단하다. 어떠한 염색체를 아래의 [식 1]과 같이 정의된 \(P({Ch}_{i})\)를 바탕으로 확률적으로 선택하는 것이 룰렛 휠 선택이다. [식 1]에서 $N$은 염색체의 수이고, $f$는 염색체의 적합도를 구하는 함수이다. [식 1]로 표현되는 룰렛 휠 선택을 그림으로 표현하면 아래의 [그림 1]과 같다. [그림 1] 룰렛 휠 선택 (Roulette wheel selection)의 개념. 즉, 룰렛 휠 선택은 [식 1]을 이용하여 [그림 1]과 같은 룰렛을 만들고, 만들어진 룰렛을 이용하여 확률적으로 염색체를 선택하는 것이다. 룰렛 휠 선택을 이용하면, 적합도가 높은 염색체가 더 높은 확률로 선택되도록 설정하는 동시에 염색체들의 다양성도 유지할 수 있다. 3.4. 선택된 염색체들로부터 자손을 생성하는 연산 앞에서 설명한 룰렛 휠 선택 방법을 통해 선택된 두개의 부모 염색체들로부터 하나의 자손 염색체를 생성한다. 유전 알고리즘에서는 자손을 생성하는 연산으로 주로 crossover라는 연산을 이용한다. Crossover 연산을 그림으로 표현하면, 아래의 [그림 2]와 같다. [그림 2] Crossover 연산의 동작. Crossover 연산에서 염색체를 분할하는 지점인 division point는 임의로 선택된다. 3.5. 돌연변이 (mutation) 연산 만약, 앞에서 설명한 4-3, 4-4와 같은 연산을 이용해서 검색을 진행하면, 유전 알고리즘은 지역 최적점에 도달하게 될 것이다. 유전 알고리즘에서는 지역 최적점에 빠지는 문제를 해결하기 위해 새롭게 생성된 염색체에 확률적으로 돌연변이가 발생하도록 한다. 일반적으로 0.1%, 0.05% 등의 아주 낮은 확률로 돌연변이가 발생하도록 설정하며, 염색체에서 돌연변이를 발생시키는 연산은 매우 다양하다. 예를 들어, [그림 2]에서 생성된 자손에 대해 아래의 [그림 3]과 같은 두 개의 돌연변이 연산을 정의할 수 있다. [그림 3] 돌연변이 연산에 대한 두 가지 예시. [그림 3-a]는 임의로 하나의 유전자를 선택하여 0이면 1로, 1이면 0으로 값을 바꾸는 돌연변이 연산이다. [그림 3-b]는 두 개의 유전자를 임의로 선택하여 두 유전자의 값을 교환하는 돌연변이 연산이다. 돌연변이 연산에는 이외에도 많은 종류가 있으며, 해결하고자 하는 문제에 맞게 돌연변이 연산을 정의하면 된다. 4. 예제 - 유전 알고리즘과 TSP 이 항목에서는 유전 알고리즘을 이용하여 NP-hard에 속하는 대표적인 문제인 TSP (Travelling Salesman Problem)의 최적해를 구해 본다. TSP를 간단히 정의하면 아래와 같다. 출발점에서 시작하여 모든 노드를 단 한번만 지나 출발점으로 돌아오는 최단 경로를 구하는 문제 노드가 15개만 있다고 해도 TSP의 완벽한 답을 찾기 위해서는 $15!$에 해당하는 약 1조 3000천억개의 경우를 계산해야 한다. 따라서, 현실적으로 TSP의 정확한 답을 찾는 것은 불가능하다. 그러나 유전 알고리즘을 이용한다면, 정확한 답은 아니더라 도 거리가 일정 수준 이하인 최적의 답은 찾을 수 있다. 이 예제에서는 유전 알고리즘을 이용하여 도시의 수가 5개인 TSP의 최적해를 구할 것이다. 각 도시의 이름과 좌표는 아래와 같으며, 출발 도시는 A이다. A (10, 10) B (10, 5) C (14, 5) D (40, 50) E (1, 3) 도시의 좌표 정보를 바탕으로 아래의 [그림 4]와 같은 거리 정보 테이블을 구성할 수 있다. 거리 정보 테이블은 염색체의 적합도를 계산할 때 이용되므로, 메모리상에 보관하는 것이 좋다. [그림 4] 거리 정보 테이블. 그리고 예제의 TSP에 대한 염색체를 아래의 [그림 5]의 좌측과 같이 크기가 4인 배열의 형태로 인코딩할 수 있다 (염색체의 크기가 4라는 것은 유전자가 4개라는 것과 같다). [그림 5]의 우측은 어떠한 염색체 [E C D B]가 의미하는 TSP의 해를 나타낸다. 염색체 [E C D B]는 출발점 A에서 시작하여 E→C→D→B를 거쳐 다시 A로 돌아오는 경로를 의미한다. [그림 5] 예제 문제에 대한 염색체 인코딩 (encoding). 또한, 유전 알고리즘의 인자 (parameter)인 한 세대 당 염색체의 수 (population size)는 4로, 돌연변이 확률은 0.1%, 최대 반복 횟수는 1000, 허용 거리는 125으로 설정했다고 가정한다. 그리고 염색체의 적합도 함수는 아래의 [식 2]와 같이 정의한다. [식 2]에서 $N$은 염색체의 크기이고, $d(A, B)$는 두 도시 $A$와 $B$의 거리를 구하는 함수이다. [식 2]는 A에서 염색체에 나타난 첫 번째 도시로 이동할 때의 거리와 염색체에 나타난 순서대로 도시를 이동할 때의 거리, 그리고 염색체의 마지막에 나타난 도시에서 A로 이동할 때의 거리를 합하여 역수를 취하고 있다. 예를 들어, [그림 5]의 염색체에 대해서는 A→E, E→C, C→D, D→B, B→A, 총 5개의 이동에 대해 거리를 계산하여 합산한다. [식 2]에서 역수의 분자에 1000을 설정하고, 제곱을 하는 것은 어떠한 규칙이 아니라, 단순히 경험론적으로 설정한 것이다. 따라서, 실제 구현에서 [식 2]와 똑같이 적합도 함수를 정의할 필요는 없다. 위에서 설정한 알고리즘의 인자 및 적합도 함수와 염색체에 대해 [항목 3]에서 서술한 대로 유전 알고리즘을 동작하면 다음과 같다. 1) 초기 염색체의 집합 생성 초기 염색체 생성 연산에 의해 생성된 염색체들은 아래의 [그림 6]과 같다. [그림 6] 초기 염색체의 집합. 2) 초기 염색체들에 대한 적합도 계산 [그림 6]의 염색체들에 대한 적합도를 계산하면 아래의 [그림 7]과 같다. [그림 7] 초기 염색체들에 대한 적합도 계산. 3) 현재 염색체들로부터 자손들을 생성 룰렛 휠 선택 방법을 통해 염색체 [B C E D]와 [D E C B]가 선택되었다고 가정하면, crossover 연산을 통해 [그림 8]과 같은 자손이 생성된다. [그림 8] 두 염색체로부터 자손 생성. TSP에서는 도시를 한 번만 경유해야 하기 때문에 첫 번째 부모로부터 B C를 받은 경우, 두 번째 부모 염색체에서 C B를 그대로 가져오는 것이 아니라, 중복되지 않은 도시들을 순서대로 가져온다. 따라서, 자손은 [B C C B]가 아니라, [B C D E]가 된다. Crossover 연산을 통해 성공적으로 자손을 생성하였다면, 확률적으로 새롭게 생성된 자손에 돌연변이를 일으킨다. 유전 알고리즘의 인자를 설정하는 단계에서 돌연변이 확률을 0.1%로 설정하였기 때문에 0.1%의 확률로 새롭게 생성된 자손에 돌연변이가 발생한다. 만약, [그림 8]에서 생성된 자손에 0.1%의 확률로 돌연변이가 발생하였다고 가정하면, [그림 9]와 같은 과정을 통해 새롭게 생성된 자손이 변형된다. 돌연변이 연산은 두 유전자를 임의로 선택하여 교환하는 exchange로 하였다. 따라서, 최종적으로 생성된 자손은 [B E D C]가 된다. [그림 9] 돌연변이 연산. 한 세대 당 염색체의 수를 4로 설정하였기 때문에 [그림 8~9]와 같은 룰렛 휠 선택→crossover→돌연변이의 과정을 3번 더 반복한다. 4) 생성된 자손들의 적합도 계산 앞의 과정을 통해 생성된 4개의 자손에 대해 적합도를 계산하면, 아래의 [그림 10]과 같다. [그림 10] 새롭게 생성된 자손들에 대한 적합도 계산. 5) 종료 조건 판별 최대 반복 횟수가 1000이고, 적합도가 가장 큰 [C B E D] 염색체의 이동 거리는 약 130으로 목표값인 125보다 크기 때문에 종료 조건 판별 연산에서는 거짓이 반환된다. 6-1) 종료 조건이 거짓인 경우, (3)으로 이동하여 반복 종료 조건 판별 연산에서 거짓이 반환되었으므로, "(3) 현재 염색체들로부터 자손들을 생성"으로 돌아가 알고리즘을 반복한다. 참고문헌 [1] E. H. L. Aarts, A. H. Eiben, and K. M. Van Hee. 1989. A general theory of genetic algorithms, In Computing Science Notes,. Eindhoven University of Technology. [2] Sangit Chatterjee, Cecilia Carrera, Lucy A. Lynch. 1996. Genetic algorithms and traveling salesman problems. European Journal of Operational Research, Vol. 93, Issue 3, pp. 490-510. [3] Sadiq M. Sait and Habib Youssef. 2000. Iterative Computer Algorithms with Applications in Engineering. Published by the IEEE Computer Society, pp. 109-173.

유전 알고리즘(Generic Algorithm in Python) 파이썬으로 풀기

https://ko.wikipedia.org/wiki/%EC%9C%A0%EC%A0%84_%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98

1. 정의

유전 알고리즘(Genetic Algorithm)은 자연세계의 진화과정에 기초한 계산모델로, 존 홀랜드(John Holland)에 의해서 1975년에 개발된 전역 최적화기법으로, 최적화 문제를 해결하는 기법의 하나이다.

생물의 진화를 모방한 진화 연산의 대표적인 기법으로, 실제 진화의 과정에서 많은 부분을 차용(채용)하였으며, 변이(돌연변이), 교배 연산 등이 존재한다.

또한 세대, 인구등의 용어도 문제풀이 과정에서 사용된다.

2. 개요

유전 알고리즘은 자연계의 생물 유전학에 기본이론을 두며, 병렬적이고 전역적인 탐색알고리즘으로서, 다윈의 적자생존 이론을 기본 개념으로 한다.

유전 알고리즘은

1) 풀고자 하는 문제에 대한 가능한 해들을 정해진 형태의 자료구조로 표현한 다음,

2) 이들을 점차적으로 변형함으로써 점점 더 좋은 해들을 만들어 낸다.

3) 여기에서 해들을 나타내는 자료구조는 유전자,

4) 이들을 변형함으로써 점점 더 좋은 해를 만들어 내는 과정은 진화로 표현할 수 있다.

달리 표현하면, 유전 알고리즘은 어떤 미지의 함수 Y = f(x)를 최적화하는 해 x를 찾기 위해, 진화를 모방한(Simulated evolution) 탐색 알고리즘이라고 말할 수 있다.

유전 알고리즘은 특정한 문제를 풀기 위한 알고리즘이라기 보다는 문제를 풀기 위한 접근방법에 가까우며, 유전 알고리즘에서 사용할 수 있는 형식으로 바꾸어 표현할 수 있는 모든 문제에 대해서 적용할 수 있다.

일반적으로 문제가 계산 불가능할 정도로 지나치게 복잡할 경우 유전 알고리즘을 통하여, 실제 최적해를 구하지는 못하더라도 최적해에 가까운 답을 얻기 위한 방안으로써 접근할 수 있다.

이 경우 해당 문제를 푸는 데 최적화되어 있는 알고리즘보다 좋은 성능을 보여주지는 못하지만, 대부분 받아들일 수 있는 수준의 해를 보여줄 수 있다.

이러한 생물의 진화 과정, 즉 자연 선택과 유전 법칙 등을 모방한 알고리즘들로 진화 전략(Evolutionary strategies), 유전 프로그래밍(Genetic programming) 등 여러 형태의 이론과 기법들이 최근에 활발히 연구되고 있다.

유전 알고리즘은 이 중에서 가장 기본이 되고 대표적인 알고리즘으로, 자연과학/공학 및 인문 사회 과학 분야에서 비선형 또는 계산 불가능한 복잡한 문제를 해결하는 데 널리 응용되고 있다.

3. 요구 조건

유전 알고리즘을 어떤 문제에 적용하기 위해서는 해를 유전자의 형식으로 표현할 수 있어야 하며, 이 해가 얼마나 적합한지를 적합도 함수를 통해 계산할 수 있어야 한다.

일반 생명체의 특성이 유전체의 집합인 유전자로 나타나는 것과 같이, 유전 알고리즘에서는 해의 특성을 숫자의 배열이나 문자열과 같은 자료 구조를 통해서 표시 하게 된다.

적합도 함수는 이렇게 나타내어진 해가 얼마나 문제의 답으로 적합한지를 평가하기 위한 함수이다.

이는 실세계의 생명체가 유전적 특성에 따라 환경에 얼마나 잘 적응할 수 있는지가 결정되는 것과 비교할 수 있다.

4. 흐름

어떤 문제에 대해 유전자 형식이 정의되었다면, 어떤 해들의 유전자들을 서로 조합함으로써 기존의 해로부터 새로운 해를 만들어낼 수 있다.

이런 조합 연산은 교배(Crossover)에 비유할 수 있다.

우수한 해들을 선택하여 이들을 교배하면, 만들어진 해는 우수한 해들이 가지는 특성을 물려받을 가능성이 높게 된다.

우수한 해의 선택에는 앞에서 정의한 적합도 함수를 이용할 수 있으며, 적합도가 높은 해가 선택될 확률을 높게 만들면, 보다 나은 유전자를 가진 해가 다음 세대에 자신의 유전자를 넘겨줄 확률이 높게 되고, 따라서 다음 세대의 해들은 최적해에 점차 가까워지게 된다.

또 비록 교배를 통해 후손을 남기지 못하더라도, 변이를 통해 새로운 유전자를 형성하여 다음 세대로 넘겨주도록 할 수 있으며, 이는 지역 최적점에 빠지지 않도록 하는 주요한 기법이다.

해들을 교배하기 위해서는 아담과 하와처럼 초기 해의 집단이 필요하다.

초기해 집단은 단지 이후의 해를 구하는 데 있어 필요한 초기 개체로서의 역할만을 위한 것이므로, 우수한 해들로 이루어질 필요는 없다. 일반적으로는 유전자를 랜덤하게 생성하여 초기화해 ‘초기해’ 집단을 구성한다.

초기해 집단이 구성되면, 이들 내부의 해의 교배를 통해 다음 세대의 해의 집합을 생성하게 되며, 이를 세대를 거듭하면서 반복해 가면, 해들은 점점 정답에 가까워지게 된다.

유전 알고리즘이 전역 최적해를 구하려면, 많은 인구를 유지하면서 많은 세대를 내려갈 필요가 있다.

따라서, 대부분의 경우는 세대가 일정 수준 진행되었거나, 해가 특정 범위에 들게되면 알고리즘을 종료하게 된다.

5. 연산

유전 알고리즘은

1) 선택,

2) 교차,

3) 변이,

4) 대치 등 몇가지 주요 연산으로 구성된다.

6. 선택

한 세대에서 다음 세대로 전해지는 해의 후보가 되는 해들을 선택한다.

선택 방법에는

1) 균등 비례 룰렛 휠 선택,

2) 토너먼트 선택,

3) 순위 기반 선택 등이 있다.

해의 선택은 유전 알고리즘의 성능에 큰 영향을 미친다. 어떤 방법을 쓰느냐에 따라 최적해로 다가가는 속도가 더디게 되거나, 아니면 지역 최적해에 빠지는 경우가 생길 수도 있기 때문이다.

또는 우수한 해가 보유한 나쁜 인자가 전체 인구에 퍼지거나, 반대로 나쁜 해가 보유한 우수한 인자가 영구히 사장될 수도 있다.

따라서 어떤 해를 선택하는지는 유전 알고리즘의 성능을 위해서 중요한 요소라고 할 수 있다.

일반적으로는 가장 좋은 해의 순으로 선택될 확률을 높게 부여하는 방법이 많이 사용된다.

이는 반대로 말하면, 나쁜 해라 할지라도 그 해에 포함된 좋은 인자를 퍼뜨릴 기회를 준다고 볼 수 있다. 현 세대에서 가장 좋은 해라 할지라도 실제로는 지역 최적해에 가까운 해일 수도 있고, 반대로 좋지 않은 해라 할지라도 전역 최적해에는 더 가까울 수도 있기 때문이다.

실제로 전역 최적해가 어디에 있는지는 알 수 없는 일이므로, 가능한 해들의 평균적인 적합도를 높여 가면서도 유전자의 다양성을 유지하는 것이 지역 최적해에 빠지는 것을 가능한 한가지 방지하는 방법이며, 이는 실세계의 생명체들 역시 유전적 다양성을 유지하는 종이 장기적인 생존 가능성이 높은 것과 비견할 수 있다.

7. 교차

생명체는 세대 내에서의 교배를 통해 다음 세대를 생성한다.

이와 마찬가지로 유전 알고리즘에서 자연 선택된 해들은 교배를 통하여 다음 세대의 해들을 생성하게 된다. 일반적으로 두 개의 해를 선택한 후 둘 간에 교배 연산을 수행하게 되며, 이를 통해 생성된 해는 각각의 부모 해의 교차 연산을 통해서 서로 겹치지 않는 위치의 유전인자를 받아 새로운 유전자를 구성하게 된다.

실제 생명체의 염색체가 재조합되는 과정에서 부모 염색체의 일부분이 특정 위치를 기준으로 서로 바뀌어 결합되는 경우가 있는데, 이 현상을 교차라고 한다.

유전 알고리즘의 교차 연산은 이 현상을 본따, 부모 해의 유전자들을 서로 교차시켜서 자식해를 만들어낸다.

교차 연산의 실제 수행 방법은 비트 단위 교차에서부터 블록 단위 교차까지 다양한 방법으로 구현할 수 있으며, 교차를 한 번만 수행할지 전 영역에 대해서 교차시킬지 역시 결정할 수 있다.

또한 모든 해에 대해 교차연산을 수행할 경우 우수한 해가 다른 해와의 교배를 통해서 우수성을 잃어버림에 따라 세대의 최고 우수해가 보존되지 않는 상황이 발생할 수 있다. 이런 경우를 방지하기 위하여 교차를 확률적으로 수행하여 우수한 해가 변형되지 않고 그대로 다음 세대에 전해질 확률을 부여하는 방법도 사용된다.

8. 변이

일반 생명체에서, 유전자의 교배 뿐 아니라, 하나의 유전자가 직접적으로 변이를 일으켜서 주어진 환경에서 살아남을 확률 역시 존재한다.

변이 연산은 주어진 해의 유전자 내의 유전 인자의 순서 혹은 값이 임의로 변경되어 다른 해로 변형되는 연산이다.

해의 유전자들을 가상의 공간에 맵핑할 경우 교배 연산은 부모해들 사이의 어떤 지점에 자식해를 생성하는 것이라고 볼 수 있다면, 변이 연산은 임의의 위치로 점프하는 것에 비견할 수 있다.

따라서 약간의 확률로 변이 연산을 수행시켜 주는 것은 전체 세대가 함께 지역 최적해에 빠져드는 경우를 방지하기 위한 주요한 기법이 될 수 있으며, 해집단의 다양성을 높여준다.

9. 대치

교차·변이 등을 거쳐서 만들어진 새로운 해를 해집단에 추가하고, 기존 해 중 열등한 해를 가려내서 제외시키는 연산이다.

가장 품질이 나쁜 해를 대치하는 방법, 새로운 해의 부모해 중에서 새로운 해와 가장 비슷한 해를 대치시키는 방법(해집단의 다양성을 유지하기 위함) 등이 있다.

예)

{1, 5, 6, 8, 3, 7, 3, 5, 9, 0} 중 3개를 골라서 20으로 만드는 문제가 있다고 하자. 여기서 유전체는 각 숫자이며, 각 해의 유전자는 (1,5,3)와 같이 유전체 3개의 집합으로 이루어진다. 적합도 함수를 20과 얼마나 가까운지를 나타내는 값으로 둔다면, (1,5,3)에 대한 적합도는 f( (1,5,3) ) = 11이 된다.

먼저 첫 세대를 아무렇게나 생성한다. 첫 세대가 만약 { (1,5,3) (8,0,9) (9,9,8) (3,7,5) } 으로 형성되었다고 하자. 각각의 적합도를 구하면, { 11, 3, 6, 5 }이 되며, 이 값이 높을수록 20에서 멀기 때문에 해로서 부적당하다는 것을 의미하며, 따라서 세대를 거침에 따라 살아남을 확률이 낮게 된다.

다음 세대를 형성하기 위해, 이 세대의 개체중 2개의 유전자를 선택한다. 이때 선택은 적합도를 기준으로 확률적으로 선택한다. (룰렛 알고리즘이 자주 쓰인다) 위의 예에서 적합도가 3인 (8,0,9)는 적합도가 6인 (9,9,8)에 비해 훨씬 높은 선택 기회를 가진다. 선택된 2개의 유전자의 유전체는 랜덤한 위치에서 교환되어 새로운 세대가 형성된다. 예로 (8,0,9), (9,9,8) 이 선택되었고 교배위치가 첫번째 자리로 무작위로 결정되었다면 다음 세대의 개체는 (8,9,8), (9,0,9)가 되며, 각각의 적합도는 5, 2가 된다.

10. 관련 기법

11. 참고 문헌

12. 관련 논문

Differential Gene Set Enrichment Analysis: A statistical approach to quantify the relative en- richment of two gene sets

https://github.com/Kcrong/Simple-Genetic-Algorithm

원문

https://blog.devkcr.org/entry/%EC%9C%A0%EC%A0%84-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EA%B0%80%EC%A7%80%EA%B3%A0-%EB%86%80%EA%B8%B0

예제 링크: https://github.com/Kcrong/Simple-Genetic-Algorithm

유전 알고리즘이란,

“유전 알고리즘(Genetic Algorithm)은 자연세계의 진화과정에 기초한 계산 모델로서 존 홀랜드(John Holland)에 의해서 1975년에 개발된 전역 최적화 기법으로, 최적화 문제를 해결하는 기법의 하나이다. 생물의 진화를 모방한 진화 연산의 대표적인 기법으로, 실제 진화의 과정에서 많은 부분을 차용하였으며, 변이(돌연변이), 교배 연산 등이 존재한다. 또한 세대, 인구 등의 용어도 문제 풀이 과정에서 사용된다.” – 위키피디아

유전 알고리즘은 부모의 유전 정보들이 자식들에게 골고루 분포 됨으로써, 문제에 대한 해를 찾아가는 알고리즘이다.

자식 해는 부모 해와 비슷한 형질을 가지며, 우월한 유전자들은 다시 자식해를 만들며 우수 유전자를 널리 퍼트리는 특징이 있다.

소스 설명 전, 사용할 용어에 대한 설명은 아래와 같다.

1. 유전자

예시 소스에서는 integer list 로 정의했다. 하지만 그 형태와 값의 크기는 무엇이든지 될 수 있으며, 제한이 없다. (구현이 어려울 뿐..)

2. 세대

유전자들의 생성과 소멸을 아우르는 하나의 주기를 말한다.

보통 생성 > 번식 > 소멸 의 주기를 가진다.

3. 적합도 (Fitness)

유전자가 얼마나 우월한지 보여주는 지수.

이 지수가 높을 수록 우월한 유전자임을 뜻한다.

전체적인 알고리즘은 3가지로 이루어져있다.

1. 부모 유전자 선택

2. 번식

3. 돌연변이

부모 유전자 선택

부모 유전자를 선택하는 부분에서는, 룰렛 휠 선택 방식을 이용했다.

1

2

3 # 부모를 select_list를 이용해 정함.

# 부모로 선출될 확률은 fitness 과 비례한다.

parents = tuple(self.select_list[rand( 0 , len (self.select_list))] for i in range ( 2 )) cs

룰렛 휠 방식

이미지 출처: http://blog.secmem.org/category/IT%20%EB%86%80%EC%9D%B4%ED%84%B0/Elite%20Member%20Tech%20%26%20Talk?page=37

룰렛 휠 방식이란, 적합도가 높을수록 부모 해로 선택될 확률이 높아지도록 하는 방식이다.

위 그림처럼, 적합도가 100인 C는 룰렛에서 보듯이 선택될 확률이 높다.

하지만 적합도가 40인 D는 C와 달리 선택될 확률이 적다.

이처럼 우월한 유전자를 가질 수록 부모 해로 선택될 확률을 높이는 것을 룰렛 휠 방식이라고 한다.

번식 (교차)

자식 유전자를 만들 때는, 2점 교차 라는 방식을 이용했다.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25 # 각 교차 포인트를 정한다.

# rand 함수의 반환이 float 형이므로, 소수점을 버리기 위해 int() 형변한을 해준다.

switch_point = (rand( 1 , gene_len / / 2 ), rand(gene_len / / 2 , gene_len))

# 처음 자식이 받는 유전자는 parent1

# 다만 교차 포인트에 다다르면, 다른 parent 유전자 정보를 받아오기 시작한다. (parent = parent2)

parent = parents[ 0 ]

for i in range (gene_len):

# 자식 유전자 정보는 부모 유전자에서 받아온다

gene_data.append(parent.gene_data[i])

if i in switch_point:

# 유전자를 받아오는 부모 변경

try :

parent = parents[parents.index(parent) + 1 ]

except IndexError:

parent = parents[ 0 ]

“” ”

a = parents.index(parent) –> 현재 부모의 index 값

parents[a+1] –> 부모 리스트에서, 현재 부모 인덱스값보다 +1 된 값 가져옴

IndexError –> 만약 1이 넘어가면

parent = parents[0] 다시 0으로 돌아옴

” “”

Colored by Color Scripter cs

2점 교차는 두 점을 임의로 선택하여, 그 점을 기준으로 각 부모 유전자에서 번갈아 유전자를 받아오는 방법이다.

물론 점의 위치에 따라 부모1과 부모2의 유전 정보 비율은 달라질 수 있지만 교차의 경우 섞이는 복잡도를 정하는 단계이므로 신경쓰지 않는다.

–> Mutation (돌연변이)

1

2

3

4 # 돌연변이 확률은 fitness 와 반비례 한다.

# fitness 가 높을 수록, 돌연변이 확률이 적어진다.

if rand( 0 , self.fitness * 100 ) = = 0 :

return DNA([rand(min(WE_WANT), max(WE_WANT)) for i in range ( len (WE_WANT))]) cs

돌연변이 확률은 적합도와 반비례 하도록 구현했으며, 돌연변이는 기존 부모와 상관없는 전혀 새로운 유전자를 갖는다.

돌연변이는 그 확률 설정에 따라 다른 결과가 나온다. 자세한 내용은 아래 결과 분석에서 살펴보자.

결과분석

우선 목표값을

0 과 1로 이루어진 8자리 list 로 잡았다.

결과는 다음 이미지와 같다. X축이 세대, Y축이 적합도 수치를 나타낸다.

[그림1] 목표 값 [0,1,0,1,0,1,0,1]

목표값이 단순한 관계로 얼마 지나지 않아, 40번째 세대 쯤에서 최대 적합도에 수렴하는 것을 볼 수 있다.

목표값을 조금 복잡하게 해보자.

0~9의 값을 가지도록 조정해봤다.

[그림2] 목표 값 [3,1,2,9,7,4,3,6]

조금 더 흥미로운 결과가 나왔다.

목표 값의 범위를 늘리자 최대 적합도에 도달하는 세대가 늘어난 것이다.

위 1차 결과와는 달리 80 ~ 100 번째 세대에서 최대 적합도에 가까이 수렴하는 결과가 나왔다.

조금 더 복잡하게 해보자. 이번엔 목표 값의 길이를 바꿔볼 것이다.

[그림3-1] 목표 값 [3,1,2,9,7,4,3,6,5,2,6,9]

100 세대로는 최대 적합도에 도달하기에 한참 부족한 듯 싶다. 진화 횟수를 조금 늘려보았다.

[그림3-2] 목표 값 [3,1,2,9,7,4,3,6,5,2,6,9] _진화 횟수 증가

비록 최대 적합도에는 도달하지 못했지만, 근사한 값을 얻었다.

그럼 보다 더 최대 적합도에 가까운 값을 얻기 위해서는 어떻게 해보는 것이 좋을까?

돌연변이의 확률을 늘리고, 세대에서 가장 좋은 유전자 (Fitness 수치가 가장 높은) 1개를 다음 세대에도 보존 시켜보았다.

[그림3-3] 목표 값 [3,1,2,9,7,4,3,6,5,2,6,9] _진화 횟수 증가 _돌연변이 확률 증가, 우월 유전자 보존

최대 적합도에 도달하는데 성공했다!!!

하지만 필요 세대가 너무 많다는 문제점이 있다…

또한 돌연변이 확률을 늘렸더니 중간중간 생기는 뾰족한 부분 (내려오는 부분)이 늘어났다.

위 문제 를 조금 개선시켜보자.

우월한 유전자를 자식 세대에 포함시키는 과정에서, 1개가 아닌 5개를 포함시켜보았다.

[그림3-4] 목표 값 [3,1,2,9,7,4,3,6,5,2,6,9] _진화 횟수 증가 _돌연변이 확률 증가, 우월 유전자 보존 _보존 유전자 갯수 증가

약 1100 – 850 = 250 세대가 감소했다!!~!

우월 유전자의 보존 비율 조금 더 늘려보자.

이번엔 5개 대신 10개를 포함시켜 보았다.

더욱 개선된 결과가 나오리라 생각했다.

[그림3-5] 목표 값 [3,1,2,9,7,4,3,6,5,2,6,9] _진화 횟수 증가 _돌연변이 확률 증가, 우월 유전자 보존 _보존 유전자 갯수 증가 _ 10개 보존

예상과는 달리, 이전 결과 보다 더욱 못한 결과가 나왔다.

이유를 살펴보았더니, 우월 유전자의 보존 비율이 증가하면 우월 유전자에 가까운 자식 유전자들이 많이 생기지만,

우월 유전자의 잘못된 부분도 같이 유지되는 문제가 있었다.

우월 유전자의 보존 비율이 높다고 진화의 방향이 좋은 것은 아니라는 것이다.

이번 실험 결과 중, 우리의 실생활과 매우 흡사한 부분이 아닐까 싶다. 🙂

P.s

질문이나 기타 문제점은 GitHub 이슈로 달아주세요

풀리퀘 받는 것도 좋아합니다.

출처: https://blog.devkcr.org/entry/유전-알고리즘-가지고-놀기 [Blog4Study]

유전 알고리즘

728×90

개요

유전 알고리즘은 자연계의 진화 체계를 모방한 메타휴리스틱 알고리즘으로 복잡한 최적화 문제를 푸는데 사용된다.

스케줄링 등 복잡한 최적화 문제를 해결하는데 활용되고 있고, 딥러닝의 초기 웨이트 설정, 특징 선택 등 머신러닝 문제를 해결하는데도 많이 사용된다.

필자의 주력 연구 방법론중 하나이며, 지금도 유전 알고리즘을 이용한 쉐이플릿 탐색이라는 주제로 연구를 진행하고 있다.

그러면 이제 유전 알고리즘이 어떻게 작동하는지, 또 파이썬으로 어떻게 구현할 수 있는지를 소개하자.

가능하면 비전공자의 입장에서 친절히 설명하고자 한다.

최적화 문제란?

최적화 문제는 제약 하에서 목적식을 최소화 혹은 최대화하는 결정 변수의 값을 찾는 문제이다.

제약이란 것은 해가 만족해야 하는 조건이고, 목적식은 최소화 혹은 최대화해야 하는 대상이며, 결정 변수는 값을 찾아야 하는 변수이다.

위키피디아에서 소개하고 있는 간단한 예제를 보자 (참고로 선형 계획법은 최적화 문제의 대표적인 유형이다).

홍길동 씨가 두 가지 종류의 빵을 판매하는데, 초코빵을 만들기 위해서는 밀가루 100g과 초콜릿 10g이 필요하고 밀빵을 만들기 위해서는 밀가루 50g이 필요하다. 재료비를 제하고 초코빵을 팔면 100원이 남고 밀빵를 팔면 40원이 남는다. 오늘 홍길동 씨는 밀가루 3000g과 초콜릿 100g을 재료로 갖고 있다. 만든 빵을 전부 팔 수 있고 더 이상 재료 공급을 받지 않는다고 가정한다면, 홍길동 씨는 이익을 극대화 하기 위해서 어떤 종류의 빵을 얼마나 만들어야 하는지 다음과 같이 선형 계획법을 이용하여 계산할 수 있다.

여기서 x1과 x2가 결정변수이다.

저 문제는 100×1 + 50×2 <= 3000, 10x1 <= 100, x1, x2 >=0을 만족하는 x1과 x2가운데, 100×1 + 40×2를 최대화하는 x1과 x2를 찾아라 라고 해석할 수 있다.

이 정도의 문제는 매우 간단하기 때문에 사실 유전 알고리즘을 사용할 필요가 없다.

여기서 간단하다는 것은 저 문제의 최적해(=정답)를 구하는 과정이 공식처럼 정의되어 있다는 것이다.

그런데 현실 문제는 저 정도로 간단하지 않은 것이 보통이다.

휴리스틱과 메타휴리스틱

이제 휴리스틱이라는 단어가 무엇인지 이해해보자.

위키피디아에서는 휴리스틱을 아래와 같이 정의하고 있다.

휴리스틱(heuristics) 또는 발견법(發見法)이란 불충분한 시간이나 정보로 인하여 합리적인 판단을 할 수 없거나, 체계적이면서 합리적인 판단이 굳이 필요하지 않은 상황에서 사람들이 빠르게 사용할 수 있게 보다 용이하게 구성된 간편추론의 방법이다.

어렵게 정의하고 있지만, 휴리스틱은 결국 그럴싸하게 대충 푸는 방법이라고 볼 수 있다.

외판원 문제 (traveling sales problem)을 예로 들어보자.

이 문제는 택배 기사가 현 위치에서 어느 순서대로 택배를 배달해야 최소한의 거리로 움직일 수 있는지를 찾는 문제로, 대표적인 NP 문제 (일단은 풀기 어려운 문제라고 이해하고 넘어가자)이다.

이 문제의 가장 직관적인 해법은 지금 있는 곳에서 가장 가까운 곳부터 배달을 가는 것이다 (즉 그리디하게 탐색하는 것)

시작점이 택배회사였다면, 택배회사에서 가장 가까운 A를 가고, 또 A에서는 A에서 가장 가까운 B를 가는 것이다.

그럴싸하지 않은가? 우리도 여러 군데를 들려야 하는 상황이라면, 가장 가까운 곳 먼저 들리는 경우가 많기 때문에, 그럴싸하고 합리적인 것처럼 보인다. 물론, 이 접근으로 찾은 답은 정답이 아닐 가능성이 훨씬 높다.

이처럼 문제를 알려진 공식으로 풀 수 없는 경우에 그럴싸하게 대충 푸는 접근을 휴리스틱이라고 할 수 있다.

그런데 휴리스틱은 문제마다 문제 상황에 맞는 경험이나 직관을 이용해야 하는 어려움이 있다.

그러니까 위에서 예를 들었던 그리디 서치는 외판원 문제에는 적용할 수 있을지 몰라도, 다른 문제에는 적용할 수 없다.

그래서 등장한 것이 메타 휴리스틱이고, 유전 알고리즘도 메타 휴리스틱에 속한다.

메타 휴리스틱은 휴리스틱이긴한데, 그 풀이 과정 등이 구조적으로 잘 정의되어 있어 대부분의 문제에 어려움없이 적용할 수 있는 휴리스틱을 말한다.

유전 알고리즘의 개념 이해하기

유전 알고리즘은 기본적으로 여러 개의 해로 구성된 해 집단을 만들고 평가한 뒤, 좋은 해를 선별해서 새로운 해 집단을 만드는 메타휴리스틱 알고리즘이다.

유전 알고리즘의 구성 등을 살펴보기 전에 작동 과정에 대해 개략적으로 이해하고 시작하자.

아래와 같이 함수 f(x)가 있고, x에 따른 f(x)의 최소값을 찾는 문제가 있다고 하자.

설명을 위해, 이 함수를 산이라고 하고, 해를 토끼, 그리고 산의 낮은 곳일수록 더 좋은 곳이라고 하자.

유전 알고리즘은 여러 토끼를 만들고, 좋은 환경에 우연히 있던 토끼들만 살아남아서 비슷한 위치에 자식을 만드는 과정을 통해, 가장 낮은 곳, 즉 최적값을 찾게 된다.

육안으로 어느 x가 가장 좋은지 알 수 있지만, 실제 문제에서는 저 그래프를 그리는 것 자체가 불가능한 경우가 대부분이다.

배우신 분들(?)은 미분을 하면 되지 않느냐라고 주장할 수도 있겠지만, 미분 자체가 불가능한 경우도 역시 매우 흔하다.

정답이 모두 정수여야 하는 정수 계획법 문제의 경우에는 어느 경우에서도 미분이 불가능할 것이다.

다시 설명으로 돌아와서 아래와 같이 5마리의 주황색 토끼를 만들어 임의로 배치한다.

우연히 4번과 5번 있던 토끼는 좋은 환경에 있었고, 1, 2, 3번은 그렇지 못하다.

즉, 4번과 5번이 적자이고, 나머지는 적자가 아니다.

이제 적자라서 살아남은 4번과 5번이 자식 a, b, c를 만든다.

자식들은 파란색으로 표시했다.

이제 다시 살펴보니, 부모보다 좋은 위치에 있는 자식 b와 c도 있고, 부모랑 비슷하거나 더 나쁜 위치에 있는 a도 생겼다.

그럼 이제 가장 적합한 b와 c가 살아남아 또 대를 이어 나갈 것이다.

그러다보면 언젠가는 최저점에 있는 토끼를 만나게 될테고, 다시말해 최적해를 구할 것이다.

주요 용어를 거의 사용하지 않고 설명한 내용이지만, 여기서 유전 알고리즘에 관한 몇 가지 인사이트를 얻을 수 있다.

(1) 해를 많이 만들면, 더 좋은 해를 찾을 가능성이 높다. 물론 시간은 더 소요될 것이다.

(2) 너무 잘난 해라면, 세대가 지나도 계속 세대를 구성하는 일원으로 남아있다.

(3) 다음 세대에서 자식을 만드는 부모의 수가 많을수록, 더 많은 해를 탐색할 수는 없다. 그렇지만 더 안정적일 것이다.

(4) 처음에 해들이 한 곳에 몰려있었다면 (특히, 1, 2번 위치), 세대를 거듭해도 좋은 해를 못 찾을 수도 있다.

유전 알고리즘 순서도

이제 본격적으로 유전 알고리즘에 대해 알아보자.

유전 알고리즘은 아래 그림과 같이 초기 해 생성, 적합도 평가, 교차 연산, 돌연변이 연산을 반복한다.

파라미터 정의

단계에는 포함하지 않았지만, 유전 알고리즘을 사용하려면 아래 내용을 미리 결정해야 한다.

해 표현 방법

최대 세대 수

종료 조건

세대 별 포함되는 해의 개수

교차 연산자

돌연변이 연산자

교차 비율

적합도 함수

돌연변이 비율 등

초기 해 생성

첫 번째 단계에서는 초기 해, 즉 첫 번째 세대의 해들을 생성한다.

이 과정에서는 보통 임의로 해를 생성하는데, 문제에 따라서 특정 조건에 맞는 해를 만들도록 설계하는 것이 유리하기도 하다. 그리고 여기서 가장 중요한 것은 해를 어떻게 표현할 것인가이다. 이를 줄여서 해 표현이라 하는데, 해 표현을 어떻게 하느냐에 따라서 문제 풀이가 쉬울 수도 있고 그렇지 않을 수도 있다. 유전 알고리즘을 많이 사용해본 사람과 그렇지 않은 사람의 차이가 사실 여기서 판가름난다.

가장 흔히 사용되는 해 구조는 다음과 같은 이진 벡터이다.

이진 벡터가 많이 사용되는 이유는 뒤에서 설명할 교차 연산이나 돌연변이 연산이 편리하기 때문이다.

외판원 문제처럼 순서를 결정하는 경우라면 이진 벡터보다는 각 위치가 도달한 장소의 인덱스를 나타내는 벡터로 표현하는 것이 적합할 수도 있다.

적합도 평가 및 해 선택

이 단계에서는 현재 세대에 있는 모든 해들을 적합도 함수라는 것을 이용하여 평가한다.

적합도는 보통 최적화 문제의 목적식을 그대로 사용하는 것이 일반적이다.

가령, 외판원 문제에서는 해의 적합도가 전체 이동 거리에 반비례할테고, 최대화 문제라면 해의 적합도가 목적식에 비례할 것이다.

적합도 평가 결과를 토대로 그 다음 세대를 만들 해들을 결정한다.

즉, 교차연산과 돌연변이 연산을 적합도가 우수한 해들에 적용하여 다음 세대에 속할 해를 만든다.

여기서 적합도가 높은 상위 N1개의 해를 선택하여 N2개의 해를 만드는 방식으로 다음 세대를 구성할 수도 있고 (세대별 해의 개수 (N) = N1 + N2), 혹은 적합도에 비례하게 해를 확률적으로 선택하여 해를 생성할 수도 있다.

전자의 경우에는 이전 세대의 해가 다음 세대로 그대로 넘어가고, 좋은 해들만 선별되므로 안정적이라는 장점이 있으나, 지역 최적에 빠질 위험이 있다.

후자의 경우에는 반대로 세대가 거듭될수록 이전에 고려하지 않았던 새로운 종류의 해를 탐색할 수 있으므로, 더 좋은 해를 찾을 수도 있지만, 수렴하지 못할 가능성이 크다.

교차 연산

교차 연산은 두 개의 부모 해를 바탕으로 자식 해를 만드는 연산을 말한다.

즉, 부모가 결합하여 자식을 낳는 과정을 모방한 것이 바로 교차 연산이다.

당연히 교차 연산을 해서 나온 해는 부모를 닮게 된다.

대표적인 교차 연산자로는 한 점 교차 연산자, 두 점 교차 연산자 등이 있다.

이들 교차 연산자는 교차 지점을 임의로 설정한 뒤, 교차 지점 앞쪽에서는 부모 1의 유전자를, 뒤쪽에서는 부모 2의 유전자를 가져와 새로운 자식을 만든다.

아래 그림에서 빨간색 해와 파란색 해가 교차되면서, 앞쪽이 빨갛고 뒤쪽이 파란 해와 앞쪽이 파랗고 뒤쪽이 빨간 해가 생성되었다.

한 점 교차 연산자 두 점 교차 연산자

돌연변이 연산

돌연변이 연산은 만들어진 자식 해를 일부 수정하는 것이다.

즉, 두 부모가 교차를 하더라도, 두 부모와는 완전히 일치하지 않는 그런 특성을 만들기 위한 연산이다.

세대를 거듭할수록 다양한 해를 찾지 않고 특정한 해로 빠르게 수렴하는 것을 막기 위한 연산이다.

아래와 같은 함수가 있고, 해가 주황색으로 표시된 상황을 보자.

여기서 저 네 개의 해를 바탕으로 교차 연산을 계속해서 진행하면 왼쪽 지역 최적에 빠져버리게 될 위험이 있다.

그런데 돌연변이 연산을 해주게 되면, 아예 엉뚱한 위치에 해를 만들기도 하므로, 우연히 좋은 해를 찾을 가능성이 높아지는 것이다.

다시 한 번 강조하지만, 돌연변이 연산을 한다고 해서 무조건 좋은 해를 찾을 수 있는 것은 아니다.

오히려 전역 최적에 가까워지다가 돌연변이 연산 때문에 전역 최적과 멀어지기도 한다.

대표적인 돌연변이 연산 방법으로는 flip-bit 변이 연산이 있다.

임의로 돌연변이를 할 자식을 선택하고, 자식의 유전 개체 (참고: 해를 유전자라하며, 해의 구성 요소 (즉 벡터의 구성 요소)를 유전 개체라 함)를 임의로 선택하여, 0이면 1로, 1이면 0으로 바꾸는 간단한 연산이다.

파이썬을 이용한 예제 풀이

최적화 문제를 소개하는 과정에서 나왔던 예제를 유전 알고리즘을 통해 풀어보자.

이 문제에서는 x1과 x2를 찾아야 한다.

해 구조는 다음과 같은 2 x 5 크기의 이진 행렬을 사용한다.

첫 번째 행은 x1과 관련이 있고, 두 번째 행은 x2와 관련이 있다.

즉, 위 구조의 해는 x1과 x2를 다음과 같이 표현한다.

사실 이렇게 모두 양수만 표현하도록 설계한 이유는 세 번째 제약을 만족시키는 해를 만들기 위함이다 (이런게 유전 알고리즘을 사용할 때 매우 중요한 센스이다!).

해 표현을 제외한 유전 알고리즘의 주요 파라미터는 다음과 같이 설정한다.

최대 세대 수: 10

종료 조건: 최대 세대 수 도달

세대 별 포함되는 해의 개수: 20

교차 연산자: 1점 교차 연산

부모 수: 10

돌연변이 연산자: flip bit 돌연변이 연산

적합도 함수: 목적식 (제약을 만족못하면 0점)

돌연변이 비율: 10%

돌연변이 유전 개체 비율: 20%

이제 파이썬을 사용해서 유전 알고리즘의 각 단계를 함수 단위로 구현해보도록 하자.

유전 알고리즘을 사용할 수 있는 패키지가 있긴 하지만, 문제에 따라서 직접 정의해야 하는 부분이 많다보니 개인적으로는 numpy를 활용하는 것이 편리하다.

먼저, numpy를 임포트해주자.

import numpy as np

그리고 N개의 초기 해를 생성하는 함수를 정의하자.

이 함수는 random.randint를 사용하여 0과 2사이 중 하나를 선택하여 (N, 2, 5) shape의 배열을 생성한다.

즉, 0과 1로만 구성되는 (N, 2, 5) shape의 배열을 만드는 것이며, N은 결국 해의 개수, (2, 5)는 해의 구조 (행렬 구조)라고 볼 수 있다.

def generate_initial_population(N): initial_population = np.random.randint(0, 2, (N, 2, 5)) return initial_population

이제 각각의 해를 평가하는 적합도 함수를 만들자.

제약이 문제에 포함되어 있으므로 제약을 어기는 경우에는 적합도를 0으로 주도록 하자.

먼저 2 * 5 크기의 행렬이 입력되면, 여기서 x1과 x2를 계산한다.

그리고 문제의 제약을 만족하는지 여부를 확인해서, 모두 만족하면 목적식으로 적합도를 평가하고, 하나라도 만족하지 못하면 적합도를 0으로 설정한다.

def evaluate_fitness(solution): x1 = sum([2**(4-i) * solution[0][i] for i in range(5)]) x2 = sum([2**(4-i) * solution[1][i] for i in range(5)]) constraint_1 = (100 * x1 + 50 * x2) <= 3000 constraint_2 = (10 * x1) <= 100 if constraint_1 and constraint_2: fitness_value = 100 * x1 + 40 * x2 else: fitness_value = 0 # 제약을 하나라도 위반하면 적합도 0점 return fitness_value 이제 한 세대에서 두 개의 해를 선택하여 1점 교차 연산을 수행하는 함수를 정의하자. 이 함수는 두 개의 해 (solution1, solution2)를 입력받아 교차 지점을 1과 5사이에서 임의로 선택하여 자식을 만든다. 해 자체가 행렬이기 때문에 교차 지점을 각 행마다 설정했다. 자세히 살펴보면, 각 행마다 교차 지점은 1, 2, 3 중 하나를 선택하는데, 0이나 4가 교차지점이 되면 사실상 하나의 부모의 유전자가 그대로 내려오는 것이기 때문에 0과 4는 제외하였다. 그리고 자식 해를 빈 배열로 생성한 뒤, 0번째 행과 1번째 행을 각각 부모들의 유전자로 채운다. 리스트로 만들어서 더하는 방식도 괜찮지만, 그렇게 되면 ndarray와 리스트를 왔다갔다하면서 문제가 생길 위험이 있기 때문에, empty 함수를 사용했다. def crossover(solution1, solution2): crossover_point_1 = np.random.randint(1, 4) # x1에 대한 교차 지점 crossover_point_2 = np.random.randint(1, 4) # x2에 대한 교차 지점 child = np.empty((2, 5)) # 자식을 빈 배열로 생성 # 부모 유전자 가져오기 child[0][:crossover_point_1] = solution1[0][:crossover_point_1] child[0][crossover_point_1:] = solution2[0][crossover_point_1:] child[1][:crossover_point_2] = solution1[1][:crossover_point_2] child[1][crossover_point_2:] = solution2[1][crossover_point_2:] return child 이제 돌연변이 연산을 정의하자. p는 각 개체에서 돌연변이가 일어날 확률이다. 해의 모든 인덱스를 row와 col로 순회하면서, 각 위치마다 난수를 생성한 뒤, 그 난수가 p보다 작다면 (즉, p의 확률로), 그 위치에 있는 값을 바꿔준다. 여기서 유용한 두 가지 테크닉을 짚고 넘어가자. x = 1 - x는 x가 0이면 1로, 1이면 0으로 바꾸는데 사용 if 난수 < p는 결국 p의 확률로 선택하는데 사용 def mutation(child, p): for row in range(2): for col in range(5): if np.random.random() < p: child[row, col] = 1 - child[row, col] return child 이제 함수 정의는 끝났으니, 함수들을 이용하여 유전 알고리즘을 구현하자. 먼저, 파라미터를 이렇게 정의하자. num_iter = 10 # 세대 수 N = 20 # 한 세대에 포함되는 해의 개수 N_P = 10 # 부모 개수 mutation_sol_prob = 0.1 # 유전자(해)가 돌연변이일 확률 mutation_gene_prob = 0.2 # 유전 개체가 돌연변이일 확률 그리고나서 메인 코드를 작성한다. 가장 먼저 초기 해를 생성하고, 지금까지 찾은 최대 적합도를 초기화한다. 그리고 각 이터레이션마다 현재 세대를 평가하고, 현재 세대에 지금까지 찾은 최대 적합도보다 큰 적합도를 갖는 해가 있다면, 그 해를 best_solution에, 그 해의 적합도를 best_score에 저장한다. 그리고 fitness_value_list를 기준으로 상위 N_P개의 해를 선택하여 parents에 저장한다. 그리고 한 세대에 포함되야 하는 해의 개수에서 부모의 개수를 뺀 만큼 자식을 생성한 뒤, 20%의 확률로 돌연변이 연산을 적용한 자식을 new_population에 추가한다. # 초기 해 생성 current_population = generate_initial_population(N) best_score = -1 # 지금까지 찾은 최대 적합도 초기화 for _ in range(num_iter - 1): # 해 평가 수행 fitness_value_list = np.array([evaluate_fitness(solution) for solution in current_population]) # 지금까지 찾은 최대 적합도보다 현세대에 있는 최대 적합도가 크다면 업데이트 if fitness_value_list.max() > best_score: best_score = fitness_value_list.max() best_solution = current_population[fitness_value_list.argmax()] # 적합도 기준 상위 N_P개 해 선정 (값이 큰 순으로 정렬하기 위해 -를 붙임) parents = current_population[np.argsort(-fitness_value_list)] # 새로운 해 집단 정의 new_population = parents # 두 개의 부모를 선택하면서 자식 생성 for _ in range(N – N_P): # N – N_P = 생성해야 하는 자식 개수 # 부모 선택 parent_1_idx, parent_2_idx = np.random.choice(N_P, 2, replace = False) parent_1 = parents[parent_1_idx] parent_2 = parents[parent_2_idx] # 자식 생성 child = crossover(parent_1, parent_2) # mutation_sol_prob의 확률로 돌연변이 연산 수행 if np.random.random() < mutation_sol_prob: child = mutation(child, mutation_gene_prob) # new_population에 child 추가 (child 구조가 (2, 5)라서 vstack이 안되므로, 구조를 변경) new_population = np.vstack([new_population, child.reshape(1, 2, 5)]) 이렇게 찾은 해는 다음과 같다. best_solution을 뜯어보면, x1 = 10, x2 = 31인데, 주어진 해 구조에서는 최적임을 쉽게 알 수 있다. 다 풀고 나서 실수를 알아차렸는데, 2*5크기가 아니라 2*6크기의 해 구조를 정의했으면 최적해를 찾았을 것이다... 728x90

유전 알고리즘 가지고 놀기

예제 링크: https://github.com/Kcrong/Simple-Genetic-Algorithm

유전 알고리즘이란,

“유전 알고리즘(Genetic Algorithm)은 자연세계의 진화과정에 기초한 계산 모델로서 존 홀랜드(John Holland)에 의해서 1975년에 개발된 전역 최적화 기법으로, 최적화 문제를 해결하는 기법의 하나이다. 생물의 진화를 모방한 진화 연산의 대표적인 기법으로, 실제 진화의 과정에서 많은 부분을 차용하였으며, 변이(돌연변이), 교배 연산 등이 존재한다. 또한 세대, 인구 등의 용어도 문제 풀이 과정에서 사용된다.” – 위키피디아

유전 알고리즘은 부모의 유전 정보들이 자식들에게 골고루 분포 됨으로써, 문제에 대한 해를 찾아가는 알고리즘이다.

자식 해는 부모 해와 비슷한 형질을 가지며, 우월한 유전자들은 다시 자식해를 만들며 우수 유전자를 널리 퍼트리는 특징이 있다.

소스 설명 전, 사용할 용어에 대한 설명은 아래와 같다.

1. 유전자

예시 소스에서는 integer list 로 정의했다. 하지만 그 형태와 값의 크기는 무엇이든지 될 수 있으며, 제한이 없다. (구현이 어려울 뿐..)

2. 세대

유전자들의 생성과 소멸을 아우르는 하나의 주기를 말한다.

보통 생성 -> 번식 -> 소멸 의 주기를 가진다.

3. 적합도 (Fitness)

유전자가 얼마나 우월한지 보여주는 지수.

이 지수가 높을 수록 우월한 유전자임을 뜻한다.

전체적인 알고리즘은 3가지로 이루어져있다.

1. 부모 유전자 선택

2. 번식

3. 돌연변이

부모 유전자 선택

부모 유전자를 선택하는 부분에서는, 룰렛 휠 선택 방식을 이용했다.

1 2 3 # 부모를 select_list를 이용해 정함. # 부모로 선출될 확률은 fitness 과 비례한다. parents = tuple(self.select_list[rand( 0 , len (self.select_list))] for i in range ( 2 )) cs

룰렛 휠 방식

이미지 출처: http://blog.secmem.org/category/IT%20%EB%86%80%EC%9D%B4%ED%84%B0/Elite%20Member%20Tech%20%26%20Talk?page=37

룰렛 휠 방식이란, 적합도가 높을 수록 부모 해로 선택될 확률이 높아지도록 하는 방식이다.

위 그림처럼, 적합도가 100인 C는 룰렛에서 보듯이 선택될 확률이 높다. 하지만 적합도가 40인 D는 C와 달리 선택될 확률이 적다.

이처럼 우월한 유전자를 가질 수록 부모 해로 선택될 확률을 높이는 것을 룰렛 휠 방식이라고 한다.

번식 (교차)

자식 유전자를 만들 때는, 2점 교차 라는 방식을 이용했다.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 # 각 교차 포인트를 정한다. # rand 함수의 반환이 float 형이므로, 소수점을 버리기 위해 int() 형변한을 해준다. switch_point = (rand( 1 , gene_len / / 2 ), rand(gene_len / / 2 , gene_len)) # 처음 자식이 받는 유전자는 parent1 # 다만 교차 포인트에 다다르면, 다른 parent 유전자 정보를 받아오기 시작한다. (parent = parent2) parent = parents[ 0 ] for i in range (gene_len): # 자식 유전자 정보는 부모 유전자에서 받아온다 gene_data.append(parent.gene_data[i]) if i in switch_point: # 유전자를 받아오는 부모 변경 try : parent = parents[parents.index(parent) + 1 ] except IndexError: parent = parents[ 0 ] “” ” a = parents.index(parent) –> 현재 부모의 index 값 parents[a+1] –> 부모 리스트에서, 현재 부모 인덱스값보다 +1 된 값 가져옴 IndexError –> 만약 1이 넘어가면 parent = parents[0] 다시 0으로 돌아옴 ” “” Colored by Color Scripter cs

2점 교차는 두 점을 임의로 선택하여, 그 점을 기준으로 각 부모 유전자에서 번갈아 유전자를 받아오는 방법이다.

물론 점의 위치에 따라 부모1과 부모2의 유전 정보 비율은 달라질 수 있지만 교차의 경우 섞이는 복잡도를 정하는 단계이므로 신경쓰지 않는다.

–> Mutation (돌연변이)

1 2 3 4 # 돌연변이 확률은 fitness 와 반비례 한다. # fitness 가 높을 수록, 돌연변이 확률이 적어진다. if rand( 0 , self.fitness * 100 ) = = 0 : return DNA([rand(min(WE_WANT), max(WE_WANT)) for i in range ( len (WE_WANT))]) cs

돌연변이 확률은 적합도와 반비례 하도록 구현했으며, 돌연변이는 기존 부모와 상관없는 전혀 새로운 유전자를 갖는다.

돌연변이는 그 확률 설정에 따라 다른 결과가 나온다. 자세한 내용은 아래 결과 분석에서 살펴보자.

결과분석

우선 목표값을

0 과 1로 이루어진 8자리 list 로 잡았다.

결과는 다음 이미지와 같다. X축이 세대, Y축이 적합도 수치를 나타낸다.

[그림1] 목표 값 [0,1,0,1,0,1,0,1]

목표 값이 단순한 관계로 얼마 지나지 않아 40번째 세대 쯤에서 최대 적합도에 수렴하는 것을 볼 수 있다.

목표 값을 조금 복잡하게 해보자.

0~9의 값을 가지도록 조정해봤다.

[그림2] 목표 값 [3,1,2,9,7,4,3,6]

조금 더 흥미로운 결과가 나왔다.

목표 값의 범위를 늘리자 최대 적합도에 도달하는 세대가 늘어난 것이다.

위 1차 결과와는 달리 80 ~ 100 번째 세대에서 최대 적합도에 가까이 수렴하는 결과가 나왔다.

조금 더 복잡하게 해보자. 이번엔 목표 값의 길이를 바꿔볼 것이다.

[그림3-1] 목표 값 [3,1,2,9,7,4,3,6,5,2,6,9]

100 세대로는 최대 적합도에 도달하기에 한참 부족한 듯 싶다. 진화 횟수를 조금 늘려보았다.

[그림3-2] 목표 값 [3,1,2,9,7,4,3,6,5,2,6,9] _진화 횟수 증가

비록 최대 적합도에는 도달하지 못했지만, 근사한 값을 얻었다.

그럼 보다 더 최대 적합도에 가까운 값을 얻기 위해서는 어떻게 해보는 것이 좋을까?

돌연변이의 확률을 늘리고, 세대에서 가장 좋은 유전자 (Fitness 수치가 가장 높은) 1개를 다음 세대에도 보존 시켜보았다.

[그림3-3] 목표 값 [3,1,2,9,7,4,3,6,5,2,6,9] _진화 횟수 증가 _돌연변이 확률 증가, 우월 유전자 보존

최대 적합도에 도달하는데 성공했다!!!

하지만 필요 세대가 너무 많다는 문제점이 있다…

또한 돌연변이 확률을 늘렸더니 중간중간 생기는 뾰족한 부분 (내려오는 부분)이 늘어났다.

위 문제 를 조금 개선시켜보자.

우월한 유전자를 자식 세대에 포함시키는 과정에서, 1개가 아닌 5개를 포함시켜보았다.

[그림3-4] 목표 값 [3,1,2,9,7,4,3,6,5,2,6,9] _진화 횟수 증가 _돌연변이 확률 증가, 우월 유전자 보존 _보존 유전자 갯수 증가

약 1100 – 850 = 250 세대가 감소했다!!~!

우월 유전자의 보존 비율 조금 더 늘려보자.

이번엔 5개 대신 10개를 포함시켜 보았다.

더욱 개선된 결과가 나오리라 생각했다.

[그림3-5] 목표 값 [3,1,2,9,7,4,3,6,5,2,6,9] _진화 횟수 증가 _돌연변이 확률 증가, 우월 유전자 보존 _보존 유전자 갯수 증가 _ 10개 보존

예상과는 달리, 이전 결과 보다 더욱 못한 결과가 나왔다.

이유를 살펴보았더니, 우월 유전자의 보존 비율이 증가하면 우월 유전자에 가까운 자식 유전자들이 많이 생기지만,

우월 유전자의 잘못된 부분도 같이 유지되는 문제가 있었다.

우월 유전자의 보존 비율이 높다고 진화의 방향이 좋은 것은 아니라는 것이다.

이번 실험 결과 중, 우리의 실생활과 매우 흡사한 부분이 아닐까 싶다. 🙂

P.s

질문이나 기타 문제점은 GitHub 이슈로 달아주세요

풀리퀘 받는 것도 좋아합니다.

유전 알고리즘 (Genetic Algorithm)

0. 유전 알고리즘이란?

생물학적 진화에 바탕을 둔 통계적 탐색 알고리즘 집합이다.

쉽게 말하면 그냥 유전을 이용해 문제를 푸는 거다.

유전 알고리즘은 자연 선택과, 유전학에서 영감을 얻은 교차와 변이 연산을 사용한다.

유전자 표현를 프로그래밍으로 표현하는 방법

유전자는 여러 개로 이루어지고, 유전자는 0이나 1로 나타나게 된다.

자연은 무조건 좋은 염색체를 찾는다. 그리고 무엇을 할지 가르쳐주지 않아도 적응하고 학습한다.

유전 알고리즘도 마찬가지다. 인코딩과 평가를 통해 자연을 모방한다.

인코딩은 염색체를 1과 0으로 된 문자열로 나타낸다. 가장 대표적인 방식이 이진 문자열이다.

ex_) 0101011100 -> 이게 유전자가 되는 것임

설명 할 것들 간단요약

평가 함수는 풀려는 문제에 대한 염색체의 성능, 적합도를 재는데 쓰인다.

유전 알고리즘은 재생산을 할 때 측정한 개별 염책체의 적합도를 쓴다.

선택은 적합도 비율에 따라 진행되기 때문에, 잘난놈 끼리 잘 매칭된다.

교차를 할 때는 두 염책체의 일부를 교환하고 , 변이 연산자는 몇몇 자리에 있는 유전자 값을 바꾼다.

적합도 비교에 의해서 더 좋은 염색체만 살아남게 되고 결국 재생산을 할 수록 우월해진다.

1. 유전 알고리즘 기본 동작 원리

전체적인 알고리즘

1) 문제 변수 영역을 고정된 길이의 염색체로 나타낸다.

해집단 크기 N, 교차율 Pc, 변이율 Pm을 정의한다.

(보통 교차율은 0.7, 변이율은 0.001로 설정한다.)

2) 문제 영역에서 개별 염색체의 성능, 적 적합도를 재는 적합도 한수를 정의한다.

적합도 함수는 재생산 과정에서 짝지어지는 염색체를 선택하는 근거다.

3) 염색체 N개로 이루어진 초기 해집단을 임의로 생성한다.

4) 염색체 각각의 적합도를 계산한다.

5) 현재 해집단에서 짝지을 염색체 한 쌍을 선택한다. 적합도에 따라 확률적으로 부모 염색체를 선택한다.

적합도가 높은 염색체는 적합도가 낮은 염색체보다 선택될 확률이 높다.

6) 유전 연산자인 교차와 변이를 적용하여 가식 염색체 한 쌍을 만든다.

7) 만들어진 자식 염색체를 새로운 해집단에 넣는다.

8) 새로운 해집단의 크기가 초기 해집단 크기인 N이 될 때까지 5단계를 반복한다.

9) 초기 해집단을 새로운 해집단으로 교체한다.

10) 4단계로 가서 종료 조건을 만족할 때까지 이 과정을 반복한다.

사진 및 내용 출처 : http://m.blog.daum.net/kimjaehun12/216?categoryId=19

세대 수 기반의 종료 조건과 적합도 정체의 문제

유전 알고리즘은 통계적 탐색 기법을 쓰기 때문에 더 좋은 염색체가 나타나기 전까지 몇 세대 동안은 해집단의 적합도가 정체될 수 있다.

이때 전형적인 종료 조건을 쓰면 문제가 생길 수 있다. 보통은 정해진 세대수가 되면 유전 알고리즘을 종료하고 해집단에서 가장 좋은 염색체를 찾는다. 적합도 정체가 심하면은 아무리 많은 세대를 거쳐도 결과는 불만족일 수 밖에 없다.

보통은 만족스러운 해를 발견하지 못하면 유전 알고리즘을 다시 시작하는데.. 돌릴때마다 정체되면 무슨의미가 있을까..?

결국에는 적합도를 정체시키지 않는 것이 중요하다.

그렇다면 평균 적합도를 정체시키지 않고 어떻게 올릴 수 있을까? 기본적으로 좋은 적합도 함수를 써야겠지만,

선택, 교차, 변이 같은 유전 연산자를 써서 초기해를 변형해야지, 적합도가 정체되는 것을 막을 수 있다.

적합도 비율

적합도 뿐만 아니라 적합도 비율 또한 존재한다.

이 비율은 개별 염색체의 적합도와 해집단 전체 적합도의 비율을 통하여 구한다.

적합도 비율이란 염색체가 짝짓기에 참가할 확률을 결정한다.

당연히 열성인 염색체가 적합도 비율이 낮고, 우성인 염색체가 적합도 비율이 높다.

그래서 염색체 평균 적합도는 세대를 거듭할 수 록 향상된다.

출처 : http://m.blog.daum.net/kimjaehun12/216?categoryId=19

염색체 선택

보통 룰렛 휠 선택 기법을 많이 쓴다.

염색체 각각은 원형 룰렛 휠 조각을 하나씩 할당 받는데, 그 넓이는 적합도 비율을 통해 배정받는다.

적합도 비율이 높을 수록 넓게, 작을 주록 적게 넓이를 받는 것이다.

그리고 랜덤으로 값을 뽑고, 뽑힌 면적에 해당하는 염색체를 부모로 쓰면된다.

(랜덤은 그냥 0~100 범위에서 정수나 실수 뽑으면 댐.)

출처 : http://m.blog.daum.net/kimjaehun12/216?categoryId=19

교차 연산

교차 연산은 부모 염색체 줄이 끊어지는 지점을 임의로 선택하고, 염색체에서 이 지점 보다 뒤 쪽에 있는 부분을 교환하다.

그 결과 새로운 자식 염색체 두 개가 만들어 진다. 또 일정 확률로는 그냥 부모 그대로 복사할 수도 있다.

이런 교차 성공률은 보통 70%일때 좋은 결과를 보인다.

출처 : http://m.blog.daum.net/kimjaehun12/216?categoryId=19

변이 연산

변인 연산은 유전자를 변일 시키는 것이다. 자연에서는 아주 드문일고 안좋게 보인다.

하지만 유전 알고리즘에서 변이를 사용하면, 적합도를 상당히 증가시킬 수 있다.

하지만 좋지 않은 결과를 만들 가능성도 상당히 증가한다.

변이를 사용하지 않으면은, 선택과 교차 연산을 반복하다가 어느새부터 위 과정이 동질적인 해집단에서 정체될 수 있다.

탐색 알고리즘이 효율적으로 진행되지 못하기 때문에,평균 적합도가 향상되지 않는다.

그러다 보면 평균 적합도 변화율이 정체되고, 최적해가 나온 것처럼 보일 수 있다.

변이는 임의 탐색과 동등한 효과를 주며 유전적 다양성을 잃지 않게 한다.

변이 연산은 염색체에서 임의로 선택한 유전자를 뒤집는다. ex_) 염색체의 특정 유전자를 반대로 바꾸는 거임 0 -> 1 이런식.

변이는 염색체의 모든 유전자에 일정한 확률로 일어날 수 있다.

변이율은 자연계에서도 꽤 낮기도 하고, 프로그래밍시 높게 잡으면 안 좋은 결과를 만들 가능성도 커지기 때문에

보통 0.001~0.01 사이의 낮은 수치로 정한다.

디코딩

이러한 연산들 덕분에 유전 알고리즘은 평균 적합도가 연속적으로 증가하고, 세대가 지날수록 해집단이 최적에 가까운 해로 진화한다.

중요한 거는 적합도 함수다. 잘 작동하는 적합도 함수를 만드는 것은 까다로운 작업이다.

적합도 함수를 만들 때 인자를 몇개를 요구하느냐에 따라 내부 처리의 어려움 또한 증가한다.

인자를 2개 요구하는 적합도 함수를 만들었다면 어떻게 해야할까?

이렇게 하면 된다. 아래 같이 8bit씩 쪼개져 있는걸 하나로 붙이고, 계산할 때 다시 쪼개면 된다.

범위가 -3 ~ 3이면은 어떻게 해야할까 간단하다.

출처 : http://m.blog.daum.net/kimjaehun12/216?categoryId=1 9

성능 그래프

안정적으로 좋은 결과를 얻기 위해서는 어떻게 해야할까? 해집단의 크기를 늘리면 된다.

근데 그렇게 해서 얻은 결과가 정말 최적해를 찾았는지 확일 할 수 있는 방법이 있을까?

여러가지 변이율을 이용해서 얻은 결과들을 비교해 볼 수도 있다. 거기에 성능 그래프를 이용하면 더 효율적이다.

적합도 함수의 그래프를 만들 수도 있겠지만, 적합도 함수는 그래프로 만들기 힘든 경우가 많이 있다.

유전 알고리즘은 확률적이기 때문에 보통 세대마다 성능이 달라진다.

세대마다의 평균성능을 나타내는 곡선을 만드는 것도 유용하고,

세대마다 해집단의 가장 우수한 개체의 성능을 그래프로 만드는 것도 좋다.

성능 그래프의 곡선은 최적해에 가깝게 수렴할수록 천천히 상승하고 나중에는 평평해진다.

(첫 번째 그래프는 변이율이 평범한데, 두 번째 그래프는 변이율이 높다.)

2. 유전 알고리즘을 사용한 예시 (동영상)

내가 만든거는 없고, 그냥 유튜브에서 인기 많은 유전 알고리즘 동영상이다.

일본인 교수가 이런거 올렸다가 인기가 좀 타서 비슷한게 많이 올라온 걸로 알고 있다.

유전 알고리즘으로 운전자 AI 만들기

기대했는데 결과는 안습 ㅠㅠ

유전 알고리즘을 통해 나무 만들기

프렉탈 트리랑 유전 알고리즘의 혼합버전이라고 생각된다.

프렉탈 트리는 전에 정리한 적이 있는데 아래 링크에서 확인 할 수 있다.

https://blog.naver.com/jerrypoiu/221172952459

유전 알고리즘으로 전사 학습시키기 (자작)

재밌어보여서 직접 하나 만들어 보았다.

http://blog.naver.com/jerrypoiu/221282872190

유전자 알고리즘 실습 – 날도의 잡다한 기술 블로그

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192

import datetime import random import unittest import copy def _generate_parent ( length , geneSet , get_fitness ): chromosome_list = [] for i in range ( 0 , 10 ): genes = [] while len ( genes ) < length : sampleSize = min ( length - len ( genes ), len ( geneSet )) genes . extend ( random . sample ( geneSet , sampleSize )) fitness = get_fitness ( genes ) chromosome_list . append ( Chromosome ( genes , fitness )) return chromosome_list def _mutate ( parent , geneSet , get_fitness ): childGenes = parent . Genes [:] index = random . randrange ( 0 , len ( parent . Genes )) newGene , alternate = random . sample ( geneSet , 2 ) childGenes [ index ] = alternate if newGene == childGenes [ index ] else newGene fitness = get_fitness ( childGenes ) return Chromosome ( childGenes , fitness ) def _generate_child ( parent_list , geneSet , get_fitness ): child_list = [] fitness_percent_list = [] fitness_accum_list = [] fitness_sum = 0 for parent in parent_list : fitness_sum += parent . Fitness for parent in parent_list : fitness_percent_list . append ( parent . Fitness / fitness_sum ) fitness_sum = 0 for fitness_percent in fitness_percent_list : fitness_sum += fitness_percent fitness_accum_list . append ( fitness_sum ) # Selection for i in range ( 0 , 10 ): rand = random . random () before = 0 for j in range ( 0 , len ( fitness_accum_list )): if rand > before and rand <= fitness_accum_list [ j ]: child_list . append ( copy . deepcopy ( parent_list [ j ])) break before = fitness_accum_list [ j ] # Crossover crossover_rate = 0.20 selected = None for i in range ( 0 , len ( child_list )): rand = random . random () if rand < crossover_rate : if selected is None : selected = i else : child_list [ selected ] . Genes [ 2 :], child_list [ i ] . Genes [ 2 :] = \ child_list [ i ] . Genes [ 2 :], child_list [ selected ] . Genes [ 2 :] selected = None # update child_list [ i ] . Fitness = get_fitness ( child_list [ i ] . Genes ) # mutate mutate_rate = 0.2 for i in range ( 0 , len ( child_list )): rand = random . random () if rand < mutate_rate : child = _mutate ( child_list [ i ], geneSet , get_fitness ) del child_list [ i ] child_list . append ( child ) return child_list def get_best ( get_fitness , targetLen , optimalFitness , geneSet , display ): random . seed () # 1. Generate Parent bestParentList = _generate_parent ( targetLen , geneSet , get_fitness ) display ( bestParentList ) gen_count = 0 maximum_average = 0 while True : gen_count += 1 #print("generation : {}".format(gen_count)) child_list = _generate_child ( bestParentList , geneSet , get_fitness ) fitness_sum = 0 for child in child_list : fitness_sum += child . Fitness average = fitness_sum / 10 if average > maximum_average : print ( “new maximum fitness : {}” . format ( average )) bestParentList = child_list maximum_average = average if average >= optimalFitness : return child_list class Chromosome : def __init__ ( self , genes , fitness ): self . Genes = genes self . Fitness = fitness def get_fitness ( guess , target ): fitness = 0 for expected , actual in zip ( target , guess ): if expected == actual : fitness += 5 elif actual in target : fitness += 1 return fitness def display ( candidate , target , startTime ): timeDiff = datetime . datetime . now () – startTime strike = 0 ball = 0 for expected , actual in zip ( target , candidate . Genes ): if expected == actual : strike += 1 elif actual in target : ball += 1 if strike == 0 and ball == 0 : result = “out” else : result = “{}/{}” . format ( strike , ball ) print ( “{} \t {} \t {} \t {}” . format ( ” . join ( candidate . Genes ), result , candidate . Fitness , timeDiff )) def display_list ( candidate_list , target , startTime ): fitness_sum = 0 for candidate in candidate_list : display ( candidate , target , startTime ) fitness_sum += candidate . Fitness print ( “average fitness : {}” . format ( fitness_sum / len ( candidate_list ))) def pick_baseball_num ( length , is_duplicate_allowed ): if is_duplicate_allowed is True or length > 10 : return ” . join ( random . choice ( “0123456789” ) for _ in range ( length )) baseball_list = [] num = random . randrange ( 0 , 10 ) for i in range ( length ): while str ( num ) in baseball_list : num = random . randrange ( 0 , 10 ) baseball_list . append ( str ( num )) return ” . join ( baseball_list ) class BaseballGames ( unittest . TestCase ): geneset = “0123456789” def test_Baseball ( self ): length = 6 target = pick_baseball_num ( length , False ) print ( “target : {}” . format ( target )) self . guess_baseball ( target ) def guess_baseball ( self , target ): startTime = datetime . datetime . now () def fnGetFitness ( genes ): return get_fitness ( genes , target ) def fnDisplay ( candidate_list ): display_list ( candidate_list , target , startTime ) optimalFitness = len ( target ) * 5 child_list = get_best ( fnGetFitness , len ( target ), optimalFitness , self . geneset , fnDisplay ) fnDisplay ( child_list ) if __name__ == ‘__main__’ : unittest . main ()

유전 알고리즘 (Genetic algorithm)

유전 알고리즘 (Genetic algorithm) Start

BioinformaticsAndMe

유전 알고리즘 (Genetic Algorithm)

: 유전 알고리즘(GA)은 존 홀랜드(John Holland)가 다윈 진화론의 적자생존에 기반하여 개발한 최적화 연산 방법(1975)

*진화론에서 언급되는 최종적으로 살아남는 종은 변화에 가장 발빠르게 적응하는 종

*https://bioinformaticsandme.tistory.com/52

: 생물의 진화를 모방한 진화 연산의 대표적인 기법 (탐색 알고리즘의 일종)

1) 문제에 대한 가능한 해(유전자)들을 나열

2) 유전자들을 변화시켜 높은 정확도를 가진 해들을 생성

3) 이런 유전자들의 변형으로 좋은 해를 얻는 것을 진화라 봄

: 실제 진화 연구에서 사용되는 여러 용어들을 사용 중

*세대(Generation), 인구(Population), 변이(Mutation), 교차(Crossover) 등

Matlab을 이용한 유전 알고리즘(Genetic Algorithm) 예제

반응형

지난 포스트에서는 유전 알고리즘이 어떤 의미를 가지며, 어떤 연산으로 이루어지는지에 대해 알아보았다.

이번 포스트에서는 지난 번에 다루었던 내용을 바탕으로 간단한 형태의 유전 알고리즘을 구현하고, 그 연산 과정이 어떻게 이루어지는지 알아보도록 하겠다.

경험적으로 장황한 이론적인 설명 보다는 복잡하지 않은 예제에 대해 이야기 하는 것이 더 이해가 빠른 경우가 많았다. 따라서 지난번에 유전 알고리즘에 대한 개념에 대해 간단히 언급을 했다라면, 이번 경우에는 실제 문제를 통해 유전 알고리즘의 구성 요소와 연산이 실제 어떻게 이루어지는지에 대해 알아보는 것이 좋을 것 같다.

문제 정의 : 모든 개체가 특정 값의 20자리 바이너리 스트링을 가지도록 진화 수렴 시킴

바이너리 스트링 유전자의 예

초기화 : 100개의 개체가 랜덤한 값을 가지는 20자리 바이너리 스트링으로 초기화

적합도 함수 Fitness Function : 20자리의 값이 원하는 값과 얼마나 매칭되느냐에 따라 점수를 매긴다.

예를 들어, 20 자리 중 7자리가 원하는 값과 일치하면 7이라는 값을 매긴다. 따라서 적합도 함수 출력은 최소 0에서 최대 20까지의 값을 가진다.

하기의 적합도 함수 코드는 유전자 스트링의 앞 10자리는 0, 그리고 뒤의 10자리는 1인 경우에 가장 적합도가 높다고 판단한다.

function [ y ] = ga_fitness( X , size) check = 0; for i = 1:size

if i >= 1 && i <= size/2 if X(1,i) == 0 check = check + 1; end elseif i >= (size/2+1) && i <= size if X(1,i) == 1 check = check + 1; end end end y = check; end 이제 연산의 종류를 선택할 차례이다. 선택, 교차, 변이, 대치 연산에 대해 어떻게 수행할지를 결정해야 한다. 선택 연산 먼저 선택 연산은 룰렛휠 선택 방식을 사용할 것이다. 룰렛휠 선택은 원형 회전판을 몇 개의 구역으로 나누고, 이 회전판이 돌아가고 있는 상태에서 다트를 던져 맟주는 방식을 생각하면 된다. 다트가 회전 판에 어느 구역에 꽂힐지는 랜덤하지만 확률로 보면 넓은 구역에 꽂히게 될 가능성이 높다. 룰렛휠 선택 연산은 모든 개체의 적합도 함수 값을 구해서 이를 더하고, 각각의 개체가 차지하는 영역의 비율을 산출하여 룰렛 판의 영역을 결정한다. 개체의 적합도가 높아 좋은 품질이라고 생각되는 개체는 많은 영역을 차지하게 되고, 적합도가 낮아 나쁜 품질이라고 생각되는 개체는 작은 영역을 차지하게 된다. 따라서 좋은 품질의 개체가 부모로 선택될 확률이 커지게 된다. 룰렛휠 선택 연산의 공식은 다음과 같다. 여기서 Cw는 해집단 내에서 가장 나쁜 품질의 개체가 가지는 비용, Cb는 해집단 내에서 가장 좋은 품질의 개체가 가지는 비용, Ci는 i번째 개체가 가지는 비용으로 좋은 품질의 개체일 수록 f 값은 커지게 된다. Cw, Cb, Ci는 각각 비용을 뜻하는 변수로 그 값이 작을수록 좋다. k는 튜닝 변수로 일반적으로 3 혹은 4의 값을 사용한다. 이 예제에서는 해집단이 100개의 개체로 이루어져 있으므로 f(1) ~ f(100)의 값을 모두 더하여 룰렛휠을 만든다. 0 ~ (모든 f의 합) 사이의 임의의 랜덤 값을 구해 그 값의 위치에 해당하는 개체를 선택하게 된다. 적합도가 높은 개체가 선택되는 것은 자연계에서 환경에 적응을 잘하는 개체가 더 잘 살아남는 현상을 모델링하는 것이다. 교차 연산 교차 연산은 2점 교차 방식을 사용하였다. 2점 교차 방식은 유전자 스트링의 임의의 2점을 선택하여 한 쪽 부모에게서는 바깥 쪽 유전자를, 다른 한 쪽 부모에게서는 안 쪽 유전자를 물려 받게 하는 방식이다. 선택되는 2점은 랜덤이므로 어느 부모에게서 더 많은 유전자를 물려받게 될지는 예측하기 어렵다. 변이 연산 사람에게서도 부모가 가지고 있지 않는 어떤 재능이나 특징이 굉장히 드물게 나타나는 경우가 있다. 훌륭한 부모 밑에서 상당히 좋지 않은 자식이 태어날 수도 있고, 그 반대의 경우도 생각할 수 있다. 이것은 유전자의 품질 향상이 한 방량으로만 흐르는 것을 탈피하여 일정 변화를 주어 좀 더 환경에서 더 잘 살아남게 하는 기회로 작용하게 한다. 이러한 과정을 모델링하는 변이 연산은 부모에게서 교차 연산을 통해 물려 받은 유전자에 작은 확률로 변화를 주는 것을 말한다. 유전자 스트링을 하나하나 탐색하면서 랜덤하게 변이를 가한다. 여기서는 바이너리 유전자를 가지므로 물려 받은 n번째 유전자가 0이라면 1로 변이를 가하게 된다. 대치 연산 대치 연산은 해집단을 자식 개체로 교체하는 것으로 사람으로 말하자면 사회의 주요 구성원이 다음 세대로 바뀌는 것이라고 보면 된다. 이 때 해집단 내의 모든 개체를 자식 개체로 교체할 수도 있고, 실제 생명체의 조직과는 다르지만 적합도가 부모에 비해 우수하다고 판단된 자식의 경우로만 교체할 수도 있다. 여기서는 모든 개체를 교체하는 것으로 한다. Matlab 시뮬레이션 앞에서 설명한 유전자 구조와 해집단, 적합도 함수를 바탕으로 각각의 연산이 수행될 수 있도록 Matlab 코드로 구현하였다. 시나리오는 다음과 같다. 1. 20개의 길이를 가지는 유전자 바이너리 스트링을 랜덤하게 초기화하며, 개체는 100개를 생성한다. 2. 선택 연산 : 룰렛휠 선택 연산을 사용하며 k값은 3으로 설정한다. 부모 개체 선택을 위해 2번 연산을 수행한다. 3. 교차 연산 : 2점 교차 방식을 사용하며, 첫 번째 점은 1~19 사이의 값을, 두 번째 점은 첫 번째 점과 20 사이의 값을 선택하여 유전자 교차를 수행한다. 4. 변이 연산 : 교차 연산으로 생성된 자식 개체의 유전자 스트링을 하나하나 체크하여 랜덤 변수가 변이율 0.001 보다 작을 경우 비트를 반전시킨다. 5. 대치 연산 : 모든 개체를 자식 개체로 교체한다. 6. 2~5의 과정을 1000 세대 동안 수행하며, 만약 모든 개체의 적합도가 최대치인 20을 만족할 경우 진화를 종료한다. 아래는 진화를 수행한 그래프이다. 코드를 실행시키면 세대가 진행되면서 각 세대에서 최대의 적합도를 가지는 개체가 얼마의 적합도 값을 가지는지와 그 세대의 해집단이 가지는 평균 적합도가 얼마인지를 표시하게 된다. 진화는 153 세대에서 완료되었다. 세대가 진행 될 수록 전반적으로 적합도가 상승하는 것으로 나타나며, 최대 적합도는 어느 순간 상승하다가도 다시 하락하는 양상을 볼 수가 있다. 초중반에는 비교적 빠른 진화를 나타내며, 후반부로 갈수록 수렵 속도가 줄어드는 것을 볼 수 있다. 이것은 해집단이 전체적으로 좋은 품질의 유전자를 가지고 있어서 선택에 있어서 거의 균등한 확률로 부모 세대의 개체를 선택하고, 부족한 개체를 찾아 보완시키는데 시간이 걸리기 때문이며 간혹 변이에 의해서 양질의 유전자가 오히려 낮은 품질로 바뀌는 경우가 발생하기도 하기 때문이다. 변이의 확률을 좀 더 높여주면 어떻게 될까? 아래는 변이 확률을 0.001에서 0.01로 올려 진화를 수행한 경우이다. 초기 수렴 속도는 0.001일 경우보다 다소 빠르지만 변이가 자주 일어나기 때문에 양질의 유전자도 다수 변이가 되기 때문에 결국에는 수렴이 되지 않는다. 이를 통해 적당한 변이율을 선택하는 것이 중요하다는 것을 알 수가 있다. 이 밖에도 주어진 문제에 따라 적당한 수의 해집단, 적당한 형태의 유전자 표현 형태 등을 고려해야 한다. 해집단의 수가 너무 작으면 다양성을 확보하기 어렵고, 너무 많도 수렴성에 문제가 되며 연산량 또한 많아진다. 우리가 풀고자 하는 문제의 유형에 따라 찾는 값이 실수형 값인지 단계의 구분을 원하는지에 따라서 유전자 구성이 달라져야 한다. 더 생각해봐야 할 것들 간단한 형태의 유전 알고리즘을 Matlab 코드로 구현해 보았다. 이 예제에서 구현된 코드는 하기에 첨부하도록 하겠다. 유전 알고리즘에서 각 단계의 연산에는 여러 방법들이 있으며 각각의 장단점이 있을 것이다. 유전 알고리즘을 자유자재로 사용할 수 있으려면 그런 다양한 방법을 알고 있어야 할 것이다. 또한 경험적으로 유전자 표현형을 어떻게 설정하여 염색체를 구성한 것인가도 중요하다. 다음 글에서는 이러한 것들을 알아보도록 하겠다. 또한 이해를 위한 예제를 넘어서 실제 문제에의 응용을 통해 유전 알고리즘의 가능성과 한계에 대해서도 알아보도록 한다. ga.m ga_fitness.m (이 글이 마음에 드신다면 아래 버튼을 눌러 주세요~~^^) 반응형

키워드에 대한 정보 유전 알고리즘 예제

다음은 Bing에서 유전 알고리즘 예제 주제에 대한 검색 결과입니다. 필요한 경우 더 읽을 수 있습니다.

이 기사는 인터넷의 다양한 출처에서 편집되었습니다. 이 기사가 유용했기를 바랍니다. 이 기사가 유용하다고 생각되면 공유하십시오. 매우 감사합니다!

사람들이 주제에 대해 자주 검색하는 키워드 01-3 Dimensionality Reduction – Genetic Algorithm

  • 변수 선택
  • 유전 알고리즘
  • Genetic Algorithm

01-3 #Dimensionality #Reduction #- #Genetic #Algorithm


YouTube에서 유전 알고리즘 예제 주제의 다른 동영상 보기

주제에 대한 기사를 시청해 주셔서 감사합니다 01-3 Dimensionality Reduction – Genetic Algorithm | 유전 알고리즘 예제, 이 기사가 유용하다고 생각되면 공유하십시오, 매우 감사합니다.

See also  경기도 집값 순위 | 경기도에서 아파트가 비싼 지역 Top 20 상위 205개 답변

Leave a Comment