xiahaifeng1995 / PaDiM-Anomaly-Detection-Localization-master

This is an unofficial implementation of the paper “PaDiM: a Patch Distribution Modeling Framework for Anomaly Detection and Localization”.
Apache License 2.0
400 stars 94 forks source link

Question about CPU out of memory #27

Open Youskrpig opened 3 years ago

Youskrpig commented 3 years ago

Hi, I run the experiments with my own dataset, which the number of training samples is about 1000 and the number of testing samples is about 1500. but in the process of embedding_concat (function F.fold),cpu out of memory. Any suggestions?

Youskrpig commented 3 years ago

z = F.fold(z, kernel_size=s, output_size=(H1, W1), stride=s) File "/opt/conda/lib/python3.8/site-packages/torch/nn/functional.py", line 3860, in fold return torch._C._nn.col2im(input, _pair(output_size), _pair(kernel_size), RuntimeError: [enforce fail at CPUAllocator.cpp:65] . DefaultCPUAllocator: can't allocate memory: you tried to allocate 52626456576 bytes. Error code 12 (Cannot allocate memory)

Chavo11 commented 3 years ago

I did this as a workaround:

    embedding_vectors = test_outputs['layer1']
    # randomly select d dimension
    condition = idx < embedding_vectors.shape[1]
    idx_1 = idx[condition]
    embedding_vectors = torch.index_select(embedding_vectors, 1, idx_1)

    for layer_name in ['layer2', 'layer3']:
        emb_vect = test_outputs[layer_name]
        condition1 = embedding_vectors.shape[1] <= idx
        condition2 = idx < (embedding_vectors.shape[1] + emb_vect.shape[1])
        condition = torch.logical_and(condition1, condition2)
        idx_1 = idx[condition]
        idx_1 -= embedding_vectors.shape[1]
        emb_vect = torch.index_select(emb_vect, 1, idx_1)
        embedding_vectors = embedding_concat(embedding_vectors, emb_vect)

Practically I'm dividing the expensive concat operation into "multiple stages". It helped me out with the memory issue. Also I moved this out of the for cycle in plot_figs():

fig_img, ax_img = plt.subplots(1, 5, figsize=(12, 3))
fig_img.subplots_adjust(right=0.9)
norm = matplotlib.colors.Normalize(vmin=vmin, vmax=vmax)

Because it was causing a huge memory leak (16-20 gb for the whole dataset)

Youskrpig commented 3 years ago

I did this as a workaround:

    embedding_vectors = test_outputs['layer1']
    # randomly select d dimension
    condition = idx < embedding_vectors.shape[1]
    idx_1 = idx[condition]
    embedding_vectors = torch.index_select(embedding_vectors, 1, idx_1)

    for layer_name in ['layer2', 'layer3']:
        emb_vect = test_outputs[layer_name]
        condition1 = embedding_vectors.shape[1] <= idx
        condition2 = idx < (embedding_vectors.shape[1] + emb_vect.shape[1])
        condition = torch.logical_and(condition1, condition2)
        idx_1 = idx[condition]
        idx_1 -= embedding_vectors.shape[1]
        emb_vect = torch.index_select(emb_vect, 1, idx_1)
        embedding_vectors = embedding_concat(embedding_vectors, emb_vect)

Practically I'm dividing the expensive concat operation into "multiple stages". It helped me out with the memory issue. Also I moved this out of the for cycle in plot_figs():

fig_img, ax_img = plt.subplots(1, 5, figsize=(12, 3))
fig_img.subplots_adjust(right=0.9)
norm = matplotlib.colors.Normalize(vmin=vmin, vmax=vmax)

Because it was causing a huge memory leak (16-20 gb for the whole dataset)

Thanks for your reply. It seems that firstly you index_select for every-layer feature and then concat. It helps. but in my experimental condition, i found the C,H,W of feature is not large,but the B is. in ( z = torch.zeros(B, C1 + C2, x.size(2), H2, W2) ) . I split the training samples into parts and concat them after part feature embedding_cat. In addition, random choose feature dimension is not so good. For details, refer to the latest paper: "Semi-orthogonal Embedding for Efficient Unsupervised Anomaly Segmentation"

jackft2 commented 3 years ago

hi i met this problem in training phase. and i change this code to your version. but i met

File "main.py", line 337, in main() File "main.py", line 128, in main condition2 = idx < (embedding_vectors.shape[1] + emb_vect.shape[1]) AttributeError: 'list' object has no attribute 'shape'

nikkymen commented 3 years ago

@Youskrpig

In addition, random choose feature dimension is not so good. For details, refer to the latest paper: "Semi-orthogonal Embedding for Efficient Unsupervised Anomaly Segmentation"

Hello, do you understand the essence proposed by the authors of the article?

As far as I understand, instead of random sampling of d features, calculating and storing covariance matrices of size dxd, they propose to calculate the expression

, , , where S is a Fxk random matrix with standard normal distribution,

and use the result D when calculating the score map.

I'm right?

Youskrpig commented 3 years ago

@Youskrpig

In addition, random choose feature dimension is not so good. For details, refer to the latest paper: "Semi-orthogonal Embedding for Efficient Unsupervised Anomaly Segmentation"

Hello, do you understand the essence proposed by the authors of the article?

As far as I understand, instead of random sampling of d features, calculating and storing covariance matrices of size dxd, they propose to calculate the expression

![](https://render.githubusercontent.com/render/math?math=D=W(W^T C W)^{-1}W^T), ![](https://render.githubusercontent.com/render/math?math=W=Q * sign(diag(R))), , where S is a Fxk random matrix with standard normal distribution,

and use the result D when calculating the score map.

I'm right?

Yeah,I think you're right! Have you tried it ?

nikkymen commented 3 years ago

@Youskrpig

Yeah,I think you're right! Have you tried it ?

Nope, not yet, but it sounds promising.

Pangoraw commented 3 years ago

S is a Fxk random matrix with standard normal distribution,

and use the result D when calculating the score map.

I think you can simply consider the reduced dataset of size k as being the original dataset of size FxN multiplied by the semi-orthogonal matrix:

You can then compute the covariance matrices as usual:

And the score will be the regular Mahalanobis distance:

Note: you still need to substract the mean vectors but I removed them for an easier reading. I have implemented it at Pangoraw/SemiOrthogonal using the outer product for the covariance so the memory footprint is not dependent on the number of training samples (no concat) which could also be useful for this issue.

zhangyumo95 commented 3 years ago

I made the following changes to the code: ` # Embedding concat

embedding_vectors = test_outputs['layer1']

    # for layer_name in ['layer2', 'layer3']:
    #     embedding_vectors = embedding_concat(embedding_vectors, test_outputs[layer_name])

    tmp = test_outputs['layer1'].shape[0]
    embedding_vectors1 = None
    for tmp_i in range(0, tmp, 32):
        if tmp_i + 32 >= tmp:
            embedding_vectors = test_outputs['layer1'][tmp_i:]
        else:
            embedding_vectors = test_outputs['layer1'][tmp_i:tmp_i + 32]
        for layer_name in ['layer2', 'layer3']:
            if tmp_i + 32 >= tmp:
                embedding_vectors = embedding_concat(embedding_vectors, test_outputs[layer_name][tmp_i:])
            else:
                embedding_vectors = embedding_concat(embedding_vectors, test_outputs[layer_name][tmp_i:tmp_i + 32])
        embedding_vectors = torch.index_select(embedding_vectors, 1, idx)
        if tmp_i != 0:
            embedding_vectors1 = torch.cat([embedding_vectors1, embedding_vectors], 0)
        else:
            embedding_vectors1 = embedding_vectors
    embedding_vectors = embedding_vectors1

    # randomly select d dimension
    # embedding_vectors = torch.index_select(embedding_vectors, 1, idx)`
haobo827 commented 2 years ago

hi i met this problem in training phase. and i change this code to your version. but i met

File "main.py", line 337, in main() File "main.py", line 128, in main condition2 = idx < (embedding_vectors.shape[1] + emb_vect.shape[1]) AttributeError: 'list' object has no attribute 'shape'

np.array(list).shape[1]