// The value represents a n-dimensional tensor with 2 dynamic axes: sequence and batch // It assumes that only the highest 2 axes are dynamic, and all the other axes are static. public static void CopyTo <T>(this Value value, Variable variable, List <List <T> > data) { if ((value.GetDataType() == DataType.Float) && (!typeof(T).Equals(typeof(float))) || (value.GetDataType() == DataType.Double) && (!typeof(T).Equals(typeof(double)))) { throw new ArgumentException("The value type does not match the list type."); } // Todo: how to check whether the dynamic axes are the highest 2 axes in the shape. if (variable.DynamicAxes().Count != 2) { throw new ArgumentException("The variable should have 2 dynamic axes."); } var variableShape = variable.Shape; var valueShape = value.Shape; if (variableShape != value.Shape.SubShape(0, valueShape.Rank - 2)) { throw new ArgumentException("The variable and value does not have same shape."); } // Todo: transform sparse to dense // Currently only for dense if ((value.GetStorageFormat() != StorageFormat.Dense)) { throw new ArgumentException("The value is not in denst format."); } var outputNDArrayView = value.Data(); var outputShape = outputNDArrayView.Shape(); var outputShapeRank = outputShape.Rank; var numOfElementsInSample = variableShape.TotalSize; var numOfSamplesInSequence = outputShape.GetDimensionSize(outputShapeRank - 2); var numOfSequences = outputShape.GetDimensionSize(outputShapeRank - 1); // Copy the data from the output buffer. // Todo: directly access the data in output buffer? // Todo: need to map DataBuffer() to C# NDArrayView cpuOutputNDArrayView; uint numOfOutputData = outputNDArrayView.Shape().TotalSize; // Todo: consider mask. Debug.Assert(numOfElementsInSample * numOfSamplesInSequence * numOfSequences == numOfOutputData); T[] outputData = new T[numOfOutputData]; if (value.GetDataType() == DataType.Float) { cpuOutputNDArrayView = new NDArrayView(outputNDArrayView.Shape(), outputData as float[], numOfOutputData, DeviceDescriptor.CPUDevice); } else if (value.GetDataType() == DataType.Double) { cpuOutputNDArrayView = new NDArrayView(outputNDArrayView.Shape(), outputData as double[], numOfOutputData, DeviceDescriptor.CPUDevice); } else { throw new ArgumentException("The data type " + value.GetDataType().ToString() + " is not supported. Only float or double is supported by CNTK."); } cpuOutputNDArrayView.CopyFrom(outputNDArrayView); for (int seqIndex = 0, dataIndex = 0; seqIndex < numOfSequences; seqIndex++) { var seqData = new List <T>(); // Todo: consider mask // Todo: make it more efficient. for (int i = 0; i < numOfElementsInSample * numOfSamplesInSequence; i++) { seqData.Add(outputData[dataIndex++]); } data.Add(seqData); } }
// Copy Value to List<List<T>> for dense input // Todo: could this be a extension to Value class?? public void CopyValueTo <T>(string varName, Value value, List <List <T> > sequences) { // Todo: deal with GPUDevice. if (value.Device != DeviceDescriptor.CPUDevice) { throw new InvalidOperationException("Currently only CPU device is supported."); } if ((value.GetDataType() == DataType.Float) && (!typeof(T).Equals(typeof(float))) || (value.GetDataType() == DataType.Double) && (!typeof(T).Equals(typeof(double)))) { throw new InvalidDataException("The value type does not match the list type."); } // Todo: transform sparse to dense // Currently only for dense if ((value.GetStorageFormat() != StorageFormat.Dense)) { throw new InvalidDataException("The value is not in denst format."); } var variable = getVariableByName(varName); var outputNDArrayView = value.Data(); var outputShape = outputNDArrayView.Shape(); var varRank = variable.Shape.Rank; var valueRank = outputNDArrayView.Shape().Rank; Debug.Assert(varRank + 2 == valueRank); var numOfElementsInSample = variable.Shape.TotalSize; var numOfSamplesInSequence = outputShape.GetDimensionSize(varRank); var numOfSequences = outputShape.GetDimensionSize(varRank + 1); //var outputShape = outputVar.Shape().AppendShape(new NDShape(dynamicAxisShape)); // Copy the data from the output buffer. // Todo: directly access the data in output buffer? // Todo: need to map DataBuffer() to C# NDArrayView cpuOutputNDArrayView; uint numOfOutputData = outputNDArrayView.Shape().TotalSize; Debug.Assert(numOfElementsInSample * numOfSamplesInSequence * numOfSequences == numOfOutputData); T[] outputData = new T[numOfOutputData]; if (value.GetDataType() == DataType.Float) { cpuOutputNDArrayView = new NDArrayView(outputNDArrayView.Shape(), outputData as float[], numOfOutputData, DeviceDescriptor.CPUDevice); } else if (value.GetDataType() == DataType.Double) { cpuOutputNDArrayView = new NDArrayView(outputNDArrayView.Shape(), outputData as double[], numOfOutputData, DeviceDescriptor.CPUDevice); } else { throw new InvalidDataException("The data type " + value.GetDataType().ToString() + " is not supported. Only float or double is supported by CNTK."); } cpuOutputNDArrayView.CopyFrom(outputNDArrayView); for (int seqIndex = 0, dataIndex = 0; seqIndex < numOfSequences; seqIndex++) { var seqData = new List <T>(); // Todo: make it more efficient. for (int i = 0; i < numOfElementsInSample * numOfSamplesInSequence; i++) { seqData.Add(outputData[dataIndex++]); } sequences.Add(seqData); } }