Skip to content

Commit

Permalink
Merge pull request #28 from N3PDF/migrate_tf2
Browse files Browse the repository at this point in the history
Migrate TF1 to TF2
  • Loading branch information
scarlehoff authored May 26, 2020
2 parents 5ebf3e1 + 2247cb9 commit b31d4e5
Show file tree
Hide file tree
Showing 11 changed files with 154 additions and 110 deletions.
6 changes: 3 additions & 3 deletions .github/workflows/pythonapp.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ jobs:

runs-on: ubuntu-latest
strategy:
max-parallel: 2
max-parallel: 3
matrix:
python-version: [3.6, 3.7]
python-version: [3.6, 3.7, 3.8]

steps:
- uses: actions/checkout@v1
Expand All @@ -20,6 +20,7 @@ jobs:
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install setuptools --upgrade
pip install .
- name: Lint with pylint
run: |
Expand All @@ -31,5 +32,4 @@ jobs:
- name: Test with pytest
run: |
pip install pytest
pip install tensorflow # Keras does not install any backend by default?
pytest
7 changes: 6 additions & 1 deletion .readthedocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,9 @@ sphinx:

python:
version: 3.7
pip_install: True
install:
- method: pip
path: .
extra_requirements:
- docs
system_packages: true
1 change: 1 addition & 0 deletions doc/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@

# The full version, including alpha/beta/rc tags
release = evolutionary_keras .__version__
autodoc_mock_imports = ['tensorflow']


# -- General configuration ---------------------------------------------------
Expand Down
31 changes: 18 additions & 13 deletions examples/test.py
Original file line number Diff line number Diff line change
@@ -1,21 +1,25 @@
""" Example implementation of evolutionary_keras
"""
import sys
import keras
from keras.datasets import mnist
from keras import backend as K
from keras.layers import Dense, Input, Flatten

import tensorflow as tf
from tensorflow.keras.datasets import mnist
from tensorflow.keras import backend as K
from tensorflow.keras.layers import Dense, Input, Flatten
from evolutionary_keras.models import EvolModel
import evolutionary_keras.optimizers

import logging
logging.basicConfig(level = logging.INFO)
logger = logging.getLogger()



batch_size = 128
num_classes = 10
dense_size = 16
epochs = 4000
epochs = 40

max_epochs = 40000
max_epochs = 400

# input image dimensions
img_rows, img_cols = 28, 28
Expand All @@ -41,8 +45,8 @@
print(x_test.shape[0], "test samples")

# convert class vectors to binary class matrices
y_train = keras.utils.to_categorical(y_train, num_classes)
y_test = keras.utils.to_categorical(y_test, num_classes)
y_train = tf.keras.utils.to_categorical(y_train, num_classes)
y_test = tf.keras.utils.to_categorical(y_test, num_classes)

inputs = Input(shape=(28, 28, 1))
flatten = Flatten()(inputs)
Expand All @@ -56,7 +60,7 @@
myopt = evolutionary_keras.optimizers.CMA(population_size=5, sigma_init=15)
epochs = 1
else:
myopt = evolutionary_keras.optimizers.NGA(population_size=20, sigma_init=15)
myopt = evolutionary_keras.optimizers.NGA(population_size=2, sigma_init=15)

print(" > Compiling the model")
model.compile(optimizer=myopt, loss="categorical_crossentropy", metrics=["accuracy"])
Expand All @@ -71,6 +75,7 @@
verbose=1,
# validation_data=(x_test, y_test)
)
score = model.evaluate(x=x_test, y=y_test, verbose=0)
print("Test loss:", score[0])
print("Test accuracy:", score[1])
score = model.evaluate(x=x_test, y=y_test, return_dict=True, verbose=0)

print("Test loss:", score['loss'])
print("Test accuracy:", score['accuracy'])
35 changes: 30 additions & 5 deletions setup.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,44 @@
from setuptools import setup, find_packages
from os import path
import os
import re

this_directory = path.abspath(path.dirname(__file__))
with open(path.join(this_directory, "README.md"), encoding="utf-8") as f:

requirements = ['numpy', 'cma']
if os.environ.get('READTHEDOCS') != 'True':
requirements.append('tensorflow>2.1*')
PACKAGE = 'evolutionary_keras'

this_directory = os.path.abspath(os.path.dirname(__file__))
with open(os.path.join(this_directory, "README.md"), encoding="utf-8") as f:
long_description = f.read()

