Interpretation of in_channels and out_channels in Conv2D in Pytorch Convolution Neural Networks (CNN)
Let us suppose I have a CNN with starting 2 layers as:

inp_conv = Conv2D(in_channels=1,out_channels=6,kernel_size=(3,3))


Please correct me if I am wrong but I think what this line if code can be thought as that

There is a single grayscale image coming as input where we have to use 6 different kernals of same size (3,3) to make 6 different feature maps from a single image.

And if I have a second Conv2D layer just after first one as

second_conv_connected_to_inp_conv = Conv2D(in_channels=6,out_channels=12,kernel_size=(3,3))


What does this mean in terms of out_channels? Is there going to be 12 new feature maps for each of the 6 feature maps coming as output from first layer OR are there going to be a total of 12 feature maps from 6 incoming features?

For each out_channel, you have a set of kernels for each in_channel.
Equivalently, each out_channel has an in_channel x height x width kernel:
for i in nn.Conv2d(in_channels=2, out_channels=3, kernel_size=(4, 5)).parameters():    
    print(i)

Output:
Parameter containing:
tensor([[[[-0.0012,  0.0848, -0.1301, -0.1164, -0.0609],
      [ 0.0424, -0.0031,  0.1254, -0.0140,  0.0418],
      [-0.0478, -0.0311, -0.1511, -0.1047, -0.0652],
      [ 0.0059,  0.0625,  0.0949, -0.1072, -0.0689]],

     [[ 0.0574,  0.1313, -0.0325,  0.1183, -0.0255],
      [ 0.0167,  0.1432, -0.1467, -0.0995, -0.0400],
      [-0.0616,  0.1366, -0.1025, -0.0728, -0.1105],
      [-0.1481, -0.0923,  0.1359,  0.0706,  0.0766]]],


    [[[ 0.0083, -0.0811,  0.0268, -0.1476, -0.1142],
      [-0.0815,  0.0998,  0.0927, -0.0701, -0.0057],
      [ 0.1011,  0.1572,  0.0628,  0.0214,  0.1060],
      [-0.0931,  0.0295, -0.1226, -0.1096, -0.0817]],

     [[ 0.0715,  0.0636, -0.0937,  0.0478,  0.0868],
      [-0.0200,  0.0060,  0.0366,  0.0981,  0.1518],
      [-0.1218, -0.0579,  0.0621,  0.1310,  0.1376],
      [ 0.1395,  0.0315, -0.1375,  0.0145, -0.0989]]],


    [[[-0.1474,  0.1405,  0.1202, -0.1577,  0.0296],
      [-0.0266, -0.0260, -0.0724,  0.0608, -0.0937],
      [ 0.0580,  0.0800,  0.1132,  0.0591, -0.1565],
      [-0.1026,  0.0789,  0.0331, -0.1233, -0.0910]],

     [[ 0.1487,  0.1065, -0.0689, -0.0398, -0.1506],
      [-0.0028, -0.1191, -0.1220, -0.0087,  0.0237],
      [-0.0648,  0.0938, -0.0962,  0.1435,  0.1084],
      [-0.1333, -0.0394,  0.0071,  0.0231,  0.0375]]]], requires_grad=True)
Parameter containing:
tensor([ 0.0620,  0.0095, -0.0771], requires_grad=True)

A more detailed example going from 1 channel input, through 2 and 4 channel convolutions:
import torch

torch.manual_seed(0)

input0 = torch.randint(-1, 1, (1, 1, 8, 8)).type(torch.FloatTensor)
print('input0:', input0.size())
print(input0.data)

layer0 = nn.Conv2d(in_channels=1, out_channels=2, kernel_size=2, stride=2, padding=0, bias=False)
print('\nlayer1:')
for i in layer0.parameters():
    print(i.size())
    i.data = torch.randint(-1, 1, i.size()).type(torch.FloatTensor)
    print(i.data)

output0 = layer0(input0)
print('\noutput0:', output0.size())
print(output0.data)

print('\nlayer1:')
layer1 = nn.Conv2d(in_channels=2, out_channels=4, kernel_size=2, stride=2, padding=0, bias=False)
for i in layer1.parameters():
    print(i.size())
    i.data = torch.randint(-1, 1, i.size()).type(torch.FloatTensor)
    print(i.data)
output1 = layer1(output0)
print('\noutput1:', output1.size())
print(output1.data)

output:
input0: torch.Size([1, 1, 8, 8])
tensor([[[[-1.,  0.,  0., -1.,  0.,  0.,  0.,  0.],
  [ 0.,  0.,  0., -1., -1.,  0., -1., -1.],
  [-1., -1., -1.,  0., -1.,  0.,  0., -1.],
  [-1.,  0.,  0.,  0.,  0., -1.,  0., -1.],
  [ 0., -1.,  0.,  0., -1.,  0.,  0., -1.],
  [-1.,  0., -1.,  0.,  0.,  0.,  0.,  0.],
  [-1.,  0., -1.,  0.,  0.,  0.,  0., -1.],
  [ 0., -1., -1.,  0.,  0., -1.,  0., -1.]]]])

layer1:
torch.Size([2, 1, 2, 2])
tensor([[[[-1., -1.],
          [-1.,  0.]]],

        [[[ 0., -1.],
          [ 0., -1.]]]])

output0: torch.Size([1, 2, 4, 4])
tensor([[[[1., 1., 1., 1.],
          [3., 1., 1., 1.],
          [2., 1., 1., 1.],
          [1., 2., 0., 1.]],

         [[0., 2., 0., 1.],
          [1., 0., 1., 2.],
          [1., 0., 0., 1.],
          [1., 0., 1., 2.]]]])

layer1:
torch.Size([4, 2, 2, 2])
tensor([[[[-1., -1.],
          [-1., -1.]],

         [[ 0., -1.],
          [ 0., -1.]]],


        [[[ 0.,  0.],
          [ 0.,  0.]],

         [[ 0., -1.],
          [ 0.,  0.]]],


        [[[ 0.,  0.],
          [-1.,  0.]],

         [[ 0., -1.],
          [-1.,  0.]]],


        [[[-1., -1.],
          [-1., -1.]],

         [[ 0.,  0.],
          [-1., -1.]]]])

output1: torch.Size([1, 4, 2, 2])
tensor([[[[-8., -7.],
          [-6., -6.]],

         [[-2., -1.],
          [ 0., -1.]],

         [[-6., -3.],
          [-2., -2.]],

         [[-7., -7.],
          [-7., -6.]]]])

Breaking down the linear algebra:
np.sum(
    # kernel for layer1, in_channel 0, out_channel 0
    # multiplied by output0, channel 0, top left corner
    (np.array([[-1., -1.],
              [-1., -1.]]) * \
    np.array([[1., 1.],
              [3., 1.]])) + \

    # kernel for layer1, in_channel 1, out_channel 0
    # multiplied by output0, channel 1, top left corner
    (np.array([[ 0., -1.],
              [ 0., -1.]]) * \
    np.array([[0., 2.],
              [1., 0.]]))
)

This will be equal to output1, channel 0, top left corner:
-8.0
