ImageClassifierData.from_arrays

I am looking at the ImageClassifierData.from_arrays command and my understanding is that if I am pulling my data in from something besides a csv, path, or dls (not sure what dls stands for), I will use the from_arrays to get the data. I am pulling my data in from a JSON file and then forming it into 75x75 pixel images (Kaggle iceberg challenge).

When I look at the code behind this (??ImageClassifierData.from_arrays()) I can see it uses the following arguments:

ImageClassifierData.from_arrays(path, trn, val, bs=64, tfms=(None, None), classes=None, num_workers=4, test=None)

What would my path be when I have already uploaded my arrays into variables?

I have trn, val, and test variables and I have an idea of what I want for tfms (tfms = tfms_from_model(f_model, sz, aug_tfms=transforms_top_down, max_zoom=1.05)) which I took from the lesson2 notebook.

Did you accidentally submit this post before it was done? It cuts off half way through…

Yeah, live by the ctrl+enter and die by the ctrl+enter.

I finished it up now though.

In this case, the path is just there so it knows where to put stuff like precomputed activations, saved models, etc.

(BTW, this competition looks somewhat similar to the popular CIFAR10 dataset, so I’d suspect architectures that work well there are also going to be good here.)

2 Likes

Ok, my initial thought was to just go through the same steps we did in the first 2 lessons and try to train a few more of the layers and see how it does. It seems somewhat similar to the satellite images. That path thing definitely makes sense though when you explain it.

Well the issue is that these iceberg images are tiny - just 72x72 IIRC. So I’m not sure these imagenet architectures are going to be great for it. It should work OK-ish, but you’ll probably have to look at architectures designed for smaller images to get better results.

Yeah, it probably won’t be the winning architecture, but even just getting something submitted would be a big win for me. The images are 75x75 so definitely not ideal. Even if I just was able to get a decent score then I can iterate and try different architectures at that point. That will at least tell me that the data is good and I’m building my model correctly.

2 Likes

I got to thinking about this more and I am wondering if you have some advice on how to find architectures that work well on CIFAR10.

Yup search this category for CIFAR 10 - I’ve linked a couple of times to the latest architectures.

1 Like

Is this the link you are referring to? I just went to the magnifying glass and searched CIFAR10 that was posted by you and I only saw three posts and this is the one that had a link. Just want to make sure I’m looking at the correct thing before I dig too deep into it.

Yup that’s it

1 Like

Ok, thanks I will see if this helps my results any.

I have a new question about this function. I am trying to add my test data in and I used the following command. I wasn’t sure what to feed in to the test argument. By default it is None, but I actually have test data and I thought it would be easier to predict later if I put it into the ImageClassifierData object.

data=ImageClassifierData.from_arrays(path, (X_train,y_train), (X_valid, y_valid), tfms=tfms, bs=32, test=X_test)

I get an error because of the if test: is basically trying to say whether an entire array is true or false which logically doesn’t make any sense.

---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-37-84e446ed1604> in <module>()
      1 tfms = tfms_from_model(f_model, sz, aug_tfms=transforms_top_down, max_zoom=1.05)
----> 2 data=ImageClassifierData.from_arrays(path, (X_train,y_train), (X_valid, y_valid), tfms=tfms, bs=32, test=X_test)
      3 arch=resnet50

~/fastaip1v2/fastai/courses/dl1/fastai/dataset.py in from_arrays(self, path, trn, val, bs, tfms, classes, num_workers, test)
    289     @classmethod
    290     def from_arrays(self, path, trn, val, bs=64, tfms=(None,None), classes=None, num_workers=4, test=None):
--> 291         datasets = self.get_ds(ArraysIndexDataset, trn, val, tfms, test=test)
    292         return self(path, datasets, bs, num_workers, classes=classes)
    293 

~/fastaip1v2/fastai/courses/dl1/fastai/dataset.py in get_ds(self, fn, trn, val, tfms, test, **kwargs)
    278             fn(val[0], val[1], tfms[0], **kwargs)  # aug
    279         ]
