mirror of
https://github.com/jung-geun/PSO.git
synced 2025-12-19 20:44:39 +09:00
23-07-21
pypi 0.1.4 업데이트 keras 의 메모리 누수를 어느정도 해결했으나 아직 완벽히 해결이 되지 않음 입력 데이터를 tensor 형태로 변환해주어 넣는 방식으로 전환
This commit is contained in:
2
.github/workflows/pypi.yml
vendored
2
.github/workflows/pypi.yml
vendored
@@ -1,4 +1,4 @@
|
||||
name: Python Package Index publish
|
||||
name: PyPI package
|
||||
|
||||
on: [push]
|
||||
|
||||
|
||||
75
README.md
75
README.md
@@ -1,3 +1,5 @@
|
||||
[](https://github.com/jung-geun/PSO/actions/workflows/pypi.yml)
|
||||
|
||||
# PSO 알고리즘 구현 및 새로운 시도
|
||||
|
||||
pso 알고리즘을 사용하여 새로운 학습 방법을 찾는중 입니다
|
||||
@@ -21,16 +23,24 @@ pso 알고리즘을 사용하여 새로운 학습 방법을 찾는중 입니다
|
||||
> \end{cases}
|
||||
> $$
|
||||
|
||||
### 위치를 현재 전역해로 변경(덮어쓰기)하면 안되는 이유
|
||||
|
||||
위치를 가장 최적값으로 변경하면 지역 최적값에서 벗어나지 못합니다. 따라서 전역 최적값을 찾을 수 없습니다.
|
||||
|
||||
# 초기 세팅
|
||||
|
||||
자동으로 conda 환경을 설정하기 위해서는 다음 명령어를 사용합니다
|
||||
|
||||
```shell
|
||||
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 알고리즘 구현
|
||||
@@ -55,6 +65,7 @@ conda env create -f ./conda_env/environment.yaml
|
||||
|-- mnist_tf.py # tensorflow 를 이용한 mnist 문제 풀이
|
||||
|-- plt.ipynb # pyplot 으로 학습 결과를 그래프로 표현
|
||||
|-- README.md # 현재 파일
|
||||
|-- requirements.txt # pypi 에서 다운로드 받을 패키지 목록
|
||||
```
|
||||
|
||||
pso 라이브러리는 tensorflow 모델을 학습하기 위해 기본 ./metacode/pso_meta.py 코드에서 수정하였습니다 [2]
|
||||
@@ -63,20 +74,12 @@ pso 라이브러리는 tensorflow 모델을 학습하기 위해 기본 ./metacod
|
||||
|
||||
pso 알고리즘을 이용하여 오차역전파 함수를 최적화 하는 방법을 찾는 중입니다
|
||||
|
||||
### 브레인스토밍
|
||||
### 알고리즘 작동 방식
|
||||
|
||||
> 1. 오차역전파 함수를 1~5회 실행하여 오차를 구합니다
|
||||
> 2. 오차가 가장 적은 다른 노드(particle) 가중치로 유도합니다.
|
||||
>
|
||||
> > 2-1. 만약 오차가 가장 작은 다른 노드가 현재 노드보다 오차가 크다면, 현재 노드의 가중치를 유지합니다. - 현재의 가중치를 최적값으로 업로드합니다
|
||||
> >
|
||||
> > 2-2. 지역 최적값을 찾았다면, 전역 최적값을 찾을 때까지 1~2 과정을 반복합니다
|
||||
>
|
||||
> 3. 전역 최적값이 특정 임계치에서 변화율이 적다면 학습을 종료합니다 - 현재 결과가 정확도가 높지 않아서 이 기능은 추후에 추가할 예정입니다
|
||||
|
||||
</br>
|
||||
위의 아이디어는 원래의 목표와 다른 방향으로 가고 있습니다. 따라서 다른 방법을 모색해야할 것 같습니다
|
||||
</br>
|
||||
> 1. 파티클의 위치와 속도를 초기화 한다.
|
||||
> 2. 각 파티클의 점수를 계산한다.
|
||||
> 3. 각 파티클의 지역 최적해와 전역 최적해를 구한다.
|
||||
> 4. 각 파티클의 속도를 업데이트 한다.
|
||||
|
||||
## 3. PSO 알고리즘을 이용하여 풀이한 문제들의 정확도
|
||||
|
||||
@@ -160,30 +163,33 @@ loss = 'mean_squared_error'
|
||||
pso_mnist = Optimizer(
|
||||
model,
|
||||
loss=loss,
|
||||
n_particles=75,
|
||||
c0=0.25,
|
||||
c1=0.4,
|
||||
w_min=0.2,
|
||||
w_max=0.6,
|
||||
n_particles=100,
|
||||
c0=0.3,
|
||||
c1=0.5,
|
||||
w_min=0.4,
|
||||
w_max=0.7,
|
||||
negative_swarm=0.1,
|
||||
mutation_swarm=0.2,
|
||||
particle_min=-5,
|
||||
particle_max=5,
|
||||
)
|
||||
|
||||
best_score = pso_mnist.fit(
|
||||
x_test,
|
||||
y_test,
|
||||
x_train,
|
||||
y_train,
|
||||
epochs=200,
|
||||
save=True,
|
||||
save_info=True,
|
||||
log=2,
|
||||
log_name="mnist",
|
||||
save_path="./result/mnist",
|
||||
renewal="acc",
|
||||
empirical_balance=False,
|
||||
Dispersion=False,
|
||||
check_point=25
|
||||
check_point=25,
|
||||
)
|
||||
```
|
||||
|
||||
위의 파라미터 기준 현재 정확도 43.38%를 보이고 있습니다
|
||||

|
||||
위의 파라미터 기준 현재 정확도 51.84%를 보이고 있습니다
|
||||

|
||||

|
||||
|
||||
### Trouble Shooting
|
||||
|
||||
@@ -194,13 +200,20 @@ best_score = pso_mnist.fit(
|
||||
|
||||
> 2. 지역최적값에 계속 머무르는 조기 수렴 현상이 나타난다. - 30% 정도의 정확도를 가진다
|
||||
|
||||
-> 지역최적값에 머무르는 것을 방지하기 위해 negative_swarm, mutation_swarm 파라미터를 추가하였습니다 - 현재 43% 정도의 정확도를 보이고 있습니다
|
||||
-> 지역최적값에 머무르는 것을 방지하기 위해 negative_swarm, mutation_swarm 파라미터를 추가하였습니다 - 현재 51% 정도의 정확도를 보이고 있습니다
|
||||
|
||||
> 3. 파티클의 수를 늘리면 전역 최적해에 좀더 가까워지는 현상을 발견하였다. 하지만 파티클의 수를 늘리면 메모리 사용량이 기하급수적으로 늘어난다.
|
||||
|
||||
-> keras 모델을 사용할때 predict, evaluate 함수를 사용하면 메모리 누수가 발생하는 문제를 찾았습니다. 해결방법을 추가로 찾아보는중 입니다.
|
||||
-> 추가로 파티클의 수가 적을때에도 전역 최적해를 쉽게 찾는 방법을 찾는중 입니다
|
||||
|
||||
### 개인적인 생각
|
||||
|
||||
> 머신러닝 분류 방식에 존재하는 random forest 방식을 이용하여, 오차역전파 함수를 최적화 하는 방법이 있을것 같습니다
|
||||
>
|
||||
> > pso 와 random forest 방식이 매우 유사하다고 생각하여 학습할 때 뿐만 아니라 예측 할 때도 이러한 방식으로 사용할 수 있을 것 같습니다
|
||||
>
|
||||
> 각
|
||||
|
||||
# 참고 자료
|
||||
|
||||
|
||||
BIN
history_plt/mnist_51.74_acc.png
Executable file
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
BIN
history_plt/mnist_51.74_loss.png
Executable file
Binary file not shown.
|
After Width: | Height: | Size: 220 KiB |
37
mnist.py
37
mnist.py
@@ -1,4 +1,5 @@
|
||||
# %%
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
|
||||
@@ -6,6 +7,7 @@ os.environ["TF_CPP_MIN_LOG_LEVEL"] = "2"
|
||||
|
||||
import gc
|
||||
|
||||
import numpy as np
|
||||
import tensorflow as tf
|
||||
from keras.datasets import mnist
|
||||
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)
|
||||
|
||||
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_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)
|
||||
|
||||
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}")
|
||||
|
||||
return x_test, y_test
|
||||
@@ -58,6 +66,23 @@ def make_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()
|
||||
x_train, y_train = get_data_test()
|
||||
@@ -76,15 +101,16 @@ loss = [
|
||||
"mean_absolute_percentage_error",
|
||||
]
|
||||
|
||||
# rs = random_state()
|
||||
|
||||
pso_mnist = Optimizer(
|
||||
model,
|
||||
loss=loss[0],
|
||||
n_particles=70,
|
||||
c0=0.3,
|
||||
c1=0.5,
|
||||
w_min=0.4,
|
||||
w_max=0.7,
|
||||
n_particles=100,
|
||||
c0=0.25,
|
||||
c1=0.4,
|
||||
w_min=0.3,
|
||||
w_max=0.9,
|
||||
negative_swarm=0.1,
|
||||
mutation_swarm=0.2,
|
||||
particle_min=-5,
|
||||
@@ -105,5 +131,4 @@ best_score = pso_mnist.fit(
|
||||
|
||||
print("Done!")
|
||||
|
||||
gc.collect()
|
||||
sys.exit(0)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
from .optimizer import Optimizer
|
||||
from .particle import Particle
|
||||
|
||||
__version__ = "0.1.3"
|
||||
__version__ = "0.1.4"
|
||||
|
||||
__all__ = [
|
||||
"Optimizer",
|
||||
|
||||
@@ -38,6 +38,7 @@ class Optimizer:
|
||||
mutation_swarm: float = 0,
|
||||
np_seed: int = None,
|
||||
tf_seed: int = None,
|
||||
random_state: tuple = None,
|
||||
particle_min: float = -5,
|
||||
particle_max: float = 5,
|
||||
):
|
||||
@@ -66,6 +67,9 @@ class Optimizer:
|
||||
|
||||
self.random_state = np.random.get_state()
|
||||
|
||||
if random_state is not None:
|
||||
np.random.set_state(random_state)
|
||||
|
||||
self.model = model # 모델 구조
|
||||
self.loss = loss # 손실함수
|
||||
self.n_particles = n_particles # 파티클 개수
|
||||
@@ -113,6 +117,8 @@ class Optimizer:
|
||||
print(f"mutation swarm : {mutation_swarm * 100}%")
|
||||
|
||||
gc.collect()
|
||||
tf.keras.backend.reset_uids()
|
||||
tf.keras.backend.clear_session()
|
||||
|
||||
def __del__(self):
|
||||
del self.model
|
||||
@@ -129,6 +135,8 @@ class Optimizer:
|
||||
del self.g_best_
|
||||
del self.avg_score
|
||||
gc.collect()
|
||||
tf.keras.backend.reset_uids()
|
||||
tf.keras.backend.clear_session()
|
||||
|
||||
def _encode(self, weights):
|
||||
"""
|
||||
@@ -304,7 +312,8 @@ class Optimizer:
|
||||
tf.summary.scalar("accuracy", local_score[1], step=0)
|
||||
del local_score
|
||||
gc.collect()
|
||||
|
||||
tf.keras.backend.reset_uids()
|
||||
tf.keras.backend.clear_session()
|
||||
print(
|
||||
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(", ")
|
||||
else:
|
||||
f.write("\n")
|
||||
|
||||
# gc.collect()
|
||||
# tf.keras.backend.reset_uids()
|
||||
# tf.keras.backend.clear_session()
|
||||
part_pbar.refresh()
|
||||
|
||||
if check_point is not None:
|
||||
@@ -463,6 +474,8 @@ class Optimizer:
|
||||
self._check_point_save(f"./{save_path}/{self.day}/ckpt-{epoch}")
|
||||
|
||||
gc.collect()
|
||||
tf.keras.backend.reset_uids()
|
||||
tf.keras.backend.clear_session()
|
||||
|
||||
except KeyboardInterrupt:
|
||||
print("Ctrl + C : Stop Training")
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import gc
|
||||
|
||||
import numpy as np
|
||||
import tensorflow as tf
|
||||
from tensorflow import keras
|
||||
|
||||
|
||||
@@ -37,7 +38,6 @@ class Particle:
|
||||
|
||||
del i_w_, s_, l_
|
||||
del init_weights
|
||||
gc.collect()
|
||||
|
||||
def __del__(self):
|
||||
del self.model
|
||||
@@ -46,7 +46,6 @@ class Particle:
|
||||
del self.negative
|
||||
del self.best_score
|
||||
del self.best_weights
|
||||
gc.collect()
|
||||
|
||||
def _encode(self, weights: list):
|
||||
"""
|
||||
@@ -109,7 +108,7 @@ class Particle:
|
||||
(float): 점수
|
||||
"""
|
||||
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 score[1] > self.best_score:
|
||||
self.best_score = score[1]
|
||||
@@ -221,26 +220,6 @@ class Particle:
|
||||
del encode_w, w_sh, w_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"):
|
||||
"""
|
||||
파티클의 한 스텝을 진행합니다.
|
||||
|
||||
6
setup.py
6
setup.py
@@ -12,16 +12,14 @@ setup(
|
||||
author_email="jgbong0306@gmail.com",
|
||||
url="https://github.com/jung-geun/PSO",
|
||||
install_requires=[
|
||||
"tqdm==4.65.0",
|
||||
"tensorflow==2.11.1",
|
||||
"tensorboard==2.11.2",
|
||||
"tqdm",
|
||||
"numpy",
|
||||
"pandas",
|
||||
"ipython",
|
||||
],
|
||||
packages=find_packages(exclude=[]),
|
||||
keywords=["pso", "tensorflow", "keras"],
|
||||
python_requires="==3.8",
|
||||
python_requires="==3.9",
|
||||
package_data={},
|
||||
zip_safe=False,
|
||||
long_description=open("README.md", encoding="UTF8").read(),
|
||||
|
||||
Reference in New Issue
Block a user