The nn.Conv1d uses a 3-dimensional input of the shape [batch_size, channels, length].
Each kernel has a specific kernel size and shifted through the temporal dimension (length in the example).
For each window, all input channels are used. This is similar to the vanilla Conv2d operation, where each kernel is moved through the spatial dimensions (height and width) and is using all input channels in the default setup.
If you just have a 2-dimensional input, I assume you are only using one channel.
In this case, you could just add the channel dimension and use your conv layer directly:
x_data = x.data.unsqueeze(1)

Currently your conv layer expects a 16-dimensional (channel-wise) input.
Max pooling is not supposed to lower the dimension. It uses kernels to draw the maximal value of the current overlapping window. Here is a small example:
x = torch.arange(10).float().unsqueeze(0).unsqueeze(1)  # Add batch and channel dims
pool = nn.MaxPool1d(kernel_size=2, stride=2)
output = pool(x)
print('Input: ', x)
> Input:  tensor([[[0., 1., 2., 3., 4., 5., 6., 7., 8., 9.]]])
print('Output: ', output)
> Output:  tensor([[[1., 3., 5., 7., 9.]]])

As you can see, we are using a kernel size of 2 and a stride of 2, which means the kernel windows are not overlapping.
In each window, the maximal value will be pooled.
You can use layers defined as classes like nn.Conv1d, which will hold all parameters as class members etc. or alternatively use the functional API, which is stateless so that you would have to store all parameters. Sometimes you need the flexibility the functional API provides, but for the most use cases the modules should work just fine.
As a small side note: Variables are deprecated since 0.4.0. If you are using a newer PyTorch version, you can just remove the Variable wrappings. You’ll find the install instructions here.