dan mackinlay - 6 months ago 473

Python Question

OK, I'd like to do a 1-dimensional convolution of time series data in Tensorflow. This is apparently supported using

`tf.nn.conv2d`

`strides=[1,1,1,1]`

However, I cannot work out how to do this in even a very minimal test case. What am I doing wrong?

Let's set this up.

`import tensorflow as tf`

import numpy as np

print(tf.__version__)

>>> 0.9.0

OK, now generate a basic convolution test on two small arrays. I will make it easy by using a batch size of 1, and since time series are 1-dimensional, I will have an "image height" of 1. And since it's a univariate time series, clearly the number of "channels" is also 1, so this will be simple, right?

`g = tf.Graph()`

with g.as_default():

# data shape is "[batch, in_height, in_width, in_channels]",

x = tf.Variable(np.array([0.0, 0.0, 0.0, 0.0, 1.0]).reshape(1,1,-1,1), name="x")

# filter shape is "[filter_height, filter_width, in_channels, out_channels]"

phi = tf.Variable(np.array([0.0, 0.5, 1.0]).reshape(1,-1,1,1), name="phi")

conv = tf.nn.conv2d(

phi,

x,

strides=[1, 1, 1, 1],

padding="SAME",

name="conv")

BOOM. Error.

`ValueError: Dimensions 1 and 5 are not compatible`

OK, For a start, I don't understand how this should happen with

but fine, maybe there are limits to that. I must have got the documentation confused and set up this convolution on the wrong axes of the tensor. I'll try all possible permutations:

`for i in range(4):`

for j in range(4):

shape1 = [1,1,1,1]

shape1[i] = -1

shape2 = [1,1,1,1]

shape2[j] = -1

x_array = np.array([0.0, 0.0, 0.0, 0.0, 1.0]).reshape(*shape1)

phi_array = np.array([0.0, 0.5, 1.0]).reshape(*shape2)

try:

g = tf.Graph()

with g.as_default():

x = tf.Variable(x_array, name="x")

phi = tf.Variable(phi_array, name="phi")

conv = tf.nn.conv2d(

x,

phi,

strides=[1, 1, 1, 1],

padding="SAME",

name="conv")

init_op = tf.initialize_all_variables()

sess = tf.Session(graph=g)

sess.run(init_op)

print("SUCCEEDED!", x_array.shape, phi_array.shape, conv.eval(session=sess))

sess.close()

except Exception as e:

print("FAILED!", x_array.shape, phi_array.shape, type(e), e.args or e._message)

Result:

`FAILED! (5, 1, 1, 1) (3, 1, 1, 1) <class 'ValueError'> ('Filter must not be larger than the input: Filter: (3, 1) Input: (1, 1)',)`

FAILED! (5, 1, 1, 1) (1, 3, 1, 1) <class 'ValueError'> ('Filter must not be larger than the input: Filter: (1, 3) Input: (1, 1)',)

FAILED! (5, 1, 1, 1) (1, 1, 3, 1) <class 'ValueError'> ('Dimensions 1 and 3 are not compatible',)

FAILED! (5, 1, 1, 1) (1, 1, 1, 3) <class 'tensorflow.python.framework.errors.InvalidArgumentError'> No OpKernel was registered to support Op 'Conv2D' with these attrs

[[Node: conv = Conv2D[T=DT_DOUBLE, data_format="NHWC", padding="SAME", strides=[1, 1, 1, 1], use_cudnn_on_gpu=true](x/read, phi/read)]]

FAILED! (1, 5, 1, 1) (3, 1, 1, 1) <class 'tensorflow.python.framework.errors.InvalidArgumentError'> No OpKernel was registered to support Op 'Conv2D' with these attrs

[[Node: conv = Conv2D[T=DT_DOUBLE, data_format="NHWC", padding="SAME", strides=[1, 1, 1, 1], use_cudnn_on_gpu=true](x/read, phi/read)]]

