**Dear ptrblck**

**I hope even if you touch soil, it will be changed to gold(It is a proverb in my language and it means I hope the best things for you). I never forget your help.**

I adapt every changes that you told me.

I would appreciate it if you check my code, whether there is any problem or not.

```
# Besmelahel vahedel ghahar
# Khodaya be omide to
# This code is generated by ptrblck and Zahra Pourbahman
# https://pytorch.org/tutorials/beginner/blitz/cifar10_tutorial.html
import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
class convZ(torch.autograd.Function):
# Note that both forward and backward are @staticmethods
@staticmethod
# bias is an optional argument
def forward(ctx, input, weight, bias=None):
ctx.save_for_backward(input, weight, bias)
'''Output: (N, C_out, H_out, W_out) where N = batch size = 2, c_out = 1, H=height, W=width
H_out = (H_in+2Ăpadding[0]âdilation[0]Ă(kernel_size[0]â1)â1)/stride[0] +1
W_out = (W_in+2Ăpadding[1]âdilation[1]Ă(kernel_size[1]â1)â1)/stride[1] +1
stride = 1
padding = 0
dilation = 0
h_in = 1
'''
batch_size = len(input)
c_out = 1 #len(input[0][0])-1
h_out = 1
w_out = len(input[0][0][0]) -1
output = torch.empty(batch_size, c_out, h_out, w_out)
start_col_indx = 0
end_col_indx = 2
for j in range(len(input)): # batch size
out_col_indx = 0
for i in range(len(input[j][0][0]) - 1): # nb of cols in each sample data
conv_mul = input[j][0][:, start_col_indx:end_col_indx] * weight
start_col_indx += 1
end_col_indx += 1
conv_sum = torch.sum(conv_mul)
output[j][0][0][out_col_indx] = conv_sum
out_col_indx +=1
# output = input.mm(weight.t())
# output = input + weight
if bias is not None:
output += bias.unsqueeze(0).expand_as(output)
return output
# This function has only a single output, so it gets only one gradient
@staticmethod
def backward(ctx, grad_output):
# This is a pattern that is very convenient - at the top of backward
# unpack saved_tensors and initialize all gradients w.r.t. inputs to
# None. Thanks to the fact that additional trailing Nones are
# ignored, the return statement is simple even when the function has
# optional inputs.
input, weight, bias = ctx.saved_tensors
grad_input = grad_weight = grad_bias = None
# These needs_input_grad checks are optional and there only to
# improve efficiency. If you want to make your code simpler, you can
# skip them. Returning gradients for inputs that don't require it is
# not an error.
# if ctx.needs_input_grad[0]:
# grad_input = grad_output.mm(weight)
# if ctx.needs_input_grad[1]:
# grad_weight = grad_output.t().mm(input)
# if bias is not None and ctx.needs_input_grad[2]:
# grad_bias = grad_output.sum(0).squeeze(0)
return grad_input, grad_weight, grad_bias
class MyConvZ(nn.Module):
def __init__(self):
super(MyConvZ, self).__init__()
self.fn = convZ.apply
# weight tensor = out_channelsĂ in_channels/groups ĂkHĂkW
self.weight = nn.Parameter(torch.randn(1, 1, 2, 2)) # when groups=1
def forward(self, x):
x = self.fn(x, self.weight)
'''How to initialize weight with arbitrary tensor:
https://discuss.pytorch.org/t/how-to-initialize-weight-with-arbitrary-tensor/3432'''
return x
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
self.convZ = MyConvZ()
self.pool = nn.AvgPool2d((1, 3))
self.fc1 = nn.Linear(1 * 1 * 1, 2)
def forward(self, x):
x = self.pool(F.relu(self.convZ(x)))
x = x.view(-1, 1 * 1 * 1)
x = self.fc1(x)
return x
if __name__ == '__main__':
''' Conv2D when we have just 1 channel(1 input matrix) and the size of the kernel = height of input matrix
a 2D convolution where the kernel height is equal to the input height:
batch_size = 2 => nb_input in each batch = 2
channels = 1 => in RGB photo, each photo includes 3 matrix, so nb_channel = 3, here each input is just a matrix
height = 2 => nb_row in each input
width = 4 => nb_col in each input
kernel_size = (height, 2)
(N,C_in,H,W) N is a batch size, C_in denotes a number of channels, H is a height of input planes in pixels, and W is width in pixels.
# an example is in "https://discuss.pytorch.org/t/2d-input-with-1d-convolution/20331/2" for conv2d standard for 1 input matrix
'''
input1 = torch.Tensor([
[[[1, 0, 0, 1],
[0, 1, 0, 1]]],
[[[1, 0, 0, 1],
[0, 1, 0, 1]]]
])
label1 = torch.LongTensor([0., 1.])
net = Net()
# Define a Loss function and optimizer
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9)
# zero the parameter gradients
optimizer.zero_grad()
# forward + backward + optimize
outputs = net(input1)
loss = criterion(outputs, label1)
loss.backward()
optimizer.step()
# print statistics
running_loss = 0.0
running_loss += loss.item()
print(running_loss)
print('Finished Training')
# Test the network on the test data
test = torch.Tensor([
[[[1, 1, 1, 1],
[0, 1, 0, 1]]],
[[[0, 0, 0, 0],
[0, 1, 0, 1]]]
])
classes = [0, 1]
test_output = net(test)
print(test_output)
_, predicted = torch.max(test_output, 1)
print('Predicted: ', ' '.join('%5s' % classes[predicted[j]]
for j in range(2)))
print('Finished Testing')
```

I am looking forward to get any excellent recommendation from youâŠ

Also, how to be hopeful that I could receive your answers in any new topics, maybe, I will send next times?

Many thanks before all