--> 280         if test:
    281             test_lbls = np.zeros((len(test),1))
    282             res += [

ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()

I was able to get this same error by directly doing if X_test: just to validate that I understood what that error actually was telling me.

I looked in the lesson1 notebook but I didn’t see this command actually used anywhere. Any help would be much appreciated.

I also tried feeding in test=(X_test, test_lbls) but this also didn’t work.

Is there a way to search for the implementation of a function?

1 Like

I was looking at that function in an attempt to add some docstring. I almost want to say, the if statement on the line 280 should be:

if test is not None:

… but I could be wrong.

1 Like

You can be wrong, but you’re not! :smiley:

I just pushed that change to GH. (I’ve used from_arrays only for precomputed activations, so this part of the code isn’t well tested - sorry!)

4 Likes

I think that might have generated a new error here:

---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-24-0e8771e4fad3> in <module>()
----> 1 learn = ConvLearner.pretrained(arch, data, precompute=True)

~/fastaip1v2/fastai/courses/dl1/fastai/conv_learner.py in pretrained(self, f, data, ps, xtra_fc, xtra_cut, **kwargs)
     90     def pretrained(self, f, data, ps=None, xtra_fc=None, xtra_cut=0, **kwargs):
     91         models = ConvnetBuilder(f, data.c, data.is_multi, data.is_reg, ps=ps, xtra_fc=xtra_fc, xtra_cut=xtra_cut)
---> 92         return self(data, models, **kwargs)
     93 
     94     @property

~/fastaip1v2/fastai/courses/dl1/fastai/conv_learner.py in __init__(self, data, models, precompute, **kwargs)
     83         elif self.metrics is None:
     84             self.metrics = [accuracy_multi] if self.data.is_multi else [accuracy]
---> 85         if precompute: self.save_fc1()
     86         self.freeze()
     87         self.precompute = precompute

~/fastaip1v2/fastai/courses/dl1/fastai/conv_learner.py in save_fc1(self)
    130         self.fc_data = ImageClassifierData.from_arrays(self.data.path,
    131                 (act, self.data.trn_y), (val_act, self.data.val_y), self.data.bs, classes=self.data.classes,
--> 132                 test = test_act if self.data.test_dl else None, num_workers=8)
    133 
    134     def freeze(self): self.freeze_to(-1)

~/fastaip1v2/fastai/courses/dl1/fastai/dataset.py in from_arrays(self, path, trn, val, bs, tfms, classes, num_workers, test)
    289     @classmethod
    290     def from_arrays(self, path, trn, val, bs=64, tfms=(None,None), classes=None, num_workers=4, test=None):
--> 291         datasets = self.get_ds(ArraysIndexDataset, trn, val, tfms, test=test)
    292         return self(path, datasets, bs, num_workers, classes=classes)
    293 

~/fastaip1v2/fastai/courses/dl1/fastai/dataset.py in get_ds(self, fn, trn, val, tfms, test, **kwargs)
    281             test_lbls = np.zeros((len(test),1))
    282             res += [
--> 283                 fn(test, test_lbls, tfms[1], **kwargs), # test
    284                 fn(test, test_lbls, tfms[0], **kwargs)  # test_aug
    285             ]

~/fastaip1v2/fastai/courses/dl1/fastai/dataset.py in __init__(self, x, y, transform)
    166         self.x,self.y=x,y
    167         assert(len(x)==len(y))
--> 168         super().__init__(transform)
    169     def get_x(self, i):
    170         return self.x[i]

~/fastaip1v2/fastai/courses/dl1/fastai/dataset.py in __init__(self, transform)
     92         #self.lock=threading.Lock()
     93         self.n = self.get_n()
---> 94         self.c = self.get_c()
     95         self.sz = self.get_sz()
     96 

~/fastaip1v2/fastai/courses/dl1/fastai/dataset.py in get_c(self)
    178 
    179 class ArraysIndexDataset(ArraysDataset):
--> 180     def get_c(self): return int(self.y.max())+1
    181 
    182 

~/anaconda3/envs/fastai/lib/python3.6/site-packages/numpy/core/_methods.py in _amax(a, axis, out, keepdims)
     24 # small reductions
     25 def _amax(a, axis=None, out=None, keepdims=False):
---> 26     return umr_maximum(a, axis, None, out, keepdims)
     27 
     28 def _amin(a, axis=None, out=None, keepdims=False):

ValueError: zero-size array to reduction operation maximum which has no identity

I think the actual problem is test = test_act if self.data.test_dl else None from here:

~/fastaip1v2/fastai/courses/dl1/fastai/conv_learner.py in save_fc1(self)
    130         self.fc_data = ImageClassifierData.from_arrays(self.data.path,
    131                 (act, self.data.trn_y), (val_act, self.data.val_y), self.data.bs, classes=self.data.classes,
--> 132                 test = test_act if self.data.test_dl else None, num_workers=8)
    133 
    134     def freeze(self): self.freeze_to(-1)

I don’t full understand that mostly because I don’t know what test_act is suppose to provide, but it doesn’t seem like it’s doing quite what I want it do do.

So it works if I don’t try to precompute so it looks like the issue may be with precompute=True when using a test dataset?

Do you want to have a try at fixing it and sending a PR?

Sure, I can dig into it more. I am not super familiar with pull requests, but I will give it a go.

This is the secret to pull requests: https://github.com/github/hub . Makes life so so easy…

4 Likes

I think this may be a little over my head. Here is what I’ve found so far.

    def save_fc1(self):
        self.get_activations()
        act, val_act, test_act = self.activations

        if len(self.activations[0])==0:
            m=self.models.top_model
            predict_to_bcolz(m, self.data.fix_dl, act)
            predict_to_bcolz(m, self.data.val_dl, val_act)
            if self.data.test_dl: predict_to_bcolz(m, self.data.test_dl, test_act)

        self.fc_data = ImageClassifierData.from_arrays(self.data.path,
                (act, self.data.trn_y), (val_act, self.data.val_y), self.data.bs, classes=self.data.classes,
                test = test_act if self.data.test_dl else None, num_workers=8)

If you look at this, it is getting all of the activations using:
ConvLearner.get_activations(learn) and then grabbing test_act which is the activations for the test dataset so in my case it is:

carray((0, 4096), float32)
  nbytes := 0; cbytes := 16.00 KB; ratio: 0.00
  cparams := cparams(clevel=5, shuffle=1, cname='lz4', quantize=0)
  chunklen := 1; chunksize: 16384; blocksize: 0
  rootdir := 'data/iceberg/tmp/x_act_test_resnet50_0_4096.bc'
  mode    := 'w'
[]

When I try to look inside of test_act, it looks like everything is empty:

test_act[:,0]

(and test_act[:,4095]) gives me

array([], dtype=float32)

so I think that the error I am getting basically corresponds to that fact: “ValueError: zero-size array to reduction operation maximum which has no identity”

Unfortunately I have no idea why this is happening or what I should be doing to fix it. Any ideas for me to try?

A side note, it looks like everything is good if I just take out the precompute=True argument so that’s at least a work-around, but not really a fix unless I am just totally missing what precompute=True actually means.