pypi 0.1.4 업데이트
keras 의 메모리 누수를 어느정도 해결했으나 아직 완벽히 해결이 되지 않음
입력 데이터를 tensor 형태로 변환해주어 넣는 방식으로 전환
This commit is contained in:
jung-geun
2023-07-21 15:20:24 +09:00
parent 23176bafb2
commit 99b1de3f82
9 changed files with 96 additions and 68 deletions

View File

@@ -1,4 +1,4 @@
name: Python Package Index publish name: PyPI package
on: [push] on: [push]

View File

@@ -1,3 +1,5 @@
[![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)
# PSO 알고리즘 구현 및 새로운 시도 # PSO 알고리즘 구현 및 새로운 시도
pso 알고리즘을 사용하여 새로운 학습 방법을 찾는중 입니다 pso 알고리즘을 사용하여 새로운 학습 방법을 찾는중 입니다
@@ -21,16 +23,24 @@ pso 알고리즘을 사용하여 새로운 학습 방법을 찾는중 입니다
> \end{cases} > \end{cases}
> $$ > $$
### 위치를 현재 전역해로 변경(덮어쓰기)하면 안되는 이유
위치를 가장 최적값으로 변경하면 지역 최적값에서 벗어나지 못합니다. 따라서 전역 최적값을 찾을 수 없습니다.
# 초기 세팅 # 초기 세팅
자동으로 conda 환경을 설정하기 위해서는 다음 명령어를 사용합니다
```shell ```shell
conda env create -f ./conda_env/environment.yaml conda env create -f ./conda_env/environment.yaml
``` ```
현재 python 3.9 버전, tensorflow 2.11 버전에서 테스트 되었습니다
</br>
직접 설치하여 사용할 경우 pso2keras 패키지를 pypi 에서 다운로드 받아서 사용하시기 바랍니다
```shell
pip install pso2keras==0.1.4
```
위의 패키지를 사용하기 위해서는 tensorflow 와 tensorboard 가 설치되어 있어야 합니다
# 현재 진행 상황 # 현재 진행 상황
## 1. PSO 알고리즘 구현 ## 1. PSO 알고리즘 구현
@@ -55,6 +65,7 @@ conda env create -f ./conda_env/environment.yaml
|-- mnist_tf.py # tensorflow 를 이용한 mnist 문제 풀이 |-- mnist_tf.py # tensorflow 를 이용한 mnist 문제 풀이
|-- plt.ipynb # pyplot 으로 학습 결과를 그래프로 표현 |-- plt.ipynb # pyplot 으로 학습 결과를 그래프로 표현
|-- README.md # 현재 파일 |-- README.md # 현재 파일
|-- requirements.txt # pypi 에서 다운로드 받을 패키지 목록
``` ```
pso 라이브러리는 tensorflow 모델을 학습하기 위해 기본 ./metacode/pso_meta.py 코드에서 수정하였습니다 [2] pso 라이브러리는 tensorflow 모델을 학습하기 위해 기본 ./metacode/pso_meta.py 코드에서 수정하였습니다 [2]
@@ -63,20 +74,12 @@ pso 라이브러리는 tensorflow 모델을 학습하기 위해 기본 ./metacod
pso 알고리즘을 이용하여 오차역전파 함수를 최적화 하는 방법을 찾는 중입니다 pso 알고리즘을 이용하여 오차역전파 함수를 최적화 하는 방법을 찾는 중입니다
### 브레인스토밍 ### 알고리즘 작동 방식
> 1. 오차역전파 함수를 1~5회 실행하여 오차를 구합니다 > 1. 파티클의 위치와 속도를 초기화 한다.
> 2. 오차가 가장 적은 다른 노드(particle) 가중치로 유도합니다. > 2. 각 파티클의 점수를 계산한다.
> > 3. 각 파티클의 지역 최적해와 전역 최적해를 구한다.
> > 2-1. 만약 오차가 가장 작은 다른 노드가 현재 노드보다 오차가 크다면, 현재 노드의 가중치를 유지합니다. - 현재의 가중치를 최적값으로 업로드합니다 > 4. 각 파티클의 속도를 업데이트 한다.
> >
> > 2-2. 지역 최적값을 찾았다면, 전역 최적값을 찾을 때까지 1~2 과정을 반복합니다
>
> 3. 전역 최적값이 특정 임계치에서 변화율이 적다면 학습을 종료합니다 - 현재 결과가 정확도가 높지 않아서 이 기능은 추후에 추가할 예정입니다
</br>
위의 아이디어는 원래의 목표와 다른 방향으로 가고 있습니다. 따라서 다른 방법을 모색해야할 것 같습니다
</br>
## 3. PSO 알고리즘을 이용하여 풀이한 문제들의 정확도 ## 3. PSO 알고리즘을 이용하여 풀이한 문제들의 정확도
@@ -160,30 +163,33 @@ loss = 'mean_squared_error'
pso_mnist = Optimizer( pso_mnist = Optimizer(
model, model,
loss=loss, loss=loss,
n_particles=75, n_particles=100,
c0=0.25, c0=0.3,
c1=0.4, c1=0.5,
w_min=0.2, w_min=0.4,
w_max=0.6, w_max=0.7,
negative_swarm=0.1, negative_swarm=0.1,
mutation_swarm=0.2, mutation_swarm=0.2,
particle_min=-5,
particle_max=5,
) )
best_score = pso_mnist.fit( best_score = pso_mnist.fit(
x_test, x_train,
y_test, y_train,
epochs=200, epochs=200,
save=True, save_info=True,
log=2,
log_name="mnist",
save_path="./result/mnist", save_path="./result/mnist",
renewal="acc", renewal="acc",
empirical_balance=False, check_point=25,
Dispersion=False,
check_point=25
) )
``` ```
위의 파라미터 기준 현재 정확도 43.38%를 보이고 있습니다 위의 파라미터 기준 현재 정확도 51.84%를 보이고 있습니다
![mnist](./history_plt/mnist_mse_43.38.png) ![mnist_acc](./history_plt/mnist_51.74_acc.png)
![mnist_loss](./history_plt/mnist_51.74_loss.png)
### Trouble Shooting ### Trouble Shooting
@@ -194,13 +200,20 @@ best_score = pso_mnist.fit(
> 2. 지역최적값에 계속 머무르는 조기 수렴 현상이 나타난다. - 30% 정도의 정확도를 가진다 > 2. 지역최적값에 계속 머무르는 조기 수렴 현상이 나타난다. - 30% 정도의 정확도를 가진다
-> 지역최적값에 머무르는 것을 방지하기 위해 negative_swarm, mutation_swarm 파라미터를 추가하였습니다 - 현재 43% 정도의 정확도를 보이고 있습니다 -> 지역최적값에 머무르는 것을 방지하기 위해 negative_swarm, mutation_swarm 파라미터를 추가하였습니다 - 현재 51% 정도의 정확도를 보이고 있습니다
> 3. 파티클의 수를 늘리면 전역 최적해에 좀더 가까워지는 현상을 발견하였다. 하지만 파티클의 수를 늘리면 메모리 사용량이 기하급수적으로 늘어난다.
-> keras 모델을 사용할때 predict, evaluate 함수를 사용하면 메모리 누수가 발생하는 문제를 찾았습니다. 해결방법을 추가로 찾아보는중 입니다.
-> 추가로 파티클의 수가 적을때에도 전역 최적해를 쉽게 찾는 방법을 찾는중 입니다
### 개인적인 생각 ### 개인적인 생각
> 머신러닝 분류 방식에 존재하는 random forest 방식을 이용하여, 오차역전파 함수를 최적화 하는 방법이 있을것 같습니다 > 머신러닝 분류 방식에 존재하는 random forest 방식을 이용하여, 오차역전파 함수를 최적화 하는 방법이 있을것 같습니다
> >
> > pso 와 random forest 방식이 매우 유사하다고 생각하여 학습할 때 뿐만 아니라 예측 할 때도 이러한 방식으로 사용할 수 있을 것 같습니다 > > pso 와 random forest 방식이 매우 유사하다고 생각하여 학습할 때 뿐만 아니라 예측 할 때도 이러한 방식으로 사용할 수 있을 것 같습니다
>
>
# 참고 자료 # 참고 자료

BIN
history_plt/mnist_51.74_acc.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 217 KiB

BIN
history_plt/mnist_51.74_loss.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 220 KiB

View File

@@ -1,4 +1,5 @@
# %% # %%
import json
import os import os
import sys import sys
@@ -6,6 +7,7 @@ os.environ["TF_CPP_MIN_LOG_LEVEL"] = "2"
import gc import gc
import numpy as np
import tensorflow as tf import tensorflow as tf
from keras.datasets import mnist from keras.datasets import mnist
from keras.layers import Conv2D, Dense, Dropout, Flatten, MaxPooling2D from keras.layers import Conv2D, Dense, Dropout, Flatten, MaxPooling2D
@@ -24,6 +26,9 @@ def get_data():
y_train, y_test = tf.one_hot(y_train, 10), tf.one_hot(y_test, 10) y_train, y_test = tf.one_hot(y_train, 10), tf.one_hot(y_test, 10)
x_train, x_test = tf.convert_to_tensor(x_train), tf.convert_to_tensor(x_test)
y_train, y_test = tf.convert_to_tensor(y_train), tf.convert_to_tensor(y_test)
print(f"x_train : {x_train[0].shape} | y_train : {y_train[0].shape}") print(f"x_train : {x_train[0].shape} | y_train : {y_train[0].shape}")
print(f"x_test : {x_test[0].shape} | y_test : {y_test[0].shape}") print(f"x_test : {x_test[0].shape} | y_test : {y_test[0].shape}")
@@ -37,6 +42,9 @@ def get_data_test():
y_test = tf.one_hot(y_test, 10) y_test = tf.one_hot(y_test, 10)
x_test = tf.convert_to_tensor(x_test)
y_test = tf.convert_to_tensor(y_test)
print(f"x_test : {x_test[0].shape} | y_test : {y_test[0].shape}") print(f"x_test : {x_test[0].shape} | y_test : {y_test[0].shape}")
return x_test, y_test return x_test, y_test
@@ -58,6 +66,23 @@ def make_model():
return model return model
def random_state():
with open(
"result/mnist/20230720-192726/mean_squared_error_[0.4970000088214874, 0.10073449462652206].json",
"r",
) as f:
json_ = json.load(f)
rs = (
json_["random_state_0"],
np.array(json_["random_state_1"]),
json_["random_state_2"],
json_["random_state_3"],
json_["random_state_4"],
)
return rs
# %% # %%
model = make_model() model = make_model()
x_train, y_train = get_data_test() x_train, y_train = get_data_test()
@@ -76,15 +101,16 @@ loss = [
"mean_absolute_percentage_error", "mean_absolute_percentage_error",
] ]
# rs = random_state()
pso_mnist = Optimizer( pso_mnist = Optimizer(
model, model,
loss=loss[0], loss=loss[0],
n_particles=70, n_particles=100,
c0=0.3, c0=0.25,
c1=0.5, c1=0.4,
w_min=0.4, w_min=0.3,
w_max=0.7, w_max=0.9,
negative_swarm=0.1, negative_swarm=0.1,
mutation_swarm=0.2, mutation_swarm=0.2,
particle_min=-5, particle_min=-5,
@@ -105,5 +131,4 @@ best_score = pso_mnist.fit(
print("Done!") print("Done!")
gc.collect()
sys.exit(0) sys.exit(0)

View File

@@ -1,7 +1,7 @@
from .optimizer import Optimizer from .optimizer import Optimizer
from .particle import Particle from .particle import Particle
__version__ = "0.1.3" __version__ = "0.1.4"
__all__ = [ __all__ = [
"Optimizer", "Optimizer",

View File

@@ -38,6 +38,7 @@ class Optimizer:
mutation_swarm: float = 0, mutation_swarm: float = 0,
np_seed: int = None, np_seed: int = None,
tf_seed: int = None, tf_seed: int = None,
random_state: tuple = None,
particle_min: float = -5, particle_min: float = -5,
particle_max: float = 5, particle_max: float = 5,
): ):
@@ -66,6 +67,9 @@ class Optimizer:
self.random_state = np.random.get_state() self.random_state = np.random.get_state()
if random_state is not None:
np.random.set_state(random_state)
self.model = model # 모델 구조 self.model = model # 모델 구조
self.loss = loss # 손실함수 self.loss = loss # 손실함수
self.n_particles = n_particles # 파티클 개수 self.n_particles = n_particles # 파티클 개수
@@ -113,6 +117,8 @@ class Optimizer:
print(f"mutation swarm : {mutation_swarm * 100}%") print(f"mutation swarm : {mutation_swarm * 100}%")
gc.collect() gc.collect()
tf.keras.backend.reset_uids()
tf.keras.backend.clear_session()
def __del__(self): def __del__(self):
del self.model del self.model
@@ -129,6 +135,8 @@ class Optimizer:
del self.g_best_ del self.g_best_
del self.avg_score del self.avg_score
gc.collect() gc.collect()
tf.keras.backend.reset_uids()
tf.keras.backend.clear_session()
def _encode(self, weights): def _encode(self, weights):
""" """
@@ -304,7 +312,8 @@ class Optimizer:
tf.summary.scalar("accuracy", local_score[1], step=0) tf.summary.scalar("accuracy", local_score[1], step=0)
del local_score del local_score
gc.collect() gc.collect()
tf.keras.backend.reset_uids()
tf.keras.backend.clear_session()
print( print(
f"initial g_best_score : {self.g_best_score[0] if self.renewal == 'acc' else self.g_best_score[1]}" f"initial g_best_score : {self.g_best_score[0] if self.renewal == 'acc' else self.g_best_score[1]}"
) )
@@ -454,7 +463,9 @@ class Optimizer:
f.write(", ") f.write(", ")
else: else:
f.write("\n") f.write("\n")
# gc.collect()
# tf.keras.backend.reset_uids()
# tf.keras.backend.clear_session()
part_pbar.refresh() part_pbar.refresh()
if check_point is not None: if check_point is not None:
@@ -463,6 +474,8 @@ class Optimizer:
self._check_point_save(f"./{save_path}/{self.day}/ckpt-{epoch}") self._check_point_save(f"./{save_path}/{self.day}/ckpt-{epoch}")
gc.collect() gc.collect()
tf.keras.backend.reset_uids()
tf.keras.backend.clear_session()
except KeyboardInterrupt: except KeyboardInterrupt:
print("Ctrl + C : Stop Training") print("Ctrl + C : Stop Training")

View File

@@ -1,6 +1,7 @@
import gc import gc
import numpy as np import numpy as np
import tensorflow as tf
from tensorflow import keras from tensorflow import keras
@@ -37,7 +38,6 @@ class Particle:
del i_w_, s_, l_ del i_w_, s_, l_
del init_weights del init_weights
gc.collect()
def __del__(self): def __del__(self):
del self.model del self.model
@@ -46,7 +46,6 @@ class Particle:
del self.negative del self.negative
del self.best_score del self.best_score
del self.best_weights del self.best_weights
gc.collect()
def _encode(self, weights: list): def _encode(self, weights: list):
""" """
@@ -109,7 +108,7 @@ class Particle:
(float): 점수 (float): 점수
""" """
self.model.compile(loss=self.loss, optimizer="sgd", metrics=["accuracy"]) self.model.compile(loss=self.loss, optimizer="sgd", metrics=["accuracy"])
score = self.model.evaluate(x, y, verbose=0) score = self.model.evaluate(x, y, verbose=0, use_multiprocessing=True)
if renewal == "acc": if renewal == "acc":
if score[1] > self.best_score: if score[1] > self.best_score:
self.best_score = score[1] self.best_score = score[1]
@@ -221,26 +220,6 @@ class Particle:
del encode_w, w_sh, w_len del encode_w, w_sh, w_len
del encode_v, v_sh, v_len del encode_v, v_sh, v_len
def f(self, x, y, weights):
"""
EBPSO의 목적함수(예상)
Args:
x (list): 입력 데이터
y (list): 출력 데이터
weights (list): 가중치
Returns:
float: 목적함수 값
"""
self.model.set_weights(weights)
score = self.model.evaluate(x, y, verbose=0)[1]
if score > 0:
return 1 / (1 + score)
else:
return 1 + np.abs(score)
def step(self, x, y, local_rate, global_rate, w, g_best, renewal: str = "acc"): def step(self, x, y, local_rate, global_rate, w, g_best, renewal: str = "acc"):
""" """
파티클의 한 스텝을 진행합니다. 파티클의 한 스텝을 진행합니다.

View File

@@ -12,16 +12,14 @@ setup(
author_email="jgbong0306@gmail.com", author_email="jgbong0306@gmail.com",
url="https://github.com/jung-geun/PSO", url="https://github.com/jung-geun/PSO",
install_requires=[ install_requires=[
"tqdm==4.65.0", "tqdm",
"tensorflow==2.11.1",
"tensorboard==2.11.2",
"numpy", "numpy",
"pandas", "pandas",
"ipython", "ipython",
], ],
packages=find_packages(exclude=[]), packages=find_packages(exclude=[]),
keywords=["pso", "tensorflow", "keras"], keywords=["pso", "tensorflow", "keras"],
python_requires="==3.8", python_requires="==3.9",
package_data={}, package_data={},
zip_safe=False, zip_safe=False,
long_description=open("README.md", encoding="UTF8").read(), long_description=open("README.md", encoding="UTF8").read(),