def get_version():
""" Gets the version from the package's __init__ file
if there is some problem, let it happily fail """
VERSIONFILE = os.path.join('src', PACKAGE, '__init__.py')
initfile_lines = open(VERSIONFILE, 'rt').readlines()
VSRE = r"^__version__ = ['\"]([^'\"]*)['\"]"
for line in initfile_lines:
mo = re.search(VSRE, line, re.M)
if mo:
return mo.group(1)

setup(
name="evolutionary_keras",
version="1.0.1",
version=get_version(),
author="S. Carrazza, J. Cruz-Martinez, Roy Stegeman",
author_email="juan.cruz@mi.infn.it, roy.stegeman@mi.infn.it",
url="https://github.com/N3PDF/evolutionary_keras",
package_dir={"": "src"},
packages=find_packages("src"),
install_requires=["numpy", "keras", "sphinx_rtd_theme", "recommonmark", "cma"],
zip_safe=False,
install_requires=requirements,
extras_require={
'docs' : [
'sphinx_rtd_theme',
'recommonmark',
],
},
python_requires=">=3.6",
descriptions="An evolutionary algorithm implementation for Keras",
long_description=long_description,
Expand Down
2 changes: 1 addition & 1 deletion src/evolutionary_keras/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = "1.0.0"
__version__ = "1.9"
34 changes: 15 additions & 19 deletions src/evolutionary_keras/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,10 @@

import logging

from keras.callbacks.callbacks import History
from keras.models import Model
from tensorflow.keras.callbacks import History
from tensorflow.keras.models import Model

import evolutionary_keras.optimizers as Evolutionary_Optimizers
from evolutionary_keras.utilities import parse_eval

log = logging.getLogger(__name__)

Expand All @@ -27,15 +26,16 @@ def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.is_genetic = False
self.opt_instance = None
self.history = History()
self.history_info = History()

def parse_optimizer(self, optimizer):
""" Checks whether the optimizer is genetic and creates and optimizer instance in case a
string was given as input.
"""
# Checks (if the optimizer input is a string) and whether it is in the 'optimizers'
# dictionary
if isinstance(optimizer, str) and optimizer in optimizer_dict.keys():

if isinstance(optimizer, str) and optimizer.lower() in optimizer_dict.keys():
opt = optimizer_dict.get(optimizer.lower())
# And instanciate it with default values
optimizer = opt()
Expand All @@ -50,6 +50,7 @@ def compile(self, optimizer="rmsprop", **kwargs):
""" When the optimizer is genetic, compiles the model in keras setting an arbitrary
keras supported optimizer """
self.parse_optimizer(optimizer)
self.history_info.set_model(self)
if self.is_genetic:
super().compile(optimizer="rmsprop", **kwargs)
else:
Expand All @@ -71,7 +72,7 @@ def perform_genetic_fit(
verbose, prints to log.info the loss per epoch
"""
# Prepare the history for the initial epoch
self.history.on_train_begin()
self.history_info.on_train_begin()
# Validation data is currently not being used!!
if validation_data is not None:
log.warning(
Expand All @@ -84,29 +85,24 @@ def perform_genetic_fit(
"The optimizer determines the number of generations, epochs will be ignored."
)

metricas = self.metrics_names
for epoch in range(epochs):
# Generate the best mutant
score, best_mutant = self.opt_instance.run_step(x=x, y=y)

training_metric = next(iter(score))

# Ensure the best mutant is the current one
self.set_weights(best_mutant)
if verbose == 1:
loss = parse_eval(score)
loss = score[training_metric]
information = f" > epoch: {epoch+1}/{epochs}, {loss} "
log.info(information)

# Fill keras history
try:
history_data = dict(zip(metricas, score))
except TypeError as e:
# Maybe score was just one number, evil Keras
if parse_eval(score) == score:
score = [score, score]
history_data = dict(zip(metricas, score))
else:
raise e
self.history.on_epoch_end(epoch, history_data)
return self.history
history_data = score
self.history_info.on_epoch_end(epoch, history_data)

return self.history_info

def fit(self, x=None, y=None, validation_data=None, epochs=1, verbose=0, **kwargs):
""" If the optimizer is genetic, the fitting procedure consists on executing `run_step` for
Expand Down
Loading

0 comments on commit b31d4e5

Please sign in to comment.