빌드 단계 추가 및 코드 정리

This commit is contained in:
jung-geun
2024-03-08 17:49:44 +09:00
parent 9cce58c177
commit 4cd563190f
10 changed files with 2478 additions and 2384 deletions

View File

@@ -1,5 +1,6 @@
stages: stages:
- sonarqube-check - sonarqube-check
- build
include: include:
- local: ".gitlab/ci/*.gitlab-ci.yml" - local: ".gitlab/ci/*.gitlab-ci.yml"

View File

@@ -0,0 +1,18 @@
variables:
PYTHON_VERSION: "3.9"
TWINE_USERNAME: "__token__"
build-package:
stage: build
image: python:${PYTHON_VERSION}
script:
- pip install --upgrade pip
- if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
- pip install setuptools wheel twine
- python setup.py bdist_wheel sdist
- twine upload dist/*.whl dist/*.tar.gz
only:
changes:
- "setup.py"
- "pso/__init__.py"

View File

@@ -1,5 +1,8 @@
[![Python Package Index publish](https://github.com/jung-geun/PSO/actions/workflows/pypi.yml/badge.svg?event=push)](https://github.com/jung-geun/PSO/actions/workflows/pypi.yml) [![Python Package Index publish](https://github.com/jung-geun/PSO/actions/workflows/pypi.yml/badge.svg?event=push)](https://github.com/jung-geun/PSO/actions/workflows/pypi.yml)
[![PyPI - Version](https://img.shields.io/pypi/v/pso2keras)](https://pypi.org/project/pso2keras/) [![PyPI - Version](https://img.shields.io/pypi/v/pso2keras)](https://pypi.org/project/pso2keras/)
[![Quality Gate Status](https://sonar.pieroot.xyz/api/project_badges/measure?project=pieroot_pso_6a2f36a9-2688-4900-a4a5-5be85f36f75a&metric=alert_status&token=sqb_5fa45d924cd1c13f71a23a9283fba9460dc63eb6)](https://sonar.pieroot.xyz/dashboard?id=pieroot_pso_6a2f36a9-2688-4900-a4a5-5be85f36f75a)
[![Duplicated Lines (%)](https://sonar.pieroot.xyz/api/project_badges/measure?project=pieroot_pso_6a2f36a9-2688-4900-a4a5-5be85f36f75a&metric=duplicated_lines_density&token=sqb_5fa45d924cd1c13f71a23a9283fba9460dc63eb6)](https://sonar.pieroot.xyz/dashboard?id=pieroot_pso_6a2f36a9-2688-4900-a4a5-5be85f36f75a)
[![Security Rating](https://sonar.pieroot.xyz/api/project_badges/measure?project=pieroot_pso_6a2f36a9-2688-4900-a4a5-5be85f36f75a&metric=security_rating&token=sqb_5fa45d924cd1c13f71a23a9283fba9460dc63eb6)](https://sonar.pieroot.xyz/dashboard?id=pieroot_pso_6a2f36a9-2688-4900-a4a5-5be85f36f75a)
### 목차 ### 목차

File diff suppressed because it is too large Load Diff

View File

@@ -14,10 +14,7 @@ from pso2keras import Particle
gpus = tf.config.experimental.list_physical_devices("GPU") gpus = tf.config.experimental.list_physical_devices("GPU")
if gpus: if gpus:
try: try:
# tf.config.experimental.set_visible_devices(gpus[0], "GPU")
# print(tf.config.experimental.get_visible_devices("GPU"))
tf.config.experimental.set_memory_growth(gpus[0], True) tf.config.experimental.set_memory_growth(gpus[0], True)
# print("set memory growth")
except RuntimeError as e: except RuntimeError as e:
print(e) print(e)

View File

@@ -9,7 +9,13 @@ class PSO(object):
Class implementing PSO algorithm Class implementing PSO algorithm
""" """
def __init__(self, model: keras.models, loss_method=keras.losses.MeanSquaredError(), optimizer='adam', n_particles=5): def __init__(
self,
model: keras.models,
loss_method=keras.losses.MeanSquaredError(),
optimizer="adam",
n_particles=5,
):
""" """
Initialize the key variables. Initialize the key variables.
@@ -19,39 +25,39 @@ class PSO(object):
optimizer : 최적화 함수 optimizer : 최적화 함수
n_particles(int) : 파티클의 개수 n_particles(int) : 파티클의 개수
""" """
self.model = model # 모델 self.model = model # 모델
self.n_particles = n_particles # 파티클의 개수 self.n_particles = n_particles # 파티클의 개수
self.loss_method = loss_method # 손실 함수 self.loss_method = loss_method # 손실 함수
self.optimizer = optimizer # 최적화 함수 self.optimizer = optimizer # 최적화 함수
self.model_structure = self.model.to_json() # 모델의 구조 self.model_structure = self.model.to_json() # 모델의 구조
self.init_weights = self.model.get_weights() # 검색할 차원 self.init_weights = self.model.get_weights() # 검색할 차원
self.particle_depth = len(self.model.get_weights()) # 검색할 차원의 깊이 self.particle_depth = len(self.model.get_weights()) # 검색할 차원의 깊이
self.particles_weights = [None] * n_particles # 파티클의 위치 self.particles_weights = [None] * n_particles # 파티클의 위치
for _ in tqdm(range(self.n_particles), desc="init particles position"): for _ in tqdm(range(self.n_particles), desc="init particles position"):
# particle_node = [] # particle_node = []
m = keras.models.model_from_json(self.model_structure) m = keras.models.model_from_json(self.model_structure)
m.compile(loss=self.loss_method, m.compile(
optimizer=self.optimizer, metrics=["accuracy"]) loss=self.loss_method, optimizer=self.optimizer, metrics=["accuracy"]
)
self.particles_weights[_] = m.get_weights() self.particles_weights[_] = m.get_weights()
# print(f"shape > {self.particles_weights[_][0]}") # print(f"shape > {self.particles_weights[_][0]}")
# self.particles_weights.append(particle_node) # self.particles_weights.append(particle_node)
# print(f"particles_weights > {self.particles_weights}") # print(f"particles_weights > {self.particles_weights}")
# self.particles_weights = np.random.uniform(size=(n_particles, self.particle_depth)) \ # self.particles_weights = np.random.uniform(size=(n_particles, self.particle_depth)) \
# * self.init_pos # * self.init_pos
# 입력받은 파티클의 개수 * 검색할 차원의 크기 만큼의 균등한 위치를 생성 # 입력받은 파티클의 개수 * 검색할 차원의 크기 만큼의 균등한 위치를 생성
# self.velocities = [None] * self.n_particles # self.velocities = [None] * self.n_particles
self.velocities = [ self.velocities = [
[0 for i in range(self.particle_depth)] for n in range(n_particles)] [0 for i in range(self.particle_depth)] for n in range(n_particles)
]
for i in tqdm(range(n_particles), desc="init velocities"): for i in tqdm(range(n_particles), desc="init velocities"):
# print(i) # print(i)
for index, layer in enumerate(self.init_weights): for index, layer in enumerate(self.init_weights):
# print(f"index > {index}") # print(f"index > {index}")
# print(f"layer > {layer.shape}") # print(f"layer > {layer.shape}")
self.velocities[i][index] = np.random.rand( self.velocities[i][index] = np.random.rand(*layer.shape) / 5 - 0.10
*layer.shape) / 5 - 0.10
# if layer.ndim == 1: # if layer.ndim == 1:
# self.velocities[i][index] = np.random.uniform( # self.velocities[i][index] = np.random.uniform(
# size=(layer.shape[0],)) # size=(layer.shape[0],))
@@ -72,11 +78,10 @@ class PSO(object):
# size=(n_particles, self.particle_depth)) # size=(n_particles, self.particle_depth))
# 입력받은 파티클의 개수 * 검색할 차원의 크기 만큼의 속도를 무작위로 초기화 # 입력받은 파티클의 개수 * 검색할 차원의 크기 만큼의 속도를 무작위로 초기화
# 최대 사이즈로 전역 최적갑 저장 - global best # 최대 사이즈로 전역 최적갑 저장 - global best
self.g_best = self.model.get_weights() # 전역 최적값(최적의 가중치) self.g_best = self.model.get_weights() # 전역 최적값(최적의 가중치)
self.p_best = self.particles_weights # 각 파티클의 최적값(최적의 가중치) self.p_best = self.particles_weights # 각 파티클의 최적값(최적의 가중치)
self.p_best_score = [0 for i in range( self.p_best_score = [0 for i in range(n_particles)] # 각 파티클의 최적값의 점수
n_particles)] # 각 파티클의 최적값의 점수 self.g_best_score = 0 # 전역 최적값의 점수(초기화 - 무한대)
self.g_best_score = 0 # 전역 최적값의 점수(초기화 - 무한대)
self.g_history = [] self.g_history = []
self.g_best_score_history = [] self.g_best_score_history = []
self.history = [] self.history = []
@@ -101,22 +106,22 @@ class PSO(object):
# print(f"shape > w : {np.shape(w[i])}, v : {np.shape(v[i])}") # print(f"shape > w : {np.shape(w[i])}, v : {np.shape(v[i])}")
new_weights[i] = tf.add(weights[i], v[i]) new_weights[i] = tf.add(weights[i], v[i])
# new_w = tf.add(w, v) # 각 파티클을 랜덤한 속도만큼 진행 # new_w = tf.add(w, v) # 각 파티클을 랜덤한 속도만큼 진행
return new_weights # 진행한 파티클들의 위치를 반환 return new_weights # 진행한 파티클들의 위치를 반환
def _update_velocity(self, weights, v, p_best, c0=0.5, c1=1.5, w=0.75): def _update_velocity(self, weights, v, p_best, c0=0.5, c1=1.5, w=0.75):
""" """
Update particle velocity Update particle velocity
Args: Args:
weights (array-like) : 파티클의 현재 가중치 weights (array-like) : 파티클의 현재 가중치
v (array-like) : 속도 v (array-like) : 속도
p_best(array-like) : 각 파티클의 최적의 위치 (최적의 가중치) p_best(array-like) : 각 파티클의 최적의 위치 (최적의 가중치)
c0 (float) : 인지 스케일링 상수 (가중치의 중요도 - 지역) - 지역 관성 c0 (float) : 인지 스케일링 상수 (가중치의 중요도 - 지역) - 지역 관성
c1 (float) : 사회 스케일링 상수 (가중치의 중요도 - 전역) - 전역 관성 c1 (float) : 사회 스케일링 상수 (가중치의 중요도 - 전역) - 전역 관성
w (float) : 관성 상수 (현재 속도의 중요도) w (float) : 관성 상수 (현재 속도의 중요도)
Returns: Returns:
(array-like) : 각 파티클의 새로운 속도 (array-like) : 각 파티클의 새로운 속도
""" """
# x = np.array(x) # x = np.array(x)
# v = np.array(v) # v = np.array(v)
@@ -140,9 +145,9 @@ class PSO(object):
new_velocity = [None] * len(weights) new_velocity = [None] * len(weights)
for i, layer in enumerate(weights): for i, layer in enumerate(weights):
new_v = w*v[i] new_v = w * v[i]
new_v = new_v + c0*r0*(p_best[i] - layer) new_v = new_v + c0 * r0 * (p_best[i] - layer)
new_v = new_v + c1*r1*(self.g_best[i] - layer) new_v = new_v + c1 * r1 * (self.g_best[i] - layer)
new_velocity[i] = new_v new_velocity[i] = new_v
# m2 = tf.multiply(tf.multiply(c0, r0), # m2 = tf.multiply(tf.multiply(c0, r0),
@@ -176,7 +181,19 @@ class PSO(object):
return score return score
def optimize(self, x_train, y_train, x_test, y_test, maxiter=10, epochs=1, batch_size=32, c0=0.5, c1=1.5, w=0.75): def optimize(
self,
x_train,
y_train,
x_test,
y_test,
maxiter=10,
epochs=1,
batch_size=32,
c0=0.5,
c1=1.5,
w=0.75,
):
""" """
Run the PSO optimization process utill the stoping critera is met. Run the PSO optimization process utill the stoping critera is met.
Cas for minization. The aim is to minimize the cost function Cas for minization. The aim is to minimize the cost function
@@ -190,13 +207,18 @@ class PSO(object):
for _ in range(maxiter): for _ in range(maxiter):
loss = 0 loss = 0
acc = 1e-10 acc = 1e-10
for i in tqdm(range(self.n_particles), desc=f"Iter {_}/{maxiter} | acc avg {round(acc/(_+1) ,4)}", ascii=True): for i in tqdm(
range(self.n_particles),
desc=f"Iter {_}/{maxiter} | acc avg {round(acc/(_+1) ,4)}",
ascii=True,
):
weights = self.particles_weights[i] # 각 파티클 추출 weights = self.particles_weights[i] # 각 파티클 추출
v = self.velocities[i] # 각 파티클의 다음 속도 추출 v = self.velocities[i] # 각 파티클의 다음 속도 추출
p_best = self.p_best[i] # 결과치 저장할 변수 지정 p_best = self.p_best[i] # 결과치 저장할 변수 지정
# 2. 속도 계산 # 2. 속도 계산
self.velocities[i] = self._update_velocity( self.velocities[i] = self._update_velocity(
weights, v, p_best, c0, c1, w) weights, v, p_best, c0, c1, w
)
# 다음에 움직일 속도 = 최초 위치, 현재 속도, 현재 위치, 최종 위치 # 다음에 움직일 속도 = 최초 위치, 현재 속도, 현재 위치, 최종 위치
# 3. 위치 업데이트 # 3. 위치 업데이트
self.particles_weights[i] = self._update_weights(weights, v) self.particles_weights[i] = self._update_weights(weights, v)
@@ -204,12 +226,19 @@ class PSO(object):
# Update the besst position for particle i # Update the besst position for particle i
# 내 현재 위치가 내 위치의 최소치보다 작으면 갱신 # 내 현재 위치가 내 위치의 최소치보다 작으면 갱신
self.model.set_weights(self.particles_weights[i].copy()) self.model.set_weights(self.particles_weights[i].copy())
self.model.fit(x_train, y_train, epochs=epochs, batch_size=batch_size, self.model.fit(
verbose=0, validation_data=(x_test, y_test)) x_train,
y_train,
epochs=epochs,
batch_size=batch_size,
verbose=0,
validation_data=(x_test, y_test),
)
self.particles_weights[i] = self.model.get_weights() self.particles_weights[i] = self.model.get_weights()
# 4. 평가 # 4. 평가
self.model.compile(loss=self.loss_method, self.model.compile(
optimizer='adam', metrics=['accuracy']) loss=self.loss_method, optimizer="adam", metrics=["accuracy"]
)
score = self._get_score(x_test, y_test) score = self._get_score(x_test, y_test)
# print(score) # print(score)
@@ -224,8 +253,7 @@ class PSO(object):
self.g_best_score = score[1] self.g_best_score = score[1]
self.g_best = self.particles_weights[i].copy() self.g_best = self.particles_weights[i].copy()
self.g_history.append(self.g_best) self.g_history.append(self.g_best)
self.g_best_score_history.append( self.g_best_score_history.append(self.g_best_score)
self.g_best_score)
self.score = score[1] self.score = score[1]
loss = loss + score[0] loss = loss + score[0]
@@ -240,7 +268,8 @@ class PSO(object):
# self.g_history.append(self.g_best) # self.g_history.append(self.g_best)
# print(f"{i} particle score : {score[0]}") # print(f"{i} particle score : {score[0]}")
print( print(
f"loss avg : {loss/self.n_particles} | acc avg : {acc/self.n_particles} | best loss : {self.g_best_score}") f"loss avg : {loss/self.n_particles} | acc avg : {acc/self.n_particles} | best loss : {self.g_best_score}"
)
# self.history.append(self.particles_weights.copy()) # self.history.append(self.particles_weights.copy())

View File

@@ -1,5 +1,6 @@
import numpy as np import numpy as np
class PSO(object): class PSO(object):
""" """
Class implementing PSO algorithm Class implementing PSO algorithm
@@ -16,16 +17,16 @@ class PSO(object):
""" """
self.func = func self.func = func
self.n_particles = n_particles self.n_particles = n_particles
self.init_pos = init_pos # 검색할 차원 self.init_pos = init_pos # 검색할 차원
self.particle_dim = len(init_pos) # 검색할 차원의 크기 self.particle_dim = len(init_pos) # 검색할 차원의 크기
self.particles_pos = np.random.uniform(size=(n_particles, self.particle_dim)) \ self.particles_pos = (
* self.init_pos np.random.uniform(size=(n_particles, self.particle_dim)) * self.init_pos
)
# 입력받은 파티클의 개수 * 검색할 차원의 크기 만큼의 균등한 위치를 생성 # 입력받은 파티클의 개수 * 검색할 차원의 크기 만큼의 균등한 위치를 생성
self.velocities = np.random.uniform( self.velocities = np.random.uniform(size=(n_particles, self.particle_dim))
size=(n_particles, self.particle_dim))
# 입력받은 파티클의 개수 * 검색할 차원의 크기 만큼의 속도를 무작위로 초기화 # 입력받은 파티클의 개수 * 검색할 차원의 크기 만큼의 속도를 무작위로 초기화
self.g_best = init_pos # 최대 사이즈로 전역 최적갑 저장 - global best self.g_best = init_pos # 최대 사이즈로 전역 최적갑 저장 - global best
self.p_best = self.particles_pos # 모든 파티클의 위치 - particles best self.p_best = self.particles_pos # 모든 파티클의 위치 - particles best
self.g_history = [] self.g_history = []
self.history = [] self.history = []
@@ -42,24 +43,24 @@ class PSO(object):
""" """
x = np.array(x) # 각 파티클의 위치 x = np.array(x) # 각 파티클의 위치
v = np.array(v) # 각 파티클의 속도(방향과 속력을 가짐) v = np.array(v) # 각 파티클의 속도(방향과 속력을 가짐)
new_x = x + v # 각 파티클을 랜덤한 속도만큼 진행 new_x = x + v # 각 파티클을 랜덤한 속도만큼 진행
return new_x # 진행한 파티클들의 위치를 반환 return new_x # 진행한 파티클들의 위치를 반환
def update_velocity(self, x, v, p_best, g_best, c0=0.5, c1=1.5, w=0.75): def update_velocity(self, x, v, p_best, g_best, c0=0.5, c1=1.5, w=0.75):
""" """
Update particle velocity Update particle velocity
Args: Args:
x(array-like): particle current position x(array-like): particle current position
v (array-like): particle current velocity v (array-like): particle current velocity
p_best(array-like): the best position found so far for a particle p_best(array-like): the best position found so far for a particle
g_best(array-like): the best position regarding all the particles found so far g_best(array-like): the best position regarding all the particles found so far
c0 (float): the congnitive scaling constant, 인지 스케일링 상수 c0 (float): the congnitive scaling constant, 인지 스케일링 상수
c1 (float): the social scaling constant c1 (float): the social scaling constant
w (float): the inertia weight, 관성 중량 w (float): the inertia weight, 관성 중량
Returns: Returns:
The updated velocity (array-like). The updated velocity (array-like).
""" """
x = np.array(x) x = np.array(x)
v = np.array(v) v = np.array(v)
@@ -73,7 +74,7 @@ class PSO(object):
# 가중치(상수)*속도 + \ # 가중치(상수)*속도 + \
# 스케일링 상수*랜덤 가중치*(나의 최적값 - 처음 위치) + \ # 스케일링 상수*랜덤 가중치*(나의 최적값 - 처음 위치) + \
# 전역 스케일링 상수*랜덤 가중치*(전체 최적값 - 처음 위치) # 전역 스케일링 상수*랜덤 가중치*(전체 최적값 - 처음 위치)
new_v = w*v + c0*r*(p_best - x) + c1*r*(g_best - x) new_v = w * v + c0 * r * (p_best - x) + c1 * r * (g_best - x)
return new_v return new_v
def optimize(self, maxiter=200): def optimize(self, maxiter=200):
@@ -90,10 +91,9 @@ class PSO(object):
for _ in range(maxiter): for _ in range(maxiter):
for i in range(self.n_particles): for i in range(self.n_particles):
x = self.particles_pos[i] # 각 파티클 추출 x = self.particles_pos[i] # 각 파티클 추출
v = self.velocities[i] # 랜덤 생성한 속도 추출 v = self.velocities[i] # 랜덤 생성한 속도 추출
p_best = self.p_best[i] # 결과치 저장할 변수 지정 p_best = self.p_best[i] # 결과치 저장할 변수 지정
self.velocities[i] = self.update_velocity( self.velocities[i] = self.update_velocity(x, v, p_best, self.g_best)
x, v, p_best, self.g_best)
# 다음에 움직일 속도 = 최초 위치, 현재 속도, 현재 위치, 최종 위치 # 다음에 움직일 속도 = 최초 위치, 현재 속도, 현재 위치, 최종 위치
self.particles_pos[i] = self.update_position(x, v) self.particles_pos[i] = self.update_position(x, v)
# 현재 위치 = 최초 위치 현재 속도 # 현재 위치 = 최초 위치 현재 속도
@@ -106,7 +106,7 @@ class PSO(object):
if self.func(self.particles_pos[i]) < self.func(self.g_best): if self.func(self.particles_pos[i]) < self.func(self.g_best):
self.g_best = self.particles_pos[i] self.g_best = self.particles_pos[i]
self.g_history.append(self.g_best) self.g_history.append(self.g_best)
self.history.append(self.particles_pos.copy()) self.history.append(self.particles_pos.copy())
# 전체 최소 위치, 전체 최소 벡터 # 전체 최소 위치, 전체 최소 벡터

View File

@@ -12,13 +12,17 @@ import gc
import cupy as cp import cupy as cp
class PSO(object): class PSO(object):
""" """
Class implementing PSO algorithm Class implementing PSO algorithm
""" """
def __init__(self, model: keras.models, loss_method=keras.losses.MeanSquaredError(), n_particles: int = 5): def __init__(
self,
model: keras.models,
loss_method=keras.losses.MeanSquaredError(),
n_particles: int = 5,
):
""" """
Initialize the key variables. Initialize the key variables.
@@ -27,44 +31,45 @@ class PSO(object):
loss_method : 손실 함수 loss_method : 손실 함수
n_particles(int) : 파티클의 개수 n_particles(int) : 파티클의 개수
""" """
self.model = model # 모델 self.model = model # 모델
self.n_particles = n_particles # 파티클의 개수 self.n_particles = n_particles # 파티클의 개수
self.loss_method = loss_method # 손실 함수 self.loss_method = loss_method # 손실 함수
model_structure = self.model.to_json() # 모델의 구조 정보 model_structure = self.model.to_json() # 모델의 구조 정보
self.init_weights = self.model.get_weights() # 검색할 차원 self.init_weights = self.model.get_weights() # 검색할 차원
self.particle_depth = len(self.model.get_weights()) # 검색할 차원의 깊이 self.particle_depth = len(self.model.get_weights()) # 검색할 차원의 깊이
self.particles_weights = [None] * n_particles # 파티클의 위치 self.particles_weights = [None] * n_particles # 파티클의 위치
for _ in tqdm(range(self.n_particles), desc="init particles position"): for _ in tqdm(range(self.n_particles), desc="init particles position"):
m = keras.models.model_from_json(model_structure) m = keras.models.model_from_json(model_structure)
m.compile(loss=self.loss_method, m.compile(loss=self.loss_method, optimizer="adam", metrics=["accuracy"])
optimizer="adam", metrics=["accuracy"]) self.particles_weights[_] = m.get_weights()
self.particles_weights[_] = m.get_weights()
# 입력받은 파티클의 개수 * 검색할 차원의 크기 만큼의 균등한 위치를 생성 # 입력받은 파티클의 개수 * 검색할 차원의 크기 만큼의 균등한 위치를 생성
self.velocities = [ self.velocities = [
[0 for i in range(self.particle_depth)] for n in range(n_particles)] [0 for i in range(self.particle_depth)] for n in range(n_particles)
]
for i in tqdm(range(n_particles), desc="init velocities"): for i in tqdm(range(n_particles), desc="init velocities"):
self.init_weights = self.model.get_weights() self.init_weights = self.model.get_weights()
w_,s_,l_ = self._encode(self.init_weights) w_, s_, l_ = self._encode(self.init_weights)
w_ = np.random.rand(len(w_)) / 5 - 0.10 w_ = np.random.rand(len(w_)) / 5 - 0.10
self.velocities[i] = self._decode(w_,s_,l_) self.velocities[i] = self._decode(w_, s_, l_)
# for index, layer in enumerate(self.init_weights): # for index, layer in enumerate(self.init_weights):
# self.velocities[i][index] = np.random.rand( # self.velocities[i][index] = np.random.rand(
# *layer.shape) / 5 - 0.10 # *layer.shape) / 5 - 0.10
# 입력받은 파티클의 개수 * 검색할 차원의 크기 만큼의 속도를 무작위로 초기화 # 입력받은 파티클의 개수 * 검색할 차원의 크기 만큼의 속도를 무작위로 초기화
# 최대 사이즈로 전역 최적갑 저장 - global best # 최대 사이즈로 전역 최적갑 저장 - global best
self.p_best = self.particles_weights # 각 파티클의 최적값(최적의 가중치) self.p_best = self.particles_weights # 각 파티클의 최적값(최적의 가중치)
self.g_best=self.model.get_weights() # 전역 최적값(최적의 가중치) | 초기값은 모델의 가중치 self.g_best = (
self.model.get_weights()
) # 전역 최적값(최적의 가중치) | 초기값은 모델의 가중치
# 각 파티클의 최적값의 점수 # 각 파티클의 최적값의 점수
self.p_best_score = [0 for i in range(n_particles)] self.p_best_score = [0 for i in range(n_particles)]
# 전역 최적값의 점수(초기화 - 0) # 전역 최적값의 점수(초기화 - 0)
self.g_best_score = 0 self.g_best_score = 0
def __del__(self): def __del__(self):
del self.model del self.model
del self.n_particles del self.n_particles
@@ -77,7 +82,7 @@ class PSO(object):
del self.p_best_score del self.p_best_score
del self.g_best_score del self.g_best_score
def _encode(self,weights: list): def _encode(self, weights: list):
# w_gpu = cp.array([]) # w_gpu = cp.array([])
w_gpu = np.array([]) w_gpu = np.array([])
lenght = [] lenght = []
@@ -88,10 +93,10 @@ class PSO(object):
lenght.append(len(w_)) lenght.append(len(w_))
w_gpu = np.append(w_gpu, w_) w_gpu = np.append(w_gpu, w_)
# w_gpu = cp.append(w_gpu, w_) # w_gpu = cp.append(w_gpu, w_)
return w_gpu, shape, lenght return w_gpu, shape, lenght
def _decode(self,weight, shape, lenght): def _decode(self, weight, shape, lenght):
weights = [] weights = []
start = 0 start = 0
for i in range(len(shape)): for i in range(len(shape)):
@@ -105,7 +110,7 @@ class PSO(object):
start = end start = end
return weights return weights
def _update_weights(self, weights, v): def _update_weights(self, weights, v):
""" """
Update particle position Update particle position
@@ -121,30 +126,30 @@ class PSO(object):
# v = np.array(v) # 각 파티클의 속도(방향과 속력을 가짐) # v = np.array(v) # 각 파티클의 속도(방향과 속력을 가짐)
# new_weights = [0 for i in range(len(weights))] # new_weights = [0 for i in range(len(weights))]
# print(f"weights : {weights}") # print(f"weights : {weights}")
encode_w, w_sh, w_len = self._encode(weights = weights) encode_w, w_sh, w_len = self._encode(weights=weights)
encode_v, _, _ = self._encode(weights = v) encode_v, _, _ = self._encode(weights=v)
new_w = encode_w + encode_v new_w = encode_w + encode_v
new_weights = self._decode(new_w, w_sh, w_len) new_weights = self._decode(new_w, w_sh, w_len)
# for i in range(len(weights)): # for i in range(len(weights)):
# new_weights[i] = tf.add(weights[i], v[i]) # new_weights[i] = tf.add(weights[i], v[i])
# new_w = tf.add(w, v) # 각 파티클을 랜덤한 속도만큼 진행 # new_w = tf.add(w, v) # 각 파티클을 랜덤한 속도만큼 진행
return new_weights # 진행한 파티클들의 위치를 반환 return new_weights # 진행한 파티클들의 위치를 반환
def _update_velocity(self, weights, v, p_best, c0=0.5, c1=1.5, w=0.75): def _update_velocity(self, weights, v, p_best, c0=0.5, c1=1.5, w=0.75):
""" """
Update particle velocity Update particle velocity
Args: Args:
weights (array-like) : 파티클의 현재 가중치 weights (array-like) : 파티클의 현재 가중치
v (array-like) : 속도 v (array-like) : 속도
p_best(array-like) : 각 파티클의 최적의 위치 (최적의 가중치) p_best(array-like) : 각 파티클의 최적의 위치 (최적의 가중치)
c0 (float) : 인지 스케일링 상수 (가중치의 중요도 - 지역) - 지역 관성 c0 (float) : 인지 스케일링 상수 (가중치의 중요도 - 지역) - 지역 관성
c1 (float) : 사회 스케일링 상수 (가중치의 중요도 - 전역) - 전역 관성 c1 (float) : 사회 스케일링 상수 (가중치의 중요도 - 전역) - 전역 관성
w (float) : 관성 상수 (현재 속도의 중요도) w (float) : 관성 상수 (현재 속도의 중요도)
Returns: Returns:
(array-like) : 각 파티클의 새로운 속도 (array-like) : 각 파티클의 새로운 속도
""" """
# x = np.array(x) # x = np.array(x)
# v = np.array(v) # v = np.array(v)
@@ -159,21 +164,25 @@ class PSO(object):
# 가중치(상수)*속도 + \ # 가중치(상수)*속도 + \
# 스케일링 상수*랜덤 가중치*(나의 최적값 - 처음 위치) + \ # 스케일링 상수*랜덤 가중치*(나의 최적값 - 처음 위치) + \
# 전역 스케일링 상수*랜덤 가중치*(전체 최적값 - 처음 위치) # 전역 스케일링 상수*랜덤 가중치*(전체 최적값 - 처음 위치)
encode_w, w_sh, w_len = self._encode(weights = weights) encode_w, w_sh, w_len = self._encode(weights=weights)
encode_v, _, _ = self._encode(weights = v) encode_v, _, _ = self._encode(weights=v)
encode_p, _, _ = self._encode(weights = p_best) encode_p, _, _ = self._encode(weights=p_best)
encode_g, _, _ = self._encode(weights = self.g_best) encode_g, _, _ = self._encode(weights=self.g_best)
new_v = encode_w * encode_v + c0*r0*(encode_p - encode_w) + c1*r1*(encode_g - encode_w) new_v = (
encode_w * encode_v
+ c0 * r0 * (encode_p - encode_w)
+ c1 * r1 * (encode_g - encode_w)
)
new_velocity = self._decode(new_v, w_sh, w_len) new_velocity = self._decode(new_v, w_sh, w_len)
# new_velocity = [None] * len(weights) # new_velocity = [None] * len(weights)
# for i, layer in enumerate(weights): # for i, layer in enumerate(weights):
# new_v = w*v[i] # new_v = w*v[i]
# new_v = new_v + c0*r0*(p_best[i] - layer) # new_v = new_v + c0*r0*(p_best[i] - layer)
# new_v = new_v + c1*r1*(self.g_best[i] - layer) # new_v = new_v + c1*r1*(self.g_best[i] - layer)
# new_velocity[i] = new_v # new_velocity[i] = new_v
# new_v = w*v + c0*r0*(p_best - weights) + c1*r1*(g_best - weights) # new_v = w*v + c0*r0*(p_best - weights) + c1*r1*(g_best - weights)
return new_velocity return new_velocity
@@ -192,7 +201,17 @@ class PSO(object):
return score return score
def optimize(self, x_, y_, maxiter=10, c0=0.5, c1=1.5, w=0.75, save=False, save_path="./result/history"): def optimize(
self,
x_,
y_,
maxiter=10,
c0=0.5,
c1=1.5,
w=0.75,
save=False,
save_path="./result/history",
):
""" """
Run the PSO optimization process utill the stoping critera is met. Run the PSO optimization process utill the stoping critera is met.
Cas for minization. The aim is to minimize the cost function Cas for minization. The aim is to minimize the cost function
@@ -205,17 +224,20 @@ class PSO(object):
""" """
if save: if save:
os.makedirs(save_path, exist_ok=True) os.makedirs(save_path, exist_ok=True)
day = datetime.datetime.now().strftime('%m-%d-%H-%M') day = datetime.datetime.now().strftime("%m-%d-%H-%M")
for _ in range(maxiter): for _ in range(maxiter):
for i in tqdm(range(self.n_particles), desc=f"Iter {_}/{maxiter} ", ascii=True): for i in tqdm(
range(self.n_particles), desc=f"Iter {_}/{maxiter} ", ascii=True
):
weights = self.particles_weights[i] # 각 파티클 추출 weights = self.particles_weights[i] # 각 파티클 추출
v = self.velocities[i] # 각 파티클의 다음 속도 추출 v = self.velocities[i] # 각 파티클의 다음 속도 추출
p_best = self.p_best[i] # 결과치 저장할 변수 지정 p_best = self.p_best[i] # 결과치 저장할 변수 지정
# 2. 속도 계산 # 2. 속도 계산
self.velocities[i] = self._update_velocity( self.velocities[i] = self._update_velocity(
weights, v, p_best, c0, c1, w) weights, v, p_best, c0, c1, w
)
# 다음에 움직일 속도 = 최초 위치, 현재 속도, 현재 위치, 최종 위치 # 다음에 움직일 속도 = 최초 위치, 현재 속도, 현재 위치, 최종 위치
# 3. 위치 업데이트 # 3. 위치 업데이트
self.particles_weights[i] = self._update_weights(weights, v) self.particles_weights[i] = self._update_weights(weights, v)
@@ -224,8 +246,9 @@ class PSO(object):
self.model.set_weights(self.particles_weights[i]) self.model.set_weights(self.particles_weights[i])
# self.particles_weights[i] = self.model.get_weights() # self.particles_weights[i] = self.model.get_weights()
# 4. 평가 # 4. 평가
self.model.compile(loss=self.loss_method, self.model.compile(
optimizer='sgd', metrics=['accuracy']) loss=self.loss_method, optimizer="sgd", metrics=["accuracy"]
)
score = self._get_score(x_, y_) score = self._get_score(x_, y_)
if score[1] > self.p_best_score[i]: if score[1] > self.p_best_score[i]:
@@ -234,18 +257,25 @@ class PSO(object):
if score[1] > self.g_best_score: if score[1] > self.g_best_score:
self.g_best_score = score[1] self.g_best_score = score[1]
self.g_best = self.particles_weights[i] self.g_best = self.particles_weights[i]
if save: if save:
with open(f"{save_path}/{day}_{self.n_particles}_{maxiter}_{c0}_{c1}_{w}.csv",'a')as f: with open(
f"{save_path}/{day}_{self.n_particles}_{maxiter}_{c0}_{c1}_{w}.csv",
"a",
) as f:
f.write(f"{score[0]}, {score[1]}") f.write(f"{score[0]}, {score[1]}")
if i != self.n_particles - 1: if i != self.n_particles - 1:
f.write(",") f.write(",")
if save: if save:
with open(f"{save_path}/{day}_{self.n_particles}_{maxiter}_{c0}_{c1}_{w}.csv",'a')as f: with open(
f"{save_path}/{day}_{self.n_particles}_{maxiter}_{c0}_{c1}_{w}.csv",
"a",
) as f:
f.write("\n") f.write("\n")
print( print(
f"loss avg : {score[0]/self.n_particles} | acc avg : {score[1]/self.n_particles} | best score : {self.g_best_score}") f"loss avg : {score[0]/self.n_particles} | acc avg : {score[1]/self.n_particles} | best score : {self.g_best_score}"
)
gc.collect() gc.collect()
# 전체 최소 위치, 전체 최소 벡터 # 전체 최소 위치, 전체 최소 벡터
@@ -265,4 +295,4 @@ class PSO(object):
""" """
def best_score(self): def best_score(self):
return self.g_best_score return self.g_best_score

View File

@@ -12,7 +12,12 @@ class PSO(object):
Class implementing PSO algorithm Class implementing PSO algorithm
""" """
def __init__(self, model: keras.models, loss_method=keras.losses.MeanSquaredError(), n_particles: int = 5): def __init__(
self,
model: keras.models,
loss_method=keras.losses.MeanSquaredError(),
n_particles: int = 5,
):
""" """
Initialize the key variables. Initialize the key variables.
@@ -21,40 +26,41 @@ class PSO(object):
loss_method : 손실 함수 loss_method : 손실 함수
n_particles(int) : 파티클의 개수 n_particles(int) : 파티클의 개수
""" """
self.model = model # 모델 self.model = model # 모델
self.n_particles = n_particles # 파티클의 개수 self.n_particles = n_particles # 파티클의 개수
self.loss_method = loss_method # 손실 함수 self.loss_method = loss_method # 손실 함수
self.model_structure = self.model.to_json() # 모델의 구조 정보 self.model_structure = self.model.to_json() # 모델의 구조 정보
self.init_weights = self.model.get_weights() # 검색할 차원 self.init_weights = self.model.get_weights() # 검색할 차원
self.particle_depth = len(self.model.get_weights()) # 검색할 차원의 깊이 self.particle_depth = len(self.model.get_weights()) # 검색할 차원의 깊이
self.particles_weights = [None] * n_particles # 파티클의 위치 self.particles_weights = [None] * n_particles # 파티클의 위치
for _ in tqdm(range(self.n_particles), desc="init particles position"): for _ in tqdm(range(self.n_particles), desc="init particles position"):
m = keras.models.model_from_json(self.model_structure) m = keras.models.model_from_json(self.model_structure)
m.compile(loss=self.loss_method, m.compile(loss=self.loss_method, optimizer="adam", metrics=["accuracy"])
optimizer="adam", metrics=["accuracy"])
self.particles_weights[_] = m.get_weights() self.particles_weights[_] = m.get_weights()
# 입력받은 파티클의 개수 * 검색할 차원의 크기 만큼의 균등한 위치를 생성 # 입력받은 파티클의 개수 * 검색할 차원의 크기 만큼의 균등한 위치를 생성
self.velocities = [ self.velocities = [
[0 for i in range(self.particle_depth)] for n in range(n_particles)] [0 for i in range(self.particle_depth)] for n in range(n_particles)
]
for i in tqdm(range(n_particles), desc="init velocities"): for i in tqdm(range(n_particles), desc="init velocities"):
for index, layer in enumerate(self.init_weights): for index, layer in enumerate(self.init_weights):
self.velocities[i][index] = np.random.rand( self.velocities[i][index] = np.random.rand(*layer.shape) / 5 - 0.10
*layer.shape) / 5 - 0.10
# 입력받은 파티클의 개수 * 검색할 차원의 크기 만큼의 속도를 무작위로 초기화 # 입력받은 파티클의 개수 * 검색할 차원의 크기 만큼의 속도를 무작위로 초기화
# 최대 사이즈로 전역 최적갑 저장 - global best # 최대 사이즈로 전역 최적갑 저장 - global best
self.p_best = self.particles_weights # 각 파티클의 최적값(최적의 가중치) self.p_best = self.particles_weights # 각 파티클의 최적값(최적의 가중치)
self.g_best = self.model.get_weights() # 전역 최적값(최적의 가중치) | 초기값은 모델의 가중치 self.g_best = (
self.model.get_weights()
) # 전역 최적값(최적의 가중치) | 초기값은 모델의 가중치
# 각 파티클의 최적값의 점수 # 각 파티클의 최적값의 점수
self.p_best_score = [0 for i in range(n_particles)] self.p_best_score = [0 for i in range(n_particles)]
# 전역 최적값의 점수(초기화 - 0) # 전역 최적값의 점수(초기화 - 0)
self.g_best_score = 0 self.g_best_score = 0
self.loss_history = [[] for i in range(n_particles)] # 각 파티클의 손실값 변화 self.loss_history = [[] for i in range(n_particles)] # 각 파티클의 손실값 변화
self.acc_history = [[] for i in range(n_particles)] # 각 파티클의 정확도 변화 self.acc_history = [[] for i in range(n_particles)] # 각 파티클의 정확도 변화
self.g_best_score_history = [] # 전역 최적값의 점수 변화 self.g_best_score_history = [] # 전역 최적값의 점수 변화
def _update_weights(self, weights, v): def _update_weights(self, weights, v):
""" """
@@ -73,22 +79,22 @@ class PSO(object):
for i in range(len(weights)): for i in range(len(weights)):
new_weights[i] = tf.add(weights[i], v[i]) new_weights[i] = tf.add(weights[i], v[i])
# new_w = tf.add(w, v) # 각 파티클을 랜덤한 속도만큼 진행 # new_w = tf.add(w, v) # 각 파티클을 랜덤한 속도만큼 진행
return new_weights # 진행한 파티클들의 위치를 반환 return new_weights # 진행한 파티클들의 위치를 반환
def _update_velocity(self, weights, v, p_best, c0=0.5, c1=1.5, w=0.75): def _update_velocity(self, weights, v, p_best, c0=0.5, c1=1.5, w=0.75):
""" """
Update particle velocity Update particle velocity
Args: Args:
weights (array-like) : 파티클의 현재 가중치 weights (array-like) : 파티클의 현재 가중치
v (array-like) : 속도 v (array-like) : 속도
p_best(array-like) : 각 파티클의 최적의 위치 (최적의 가중치) p_best(array-like) : 각 파티클의 최적의 위치 (최적의 가중치)
c0 (float) : 인지 스케일링 상수 (가중치의 중요도 - 지역) - 지역 관성 c0 (float) : 인지 스케일링 상수 (가중치의 중요도 - 지역) - 지역 관성
c1 (float) : 사회 스케일링 상수 (가중치의 중요도 - 전역) - 전역 관성 c1 (float) : 사회 스케일링 상수 (가중치의 중요도 - 전역) - 전역 관성
w (float) : 관성 상수 (현재 속도의 중요도) w (float) : 관성 상수 (현재 속도의 중요도)
Returns: Returns:
(array-like) : 각 파티클의 새로운 속도 (array-like) : 각 파티클의 새로운 속도
""" """
# x = np.array(x) # x = np.array(x)
# v = np.array(v) # v = np.array(v)
@@ -106,9 +112,9 @@ class PSO(object):
new_velocity = [None] * len(weights) new_velocity = [None] * len(weights)
for i, layer in enumerate(weights): for i, layer in enumerate(weights):
new_v = w*v[i] new_v = w * v[i]
new_v = new_v + c0*r0*(p_best[i] - layer) new_v = new_v + c0 * r0 * (p_best[i] - layer)
new_v = new_v + c1*r1*(self.g_best[i] - layer) new_v = new_v + c1 * r1 * (self.g_best[i] - layer)
new_velocity[i] = new_v new_velocity[i] = new_v
# new_v = w*v + c0*r0*(p_best - weights) + c1*r1*(g_best - weights) # new_v = w*v + c0*r0*(p_best - weights) + c1*r1*(g_best - weights)
@@ -141,13 +147,16 @@ class PSO(object):
""" """
for _ in range(maxiter): for _ in range(maxiter):
for i in tqdm(range(self.n_particles), desc=f"Iter {_}/{maxiter} ", ascii=True): for i in tqdm(
range(self.n_particles), desc=f"Iter {_}/{maxiter} ", ascii=True
):
weights = self.particles_weights[i] # 각 파티클 추출 weights = self.particles_weights[i] # 각 파티클 추출
v = self.velocities[i] # 각 파티클의 다음 속도 추출 v = self.velocities[i] # 각 파티클의 다음 속도 추출
p_best = self.p_best[i] # 결과치 저장할 변수 지정 p_best = self.p_best[i] # 결과치 저장할 변수 지정
# 2. 속도 계산 # 2. 속도 계산
self.velocities[i] = self._update_velocity( self.velocities[i] = self._update_velocity(
weights, v, p_best, c0, c1, w) weights, v, p_best, c0, c1, w
)
# 다음에 움직일 속도 = 최초 위치, 현재 속도, 현재 위치, 최종 위치 # 다음에 움직일 속도 = 최초 위치, 현재 속도, 현재 위치, 최종 위치
# 3. 위치 업데이트 # 3. 위치 업데이트
self.particles_weights[i] = self._update_weights(weights, v) self.particles_weights[i] = self._update_weights(weights, v)
@@ -156,8 +165,9 @@ class PSO(object):
self.model.set_weights(self.particles_weights[i].copy()) self.model.set_weights(self.particles_weights[i].copy())
# self.particles_weights[i] = self.model.get_weights() # self.particles_weights[i] = self.model.get_weights()
# 4. 평가 # 4. 평가
self.model.compile(loss=self.loss_method, self.model.compile(
optimizer='adam', metrics=['accuracy']) loss=self.loss_method, optimizer="adam", metrics=["accuracy"]
)
score = self._get_score(x_, y_) score = self._get_score(x_, y_)
if score[1] > self.p_best_score[i]: if score[1] > self.p_best_score[i]:
@@ -166,14 +176,14 @@ class PSO(object):
if score[1] > self.g_best_score: if score[1] > self.g_best_score:
self.g_best_score = score[1] self.g_best_score = score[1]
self.g_best = self.particles_weights[i].copy() self.g_best = self.particles_weights[i].copy()
self.g_best_score_history.append( self.g_best_score_history.append(self.g_best_score)
self.g_best_score)
self.loss_history[i].append(score[0]) self.loss_history[i].append(score[0])
self.acc_history[i].append(score[1]) self.acc_history[i].append(score[1])
print( print(
f"loss avg : {score[0]/self.n_particles} | acc avg : {score[1]/self.n_particles} | best score : {self.g_best_score}") f"loss avg : {score[0]/self.n_particles} | acc avg : {score[1]/self.n_particles} | best score : {self.g_best_score}"
)
# 전체 최소 위치, 전체 최소 벡터 # 전체 최소 위치, 전체 최소 벡터
return self.g_best, self._get_score(x_, y_) return self.g_best, self._get_score(x_, y_)
@@ -193,6 +203,7 @@ class PSO(object):
def best_score(self): def best_score(self):
return self.g_best_score return self.g_best_score
""" """
Returns: Returns:
global best score 의 갱신된 값의 변화를 반환 global best score 의 갱신된 값의 변화를 반환

View File

@@ -83,30 +83,30 @@ class Optimizer:
try: try:
if model is None: if model is None:
raise ValueError("model is None") raise ValueError("model is None")
if model is not None and not isinstance(model, keras.models.Model): elif model is not None and not isinstance(model, keras.models.Model):
raise ValueError("model is not keras.models.Model") raise ValueError("model is not keras.models.Model")
if loss is None: elif loss is None:
raise ValueError("loss is None") raise ValueError("loss is None")
if n_particles is None: elif n_particles is None:
raise ValueError("n_particles is None") raise ValueError("n_particles is None")
if n_particles < 1: elif n_particles < 1:
raise ValueError("n_particles < 1") raise ValueError("n_particles < 1")
if c0 < 0 or c1 < 0: elif c0 < 0 or c1 < 0:
raise ValueError("c0 or c1 < 0") raise ValueError("c0 or c1 < 0")
if np_seed is not None: elif np_seed is not None:
np.random.seed(np_seed) np.random.seed(np_seed)
if tf_seed is not None: elif tf_seed is not None:
tf.random.set_seed(tf_seed) tf.random.set_seed(tf_seed)
self.random_state = np.random.get_state() elif random_state is not None:
if random_state is not None:
np.random.set_state(random_state) np.random.set_state(random_state)
self.random_state = np.random.get_state()
model.compile(loss=loss, optimizer="adam", metrics=["accuracy", "mse"]) model.compile(loss=loss, optimizer="adam", metrics=["accuracy", "mse"])
self.model = model # 모델 구조 self.model = model # 모델 구조
self.loss = loss # 손실함수 self.loss = loss # 손실함수
@@ -116,8 +116,12 @@ class Optimizer:
self.c1 = c1 # global rate - 전역 최적값 관성 수치 self.c1 = c1 # global rate - 전역 최적값 관성 수치
self.w_min = w_min # 최소 관성 수치 self.w_min = w_min # 최소 관성 수치
self.w_max = w_max # 최대 관성 수치 self.w_max = w_max # 최대 관성 수치
self.negative_swarm = negative_swarm # 최적해와 반대로 이동할 파티클 비율 - 0 ~ 1 사이의 값 self.negative_swarm = (
self.mutation_swarm = mutation_swarm # 관성을 추가로 사용할 파티클 비율 - 0 ~ 1 사이의 값 negative_swarm # 최적해와 반대로 이동할 파티클 비율 - 0 ~ 1 사이의 값
)
self.mutation_swarm = (
mutation_swarm # 관성을 추가로 사용할 파티클 비율 - 0 ~ 1 사이의 값
)
self.avg_score = 0 # 평균 점수 self.avg_score = 0 # 평균 점수
# self.sigma = 1.0 # self.sigma = 1.0
@@ -136,9 +140,9 @@ class Optimizer:
self.particles[i] = Particle( self.particles[i] = Particle(
model, model,
self.loss, self.loss,
negative=True negative=(
if i < self.negative_swarm * self.n_particles True if i < self.negative_swarm * self.n_particles else False
else False, ),
mutation=self.mutation_swarm, mutation=self.mutation_swarm,
converge_reset=convergence_reset, converge_reset=convergence_reset,
converge_reset_patience=convergence_reset_patience, converge_reset_patience=convergence_reset_patience,