Integrate blis/pythonapi-vnext-merge into master

This commit is contained in:
Project Philly 2016-04-06 07:11:23 -07:00
Родитель 17377d845d 4bdbf79c1c
Коммит 7cf42393dd
24 изменённых файлов: 2794 добавлений и 1614 удалений

Просмотреть файл

@ -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()]