public Mapper(IHostEnvironment env, TensorFlowTransform parent, ISchema inputSchema) { Contracts.CheckValue(env, nameof(env)); _host = env.Register(nameof(Mapper)); _host.CheckValue(inputSchema, nameof(inputSchema)); _host.CheckValue(parent, nameof(parent)); _parent = parent; _schema = inputSchema; _inputColIndices = new int[_parent.Inputs.Length]; _isInputVector = new bool[_parent.Inputs.Length]; _fullySpecifiedShapes = new TFShape[_parent.Inputs.Length]; for (int i = 0; i < _parent.Inputs.Length; i++) { if (!inputSchema.TryGetColumnIndex(_parent.Inputs[i], out _inputColIndices[i])) { throw _host.Except($"Column {_parent.Inputs[i]} doesn't exist"); } var type = inputSchema.GetColumnType(_inputColIndices[i]); _isInputVector[i] = type.IsVector; var expectedType = TensorFlowUtils.Tf2MlNetType(_parent.TFInputTypes[i]); if (type.ItemType != expectedType) { throw _host.ExceptSchemaMismatch(nameof(inputSchema), "input", _parent.Inputs[i], expectedType.ToString(), type.ToString()); } var originalShape = _parent.TFInputShapes[i]; var shape = originalShape.ToIntArray(); var colTypeDims = Enumerable.Range(0, type.AsVector.DimCount + 1).Select(d => d == 0 ? 1 : (long)type.AsVector.GetDim(d - 1)).ToArray(); if (shape == null) { _fullySpecifiedShapes[i] = new TFShape(colTypeDims); } else if (type.AsVector.DimCount == 1) { // If the column is one dimension we make sure that the total size of the TF shape matches. // Compute the total size of the known dimensions of the shape. int valCount = shape.Where(x => x > 0).Aggregate((x, y) => x * y); // The column length should be divisible by this, so that the other dimensions can be integral. if (type.ValueCount % valCount != 0) { throw Contracts.Except($"Input shape mismatch: Input '{_parent.Inputs[i]}' has shape {originalShape.ToString()}, but input data is of length {type.ValueCount}."); } // If the shape is multi-dimensional, we should be able to create the length of the vector by plugging // in a single value for the unknown shapes. E.g., if the shape is [?,?,3], then there should exist a value // d such that d*d*3 is equal to the length of the input column. var d = originalShape.NumDimensions > 2 ? Math.Pow(type.ValueCount / valCount, 1.0 / (originalShape.NumDimensions - 2)) : 1; if (originalShape.NumDimensions > 2 && d - (int)d != 0) { throw Contracts.Except($"Input shape mismatch: Input '{_parent.Inputs[i]}' has shape {originalShape.ToString()}, but input data is of length {type.ValueCount}."); } // Fill in the unknown dimensions. var l = new long[originalShape.NumDimensions]; for (int ishape = 0; ishape < originalShape.NumDimensions; ishape++) { l[ishape] = originalShape[ishape] == -1 ? (int)d : originalShape[ishape]; } _fullySpecifiedShapes[i] = new TFShape(l); } else { if (shape.Select((dim, j) => dim != -1 && dim != colTypeDims[j]).Any(b => b)) { throw Contracts.Except($"Input shape mismatch: Input '{_parent.Inputs[i]}' has shape {originalShape.ToString()}, but input data is {type.AsVector.ToString()}."); } // Fill in the unknown dimensions. var l = new long[originalShape.NumDimensions]; for (int ishape = 0; ishape < originalShape.NumDimensions; ishape++) { l[ishape] = originalShape[ishape] == -1 ? colTypeDims[ishape] : originalShape[ishape]; } _fullySpecifiedShapes[i] = new TFShape(l); } } }
private ITensorValueGetter CreateTensorValueGetter <T>(IRow input, bool isVector, int colIndex, TFShape tfShape) { if (isVector) { return(new TensorValueGetterVec <T>(input, colIndex, tfShape)); } else { return(new TensorValueGetter <T>(input, colIndex)); } }
/// <summary> /// Creates a new tensor from a portion of an array of bytes /// </summary> /// <param name="shape">Represents the tensor shape.</param> /// <param name="data">The linear array of data, the data is shuffled to fit in the tensor with the specified dimensions.</param> /// <param name="start">The offset into the provided data array where the data resides.</param> /// <param name="count">The number of bytes to copy from count into the tensor.</param> /// <remarks> /// Use the FromBuffer method to create a tensor that has the specified dimensions /// and is initialized with data from the data array. The data is copied starting /// at the start offset, for count bytes and is laid out into the tensor following the /// specified dimensions. /// </remarks> public static TFTensor FromBuffer(TFShape shape, byte [] data, int start, int count) { return(new TFTensor(SetupTensor(TFDataType.UInt8, shape, data, start, count, size: 1))); }
private TensorFlowTransform(IHostEnvironment env, TFSession session, string[] inputs, string[] outputs) { Contracts.CheckValue(env, nameof(env)); _host = env.Register(nameof(RegistrationName)); _host.CheckValue(session, nameof(session)); _host.CheckNonEmpty(inputs, nameof(inputs)); _host.CheckNonEmpty(outputs, nameof(outputs)); Session = session; foreach (var input in inputs) { _host.CheckNonWhiteSpace(input, nameof(inputs)); if (Session.Graph[input] == null) { throw _host.ExceptParam(nameof(inputs), $"Input column '{input}' does not exist in the model"); } var tfInput = new TFOutput(Session.Graph[input]); if (!TensorFlowUtils.IsTypeSupported(tfInput.OutputType)) { throw _host.ExceptParam(nameof(session), $"Input type '{tfInput.OutputType}' of input column '{input}' is not supported in TensorFlow"); } } var newNames = new HashSet <string>(); foreach (var output in outputs) { _host.CheckNonWhiteSpace(output, nameof(outputs)); if (!newNames.Add(output)) { throw _host.ExceptParam(nameof(outputs), $"Output column '{output}' specified multiple times"); } if (Session.Graph[output] == null) { throw _host.ExceptParam(nameof(outputs), $"Output column '{output}' does not exist in the model"); } } Inputs = inputs; TFInputTypes = new TFDataType[Inputs.Length]; TFInputShapes = new TFShape[Inputs.Length]; for (int i = 0; i < Inputs.Length; i++) { var tfInput = new TFOutput(Graph[Inputs[i]]); TFInputTypes[i] = tfInput.OutputType; TFInputShapes[i] = Graph.GetTensorShape(tfInput); if (TFInputShapes[i].NumDimensions != -1) { var newShape = new long[TFInputShapes[i].NumDimensions]; newShape[0] = TFInputShapes[i][0] == -1 ? BatchSize : TFInputShapes[i][0]; for (int j = 1; j < TFInputShapes[i].NumDimensions; j++) { newShape[j] = TFInputShapes[i][j]; } TFInputShapes[i] = new TFShape(newShape); } } Outputs = outputs; OutputTypes = new ColumnType[Outputs.Length]; TFOutputTypes = new TFDataType[Outputs.Length]; for (int i = 0; i < Outputs.Length; i++) { var tfOutput = new TFOutput(Graph[Outputs[i]]); var shape = Graph.GetTensorShape(tfOutput); int[] dims = shape.NumDimensions > 0 ? shape.ToIntArray().Skip(shape[0] == -1 ? BatchSize : 0).ToArray() : new[] { 0 }; var type = TensorFlowUtils.Tf2MlNetType(tfOutput.OutputType); OutputTypes[i] = new VectorType(type, dims); TFOutputTypes[i] = tfOutput.OutputType; } }
/// <summary> /// Creates a new tensor from a portion of an array of Complex numbers /// </summary> /// <param name="shape">Represents the tensor shape.</param> /// <param name="data">The linear array of data, the data is shuffled to fit in the tensor with the specified dimensions.</param> /// <param name="start">The offset into the provided data array where the data resides.</param> /// <param name="count">The number of bytes to copy from count into the tensor.</param> /// <remarks> /// Use the FromBuffer method to create a tensor that has the specified dimensions /// and is initialized with data from the data array. The data is copied starting /// at the start offset, for count bytes and is laid out into the tensor following the /// specified dimensions. /// </remarks> public static TFTensor FromBuffer(TFShape shape, Complex [] data, int start, int count) { return(new TFTensor(SetupTensor(TFDataType.Complex128, shape, data, start, count, size: 16))); }
/// <summary> /// Creates a new tensor from a portion of an array of longs /// </summary> /// <param name="shape">Represents the tensor shape.</param> /// <param name="data">The linear array of data, the data is shuffled to fit in the tensor with the specified dimensions.</param> /// <param name="start">The offset into the provided data array where the data resides.</param> /// <param name="count">The number of bytes to copy from count into the tensor.</param> /// <remarks> /// Use the FromBuffer method to create a tensor that has the specified dimensions /// and is initialized with data from the data array. The data is copied starting /// at the start offset, for count bytes and is laid out into the tensor following the /// specified dimensions. /// </remarks> public static TFTensor FromBuffer(TFShape shape, long [] data, int start, int count) { return(new TFTensor(SetupTensor(TFDataType.Int64, shape, data, start, count, size: 8))); }
/// <summary> /// Creates a new tensor from a portion of an array of floats /// </summary> /// <param name="shape">Represents the tensor shape.</param> /// <param name="data">The linear array of data, the data is shuffled to fit in the tensor with the specified dimensions.</param> /// <param name="start">The offset into the provided data array where the data resides.</param> /// <param name="count">The number of bytes to copy from count into the tensor.</param> /// <remarks> /// Use the FromBuffer method to create a tensor that has the specified dimensions /// and is initialized with data from the data array. The data is copied starting /// at the start offset, for count bytes and is laid out into the tensor following the /// specified dimensions. /// </remarks> public static TFTensor FromBuffer(TFShape shape, float [] data, int start, int count) { return(new TFTensor(SetupTensor(TFDataType.Float, shape, data, start, count, size: 4))); }
private ITensorValueGetter CreateTensorValueGetter(IRow input, TFDataType tfType, bool isVector, int colIndex, TFShape tfShape) { var type = TFTensor.TypeFromTensorType(tfType); _host.AssertValue(type); return(Utils.MarshalInvoke(CreateTensorValueGetter <int>, type, input, isVector, colIndex, tfShape)); }
/// <summary> /// Compiles the initialization function /// </summary> /// <param name="graph">Tensorflow graph to use for creating the initialization function</param> /// <param name="shape">The shape of the variable to initialize</param> /// <returns>Returns the compiled initialization function</returns> public override TFOutput Compile(TFGraph graph, TFShape shape) { return(graph.Zeros(shape)); }