| @@ -216,6 +216,204 @@ namespace Tensorflow | |||
| return tensor_proto; | |||
| } | |||
| public static TensorShape constant_value_as_shape(Tensor tensor) | |||
| { | |||
| bool hasattr(Graph property, string attr) | |||
| { | |||
| var t = property.GetType().GetProperties(); | |||
| foreach (System.Reflection.PropertyInfo pi in t) | |||
| { | |||
| if (pi.Name == attr) | |||
| return true; | |||
| } | |||
| return false; | |||
| } | |||
| if (tensor.GetType() == typeof(EagerTensor)) | |||
| { | |||
| int[] dims = {}; | |||
| foreach (int dim in tensor.numpy()) | |||
| if (dim != 1) | |||
| { | |||
| dims[dims.Length] = dim; | |||
| } else | |||
| { | |||
| // -1 == Unknown | |||
| dims[dims.Length] = -1; | |||
| } | |||
| return new TensorShape(dims); | |||
| } | |||
| if (tensor.TensorShape.ndim == 0) | |||
| { | |||
| var value_ = constant_value(tensor); | |||
| if (value_ == null) | |||
| throw new ValueError( | |||
| @"Received a scalar with unknown value as shape; require a statically | |||
| known scalar with value '-1' to describe an unknown shape."); | |||
| if (value_ != -1) | |||
| throw new ValueError( | |||
| String.Format(@"Received a scalar value {0} as shape; require a statically known | |||
| scalar with value '-1' to describe an unknown shape.", value_)); | |||
| return tensor.TensorShape.unknown_shape(-1); | |||
| } | |||
| var shape = tensor.TensorShape.with_rank(1); | |||
| if (shape == new TensorShape(new int[] {1})) | |||
| { | |||
| return new TensorShape(new int[] {}); | |||
| } else if (tensor.op.type == "Cast") | |||
| { | |||
| var pre_cast = constant_value_as_shape(tensor.op.inputs[0]); | |||
| if (pre_cast.dims == null) | |||
| return pre_cast; | |||
| var cast_dtype = dtypes.as_dtype((Type)tensor.op.get_attr("DstT")); | |||
| if (!Array.Exists(new [] {dtypes.int32, dtypes.int64}, cast_dtype_ => cast_dtype_ == cast_dtype)) | |||
| return tensor.TensorShape.unknown_shape(shape.dims[0]); | |||
| int[] x_ = {}; | |||
| foreach (var x in pre_cast.as_list()) | |||
| if (x != -1) | |||
| x_[x_.Length] = x; | |||
| else | |||
| x_[x_.Length] = -1; | |||
| var dest_dtype_shape_array = np.array(x_).astype(cast_dtype.as_numpy_dtype()); | |||
| int[] y_ = {}; | |||
| foreach(int y in dest_dtype_shape_array) | |||
| if (y >= 0) | |||
| y_[y_.Length] = y; | |||
| else | |||
| y_[y_.Length] = -1; | |||
| return new TensorShape(y_); | |||
| } else if (tensor.op.type == "Shape") | |||
| { | |||
| return tensor.op.inputs[0].shape; | |||
| } else if (tensor.op.type == "Pack") | |||
| { | |||
| var ret_ = new TensorShape(new int[] {}); | |||
| if ((int)tensor.op.get_attr("axis") != 0) | |||
| throw new ValueError(String.Format( | |||
| @"Since rank 1 inputs are expected, Pack's axis: {0} must be 0, otherwise it | |||
| would not be rank 1.", tensor.op.get_attr("axis"))); | |||
| foreach (Tensor pack_input in tensor.op.inputs) | |||
| { | |||
| var pack_input_val = constant_value(pack_input); | |||
| Dimension new_dim; | |||
| if (pack_input_val < 0) | |||
| { | |||
| new_dim = new Dimension(-1); | |||
| } else if (pack_input_val == null) | |||
| { | |||
| new_dim = new Dimension(-1); | |||
| } else | |||
| { | |||
| new_dim = new Dimension(pack_input_val); | |||
| } | |||
| ret_ = ret_.concatenate(new int[] {new_dim}); | |||
| } | |||
| return ret_; | |||
| } else if (tensor.op.type == "Concat") | |||
| { | |||
| var ret_ = new TensorShape(new int[] {}); | |||
| var inputlist_ = new ArraySegment<Tensor>(tensor.op.inputs, 1, | |||
| tensor.op.inputs.Length - 1); | |||
| foreach (var concat_input in inputlist_) | |||
| { | |||
| ret_ = ret_.concatenate(constant_value_as_shape(concat_input)); | |||
| } | |||
| return ret_; | |||
| } else if (tensor.op.type == "StridedSlice") | |||
| { | |||
| try | |||
| { | |||
| var begin = constant_value(tensor.op.inputs[1]); | |||
| var end = constant_value(tensor.op.inputs[2]); | |||
| var strides = constant_value(tensor.op.inputs[3]); | |||
| if (new [] {begin, end, strides}.All(x => x == null)) | |||
| { | |||
| begin = begin[0]; | |||
| end = end[0]; | |||
| strides = strides[0]; | |||
| var begin_mask = tensor.op.get_attr("begin_mask"); | |||
| if ((int)begin_mask == 1) | |||
| { | |||
| begin = null; | |||
| } | |||
| var end_mask = tensor.op.get_attr("end_mask"); | |||
| if ((int)end_mask == 1) | |||
| { | |||
| end = null; | |||
| } | |||
| var ellipsis_mask = tensor.op.get_attr("ellipsis_mask"); | |||
| var new_axis_mask = tensor.op.get_attr("new_axis_mask"); | |||
| var shrink_axis_mask = tensor.op.get_attr("shrink_axis_mask"); | |||
| bool valid_attributes; | |||
| if (!(bool)ellipsis_mask && !(bool)new_axis_mask && | |||
| !(bool)shrink_axis_mask && !((bool)begin_mask || (int)begin_mask == 1) && | |||
| !((bool)end_mask || (int)end_mask == 1)) | |||
| { | |||
| valid_attributes = true; | |||
| } else {valid_attributes = false;} | |||
| if (valid_attributes) | |||
| { | |||
| // sorry for the mess here, but this hacky solution was the best way | |||
| // i could come up with to implement the things done in python in c# | |||
| var prev_ = constant_value_as_shape(tensor.op.inputs[0]).dims; | |||
| var prev = prev_.Skip(begin).Take(end - begin).ToArray(); | |||
| // 100 being the comparison doesn't really matter here; it's going to break anyway | |||
| for (int iter = 0; iter != 100; iter = iter + strides) | |||
| { | |||
| prev[prev.Length] = prev_[iter]; | |||
| if ((iter + strides) > prev_.Length) | |||
| break; | |||
| } | |||
| var ret_ = new TensorShape(prev); | |||
| return ret_; | |||
| } | |||
| } | |||
| } catch (Exception ex) | |||
| { | |||
| if (ex is ValueError || ex is TypeError) {} | |||
| } | |||
| } else if (tensor.op.type == "Placeholder" && | |||
| tensor.op.graph.building_function && | |||
| hasattr(tensor.op.graph, "internal_captures")) | |||
| { | |||
| int i = 0; | |||
| foreach (Tensor capture in tensor.op.graph.internal_captures()) | |||
| { | |||
| if (capture.GetType() == typeof(Tensor)) | |||
| { | |||
| var external_capture = tensor.op.graph.external_captures()[i]; | |||
| return constant_value_as_shape(external_capture); | |||
| } | |||
| i++; | |||
| } | |||
| } | |||
| var ret = tensor.TensorShape.unknown_shape(shape.dims[0]); | |||
| var value = constant_value(tensor); | |||
| if (value != null) | |||
| { | |||
| int[] d_ = {}; | |||
| foreach (int d in value) | |||
| { | |||
| if (d >= 0) | |||
| d_[d_.Length] = d; | |||
| else | |||
| d_[d_.Length] = -1; // None | |||
| } | |||
| ret = ret.merge_with(new TensorShape(d_)); | |||
| } | |||
| return ret; | |||
| } | |||
| public static NDArray convert_to_numpy_ndarray(object values) | |||
| { | |||
| NDArray nd; | |||