FAILED! (1, 5, 1, 1) (1, 3, 1, 1) <class 'ValueError'> ('Filter must not be larger than the input: Filter: (1, 3) Input: (5, 1)',)

FAILED! (1, 5, 1, 1) (1, 1, 3, 1) <class 'ValueError'> ('Dimensions 1 and 3 are not compatible',)

FAILED! (1, 5, 1, 1) (1, 1, 1, 3) <class 'tensorflow.python.framework.errors.InvalidArgumentError'> No OpKernel was registered to support Op 'Conv2D' with these attrs

[[Node: conv = Conv2D[T=DT_DOUBLE, data_format="NHWC", padding="SAME", strides=[1, 1, 1, 1], use_cudnn_on_gpu=true](x/read, phi/read)]]

FAILED! (1, 1, 5, 1) (3, 1, 1, 1) <class 'ValueError'> ('Filter must not be larger than the input: Filter: (3, 1) Input: (1, 5)',)

FAILED! (1, 1, 5, 1) (1, 3, 1, 1) <class 'tensorflow.python.framework.errors.InvalidArgumentError'> No OpKernel was registered to support Op 'Conv2D' with these attrs

[[Node: conv = Conv2D[T=DT_DOUBLE, data_format="NHWC", padding="SAME", strides=[1, 1, 1, 1], use_cudnn_on_gpu=true](x/read, phi/read)]]

FAILED! (1, 1, 5, 1) (1, 1, 3, 1) <class 'ValueError'> ('Dimensions 1 and 3 are not compatible',)

FAILED! (1, 1, 5, 1) (1, 1, 1, 3) <class 'tensorflow.python.framework.errors.InvalidArgumentError'> No OpKernel was registered to support Op 'Conv2D' with these attrs

[[Node: conv = Conv2D[T=DT_DOUBLE, data_format="NHWC", padding="SAME", strides=[1, 1, 1, 1], use_cudnn_on_gpu=true](x/read, phi/read)]]

FAILED! (1, 1, 1, 5) (3, 1, 1, 1) <class 'ValueError'> ('Dimensions 5 and 1 are not compatible',)

FAILED! (1, 1, 1, 5) (1, 3, 1, 1) <class 'ValueError'> ('Dimensions 5 and 1 are not compatible',)

FAILED! (1, 1, 1, 5) (1, 1, 3, 1) <class 'ValueError'> ('Dimensions 5 and 3 are not compatible',)

FAILED! (1, 1, 1, 5) (1, 1, 1, 3) <class 'ValueError'> ('Dimensions 5 and 1 are not compatible',)

Hmm. OK, it looks like there are two problems now. Firstly, the

`ValueError`

But then the axes along which I can apply the filter are confusing too - notice that it actually constructs the graph with input shape (5, 1, 1, 1) and filter shape (1, 1, 1, 3). AFAICT from the documentation, this should be a filter that looks at on example from the batch, one "pixel" and one "channel" and outputs 3 "channels". Why does that one work, then, when others do not?

Anyway, sometimes it does not fail while constructing the graph.

Sometime it constructs the graph; then we get the

`tensorflow.python.framework.errors.InvalidArgumentError`

Answer

I am sorry to say that, but your first code was almost right. You just inverted `x`

and `phi`

in `tf.nn.conv2d`

:

```
g = tf.Graph()
with g.as_default():
# data shape is "[batch, in_height, in_width, in_channels]",
x = tf.Variable(np.array([0.0, 0.0, 0.0, 0.0, 1.0]).reshape(1, 1, 5, 1), name="x")
# filter shape is "[filter_height, filter_width, in_channels, out_channels]"
phi = tf.Variable(np.array([0.0, 0.5, 1.0]).reshape(1, 3, 1, 1), name="phi")
conv = tf.nn.conv2d(
x,
phi,
strides=[1, 1, 1, 1],
padding="SAME",
name="conv")
```