keras/docs/autogen.py

430 lines
12 KiB
Python
Raw Normal View History

2015-12-12 20:39:22 +00:00
# -*- coding: utf-8 -*-
2016-04-07 00:34:25 +00:00
'''
General documentation architecture:
Home
Index
- Getting started
Getting started with the sequential model
Getting started with the functional api
Examples
FAQ
Installation guide
- Models
About Keras models
explain when one should use Sequential or functional API
explain compilation step
explain weight saving, weight loading
explain serialization, deserialization
Sequential
Model (functional API)
- Layers
About Keras layers
explain common layer functions: get_weights, set_weights, get_config
explain input_shape
explain usage on non-Keras tensors
Core layers
Convolutional
Recurrent
Embeddings
Normalization
Advanced activations
Noise
- Preprocessing
Image preprocessing
Text preprocessing
Sequence preprocessing
Objectives
Optimizers
Activations
Callbacks
Datasets
Backend
Initializations
Regularizers
Constraints
Visualization
Scikit-learn API
'''
2015-12-12 20:39:22 +00:00
from __future__ import print_function
from __future__ import unicode_literals
2015-12-12 20:39:22 +00:00
import re
import inspect
import os
import shutil
import sys
if sys.version[0] == '2':
reload(sys)
sys.setdefaultencoding('utf8')
2015-12-12 20:39:22 +00:00
from keras.layers import convolutional
from keras.layers import recurrent
from keras.layers import core
from keras.layers import noise
from keras.layers import normalization
from keras.layers import advanced_activations
from keras.layers import embeddings
2016-04-07 00:34:25 +00:00
from keras.layers import wrappers
2015-12-12 20:39:22 +00:00
from keras import optimizers
from keras import callbacks
from keras import models
2016-04-07 00:34:25 +00:00
from keras.engine import topology
from keras import objectives
from keras import backend
from keras import constraints
from keras import activations
from keras import regularizers
2016-06-06 17:18:09 +00:00
2016-04-07 00:34:25 +00:00
EXCLUDE = {
'Optimizer',
2016-04-07 21:23:34 +00:00
'Wrapper',
'get_session',
'set_session',
2016-08-01 00:45:32 +00:00
'CallbackList',
2016-04-07 00:34:25 +00:00
}
PAGES = [
{
'page': 'models/sequential.md',
'functions': [
models.Sequential.compile,
models.Sequential.fit,
models.Sequential.evaluate,
models.Sequential.predict,
models.Sequential.predict_classes,
models.Sequential.predict_proba,
models.Sequential.train_on_batch,
models.Sequential.test_on_batch,
models.Sequential.predict_on_batch,
models.Sequential.fit_generator,
models.Sequential.evaluate_generator,
],
},
{
'page': 'models/model.md',
'functions': [
models.Model.compile,
models.Model.fit,
models.Model.evaluate,
models.Model.predict,
models.Model.train_on_batch,
models.Model.test_on_batch,
models.Model.predict_on_batch,
models.Model.fit_generator,
models.Model.evaluate_generator,
models.Model.get_layer,
]
},
{
'page': 'layers/core.md',
'classes': [
core.Dense,
core.Activation,
core.Dropout,
core.Flatten,
core.Reshape,
core.Permute,
core.RepeatVector,
topology.Merge,
core.Lambda,
core.ActivityRegularization,
core.Masking,
core.Highway,
core.MaxoutDense,
core.TimeDistributedDense,
],
},
{
'page': 'layers/convolutional.md',
'classes': [
convolutional.Convolution1D,
convolutional.Convolution2D,
2016-07-13 19:35:11 +00:00
convolutional.AtrousConv2D,
2016-04-07 00:34:25 +00:00
convolutional.Convolution3D,
convolutional.UpSampling1D,
convolutional.UpSampling2D,
convolutional.UpSampling3D,
convolutional.ZeroPadding1D,
convolutional.ZeroPadding2D,
convolutional.ZeroPadding3D,
],
},
2016-07-13 19:35:11 +00:00
{
'page': 'layers/pooling.md',
'classes': [
convolutional.MaxPooling1D,
convolutional.MaxPooling2D,
convolutional.MaxPooling3D,
convolutional.AveragePooling1D,
convolutional.AveragePooling2D,
convolutional.AveragePooling3D,
],
},
2016-04-07 00:34:25 +00:00
{
'page': 'layers/recurrent.md',
'classes': [
recurrent.Recurrent,
recurrent.SimpleRNN,
recurrent.GRU,
recurrent.LSTM,
],
},
{
'page': 'layers/embeddings.md',
'classes': [
embeddings.Embedding,
],
},
{
'page': 'layers/normalization.md',
'classes': [
normalization.BatchNormalization,
],
},
{
'page': 'layers/advanced-activations.md',
'all_module_classes': [advanced_activations],
},
{
'page': 'layers/noise.md',
'all_module_classes': [noise],
},
{
'page': 'layers/wrappers.md',
'all_module_classes': [wrappers],
},
{
'page': 'optimizers.md',
'all_module_classes': [optimizers],
},
{
'page': 'callbacks.md',
'all_module_classes': [callbacks],
},
{
'page': 'backend.md',
'all_module_functions': [backend],
},
]
2015-12-12 20:39:22 +00:00
ROOT = 'http://keras.io/'
def get_earliest_class_that_defined_member(member, cls):
ancestors = get_classes_ancestors([cls])
result = None
for ancestor in ancestors:
if member in dir(ancestor):
result = ancestor
if not result:
return cls
return result
def get_classes_ancestors(classes):
ancestors = []
for cls in classes:
ancestors += cls.__bases__
filtered_ancestors = []
for ancestor in ancestors:
if ancestor.__name__ in ['object']:
continue
filtered_ancestors.append(ancestor)
if filtered_ancestors:
return filtered_ancestors + get_classes_ancestors(filtered_ancestors)
else:
return filtered_ancestors
2016-04-07 21:23:34 +00:00
def get_function_signature(function, method=True):
2016-04-07 00:34:25 +00:00
signature = inspect.getargspec(function)
2015-12-12 20:39:22 +00:00
defaults = signature.defaults
2016-04-07 21:23:34 +00:00
if method:
args = signature.args[1:]
else:
args = signature.args
2015-12-12 20:39:22 +00:00
if defaults:
kwargs = zip(args[-len(defaults):], defaults)
args = args[:-len(defaults)]
else:
kwargs = []
2016-04-07 00:34:25 +00:00
st = '%s.%s(' % (function.__module__, function.__name__)
2015-12-12 20:39:22 +00:00
for a in args:
st += str(a) + ', '
for a, v in kwargs:
if type(v) == str:
v = '\'' + v + '\''
2015-12-12 20:39:22 +00:00
st += str(a) + '=' + str(v) + ', '
if kwargs or args:
return st[:-2] + ')'
else:
return st + ')'
2016-04-07 00:34:25 +00:00
def get_class_signature(cls):
try:
class_signature = get_function_signature(cls.__init__)
class_signature = class_signature.replace('__init__', cls.__name__)
except:
# in case the class inherits from object and does not
# define __init__
class_signature = cls.__module__ + '.' + cls.__name__ + '()'
return class_signature
def class_to_docs_link(cls):
2015-12-12 20:39:22 +00:00
module_name = cls.__module__
assert module_name[:6] == 'keras.'
module_name = module_name[6:]
link = ROOT + module_name.replace('.', '/') + '#' + cls.__name__.lower()
return link
def class_to_source_link(cls):
module_name = cls.__module__
assert module_name[:6] == 'keras.'
path = module_name.replace('.', '/')
path += '.py'
line = inspect.getsourcelines(cls)[-1]
link = 'https://github.com/fchollet/keras/blob/master/' + path + '#L' + str(line)
return '[[source]](' + link + ')'
2015-12-12 20:39:22 +00:00
def code_snippet(snippet):
result = '```python\n'
result += snippet + '\n'
result += '```\n'
return result
def process_class_docstring(docstring):
2016-02-07 23:38:20 +00:00
docstring = re.sub(r'\n # (.*)\n',
r'\n __\1__\n\n',
2015-12-12 20:39:22 +00:00
docstring)
docstring = re.sub(r' ([^\s\\]+):(.*)\n',
r' - __\1__:\2\n',
docstring)
docstring = docstring.replace(' ' * 5, '\t\t')
2015-12-12 20:39:22 +00:00
docstring = docstring.replace(' ' * 3, '\t')
docstring = docstring.replace(' ', '')
return docstring
2016-04-07 00:34:25 +00:00
def process_function_docstring(docstring):
2016-04-07 21:23:34 +00:00
docstring = re.sub(r'\n # (.*)\n',
r'\n __\1__\n\n',
docstring)
docstring = re.sub(r'\n # (.*)\n',
r'\n __\1__\n\n',
2015-12-12 20:39:22 +00:00
docstring)
docstring = re.sub(r' ([^\s\\]+):(.*)\n',
r' - __\1__:\2\n',
docstring)
docstring = docstring.replace(' ' * 6, '\t\t')
2015-12-12 20:39:22 +00:00
docstring = docstring.replace(' ' * 4, '\t')
docstring = docstring.replace(' ', '')
return docstring
print('Cleaning up existing sources directory.')
if os.path.exists('sources'):
shutil.rmtree('sources')
2016-06-06 17:18:09 +00:00
2015-12-12 20:39:22 +00:00
print('Populating sources directory with templates.')
for subdir, dirs, fnames in os.walk('templates'):
for fname in fnames:
new_subdir = subdir.replace('templates', 'sources')
if not os.path.exists(new_subdir):
os.makedirs(new_subdir)
if fname[-3:] == '.md':
fpath = os.path.join(subdir, fname)
new_fpath = fpath.replace('templates', 'sources')
shutil.copy(fpath, new_fpath)
print('Starting autogeneration.')
2016-04-07 00:34:25 +00:00
for page_data in PAGES:
blocks = []
classes = page_data.get('classes', [])
for module in page_data.get('all_module_classes', []):
module_classes = []
for name in dir(module):
if name[0] == '_' or name in EXCLUDE:
continue
module_member = getattr(module, name)
if inspect.isclass(module_member):
cls = module_member
if cls.__module__ == module.__name__:
if cls not in module_classes:
module_classes.append(cls)
module_classes.sort(key=lambda x: id(x))
classes += module_classes
2015-12-12 20:39:22 +00:00
2016-04-07 00:34:25 +00:00
for cls in classes:
subblocks = []
signature = get_class_signature(cls)
subblocks.append('<span style="float:right;">' + class_to_source_link(cls) + '</span>')
subblocks.append('### ' + cls.__name__ + '\n')
subblocks.append(code_snippet(signature))
docstring = cls.__doc__
if docstring:
subblocks.append(process_class_docstring(docstring))
blocks.append('\n'.join(subblocks))
functions = page_data.get('functions', [])
for module in page_data.get('all_module_functions', []):
module_functions = []
for name in dir(module):
if name[0] == '_' or name in EXCLUDE:
continue
module_member = getattr(module, name)
2016-04-07 21:23:34 +00:00
if inspect.isfunction(module_member):
2016-04-07 00:34:25 +00:00
function = module_member
2016-04-07 21:23:34 +00:00
if module.__name__ in function.__module__:
2016-04-07 00:34:25 +00:00
if function not in module_functions:
module_functions.append(function)
module_functions.sort(key=lambda x: id(x))
functions += module_functions
for function in functions:
subblocks = []
2016-04-07 21:23:34 +00:00
signature = get_function_signature(function, method=False)
2016-04-07 00:34:25 +00:00
signature = signature.replace(function.__module__ + '.', '')
2016-04-07 21:23:34 +00:00
subblocks.append('### ' + function.__name__ + '\n')
2016-04-07 00:34:25 +00:00
subblocks.append(code_snippet(signature))
docstring = function.__doc__
if docstring:
subblocks.append(process_function_docstring(docstring))
2016-04-07 21:23:34 +00:00
blocks.append('\n\n'.join(subblocks))
2016-04-07 00:34:25 +00:00
mkdown = '\n----\n\n'.join(blocks)
2015-12-12 20:39:22 +00:00
# save module page.
# Either insert content into existing page,
# or create page otherwise
2016-04-07 00:34:25 +00:00
page_name = page_data['page']
path = os.path.join('sources', page_name)
2015-12-12 20:39:22 +00:00
if os.path.exists(path):
template = open(path).read()
assert '{{autogenerated}}' in template, ('Template found for ' + path +
' but missing {{autogenerated}} tag.')
2016-04-07 00:34:25 +00:00
mkdown = template.replace('{{autogenerated}}', mkdown)
2015-12-12 20:39:22 +00:00
print('...inserting autogenerated content into template:', path)
else:
print('...creating new page with autogenerated content:', path)
subdir = os.path.dirname(path)
if not os.path.exists(subdir):
os.makedirs(subdir)
2016-04-07 00:34:25 +00:00
open(path, 'w').write(mkdown)