#
# Copyright 2016 The BigDL Authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
import numpy as np
import bigdl.nn.layer as BLayer
import bigdl.util.common as BCommon
from bigdl.util.common import get_activation_by_name
from keras.models import model_from_json
from keras.models import Sequential, Model, Layer
import keras
import warnings
from bigdl.keras.ToBigDLHelper import *
[docs]def unsupport_exp(name):
raise Exception("We don't support %s for now" % name)
[docs]class WeightLoader:
# TODO: add more unitest
# bmodel and kmodel should have the same layers.
# and this method should only be called when bmodel is generated by kmodel
[docs] @staticmethod
def load_weights_from_kmodel(bmodel, kmodel):
keras_name_to_layer = WeightLoader.__keras_name_to_Layers(kmodel, with_weights=True)
bigdl_name_to_layer = WeightLoader.__bigdl_name_to_Layers(bmodel, with_weights=True)
# klayer should be just a layer, not seq, not Model
for klayer in keras_name_to_layer.values():
if klayer.name in bigdl_name_to_layer:
blayer = bigdl_name_to_layer[klayer.name]
bigdl_weights = WeightsConverter.get_bigdl_weights_from_klayer(klayer)
blayer.set_weights(bigdl_weights)
if isinstance(klayer, keras.layers.BatchNormalization):
blayer.set_running_mean(keras.backend.eval(klayer.running_mean))
blayer.set_running_std(keras.backend.eval(klayer.running_std))
else:
raise Exception("should not enter here, klayer: %s", klayer)
[docs] @staticmethod
def load_weights_from_json_hdf5(def_json, weights_hdf5, by_name=False):
"""
The file path can be stored in a local file system, HDFS, S3,
or any Hadoop-supported file system.
"""
bmodel = DefinitionLoader.from_json_path(def_json)
def_value = BCommon.text_from_path(def_json)
kmodel = model_from_json(def_value)
WeightLoader.load_weights_from_hdf5(bmodel, kmodel, weights_hdf5, by_name)
return bmodel
[docs] @staticmethod
def load_weights_from_hdf5(bmodel, kmodel, filepath, by_name=False):
'''Loads all layer weights from a HDF5 save file.
filepath can be stored in a local file system, HDFS, S3,
or any Hadoop-supported file system.
If `by_name` is False (default) weights are loaded
based on the network's execution order topology,
meaning layers in the execution seq should be exactly the same
the architecture
If `by_name` is True, weights are loaded into layers
only if they share the same name. This is useful
for fine-tuning or transfer-learning models where
some of the layers have changed.
'''
local_file_path = BCommon.get_local_file(filepath)
kmodel.load_weights(filepath=local_file_path, by_name=by_name)
WeightLoader.load_weights_from_kmodel(bmodel, kmodel)
@staticmethod
def __keras_name_to_Layers(model, with_weights=False):
total_layers = DefinitionLoader(model).node_id_to_layer.values()
if with_weights:
layers = [l for l in total_layers
if l.get_weights() and not isinstance(l, Model) and not isinstance(l, Sequential)] # noqa
else:
layers = [l for l in total_layers if not isinstance(l, Model) and not isinstance(l, Sequential)] # noqa
return dict([(layer.name, layer) for layer in layers])
@staticmethod
def __bigdl_name_to_Layers(model, with_weights=False):
# NB: Container in BigDL is_with_weights() is true if one of the nested layer with_weights
# but in Keras container get_weights() return false even if the nested layer with_weights
all_layers = model.flattened_layers(include_container=True)
if with_weights:
layers = [l for l in all_layers if l.is_with_weights()]
else:
layers = all_layers
return dict([(layer.name(), layer) for layer in layers])
[docs]class WeightsConverter:
"""
Convert keras weights to bigdl weights
The shape of weights would be changed if using different backend,
so we only test against TensorFlow backend.
TODO: Support th backend as well.
"""
[docs] @staticmethod
def get_converter(class_name):
function_name = "convert_" + class_name.lower()
if not hasattr(WeightsConverter, function_name):
raise unsupport_exp(class_name)
converter = getattr(WeightsConverter, function_name)
return converter
[docs] @staticmethod
# weights is a list of ndarray or a ndarray
# convert keras weights per layer to bigdl format
def to_bigdl_weights(klayer, weights):
return WeightsConverter.get_converter(klayer.__class__.__name__)(klayer, weights)
[docs] @staticmethod
def get_bigdl_weights_from_klayer(klayer):
# we should use get_weights instead of klayer.weights
return WeightsConverter.to_bigdl_weights(klayer, klayer.get_weights())
[docs] @staticmethod
def get_weights_from_kmodel(kmodel):
"""
Convert kmodel's weights to bigdl format.
We are supposing the order is the same as the execution order.
:param kmodel: keras model
:return: list of ndarray
"""
layers_with_weights = [layer for layer in kmodel.layers if layer.weights]
bweights = []
for klayer in layers_with_weights:
# bws would be [weights, bias] or [weights]
bws = WeightsConverter.get_bigdl_weights_from_klayer(klayer)
for w in bws:
bweights.append(w)
return bweights
[docs] @staticmethod
def convert_timedistributed(klayer, weights):
return WeightsConverter.to_bigdl_weights(klayer.layer, weights)
[docs] @staticmethod
def convert_bidirectional(klayer, weights):
kweights_forward = weights[:int(len(weights) / 2)]
kweights_backward = weights[int(len(weights) / 2):]
bweights_forward = WeightsConverter.to_bigdl_weights(klayer.layer, kweights_forward)
bweights_backward = WeightsConverter.to_bigdl_weights(klayer.layer, kweights_backward)
return bweights_forward + bweights_backward
[docs] @staticmethod
def convert_dense(klayer, weights):
return [np.transpose(weights[0]), weights[1]]
[docs] @staticmethod
def convert_timedistributeddense(klayer, weights):
return [np.transpose(weights[0]), weights[1]]
[docs] @staticmethod
def convert_batchnormalization(klayer, weights):
gamma = weights[0]
beta = weights[1]
return [gamma, beta]
[docs] @staticmethod
def convert_atrousconvolution2d(klayer, weights):
return weights
[docs] @staticmethod
def convert_atrousconvolution1d(klayer, weights):
return [np.transpose(weights[0], (3, 2, 0, 1)), weights[1]]
[docs] @staticmethod
def convert_deconvolution2d(klayer, weights):
w = np.transpose(weights[0], (1, 0, 2, 3))
weight = np.expand_dims(w, 0)
if len(weights) > 1:
return [weight, weights[1]]
else:
return [weight]
[docs] @staticmethod
def convert_convolution2d(klayer, weights):
weight = np.expand_dims(weights[0], 0) # bigdl has a leading dim with value 1
if len(weights) > 1:
return [weight, weights[1]]
else:
return [weight]
[docs] @staticmethod
def convert_convolution1d(klayer, weights):
return WeightsConverter.convert_convolution2d(klayer, weights)
[docs] @staticmethod
def convert_convolution3d(klayer, weights):
return weights
[docs] @staticmethod
def convert_embedding(klayer, weights):
return weights
[docs] @staticmethod
def convert_simplernn(klayer, weights):
return [np.transpose(weights[0]), np.transpose(weights[1]), weights[2]]
[docs] @staticmethod
def convert_lstm(klayer, weights):
w1 = np.concatenate((weights[0].T, weights[3].T, weights[6].T, weights[9].T))
w2 = np.concatenate((weights[2], weights[5], weights[8], weights[11]))
w3 = np.concatenate((weights[1].T, weights[4].T, weights[7].T, weights[10].T))
return [w1, w2, w3]
[docs] @staticmethod
def convert_convlstm2d(klayer, weights):
return [np.expand_dims(weights[6], 0), weights[8], np.expand_dims(weights[7], 0),
np.expand_dims(weights[0], 0), weights[2], np.expand_dims(weights[1], 0),
np.expand_dims(weights[3], 0), weights[5], np.expand_dims(weights[4], 0),
np.expand_dims(weights[9], 0), weights[11], np.expand_dims(weights[10], 0)]
[docs] @staticmethod
def convert_gru(klayer, weights):
w1 = np.concatenate((weights[3].T, weights[0].T, weights[6].T))
w2 = np.concatenate((weights[5], weights[2], weights[8]))
w3 = np.concatenate((weights[4].T, weights[1].T))
w4 = weights[7].T
return [w1, w2, w3, w4]
[docs] @staticmethod
def convert_highway(klayer, weights):
if len(weights) == 2: # if without bias
return [weights[1].T, weights[0].T]
return [weights[1].T, weights[3], weights[0].T, weights[2]]
[docs] @staticmethod
def convert_maxoutdense(klayer, weights):
k_weights = weights[0]
b_weights = k_weights[0].T
for i in range(1, k_weights.shape[0]):
b_weights = np.concatenate((b_weights, k_weights[i].T))
if len(weights) == 1: # if without bias
return [b_weights]
return [b_weights, weights[1].reshape(k_weights.shape[0]*k_weights.shape[2], )]
[docs] @staticmethod
def convert_srelu(klayer, weights):
return weights
[docs] @staticmethod
def convert_separableconvolution2d(klayer, weights):
if len(weights) == 2: # if without bias
if klayer.dim_ordering == "th":
bias = weights[1].shape[0]
else:
bias = weights[1].shape[3]
return [weights[0], weights[1], np.zeros(bias, )]
return weights
[docs] @staticmethod
def convert_locallyconnected1d(klayer, weights):
bweights1 = np.transpose(weights[0], (0, 2, 1))
if len(weights) == 1: # if without bias
return [bweights1]
return[bweights1, weights[1]]
[docs] @staticmethod
def convert_locallyconnected2d(klayer, weights):
bweights1 = np.transpose(weights[0], (0, 2, 1))
if len(weights) == 1: # if without bias
return [bweights1]
bweights2 = weights[1].reshape(weights[1].shape[0]*weights[1].shape[1], weights[1].shape[2])
return[bweights1, bweights2]
[docs]class DefinitionLoader:
@staticmethod
def __build_node_id_2_klayer(kmodel, node_id_to_config_layer):
"""
The result would contain all of the layers including nested layers.
:param kmodel: a keras model which can be Sequential or Model
:param node_id_to_config_layer: a container to store the result
"""
node_id_to_config_layer[kmodel.name] = kmodel # include itself as well
def gather_result(layers):
if layers: # layers maybe None here.
for layer in layers:
if layer.name not in node_id_to_config_layer:
node_id_to_config_layer[layer.name] = layer
DefinitionLoader.__build_node_id_2_klayer(layer, node_id_to_config_layer)
if hasattr(kmodel, "layers"):
gather_result(kmodel.layers)
if hasattr(kmodel, "flattened_layers"):
gather_result(kmodel.flattened_layers) # it's a expensive operation
@staticmethod
def __build_node_id_2_kclayer(kmodel, node_id_to_config_layer):
if isinstance(kmodel, Sequential):
for layer_config in kmodel.get_config():
layer_name = layer_config["config"]["name"]
node_id_to_config_layer[layer_name] = layer_config
elif isinstance(kmodel, Model):
for layerConfig in kmodel.get_config()["layers"]:
node_id_to_config_layer[layerConfig["name"]] = layerConfig
elif isinstance(kmodel, Layer):
node_id_to_config_layer[kmodel.name] = kmodel.get_config()
else:
raise Exception("should not enter here: %s" % kmodel)
def __init__(self, kmodel):
self.node_id_to_instance = {}
self.node_id_to_layer = {}
self.node_id_to_config_layer = {}
self.kmodel = kmodel
self.kconfig = self.kmodel.get_config()
DefinitionLoader.__build_node_id_2_klayer(kmodel, self.node_id_to_layer)
DefinitionLoader.__build_node_id_2_kclayer(kmodel, self.node_id_to_config_layer)
def __to_bigdl(self):
if isinstance(self.kmodel, Sequential):
bigdlmodel = self._construct_bigdl_sequence()
elif isinstance(self.kmodel, Model):
bigdlmodel = self._construct_bigdl_model()
elif isinstance(self.kmodel, Layer):
bigdlmodel = LayerConverter(self.kmodel,
self.node_id_to_config_layer[self.kmodel.name]).create()
else:
raise Exception("Should not enter here: %s" % self.kmodel)
return bigdlmodel
[docs] @classmethod
def from_kmodel(cls, kmodel):
return cls(kmodel).__to_bigdl()
[docs] @classmethod
def from_hdf5_path(cls, hdf5_path):
"""
:param hdf5_path: hdf5 path which can be stored in a local file system, HDFS, S3, or any Hadoop-supported file system.
:return: BigDL Model
"""
from keras.models import load_model
hdf5_local_path = BCommon.get_local_file(hdf5_path)
kmodel = load_model(hdf5_local_path)
return kmodel, DefinitionLoader.from_kmodel(kmodel)
[docs] @classmethod
def from_json_path(cls, json_path):
"""
:param json_path: definition path which can be stored in a local file system, HDFS, S3, or any Hadoop-supported file system.
:return: BigDL Model
"""
json_str = BCommon.text_from_path(json_path)
return DefinitionLoader.from_json_str(json_str)
[docs] @classmethod
def from_json_str(cls, json_str):
kmodel = model_from_json(json_str)
return DefinitionLoader.from_kmodel(kmodel)
def _do_create_node(self, layer, clayer):
if clayer["class_name"] == "InputLayer":
input = BLayer.Input()
input.element().set_name(layer.name) # cannot set name for node?
self.node_id_to_instance[layer.name] = input
return input
bigdl_in_nodes = []
for node in clayer["inbound_nodes"]:
for out in node:
out_name = out[0]
out_index = out[1]
out_tensor_index = out[2]
if out_name not in self.node_id_to_instance:
self._do_create_node(self.node_id_to_layer[out_name],
self.node_id_to_config_layer[out_name])
bigdl_in_nodes.append(self.node_id_to_instance[out_name])
blayer = LayerConverter(layer, clayer).create()
new_bnode = blayer(bigdl_in_nodes)
self.node_id_to_instance[layer.name] = new_bnode
return new_bnode
def _construct_bigdl_model(self):
for clayer in self.kconfig["layers"]:
if clayer["name"] not in self.node_id_to_instance:
self._do_create_node(self.node_id_to_layer[clayer["name"]],
clayer)
ins = []
for input_layer in self.kconfig["input_layers"]:
name = input_layer[0]
ins.append(self.node_id_to_instance[name])
outs = []
for output_layer in self.kconfig["output_layers"]:
name = output_layer[0]
outs.append(self.node_id_to_instance[name])
return BLayer.Model(inputs=ins, outputs=outs)
def _construct_bigdl_sequence(self):
bseq = BLayer.Sequential()
for layer in self.kmodel.layers:
# recursive logic is within create method.
blayer = LayerConverter(layer, self.node_id_to_config_layer[layer.name]).create()
bseq.add(blayer)
return bseq
[docs]class LayerConverter:
def __init__(self, klayer, kclayer, input_shape=None):
self.klayer = klayer
self.kclayer = kclayer
if "config" in kclayer:
self.config = kclayer["config"]
else:
self.config = {}
if not input_shape:
self.input_shape = klayer.get_input_shape_at(0)
else:
self.input_shape = input_shape
def __check_is_share_weights(self):
# For Merge layer len(kclayer["inbound_nodes"]) is equal to 1
# "inbound_nodes": [
# [
# [
# "batchnormalization_194",
# 0,
# 0
# ],
# [
# "batchnormalization_196",
# 0,
# 0
# ],
# [
# "batchnormalization_199",
# 0,
# 0
# ],
# [
# "batchnormalization_200",
# 0,
# 0
# ]
# ]
# ],
if "inbound_nodes" in self.kclayer and len(self.kclayer["inbound_nodes"]) > 1:
raise Exception(
"%s doesn't support multiple inputs with shared weights" % self.kclayer["class_name"])
[docs] def create(self):
class_name = self.klayer.__class__.__name__
self.__check_is_share_weights()
if (hasattr(self.klayer, "b_constraint") and self.klayer.b_constraint) or \
(hasattr(self.klayer, "W_constraint") and self.klayer.W_constraint):
raise Exception("We don't support constraint for now")
if hasattr(self.klayer, "activity_regularizer") and self.klayer.activity_regularizer:
raise Exception("We don't support activity_regularizer for now")
function_name = "create_" + class_name.lower()
if not hasattr(self, function_name):
raise Exception("We don't support layer: %s for now" % class_name )
blayer_creator = getattr(self, function_name)
blayer = blayer_creator()
return blayer.set_name(self.klayer.name)
[docs] def create_model(self):
return DefinitionLoader.from_kmodel(self.klayer)
[docs] def create_sequential(self):
return DefinitionLoader.from_kmodel(self.klayer)
[docs] def create_dense(self):
# Multiple inputs should share the same input_dim for Dense layer
# We don't need to respect the tensor index for method `get_input_shape_at`
# which is internal implementation and `get_input_shape_at` has hided that for us,
# What we need to use is the input index, not node index, not tensor index.
out_dim = self.config["output_dim"]
in_dim = int(self.input_shape[-1])
blayer = BLayer.Linear(
input_size=in_dim,
output_size=out_dim,
with_bias=self.config["bias"],
wRegularizer=to_bigdl_reg(self.config["W_regularizer"]),
bRegularizer=to_bigdl_reg(self.config["b_regularizer"])
)
if len(self.input_shape) <= 2:
return self.combo_parameter_layer(blayer, self.config)
else:
seq = BLayer.Sequential()
seq.add(BLayer.InferReshape([-1, in_dim], False))
seq.add(blayer)
seq.add(BLayer.InferReshape([-1] + list(self.input_shape[1:-1]) + [out_dim], False))
return self.combo_parameter_layer(seq, self.config)
[docs] def create_timedistributeddense(self):
blayer = BLayer.TimeDistributed(BLayer.Linear(
input_size=int(self.input_shape[-1]),
output_size=self.config["output_dim"],
with_bias=self.config["bias"],
wRegularizer=to_bigdl_reg(self.config["W_regularizer"]),
bRegularizer=to_bigdl_reg(self.config["b_regularizer"])
))
return self.combo_parameter_layer(blayer, self.config)
[docs] def create_timedistributed(self):
# input_shape is (batch, time, other dims)
inner_input_shape = (self.input_shape[0], ) + self.input_shape[2:]
blayer = LayerConverter(self.klayer.layer, self.config['layer'], inner_input_shape).create()
return BLayer.TimeDistributed(blayer)
[docs] def create_bidirectional(self):
if not self.klayer.layer.return_sequences:
raise Exception("Only return_sequences=True is supported for RNNs for now")
recurrent_name = "generate_" + self.klayer.layer.__class__.__name__.lower() + "_cell"
recurrent_creator = getattr(self, recurrent_name)
recurrent = recurrent_creator(self.klayer.layer, self.config['layer'], self.input_shape)
if self.klayer.merge_mode == "concat":
merge = BLayer.JoinTable(len(self.input_shape) - 1, len(self.input_shape) - 1)
elif self.klayer.merge_mode == "sum":
merge = BLayer.CAddTable()
elif self.klayer.merge_mode == "mul":
merge = BLayer.CMulTable()
elif self.klayer.merge_mode == "ave":
merge = BLayer.CAveTable()
else:
raise Exception("Invalid merge mode: %s" % self.klayer.merge_mode)
blayer = BLayer.BiRecurrent(merge).add(recurrent)
return blayer
[docs] def create_embedding(self):
seq_len = int(self.input_shape[1])
if self.klayer.input_length and self.klayer.input_length != seq_len:
raise Exception(
"The input_length doesn't match: %s vs %s" % (seq_len, self.klayer.input_length))
if hasattr(self.klayer, "dropout") and self.klayer.dropout != 0:
raise Exception("We don't support dropout for now")
if hasattr(self.klayer, "mask_zero") and self.klayer.mask_zero != False:
raise Exception("We don't support mask_zero for now")
bseq = BLayer.Sequential()
blayer = BLayer.LookupTable(
n_index=self.klayer.input_dim,
n_output=self.klayer.output_dim,
padding_value=0.0,
norm_type=2.0,
should_scale_grad_by_freq=False,
wRegularizer=to_bigdl_reg(self.config["W_regularizer"]),
bigdl_type="float")
bseq.add(BLayer.AddConstant(1.0)) # Add 1 as BigDL is one-based index
bseq.add(blayer)
blayer.set_init_method(to_bigdl_init(self.config["init"]))
return bseq
[docs] def create_activation(self):
blayer = get_activation_by_name(self.config["activation"], self.klayer.name)
# SoftMax is different between Keras and BigDL for 3D inputs
if self.config["activation"] == "softmax" and len(self.input_shape) == 3:
model = BLayer.Sequential()
model.add(BLayer.Transpose([(1, 3)]))
model.add(blayer)
model.add(BLayer.Transpose([(1, 3)]))
return model
return blayer
[docs] def create_dropout(self):
return BLayer.Dropout(self.klayer.p)
[docs] def create_flatten(self):
return BLayer.Reshape([int(np.prod(self.input_shape[1:]))], None)
[docs] def create_permute(self):
swaps = self.__perm_to_pair(list(self.klayer.dims))
swaps.reverse()
swaps = map(lambda pair: (pair[0]+1, pair[1]+1), swaps)
return BLayer.Transpose(list(swaps))
def __perm_to_pair(self, perm):
# perm: a list as a permutation of [1..n], eg [3, 1, 2] for n=3.
# return a list of tuples that needs to be swapped to obtain the input `perm`.
pairs = []
def sort(arr, low, high):
i = low
j = high
pivot = arr[low + int((high - low) / 2)]
while i <= j:
while arr[i] < pivot:
i += 1
while arr[j] > pivot:
j -= 1
if i <= j:
exchangeNumbers(arr, i, j)
i += 1
j -= 1
if low < j:
sort(arr, low, j)
if i < high:
sort(arr, i, high)
def exchangeNumbers(arr, i, j):
temp = arr[i]
arr[i] = arr[j]
arr[j] = temp
pairs.append((i + 1, j + 1))
sort(perm, 0, len(perm) - 1)
return list(filter(lambda pair: pair[0] != pair[1], pairs))
[docs] def create_reshape(self):
if -1 in self.klayer.target_shape:
blayer = BLayer.InferReshape(self.klayer.target_shape, True)
else:
blayer = BLayer.Reshape(self.klayer.target_shape, None)
return blayer
[docs] def create_repeatvector(self):
return BLayer.Replicate(n_features=self.klayer.n,
n_dim=1,
bigdl_type="float")
def __is_from_sequential(self):
return "layers" in self.kclayer["config"] and hasattr(self.klayer, "layers") and self.klayer.layers is not None # noqa
[docs] def create_merge(self):
if self.klayer.output_shape and not isinstance(self.klayer.output_shape, tuple):
raise Exception("Only output_shape=None or a shape tuple is supported for now")
if self.klayer.node_indices and not all(0 == i for i in self.klayer.node_indices):
unsupport_exp("node_indices")
if self.klayer.output_mask:
unsupport_exp("output_mask")
if self.klayer.mode == "concat":
blayer = BLayer.JoinTable(
dimension=self.klayer.concat_axis,
n_input_dims=len(self.input_shape[0]) - 1,
bigdl_type="float")
elif self.klayer.mode == "sum":
blayer = BLayer.CAddTable(
inplace=False,
bigdl_type="float")
elif self.klayer.mode == "mul":
blayer = BLayer.CMulTable(bigdl_type="float")
elif self.klayer.mode == "max":
blayer = BLayer.CMaxTable(bigdl_type="float")
elif self.klayer.mode == "dot":
if len(self.input_shape[0]) >= 3:
raise Exception("For merge mode dot, 3D input or above is not supported for now.")
if self.klayer.dot_axes != [1, 1]:
raise Exception("For merge mode dot, only dot_axes=1 is supported for now.")
model = BLayer.Sequential()
blayer = model.add(BLayer.DotProduct(bigdl_type="float"))\
.add(BLayer.Reshape([1], True))
elif self.klayer.mode == "ave":
blayer = BLayer.CAveTable(
inplace=False,
bigdl_type="float")
elif self.klayer.mode in ['cos']:
if len(self.input_shape[0]) >= 3:
raise Exception("For merge mode cos, 3D input or above is not supported for now.")
if self.klayer.dot_axes != [1, 1]:
raise Exception("For merge mode cos, only dot_axes=1 is supported for now.")
blayer = BLayer.Sequential()
blayer.add(BLayer.CosineDistance(bigdl_type="float")).add(BLayer.Reshape([1, 1], True))
else: # invalid mode or lambda functions
raise Exception("Invalid merge mode: `%s`. Lambda/function as merge mode is not supported for now."
% self.klayer.mode)
if self.__is_from_sequential():
bseq = BLayer.Sequential()
parallel_table = BLayer.ParallelTable()
for l in self.klayer.layers:
bl = DefinitionLoader.from_kmodel(l)
parallel_table.add(bl)
bseq.add(parallel_table)
bseq.add(blayer)
return bseq
else:
return blayer
[docs] def create_elu(self):
return BLayer.ELU(alpha=float(self.klayer.alpha),
inplace=False,
bigdl_type="float")
[docs] def create_prelu(self):
return BLayer.PReLU(n_output_plane=0,
bigdl_type="float")
[docs] def create_leakyrelu(self):
return BLayer.LeakyReLU(negval=float(self.klayer.alpha),
inplace=False,
bigdl_type="float")
[docs] def create_parametricsoftplus(self):
alpha = float(self.klayer.alpha_init)
beta = float(self.klayer.beta_init)
if self.klayer.shared_axes != [None]:
unsupport_exp("shared_axes")
if round(alpha * beta, 4) == 1.0:
return BLayer.SoftPlus(beta=beta,
bigdl_type="float")
else:
raise Exception("Only alpha_init = 1/beta_init is supported for now")
[docs] def create_thresholdedrelu(self):
return BLayer.Threshold(th=float(self.klayer.theta),
v=0.0,
ip=False,
bigdl_type="float")
def __generate_zeropadding1d(self, pad_top, pad_bottom):
return BLayer.SpatialZeroPadding(pad_left=0,
pad_right=0,
pad_top=pad_top,
pad_bottom=pad_bottom,
bigdl_type="float")
[docs] def create_zeropadding1d(self):
padding = self.klayer.padding
if isinstance(padding, int):
return self.__generate_zeropadding1d(padding, padding)
elif isinstance(padding, dict):
return self.__generate_zeropadding1d(padding.get('left_pad', 0), padding.get('right_pad', 0))
else: # tuple of int (length 2)
padding = tuple(padding)
return self.__generate_zeropadding1d(padding[0], padding[1])
def __generate_zeropadding2d(self, dim1, dim2, n_input_dim, pad1, pad2, pad3, pad4):
model = BLayer.Sequential()
paddinglayer1 = BLayer.Padding(dim=dim1,
pad=pad1,
n_input_dim=n_input_dim,
value=0.0,
n_index=1,
bigdl_type="float")
paddinglayer2 = BLayer.Padding(dim=dim1,
pad=pad2,
n_input_dim=n_input_dim,
value=0.0,
n_index=1,
bigdl_type="float")
paddinglayer3 = BLayer.Padding(dim=dim2,
pad=pad3,
n_input_dim=n_input_dim,
value=0.0,
n_index=1,
bigdl_type="float")
paddinglayer4 = BLayer.Padding(dim=dim2,
pad=pad4,
n_input_dim=n_input_dim,
value=0.0,
n_index=1,
bigdl_type="float")
model.add(paddinglayer1)
model.add(paddinglayer2)
model.add(paddinglayer3)
model.add(paddinglayer4)
return model
# NB: zeropadding doesn't serialize dim_ording to json file
[docs] def create_zeropadding2d(self):
padding = self.klayer.padding
dim = 1
if "dim_ordering" not in self.config:
warnings.warn("Cannot find dim_ordering from json definition. Using the default instead.")
if self.klayer.dim_ordering == "th":
dim = 2
if isinstance(padding, dict): # dictionary
return self.__generate_zeropadding2d(dim, dim+1, len(self.input_shape) - 1,
-padding.get('top_pad', 0), padding.get('bottom_pad', 0),
-padding.get('left_pad', 0), padding.get('right_pad', 0))
else: # tuple of int
padding = tuple(padding)
if len(padding) == 2:
return self.__generate_zeropadding2d(dim, dim+1, len(self.input_shape) - 1,
-padding[0], padding[0], -padding[1], padding[1])
elif len(padding) == 4:
return self.__generate_zeropadding2d(dim, dim+1, len(self.input_shape) - 1,
-padding[0], padding[1], -padding[2], padding[3])
# NB: zeropadding doesn't serialize dim_ording to json file
[docs] def create_zeropadding3d(self):
padding = tuple(self.klayer.padding)
dim = 1
if "dim_ordering" not in self.config:
warnings.warn("Cannot find dim_ordering from json definition. Using the default instead.")
if self.klayer.dim_ordering == "th":
dim = 2
model = BLayer.Sequential()
paddinglayer1 = BLayer.Padding(dim=dim,
pad=-padding[0],
n_input_dim=len(self.input_shape) - 1,
value=0.0,
n_index=1,
bigdl_type="float")
paddinglayer2 = BLayer.Padding(dim=dim,
pad=padding[0],
n_input_dim=len(self.input_shape) - 1,
value=0.0,
n_index=1,
bigdl_type="float")
paddinglayer3 = BLayer.Padding(dim=dim+1,
pad=-padding[1],
n_input_dim=len(self.input_shape) - 1,
value=0.0,
n_index=1,
bigdl_type="float")
paddinglayer4 = BLayer.Padding(dim=dim+1,
pad=padding[1],
n_input_dim=len(self.input_shape) - 1,
value=0.0,
n_index=1,
bigdl_type="float")
paddinglayer5 = BLayer.Padding(dim=dim+2,
pad=-padding[2],
n_input_dim=len(self.input_shape) - 1,
value=0.0,
n_index=1,
bigdl_type="float")
paddinglayer6 = BLayer.Padding(dim=dim+2,
pad=padding[2],
n_input_dim=len(self.input_shape) - 1,
value=0.0,
n_index=1,
bigdl_type="float")
model.add(paddinglayer1)
model.add(paddinglayer2)
model.add(paddinglayer3)
model.add(paddinglayer4)
model.add(paddinglayer5)
model.add(paddinglayer6)
return model
[docs] def create_cropping1d(self):
cropping = tuple(self.klayer.cropping)
return BLayer.SpatialZeroPadding(0, 0, -cropping[0], -cropping[1])
[docs] def create_cropping2d(self):
bigdl_order = self.get_bdim_order()
blayer = BLayer.Cropping2D(heightCrop=self.klayer.cropping[0],
widthCrop=self.klayer.cropping[1],
data_format=bigdl_order)
return blayer
[docs] def create_cropping3d(self):
bigdl_order = self.get_bdim_order("3D")
blayer = BLayer.Cropping3D(dim1Crop=self.klayer.cropping[0],
dim2Crop=self.klayer.cropping[1],
dim3Crop=self.klayer.cropping[2],
data_format=bigdl_order)
return blayer
def __check_recurrent_parameters(self, klayer):
if klayer.stateful:
raise Exception("Only stateful=False for recurrent layers is supported for now")
if hasattr(klayer, "consume_less") and klayer.consume_less == "gpu":
raise Exception("consume_less=gpu is not supported for now")
def __process_recurrent_layer(self, return_sequences, go_backwards, blayer):
# For recurrent layers,
# handle whether to return the last output sentence or the full sequence;
# handle whether the input will go backwards
model = BLayer.Sequential()
if go_backwards:
model.add(BLayer.Reverse(2))
model.add(blayer)
if not return_sequences:
model.add(BLayer.Select(2, -1))
return model
[docs] def generate_simplernn_cell(self, klayer, kclayer, input_shape): # create a simplernn cell only
self.__check_recurrent_parameters(klayer)
config = kclayer["config"]
activation = get_activation_by_name(config["activation"],
"%s_%s" % (config["name"], config["activation"]))
rnn = BLayer.RnnCell(input_size=int(input_shape[2]),
hidden_size=klayer.output_dim,
activation=activation,
isInputWithBias=False,
wRegularizer=to_bigdl_reg(config["W_regularizer"]),
uRegularizer=to_bigdl_reg(config["U_regularizer"]),
bRegularizer=to_bigdl_reg(config["b_regularizer"]),
bigdl_type="float")
return rnn
[docs] def create_simplernn(self):
rec = BLayer.Recurrent()
rnn = self.generate_simplernn_cell(self.klayer, self.kclayer, self.input_shape)
return self.__process_recurrent_layer(self.klayer.return_sequences,
self.klayer.go_backwards, rec.add(rnn))
[docs] def generate_lstm_cell(self, klayer, kclayer, input_shape): # create a lstm cell only
self.__check_recurrent_parameters(klayer)
config = kclayer["config"]
activation = get_activation_by_name(config["activation"],
"%s_%s" % (config["name"], config["activation"]))
inner_activation = get_activation_by_name(config["inner_activation"],
"%s_%s" % (config["name"], config["inner_activation"]))
lstm = BLayer.LSTM(input_size=int(input_shape[2]),
hidden_size=klayer.output_dim,
p=0.0,
activation=activation,
inner_activation=inner_activation,
wRegularizer=to_bigdl_reg(config["W_regularizer"]),
uRegularizer=to_bigdl_reg(config["U_regularizer"]),
bRegularizer=to_bigdl_reg(config["b_regularizer"]),
bigdl_type="float")
return lstm
[docs] def create_lstm(self):
rec = BLayer.Recurrent()
lstm = self.generate_lstm_cell(self.klayer, self.kclayer, self.input_shape)
return self.__process_recurrent_layer(self.klayer.return_sequences,
self.klayer.go_backwards, rec.add(lstm))
[docs] def generate_convlstm2d_cell(self, klayer, kclayer, input_shape): # create a convlstm2d cell only
self.__check_recurrent_parameters(klayer)
config = kclayer["config"]
activation = get_activation_by_name(config["activation"],
"%s_%s" % (config["name"], config["activation"]))
inner_activation = get_activation_by_name(config["inner_activation"],
"%s_%s" % (config["name"], config["inner_activation"]))
convlstm = BLayer.ConvLSTMPeephole(input_size=int(input_shape[2]),
output_size=config["nb_filter"],
kernel_i=config["nb_col"],
kernel_c=config["nb_row"],
# NB: ConvLSTM doesn't serialize subsample to json file
stride=klayer.subsample[0],
padding=-1,
activation=activation,
inner_activation=inner_activation,
# NB: ConvLSTM doesn't serialize regularizers to json file
# wRegularizer=to_bigdl_reg(config["W_regularizer"]),
# uRegularizer=to_bigdl_reg(config["U_regularizer"]),
# bRegularizer=to_bigdl_reg(config["b_regularizer"]),
cRegularizer=None,
with_peephole=False,
bigdl_type="float")
return convlstm
[docs] def create_convlstm2d(self):
# TODO: border_mode = 'valid'
if self.config["border_mode"] != 'same':
raise Exception("Unsupported border_mode: valid")
if self.klayer.dim_ordering != "th":
raise Exception("Please use `th` for `dim_ordering`. `%s` is not supported for now."
% self.klayer.dim_ordering)
if self.config["nb_row"] != self.config["nb_col"]:
raise Exception("Only square kernel is supported for now. Please set nb_row=nb_col.")
if self.klayer.subsample[0] != self.klayer.subsample[1]:
raise Exception("Only equal stride is supported for now. "
"Please set subsample to be a tuple with equal values.")
rec = BLayer.Recurrent()
convlstm = self.generate_convlstm2d_cell(self.klayer,
self.kclayer, self.input_shape)
return self.__process_recurrent_layer(self.klayer.return_sequences,
self.klayer.go_backwards, rec.add(convlstm))
[docs] def generate_gru_cell(self, klayer, kclayer, input_shape): # create a gru cell only
self.__check_recurrent_parameters(klayer)
config = kclayer["config"]
activation = get_activation_by_name(config["activation"],
"%s_%s" % (config["name"], config["activation"]))
inner_activation = get_activation_by_name(config["inner_activation"],
"%s_%s" % (config["name"], config["inner_activation"]))
gru = BLayer.GRU(input_size=int(input_shape[2]),
hidden_size=klayer.output_dim,
p=0.0,
activation=activation,
inner_activation=inner_activation,
wRegularizer=to_bigdl_reg(config["W_regularizer"]),
uRegularizer=to_bigdl_reg(config["U_regularizer"]),
bRegularizer=to_bigdl_reg(config["b_regularizer"]),
bigdl_type="float")
return gru
[docs] def create_gru(self):
rec = BLayer.Recurrent()
gru = self.generate_gru_cell(self.klayer, self.kclayer, self.input_shape)
return self.__process_recurrent_layer(self.klayer.return_sequences,
self.klayer.go_backwards, rec.add(gru))
[docs] def create_batchnormalization(self):
if len(self.input_shape) != 4:
raise Exception("Only 4D input is supported for now, but the current input dim is %s",
len(self.input_shape))
if keras.backend.image_dim_ordering() == "th" and self.klayer.axis != 1:
raise Exception("""For BatchNormalization with th image ordering, we only support """ +
"""axis = 1 for now, but the current axis is %s
""" % self.klayer.axis) # noqa
if keras.backend.image_dim_ordering() == "tf" and self.klayer.axis != -1:
raise Exception("""For BatchNormalization with tf image ordering, we only support """ +
"""axis = -1 for now, but the current axis is %s
""" % self.klayer.axis)
if self.klayer.mode != 0:
raise Exception(
"Only support mode = 0 for now, but the current mode is: %s", self.klayer.mode)
if self.config["gamma_regularizer"]:
raise Exception("We don't support gamma_regularizer for now")
if self.config["beta_regularizer"]:
raise Exception("We don't support beta_regularizer for now")
bigdl_order = to_bigdl_2d_ordering(keras.backend.image_dim_ordering())
n_input_channel = int(self.input_shape[self.klayer.axis])
# init gamma and beta
# TODO: replace this with to_bigdl_init in the future
gamma = self.get_value_from_init(self.klayer.gamma_init.__name__, (n_input_channel,))
beta = self.get_value_from_init(self.klayer.beta_init.__name__, (n_input_channel,))
blayer = BLayer.SpatialBatchNormalization(
n_output=n_input_channel,
eps=self.klayer.epsilon,
momentum=self.klayer.momentum,
affine=True,
init_weight=gamma,
init_bias=beta,
init_grad_weight=None,
init_grad_bias=None,
data_format=bigdl_order,
bigdl_type="float")
k_running_mean = keras.backend.eval(self.klayer.running_mean)
k_running_std = keras.backend.eval(self.klayer.running_std)
blayer.set_running_mean(k_running_mean)
blayer.set_running_std(k_running_std)
return blayer
[docs] def get_bdim_order(self, dim="2D"): # get bigdl dim_ordering from keras dim_ordering
if "dim_ordering" in self.config:
order = self.config["dim_ordering"]
else:
warnings.warn("Cannot find dim_ordering from json definition. Using the default instead.")
order = keras.backend.image_dim_ordering()
if dim == "3D":
return to_bigdl_3d_ordering(order)
return to_bigdl_2d_ordering(order)
[docs] def create_convolution1d(self):
# batch, steps, dim, batch is None here, so you cannot use it directly.
stack_size = int(self.input_shape[2])
bpadW, bpadH = to_bigdl_2d_padding(self.klayer.border_mode)
seq = BLayer.Sequential()
seq.add(BLayer.Reshape([int(self.input_shape[1]), 1, int(self.input_shape[2])], True))
blayer = BLayer.SpatialConvolution(
n_input_plane=stack_size,
n_output_plane=self.klayer.nb_filter,
kernel_w=1,
kernel_h=self.klayer.filter_length,
stride_w=1,
stride_h=self.klayer.subsample_length,
pad_w=bpadW,
pad_h=bpadH,
n_group=1,
propagate_back=True,
wRegularizer=to_bigdl_reg(self.config["W_regularizer"]),
bRegularizer=to_bigdl_reg(self.config["b_regularizer"]),
init_weight=None,
init_bias=None,
init_grad_weight=None,
init_grad_bias=None,
with_bias=self.config["bias"],
data_format="NHWC",
bigdl_type="float")
seq.add(blayer)
seq.add(BLayer.Squeeze(3))
return self.combo_parameter_layer(seq, self.config)
[docs] def create_convolution2d(self):
bigdl_order = self.get_bdim_order()
if bigdl_order == "NCHW":
stack_size = int(self.input_shape[1])
elif bigdl_order == "NHWC":
stack_size = int(self.input_shape[3])
bpadW, bpadH = to_bigdl_2d_padding(self.klayer.border_mode)
blayer = BLayer.SpatialConvolution(
n_input_plane=stack_size,
n_output_plane=self.klayer.nb_filter,
kernel_w=self.klayer.nb_col,
kernel_h=self.klayer.nb_row,
stride_w=self.klayer.subsample[1],
stride_h=self.klayer.subsample[0],
pad_w=bpadW,
pad_h=bpadH,
n_group=1,
propagate_back=True,
wRegularizer=to_bigdl_reg(self.config["W_regularizer"]),
bRegularizer=to_bigdl_reg(self.config["b_regularizer"]),
init_weight=None,
init_bias=None,
init_grad_weight=None,
init_grad_bias=None,
with_bias=self.config["bias"],
data_format=bigdl_order,
bigdl_type="float")
return self.combo_parameter_layer(blayer, self.config)
[docs] def create_convolution3d(self):
if self.klayer.dim_ordering != "th":
raise Exception("Please use `th` for `dim_ordering`. `%s` is not supported for now." % self.klayer.dim_ordering)
bpadT, bpadW, bpadH = to_bigdl_3d_padding(self.klayer.border_mode)
blayer = BLayer.VolumetricConvolution(
n_input_plane=int(self.input_shape[1]),
n_output_plane=self.klayer.nb_filter,
k_t=self.klayer.kernel_dim1,
k_w=self.klayer.kernel_dim3,
k_h=self.klayer.kernel_dim2,
d_t=self.klayer.subsample[0],
d_w=self.klayer.subsample[2],
d_h=self.klayer.subsample[1],
pad_t=bpadT,
pad_w=bpadW,
pad_h=bpadH,
with_bias=self.config["bias"],
wRegularizer=to_bigdl_reg(self.config["W_regularizer"]),
bRegularizer=to_bigdl_reg(self.config["b_regularizer"]),
bigdl_type="float")
return self.combo_parameter_layer(blayer, self.config)
[docs] def create_atrousconvolution1d(self):
if not self.config["bias"]:
raise Exception("Only bias=True is supported for AtrousConvolution1D")
h = int(self.input_shape[1])
kh = self.config["filter_length"]
dh = self.config["subsample_length"]
dilation_h = self.config["atrous_rate"]
pad_h, pad_w = to_bigdl_2d_padding(self.config["border_mode"], h, kh, dh, dilation_h)
seq = BLayer.Sequential()
seq.add(BLayer.Transpose([(2, 3)]))
seq.add(BLayer.Reshape([int(self.input_shape[2]), int(self.input_shape[1]), 1], True))
blayer = BLayer.SpatialDilatedConvolution(
n_input_plane=int(self.input_shape[2]),
n_output_plane=self.config["nb_filter"],
kw=1,
kh=kh,
dw=1,
dh=dh,
pad_w=pad_w,
pad_h=pad_h,
dilation_w=1,
dilation_h=dilation_h,
wRegularizer=to_bigdl_reg(self.config["W_regularizer"]),
bRegularizer=to_bigdl_reg(self.config["b_regularizer"]),
bigdl_type="float")
seq.add(blayer)
seq.add(BLayer.Transpose([(2, 3)]))
seq.add(BLayer.Squeeze(4))
return self.combo_parameter_layer(seq, self.config)
[docs] def create_atrousconvolution2d(self):
if self.klayer.dim_ordering != "th":
raise Exception("Please use `th` for `dim_ordering`. `%s` is not supported for now." % self.klayer.dim_ordering)
if not self.config["bias"]:
raise Exception("Only bias=True is supported for AtrousConvolution2D")
h = int(self.input_shape[2])
w = int(self.input_shape[3])
kh = self.config["nb_row"]
kw = self.config["nb_col"]
dh = self.config["subsample"][0]
dw = self.config["subsample"][1]
dilation_h = self.config["atrous_rate"][0]
dilation_w = self.config["atrous_rate"][1]
pad_h, pad_w = to_bigdl_2d_padding(self.config["border_mode"], h, kh, dh, dilation_h,
w, kw, dw, dilation_w)
blayer = BLayer.SpatialDilatedConvolution(
n_input_plane=int(self.input_shape[1]),
n_output_plane=self.config["nb_filter"],
kw=kw,
kh=kh,
dw=dw,
dh=dh,
pad_w=pad_w,
pad_h=pad_h,
dilation_w=dilation_w,
dilation_h=dilation_h,
wRegularizer=to_bigdl_reg(self.config["W_regularizer"]),
bRegularizer=to_bigdl_reg(self.config["b_regularizer"]),
bigdl_type="float")
return self.combo_parameter_layer(blayer, self.config)
[docs] def create_deconvolution2d(self):
if self.klayer.dim_ordering != "th":
raise Exception("Please use `th` for `dim_ordering`. `%s` is not supported for now." % self.klayer.dim_ordering)
output_shape = self.config["output_shape"]
h = int(self.input_shape[2])
w = int(self.input_shape[3])
kh = self.config["nb_row"]
kw = self.config["nb_col"]
dh = self.config["subsample"][0]
dw = self.config["subsample"][1]
output_h = output_shape[2]
output_w = output_shape[3]
pad_w = 0
pad_h = 0
if self.config["border_mode"] == "same":
two_pad_h = (h - 1) * dh + kh - output_h # 2 times pad_h
two_pad_w = (w - 1) * dw + kw - output_w # 2 times pad_w
if two_pad_h % 2 == 0: # we only support pad_h as an int
pad_h = int(two_pad_h / 2)
else:
raise Exception("For same padding, we only support padding on both sides for now. "
"Please make `(input_row - 1) * subsample[0] + nb_row - output_row` an even integer.")
if two_pad_w % 2 == 0: # we only support pad_w as an int
pad_w = int(two_pad_w / 2)
else:
raise Exception("For same padding, we only support padding on both sides for now. "
"Please make `(input_col - 1) * subsample[1] + nb_col - output_col` an even integer.")
blayer = BLayer.SpatialFullConvolution(
n_input_plane=int(self.input_shape[1]),
n_output_plane=self.klayer.nb_filter,
kw=self.klayer.nb_col,
kh=self.klayer.nb_row,
dw=self.klayer.subsample[1],
dh=self.klayer.subsample[0],
pad_w=pad_w,
pad_h=pad_h,
adj_w=0,
adj_h=0,
n_group=1,
no_bias=not self.klayer.bias,
wRegularizer=to_bigdl_reg(self.config["W_regularizer"]),
bRegularizer=to_bigdl_reg(self.config["b_regularizer"]),
bigdl_type="float")
return self.combo_parameter_layer(blayer, self.config)
[docs] def create_maxpooling3d(self):
if self.klayer.dim_ordering != "th":
raise Exception("Please use `th` for `dim_ordering`. `%s` is not supported for now." % klayer.dim_ordering)
# TODO: border_mode = 'same'
if self.klayer.border_mode == 'same':
raise Exception("Unsupported border_mode: same")
bpadT, bpadW, bpadH = to_bigdl_3d_padding(self.klayer.border_mode)
blayer = BLayer.VolumetricMaxPooling(
k_t=self.klayer.pool_size[0],
k_w=self.klayer.pool_size[2],
k_h=self.klayer.pool_size[1],
d_t=self.klayer.strides[0],
d_w=self.klayer.strides[2],
d_h=self.klayer.strides[1],
pad_t=bpadT,
pad_w=bpadW,
pad_h=bpadH,
bigdl_type="float")
return blayer
[docs] def create_maxpooling2d(self):
bigdl_order = self.get_bdim_order()
bpadW, bpadH = to_bigdl_2d_padding(self.klayer.border_mode)
blayer = BLayer.SpatialMaxPooling(
kw=self.klayer.pool_size[1],
kh=self.klayer.pool_size[0],
dw=self.klayer.strides[1],
dh=self.klayer.strides[0],
pad_w=bpadW,
pad_h=bpadH,
to_ceil=False,
format=bigdl_order,
bigdl_type="float")
return blayer
[docs] def create_globalmaxpooling3d(self):
if self.klayer.dim_ordering == "th":
b_kt = int(self.input_shape[2])
b_kw = int(self.input_shape[4])
b_kh = int(self.input_shape[3])
else:
raise Exception("Please use `th` for dim_ordering. `%s` is not supported for now." % self.klayer.dim_ordering)
seq = BLayer.Sequential()
blayer = BLayer.VolumetricMaxPooling(
k_t=b_kt,
k_w=b_kw,
k_h=b_kh,
d_t=1,
d_w=1,
d_h=1,
pad_t=0,
pad_w=0,
pad_h=0,
bigdl_type="float"
)
seq.add(blayer)
seq.add(BLayer.Squeeze(5))
seq.add(BLayer.Squeeze(4))
seq.add(BLayer.Squeeze(3))
return seq
[docs] def create_globalaveragepooling3d(self):
if self.klayer.dim_ordering == "th":
b_kt = int(self.input_shape[2])
b_kw = int(self.input_shape[4])
b_kh = int(self.input_shape[3])
else:
raise Exception("Please use `th` for dim_ordering. `%s` is not supported for now." % self.klayer.dim_ordering)
seq = BLayer.Sequential()
blayer = BLayer.VolumetricAveragePooling(
k_t=b_kt,
k_w=b_kw,
k_h=b_kh,
d_t=1,
d_w=1,
d_h=1,
pad_t=0,
pad_w=0,
pad_h=0,
count_include_pad=False,
bigdl_type="float"
)
seq.add(blayer)
seq.add(BLayer.Squeeze(5))
seq.add(BLayer.Squeeze(4))
seq.add(BLayer.Squeeze(3))
return seq
[docs] def create_averagepooling2d(self):
bigdl_order = self.get_bdim_order()
bpadW, bpadH = to_bigdl_2d_padding(self.klayer.border_mode)
blayer = BLayer.SpatialAveragePooling(
kw=self.klayer.pool_size[1],
kh=self.klayer.pool_size[0],
dw=self.klayer.strides[1],
dh=self.klayer.strides[0],
pad_w=bpadW,
pad_h=bpadH,
global_pooling=False,
ceil_mode=False,
count_include_pad=False,
divide=True,
format=bigdl_order,
bigdl_type="float"
)
return blayer
[docs] def create_averagepooling3d(self):
if self.klayer.dim_ordering != "th":
raise Exception("Please use `th` for `dim_ordering`. `%s` is not supported for now." % klayer.dim_ordering)
# TODO: border_mode = 'same'
if self.klayer.border_mode == 'same':
raise Exception("Unsupported border_mode: same")
bpadT, bpadW, bpadH = to_bigdl_3d_padding(self.klayer.border_mode)
blayer = BLayer.VolumetricAveragePooling(
k_t=self.klayer.pool_size[0],
k_w=self.klayer.pool_size[2],
k_h=self.klayer.pool_size[1],
d_t=self.klayer.strides[0],
d_w=self.klayer.strides[2],
d_h=self.klayer.strides[1],
pad_t=bpadT,
pad_w=bpadW,
pad_h=bpadH,
count_include_pad=False,
bigdl_type="float")
return blayer
[docs] def create_globalmaxpooling2d(self):
bigdl_order = self.get_bdim_order()
if bigdl_order == "NCHW":
b_kw = int(self.input_shape[3])
b_kh = int(self.input_shape[2])
else:
b_kw = int(self.input_shape[2])
b_kh = int(self.input_shape[1])
seq = BLayer.Sequential()
blayer = BLayer.SpatialMaxPooling(
kw=b_kw,
kh=b_kh,
dw=b_kw,
dh=b_kh,
pad_w=0,
pad_h=0,
to_ceil=False,
format=bigdl_order,
bigdl_type="float"
)
seq.add(blayer)
if bigdl_order == "NCHW":
seq.add(BLayer.Squeeze(3, num_input_dims=3))
seq.add(BLayer.Squeeze(2, num_input_dims=2))
else:
seq.add(BLayer.Squeeze(2, num_input_dims=3))
seq.add(BLayer.Squeeze(1, num_input_dims=2))
return seq
[docs] def create_globalmaxpooling1d(self):
b_kw = 1
b_kh = int(self.input_shape[1])
seq = BLayer.Sequential()
seq.add(BLayer.Reshape([int(self.input_shape[1]), 1, int(self.input_shape[2])], True))
blayer = BLayer.SpatialMaxPooling(
kw=b_kw,
kh=b_kh,
dw=1,
dh=1,
pad_w=0,
pad_h=0,
to_ceil=False,
format="NHWC",
bigdl_type="float"
)
seq.add(blayer)
seq.add(BLayer.Squeeze(3))
seq.add(BLayer.Squeeze(2))
return seq
[docs] def create_globalaveragepooling1d(self):
b_kw = 1
b_kh = int(self.input_shape[1])
seq = BLayer.Sequential()
seq.add(BLayer.Reshape([int(self.input_shape[1]), 1, int(self.input_shape[2])], True))
blayer = BLayer.SpatialAveragePooling(
kw=b_kw,
kh=b_kh,
dw=1,
dh=1,
pad_w=0,
pad_h=0,
global_pooling=False,
ceil_mode=False,
count_include_pad=False,
divide=True,
format="NHWC",
bigdl_type="float"
)
seq.add(blayer)
seq.add(BLayer.Squeeze(3))
seq.add(BLayer.Squeeze(2))
return seq
[docs] def create_maxpooling1d(self):
bpadW, bpadH = to_bigdl_2d_padding(self.klayer.border_mode)
seq = BLayer.Sequential()
seq.add(BLayer.Reshape([int(self.input_shape[1]), 1, int(self.input_shape[2])], True))
blayer = BLayer.SpatialMaxPooling(
kw=1,
kh=self.klayer.pool_length,
dw=1,
dh=self.klayer.stride,
pad_w=bpadW,
pad_h=bpadH,
to_ceil=False,
format="NHWC",
bigdl_type="float"
)
seq.add(blayer)
seq.add(BLayer.Squeeze(3))
return seq
[docs] def create_averagepooling1d(self):
bpadW, bpadH = to_bigdl_2d_padding(self.klayer.border_mode)
seq = BLayer.Sequential()
seq.add(BLayer.Reshape([int(self.input_shape[1]), 1, int(self.input_shape[2])], True))
blayer = BLayer.SpatialAveragePooling(
kw=1,
kh=self.klayer.pool_length,
dw=1,
dh=self.klayer.stride,
pad_w=bpadW,
pad_h=bpadH,
global_pooling=False,
ceil_mode=False,
count_include_pad=False,
divide=True,
format="NHWC",
bigdl_type="float"
)
seq.add(blayer)
seq.add(BLayer.Squeeze(3))
return seq
[docs] def create_globalaveragepooling2d(self):
bigdl_order = self.get_bdim_order()
if bigdl_order == "NCHW":
b_kw = int(self.input_shape[3])
b_kh = int(self.input_shape[2])
else:
b_kw = int(self.input_shape[2])
b_kh = int(self.input_shape[1])
seq = BLayer.Sequential()
blayer = BLayer.SpatialAveragePooling(
kw=b_kw,
kh=b_kh,
dw=b_kw,
dh=b_kh,
pad_w=0,
pad_h=0,
global_pooling=False,
ceil_mode=False,
count_include_pad=False,
divide=True,
format=bigdl_order,
bigdl_type="float"
)
seq.add(blayer)
if bigdl_order == "NCHW":
seq.add(BLayer.Squeeze(3, num_input_dims=3))
seq.add(BLayer.Squeeze(2, num_input_dims=2))
else:
seq.add(BLayer.Squeeze(2, num_input_dims=3))
seq.add(BLayer.Squeeze(1, num_input_dims=2))
return seq
[docs] def create_upsampling1d(self):
return BLayer.UpSampling1D(self.klayer.length)
[docs] def create_upsampling2d(self):
bigdl_order = self.get_bdim_order()
return BLayer.UpSampling2D(size=self.klayer.size,
data_format=bigdl_order)
[docs] def create_upsampling3d(self):
if self.klayer.dim_ordering != "th":
raise Exception("Please use th for dim_ordering. %s is not supported for now." % self.klayer.dim_ordering)
if "dim_ordering" not in self.config:
warnings.warn("Cannot find dim_ordering from json definition. Using the default instead."
"We only support th for now.")
return BLayer.UpSampling3D(self.klayer.size)
[docs] def create_gaussiannoise(self):
return BLayer.GaussianNoise(float(self.klayer.sigma))
[docs] def create_gaussiandropout(self):
return BLayer.GaussianDropout(float(self.klayer.p))
[docs] def create_highway(self):
if self.config["activation"] == 'linear':
activation = None
else:
activation = get_activation_by_name(self.config["activation"],
"%s_%s" % (self.config["name"], self.config["activation"]))
blayer = BLayer.Highway(size=int(self.input_shape[1]),
with_bias=self.klayer.bias,
activation=activation,
wRegularizer=to_bigdl_reg(self.config["W_regularizer"]),
bRegularizer=to_bigdl_reg(self.config["b_regularizer"]))
return blayer
[docs] def create_maxoutdense(self):
blayer = BLayer.Maxout(input_size=int(self.input_shape[1]),
output_size=self.klayer.output_dim,
maxout_number=self.klayer.nb_feature,
with_bias=self.klayer.bias,
w_regularizer=to_bigdl_reg(self.config["W_regularizer"]),
b_regularizer=to_bigdl_reg(self.config["b_regularizer"]))
return blayer
[docs] def create_masking(self):
return BLayer.Masking(float(self.klayer.mask_value))
[docs] def create_srelu(self):
if "shared_axes" not in self.config:
warnings.warn("Cannot find shared_axes from json definition. Using shared_axes=None instead.")
shape = self.input_shape[1:]
t_left_init = to_bigdl_init(self.config["t_left_init"])
a_left_init = to_bigdl_init(self.config["a_left_init"])
t_right_init = to_bigdl_init(self.config["t_right_init"])
a_right_init = to_bigdl_init(self.config["a_right_init"])
if self.klayer.shared_axes == [None]:
srelu = BLayer.SReLU(shape)
else:
srelu = BLayer.SReLU(shape, self.klayer.shared_axes)
srelu.set_init_method(t_left_init, a_left_init, t_right_init, a_right_init)
return srelu
[docs] def create_separableconvolution2d(self):
if keras.backend.backend() != 'tensorflow':
raise Exception('Please use tensorflow backend for keras 1.2.2 '
'if you want to load SeparableConv2D')
bigdl_order = self.get_bdim_order()
if bigdl_order == "NCHW":
stack_size = int(self.input_shape[1])
elif bigdl_order == "NHWC":
stack_size = int(self.input_shape[3])
bpadW, bpadH = to_bigdl_2d_padding(self.klayer.border_mode)
blayer = BLayer.SpatialSeperableConvolution(
n_input_channel=stack_size,
n_output_channel=self.klayer.nb_filter,
depth_multiplier=self.klayer.depth_multiplier,
kernel_w=self.klayer.nb_col,
kernel_h=self.klayer.nb_row,
stride_w=self.klayer.subsample[1],
stride_h=self.klayer.subsample[0],
pad_w=bpadW,
pad_h=bpadH,
with_bias=self.klayer.bias,
data_format=bigdl_order,
w_regularizer=to_bigdl_reg(self.config["depthwise_regularizer"]),
b_regularizer=to_bigdl_reg(self.config["b_regularizer"]),
p_regularizer=to_bigdl_reg(self.config["pointwise_regularizer"])
)
return self.combo_parameter_layer(blayer, self.config)
[docs] def create_activityregularization(self):
return BLayer.ActivityRegularization(l1=self.klayer.l1, l2=self.klayer.l2)
[docs] def create_spatialdropout1d(self):
return BLayer.SpatialDropout1D(init_p=float(self.klayer.p))
[docs] def create_spatialdropout2d(self):
bigdl_order = self.get_bdim_order()
blayer = BLayer.SpatialDropout2D(init_p=float(self.klayer.p),
data_format=bigdl_order)
return blayer
[docs] def create_spatialdropout3d(self):
bigdl_order = self.get_bdim_order()
blayer = BLayer.SpatialDropout3D(init_p=float(self.klayer.p),
data_format=bigdl_order)
return blayer
[docs] def create_locallyconnected1d(self):
seq = BLayer.Sequential()
seq.add(BLayer.Reshape([int(self.input_shape[1]), 1, int(self.input_shape[2])], True))
blayer = BLayer.LocallyConnected2D(n_input_plane=int(self.input_shape[2]),
input_width=1,
input_height=int(self.input_shape[1]),
n_output_plane=self.klayer.nb_filter,
kernel_w=1,
kernel_h=self.klayer.filter_length,
stride_w=1,
stride_h=self.klayer.subsample_length,
pad_w=0,
pad_h=0,
wRegularizer=to_bigdl_reg(self.config["W_regularizer"]),
bRegularizer=to_bigdl_reg(self.config["b_regularizer"]),
with_bias=self.klayer.bias,
data_format="NHWC")
seq.add(blayer)
seq.add(BLayer.Squeeze(3))
if self.config["activation"] != "linear":
activation = get_activation_by_name(self.config["activation"],
"%s_%s" % (self.config["name"], self.config["activation"]))
return self.fuse(seq, activation)
else:
return seq
[docs] def create_locallyconnected2d(self):
bigdl_order = self.get_bdim_order()
if bigdl_order == "NCHW":
stack_size = int(self.input_shape[1])
input_width = int(self.input_shape[3])
input_height = int(self.input_shape[2])
elif bigdl_order == "NHWC":
stack_size = int(self.input_shape[3])
input_width = int(self.input_shape[2])
input_height = int(self.input_shape[1])
bpadW, bpadH = to_bigdl_2d_padding(self.klayer.border_mode)
blayer = BLayer.LocallyConnected2D(n_input_plane=stack_size,
input_width=input_width,
input_height=input_height,
n_output_plane=self.klayer.nb_filter,
kernel_w=self.klayer.nb_col,
kernel_h=self.klayer.nb_row,
stride_w=self.klayer.subsample[1],
stride_h=self.klayer.subsample[0],
pad_w=bpadW,
pad_h=bpadH,
wRegularizer=to_bigdl_reg(self.config["W_regularizer"]),
bRegularizer=to_bigdl_reg(self.config["b_regularizer"]),
with_bias=self.klayer.bias,
data_format=bigdl_order)
if self.config["activation"] != "linear":
activation = get_activation_by_name(self.config["activation"],
"%s_%s" % (self.config["name"], self.config["activation"]))
return self.fuse(blayer, activation)
else:
return blayer
[docs] def combo_parameter_layer(self, blayer, config):
blayer.set_name(config["name"])
if hasattr(blayer, "set_init_method"):
try:
blayer.set_init_method(to_bigdl_init(config["init"]),
BInit.Zeros()) # Keras always set this to be zeros
except Exception:
warning_msg = "We don't support initialization " + config["init"] + " for now. " \
+ "Using the default instead."
warnings.warn(warning_msg)
# "linear" means doing nothing
if config["activation"] != "linear":
activation = get_activation_by_name(config["activation"],
"%s_%s" % (config["name"], config["activation"]))
return self.fuse(blayer, activation)
else:
return blayer
[docs] def get_value_from_init(self, kinit_method, shape):
if kinit_method == "zero":
return np.zeros(shape)
elif kinit_method == "one":
return np.ones(shape)
else:
raise Exception("We don't support % for now", kinit_method)
[docs] def fuse(self, src_blayer, activation): # activation is a layer
seq = BLayer.Sequential()
seq.add(src_blayer)
seq.add(activation)
seq.set_name(src_blayer.name())
return seq