Phillip1982
Phillip1982

Reputation: 189

Training a CNN model using mxnet and NDarry

I'm trying to convert 20 images using cv2 into ndarry and then train a CNN model (mxnet) using the ndarry. First I'm converting color images with various pixels into gray and 128 by 128 pixel images. So at the end of the 2nd for-loop, i get a (20, 128, 128) ndarry. I use ndarry iter function (mxnet) to iterate the ndarry for training and evaluating. When I run the rest of the code, I get the following error messages:

Traceback (most recent call last):
  File "mx_n.py", line 43, in <module>
    train_iter = mx.io.NDArrayIter(datan[:ntrain, :], label[:ntrain], batch_size, shuffle=True)
IndexError: too many indices for array

Here is the code:

import numpy as np
import cv2
import time
import subprocess
import scipy as sp
import glob, os
import mxnet as mx
import pickle
import random
from pandas import *
from sklearn import preprocessing
from PIL import Image
from resizeimage import resizeimage

f_path = "/Users/phillipkim/fd"

img_name = "IMG_17"

filelist = glob.glob(f_path + "/IMG*.jpg")
length = len(filelist) + 1
label = []
data_label = []

for i in range(1,129):
    data_label.append('pixel' + str(i))

for i in range(1,length):
    img = cv2.imread(os.path.join(f_path,img_name) + str(10 + i) + ".jpg")
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    gray = cv2.resize(gray, (128,128))
    cv2.imwrite(os.path.join(f_path,img_name) + "g" + str(10 + i) + ".jpg",gray)
    if(1 <= i <= 10):
        label.append(1)
    elif(11 <= i <= 20):
        label.append(2)

filelist = glob.glob(f_path + "/*g.jpg")
label = np.array(label)
datan = np.array([preprocessing.MinMaxScaler().fit_transform(np.array(Image.open(fname))) for fname in filelist])

batch_size = 4
ntrain = int(datan.shape[0]*0.8)
train_iter = mx.io.NDArrayIter(datan[:ntrain, :], label[:ntrain], batch_size, shuffle=True)
val_iter = mx.io.NDArrayIter(datan[ntrain:, :], label[ntrain:], batch_size)

# Set up the symbolic model
#-------------------------------------------------------------------------------

data = mx.symbol.Variable('data')
# 1st convolutional layer
conv_1 = mx.symbol.Convolution(data = data, kernel = (5, 5), num_filter = 20)
tanh_1 = mx.symbol.Activation(data = conv_1, act_type = "tanh")
pool_1 = mx.symbol.Pooling(data = tanh_1, pool_type = "max", kernel = (2, 2), stride = (2, 2))
# 2nd convolutional layer
conv_2 = mx.symbol.Convolution(data = pool_1, kernel = (5, 5), num_filter = 50)
tanh_2 = mx.symbol.Activation(data = conv_2, act_type = "tanh")
pool_2 = mx.symbol.Pooling(data=tanh_2, pool_type = "max", kernel = (2, 2), stride = (2, 2))
# 1st fully connected layer
flatten = mx.symbol.Flatten(data = pool_2)
fc_1 = mx.symbol.FullyConnected(data = flatten, num_hidden = 500)
tanh_3 = mx.symbol.Activation(data = fc_1, act_type = "tanh")
# 2nd fully connected layer
fc_2 = mx.symbol.FullyConnected(data = tanh_3, num_hidden = 40)
# Output. Softmax output since we'd like to get some probabilities.
NN_model = mx.symbol.SoftmaxOutput(data = fc_2)

# Pre-training set up
#-------------------------------------------------------------------------------

# Device used. CPU in my case.
devices = mx.cpu()

# Training
#-------------------------------------------------------------------------------
train_iter.reset()

# Train the model
model = mx.mod.Module(NN_model,
                        data_names = ['data'],
                        label_names = ['softmax_label'],
                        context = devices)

model.fit(train_iter, eval_data=val_iter, num_epoch = 160,
            optimizer_params={'learning_rate':0.01, 'momentum': 0.9},
            eval_metric = mx.metric.Accuracy(),
            epoch_end_callback = mx.callback.log_train_metric(100))

I compared my code with example code on the mxnet website but I can't seem to find what's wrong. Can you help me?

Upvotes: 1

Views: 271

Answers (1)

Thom Lane
Thom Lane

Reputation: 1063

So it looks like datan is causing the issue here. You are creating a numpy array from a list of other arrrays, but if these sub-arrays aren't of compatible shape you get a list of arrays, rather than a multi-dimensional array. And when you slice assuming it's a multi-dimensional array when it's not, you hit the issue.

import numpy as np

a = np.array([1,2,3,4])
b = np.array([4,5,6])
data1 = np.array([a, b])
print(data1)
### [array([1, 2, 3, 4]) array([4, 5, 6])]

If a and b are of incompatible shape (in this case different length 1d arrays), the the result will be a list of arrays, not a multi-dimensional array.

print(data1[1,2])
### IndexError: too many indices for array

So we get an error if we slice on two axes. Instead we must index to get the correct array in list, and then slice again.

print(data1[1][2])
### 6

If the arrays were shape compatible, the numpy will concatenate everything into a single multi-dimensional array and you will then be able to index along two axes.

c = np.array([1,2,3])
d = np.array([4,5,6])
data2 = np.array([c, d])
print(data2)
### [[1 2 3]
### [4 5 6]]

print(data2[1,2])
### 6

So to fix this, either change the way you are indexing, or enforce that the input arrays are of the same shape (by cropping for example).

Upvotes: 1

Related Questions