Number of layers vs list(net.parameters()) - neural-network

New to convolutional neural nets so sorry if this doesn't make much sense. I have this code:
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
self.conv1 = nn.Conv2d(3, 6, 5)
self.pool = nn.MaxPool2d(2, 2)
self.conv2 = nn.Conv2d(6, 16, 5)
self.fc1 = nn.Linear(16 * 5 * 5, 120)
self.fc2 = nn.Linear(120, 84)
self.fc3 = nn.Linear(84, 10)
def forward(self, x):
x = self.pool(F.relu(self.conv1(x)))
x = self.pool(F.relu(self.conv2(x)))
x = x.view(-1, 16 * 5 * 5)
x = F.relu(self.fc1(x))
x = F.relu(self.fc2(x))
x = self.fc3(x)
return x
net = Net()
and I think this has 5 layers. However, when I print len((list(net.parameters())) I get 10. Shouldn't this be a list of size 5 with parameters for each layer?

Quick answer : You get an extra parameter array for each layer containing the bias vector associated to the layer.
Detailled answer:
I will try to guide you in my process of investigating your questions.
It seems like a good idea to see what our 10 parameters are :
for param in net.parameters():
print(type(param), param.size())
<class 'torch.nn.parameter.Parameter'> torch.Size([6, 3, 5, 5])
<class 'torch.nn.parameter.Parameter'> torch.Size([6])
<class 'torch.nn.parameter.Parameter'> torch.Size([16, 6, 5, 5])
<class 'torch.nn.parameter.Parameter'> torch.Size([16])
<class 'torch.nn.parameter.Parameter'> torch.Size([120, 400])
<class 'torch.nn.parameter.Parameter'> torch.Size([120])
<class 'torch.nn.parameter.Parameter'> torch.Size([84, 120])
<class 'torch.nn.parameter.Parameter'> torch.Size([84])
<class 'torch.nn.parameter.Parameter'> torch.Size([10, 84])
<class 'torch.nn.parameter.Parameter'> torch.Size([10])
We can recognize our 5 layers and an extra line for each layer. For instance, if we look at a specific layer for instance the first conv layer, we get :
for param in net.conv1.parameters():
print(type(param), param.size())
<class 'torch.nn.parameter.Parameter'> torch.Size([6, 3, 5, 5])
<class 'torch.nn.parameter.Parameter'> torch.Size([6])
So now that we know we have two array of parameters per layer, the question is why. The first 6*3*5*5 array corresponds to your 6 kernels of size 5*5 with 3 channels, the second one corresponds the the bias associated to each of your kernel. Mathematically speaking, to compute the value at the next layer associated to a given kernel, you make the convolution between the area under your desired pixel and the kernel and you add a real number. That number is called the bias and it is empirically proven that using a bias gives better results.
Now you can also create a layer without bias, and then you will only get one parameter array :
layer = nn.Conv2d(3,6,5, bias= False)
for param in layer.parameters():
print(type(param), param.size())
<class 'torch.nn.parameter.Parameter'> torch.Size([6, 3, 5, 5])

Related

function for Ordinal Pooling Neural network

please I want to create a function that computes the Ordinal Pooling neural network like the following figure:
this is my function :
def Ordinal_Pooling_NN(x):
wights = torch.tensor([0.6, 0.25, 0.10, 0.05])
top = torch.topk(x, 4, dim = 1)
wights = wights.repeat(x.shape[0], 1)
result = torch.sum(wights * (top.values), dim = 1 )
return result
but as a result, I get the following error:
<ipython-input-112-ddf99c812d56> in Ordinal_Pooling_NN(x)
9 top = torch.topk(x, 4, dim = 1)
10 wights = wights.repeat(x.shape[0], 1)
---> 11 result = torch.sum(wights * (top.values), dim = 1 )
12 return result
RuntimeError: The size of tensor a (4) must match the size of tensor b (16) at non-singleton dimension 2
Your implementation is actually correct, I believe you did not feed the function with a 2D tensor, the input must have a batch axis. For instance, the code below will run:
>>> Ordinal_Pooling_NN(torch.tensor([[1.9, 0.4, 1.3, 0.8]]))
tensor([1.5650])
Do note you are not required to repeat the weights tensor, it will be broadcasted automatically when computing the point-wise multiplication. You only need the following:
def Ordinal_Pooling_NN(x):
w = torch.tensor([0.6, 0.25, 0.10, 0.05])
top = torch.topk(x, k=4, dim=1)
result = torch.sum(w*top.values, dim=1)
return result

Scipy.curve_fit() vs. Matlab fit() weighted nonlinear least squares

I have a Matlab reference routine that I am trying to convert to numpy/scipy. I have encountered a curve fitting problem that does I cannot solve in Python. So here is a simple example which demonstrates the problem. The data is completely synthetic and not part of the problem.
Let's say I'm trying to fit a straight-line model of noisy data -
x = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
y = [0.1075, 1.3668, 1.5482, 3.1724, 4.0638, 4.7385, 5.9133, 7.0685, 8.7157, 9.5539]
For the unweighted solution in Matlab, I would code
g = #(m, b, x)(m*x + b)
f = fittype(g)
bestfit = fit(x, y, g)
which produces a solution of bestfit.m = 1.048, bestfit.b = -0.09219
Running this data through scipy.optimize.curve_fit() produces identical results.
If instead the fit uses a decay function to reduce the impact of data points
dw = [0.7290, 0.5120, 0.3430, 0.2160, 0.1250, 0.0640, 0.0270, 0.0080, 0.0010, 0]
weightedfit = fit(x, y, g, 'Weights', dw)
This produces a slope if 0.944 and offset 0.1484.
I have not figured out how to conjure this result from scipy.optimize.curve_fit using the sigma parameter. If I pass the weights as provided to Matlab, the '0' causes a divide by zero exception. Clearly Matlab and scipy are thinking very differently about the meaning of the weights in the underlying optimization routine. Is there a simple way of converting between the two that allows me to provide a weighting function which produces identical results?
Ok, so after further investigation I can offer the answer, at least for this simple example.
import numpy as np
import scipy as sp
import scipy.optimize
def modelFun(x, m, b):
return m * x + b
def testFit():
w = np.diag([1.0, 1/0.7290, 1/0.5120, 1/0.3430, 1/0.2160, 1/0.1250, 1/0.0640, 1/0.0270, 1/0.0080, 1/0.0010])
x = np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
y = np.array([0.1075, 1.3668, 1.5482, 3.1724, 4.0638, 4.7385, 5.9133, 7.0685, 8.7157, 9.5539])
popt = sp.optimize.curve_fit(modelFun, x, y, sigma=w)
print(popt[0])
print(popt[1])
Which produces the desired result.
In order to force sp.optimize.curve_fit to minimize the same chisq metric as Matlab using the curve fitting toolbox, you must do two things:
Use the reciprocal of the weight factors
Create a diagonal matrix from the new weight factors. According to the scipy reference:
sigma None or M-length sequence or MxM array, optional
Determines the uncertainty in ydata. If we define residuals as r =
ydata - f(xdata, *popt), then the interpretation of sigma depends on
its number of dimensions:
A 1-d sigma should contain values of standard deviations of errors in
ydata. In this case, the optimized function is chisq = sum((r / sigma)
** 2).
A 2-d sigma should contain the covariance matrix of errors in ydata.
In this case, the optimized function is chisq = r.T # inv(sigma) # r.
New in version 0.19.
None (default) is equivalent of 1-d sigma filled with ones.

How to get accurate encoder output for kmeans clustering of similar images

I expected that if I trained similar images in an autoencoder the output from the encoder would be similar, hence if passed through a clustering algorithm they would form clusters around the same point. So what I did was to train the model with identical images (basically 60 duplicates of the same image). What I noticed, on the contrary, is that the values from the encoder appear different and when passed through kmeans clustering the points are scattered, which tells me nothing about how related my images are to each other.
kmeans clustering of 60 duplicate images
def autoencoderConv2D(input_shape=(228, 228, 1), filters=[32, 64, 128, 10]):
input_img = Input(shape=input_shape)
if input_shape[0] % 8 == 0:
pad3 = 'same'
else:
pad3 = 'valid'
x = Conv2D(filters[0], 5, strides=2, padding='same', activation='relu', name='conv1', input_shape=input_shape)(input_img)
x = Conv2D(filters[1], 5, strides=2, padding='same', activation='relu', name='conv2')(x)
x = Conv2D(filters[2], 3, strides=2, padding=pad3, activation='relu', name='conv3')(x)
x = Flatten()(x)
encoded = Dense(units=filters[3], name='embedding')(x)
x = Dense(units=filters[2]*int(input_shape[0]/8)*int(input_shape[0]/8), activation='relu')(encoded)
print (x.shape)
x = Reshape((int(input_shape[0]/8), int(input_shape[0]/8), filters[2]))(x)
print (x.shape)
x = Conv2DTranspose(filters[1], 3, strides=2, padding=pad3, activation='relu', name='deconv3')(x)
x = Conv2DTranspose(filters[0], 5, strides=2, padding='same', activation='relu', name='deconv2')(x)
print (x.shape)
decoded = Conv2DTranspose(input_shape[2], 5, strides=2, padding='same', name='deconv1')(x)
return Model(inputs=input_img, outputs=decoded, name='AE'), Model(inputs=input_img, outputs=encoded, name='encoder')
autoencoder, encoder = autoencoderConv2D()
pretrain_epochs = 50
batch_size = 2
autoencoder.compile(optimizer='adadelta', loss='mse')
autoencoder.fit(x, x, batch_size=batch_size, epochs=pretrain_epochs)
encoded = encoder.predict(x)
encoded.shape
(60, 10)
n_clusters = 1
kmeans = KMeans(n_clusters=n_clusters, n_init=20, n_jobs=4)
y_pred_kmeans = kmeans.fit_predict(encoded)
I also tried this with MNIST dataset with digit-2 being 5958 samples and digit-4 being 50 samples. Using k=2, the clustering gives the result as the figure below which shows no distinction between the two digits. Is there something I'm not doing right as I am looking to apply this technique for image filtering where dissimilar images are distinguished and filtered from the similar ones.

Keras target shape is incorrect

I am relatively new to keras so i played around with a simple seq2seq architecture.
model = Sequential()
model.add(Embedding(22, 10, input_length=32, mask_zero=True))
model.add(LSTM(4, return_sequences = True))
model.add(TimeDistributed(Dense(output_dim=3)))
model.add(Activation('softmax'))
model.compile(loss='categorical_crossentropy',
optimizer='rmsprop',
metrics=['accuracy'])
model.fit(x,y,nb_epoch =1, batch_size = 1, verbose = 2)
Exception: Error when checking model target: expected activation_6 to have shape (None, 32, 3) but got array with shape (2, 4, 3)
x has shape of (2,32) and y has shape of (2,4,3).
According to my understanding, it means that y has 2 examples with each sequence have a length of 4 and one hot-encoded into 3 dimension. However, when i ran model.fit it seems its not the shape that i am expecting. Why is this so?

Keras Dense Layer Error: TypeError: 'int' object is not callable

I'm trying to visualize the output of each convolutional layer in keras, following this link: MNIST Visualisation. I have modified some layers to remove errors, but now I'm stuck with the Dense Layer Error.
np.set_printoptions(precision=5, suppress=True)
np.random.seed(1337) # for reproducibility
nb_classes = 10
# the data, shuffled and split between tran and test sets
(X_train, y_train), (X_test, y_test) = mnist.load_data("mnist.pkl")
X_train = X_train.reshape(X_train.shape[0], 1, 28, 28)
X_test = X_test.reshape(X_test.shape[0], 1, 28, 28)
X_train = X_train.astype("float32")
X_test = X_test.astype("float32")
X_train /= 255
X_test /= 255
print('X_train shape:', X_train.shape)
print(X_train.shape[0], 'train samples')
print(X_test.shape[0], 'test samples')
# convert class vectors to binary class matrices
Y_train = np_utils.to_categorical(y_train, nb_classes)
Y_test = np_utils.to_categorical(y_test, nb_classes)
i = 4600
pl.imshow(X_train[i, 0], interpolation='nearest', cmap=cm.binary)
print("label : ", Y_train[i,:])
model = Sequential()
model.add(Convolution2D(32, 3, 3, border_mode='same',input_shape = (1,28,28))) #changed border_mode from full -> valid
convout1 = Activation('relu')
model.add(convout1)
model.add(Convolution2D(32, 32, 3))
convout2 = Activation('relu')
model.add(convout2)
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.25))
model.add(Flatten())
model.add(Dense(32*196, 128)) #ERROR HERE
Any comment or suggestion highly appreciated. Thank you.
If you check the documentation of a Dense layer then you'll notice that the first argument it accepts is the shape of output and second is init which describes the way how weights of the layer are initiated. In your case you provided the int as second positional argument and this caused error. You should change the code to (assuming that you want an output in a form of 128-dimensional vector):
model.add(Dense(128))