Integrate blis/pythonapi-vnext-merge into master
This commit is contained in:
Коммит
7cf42393dd
|
@ -3,6 +3,6 @@ __version__ = '1.5'
|
|||
from .context import *
|
||||
from .graph import *
|
||||
from .objectives import *
|
||||
from .cntk1_ops import *
|
||||
from .ops.cntk2 import *
|
||||
from .optimizer import *
|
||||
from .reader import *
|
||||
|
|
|
@ -7,11 +7,9 @@ import numpy as np
|
|||
import shutil as sh
|
||||
|
||||
from cntk.graph import ComputationNode
|
||||
from cntk.cntk1_ops import NewReshape
|
||||
from cntk.utils import CNTK_EXECUTABLE_PATH
|
||||
|
||||
|
||||
_FLOATX = 'float32'
|
||||
from cntk.ops.cntk1 import NewReshape
|
||||
from cntk.utils import CNTK_EXECUTABLE_PATH, MODEL_INDENTATION
|
||||
from .utils import cntk_to_numpy_shape, dedupe_readers
|
||||
|
||||
CNTK_TEMPLATE_DIR = os.path.join(os.path.dirname(__file__), "templates")
|
||||
CNTK_TRAIN_TEMPLATE_PATH = os.path.join(
|
||||
|
@ -52,26 +50,27 @@ def get_new_context():
|
|||
|
||||
|
||||
class AbstractContext(object, metaclass=ABCMeta):
|
||||
|
||||
'''
|
||||
This is the abstract CNTK context. It provides an API to run CNTK actions.
|
||||
'''
|
||||
|
||||
def __init__(self, name,
|
||||
graph=None,
|
||||
optimizer=None,
|
||||
device_id=-1,
|
||||
root_node=None,
|
||||
clean_up=True):
|
||||
root_nodes=None,
|
||||
clean_up=True,
|
||||
node_unit_test=False):
|
||||
'''
|
||||
AbstractContext Constructer
|
||||
|
||||
:param name: context name
|
||||
:param graph: the computational graph to be used for training, testing and prediction
|
||||
:param optimizer: the SGD optimizer to use for training
|
||||
:param device_id: whether to use CPU or a specific GPU. -1 for CPU larger values
|
||||
:param root_node: the top node of the graph
|
||||
:param root_nodes: list of top nodes of the graph or single node itself
|
||||
:param clean_up: whether the temporary directory should be removed when the context is left
|
||||
are the GPUs indices.
|
||||
:param node_unit_test: set to True if you want to output the gradient of a node (backward pass)
|
||||
|
||||
'''
|
||||
if isinstance(name, str):
|
||||
|
@ -88,11 +87,14 @@ class AbstractContext(object, metaclass=ABCMeta):
|
|||
os.mkdir(self.directory)
|
||||
|
||||
self.name = name
|
||||
self.optimizer = optimizer
|
||||
self.device_id = device_id
|
||||
self.clean_up = clean_up
|
||||
self.input_nodes = set()
|
||||
self.root_node = root_node
|
||||
if root_nodes is None:
|
||||
self.root_nodes = None
|
||||
else:
|
||||
self.root_nodes = root_nodes if isinstance(root_nodes, list) else [root_nodes]
|
||||
self.node_unit_test= node_unit_test
|
||||
|
||||
def __enter__(self):
|
||||
_CONTEXT[self.name] = self
|
||||
|
@ -103,34 +105,65 @@ class AbstractContext(object, metaclass=ABCMeta):
|
|||
del _CONTEXT[self.name]
|
||||
|
||||
if self.clean_up:
|
||||
import shutil
|
||||
shutil.rmtree(self.directory)
|
||||
sh.rmtree(self.directory)
|
||||
|
||||
def to_config(self):
|
||||
def _generate_config(self, root_nodes=None):
|
||||
'''
|
||||
Generates the CNTK configuration for the root node.
|
||||
Helper function to create a configuration incorporating all root nodes
|
||||
'''
|
||||
return self.root_node.to_config()
|
||||
has_inputs = False
|
||||
|
||||
def _generate_train_config(self, reader, override_existing):
|
||||
desc = []
|
||||
inputs = set()
|
||||
readers = set()
|
||||
unrolled_nodes = {}
|
||||
node_counter = 0
|
||||
dep_inputs = tuple()
|
||||
reconciled_cache = {}
|
||||
|
||||
if root_nodes is None:
|
||||
root_nodes = self.root_nodes
|
||||
elif not isinstance(root_nodes, list):
|
||||
root_nodes = [root_nodes]
|
||||
|
||||
for root_node in root_nodes:
|
||||
var_name, node_counter, _desc, _has_inputs, _readers, _dep_inputs = \
|
||||
root_node._to_config(desc,
|
||||
unrolled_nodes,
|
||||
inputs,
|
||||
readers,
|
||||
dep_inputs,
|
||||
node_counter, reconciled_cache)
|
||||
|
||||
has_inputs |= _has_inputs
|
||||
readers |= _readers
|
||||
dep_inputs += _dep_inputs
|
||||
|
||||
description = "\n".join(desc)
|
||||
|
||||
return description, has_inputs, dedupe_readers(readers)
|
||||
|
||||
def _generate_train_config(self, optimizer, reader, override_existing):
|
||||
'''
|
||||
Generates the configuration file for the train action.
|
||||
:param optimizer: the SGD optimizer to use for training
|
||||
:param reader: the reader to use for reading the data
|
||||
:param override_existing: if the folder exists already override it
|
||||
'''
|
||||
|
||||
model_dir = os.path.join(self.directory, 'Models')
|
||||
if os.path.exists(model_dir) and os.listdir(model_dir) == []:
|
||||
if os.path.exists(model_dir):
|
||||
if override_existing:
|
||||
print ("Overriding the existing models")
|
||||
print("Overriding the existing models")
|
||||
sh.rmtree(model_dir)
|
||||
else:
|
||||
raise Exception("Directory '%s' already exists, set the flag override_existing to true if you want to override it"
|
||||
%self.directory)
|
||||
raise Exception("Directory '%s' already exists, set the " +
|
||||
"flag override_existing to true if you want to "
|
||||
"override it" % self.directory)
|
||||
|
||||
tmpl = open(CNTK_TRAIN_TEMPLATE_PATH, "r").read()
|
||||
model_filename = os.path.join(model_dir, self.name)
|
||||
description, has_inputs, readers = self.to_config()
|
||||
description, has_inputs, readers = self._generate_config()
|
||||
if reader:
|
||||
readers.append(reader)
|
||||
|
||||
|
@ -139,7 +172,7 @@ class AbstractContext(object, metaclass=ABCMeta):
|
|||
'ModelDescription': description,
|
||||
'ModelPath': model_filename,
|
||||
'Reader': '\n'.join(r.generate_config() for r in readers),
|
||||
'SGD': self.optimizer.generate_config(),
|
||||
'SGD': optimizer.generate_config(),
|
||||
}
|
||||
return tmpl % tmpl_dict
|
||||
|
||||
|
@ -149,10 +182,18 @@ class AbstractContext(object, metaclass=ABCMeta):
|
|||
'''
|
||||
tmpl = open(CNTK_TEST_TEMPLATE_PATH, "r").read()
|
||||
model_filename = os.path.join(self.directory, 'Models', self.name)
|
||||
|
||||
# if no reader is passed generate the reader from the network
|
||||
if reader:
|
||||
reader_config = reader.generate_config()
|
||||
else:
|
||||
description, has_inputs, readers = self._generate_config()
|
||||
reader_config = '\n'.join(r.generate_config() for r in readers)
|
||||
|
||||
tmpl_dict = {
|
||||
'DevideId': self.device_id,
|
||||
'ModelPath': model_filename,
|
||||
'Reader': reader.generate_config(),
|
||||
'Reader': reader_config,
|
||||
}
|
||||
return tmpl % tmpl_dict
|
||||
|
||||
|
@ -163,50 +204,60 @@ class AbstractContext(object, metaclass=ABCMeta):
|
|||
'''
|
||||
tmpl = open(CNTK_PREDICT_TEMPLATE_PATH, "r").read()
|
||||
model_filename = os.path.join(self.directory, 'Models', self.name)
|
||||
output_filename_base = os.path.join(self.directory, 'Outputs', self.name)
|
||||
output_filename_base = os.path.join(
|
||||
self.directory, 'Outputs', self.name)
|
||||
|
||||
# if no reader is passed generate the reader from the network
|
||||
if reader:
|
||||
reader_config = reader.generate_config()
|
||||
else:
|
||||
description, has_inputs, readers = self._generate_config()
|
||||
reader_config = '\n'.join(r.generate_config() for r in readers)
|
||||
|
||||
tmpl_dict = {
|
||||
'DevideId': self.device_id,
|
||||
'ModelPath': model_filename,
|
||||
'PredictOutputFile': output_filename_base,
|
||||
'Reader': reader.generate_config(),
|
||||
'Reader': reader_config,
|
||||
}
|
||||
return tmpl % tmpl_dict
|
||||
|
||||
def _generate_eval_config(self, root_node, reader):
|
||||
def _generate_eval_config(self, root_nodes, reader):
|
||||
'''
|
||||
Generates the configuration file for write action.
|
||||
:param root_node: the node to evaluate.
|
||||
:param root_nodes: the node to evaluate.
|
||||
:param reader: the reader used to load the data, None if the network does not have input
|
||||
'''
|
||||
model_description, has_input, readers = root_node.to_config()
|
||||
description, has_inputs, readers = self._generate_config(root_nodes)
|
||||
if reader:
|
||||
readers.append(reader)
|
||||
|
||||
if not has_input and not readers:
|
||||
if not has_inputs and not readers:
|
||||
# add dummy input to keep CNTK happy
|
||||
# TODO relieve this requirement on CNTK side
|
||||
data = [[1, 2], [3, 4]]
|
||||
fn = os.path.join(self.directory, 'dummy_input.txt')
|
||||
from .reader import NumPyReader
|
||||
reader = NumPyReader(data, fn)
|
||||
from .cntk1_ops import Input
|
||||
from .ops.cntk1 import Input
|
||||
dummy_input_node = Input(2, var_name='dummy_node')
|
||||
reader.add_input(dummy_input_node, 0, 2)
|
||||
model_description += "\ndummy_node=Input(2, tag='output')"
|
||||
description += "\n" + " "*MODEL_INDENTATION + "dummy_node = Input(2, tag='output')"
|
||||
readers.append(reader)
|
||||
|
||||
tmpl = open(CNTK_EVAL_TEMPLATE_PATH, "r").read()
|
||||
output_filename = os.path.join(self.directory, CNTK_OUTPUT_FILENAME)
|
||||
tmpl_dict = {
|
||||
'DevideId': self.device_id,
|
||||
'NodeUnitTest': self.node_unit_test,
|
||||
'OutputFile': output_filename,
|
||||
'ModelDescription': model_description,
|
||||
'ModelDescription': description,
|
||||
'Reader': '\n'.join(r.generate_config() for r in readers),
|
||||
}
|
||||
return tmpl % tmpl_dict
|
||||
|
||||
@abstractmethod
|
||||
def train(self, reader=None):
|
||||
def train(self, optimizer, reader=None, override_existing=True):
|
||||
'''
|
||||
Abstract method for the action train.
|
||||
:param reader: the reader to use for this action. Alternatively, you
|
||||
|
@ -265,31 +316,38 @@ class Context(AbstractContext):
|
|||
retrieve the node shapes.
|
||||
'''
|
||||
filename = os.path.join(self.directory, config_file_name)
|
||||
with open(os.path.join(self.directory, filename), "w") as out:
|
||||
with open(os.path.join(self.directory, filename), 'w') as out:
|
||||
out.write(config_content)
|
||||
|
||||
try:
|
||||
output = subprocess.check_output(
|
||||
[CNTK_EXECUTABLE_PATH, "configFile=%s" % filename],
|
||||
output_bytes = subprocess.check_output(
|
||||
[CNTK_EXECUTABLE_PATH, 'configFile=%s' % filename],
|
||||
stderr=subprocess.STDOUT)
|
||||
output = output_bytes.decode('utf-8')
|
||||
with open(os.path.join(self.directory, 'cntk.log'), 'w') as log:
|
||||
log.write(output)
|
||||
|
||||
except subprocess.CalledProcessError as e:
|
||||
print(e.output.decode("utf-8"), file=open('error.txt', 'w'))
|
||||
print(e.output.decode('utf-8'), file=open('error.txt', 'w'))
|
||||
raise
|
||||
|
||||
if not output:
|
||||
raise ValueError('no output returned')
|
||||
|
||||
return output.decode("utf-8")
|
||||
return output
|
||||
|
||||
def train(self, reader=None, override_existing = True):
|
||||
def train(self, optimizer, reader=None, override_existing=True):
|
||||
'''
|
||||
Run the train action locally.
|
||||
:param optimizer: the SGD optimizer to use for training
|
||||
:param reader: the reader to use for this action. Alternatively, you
|
||||
can attach a reader directly to the input node.
|
||||
:param override_existing: if the folder exists already override it
|
||||
'''
|
||||
config_content = self._generate_train_config(reader, override_existing)
|
||||
output = self._call_cntk(CNTK_TRAIN_CONFIG_FILENAME, config_content)
|
||||
|
||||
config_content = self._generate_train_config(
|
||||
optimizer, reader, override_existing)
|
||||
return self._call_cntk(CNTK_TRAIN_CONFIG_FILENAME, config_content)
|
||||
|
||||
def test(self, reader=None):
|
||||
'''
|
||||
|
@ -300,6 +358,9 @@ class Context(AbstractContext):
|
|||
config_content = self._generate_test_config(reader)
|
||||
output = self._call_cntk(CNTK_TEST_CONFIG_FILENAME, config_content)
|
||||
|
||||
return Context._parse_test_result(output)
|
||||
|
||||
|
||||
def predict(self, reader=None):
|
||||
'''
|
||||
Run the write action locally, use the trained model of this context.
|
||||
|
@ -309,13 +370,14 @@ class Context(AbstractContext):
|
|||
Returns the predicted output
|
||||
'''
|
||||
config_content = self._generate_predict_config(reader)
|
||||
output = self._call_cntk(CNTK_PREDICT_CONFIG_FILENAME, config_content)
|
||||
return self._call_cntk(CNTK_PREDICT_CONFIG_FILENAME, config_content)
|
||||
|
||||
'''
|
||||
Regular expression to parse the shape information of the nodes out of
|
||||
CNTK's output
|
||||
'''
|
||||
VAR_SHAPE_REGEX = re.compile('^Validating --> (?P<var_name>[^ ]+) = [^>]*> \[(?P<shape>[^]]+)')
|
||||
VAR_SHAPE_REGEX = re.compile(
|
||||
'^Validating --> (?P<var_name>[^ ]+) = [^>]*> \[(?P<shape>[^]]+)')
|
||||
SHAPE_STRIDE_REGEX = re.compile('\{.*?\}')
|
||||
|
||||
@staticmethod
|
||||
|
@ -330,28 +392,158 @@ class Context(AbstractContext):
|
|||
if not mo:
|
||||
continue
|
||||
var_name, shape = mo.group('var_name'), mo.group('shape')
|
||||
# In Debug mode, an additional stride information is printed
|
||||
shape = Context.SHAPE_STRIDE_REGEX.sub('', shape)
|
||||
|
||||
shape_list = []
|
||||
for x in Context.SHAPE_STRIDE_REGEX.sub('', shape).split('x'):
|
||||
for x in shape.split('x'):
|
||||
x = x.strip()
|
||||
if x != '*':
|
||||
if x == '*':
|
||||
shape_list.append(np.NaN)
|
||||
else:
|
||||
shape_list.append(int(x))
|
||||
|
||||
var_shape[var_name] = tuple(shape_list)
|
||||
|
||||
return var_shape
|
||||
|
||||
def _eval(self, node, reader):
|
||||
# FIXME manually setting the tag to output might have side-effects
|
||||
node.tag = 'output'
|
||||
config_content = self._generate_eval_config(node, reader)
|
||||
output = self._call_cntk(CNTK_EVAL_CONFIG_FILENAME, config_content)
|
||||
shapes = Context._parse_shapes_from_output(output)
|
||||
@staticmethod
|
||||
def _parse_result_output(output):
|
||||
'''
|
||||
Assuming the data has been output using the output format in the
|
||||
configuration
|
||||
|
||||
out_name = os.path.join(self.directory, CNTK_OUTPUT_FILENAME + '.' + node.var_name)
|
||||
data = np.loadtxt(out_name)
|
||||
format = [
|
||||
# %x = shape, %d = sequenceId
|
||||
sequencePrologue=%d\t|w.shape %x\n%d\t|w\s
|
||||
sampleSeparator=\n%d\t|w\s
|
||||
elementSeparator=\s
|
||||
]
|
||||
|
||||
return data, shapes
|
||||
this method will parse the output of the form
|
||||
|
||||
0 |w.shape 1 1
|
||||
0 |w 60.000000
|
||||
1 |w.shape 1 2
|
||||
1 |w 22.000000
|
||||
1 |w 24.000000
|
||||
|
||||
and return a list of tensors.
|
||||
'''
|
||||
|
||||
last_seq_idx = None
|
||||
list_of_tensors = []
|
||||
tensor_seq = []
|
||||
shape = None
|
||||
for line in output.splitlines():
|
||||
parts = line.split('|')
|
||||
|
||||
seq_idx = parts[0].strip()
|
||||
payload = parts[1]
|
||||
info, *data = payload.split(' ')
|
||||
|
||||
if seq_idx != last_seq_idx:
|
||||
if not info == 'w.shape':
|
||||
raise ValueError('expected shape information, but got "%s"'%line)
|
||||
|
||||
if tensor_seq:
|
||||
list_of_tensors.append(np.asarray(tensor_seq))
|
||||
tensor_seq = []
|
||||
|
||||
last_seq_idx = seq_idx
|
||||
|
||||
shape = cntk_to_numpy_shape(data)
|
||||
|
||||
continue
|
||||
else:
|
||||
data = np.asarray(data, dtype=float).reshape(shape)
|
||||
|
||||
tensor_seq.append(data)
|
||||
|
||||
list_of_tensors.append(np.asarray(tensor_seq))
|
||||
|
||||
return list_of_tensors
|
||||
|
||||
TEST_RESULT_REGEX = re.compile('(?P<name>[^:]+): [^=]+ = (?P<number>[0-9.]+)')
|
||||
|
||||
@staticmethod
|
||||
def _parse_test_result(output):
|
||||
result = {}
|
||||
|
||||
PREAMPLE = 'Final Results: Minibatch[1-1]: '
|
||||
for line in output.splitlines():
|
||||
|
||||
if not line.startswith(PREAMPLE):
|
||||
continue
|
||||
|
||||
line = line[len(PREAMPLE):]
|
||||
|
||||
if not line.startswith('SamplesSeen = '):
|
||||
raise ValueError('expected SamplesSeen but got "%s"'%line)
|
||||
|
||||
line = line[len('SamplesSeen = '):]
|
||||
number_ends = line.index(' ')
|
||||
result['SamplesSeen'] = int(line[:number_ends])
|
||||
line = line[number_ends:]
|
||||
|
||||
perplexity_idx = line.index('Perplexity = ')
|
||||
result['Perplexity'] = float(line[perplexity_idx+len('Perplexity = '):])
|
||||
|
||||
line = line[:perplexity_idx]
|
||||
|
||||
mo = Context.TEST_RESULT_REGEX.match(line)
|
||||
while mo:
|
||||
result[mo.group('name').strip()] = float(mo.group('number').strip())
|
||||
line = line[mo.span()[1]:]
|
||||
mo = Context.TEST_RESULT_REGEX.match(line)
|
||||
|
||||
return result
|
||||
|
||||
def _calc_expected_shape_and_size(self, node, data, shapes):
|
||||
'''
|
||||
Calculates the expected shape and size from the CNTK output and the
|
||||
retrieved data.
|
||||
|
||||
:param node: the node that was evaluated.
|
||||
:param data: the resulting data from `eval()`
|
||||
:param shapes: dictionary of node names to shape tuples
|
||||
|
||||
Returns the expected size and shape
|
||||
'''
|
||||
|
||||
# We got a single-dimensional array back, so we have to check whether
|
||||
# we need to reshape it based on CNTK's shape output.
|
||||
|
||||
expected_shape = np.asarray(shapes[node.var_name])
|
||||
|
||||
if sum(np.isnan(expected_shape))>1:
|
||||
raise ValueError("for node '%s' we received shape '%s', but " +
|
||||
"at most one dimension can be left unspecified."%\
|
||||
(node.var_name, expected_shape))
|
||||
|
||||
expected_size = np.multiply.reduce(expected_shape[~np.isnan(expected_shape)])
|
||||
if sum(np.isnan(expected_shape))==1:
|
||||
if data.size == expected_size:
|
||||
# We received all the data we need, so we have sequences of
|
||||
# length 1. For convenience, we ignore it.
|
||||
expected_shape = expected_shape[~np.isnan(expected_shape)]
|
||||
|
||||
elif data.size > expected_size:
|
||||
# We can fill in the missing dimensions
|
||||
missing_dimension = data.size / expected_size
|
||||
if int(missing_dimension) != missing_dimension:
|
||||
raise ValueError('could not infer the missing dimensions')
|
||||
|
||||
expected_shape[np.isnan(expected_shape)] = missing_dimension
|
||||
expected_size = np.multiply.reduce(expected_shape)
|
||||
# Now we have expected_size == data.size
|
||||
else:
|
||||
raise ValueError('unable to retrieve expected size')
|
||||
|
||||
# Move last dimension to the beginning: this is the time dimension
|
||||
#expected_shape = np.roll(expected_shape, 1)
|
||||
|
||||
return expected_shape, expected_size
|
||||
|
||||
def eval(self, node, reader=None):
|
||||
'''
|
||||
|
@ -365,31 +557,31 @@ class Context(AbstractContext):
|
|||
Returns the output generated by `node`
|
||||
'''
|
||||
if not isinstance(node, ComputationNode):
|
||||
raise ValueError('node is not of type ComputationNode, but %s'%type(node))
|
||||
raise ValueError(
|
||||
'node is not of type ComputationNode, but %s' % type(node))
|
||||
|
||||
data, shapes = self._eval(node, reader)
|
||||
# Taking note of the original tag of this node to restore it later
|
||||
orig_node_tag = node.tag if hasattr(node, 'tag') else None
|
||||
node.tag = 'output'
|
||||
|
||||
expected_size = np.multiply.reduce(shapes[node.var_name])
|
||||
expected_shape = shapes[node.var_name]
|
||||
config_content = self._generate_eval_config(node, reader)
|
||||
output = self._call_cntk(CNTK_EVAL_CONFIG_FILENAME, config_content)
|
||||
|
||||
receieved_all = data.size == expected_size
|
||||
if not receieved_all:
|
||||
# For some reason the CNTK write action has issues with multi-row
|
||||
# output. So we have to CNTK reshape it to one row and do it again,
|
||||
# but then NumPy reshape using node's expected shape.
|
||||
node.tag = orig_node_tag
|
||||
|
||||
reshaped = NewReshape(node, expected_size)
|
||||
data, _ = self._eval(reshaped, reader)
|
||||
shapes = Context._parse_shapes_from_output(output)
|
||||
|
||||
if not (len(expected_shape)==2 and expected_shape[1] == 1):
|
||||
# CNTK outputs e.g. [2 x 1] although it is just a vector.
|
||||
# TODO find better way to distinguis between
|
||||
data = data.reshape(expected_shape)
|
||||
out_name = os.path.join(
|
||||
self.directory, CNTK_OUTPUT_FILENAME + '.' + node.var_name)
|
||||
#data = np.loadtxt(out_name)
|
||||
result_content = open(out_name).read()
|
||||
data = Context._parse_result_output(result_content)
|
||||
|
||||
return data
|
||||
|
||||
|
||||
class ClusterContext(AbstractContext):
|
||||
|
||||
'''
|
||||
This is a sub-class of AbstractContext, use it to submit your workloads to the cluster.
|
||||
'''
|
||||
|
|
|
@ -8,7 +8,7 @@ from cntk import *
|
|||
|
||||
if (__name__ == "__main__"):
|
||||
|
||||
X = constant(np.asarray([[2,3], [4,5]]))
|
||||
X = constant(np.asarray([[2, 3], [4, 5]]))
|
||||
out = 2.5 * X + 100
|
||||
|
||||
with Context('demo', clean_up=False) as ctx:
|
||||
|
|
|
@ -0,0 +1,500 @@
|
|||
3.854499 4.163941 1
|
||||
1.058121 1.204858 0
|
||||
1.870621 1.284107 0
|
||||
1.134650 1.651822 0
|
||||
5.420541 4.557660 1
|
||||
6.042731 3.375708 1
|
||||
5.667109 2.811728 1
|
||||
0.232070 1.814821 0
|
||||
-0.647150 -1.612478 0
|
||||
2.626172 5.321667 1
|
||||
1.359751 2.056849 0
|
||||
3.534476 6.011925 1
|
||||
4.871508 2.245406 1
|
||||
4.977201 6.092787 1
|
||||
1.597508 2.110568 0
|
||||
2.099170 0.073616 0
|
||||
0.638281 -0.171881 0
|
||||
4.606747 4.092115 1
|
||||
5.168790 4.673153 1
|
||||
5.084637 4.435160 1
|
||||
3.379607 2.765107 1
|
||||
3.992242 2.799751 1
|
||||
1.807728 0.205914 0
|
||||
1.946180 0.303569 0
|
||||
0.218267 1.301271 0
|
||||
4.932840 2.117177 1
|
||||
3.739489 2.458558 1
|
||||
1.597743 -2.192362 0
|
||||
3.582005 3.350572 1
|
||||
3.930642 5.733507 1
|
||||
5.747863 3.739415 1
|
||||
-0.631374 2.314482 0
|
||||
0.866484 0.363432 0
|
||||
0.293501 0.347385 0
|
||||
4.544393 4.699040 1
|
||||
-0.242005 0.926520 0
|
||||
3.637198 5.238140 1
|
||||
-0.269463 1.525586 0
|
||||
0.682529 -0.703649 0
|
||||
3.562643 -0.126556 0
|
||||
2.671530 3.729066 1
|
||||
4.034716 3.458366 1
|
||||
5.401503 3.117191 1
|
||||
1.157177 1.183186 0
|
||||
0.778963 1.394348 0
|
||||
4.599715 2.297663 1
|
||||
4.532568 4.568362 1
|
||||
1.785478 -0.213185 0
|
||||
4.617391 4.230360 1
|
||||
5.672957 3.668370 1
|
||||
4.267738 5.390780 1
|
||||
0.707751 2.955391 0
|
||||
0.791275 1.654795 0
|
||||
1.760541 0.976920 0
|
||||
4.543920 2.222765 1
|
||||
4.515881 6.199021 1
|
||||
3.645005 3.611395 1
|
||||
0.965049 1.737265 0
|
||||
-1.779455 1.595554 0
|
||||
-0.484797 -0.559924 0
|
||||
2.944180 4.429239 1
|
||||
3.326649 4.412622 1
|
||||
4.275101 2.143945 1
|
||||
1.173035 0.641844 0
|
||||
4.003884 3.176954 1
|
||||
1.960240 -0.244709 0
|
||||
0.320283 2.115552 0
|
||||
2.303185 3.047043 1
|
||||
0.993086 0.074009 0
|
||||
5.599144 3.857344 1
|
||||
5.325894 3.931000 1
|
||||
2.840053 4.781688 1
|
||||
4.142453 3.405830 1
|
||||
1.084043 1.589581 0
|
||||
2.795705 2.319276 1
|
||||
1.980552 0.717780 0
|
||||
1.875956 -0.571905 0
|
||||
2.013802 1.694811 0
|
||||
4.690795 2.183334 1
|
||||
4.321816 1.876459 1
|
||||
4.088717 4.394346 1
|
||||
4.991936 4.299770 1
|
||||
2.592315 4.783210 1
|
||||
0.703270 2.541733 0
|
||||
0.467768 -0.007592 0
|
||||
1.694096 -0.570847 0
|
||||
2.255603 0.663395 0
|
||||
1.300394 1.518341 0
|
||||
4.354786 4.501928 1
|
||||
1.474162 0.603113 0
|
||||
1.340782 0.637653 0
|
||||
-0.351240 0.501893 0
|
||||
4.918587 5.366305 1
|
||||
2.242199 -0.916682 0
|
||||
-0.161858 0.448384 0
|
||||
1.659615 1.524191 0
|
||||
3.072670 1.703225 0
|
||||
0.003256 -0.306702 0
|
||||
-1.792094 1.193539 0
|
||||
7.200298 3.962190 1
|
||||
4.220305 4.190289 1
|
||||
4.096599 3.264797 1
|
||||
-0.674145 0.751491 0
|
||||
3.215213 4.549768 1
|
||||
1.522988 3.311437 0
|
||||
4.393445 1.822070 1
|
||||
1.991048 1.429309 0
|
||||
4.741012 3.169984 1
|
||||
2.563678 1.798587 0
|
||||
3.310656 3.600789 1
|
||||
0.559119 -0.193984 0
|
||||
3.182626 3.279566 1
|
||||
0.145061 1.428861 0
|
||||
5.748625 2.766672 1
|
||||
1.612338 -0.441931 0
|
||||
0.521950 0.355267 0
|
||||
4.284910 3.874950 1
|
||||
4.911425 3.054658 1
|
||||
2.946163 0.502614 0
|
||||
4.381390 2.600999 1
|
||||
0.585791 -0.528432 0
|
||||
1.329802 -0.076910 0
|
||||
0.860040 1.153562 0
|
||||
0.930515 -0.257435 0
|
||||
2.775174 0.751338 0
|
||||
2.429059 0.615483 0
|
||||
2.546002 1.132210 0
|
||||
5.059000 3.423829 1
|
||||
1.303533 0.013015 0
|
||||
2.160149 -0.400779 0
|
||||
5.038046 3.027673 1
|
||||
4.583471 5.379319 1
|
||||
5.608845 2.082021 1
|
||||
3.406426 3.326734 1
|
||||
4.267102 3.866177 1
|
||||
1.799669 0.489094 0
|
||||
1.807634 2.029468 0
|
||||
1.536463 1.053052 0
|
||||
5.653295 3.369125 1
|
||||
2.493326 0.794542 0
|
||||
1.528977 0.961929 0
|
||||
1.973016 0.696162 0
|
||||
2.283974 0.198255 0
|
||||
5.227293 4.395268 1
|
||||
5.302484 4.021613 1
|
||||
6.223076 4.537934 1
|
||||
1.460204 -1.055539 0
|
||||
2.985097 4.228990 1
|
||||
1.685054 0.499576 0
|
||||
0.521659 0.510605 0
|
||||
1.891089 1.284388 0
|
||||
4.620926 3.662371 1
|
||||
1.613905 -0.770152 0
|
||||
6.007418 4.755721 1
|
||||
0.798078 -0.304557 0
|
||||
5.242706 2.099872 1
|
||||
1.518268 -0.858963 0
|
||||
3.733642 4.244483 1
|
||||
0.970367 -1.534686 0
|
||||
1.334952 2.250191 0
|
||||
2.252214 3.343515 1
|
||||
3.982213 4.457969 1
|
||||
5.086620 3.180442 1
|
||||
0.005277 0.197319 0
|
||||
2.999128 2.909942 1
|
||||
2.412666 2.046286 0
|
||||
2.044537 3.416533 1
|
||||
2.650439 3.372171 1
|
||||
2.480446 1.327368 0
|
||||
4.824915 5.603495 1
|
||||
0.759204 0.531043 0
|
||||
1.965476 1.372763 0
|
||||
1.000248 1.208139 0
|
||||
1.979980 -0.446807 0
|
||||
0.528053 1.178535 0
|
||||
5.442396 3.969797 1
|
||||
-0.145691 1.375993 0
|
||||
1.336725 -0.006089 0
|
||||
5.291797 3.250537 1
|
||||
4.286453 1.117735 1
|
||||
-0.928654 -0.925485 0
|
||||
3.332391 2.603963 1
|
||||
3.215562 4.756808 1
|
||||
1.610967 0.830856 0
|
||||
2.174433 3.501271 1
|
||||
4.848584 4.251824 1
|
||||
0.810184 1.152021 0
|
||||
4.873924 4.517936 1
|
||||
1.915303 1.649095 0
|
||||
1.623343 -0.081105 0
|
||||
1.944076 0.482732 0
|
||||
2.442956 1.254540 0
|
||||
-1.002581 1.265333 0
|
||||
0.959354 0.678516 0
|
||||
-0.478621 2.502554 0
|
||||
3.357642 2.993470 1
|
||||
5.741979 2.958477 1
|
||||
4.474261 3.260622 1
|
||||
3.587932 4.572091 1
|
||||
1.274866 0.695311 0
|
||||
4.557162 4.754880 1
|
||||
0.557867 0.280893 0
|
||||
1.832047 -2.162059 0
|
||||
3.904049 5.257427 1
|
||||
3.225019 3.845294 1
|
||||
4.451218 4.125344 1
|
||||
3.138143 2.869685 1
|
||||
4.451703 3.430654 1
|
||||
0.124060 1.422203 0
|
||||
4.692774 5.156611 1
|
||||
0.735314 0.375099 0
|
||||
0.727577 1.158726 0
|
||||
0.643469 0.283426 0
|
||||
5.126834 1.929468 1
|
||||
-0.172361 2.982370 0
|
||||
3.957745 1.561874 1
|
||||
5.563733 3.417080 1
|
||||
5.181533 1.465063 1
|
||||
5.843654 5.040710 1
|
||||
0.761570 0.171094 0
|
||||
3.163795 3.940869 1
|
||||
2.435362 1.047614 0
|
||||
2.524330 3.602348 1
|
||||
4.200838 3.267377 1
|
||||
4.249560 2.926280 1
|
||||
0.060257 0.295729 0
|
||||
1.528257 1.651867 0
|
||||
2.030978 1.566011 0
|
||||
4.065243 4.375190 1
|
||||
1.406204 0.238570 0
|
||||
1.229776 1.186559 0
|
||||
2.295681 1.883864 0
|
||||
3.966570 4.293142 1
|
||||
1.713323 0.534886 0
|
||||
0.772032 -0.096214 0
|
||||
3.392854 5.195064 1
|
||||
5.063653 2.749764 1
|
||||
1.410392 1.694554 0
|
||||
0.540269 0.376759 0
|
||||
4.103946 3.870140 1
|
||||
5.132739 3.079176 1
|
||||
2.524063 0.486934 0
|
||||
0.046403 1.452778 0
|
||||
1.705593 0.243750 0
|
||||
1.621902 0.203138 0
|
||||
-0.420733 0.589060 0
|
||||
2.887145 2.621849 1
|
||||
5.545509 4.473069 1
|
||||
0.326439 -0.162102 0
|
||||
0.906097 -0.018566 0
|
||||
3.398280 5.125843 1
|
||||
0.833088 -0.808535 0
|
||||
4.535285 4.133511 1
|
||||
1.781705 4.123651 1
|
||||
4.345894 3.355084 1
|
||||
4.770073 3.007432 1
|
||||
2.537267 3.813503 1
|
||||
0.994347 2.567949 0
|
||||
0.337262 -0.224479 0
|
||||
4.936596 3.107819 1
|
||||
2.177957 -0.544641 0
|
||||
3.434811 2.806362 1
|
||||
3.172973 4.378089 1
|
||||
4.015349 3.000845 1
|
||||
3.640748 3.917499 1
|
||||
5.432434 4.092587 1
|
||||
4.701984 4.063092 1
|
||||
3.978015 3.584431 1
|
||||
5.029923 2.346036 1
|
||||
4.939017 3.209084 1
|
||||
3.999592 2.747525 1
|
||||
5.233483 4.877698 1
|
||||
2.260049 1.023384 0
|
||||
-1.149943 1.257165 0
|
||||
-0.026270 0.468090 0
|
||||
5.155107 4.620842 1
|
||||
4.179414 4.807546 1
|
||||
2.560286 0.526253 0
|
||||
5.843334 1.439470 1
|
||||
4.417442 4.483117 1
|
||||
4.354138 4.496168 1
|
||||
0.873730 2.230023 0
|
||||
4.531298 4.944164 1
|
||||
2.010164 -0.358403 0
|
||||
1.165044 1.376602 0
|
||||
1.451538 -0.197779 0
|
||||
-1.751961 0.210820 0
|
||||
2.431281 3.878465 1
|
||||
3.311168 3.697618 1
|
||||
2.324742 -0.330745 0
|
||||
1.447031 1.028776 0
|
||||
0.711003 2.631227 0
|
||||
4.872934 3.406132 1
|
||||
2.419345 0.297983 0
|
||||
0.437814 2.851194 0
|
||||
3.105758 4.098041 1
|
||||
5.310168 3.519401 1
|
||||
1.218607 -1.505891 0
|
||||
6.053827 2.848790 1
|
||||
3.475758 3.352349 1
|
||||
0.911730 -0.213069 0
|
||||
1.255973 0.089677 0
|
||||
4.152711 3.871858 1
|
||||
3.003909 3.288998 1
|
||||
0.291281 1.124965 0
|
||||
2.155017 0.550642 0
|
||||
3.494102 0.710991 0
|
||||
4.376613 2.330150 1
|
||||
4.707851 6.179972 1
|
||||
0.614240 -0.243535 0
|
||||
1.130049 0.870765 0
|
||||
3.994615 2.855247 1
|
||||
1.556420 0.106179 0
|
||||
3.182309 5.121422 1
|
||||
2.315933 0.418897 0
|
||||
1.797904 0.633645 0
|
||||
4.012446 3.887718 1
|
||||
2.106849 3.776831 1
|
||||
4.477828 3.989422 1
|
||||
2.871290 4.610706 1
|
||||
5.317459 5.621137 1
|
||||
2.265963 -0.095395 0
|
||||
2.963642 2.804267 1
|
||||
5.859384 3.673343 1
|
||||
6.365340 3.541960 1
|
||||
1.450987 0.721751 0
|
||||
4.641593 2.436289 1
|
||||
-0.126649 0.101750 0
|
||||
1.835293 1.594895 0
|
||||
2.121195 0.152643 0
|
||||
1.881799 1.169974 0
|
||||
2.421852 -0.089441 0
|
||||
0.110206 -1.491046 0
|
||||
6.200556 4.284843 1
|
||||
3.545593 5.217408 1
|
||||
3.365187 2.790974 1
|
||||
6.493131 5.311132 1
|
||||
0.800791 0.229630 0
|
||||
4.975666 4.214251 1
|
||||
1.562586 0.181976 0
|
||||
0.899273 0.003180 0
|
||||
6.064242 3.482802 1
|
||||
1.777259 2.498596 0
|
||||
5.479965 5.168898 1
|
||||
4.671380 3.356556 1
|
||||
1.730588 0.417775 0
|
||||
2.463118 -0.305587 0
|
||||
3.967679 0.361350 0
|
||||
0.164925 -0.167591 0
|
||||
4.777002 3.088492 1
|
||||
2.049808 3.096552 0
|
||||
1.416130 -1.043606 0
|
||||
0.318913 -1.539956 0
|
||||
6.004351 2.521442 1
|
||||
2.969229 3.311301 1
|
||||
0.879291 0.094171 0
|
||||
5.290177 5.198102 1
|
||||
-0.305314 0.826116 0
|
||||
2.091880 -1.176581 0
|
||||
2.816867 2.875016 1
|
||||
0.486424 -1.055319 0
|
||||
3.012812 4.530291 1
|
||||
1.137009 1.323397 0
|
||||
0.088114 -0.353501 0
|
||||
1.174005 0.188025 0
|
||||
1.928114 1.398347 0
|
||||
0.128505 1.430034 0
|
||||
2.021187 0.577234 0
|
||||
1.361335 0.394605 0
|
||||
5.125811 4.221355 1
|
||||
0.260733 1.758422 0
|
||||
2.106970 0.305971 0
|
||||
3.675850 5.051226 1
|
||||
2.105405 0.240527 0
|
||||
3.072167 3.130910 1
|
||||
0.987479 0.036861 0
|
||||
-0.271382 0.094250 0
|
||||
4.703495 2.620398 1
|
||||
3.005831 2.220124 1
|
||||
5.072896 1.477152 1
|
||||
4.443991 3.679157 1
|
||||
0.845034 0.419956 0
|
||||
4.698964 3.109439 1
|
||||
1.766144 0.595496 0
|
||||
2.046076 0.433007 0
|
||||
0.874663 1.010155 0
|
||||
4.939031 5.340021 1
|
||||
3.881158 3.072467 1
|
||||
2.928763 4.160337 1
|
||||
5.582289 4.805588 1
|
||||
3.180992 3.459563 1
|
||||
-0.486820 -0.074926 0
|
||||
4.091057 2.402846 1
|
||||
4.915464 4.543850 1
|
||||
1.492434 0.588755 0
|
||||
2.594011 0.332043 0
|
||||
0.317571 -0.525159 0
|
||||
3.936029 4.312181 1
|
||||
1.918811 -0.659594 0
|
||||
2.657582 0.028525 0
|
||||
4.637282 3.562483 1
|
||||
-0.097472 1.250080 0
|
||||
1.340281 -1.399129 0
|
||||
4.330372 3.140502 1
|
||||
4.358103 3.760854 1
|
||||
3.897352 4.806873 1
|
||||
4.962704 4.692459 1
|
||||
1.667918 -0.134096 0
|
||||
4.929650 1.727842 1
|
||||
2.434315 3.000448 1
|
||||
1.179167 1.894836 0
|
||||
0.190498 0.655592 0
|
||||
3.408802 4.843020 1
|
||||
4.497565 3.844998 1
|
||||
-0.501596 1.561013 0
|
||||
4.158981 4.875362 1
|
||||
4.017462 4.655003 1
|
||||
3.319263 3.462037 1
|
||||
2.635572 1.022114 0
|
||||
2.638164 5.051437 1
|
||||
4.875001 3.592322 1
|
||||
-0.276607 0.800369 0
|
||||
4.351591 3.321136 1
|
||||
3.699848 3.317014 1
|
||||
4.947319 4.252134 1
|
||||
4.146336 2.162761 1
|
||||
5.231704 5.477804 1
|
||||
3.302101 3.994218 1
|
||||
-0.249349 2.069960 0
|
||||
4.705134 3.921461 1
|
||||
4.652980 4.287917 1
|
||||
3.937259 -0.334385 0
|
||||
3.257619 2.758094 1
|
||||
0.994191 3.135344 0
|
||||
4.649768 2.123305 1
|
||||
1.634135 0.241517 0
|
||||
1.682542 2.057739 1
|
||||
5.163117 4.467304 1
|
||||
4.638594 4.141250 1
|
||||
1.392605 0.635603 0
|
||||
4.319784 2.965064 1
|
||||
1.872466 1.566002 0
|
||||
4.230714 5.179026 1
|
||||
2.635294 3.470599 1
|
||||
0.988464 0.943613 0
|
||||
0.897546 0.129141 0
|
||||
3.370731 2.019838 0
|
||||
1.424812 0.081647 0
|
||||
5.961444 3.372419 1
|
||||
2.839070 0.926229 0
|
||||
0.279132 1.607793 0
|
||||
5.351031 3.693640 1
|
||||
2.637437 1.951445 0
|
||||
-0.179258 0.349339 0
|
||||
3.246295 1.013459 0
|
||||
5.839643 4.556761 1
|
||||
1.435225 0.937185 0
|
||||
0.500440 0.348246 0
|
||||
4.948782 4.994416 1
|
||||
0.810541 0.456830 0
|
||||
5.098827 4.142789 1
|
||||
2.365307 0.729496 0
|
||||
-0.117730 0.891913 0
|
||||
0.485735 0.513485 0
|
||||
0.680270 1.486851 0
|
||||
1.143053 0.227480 0
|
||||
6.615446 4.561501 1
|
||||
1.016051 1.862106 0
|
||||
0.668177 -0.212610 0
|
||||
2.906047 2.415627 1
|
||||
5.576097 5.068683 1
|
||||
1.315063 -0.040980 0
|
||||
5.375285 3.306877 1
|
||||
4.549934 3.805014 1
|
||||
1.189238 0.661279 0
|
||||
4.156567 3.280736 1
|
||||
2.061355 1.090958 0
|
||||
4.499387 3.640263 1
|
||||
3.503883 1.015591 0
|
||||
0.390200 -1.037188 0
|
||||
2.922873 4.696711 1
|
||||
1.803928 3.846808 1
|
||||
0.907921 -2.139287 0
|
||||
1.640739 0.592793 0
|
||||
5.108193 3.194757 1
|
||||
4.297873 4.034234 1
|
||||
4.832678 4.073469 1
|
||||
4.391764 3.557895 1
|
||||
2.006343 0.836557 0
|
||||
0.351400 1.534742 0
|
||||
4.933823 2.937944 1
|
||||
3.926482 2.073712 1
|
||||
5.382385 4.818642 1
|
||||
4.739010 3.213326 1
|
||||
0.026227 0.177150 0
|
||||
5.001353 3.300961 1
|
||||
5.022782 2.921902 1
|
||||
4.225051 4.534986 1
|
||||
3.745148 -0.169000 0
|
||||
5.891838 2.817417 1
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -4,26 +4,47 @@ sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..', '..'))
|
|||
|
||||
from cntk import *
|
||||
|
||||
if (__name__ == "__main__"):
|
||||
X = Input(2)
|
||||
X.attach_uci_fast_reader("Train-3Classes.txt", 0)
|
||||
cur_dir = os.path.dirname(__file__)
|
||||
|
||||
# Using data from https://github.com/Microsoft/CNTK/wiki/Tutorial
|
||||
train_file = os.path.join(cur_dir, "Train-3Classes.txt")
|
||||
test_file = os.path.join(cur_dir, "Test-3Classes.txt")
|
||||
mapping_file = os.path.join(cur_dir, "SimpleMapping-3Classes.txt")
|
||||
|
||||
def train_eval_logreg(criterion_name=None, eval_name=None):
|
||||
X = Input(2)
|
||||
y = Input(3)
|
||||
y.attach_uci_fast_reader("Train-3Classes.txt", 2, True, 1, "SimpleMapping-3Classes.txt")
|
||||
|
||||
W = LearnableParameter(3, 2)
|
||||
b = LearnableParameter(3, 1)
|
||||
|
||||
out = Times(W, X) + b
|
||||
out.tag = 'output'
|
||||
ce = CrossEntropyWithSoftmax(y, out)
|
||||
ce = CrossEntropyWithSoftmax(y, out, var_name=criterion_name)
|
||||
ce.tag = 'criterion'
|
||||
eval = SquareError(y, out, var_name=eval_name)
|
||||
eval.tag = 'eval'
|
||||
|
||||
my_sgd = SGD(
|
||||
epoch_size=0, minibatch_size=25, learning_ratesPerMB=0.1, max_epochs=3)
|
||||
|
||||
with Context('demo', optimizer=my_sgd, root_node=ce, clean_up=False) as ctx:
|
||||
ctx.train(None)
|
||||
with Context('demo', root_nodes=[ce,eval], clean_up=False) as ctx:
|
||||
X.attach_uci_fast_reader(train_file, 0)
|
||||
y.attach_uci_fast_reader(train_file, 2, True, 1, mapping_file)
|
||||
ctx.train(my_sgd)
|
||||
|
||||
result = ctx.eval(out)
|
||||
print(result.argmax(axis=1))
|
||||
X.attach_uci_fast_reader(test_file, 0)
|
||||
y.attach_uci_fast_reader(test_file, 2, True, 1, mapping_file)
|
||||
result = ctx.test()
|
||||
|
||||
return result
|
||||
|
||||
def test_logreg():
|
||||
result = train_eval_logreg('crit_node', 'eval_node')
|
||||
assert result['SamplesSeen'] == 500
|
||||
assert result['Perplexity'] == 1.2216067
|
||||
assert result['eval_node'] == 13.779223
|
||||
assert result['crit_node'] == 0.20016696
|
||||
|
||||
if __name__ == "__main__":
|
||||
print(train_eval_logreg())
|
||||
|
|
|
@ -4,10 +4,11 @@ import os
|
|||
import struct
|
||||
import numpy as np
|
||||
|
||||
|
||||
def loadData(src, cimg):
|
||||
print ('Downloading ' + src)
|
||||
print('Downloading ' + src)
|
||||
gzfname, h = urllib.request.urlretrieve(src, './delete.me')
|
||||
print ('Done.')
|
||||
print('Done.')
|
||||
try:
|
||||
with gzip.open(gzfname) as gz:
|
||||
n = struct.unpack('I', gz.read(4))
|
||||
|
@ -17,21 +18,24 @@ def loadData(src, cimg):
|
|||
# Read number of entries.
|
||||
n = struct.unpack('>I', gz.read(4))[0]
|
||||
if n != cimg:
|
||||
raise Exception('Invalid file: expected {0} entries.'.format(cimg))
|
||||
raise Exception(
|
||||
'Invalid file: expected {0} entries.'.format(cimg))
|
||||
crow = struct.unpack('>I', gz.read(4))[0]
|
||||
ccol = struct.unpack('>I', gz.read(4))[0]
|
||||
if crow != 28 or ccol != 28:
|
||||
raise Exception('Invalid file: expected 28 rows/cols per image.')
|
||||
raise Exception(
|
||||
'Invalid file: expected 28 rows/cols per image.')
|
||||
# Read data.
|
||||
res = np.fromstring(gz.read(cimg * crow * ccol), dtype = np.uint8)
|
||||
res = np.fromstring(gz.read(cimg * crow * ccol), dtype=np.uint8)
|
||||
finally:
|
||||
os.remove(gzfname)
|
||||
return res.reshape((cimg, crow * ccol))
|
||||
|
||||
|
||||
def loadLabels(src, cimg):
|
||||
print ('Downloading ' + src)
|
||||
print('Downloading ' + src)
|
||||
gzfname, h = urllib.request.urlretrieve(src, './delete.me')
|
||||
print ('Done.')
|
||||
print('Done.')
|
||||
try:
|
||||
with gzip.open(gzfname) as gz:
|
||||
n = struct.unpack('I', gz.read(4))
|
||||
|
@ -41,26 +45,31 @@ def loadLabels(src, cimg):
|
|||
# Read number of entries.
|
||||
n = struct.unpack('>I', gz.read(4))
|
||||
if n[0] != cimg:
|
||||
raise Exception('Invalid file: expected {0} rows.'.format(cimg))
|
||||
raise Exception(
|
||||
'Invalid file: expected {0} rows.'.format(cimg))
|
||||
# Read labels.
|
||||
res = np.fromstring(gz.read(cimg), dtype = np.uint8)
|
||||
res = np.fromstring(gz.read(cimg), dtype=np.uint8)
|
||||
finally:
|
||||
os.remove(gzfname)
|
||||
return res.reshape((cimg, 1))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
trnData = loadData('http://yann.lecun.com/exdb/mnist/train-images-idx3-ubyte.gz', 60000)
|
||||
trnLbl = loadLabels('http://yann.lecun.com/exdb/mnist/train-labels-idx1-ubyte.gz', 60000)
|
||||
trnData = loadData(
|
||||
'http://yann.lecun.com/exdb/mnist/train-images-idx3-ubyte.gz', 60000)
|
||||
trnLbl = loadLabels(
|
||||
'http://yann.lecun.com/exdb/mnist/train-labels-idx1-ubyte.gz', 60000)
|
||||
trn = np.hstack((trnLbl, trnData))
|
||||
if not os.path.exists('./Data'):
|
||||
os.mkdir('./Data')
|
||||
print ('Writing train text file...')
|
||||
np.savetxt(r'./Data/Train-28x28.txt', trn, fmt = '%u', delimiter='\t')
|
||||
print ('Done.')
|
||||
testData = loadData('http://yann.lecun.com/exdb/mnist/t10k-images-idx3-ubyte.gz', 10000)
|
||||
testLbl = loadLabels('http://yann.lecun.com/exdb/mnist/t10k-labels-idx1-ubyte.gz', 10000)
|
||||
print('Writing train text file...')
|
||||
np.savetxt(r'./Data/Train-28x28.txt', trn, fmt='%u', delimiter='\t')
|
||||
print('Done.')
|
||||
testData = loadData(
|
||||
'http://yann.lecun.com/exdb/mnist/t10k-images-idx3-ubyte.gz', 10000)
|
||||
testLbl = loadLabels(
|
||||
'http://yann.lecun.com/exdb/mnist/t10k-labels-idx1-ubyte.gz', 10000)
|
||||
test = np.hstack((testLbl, testData))
|
||||
print ('Writing test text file...')
|
||||
np.savetxt(r'./Data/Test-28x28.txt', test, fmt = '%u', delimiter='\t')
|
||||
print ('Done.')
|
||||
print('Writing test text file...')
|
||||
np.savetxt(r'./Data/Test-28x28.txt', test, fmt='%u', delimiter='\t')
|
||||
print('Done.')
|
||||
|
|
|
@ -8,6 +8,7 @@ from cntk import *
|
|||
# MNIST Example, one hidden layer neural network
|
||||
# =====================================================================================
|
||||
|
||||
|
||||
def dnn_sigmoid_layer(in_dim, out_dim, x, param_scale):
|
||||
W = LearnableParameter(out_dim, in_dim, initValueScale=param_scale)
|
||||
b = LearnableParameter(out_dim, 1, initValueScale=param_scale)
|
||||
|
@ -15,6 +16,7 @@ def dnn_sigmoid_layer(in_dim, out_dim, x, param_scale):
|
|||
z = Plus(t, b)
|
||||
return Sigmoid(z)
|
||||
|
||||
|
||||
def dnn_layer(in_dim, out_dim, x, param_scale):
|
||||
W = LearnableParameter(out_dim, in_dim, initValueScale=param_scale)
|
||||
b = LearnableParameter(out_dim, 1, initValueScale=param_scale)
|
||||
|
@ -24,18 +26,22 @@ def dnn_layer(in_dim, out_dim, x, param_scale):
|
|||
if (__name__ == "__main__"):
|
||||
|
||||
# Network definition
|
||||
feat_dim=784
|
||||
label_dim=10
|
||||
hidden_dim=200
|
||||
feat_dim = 784
|
||||
label_dim = 10
|
||||
hidden_dim = 200
|
||||
|
||||
training_filename=os.path.join("Data", "Train-28x28.txt")
|
||||
training_filename = os.path.join("Data", "Train-28x28.txt")
|
||||
test_filename = os.path.join("Data", "Test-28x28.txt")
|
||||
|
||||
features = Input(feat_dim, var_name='features')
|
||||
features.attach_uci_fast_reader(training_filename, 1)
|
||||
|
||||
feat_scale = Constant(0.00390625)
|
||||
feats_scaled = Scale(feat_scale, features)
|
||||
|
||||
labels = Input(label_dim, tag='label', var_name='labels')
|
||||
labels.attach_uci_fast_reader(
|
||||
training_filename, 0, True, 1, os.path.join("Data", "labelsmap.txt"))
|
||||
|
||||
h1 = dnn_sigmoid_layer(feat_dim, hidden_dim, feats_scaled, 1)
|
||||
out = dnn_layer(hidden_dim, label_dim, h1, 1)
|
||||
|
@ -44,20 +50,17 @@ if (__name__ == "__main__"):
|
|||
ec = CrossEntropyWithSoftmax(labels, out)
|
||||
ec.tag = 'criterion'
|
||||
|
||||
# Build the reader
|
||||
r = UCIFastReader(filename=training_filename)
|
||||
|
||||
# Add the input node to the reader
|
||||
r.add_input(features, 1, feat_dim)
|
||||
r.add_input(labels, 0, 1, label_dim, os.path.join("Data", "labelsmap.txt"))
|
||||
|
||||
# Build the optimizer (settings are scaled down)
|
||||
my_sgd = SGD(epoch_size = 600, minibatch_size = 32, learning_ratesPerMB = 0.1, max_epochs = 5, momentum_per_mb = 0)
|
||||
my_sgd = SGD(epoch_size=600, minibatch_size=32,
|
||||
learning_ratesPerMB=0.1, max_epochs=5, momentum_per_mb=0)
|
||||
|
||||
# Create a context or re-use if already there
|
||||
with Context('mnist_one_layer', optimizer= my_sgd, root_node= ec, clean_up=False) as ctx:
|
||||
with Context('mnist_one_layer', root_node=ec, clean_up=False) as ctx:
|
||||
# CNTK actions
|
||||
ctx.train(r)
|
||||
r["FileName"] = os.path.join("Data", "Test-28x28.txt")
|
||||
ctx.test(r)
|
||||
ctx.predict(r)
|
||||
# ctx.train(my_sgd)
|
||||
features.attach_uci_fast_reader(test_filename, 1)
|
||||
labels.attach_uci_fast_reader(
|
||||
test_filename, 0, True, 1, os.path.join("Data", "labelsmap.txt"))
|
||||
ctx.predict()
|
||||
ctx.test()
|
||||
ctx.predict()
|
||||
|
|
|
@ -1,11 +1,22 @@
|
|||
from abc import ABCMeta, abstractmethod
|
||||
import numpy as np
|
||||
import scipy.sparse as sparse
|
||||
|
||||
# Workaround until we have switched to Anaconde with scipy support
|
||||
#import scipy.sparse as sparse
|
||||
class sparse(object):
|
||||
@staticmethod
|
||||
def issparse(obj):
|
||||
return hasattr(obj, 'todense')
|
||||
|
||||
from .utils import MODEL_INDENTATION
|
||||
from .utils import numpy_to_cntk_shape, dedupe_readers
|
||||
|
||||
def _tuple_to_cntk_shape(shape):
|
||||
return ':'.join(str(v) for v in shape)
|
||||
|
||||
|
||||
class ComputationNode(object):
|
||||
|
||||
'''
|
||||
Base class for all nodes and operators. Provides a NumPy-like interface
|
||||
with operators that are converted to CNTK operators.
|
||||
|
@ -13,9 +24,11 @@ class ComputationNode(object):
|
|||
|
||||
def __init__(self, name, params=None, var_name=None, reader=None):
|
||||
if not isinstance(name, str):
|
||||
raise ValueError("Parameter 'name' has to be a string and not '%s'"%type(name))
|
||||
raise ValueError(
|
||||
"Parameter 'name' has to be a string and not '%s'" % type(name))
|
||||
if var_name is not None and not isinstance(var_name, str):
|
||||
raise ValueError("Parameter 'var_name' has to be a string and not '%s'"%type(var_name))
|
||||
raise ValueError(
|
||||
"Parameter 'var_name' has to be a string and not '%s'" % type(var_name))
|
||||
|
||||
self.name = name
|
||||
self.params = params
|
||||
|
@ -128,9 +141,25 @@ class ComputationNode(object):
|
|||
|
||||
return param
|
||||
|
||||
|
||||
def _is_forward_ref(self, p_name, p_value):
|
||||
'''
|
||||
Although the unrolled graph is a DAG, when we specify recurrence we
|
||||
naturally have loops. We can resolve this by using forward references.
|
||||
This method is checking whether the particular name and value of this
|
||||
instance are actually one of those forward references.
|
||||
'''
|
||||
is_loop_node = self.name in ('Delay', 'PastValue', 'FutureValue')
|
||||
return is_loop_node and p_name == 'input' and isinstance(p_value, str)
|
||||
|
||||
def _to_config_recursively(self, desc, unrolled_nodes, inputs,
|
||||
readers, node_counter=0):
|
||||
readers, dep_inputs, node_counter,
|
||||
reconciled_cache):
|
||||
|
||||
param_variable_names = []
|
||||
# In case we have multiple unreconciled inputs, we will reconcile each
|
||||
# of them to the layout of the first input.
|
||||
first_unreconciled_input = None
|
||||
if self.params:
|
||||
for p_name in self.params:
|
||||
p_value = self.__dict__[p_name]
|
||||
|
@ -147,24 +176,60 @@ class ComputationNode(object):
|
|||
inputs_param = [p_value]
|
||||
|
||||
input_nodes_vars = []
|
||||
for p_value in inputs_param:
|
||||
if p_value in unrolled_nodes:
|
||||
# we have seen this node already, so just retrieve its
|
||||
# name
|
||||
child_var = unrolled_nodes[p_value]
|
||||
for pv in inputs_param:
|
||||
|
||||
if pv in unrolled_nodes:
|
||||
# We have seen this node already, so just retrieve its
|
||||
# name.
|
||||
child_var, child_dep_inputs = unrolled_nodes[pv]
|
||||
else:
|
||||
child_var, node_counter, child_desc = p_value._to_config_recursively(
|
||||
desc, unrolled_nodes, inputs, readers, node_counter)
|
||||
unrolled_nodes[p_value] = child_var
|
||||
child_var, node_counter, child_desc, child_dep_inputs = pv._to_config_recursively(
|
||||
desc, unrolled_nodes, inputs, readers,
|
||||
dep_inputs, node_counter, reconciled_cache)
|
||||
|
||||
unrolled_nodes[pv] = child_var, dep_inputs
|
||||
|
||||
# Whenever two unreconciled inputs meet, we need
|
||||
# reconcile them to have the same MB layout. This is a
|
||||
# temporary necessity that should go away with future
|
||||
# CNTK versions.
|
||||
if dep_inputs != child_dep_inputs:
|
||||
|
||||
if first_unreconciled_input is None:
|
||||
first_unreconciled_input = pv
|
||||
|
||||
else:
|
||||
if (pv, first_unreconciled_input) in reconciled_cache:
|
||||
child_var, dep_inputs = reconciled_cache[(pv, first_unreconciled_input)]
|
||||
else:
|
||||
unrec_pv = pv
|
||||
pv = ReconcileMBLayout(unrec_pv, first_unreconciled_input)
|
||||
child_var, node_counter, child_desc, dep_inputs = pv._to_config_recursively(
|
||||
desc, unrolled_nodes, inputs, readers,
|
||||
dep_inputs, node_counter,
|
||||
reconciled_cache)
|
||||
reconciled_cache[(unrec_pv, first_unreconciled_input)] = pv.var_name, dep_inputs
|
||||
|
||||
unrolled_nodes[pv] = child_var, dep_inputs
|
||||
|
||||
dep_inputs = child_dep_inputs
|
||||
|
||||
input_nodes_vars.append(child_var)
|
||||
|
||||
param_variable_names.append(_tuple_to_cntk_shape(input_nodes_vars))
|
||||
param_variable_names.append(
|
||||
_tuple_to_cntk_shape(input_nodes_vars))
|
||||
else:
|
||||
if self._is_forward_ref(p_name, p_value):
|
||||
# We have a forward reference to a node that will be
|
||||
# later on defined. p_value is the var_name of the
|
||||
# later defined node.
|
||||
param_variable_names.append(p_value)
|
||||
else:
|
||||
param_variable_names.append(
|
||||
self._param_to_brainscript(p_name, p_value))
|
||||
|
||||
if self.reader:
|
||||
readers.append(self.reader)
|
||||
readers.add(self.reader)
|
||||
|
||||
if self._is_input():
|
||||
inputs.add(self)
|
||||
|
@ -177,47 +242,51 @@ class ComputationNode(object):
|
|||
|
||||
params = self._get_cntk_param_string(param_variable_names)
|
||||
|
||||
line = "%s = %s(%s)" % (self.var_name, self.name, params)
|
||||
line = ' ' * MODEL_INDENTATION + \
|
||||
"%s = %s(%s)" % (self.var_name, self.name, params)
|
||||
desc.append(line)
|
||||
|
||||
return self.var_name, node_counter, desc
|
||||
if self._is_input():
|
||||
dep_inputs += (self.var_name,)
|
||||
|
||||
def _to_config(self):
|
||||
return self.var_name, node_counter, desc, dep_inputs
|
||||
|
||||
def _to_config(self, description, unrolled_nodes, inputs, readers,
|
||||
dep_inputs, node_counter, reconciled_cache):
|
||||
'''
|
||||
Helper method to generate the CNTK configuration for this node.
|
||||
'''
|
||||
unrolled_nodes = {}
|
||||
inputs=set()
|
||||
readers=[]
|
||||
var_name, node_counter, desc = self._to_config_recursively(
|
||||
desc=[],
|
||||
|
||||
var_name, node_counter, desc, dep_inputs = self._to_config_recursively(
|
||||
description,
|
||||
unrolled_nodes=unrolled_nodes,
|
||||
inputs=inputs,
|
||||
readers=readers)
|
||||
readers=readers,
|
||||
dep_inputs=dep_inputs,
|
||||
node_counter=node_counter,
|
||||
reconciled_cache=reconciled_cache)
|
||||
|
||||
return var_name, node_counter, desc, len(inputs)>0, readers
|
||||
|
||||
def _dedupe_readers(self, readers):
|
||||
readers_map = {}
|
||||
for r in readers:
|
||||
filename = r['FileName']
|
||||
if filename in readers_map:
|
||||
readers_map[filename].inputs_def.extend(r.inputs_def)
|
||||
else:
|
||||
readers_map[filename] = r
|
||||
|
||||
return [r for r in readers_map.values()]
|
||||
return var_name, node_counter, desc, len(inputs) > 0, readers, dep_inputs
|
||||
|
||||
def to_config(self):
|
||||
'''
|
||||
Generate CNTK configuration for this node including the configuration
|
||||
for all dependent child nodes.
|
||||
'''
|
||||
var_name, node_counter, desc, has_inputs, readers = self._to_config()
|
||||
var_name, node_counter, desc, has_inputs, readers, dep_inputs = \
|
||||
self._to_config(description=[],
|
||||
unrolled_nodes={},
|
||||
inputs=set(),
|
||||
readers=set(),
|
||||
dep_inputs=tuple(),
|
||||
node_counter=0,
|
||||
reconciled_cache={})
|
||||
|
||||
return "\n".join(desc), has_inputs, dedupe_readers(readers)
|
||||
|
||||
return "\n".join(desc), has_inputs, self._dedupe_readers(readers)
|
||||
|
||||
class InputComputationNodeBase(ComputationNode, metaclass=ABCMeta):
|
||||
|
||||
'''
|
||||
Base class for all non-image input nodes nodes and operators. Provides methods to attach
|
||||
a reader to an input node
|
||||
|
@ -233,7 +302,7 @@ class InputComputationNodeBase(ComputationNode, metaclass=ABCMeta):
|
|||
def attach_uci_fast_reader(self,
|
||||
filename,
|
||||
input_start,
|
||||
islabel = False,
|
||||
islabel=False,
|
||||
num_label_cols=None,
|
||||
label_mapping_file=None,
|
||||
custom_delimiter=None):
|
||||
|
@ -243,12 +312,14 @@ class InputComputationNodeBase(ComputationNode, metaclass=ABCMeta):
|
|||
self.reader = UCIFastReader(filename, custom_delimiter)
|
||||
|
||||
if islabel:
|
||||
self.reader.add_input(self, input_start, num_label_cols, self.dims, label_mapping_file)
|
||||
self.reader.add_input(
|
||||
self, input_start, num_label_cols, self.dims, label_mapping_file)
|
||||
else:
|
||||
self.reader.add_input(self, input_start, self.dims)
|
||||
|
||||
|
||||
class ImageInputComputationNodeBase(ComputationNode, metaclass=ABCMeta):
|
||||
|
||||
'''
|
||||
Base class for all image input nodes nodes and operators. Provides methods to attach
|
||||
a reader to an input node
|
||||
|
@ -261,40 +332,53 @@ class ImageInputComputationNodeBase(ComputationNode, metaclass=ABCMeta):
|
|||
raise NotImplementedError
|
||||
|
||||
# importing after defining ComputationNode to work around circular imports
|
||||
from cntk.cntk1_ops import *
|
||||
from cntk import cntk1_ops # to have a separate namespace when we want to override below
|
||||
from cntk.ops.cntk1 import *
|
||||
# to have a separate namespace when we want to override below
|
||||
from cntk.ops import cntk1 as cntk1_ops
|
||||
from .reader import UCIFastReader, CNTKTextFormatReader
|
||||
|
||||
# redefine some operators to work with NumPy and sequences as input
|
||||
|
||||
|
||||
def _dense_seq_to_str(seq):
|
||||
return ' '.join(seq.astype(np.str))
|
||||
def _dense_to_str(data):
|
||||
return ' '.join(data.ravel().astype(np.str))
|
||||
|
||||
def _sparse_seq_to_str(seq):
|
||||
#return ' '.join('%s:%s'%(k,seq[k]) for k in sorted(seq.items()))
|
||||
def _sparse_to_str(data):
|
||||
# return ' '.join('%s:%s'%(k,data[k]) for k in sorted(data.items()))
|
||||
raise NotImplementedError
|
||||
|
||||
def _seq_to_text_format(sequences, alias):
|
||||
|
||||
def _tensor_to_text_format(idx, alias, tensor, has_sequence_dimension=True):
|
||||
'''
|
||||
`sequences` is a NumPy array
|
||||
Converts a NumPy array representing tensor of one input into a format that
|
||||
is readable by `CNTKTextReader`.
|
||||
|
||||
:param `alias`: alias to be used in the temporary file
|
||||
:param `tensor`: a NumPy array having sequence as its innermost dimension
|
||||
'''
|
||||
if not alias or not isinstance(alias, str):
|
||||
if not alias:
|
||||
raise ValueError('alias is missing')
|
||||
|
||||
first_elem = sequences[0]
|
||||
if isinstance(first_elem, np.ndarray):
|
||||
seq_to_str = _dense_seq_to_str
|
||||
elif sparse.issparse(first_elem):
|
||||
seq_to_str = _sparse_seq_to_str
|
||||
if isinstance(tensor, np.ndarray):
|
||||
to_str = _dense_to_str
|
||||
elif sparse.issparse(tensor):
|
||||
raise ValueError('sparse is not yet supported')
|
||||
#to_str = _sparse_to_str
|
||||
else:
|
||||
raise ValueError('sequence elements have to be of type numpy.ndarray (dense) or dictionary (sparse), you gave "%s"'%str(first_elem))
|
||||
raise ValueError('sequence elements have to be of type numpy.ndarray' +
|
||||
' (dense) or dictionary (sparse), you gave "%s"' % \
|
||||
str(type(tensor)))
|
||||
|
||||
if has_sequence_dimension:
|
||||
num_seq_elements = tensor.shape[0]
|
||||
lines = []
|
||||
for idx, seq in enumerate(sequences):
|
||||
lines.append('%i|%s %s'%(idx, alias, seq_to_str(seq)))
|
||||
for seq_idx in range(0, num_seq_elements):
|
||||
lines.append('%i\t|%s %s'%(idx, alias, to_str(tensor[seq_idx])))
|
||||
|
||||
return '\n'.join(lines)
|
||||
else:
|
||||
return '%i\t|%s %s'%(idx, alias, to_str(tensor))
|
||||
|
||||
|
||||
def _get_constant_node(value, **kw):
|
||||
'''
|
||||
|
@ -303,7 +387,7 @@ def _get_constant_node(value, **kw):
|
|||
|
||||
To be as generic as possible, we
|
||||
- flatten the data
|
||||
- initialize a LearnableParameter operator with it
|
||||
- initialize a ParameterTensor operator with it
|
||||
- ensure that the graph does not backprob to it.
|
||||
- Finally we to reshape it.
|
||||
'''
|
||||
|
@ -319,45 +403,45 @@ def _get_constant_node(value, **kw):
|
|||
# obvious first choice, mkstemp(), would later fail in cntk.exe because the
|
||||
# file would still be locked.
|
||||
# TODO make it same filename as alias
|
||||
tf = tempfile.NamedTemporaryFile(prefix='_param_', suffix='.txt', dir=get_context().directory, delete = False)
|
||||
tf = tempfile.NamedTemporaryFile(
|
||||
prefix='_param_', suffix='.txt', dir=get_context().directory, delete=False)
|
||||
tf.close()
|
||||
|
||||
if isinstance(value, list):
|
||||
if isinstance(value, list) or np.isscalar(value):
|
||||
value = np.asarray(value)
|
||||
|
||||
if len(value.shape) == 1:
|
||||
# 1D list: interpret as one scalar per sample
|
||||
value = value[:,np.newaxis]
|
||||
|
||||
if sparse.issparse(value):
|
||||
raise ValueError('only dense data is supported')
|
||||
|
||||
with open(tf.name, 'w') as f:
|
||||
# TODO value.ravel() ?
|
||||
np.ndarray.flatten(value).tofile(f, sep='\n')
|
||||
|
||||
size = np.multiply.reduce(value.shape[:])
|
||||
|
||||
# The var_name specified by the user should be set to the operator that
|
||||
# is finally returned, which is the shape node.
|
||||
var_name = kw.pop('var_name', None)
|
||||
value.ravel().tofile(f, sep='\n')
|
||||
|
||||
from cntk.reader import CNTKTextFormatReader
|
||||
param_node = cntk1_ops.LearnableParameter(
|
||||
size,
|
||||
1,
|
||||
|
||||
cntk_shape = numpy_to_cntk_shape(value.shape)
|
||||
|
||||
dims = np.multiply.reduce(cntk_shape)
|
||||
|
||||
# TODO switch to ConstantTensor once it is in the core.bs file
|
||||
node = cntk1_ops.ParameterTensor(
|
||||
dims=dims,
|
||||
learningRateMultiplier=0.0,
|
||||
init='fromFile',
|
||||
initFromFilePath=tf.name,
|
||||
**kw)
|
||||
|
||||
reshape_node = cntk1_ops.NewReshape(param_node,
|
||||
dims=value.shape,
|
||||
var_name=var_name)
|
||||
if len(cntk_shape) > 1:
|
||||
node = cntk1_ops.NewReshape(node, dims=cntk_shape)
|
||||
|
||||
return reshape_node
|
||||
return node
|
||||
|
||||
|
||||
def _get_input_node(list_of_tensors, has_sequence_dimension, **kw):
|
||||
'''
|
||||
:param list_of_tensors: list of tensors potentially having sequences of
|
||||
different lengths.
|
||||
'''
|
||||
|
||||
def _get_input_node(value, **kw):
|
||||
# FIXME We need to better manage the context. How can we get hold
|
||||
# of the overall context without having to always pass it
|
||||
# explicitly?
|
||||
|
@ -366,50 +450,78 @@ def _get_input_node(value, **kw):
|
|||
import tempfile
|
||||
|
||||
# We have to use NamedTemporaryFile and close it, because the obvious first
|
||||
# choice, mkstemp(), would later fail in cntk.exe because the file would still be locked.
|
||||
# choice, mkstemp(), would later fail in cntk.exe because the file would
|
||||
# still be locked.
|
||||
tf = tempfile.NamedTemporaryFile(prefix='_input_', suffix='.txt',
|
||||
dir=get_context().directory, delete = False)
|
||||
dir=get_context().directory, delete=False)
|
||||
tf.close()
|
||||
|
||||
if isinstance(value, list):
|
||||
value = np.asarray(value)
|
||||
|
||||
if len(value.shape) == 1:
|
||||
# 1D list: interpret as one scalar per sample
|
||||
value = value[:,np.newaxis]
|
||||
|
||||
if 'alias' in kw:
|
||||
alias = kw['alias']
|
||||
del kw['alias'] # don't confuse with constructor's parameters
|
||||
else:
|
||||
# TODO make sure we don't have clashes
|
||||
alias = '_I_%i'%np.random.randint(1000)
|
||||
alias = '_I_%i' % np.random.randint(1000)
|
||||
|
||||
shapes = set()
|
||||
with open(tf.name, 'w') as f:
|
||||
f.write(_seq_to_text_format(value, alias))
|
||||
for idx,tensor in enumerate(list_of_tensors):
|
||||
if isinstance(tensor, list):
|
||||
tensor = np.asarray(tensor)
|
||||
|
||||
if has_sequence_dimension:
|
||||
# collecting the shapes ignoring the sequence dimension
|
||||
shapes.add(tensor.shape[1:])
|
||||
else:
|
||||
shapes.add(tensor.shape)
|
||||
|
||||
f.write(_tensor_to_text_format(idx, alias, tensor,
|
||||
has_sequence_dimension) + '\n')
|
||||
|
||||
# ignoring the sequence dimension, all shapes should be equal
|
||||
if len(shapes)!=1:
|
||||
raise ValueError('except for the sequence dimensions all shapes ' +
|
||||
'should be the same - instead we have: %s'%(", ".join(str(s) for s in shapes)))
|
||||
|
||||
# shapes now contains only one shape, which has the sequence dimension
|
||||
# removed.
|
||||
value_shape = shapes.pop()
|
||||
|
||||
cntk_shape = numpy_to_cntk_shape(value_shape)
|
||||
|
||||
from cntk.reader import CNTKTextFormatReader
|
||||
input_node = cntk1_ops.Input(value.shape, **kw)
|
||||
input_node.reader = CNTKTextFormatReader(tf.name)
|
||||
# In case we have the shape (2,3), which will be initialized at Input() as
|
||||
# '2:3', we have 2*3 = 6 dimensions when flattened out for the reader. Note
|
||||
# that the first dimension is the sample.
|
||||
dims = np.multiply.reduce(value.shape[:])
|
||||
input_node.reader.add_input(input_node, alias, dims)
|
||||
|
||||
return input_node
|
||||
# In case we have the shape (2,3) and assuming we have only sequences of
|
||||
# lengths 1, the input will be initialized with dim=3 (column major)
|
||||
# followed by a reshape node that has the dims '2:3'. So we have 2*3 = 6
|
||||
# dimensions when flattened out for the reader.
|
||||
dims = int(np.multiply.reduce(cntk_shape))
|
||||
node = cntk1_ops.Input(dims, **kw)
|
||||
node.reader = CNTKTextFormatReader(tf.name)
|
||||
node.reader.add_input(node, alias, dims)
|
||||
|
||||
def is_sequence(data):
|
||||
if len(cntk_shape) > 1:
|
||||
node = cntk1_ops.NewReshape(node,
|
||||
dims=cntk_shape)
|
||||
|
||||
return node
|
||||
|
||||
|
||||
def is_tensor_list(data):
|
||||
'''
|
||||
Checks whether the data is a CNTK sequence, which is expressed in Python as
|
||||
a list of varying sized NumPy objects.
|
||||
'''
|
||||
is_list = isinstance(data, list)
|
||||
return is_list and len(data)>0 and isinstance(data[0], np.ndarray)
|
||||
return is_list and len(data) > 0 and isinstance(data[0], np.ndarray)
|
||||
|
||||
|
||||
def is_tensor(data):
|
||||
'''
|
||||
Checks whether the data is a tensor.
|
||||
Checks whether the data is a tensor, i.e. whether it is a NumPy array or a
|
||||
list of NumPy arrays.
|
||||
|
||||
:param `data`: data to check
|
||||
'''
|
||||
if isinstance(data, np.ndarray):
|
||||
return True
|
||||
|
@ -417,7 +529,7 @@ def is_tensor(data):
|
|||
if not isinstance(data, list):
|
||||
return False
|
||||
|
||||
while len(data)>0:
|
||||
while len(data) > 0:
|
||||
# All but the innermost dimension's values have to be lists
|
||||
try:
|
||||
data[0][0]
|
||||
|
@ -432,48 +544,30 @@ def is_tensor(data):
|
|||
|
||||
return True
|
||||
|
||||
def input(value, **kw):
|
||||
|
||||
def input(value, has_sequence_dimension=True, **kw):
|
||||
'''
|
||||
Defining Input as a factory override that creates either a Constant()
|
||||
operator or an Input() operator based on the type of the `value`.
|
||||
Create an input node.
|
||||
|
||||
In case the `value` is a scalar, a normal CNTK Constant() operator is
|
||||
returned.
|
||||
|
||||
In case the `value` is a list of NumPy arrays, a CNTK Input() operator is
|
||||
returned, interpreting every element as a sequence of tensors.
|
||||
|
||||
In case the `value` is a NumPy array or list of lists, a CNTK Input()
|
||||
operator is returned, interpreting it as a dense tensor.
|
||||
|
||||
Non-scalar values are interpreted as sparse when they contain a colon.
|
||||
:param `value`: is a list of NumPy tensors. Currently, only dense tensors
|
||||
are supported. Sparse will come soon by the power of scipy.
|
||||
:param `has_sequence_dimension`: If True, the outermost dimension is
|
||||
treated as the sequence dimension. If False, it will wrap each sample
|
||||
into its own 1-dimensional array.
|
||||
:param `alias`: optional the alias to be used when serializing the data
|
||||
into an intermediate file
|
||||
'''
|
||||
if is_sequence(value) or is_tensor(value):
|
||||
return _get_input_node(value, **kw)
|
||||
if is_tensor_list(value) or is_tensor(value):
|
||||
return _get_input_node(value, has_sequence_dimension, **kw)
|
||||
else:
|
||||
raise ValueError('value type is not supported: %s'%type(value))
|
||||
raise ValueError('value type is not supported: %s' % type(value))
|
||||
|
||||
|
||||
def constant(value, **kw):
|
||||
'''
|
||||
Defining Constant as a factory override that creates either a Constant()
|
||||
operator or an Input() operator based on the type of the `value`.
|
||||
|
||||
In case the `value` is a scalar, a normal CNTK Constant() operator is
|
||||
returned.
|
||||
|
||||
In case the `value` is a list of NumPy arrays, a CNTK Input() operator is
|
||||
returned, interpreting every element as a sequence of tensors.
|
||||
|
||||
In case the `value` is a NumPy array or list of lists, a CNTK Input()
|
||||
operator is returned, interpreting it as a dense tensor.
|
||||
|
||||
Non-scalar values are interpreted as sparse when they contain a colon.
|
||||
Creating a constant tensor node around `value`.
|
||||
'''
|
||||
if np.isscalar(value):
|
||||
return cntk1_ops.Constant(value, **kw)
|
||||
else:
|
||||
if is_tensor(value):
|
||||
if np.isscalar(value) or is_tensor(value):
|
||||
return _get_constant_node(value, **kw)
|
||||
else:
|
||||
raise ValueError('value type is not supported: %s'%type(value))
|
||||
|
||||
raise ValueError('value type is not supported: %s' % type(value))
|
||||
|
|
|
@ -2,97 +2,134 @@
|
|||
|
||||
from cntk.graph import ComputationNode, InputComputationNodeBase, ImageInputComputationNodeBase
|
||||
|
||||
|
||||
class Print(ComputationNode):
|
||||
|
||||
def __init__(self, value, format='', name='Print', var_name=None):
|
||||
super(Print, self).__init__(params=['value', 'format'], name=name, var_name=var_name)
|
||||
super(Print, self).__init__(
|
||||
params=['value', 'format'], name=name, var_name=var_name)
|
||||
self.value = value
|
||||
self.format = format
|
||||
self.params_with_defaults = ['format']
|
||||
|
||||
|
||||
class Debug(ComputationNode):
|
||||
|
||||
def __init__(self, value, say='', enabled=True, name='Debug', var_name=None):
|
||||
super(Debug, self).__init__(params=['value', 'say', 'enabled'], name=name, var_name=var_name)
|
||||
super(Debug, self).__init__(
|
||||
params=['value', 'say', 'enabled'], name=name, var_name=var_name)
|
||||
self.value = value
|
||||
self.say = say
|
||||
self.enabled = enabled
|
||||
self.params_with_defaults = ['say', 'enabled']
|
||||
|
||||
|
||||
class Format(ComputationNode):
|
||||
|
||||
def __init__(self, value, format, name='Format', var_name=None):
|
||||
super(Format, self).__init__(params=['value', 'format'], name=name, var_name=var_name)
|
||||
super(Format, self).__init__(
|
||||
params=['value', 'format'], name=name, var_name=var_name)
|
||||
self.value = value
|
||||
self.format = format
|
||||
self.params_with_defaults = []
|
||||
|
||||
|
||||
class Replace(ComputationNode):
|
||||
|
||||
def __init__(self, s, from_, to, name='Replace', var_name=None):
|
||||
super(Replace, self).__init__(params=['s', 'from_', 'to'], name=name, var_name=var_name)
|
||||
super(Replace, self).__init__(
|
||||
params=['s', 'from_', 'to'], name=name, var_name=var_name)
|
||||
self.s = s
|
||||
self.from_ = from_
|
||||
self.to = to
|
||||
self.params_with_defaults = []
|
||||
|
||||
|
||||
class Substr(ComputationNode):
|
||||
|
||||
def __init__(self, s, begin, num, name='Substr', var_name=None):
|
||||
super(Substr, self).__init__(params=['s', 'begin', 'num'], name=name, var_name=var_name)
|
||||
super(Substr, self).__init__(
|
||||
params=['s', 'begin', 'num'], name=name, var_name=var_name)
|
||||
self.s = s
|
||||
self.begin = begin
|
||||
self.num = num
|
||||
self.params_with_defaults = []
|
||||
|
||||
|
||||
class Chr(ComputationNode):
|
||||
|
||||
def __init__(self, c, name='Chr', var_name=None):
|
||||
super(Chr, self).__init__(params=['c'], name=name, var_name=var_name)
|
||||
self.c = c
|
||||
self.params_with_defaults = []
|
||||
|
||||
|
||||
class Length(ComputationNode):
|
||||
|
||||
def __init__(self, x, name='Length', var_name=None):
|
||||
super(Length, self).__init__(params=['x'], name=name, var_name=var_name)
|
||||
super(Length, self).__init__(
|
||||
params=['x'], name=name, var_name=var_name)
|
||||
self.x = x
|
||||
self.params_with_defaults = []
|
||||
|
||||
|
||||
class Ceil(ComputationNode):
|
||||
|
||||
def __init__(self, x, name='Ceil', var_name=None):
|
||||
super(Ceil, self).__init__(params=['x'], name=name, var_name=var_name)
|
||||
self.x = x
|
||||
self.params_with_defaults = []
|
||||
|
||||
|
||||
class Round(ComputationNode):
|
||||
|
||||
def __init__(self, x, name='Round', var_name=None):
|
||||
super(Round, self).__init__(params=['x'], name=name, var_name=var_name)
|
||||
self.x = x
|
||||
self.params_with_defaults = []
|
||||
|
||||
|
||||
class Sign(ComputationNode):
|
||||
|
||||
def __init__(self, x, name='Sign', var_name=None):
|
||||
super(Sign, self).__init__(params=['x'], name=name, var_name=var_name)
|
||||
self.x = x
|
||||
self.params_with_defaults = []
|
||||
|
||||
|
||||
class Min(ComputationNode):
|
||||
|
||||
def __init__(self, a, b, name='Min', var_name=None):
|
||||
super(Min, self).__init__(params=['a', 'b'], name=name, var_name=var_name)
|
||||
super(Min, self).__init__(
|
||||
params=['a', 'b'], name=name, var_name=var_name)
|
||||
self.a = a
|
||||
self.b = b
|
||||
self.params_with_defaults = []
|
||||
|
||||
|
||||
class Max(ComputationNode):
|
||||
|
||||
def __init__(self, a, b, name='Max', var_name=None):
|
||||
super(Max, self).__init__(params=['a', 'b'], name=name, var_name=var_name)
|
||||
super(Max, self).__init__(
|
||||
params=['a', 'b'], name=name, var_name=var_name)
|
||||
self.a = a
|
||||
self.b = b
|
||||
self.params_with_defaults = []
|
||||
|
||||
|
||||
class Fac(ComputationNode):
|
||||
|
||||
def __init__(self, n, name='Fac', var_name=None):
|
||||
super(Fac, self).__init__(params=['n'], name=name, var_name=var_name)
|
||||
self.n = n
|
||||
self.params_with_defaults = []
|
||||
|
||||
|
||||
class LearnableParameter(ComputationNode):
|
||||
|
||||
def __init__(self, rows, cols, learningRateMultiplier=1.0, init='uniform', initValueScale=1, value=0, initFromFilePath='', initOnCPUOnly=True, randomSeed=-1, name='LearnableParameter', var_name=None):
|
||||
super(LearnableParameter, self).__init__(params=['rows', 'cols', 'learningRateMultiplier', 'init', 'initValueScale', 'value', 'initFromFilePath', 'initOnCPUOnly', 'randomSeed'], name=name, var_name=var_name)
|
||||
super(LearnableParameter, self).__init__(params=[
|
||||
'rows', 'cols', 'learningRateMultiplier', 'init', 'initValueScale', 'value', 'initFromFilePath', 'initOnCPUOnly', 'randomSeed'], name=name, var_name=var_name)
|
||||
self.rows = rows
|
||||
self.cols = cols
|
||||
self.learningRateMultiplier = learningRateMultiplier
|
||||
|
@ -102,11 +139,15 @@ class LearnableParameter(ComputationNode):
|
|||
self.initFromFilePath = initFromFilePath
|
||||
self.initOnCPUOnly = initOnCPUOnly
|
||||
self.randomSeed = randomSeed
|
||||
self.params_with_defaults = ['learningRateMultiplier', 'init', 'initValueScale', 'value', 'initFromFilePath', 'initOnCPUOnly', 'randomSeed']
|
||||
self.params_with_defaults = [
|
||||
'learningRateMultiplier', 'init', 'initValueScale', 'value', 'initFromFilePath', 'initOnCPUOnly', 'randomSeed']
|
||||
|
||||
|
||||
class ParameterTensor(ComputationNode):
|
||||
|
||||
def __init__(self, dims, learningRateMultiplier=1.0, init='uniform', initValueScale=1, value=0, initFromFilePath='', initOnCPUOnly=True, randomSeed=-1, name='ParameterTensor', var_name=None):
|
||||
super(ParameterTensor, self).__init__(params=['dims', 'learningRateMultiplier', 'init', 'initValueScale', 'value', 'initFromFilePath', 'initOnCPUOnly', 'randomSeed'], name=name, var_name=var_name)
|
||||
super(ParameterTensor, self).__init__(params=[
|
||||
'dims', 'learningRateMultiplier', 'init', 'initValueScale', 'value', 'initFromFilePath', 'initOnCPUOnly', 'randomSeed'], name=name, var_name=var_name)
|
||||
self.dims = dims
|
||||
self.learningRateMultiplier = learningRateMultiplier
|
||||
self.init = init
|
||||
|
@ -115,25 +156,35 @@ class ParameterTensor(ComputationNode):
|
|||
self.initFromFilePath = initFromFilePath
|
||||
self.initOnCPUOnly = initOnCPUOnly
|
||||
self.randomSeed = randomSeed
|
||||
self.params_with_defaults = ['learningRateMultiplier', 'init', 'initValueScale', 'value', 'initFromFilePath', 'initOnCPUOnly', 'randomSeed']
|
||||
self.params_with_defaults = [
|
||||
'learningRateMultiplier', 'init', 'initValueScale', 'value', 'initFromFilePath', 'initOnCPUOnly', 'randomSeed']
|
||||
|
||||
|
||||
class Input(InputComputationNodeBase):
|
||||
|
||||
def __init__(self, dims, tag='feature', name='Input', var_name=None):
|
||||
super(Input, self).__init__(params=['dims', 'tag'], name=name, var_name=var_name)
|
||||
super(Input, self).__init__(
|
||||
params=['dims', 'tag'], name=name, var_name=var_name)
|
||||
self.dims = dims
|
||||
self.tag = tag
|
||||
self.params_with_defaults = ['tag']
|
||||
|
||||
|
||||
class SparseInput(InputComputationNodeBase):
|
||||
|
||||
def __init__(self, dims, tag='feature', name='SparseInput', var_name=None):
|
||||
super(SparseInput, self).__init__(params=['dims', 'tag'], name=name, var_name=var_name)
|
||||
super(SparseInput, self).__init__(
|
||||
params=['dims', 'tag'], name=name, var_name=var_name)
|
||||
self.dims = dims
|
||||
self.tag = tag
|
||||
self.params_with_defaults = ['tag']
|
||||
|
||||
|
||||
class ImageInput(ImageInputComputationNodeBase):
|
||||
|
||||
def __init__(self, imageWidth, imageHeight, imageChannels, imageLayout='CHW', tag='feature', name='ImageInput', var_name=None):
|
||||
super(ImageInput, self).__init__(params=['imageWidth', 'imageHeight', 'imageChannels', 'imageLayout', 'tag'], name=name, var_name=var_name)
|
||||
super(ImageInput, self).__init__(params=[
|
||||
'imageWidth', 'imageHeight', 'imageChannels', 'imageLayout', 'tag'], name=name, var_name=var_name)
|
||||
self.imageWidth = imageWidth
|
||||
self.imageHeight = imageHeight
|
||||
self.imageChannels = imageChannels
|
||||
|
@ -141,9 +192,12 @@ class ImageInput(ImageInputComputationNodeBase):
|
|||
self.tag = tag
|
||||
self.params_with_defaults = ['imageLayout', 'tag']
|
||||
|
||||
|
||||
class SparseImageInput(ImageInputComputationNodeBase):
|
||||
|
||||
def __init__(self, imageWidth, imageHeight, imageChannels, imageLayout='CHW', tag='feature', name='SparseImageInput', var_name=None):
|
||||
super(SparseImageInput, self).__init__(params=['imageWidth', 'imageHeight', 'imageChannels', 'imageLayout', 'tag'], name=name, var_name=var_name)
|
||||
super(SparseImageInput, self).__init__(params=[
|
||||
'imageWidth', 'imageHeight', 'imageChannels', 'imageLayout', 'tag'], name=name, var_name=var_name)
|
||||
self.imageWidth = imageWidth
|
||||
self.imageHeight = imageHeight
|
||||
self.imageChannels = imageChannels
|
||||
|
@ -151,33 +205,45 @@ class SparseImageInput(ImageInputComputationNodeBase):
|
|||
self.tag = tag
|
||||
self.params_with_defaults = ['imageLayout', 'tag']
|
||||
|
||||
|
||||
class EnvironmentInput(ComputationNode):
|
||||
|
||||
def __init__(self, propertyName, name='EnvironmentInput', var_name=None):
|
||||
super(EnvironmentInput, self).__init__(params=['propertyName'], name=name, var_name=var_name)
|
||||
super(EnvironmentInput, self).__init__(
|
||||
params=['propertyName'], name=name, var_name=var_name)
|
||||
self.propertyName = propertyName
|
||||
self.params_with_defaults = []
|
||||
|
||||
|
||||
class PastValue(ComputationNode):
|
||||
|
||||
def __init__(self, dims, input, timeStep=1, defaultHiddenActivation=0.1, name='PastValue', var_name=None):
|
||||
super(PastValue, self).__init__(params=['dims', 'input', 'timeStep', 'defaultHiddenActivation'], name=name, var_name=var_name)
|
||||
super(PastValue, self).__init__(params=[
|
||||
'dims', 'input', 'timeStep', 'defaultHiddenActivation'], name=name, var_name=var_name)
|
||||
self.dims = dims
|
||||
self.input = input
|
||||
self.timeStep = timeStep
|
||||
self.defaultHiddenActivation = defaultHiddenActivation
|
||||
self.params_with_defaults = ['timeStep', 'defaultHiddenActivation']
|
||||
|
||||
|
||||
class FutureValue(ComputationNode):
|
||||
|
||||
def __init__(self, dims, input, timeStep=1, defaultHiddenActivation=0.1, name='FutureValue', var_name=None):
|
||||
super(FutureValue, self).__init__(params=['dims', 'input', 'timeStep', 'defaultHiddenActivation'], name=name, var_name=var_name)
|
||||
super(FutureValue, self).__init__(params=[
|
||||
'dims', 'input', 'timeStep', 'defaultHiddenActivation'], name=name, var_name=var_name)
|
||||
self.dims = dims
|
||||
self.input = input
|
||||
self.timeStep = timeStep
|
||||
self.defaultHiddenActivation = defaultHiddenActivation
|
||||
self.params_with_defaults = ['timeStep', 'defaultHiddenActivation']
|
||||
|
||||
|
||||
class Shift(ComputationNode):
|
||||
|
||||
def __init__(self, input, fromOffset, boundaryValue, boundaryMode=-1, dim=-1, name='Shift', var_name=None):
|
||||
super(Shift, self).__init__(params=['input', 'fromOffset', 'boundaryValue', 'boundaryMode', 'dim'], name=name, var_name=var_name)
|
||||
super(Shift, self).__init__(params=[
|
||||
'input', 'fromOffset', 'boundaryValue', 'boundaryMode', 'dim'], name=name, var_name=var_name)
|
||||
self.input = input
|
||||
self.fromOffset = fromOffset
|
||||
self.boundaryValue = boundaryValue
|
||||
|
@ -185,87 +251,121 @@ class Shift(ComputationNode):
|
|||
self.dim = dim
|
||||
self.params_with_defaults = ['boundaryMode', 'dim']
|
||||
|
||||
|
||||
class RowSlice(ComputationNode):
|
||||
|
||||
def __init__(self, startIndex, numRows, input, name='RowSlice', var_name=None):
|
||||
super(RowSlice, self).__init__(params=['startIndex', 'numRows', 'input'], name=name, var_name=var_name)
|
||||
super(RowSlice, self).__init__(
|
||||
params=['startIndex', 'numRows', 'input'], name=name, var_name=var_name)
|
||||
self.startIndex = startIndex
|
||||
self.numRows = numRows
|
||||
self.input = input
|
||||
self.params_with_defaults = []
|
||||
|
||||
|
||||
class RowRepeat(ComputationNode):
|
||||
|
||||
def __init__(self, input, numRepeats, name='RowRepeat', var_name=None):
|
||||
super(RowRepeat, self).__init__(params=['input', 'numRepeats'], name=name, var_name=var_name)
|
||||
super(RowRepeat, self).__init__(
|
||||
params=['input', 'numRepeats'], name=name, var_name=var_name)
|
||||
self.input = input
|
||||
self.numRepeats = numRepeats
|
||||
self.params_with_defaults = []
|
||||
|
||||
|
||||
class RowStack(ComputationNode):
|
||||
|
||||
def __init__(self, inputs, name='RowStack', var_name=None):
|
||||
super(RowStack, self).__init__(params=['inputs'], name=name, var_name=var_name)
|
||||
super(RowStack, self).__init__(
|
||||
params=['inputs'], name=name, var_name=var_name)
|
||||
self.inputs = inputs
|
||||
self.params_with_defaults = []
|
||||
|
||||
|
||||
class Reshape(ComputationNode):
|
||||
|
||||
def __init__(self, input, numRows, imageWidth=0, imageHeight=0, imageChannels=0, name='Reshape', var_name=None):
|
||||
super(Reshape, self).__init__(params=['input', 'numRows', 'imageWidth', 'imageHeight', 'imageChannels'], name=name, var_name=var_name)
|
||||
super(Reshape, self).__init__(params=[
|
||||
'input', 'numRows', 'imageWidth', 'imageHeight', 'imageChannels'], name=name, var_name=var_name)
|
||||
self.input = input
|
||||
self.numRows = numRows
|
||||
self.imageWidth = imageWidth
|
||||
self.imageHeight = imageHeight
|
||||
self.imageChannels = imageChannels
|
||||
self.params_with_defaults = ['imageWidth', 'imageHeight', 'imageChannels']
|
||||
self.params_with_defaults = [
|
||||
'imageWidth', 'imageHeight', 'imageChannels']
|
||||
|
||||
|
||||
class NewReshape(ComputationNode):
|
||||
|
||||
def __init__(self, input, dims, beginDim=0, endDim=0, name='NewReshape', var_name=None):
|
||||
super(NewReshape, self).__init__(params=['input', 'dims', 'beginDim', 'endDim'], name=name, var_name=var_name)
|
||||
super(NewReshape, self).__init__(
|
||||
params=['input', 'dims', 'beginDim', 'endDim'], name=name, var_name=var_name)
|
||||
self.input = input
|
||||
self.dims = dims
|
||||
self.beginDim = beginDim
|
||||
self.endDim = endDim
|
||||
self.params_with_defaults = ['beginDim', 'endDim']
|
||||
|
||||
|
||||
class TransposeDimensions(ComputationNode):
|
||||
|
||||
def __init__(self, input, dim1, dim2, name='TransposeDimensions', var_name=None):
|
||||
super(TransposeDimensions, self).__init__(params=['input', 'dim1', 'dim2'], name=name, var_name=var_name)
|
||||
super(TransposeDimensions, self).__init__(
|
||||
params=['input', 'dim1', 'dim2'], name=name, var_name=var_name)
|
||||
self.input = input
|
||||
self.dim1 = dim1
|
||||
self.dim2 = dim2
|
||||
self.params_with_defaults = []
|
||||
|
||||
|
||||
class Times(ComputationNode):
|
||||
|
||||
def __init__(self, A, B, outputRank=1, name='Times', var_name=None):
|
||||
super(Times, self).__init__(params=['A', 'B', 'outputRank'], name=name, var_name=var_name)
|
||||
super(Times, self).__init__(
|
||||
params=['A', 'B', 'outputRank'], name=name, var_name=var_name)
|
||||
self.A = A
|
||||
self.B = B
|
||||
self.outputRank = outputRank
|
||||
self.params_with_defaults = ['outputRank']
|
||||
|
||||
|
||||
class Logistic(ComputationNode):
|
||||
|
||||
def __init__(self, label, probability, name='Logistic', var_name=None):
|
||||
super(Logistic, self).__init__(params=['label', 'probability'], name=name, var_name=var_name)
|
||||
super(Logistic, self).__init__(
|
||||
params=['label', 'probability'], name=name, var_name=var_name)
|
||||
self.label = label
|
||||
self.probability = probability
|
||||
self.params_with_defaults = []
|
||||
|
||||
|
||||
class WeightedLogistic(ComputationNode):
|
||||
|
||||
def __init__(self, label, probability, instanceWeight, name='WeightedLogistic', var_name=None):
|
||||
super(WeightedLogistic, self).__init__(params=['label', 'probability', 'instanceWeight'], name=name, var_name=var_name)
|
||||
super(WeightedLogistic, self).__init__(
|
||||
params=['label', 'probability', 'instanceWeight'], name=name, var_name=var_name)
|
||||
self.label = label
|
||||
self.probability = probability
|
||||
self.instanceWeight = instanceWeight
|
||||
self.params_with_defaults = []
|
||||
|
||||
|
||||
class ReconcileMBLayout(ComputationNode):
|
||||
|
||||
def __init__(self, dataInput, layoutInput, name='ReconcileMBLayout', var_name=None):
|
||||
super(ReconcileMBLayout, self).__init__(params=['dataInput', 'layoutInput'], name=name, var_name=var_name)
|
||||
super(ReconcileMBLayout, self).__init__(
|
||||
params=['dataInput', 'layoutInput'], name=name, var_name=var_name)
|
||||
self.dataInput = dataInput
|
||||
self.layoutInput = layoutInput
|
||||
self.params_with_defaults = []
|
||||
|
||||
|
||||
class Convolution(ComputationNode):
|
||||
|
||||
def __init__(self, weightNode, inputValueNode, kernelWidth, kernelHeight, outputChannels, horizontalSubsample, verticalSubsample, zeroPadding=False, maxTempMemSizeInSamples=0, imageLayout='CHW', name='Convolution', var_name=None):
|
||||
super(Convolution, self).__init__(params=['weightNode', 'inputValueNode', 'kernelWidth', 'kernelHeight', 'outputChannels', 'horizontalSubsample', 'verticalSubsample', 'zeroPadding', 'maxTempMemSizeInSamples', 'imageLayout'], name=name, var_name=var_name)
|
||||
super(Convolution, self).__init__(params=['weightNode', 'inputValueNode', 'kernelWidth', 'kernelHeight', 'outputChannels',
|
||||
'horizontalSubsample', 'verticalSubsample', 'zeroPadding', 'maxTempMemSizeInSamples', 'imageLayout'], name=name, var_name=var_name)
|
||||
self.weightNode = weightNode
|
||||
self.inputValueNode = inputValueNode
|
||||
self.kernelWidth = kernelWidth
|
||||
|
@ -276,11 +376,15 @@ class Convolution(ComputationNode):
|
|||
self.zeroPadding = zeroPadding
|
||||
self.maxTempMemSizeInSamples = maxTempMemSizeInSamples
|
||||
self.imageLayout = imageLayout
|
||||
self.params_with_defaults = ['zeroPadding', 'maxTempMemSizeInSamples', 'imageLayout']
|
||||
self.params_with_defaults = [
|
||||
'zeroPadding', 'maxTempMemSizeInSamples', 'imageLayout']
|
||||
|
||||
|
||||
class MaxPooling(ComputationNode):
|
||||
|
||||
def __init__(self, input, windowWidth, windowHeight, horizontalSubsample, verticalSubsample, imageLayout='CHW', name='MaxPooling', var_name=None):
|
||||
super(MaxPooling, self).__init__(params=['input', 'windowWidth', 'windowHeight', 'horizontalSubsample', 'verticalSubsample', 'imageLayout'], name=name, var_name=var_name)
|
||||
super(MaxPooling, self).__init__(params=[
|
||||
'input', 'windowWidth', 'windowHeight', 'horizontalSubsample', 'verticalSubsample', 'imageLayout'], name=name, var_name=var_name)
|
||||
self.input = input
|
||||
self.windowWidth = windowWidth
|
||||
self.windowHeight = windowHeight
|
||||
|
@ -289,9 +393,12 @@ class MaxPooling(ComputationNode):
|
|||
self.imageLayout = imageLayout
|
||||
self.params_with_defaults = ['imageLayout']
|
||||
|
||||
|
||||
class AveragePooling(ComputationNode):
|
||||
|
||||
def __init__(self, input, windowWidth, windowHeight, horizontalSubsample, verticalSubsample, imageLayout='CHW', name='AveragePooling', var_name=None):
|
||||
super(AveragePooling, self).__init__(params=['input', 'windowWidth', 'windowHeight', 'horizontalSubsample', 'verticalSubsample', 'imageLayout'], name=name, var_name=var_name)
|
||||
super(AveragePooling, self).__init__(params=[
|
||||
'input', 'windowWidth', 'windowHeight', 'horizontalSubsample', 'verticalSubsample', 'imageLayout'], name=name, var_name=var_name)
|
||||
self.input = input
|
||||
self.windowWidth = windowWidth
|
||||
self.windowHeight = windowHeight
|
||||
|
@ -300,9 +407,12 @@ class AveragePooling(ComputationNode):
|
|||
self.imageLayout = imageLayout
|
||||
self.params_with_defaults = ['imageLayout']
|
||||
|
||||
|
||||
class BatchNormalization(ComputationNode):
|
||||
|
||||
def __init__(self, input, scale, bias, runMean, runInvStdDev, eval, spatial, normalizationTimeConstant=0, epsilon=1e-05, useCntkEngine=True, imageLayout='CHW', name='BatchNormalization', var_name=None):
|
||||
super(BatchNormalization, self).__init__(params=['input', 'scale', 'bias', 'runMean', 'runInvStdDev', 'eval', 'spatial', 'normalizationTimeConstant', 'epsilon', 'useCntkEngine', 'imageLayout'], name=name, var_name=var_name)
|
||||
super(BatchNormalization, self).__init__(params=['input', 'scale', 'bias', 'runMean', 'runInvStdDev', 'eval',
|
||||
'spatial', 'normalizationTimeConstant', 'epsilon', 'useCntkEngine', 'imageLayout'], name=name, var_name=var_name)
|
||||
self.input = input
|
||||
self.scale = scale
|
||||
self.bias = bias
|
||||
|
@ -314,287 +424,409 @@ class BatchNormalization(ComputationNode):
|
|||
self.epsilon = epsilon
|
||||
self.useCntkEngine = useCntkEngine
|
||||
self.imageLayout = imageLayout
|
||||
self.params_with_defaults = ['normalizationTimeConstant', 'epsilon', 'useCntkEngine', 'imageLayout']
|
||||
self.params_with_defaults = [
|
||||
'normalizationTimeConstant', 'epsilon', 'useCntkEngine', 'imageLayout']
|
||||
|
||||
|
||||
class Abs(ComputationNode):
|
||||
|
||||
def __init__(self, x, name='Abs', var_name=None):
|
||||
super(Abs, self).__init__(params=['x'], name=name, var_name=var_name)
|
||||
self.x = x
|
||||
self.params_with_defaults = []
|
||||
|
||||
|
||||
class ClassBasedCrossEntropyWithSoftmax(ComputationNode):
|
||||
|
||||
def __init__(self, labelClassDescriptorVectorSequence, mainInputInfo, mainWeight, classLogProbsBeforeSoftmax, name='ClassBasedCrossEntropyWithSoftmax', var_name=None):
|
||||
super(ClassBasedCrossEntropyWithSoftmax, self).__init__(params=['labelClassDescriptorVectorSequence', 'mainInputInfo', 'mainWeight', 'classLogProbsBeforeSoftmax'], name=name, var_name=var_name)
|
||||
super(ClassBasedCrossEntropyWithSoftmax, self).__init__(params=[
|
||||
'labelClassDescriptorVectorSequence', 'mainInputInfo', 'mainWeight', 'classLogProbsBeforeSoftmax'], name=name, var_name=var_name)
|
||||
self.labelClassDescriptorVectorSequence = labelClassDescriptorVectorSequence
|
||||
self.mainInputInfo = mainInputInfo
|
||||
self.mainWeight = mainWeight
|
||||
self.classLogProbsBeforeSoftmax = classLogProbsBeforeSoftmax
|
||||
self.params_with_defaults = []
|
||||
|
||||
|
||||
class ColumnElementTimes(ComputationNode):
|
||||
|
||||
def __init__(self, aVectorSequence, anotherVectorSequence, name='ColumnElementTimes', var_name=None):
|
||||
super(ColumnElementTimes, self).__init__(params=['aVectorSequence', 'anotherVectorSequence'], name=name, var_name=var_name)
|
||||
super(ColumnElementTimes, self).__init__(
|
||||
params=['aVectorSequence', 'anotherVectorSequence'], name=name, var_name=var_name)
|
||||
self.aVectorSequence = aVectorSequence
|
||||
self.anotherVectorSequence = anotherVectorSequence
|
||||
self.params_with_defaults = []
|
||||
|
||||
|
||||
class CosDistance(ComputationNode):
|
||||
|
||||
def __init__(self, aVectorSequence, anotherVectorSequence, name='CosDistance', var_name=None):
|
||||
super(CosDistance, self).__init__(params=['aVectorSequence', 'anotherVectorSequence'], name=name, var_name=var_name)
|
||||
super(CosDistance, self).__init__(
|
||||
params=['aVectorSequence', 'anotherVectorSequence'], name=name, var_name=var_name)
|
||||
self.aVectorSequence = aVectorSequence
|
||||
self.anotherVectorSequence = anotherVectorSequence
|
||||
self.params_with_defaults = []
|
||||
|
||||
|
||||
class CosDistanceWithNegativeSamples(ComputationNode):
|
||||
|
||||
def __init__(self, aVectorSequence, anotherVectorSequence, numShifts, numNegSamples, name='CosDistanceWithNegativeSamples', var_name=None):
|
||||
super(CosDistanceWithNegativeSamples, self).__init__(params=['aVectorSequence', 'anotherVectorSequence', 'numShifts', 'numNegSamples'], name=name, var_name=var_name)
|
||||
super(CosDistanceWithNegativeSamples, self).__init__(params=[
|
||||
'aVectorSequence', 'anotherVectorSequence', 'numShifts', 'numNegSamples'], name=name, var_name=var_name)
|
||||
self.aVectorSequence = aVectorSequence
|
||||
self.anotherVectorSequence = anotherVectorSequence
|
||||
self.numShifts = numShifts
|
||||
self.numNegSamples = numNegSamples
|
||||
self.params_with_defaults = []
|
||||
|
||||
|
||||
class Cosine(ComputationNode):
|
||||
|
||||
def __init__(self, x, name='Cosine', var_name=None):
|
||||
super(Cosine, self).__init__(params=['x'], name=name, var_name=var_name)
|
||||
super(Cosine, self).__init__(
|
||||
params=['x'], name=name, var_name=var_name)
|
||||
self.x = x
|
||||
self.params_with_defaults = []
|
||||
|
||||
|
||||
class CrossEntropy(ComputationNode):
|
||||
|
||||
def __init__(self, refProbVectorSequence, outProbVectorSequence, name='CrossEntropy', var_name=None):
|
||||
super(CrossEntropy, self).__init__(params=['refProbVectorSequence', 'outProbVectorSequence'], name=name, var_name=var_name)
|
||||
super(CrossEntropy, self).__init__(params=[
|
||||
'refProbVectorSequence', 'outProbVectorSequence'], name=name, var_name=var_name)
|
||||
self.refProbVectorSequence = refProbVectorSequence
|
||||
self.outProbVectorSequence = outProbVectorSequence
|
||||
self.params_with_defaults = []
|
||||
|
||||
|
||||
class CrossEntropyWithSoftmax(ComputationNode):
|
||||
|
||||
def __init__(self, labelVectorSequence, outProbVectorSequence, name='CrossEntropyWithSoftmax', var_name=None):
|
||||
super(CrossEntropyWithSoftmax, self).__init__(params=['labelVectorSequence', 'outProbVectorSequence'], name=name, var_name=var_name)
|
||||
super(CrossEntropyWithSoftmax, self).__init__(params=[
|
||||
'labelVectorSequence', 'outProbVectorSequence'], name=name, var_name=var_name)
|
||||
self.labelVectorSequence = labelVectorSequence
|
||||
self.outProbVectorSequence = outProbVectorSequence
|
||||
self.params_with_defaults = []
|
||||
|
||||
|
||||
class DiagTimes(ComputationNode):
|
||||
|
||||
def __init__(self, diagonalMatrixAsColumnVector, matrix, name='DiagTimes', var_name=None):
|
||||
super(DiagTimes, self).__init__(params=['diagonalMatrixAsColumnVector', 'matrix'], name=name, var_name=var_name)
|
||||
super(DiagTimes, self).__init__(
|
||||
params=['diagonalMatrixAsColumnVector', 'matrix'], name=name, var_name=var_name)
|
||||
self.diagonalMatrixAsColumnVector = diagonalMatrixAsColumnVector
|
||||
self.matrix = matrix
|
||||
self.params_with_defaults = []
|
||||
|
||||
|
||||
class Dropout(ComputationNode):
|
||||
|
||||
def __init__(self, activationVectorSequence, name='Dropout', var_name=None):
|
||||
super(Dropout, self).__init__(params=['activationVectorSequence'], name=name, var_name=var_name)
|
||||
super(Dropout, self).__init__(
|
||||
params=['activationVectorSequence'], name=name, var_name=var_name)
|
||||
self.activationVectorSequence = activationVectorSequence
|
||||
self.params_with_defaults = []
|
||||
|
||||
|
||||
class ElementTimes(ComputationNode):
|
||||
|
||||
def __init__(self, aMatrix, anotherMatrix, name='ElementTimes', var_name=None):
|
||||
super(ElementTimes, self).__init__(params=['aMatrix', 'anotherMatrix'], name=name, var_name=var_name)
|
||||
super(ElementTimes, self).__init__(
|
||||
params=['aMatrix', 'anotherMatrix'], name=name, var_name=var_name)
|
||||
self.aMatrix = aMatrix
|
||||
self.anotherMatrix = anotherMatrix
|
||||
self.params_with_defaults = []
|
||||
|
||||
|
||||
class ErrorPrediction(ComputationNode):
|
||||
|
||||
def __init__(self, labelVectorSequence, outVectorSequence, name='ErrorPrediction', var_name=None):
|
||||
super(ErrorPrediction, self).__init__(params=['labelVectorSequence', 'outVectorSequence'], name=name, var_name=var_name)
|
||||
super(ErrorPrediction, self).__init__(
|
||||
params=['labelVectorSequence', 'outVectorSequence'], name=name, var_name=var_name)
|
||||
self.labelVectorSequence = labelVectorSequence
|
||||
self.outVectorSequence = outVectorSequence
|
||||
self.params_with_defaults = []
|
||||
|
||||
|
||||
class Exp(ComputationNode):
|
||||
|
||||
def __init__(self, x, name='Exp', var_name=None):
|
||||
super(Exp, self).__init__(params=['x'], name=name, var_name=var_name)
|
||||
self.x = x
|
||||
self.params_with_defaults = []
|
||||
|
||||
|
||||
class GatherPacked(ComputationNode):
|
||||
|
||||
def __init__(self, indexSequence, sourceData, name='GatherPacked', var_name=None):
|
||||
super(GatherPacked, self).__init__(params=['indexSequence', 'sourceData'], name=name, var_name=var_name)
|
||||
super(GatherPacked, self).__init__(
|
||||
params=['indexSequence', 'sourceData'], name=name, var_name=var_name)
|
||||
self.indexSequence = indexSequence
|
||||
self.sourceData = sourceData
|
||||
self.params_with_defaults = []
|
||||
|
||||
|
||||
class GMMLogLikelihood(ComputationNode):
|
||||
|
||||
def __init__(self, unnormalizedPriorVector, meansAsRows, logStdDevAsRows, dataVectorSequence, name='GMMLogLikelihood', var_name=None):
|
||||
super(GMMLogLikelihood, self).__init__(params=['unnormalizedPriorVector', 'meansAsRows', 'logStdDevAsRows', 'dataVectorSequence'], name=name, var_name=var_name)
|
||||
super(GMMLogLikelihood, self).__init__(params=[
|
||||
'unnormalizedPriorVector', 'meansAsRows', 'logStdDevAsRows', 'dataVectorSequence'], name=name, var_name=var_name)
|
||||
self.unnormalizedPriorVector = unnormalizedPriorVector
|
||||
self.meansAsRows = meansAsRows
|
||||
self.logStdDevAsRows = logStdDevAsRows
|
||||
self.dataVectorSequence = dataVectorSequence
|
||||
self.params_with_defaults = []
|
||||
|
||||
|
||||
class InvStdDev(ComputationNode):
|
||||
|
||||
def __init__(self, dataVectorSequence, name='InvStdDev', var_name=None):
|
||||
super(InvStdDev, self).__init__(params=['dataVectorSequence'], name=name, var_name=var_name)
|
||||
super(InvStdDev, self).__init__(
|
||||
params=['dataVectorSequence'], name=name, var_name=var_name)
|
||||
self.dataVectorSequence = dataVectorSequence
|
||||
self.params_with_defaults = []
|
||||
|
||||
|
||||
class KhatriRaoProduct(ComputationNode):
|
||||
|
||||
def __init__(self, leftMatrix, rightMatrix, name='KhatriRaoProduct', var_name=None):
|
||||
super(KhatriRaoProduct, self).__init__(params=['leftMatrix', 'rightMatrix'], name=name, var_name=var_name)
|
||||
super(KhatriRaoProduct, self).__init__(
|
||||
params=['leftMatrix', 'rightMatrix'], name=name, var_name=var_name)
|
||||
self.leftMatrix = leftMatrix
|
||||
self.rightMatrix = rightMatrix
|
||||
self.params_with_defaults = []
|
||||
|
||||
|
||||
class Log(ComputationNode):
|
||||
|
||||
def __init__(self, x, name='Log', var_name=None):
|
||||
super(Log, self).__init__(params=['x'], name=name, var_name=var_name)
|
||||
self.x = x
|
||||
self.params_with_defaults = []
|
||||
|
||||
|
||||
class LogSoftmax(ComputationNode):
|
||||
|
||||
def __init__(self, z, name='LogSoftmax', var_name=None):
|
||||
super(LogSoftmax, self).__init__(params=['z'], name=name, var_name=var_name)
|
||||
super(LogSoftmax, self).__init__(
|
||||
params=['z'], name=name, var_name=var_name)
|
||||
self.z = z
|
||||
self.params_with_defaults = []
|
||||
|
||||
|
||||
class MatrixL1Reg(ComputationNode):
|
||||
|
||||
def __init__(self, matrix, name='MatrixL1Reg', var_name=None):
|
||||
super(MatrixL1Reg, self).__init__(params=['matrix'], name=name, var_name=var_name)
|
||||
super(MatrixL1Reg, self).__init__(
|
||||
params=['matrix'], name=name, var_name=var_name)
|
||||
self.matrix = matrix
|
||||
self.params_with_defaults = []
|
||||
|
||||
|
||||
class MatrixL2Reg(ComputationNode):
|
||||
|
||||
def __init__(self, matrix, name='MatrixL2Reg', var_name=None):
|
||||
super(MatrixL2Reg, self).__init__(params=['matrix'], name=name, var_name=var_name)
|
||||
super(MatrixL2Reg, self).__init__(
|
||||
params=['matrix'], name=name, var_name=var_name)
|
||||
self.matrix = matrix
|
||||
self.params_with_defaults = []
|
||||
|
||||
|
||||
class Mean(ComputationNode):
|
||||
|
||||
def __init__(self, dataVectorSequence, name='Mean', var_name=None):
|
||||
super(Mean, self).__init__(params=['dataVectorSequence'], name=name, var_name=var_name)
|
||||
super(Mean, self).__init__(
|
||||
params=['dataVectorSequence'], name=name, var_name=var_name)
|
||||
self.dataVectorSequence = dataVectorSequence
|
||||
self.params_with_defaults = []
|
||||
|
||||
|
||||
class Minus(ComputationNode):
|
||||
|
||||
def __init__(self, leftMatrix, rightMatrix, name='Minus', var_name=None):
|
||||
super(Minus, self).__init__(params=['leftMatrix', 'rightMatrix'], name=name, var_name=var_name)
|
||||
super(Minus, self).__init__(
|
||||
params=['leftMatrix', 'rightMatrix'], name=name, var_name=var_name)
|
||||
self.leftMatrix = leftMatrix
|
||||
self.rightMatrix = rightMatrix
|
||||
self.params_with_defaults = []
|
||||
|
||||
|
||||
class Negate(ComputationNode):
|
||||
|
||||
def __init__(self, input, name='Negate', var_name=None):
|
||||
super(Negate, self).__init__(params=['input'], name=name, var_name=var_name)
|
||||
super(Negate, self).__init__(
|
||||
params=['input'], name=name, var_name=var_name)
|
||||
self.input = input
|
||||
self.params_with_defaults = []
|
||||
|
||||
|
||||
class PackedIndex(ComputationNode):
|
||||
|
||||
def __init__(self, targetObject, indexSequence, name='PackedIndex', var_name=None):
|
||||
super(PackedIndex, self).__init__(params=['targetObject', 'indexSequence'], name=name, var_name=var_name)
|
||||
super(PackedIndex, self).__init__(
|
||||
params=['targetObject', 'indexSequence'], name=name, var_name=var_name)
|
||||
self.targetObject = targetObject
|
||||
self.indexSequence = indexSequence
|
||||
self.params_with_defaults = []
|
||||
|
||||
|
||||
class PerDimMeanVarDeNormalization(ComputationNode):
|
||||
|
||||
def __init__(self, dataVectorSequence, meanVector, invStdDevVector, name='PerDimMeanVarDeNormalization', var_name=None):
|
||||
super(PerDimMeanVarDeNormalization, self).__init__(params=['dataVectorSequence', 'meanVector', 'invStdDevVector'], name=name, var_name=var_name)
|
||||
super(PerDimMeanVarDeNormalization, self).__init__(params=[
|
||||
'dataVectorSequence', 'meanVector', 'invStdDevVector'], name=name, var_name=var_name)
|
||||
self.dataVectorSequence = dataVectorSequence
|
||||
self.meanVector = meanVector
|
||||
self.invStdDevVector = invStdDevVector
|
||||
self.params_with_defaults = []
|
||||
|
||||
|
||||
class PerDimMeanVarNormalization(ComputationNode):
|
||||
|
||||
def __init__(self, dataVectorSequence, meanVector, invStdDevVector, name='PerDimMeanVarNormalization', var_name=None):
|
||||
super(PerDimMeanVarNormalization, self).__init__(params=['dataVectorSequence', 'meanVector', 'invStdDevVector'], name=name, var_name=var_name)
|
||||
super(PerDimMeanVarNormalization, self).__init__(params=[
|
||||
'dataVectorSequence', 'meanVector', 'invStdDevVector'], name=name, var_name=var_name)
|
||||
self.dataVectorSequence = dataVectorSequence
|
||||
self.meanVector = meanVector
|
||||
self.invStdDevVector = invStdDevVector
|
||||
self.params_with_defaults = []
|
||||
|
||||
|
||||
class Plus(ComputationNode):
|
||||
|
||||
def __init__(self, leftMatrix, rightMatrix, name='Plus', var_name=None):
|
||||
super(Plus, self).__init__(params=['leftMatrix', 'rightMatrix'], name=name, var_name=var_name)
|
||||
super(Plus, self).__init__(
|
||||
params=['leftMatrix', 'rightMatrix'], name=name, var_name=var_name)
|
||||
self.leftMatrix = leftMatrix
|
||||
self.rightMatrix = rightMatrix
|
||||
self.params_with_defaults = []
|
||||
|
||||
|
||||
class RectifiedLinear(ComputationNode):
|
||||
|
||||
def __init__(self, z, name='RectifiedLinear', var_name=None):
|
||||
super(RectifiedLinear, self).__init__(params=['z'], name=name, var_name=var_name)
|
||||
super(RectifiedLinear, self).__init__(
|
||||
params=['z'], name=name, var_name=var_name)
|
||||
self.z = z
|
||||
self.params_with_defaults = []
|
||||
|
||||
|
||||
class Scale(ComputationNode):
|
||||
|
||||
def __init__(self, scalarScalingFactor, matrix, name='Scale', var_name=None):
|
||||
super(Scale, self).__init__(params=['scalarScalingFactor', 'matrix'], name=name, var_name=var_name)
|
||||
super(Scale, self).__init__(
|
||||
params=['scalarScalingFactor', 'matrix'], name=name, var_name=var_name)
|
||||
self.scalarScalingFactor = scalarScalingFactor
|
||||
self.matrix = matrix
|
||||
self.params_with_defaults = []
|
||||
|
||||
|
||||
class ScatterPacked(ComputationNode):
|
||||
|
||||
def __init__(self, cond, indexSequence, sourceData, name='ScatterPacked', var_name=None):
|
||||
super(ScatterPacked, self).__init__(params=['cond', 'indexSequence', 'sourceData'], name=name, var_name=var_name)
|
||||
super(ScatterPacked, self).__init__(
|
||||
params=['cond', 'indexSequence', 'sourceData'], name=name, var_name=var_name)
|
||||
self.cond = cond
|
||||
self.indexSequence = indexSequence
|
||||
self.sourceData = sourceData
|
||||
self.params_with_defaults = []
|
||||
|
||||
|
||||
class Sigmoid(ComputationNode):
|
||||
|
||||
def __init__(self, z, name='Sigmoid', var_name=None):
|
||||
super(Sigmoid, self).__init__(params=['z'], name=name, var_name=var_name)
|
||||
super(Sigmoid, self).__init__(
|
||||
params=['z'], name=name, var_name=var_name)
|
||||
self.z = z
|
||||
self.params_with_defaults = []
|
||||
|
||||
|
||||
class Softmax(ComputationNode):
|
||||
|
||||
def __init__(self, z, name='Softmax', var_name=None):
|
||||
super(Softmax, self).__init__(params=['z'], name=name, var_name=var_name)
|
||||
super(Softmax, self).__init__(
|
||||
params=['z'], name=name, var_name=var_name)
|
||||
self.z = z
|
||||
self.params_with_defaults = []
|
||||
|
||||
|
||||
class Hardmax(ComputationNode):
|
||||
|
||||
def __init__(self, z, name='Hardmax', var_name=None):
|
||||
super(Hardmax, self).__init__(params=['z'], name=name, var_name=var_name)
|
||||
super(Hardmax, self).__init__(
|
||||
params=['z'], name=name, var_name=var_name)
|
||||
self.z = z
|
||||
self.params_with_defaults = []
|
||||
|
||||
|
||||
class Sqrt(ComputationNode):
|
||||
|
||||
def __init__(self, z, name='Sqrt', var_name=None):
|
||||
super(Sqrt, self).__init__(params=['z'], name=name, var_name=var_name)
|
||||
self.z = z
|
||||
self.params_with_defaults = []
|
||||
|
||||
|
||||
class SquareError(ComputationNode):
|
||||
|
||||
def __init__(self, aMatrix, anotherMatrix, name='SquareError', var_name=None):
|
||||
super(SquareError, self).__init__(params=['aMatrix', 'anotherMatrix'], name=name, var_name=var_name)
|
||||
super(SquareError, self).__init__(
|
||||
params=['aMatrix', 'anotherMatrix'], name=name, var_name=var_name)
|
||||
self.aMatrix = aMatrix
|
||||
self.anotherMatrix = anotherMatrix
|
||||
self.params_with_defaults = []
|
||||
|
||||
|
||||
class SumColumnElements(ComputationNode):
|
||||
|
||||
def __init__(self, z, name='SumColumnElements', var_name=None):
|
||||
super(SumColumnElements, self).__init__(params=['z'], name=name, var_name=var_name)
|
||||
super(SumColumnElements, self).__init__(
|
||||
params=['z'], name=name, var_name=var_name)
|
||||
self.z = z
|
||||
self.params_with_defaults = []
|
||||
|
||||
|
||||
class SumElements(ComputationNode):
|
||||
|
||||
def __init__(self, matrix, name='SumElements', var_name=None):
|
||||
super(SumElements, self).__init__(params=['matrix'], name=name, var_name=var_name)
|
||||
super(SumElements, self).__init__(
|
||||
params=['matrix'], name=name, var_name=var_name)
|
||||
self.matrix = matrix
|
||||
self.params_with_defaults = []
|
||||
|
||||
|
||||
class Tanh(ComputationNode):
|
||||
|
||||
def __init__(self, z, name='Tanh', var_name=None):
|
||||
super(Tanh, self).__init__(params=['z'], name=name, var_name=var_name)
|
||||
self.z = z
|
||||
self.params_with_defaults = []
|
||||
|
||||
|
||||
class TimeReverse(ComputationNode):
|
||||
|
||||
def __init__(self, vectorSequence, name='TimeReverse', var_name=None):
|
||||
super(TimeReverse, self).__init__(params=['vectorSequence'], name=name, var_name=var_name)
|
||||
super(TimeReverse, self).__init__(
|
||||
params=['vectorSequence'], name=name, var_name=var_name)
|
||||
self.vectorSequence = vectorSequence
|
||||
self.params_with_defaults = []
|
||||
|
||||
|
||||
class TransposeTimes(ComputationNode):
|
||||
|
||||
def __init__(self, leftMatrix, rightMatrix, name='TransposeTimes', var_name=None):
|
||||
super(TransposeTimes, self).__init__(params=['leftMatrix', 'rightMatrix'], name=name, var_name=var_name)
|
||||
super(TransposeTimes, self).__init__(
|
||||
params=['leftMatrix', 'rightMatrix'], name=name, var_name=var_name)
|
||||
self.leftMatrix = leftMatrix
|
||||
self.rightMatrix = rightMatrix
|
||||
self.params_with_defaults = []
|
||||
|
||||
|
||||
class Where(ComputationNode):
|
||||
|
||||
def __init__(self, cond, name='Where', var_name=None):
|
||||
super(Where, self).__init__(params=['cond'], name=name, var_name=var_name)
|
||||
super(Where, self).__init__(
|
||||
params=['cond'], name=name, var_name=var_name)
|
||||
self.cond = cond
|
||||
self.params_with_defaults = []
|
||||
|
||||
|
@ -602,33 +834,47 @@ Parameter = LearnableParameter
|
|||
ColumnwiseCrossProduct = KhatriRaoProduct
|
||||
ClassificationError = ErrorPrediction
|
||||
Delay = PastValue
|
||||
|
||||
|
||||
class Constant(Parameter):
|
||||
|
||||
def __init__(self, value, rows=1, cols=1, name='Constant', var_name=None):
|
||||
super(Constant, self).__init__(rows, cols, learningRateMultiplier=0, init='fixedValue', value=value, name=name, var_name=var_name)
|
||||
self.params=['value', 'rows', 'cols']
|
||||
super(Constant, self).__init__(rows, cols, learningRateMultiplier=0,
|
||||
init='fixedValue', value=value, name=name, var_name=var_name)
|
||||
self.params = ['value', 'rows', 'cols']
|
||||
self.params_with_defaults = ['rows', 'cols']
|
||||
|
||||
|
||||
class ReshapeDimension(NewReshape):
|
||||
|
||||
def __init__(self, x, dim, tensorShape, name='ReshapeDimension', var_name=None):
|
||||
super(ReshapeDimension, self).__init__(x, tensorShape, beginDim=dim, endDim=dim + 1, name=name, var_name=var_name)
|
||||
self.params=['x', 'dim', 'tensorShape']
|
||||
super(ReshapeDimension, self).__init__(
|
||||
x, tensorShape, beginDim=dim, endDim=dim + 1, name=name, var_name=var_name)
|
||||
self.params = ['x', 'dim', 'tensorShape']
|
||||
self.params_with_defaults = []
|
||||
|
||||
|
||||
class FlattenDimensions(NewReshape):
|
||||
|
||||
def __init__(self, x, dim, num, name='FlattenDimensions', var_name=None):
|
||||
super(FlattenDimensions, self).__init__(x, 0, beginDim=dim, endDim=dim + num, name=name, var_name=var_name)
|
||||
self.params=['x', 'dim', 'num']
|
||||
super(FlattenDimensions, self).__init__(
|
||||
x, 0, beginDim=dim, endDim=dim + num, name=name, var_name=var_name)
|
||||
self.params = ['x', 'dim', 'num']
|
||||
self.params_with_defaults = []
|
||||
|
||||
|
||||
class SplitDimension(ReshapeDimension):
|
||||
|
||||
def __init__(self, x, dim, N, name='SplitDimension', var_name=None):
|
||||
super(SplitDimension, self).__init__(x, dim, '<not yet supported>', name=name, var_name=var_name)
|
||||
self.params=['x', 'dim', 'N']
|
||||
super(SplitDimension, self).__init__(
|
||||
x, dim, '<not yet supported>', name=name, var_name=var_name)
|
||||
self.params = ['x', 'dim', 'N']
|
||||
self.params_with_defaults = []
|
||||
|
||||
|
||||
class Transpose(TransposeDimensions):
|
||||
|
||||
def __init__(self, x, name='Transpose', var_name=None):
|
||||
super(Transpose, self).__init__(x, 1, 2, name=name, var_name=var_name)
|
||||
self.params=['x']
|
||||
self.params = ['x']
|
||||
self.params_with_defaults = []
|
||||
|
|
@ -2,10 +2,10 @@ class SGD(dict):
|
|||
|
||||
"""This is the Stochastic Gradien Descent optimizer used to train the networks
|
||||
"""
|
||||
def __init__(self, epoch_size = 0, minibatch_size = 1, learning_ratesPerMB = "0.1", \
|
||||
learning_rates_per_sample = None, momentum_per_mb = "0.9", \
|
||||
momentum_per_sample = None, max_epochs = 5, dropout_rate = None):
|
||||
|
||||
def __init__(self, epoch_size=0, minibatch_size=1, learning_ratesPerMB="0.1",
|
||||
learning_rates_per_sample=None, momentum_per_mb="0.9",
|
||||
momentum_per_sample=None, max_epochs=5, dropout_rate=None):
|
||||
""" SGD constructor
|
||||
|
||||
:param epoch_size: the number of samples to use in each epoch. An intermediate
|
||||
|
@ -53,7 +53,7 @@ class SGD(dict):
|
|||
"""
|
||||
|
||||
config = []
|
||||
for k,v in self.items():
|
||||
for k, v in self.items():
|
||||
if (v is not None):
|
||||
config.append('{0} = {1}\r\n'.format(k,v))
|
||||
config.append('{0} = {1}\r\n'.format(k, v))
|
||||
return ''.join(config)
|
||||
|
|
|
@ -22,6 +22,7 @@ class AbstractReader(dict, metaclass=ABCMeta):
|
|||
|
||||
def __ne__(self, x): return x is not self
|
||||
|
||||
|
||||
class UCIFastReader(AbstractReader):
|
||||
|
||||
"""This is the reader class the maps to UCIFastReader of CNTK
|
||||
|
@ -49,21 +50,24 @@ class UCIFastReader(AbstractReader):
|
|||
if not name_or_node or input_start is None or input_dim is None:
|
||||
raise ValueError("one of the parameters of add_input is None")
|
||||
|
||||
self.inputs_def.append((name_or_node, input_start, input_dim, num_of_classes, label_mapping_file))
|
||||
self.inputs_def.append(
|
||||
(name_or_node, input_start, input_dim, num_of_classes, label_mapping_file))
|
||||
|
||||
def generate_config(self):
|
||||
"""Generate the reader configuration block
|
||||
"""
|
||||
template = ''' reader = [
|
||||
template = '''\
|
||||
reader = [
|
||||
traceLevel = 2
|
||||
readerType = "%(ReaderType)s"
|
||||
file = "%(FileName)s"
|
||||
randomize = "none"
|
||||
verbosity = 1
|
||||
'''
|
||||
'''
|
||||
|
||||
if self['CustomDelimiter'] is not None:
|
||||
template += '''
|
||||
customDelimiter=%(CustomDelimiter)s
|
||||
template += '''\
|
||||
customDelimiter = %(CustomDelimiter)s
|
||||
'''
|
||||
|
||||
if self.inputs_def is not None:
|
||||
|
@ -74,30 +78,31 @@ class UCIFastReader(AbstractReader):
|
|||
name = name_or_node
|
||||
|
||||
template += '''
|
||||
{0}=[
|
||||
{0} = [
|
||||
start = {1}
|
||||
dim = {2}
|
||||
'''.format(name, start, dim)
|
||||
|
||||
if num_of_classes:
|
||||
template += '''
|
||||
template += '''\
|
||||
labelDim= {0}
|
||||
'''.format(num_of_classes)
|
||||
if map_file:
|
||||
template += '''
|
||||
template += '''\
|
||||
labelMappingFile= "{0}"
|
||||
'''.format(map_file)
|
||||
|
||||
template += '''
|
||||
]
|
||||
'''
|
||||
'''
|
||||
|
||||
template += '''
|
||||
template += '''\
|
||||
]
|
||||
'''
|
||||
'''
|
||||
|
||||
return template % self
|
||||
|
||||
|
||||
class CNTKTextFormatReader(AbstractReader):
|
||||
|
||||
"""This is the reader class the maps to CNTKTextFormatReader of CNTK
|
||||
|
@ -128,7 +133,9 @@ class CNTKTextFormatReader(AbstractReader):
|
|||
def generate_config(self):
|
||||
"""Generate the reader configuration block
|
||||
"""
|
||||
template = ''' reader = [
|
||||
template = '''
|
||||
reader = [
|
||||
traceLevel = 2
|
||||
readerType = "%(ReaderType)s"
|
||||
file = "%(FileName)s"
|
||||
'''
|
||||
|
@ -162,9 +169,9 @@ class CNTKTextFormatReader(AbstractReader):
|
|||
'''
|
||||
return template % self
|
||||
|
||||
def NumPyReader(data, filename):
|
||||
#TODO: get rid of this
|
||||
|
||||
def NumPyReader(data, filename):
|
||||
# TODO: get rid of this
|
||||
"""
|
||||
This is a factory that wraps Python arrays with a UCIFastReader.
|
||||
"""
|
||||
|
@ -181,4 +188,3 @@ def NumPyReader(data, filename):
|
|||
np.savetxt(filename, data, delimiter=' ', newline='\r\n', fmt=format_str)
|
||||
|
||||
return UCIFastReader(filename)
|
||||
|
||||
|
|
|
@ -6,13 +6,22 @@ deviceId=%(DevideId)s
|
|||
|
||||
Eval=[
|
||||
action="write"
|
||||
nodeUnitTest=%(NodeUnitTest)s
|
||||
run=BrainScriptNetworkBuilder
|
||||
|
||||
BrainScriptNetworkBuilder=[
|
||||
%(ModelDescription)s
|
||||
%(ModelDescription)s
|
||||
]
|
||||
|
||||
%(Reader)s
|
||||
%(Reader)s
|
||||
|
||||
|
||||
format = [
|
||||
# %%x = shape, %%d = sequenceId
|
||||
sequencePrologue=%%d\t|w.shape %%x\n%%d\t|w\s
|
||||
sampleSeparator=\n%%d\t|w\s
|
||||
elementSeparator=\s
|
||||
]
|
||||
|
||||
outputPath = "%(OutputFile)s"
|
||||
]
|
||||
|
|
|
@ -9,7 +9,7 @@ deviceId=%(DevideId)s
|
|||
Predict=[
|
||||
action="write"
|
||||
|
||||
%(Reader)s
|
||||
%(Reader)s
|
||||
|
||||
outputPath = "%(PredictOutputFile)s" # dump the output as text
|
||||
]
|
||||
|
|
|
@ -9,7 +9,7 @@ deviceId=%(DevideId)s
|
|||
Test=[
|
||||
action="test"
|
||||
|
||||
%(Reader)s
|
||||
%(Reader)s
|
||||
]
|
||||
|
||||
|
||||
|
|
|
@ -11,13 +11,13 @@ Train=[
|
|||
run=BrainScriptNetworkBuilder
|
||||
|
||||
BrainScriptNetworkBuilder=[
|
||||
%(ModelDescription)s
|
||||
%(ModelDescription)s
|
||||
]
|
||||
|
||||
SGD = [
|
||||
%(SGD)s
|
||||
%(SGD)s
|
||||
]
|
||||
|
||||
%(Reader)s
|
||||
%(Reader)s
|
||||
]
|
||||
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
import numpy as np
|
||||
from ..context import *
|
||||
|
||||
def test_parse_shapes():
|
||||
|
||||
def test_parse_shapes_1():
|
||||
output = '''\
|
||||
FormNestedNetwork: WARNING: Was called twice for v3 Plus operation
|
||||
|
||||
|
@ -25,12 +27,55 @@ Post-processing network complete.
|
|||
'''
|
||||
|
||||
expected = {
|
||||
'dummy_node':(2,),
|
||||
'v0':(4,1),
|
||||
'v1':(2,2),
|
||||
'v2':(1,1),
|
||||
'v3':(2,2)
|
||||
'dummy_node': (2, np.NaN),
|
||||
'v0': (4, 1),
|
||||
'v1': (2, 2),
|
||||
'v2': (1, 1),
|
||||
'v3': (2, 2)
|
||||
}
|
||||
|
||||
assert Context._parse_shapes_from_output(output) == expected
|
||||
|
||||
def test_parse_shapes_2():
|
||||
output = '''\
|
||||
Validating --> v1 = LearnableParameter() : -> [3 x 2 {1,3}]
|
||||
Validating --> v2 = InputValue() : -> [2 {1} x *]
|
||||
Validating --> v3 = Times (v1, v2) : [3 x 2 {1,3}], [2 {1} x *] -> [3 {1} x *]
|
||||
Validating --> v4 = LearnableParameter() : -> [3 x 1 {1,3}]
|
||||
Validating --> v5 = Plus (v3, v4) : [3 {1} x *], [3 x 1 {1,3}] -> [3 x 1 {1,3} x *]
|
||||
'''
|
||||
|
||||
expected = {
|
||||
'v1': (3, 2),
|
||||
'v2': (2, np.NaN),
|
||||
'v3': (3, np.NaN),
|
||||
'v4': (3, 1),
|
||||
'v5': (3, 1, np.NaN),
|
||||
}
|
||||
|
||||
assert Context._parse_shapes_from_output(output) == expected
|
||||
|
||||
def test_parse_eval_result_output_1():
|
||||
output = '''\
|
||||
0 |w.shape 1 1
|
||||
0 |w 60.000000
|
||||
1 |w.shape 1 2
|
||||
1 |w 22.000000
|
||||
1 |w 24.000000'''
|
||||
list_of_tensors = Context._parse_result_output(output)
|
||||
expected = [[[60]], [[22],[24]]]
|
||||
assert len(list_of_tensors) == len(expected)
|
||||
for res, exp in zip(list_of_tensors, expected):
|
||||
assert np.allclose(res, np.asarray(exp))
|
||||
|
||||
|
||||
def test_parse_test_result_output():
|
||||
output = '''\
|
||||
Final Results: Minibatch[1-1]: SamplesSeen = 500 v8: SquareError/Sample = 13.779223 v7: CrossEntropyWithSoftmax/Sample = 0.20016696 Perplexity = 1.2216067 '''
|
||||
result = Context._parse_test_result(output)
|
||||
|
||||
assert result['SamplesSeen'] == 500
|
||||
assert result['Perplexity'] == 1.2216067
|
||||
assert result['v8'] == 13.779223
|
||||
assert result['v7'] == 0.20016696
|
||||
assert len(result) == 4
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
from ..context import get_new_context, _CONTEXT
|
||||
from ..graph import *
|
||||
from ..graph import _seq_to_text_format
|
||||
from ..graph import _tensor_to_text_format
|
||||
|
||||
import pytest
|
||||
|
||||
|
@ -52,93 +52,91 @@ def test_overload_exception():
|
|||
C(range(0, 10))[0:3:2]
|
||||
|
||||
|
||||
@pytest.mark.parametrize("root_node, expected", [
|
||||
(C(2, var_name='c0'), "c0 = Constant(2, rows=1, cols=1)"),
|
||||
# Input should behave as Constant in case of scalars
|
||||
(I([1,2], var_name='i1'), "i1 = Input(2:1, tag='feature')"),
|
||||
(Plus(C(0), C(1)),
|
||||
"v0 = Constant(0, rows=1, cols=1)\nv1 = Constant(1, rows=1, cols=1)\nv2 = Plus(v0, v1)"),
|
||||
])
|
||||
def test_description(root_node, expected):
|
||||
description, has_inputs, readers = root_node.to_config()
|
||||
assert description == expected
|
||||
def _to_list(desc):
|
||||
return [line.strip() for line in desc.split('\n')]
|
||||
|
||||
|
||||
def test_graph_with_same_node_twice():
|
||||
v0 = C(1)
|
||||
root_node = Plus(v0, v0)
|
||||
expected = 'v0 = Constant(1, rows=1, cols=1)\nv1 = Plus(v0, v0)'
|
||||
description, has_inputs, readers = root_node.to_config()
|
||||
assert description == expected
|
||||
assert readers == []
|
||||
assert len(_to_list(description)) == 2
|
||||
|
||||
@pytest.mark.parametrize("alias, data, expected", [
|
||||
('', [A([1,0]), A([0,0,1,0])], ValueError), # no alias given
|
||||
('A', [object()], ValueError),
|
||||
])
|
||||
def test_sequence_conversion_exceptions(alias, data, expected):
|
||||
|
||||
@pytest.mark.parametrize("alias, idx, data, expected", [
|
||||
('', 0, [A([1, 0]), A([0, 0, 1, 0])], ValueError), # no alias given
|
||||
('A', 0, [object()], ValueError),
|
||||
])
|
||||
def test_tensor_conversion_exceptions(alias, idx, data, expected):
|
||||
with pytest.raises(expected):
|
||||
_seq_to_text_format(data, alias=alias)
|
||||
_tensor_to_text_format(idx, alias, data)
|
||||
|
||||
def test_constant_var_name():
|
||||
var_name = 'NODE'
|
||||
node = C([A([])], var_name=var_name)
|
||||
assert node.var_name == var_name
|
||||
|
||||
@pytest.mark.parametrize("alias, data, expected", [
|
||||
('W', [A([])], """\
|
||||
0|W \
|
||||
@pytest.mark.parametrize("alias, idx, data, expected", [
|
||||
('W', 0, A([]), "0 |W "),
|
||||
('W', 0, A([[1, 0, 0, 0], [0, 0, 1, 0]]), """\
|
||||
0 |W 1 0 0 0 0 0 1 0\
|
||||
"""),
|
||||
('W', [A([1,0]), A([0,0,1,0])], """\
|
||||
0|W 1 0
|
||||
1|W 0 0 1 0\
|
||||
"""),
|
||||
])
|
||||
def test_sequence_conversion_dense(alias, data, expected):
|
||||
assert _seq_to_text_format(data, alias=alias) == expected
|
||||
])
|
||||
def test_tensor_conversion_dense(alias, idx, data, expected):
|
||||
assert _tensor_to_text_format(idx, alias, data,
|
||||
has_sequence_dimension=False) == expected
|
||||
|
||||
if False:
|
||||
@pytest.mark.parametrize("alias, data, expected", [
|
||||
('W', [A({})], """\
|
||||
0|W \
|
||||
"""),
|
||||
('W', [{3:1, 50:1, 2:0}, {1:-5}], """\
|
||||
0|W 2:0 3:1 50:1
|
||||
1|W 1:-5\
|
||||
('W', [A({})], ""),
|
||||
('W', [{3: 1, 50: 1, 2: 0}, {1: -5}], """\
|
||||
0 |W 2:0 3:1 50:1
|
||||
1 |W 1:-5\
|
||||
"""),
|
||||
])
|
||||
def test_sequence_conversion_sparse(alias, data, expected):
|
||||
def test_tensor_conversion_sparse(alias, data, expected):
|
||||
# We use the dictionary in data to create a SciPy sparse dictionary of
|
||||
# keys, which we then feed to the converter.
|
||||
dok_data = []
|
||||
for data_elem in data:
|
||||
d = scipy.sparse.dok_matrix((100,1))
|
||||
for k,v in data_elem.items():
|
||||
for idx, data_elem in enumerate(data):
|
||||
d = scipy.sparse.dok_matrix((100, 1))
|
||||
for k, v in data_elem.items():
|
||||
d[k] = v
|
||||
dok_data.append(d)
|
||||
assert _seq_to_text_format(dok_data, alias=alias) == expected
|
||||
assert _tensor_to_text_format(idx, alias, dok_data) == expected
|
||||
|
||||
|
||||
@pytest.mark.parametrize("data, expected", [
|
||||
([], True),
|
||||
([1], True),
|
||||
([[1,2]], True),
|
||||
([[1, 2]], True),
|
||||
([[]], True),
|
||||
([[A([1,2])]], False),
|
||||
([A([1,2])], False),
|
||||
([A([1,2]), A([])], False),
|
||||
])
|
||||
([[A([1, 2])]], False),
|
||||
([A([1, 2])], False),
|
||||
([A([1, 2]), A([])], False),
|
||||
])
|
||||
def test_is_tensor(data, expected):
|
||||
#import ipdb;ipdb.set_trace()
|
||||
assert is_tensor(data) == expected
|
||||
|
||||
|
||||
@pytest.mark.parametrize("data, expected", [
|
||||
([], False),
|
||||
([1], False),
|
||||
([[1,2]], False),
|
||||
([[1, 2]], False),
|
||||
([[]], False),
|
||||
([[A([1,2])]], False),
|
||||
([A([1,2])], True),
|
||||
([A([1,2]), A([])], True),
|
||||
])
|
||||
def test_is_sequence(data, expected):
|
||||
assert is_sequence(data) == expected
|
||||
([[A([1, 2])]], False),
|
||||
([A([1, 2])], True),
|
||||
([A([1, 2]), A([])], True),
|
||||
])
|
||||
def test_is_tensor_list(data, expected):
|
||||
assert is_tensor_list(data) == expected
|
||||
|
||||
def test_loose_coupling():
|
||||
from cntk.ops.cntk1 import PastValue
|
||||
dh = PastValue(1, 'outnode')
|
||||
out = Times(dh, Constant(2), var_name='outnode')
|
||||
|
||||
expected = ['v0 = PastValue(1, outnode, timeStep=1, defaultHiddenActivation=0.1)',
|
||||
'v1 = Constant(2, rows=1, cols=1)',
|
||||
'outnode = Times(v0, v1, outputRank=1)']
|
||||
|
||||
description, has_inputs, readers = out.to_config()
|
||||
assert _to_list(description) == expected
|
||||
|
||||
|
||||
|
|
|
@ -9,76 +9,84 @@ from ..reader import *
|
|||
# keeping things short
|
||||
C = constant
|
||||
I = input
|
||||
AA = np.asarray
|
||||
|
||||
def _test(root_node, expected, clean_up=True):
|
||||
with get_new_context() as ctx:
|
||||
ctx.clean_up = clean_up
|
||||
assert not ctx.input_nodes
|
||||
result = ctx.eval(root_node)
|
||||
expected = np.asarray(expected)
|
||||
assert result.shape == expected.shape or result.shape == (1,1) and expected.shape==()
|
||||
assert np.all(result == expected)
|
||||
|
||||
@pytest.mark.parametrize('root_node, expected', [
|
||||
# __add__ / __radd__
|
||||
(C(0) + C(1), 1),
|
||||
(C(0) + 1, 1),
|
||||
(0 + C(1), 1),
|
||||
assert len(result) == len(expected)
|
||||
for res, exp in zip(result, expected):
|
||||
assert np.allclose(res, exp)
|
||||
assert res.shape == AA(exp).shape
|
||||
|
||||
# __sub__ / __rsub__
|
||||
(C(0) - C(1), -1),
|
||||
(C(0) - 1, -1),
|
||||
(0 - C(1), -1),
|
||||
#C_VALUES = [0, [[1, 2], [3, 4]], [10.1, -20.2], 1.1]
|
||||
C_VALUES = [0, [[1, 2], [3, 4]]]
|
||||
|
||||
# __mul__ / __rmul__ --> element-wise (!) multiplication
|
||||
(C(0) * C(1), 0),
|
||||
(C(0) * 1, 0),
|
||||
(0 * C(1), 0),
|
||||
@pytest.fixture(scope="module", params=C_VALUES)
|
||||
def c_arg(request):
|
||||
return request.param
|
||||
|
||||
# chaining
|
||||
(C(2) * C(3) + C(1.2), 7.2),
|
||||
(C(2) * (C(3) + C(1.2)), 8.4),
|
||||
c_left_arg = c_arg
|
||||
c_right_arg = c_arg
|
||||
|
||||
# normal ops
|
||||
if False:
|
||||
def test_op_add_constant(c_left_arg, c_right_arg):
|
||||
expected = [AA(c_left_arg) + AA(c_right_arg)]
|
||||
_test(C(c_left_arg) + c_right_arg, expected, False)
|
||||
_test(C(c_left_arg) + C(c_right_arg), expected)
|
||||
_test(c_left_arg + C(c_right_arg), expected)
|
||||
_test(c_left_arg + C(c_left_arg) + c_right_arg, c_left_arg+expected)
|
||||
|
||||
(C(np.ones((2,3))*3), [[3,3,3], [3,3,3]]),
|
||||
(C(np.ones((2,3))*3)+np.vstack([np.ones(3), np.ones(3)+1]), [[4,4,4], [5,5,5]]),
|
||||
(C(np.ones((2,3))*3)*np.vstack([np.ones(3), np.ones(3)+1]), [[3,3,3], [6,6,6]]),
|
||||
def test_op_minus_constant(c_left_arg, c_right_arg):
|
||||
expected = [AA(c_left_arg) - AA(c_right_arg)]
|
||||
_test(C(c_left_arg) - c_right_arg, expected)
|
||||
_test(C(c_left_arg) - C(c_right_arg), expected)
|
||||
_test(c_left_arg - C(c_right_arg), expected)
|
||||
_test(c_left_arg - C(c_left_arg) + c_right_arg, c_left_arg-expected)
|
||||
|
||||
# special treatment of inputs in RowStack
|
||||
# (RowStack((C(1), C(2))), [[1],[2]]), # TODO figure out the real semantic
|
||||
# of RowStack
|
||||
def test_op_times_constant(c_left_arg, c_right_arg):
|
||||
expected = [AA(c_left_arg) * AA(c_right_arg)]
|
||||
_test(C(c_left_arg) * c_right_arg, expected)
|
||||
_test(C(c_left_arg) * C(c_right_arg), expected)
|
||||
_test(c_left_arg * C(c_right_arg), expected)
|
||||
|
||||
# the following test fails because Constant() ignores the cols parameter
|
||||
#(RowStack((C(1, rows=2, cols=2), C(2, rows=2, cols=2))), [[1,1,2,2], [1,1,2,2]])
|
||||
# Testing inputs
|
||||
|
||||
# __abs__
|
||||
# uncomennt, once Abs() as ComputationNode is moved from standard function
|
||||
# to ComputationNode
|
||||
(abs(C(-3)), 3),
|
||||
(abs(C(3)), 3),
|
||||
(abs(C([[-1,2],[50,-0]])), [[1,2],[50,0]]),
|
||||
@pytest.mark.parametrize("left_arg, right_arg", [
|
||||
([30], [10]),
|
||||
([[30]], [[10]]),
|
||||
([[1.5,2.1]], [[10,20]]),
|
||||
# Adding two 3x2 inputs of sequence length 1
|
||||
([[30,40], [1,2], [0.1, 0.2]], [[10,20], [3,4], [-0.5, -0.4]]),
|
||||
([5], [[30,40], [1,2]]),
|
||||
])
|
||||
def test_op_add_input_constant(left_arg, right_arg):
|
||||
expected = AA(left_arg) + AA(right_arg)
|
||||
# sequence of 1 element, since we have has_sequence_dimension=False
|
||||
expected = [expected]
|
||||
# batch of one sample
|
||||
expected = [expected]
|
||||
_test(I([left_arg], has_sequence_dimension=False) + right_arg, expected, False)
|
||||
_test(left_arg + I([right_arg], has_sequence_dimension=False), expected, False)
|
||||
|
||||
# more complex stuff
|
||||
#(Plus(C(5), 3), 8),
|
||||
])
|
||||
def test_overload_eval(root_node, expected):
|
||||
_test(root_node, expected)
|
||||
@pytest.mark.parametrize("left_arg, right_arg", [
|
||||
([
|
||||
[[30]], # 1st element has (1,) sequence of length 1
|
||||
[[11],[12]] # 2nd element has (1,) sequence of length 2
|
||||
] ,
|
||||
2),
|
||||
([
|
||||
[[33,22]], # 1st element has (1x2) sequence of length 1
|
||||
[[11,12], [1.1,2.2]] # 2nd element has (1x2) sequence of length 2
|
||||
],
|
||||
2),
|
||||
])
|
||||
|
||||
@pytest.mark.parametrize('root_node, expected', [
|
||||
# __add__ / __radd__
|
||||
(C(np.asarray([1,2]))+0, [1,2]),
|
||||
(C(np.asarray([1,2]))+.1, [1.1,2.1]),
|
||||
(.1+C(np.asarray([1,2])), [1.1,2.1]),
|
||||
(C(np.asarray([1,2]))*0, [0,0]),
|
||||
(C(np.asarray([1,2]))*.1, [0.1,0.2]),
|
||||
(.1*C(np.asarray([1,2])), [0.1,0.2]),
|
||||
(C(np.asarray([[1,2],[3,4]]))+.1, [[1.1,2.1],[3.1,4.1]]),
|
||||
(C(np.asarray([[1,2],[3,4]]))*2, [[2,4],[6,8]]),
|
||||
(2*C(np.asarray([[1,2],[3,4]])), [[2,4],[6,8]]),
|
||||
(2*C(np.asarray([[1,2],[3,4]]))+100, [[102,104],[106,108]]),
|
||||
(C(np.asarray([[1,2],[3,4]]))*C(np.asarray([[1,2],[3,4]])), [[1,4],[9,16]]),
|
||||
])
|
||||
def test_ops_on_numpy(root_node, expected, tmpdir):
|
||||
_test(root_node, expected, clean_up=True)
|
||||
def test_op_mul_input_seq(left_arg, right_arg):
|
||||
expected = [AA(elem)*right_arg for elem in left_arg]
|
||||
result = I(left_arg, has_sequence_dimension=True) * right_arg
|
||||
_test(result, expected, False)
|
||||
|
||||
|
|
|
@ -4,22 +4,23 @@ import pytest
|
|||
from ..reader import *
|
||||
from ..graph import *
|
||||
from ..context import *
|
||||
from .. import cntk1_ops
|
||||
from ..ops import cntk1 as cntk1_ops
|
||||
|
||||
allclose = np.testing.assert_allclose
|
||||
|
||||
|
||||
def test_NumPyReader(tmpdir):
|
||||
data = [[1, 2], [3, 4]]
|
||||
fn = str(tmpdir / 'test.txt')
|
||||
reader = NumPyReader(data, fn)
|
||||
|
||||
input_node = cntk1_ops.Input(2, var_name='testInput')
|
||||
reader.add_input(input_node, 0,2)
|
||||
reader.add_input(input_node, 0, 2)
|
||||
out = input_node + 2
|
||||
|
||||
with get_new_context() as ctx:
|
||||
result = ctx.eval(out, reader)
|
||||
assert np.all(result == np.asarray(data)+2)
|
||||
for r, d in zip(result, data):
|
||||
assert np.all(r== np.asarray(d) + 2)
|
||||
|
||||
# TODO test other readers
|
||||
|
||||
|
|
|
@ -5,3 +5,51 @@ if "CNTK_EXECUTABLE_PATH" not in os.environ:
|
|||
"you need to point environmental variable 'CNTK_EXECUTABLE_PATH' to the CNTK binary")
|
||||
|
||||
CNTK_EXECUTABLE_PATH = os.environ['CNTK_EXECUTABLE_PATH']
|
||||
|
||||
# Indent model description by how many spaces
|
||||
MODEL_INDENTATION = 8
|
||||
|
||||
|
||||
def numpy_to_cntk_shape(shape):
|
||||
'''
|
||||
Converting the NumPy shape (row major) to CNTK shape (column major).
|
||||
|
||||
:param shape: NumPy shape tuple
|
||||
|
||||
Returns a tuple that can be ':'.join()ed to a CNTK dimension.
|
||||
'''
|
||||
if not shape:
|
||||
# in case of a scalar
|
||||
return (1,)
|
||||
|
||||
return tuple(reversed(shape))
|
||||
|
||||
def cntk_to_numpy_shape(shape):
|
||||
'''
|
||||
Converts col-major to row-major and removes the sequence dimension.
|
||||
|
||||
:param shape: CNTK shape iterable
|
||||
|
||||
Returns a tuple that describes the NumPy shape of a tensor
|
||||
'''
|
||||
|
||||
shape = tuple(int(s) for s in reversed(shape))
|
||||
|
||||
shape = shape[1:]
|
||||
if not shape:
|
||||
shape = (1,)
|
||||
|
||||
return shape
|
||||
|
||||
def dedupe_readers(readers):
|
||||
import copy
|
||||
readers_map = {}
|
||||
for r in readers:
|
||||
filename = r['FileName']
|
||||
if filename in readers_map:
|
||||
readers_map[filename].inputs_def.extend(r.inputs_def)
|
||||
else:
|
||||
readers_map[filename] = copy.deepcopy(r)
|
||||
|
||||
return [r for r in readers_map.values()]
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче