主要内容

Visualize and Apply Image Embeddings for Classification

R2026b
Since R2026b

This example shows how to use image embeddings from the CLIP (Contrastive Language-Image Pre-training) [1] model to classify images without training a custom model. CLIP learns a shared embedding space for images and text. This enables you to classify images by using text descriptions alone, compare images directly by their embeddings, and detect anomalies by contrasting normal and abnormal text prompts.

In this example, you:

  1. Visualize high-dimensional image and text embeddings in a low-dimensional space by using dimensionality reduction techniques.

  2. Classify images using text-prompted and image exemplar methods.

Download VisA Data Set

This example uses a subset of the VisA (Visual Anomaly) data set [2], which contains industrial inspection images of objects across multiple categories. Each category has normal images and images with defects.

Download the data set and unzip the contents into a temporary folder.

dataDir = fullfile(tempdir,"VisA");
downloadVisAData(dataDir)

Prepare Data Set

Select six classes from the VisA data set and use 50 images from each class. Consider decreasing the number of images per class if no GPU is available, because generating the image embeddings on CPU is time-consuming.

samplesPerClass = 50
samplesPerClass = 
50
classNames = ["candle","capsules","cashew","chewinggum","macaroni1","pcb2"];
classDescriptions = ["candle","pills","cashew","chewing gum","macaroni pasta", ...
    "printed circuit board"];

imds = imageDatastore(fullfile(dataDir,"VisA",classNames,"test","good"));

Assign class labels extracted from the folder structure by using the helperExtractClassLabels helper function, included in the supporting project file attached to this example.

classLabels = helperExtractClassLabels(imds.Files);
imds.Labels = classLabels;

Subsample the data set by using the subsampleDatastore helper function, included in the supporting project file attached to this example. Set the random number generator state to ensure deterministic sampling.

rng("default")
imds = subsampleDatastore(imds,samplesPerClass);

Re-extract class labels after subsampling.

classLabels = helperExtractClassLabels(imds.Files);

Rename the folder-based class labels to human-readable descriptions. Using natural language names such as "pills" instead of "capsules" better matches CLIP training data and improves text prompt accuracy.

classLabels = renamecats(classLabels,classNames,classDescriptions);
imds.Labels = renamecats(imds.Labels,classNames,classDescriptions);
classNames = classDescriptions;

Preview Image Data

Display one sample image from each class by using the helperPreviewClasses helper function, included in the supporting project file attached to this example.

helperPreviewClasses(classNames,classLabels,imds);

Figure contains 6 axes objects. Hidden axes object 1 with title candle contains an object of type image. Hidden axes object 2 with title pills contains an object of type image. Hidden axes object 3 with title cashew contains an object of type image. Hidden axes object 4 with title chewing gum contains an object of type image. Hidden axes object 5 with title macaroni pasta contains an object of type image. Hidden axes object 6 with title printed circuit board contains an object of type image.

Load CLIP Network

Create a pretrained CLIP network by using the clipNetwork object. The CLIP model encodes both images and text into a shared embedding space, where semantically similar content maps to nearby points.

Select a CLIP backbone. Larger backbones have more parameters, which produces more discriminative embeddings but requires more computation time.

Backbone

Approximate Parameter Count

vit-l-14

428 million

vit-b-16

150 million

resnet50

102 million

backbone = "resnet50";
clip = clipNetwork(backbone);

Extract Image Embeddings

Extract a fixed-length embedding vector for each image by using the extractImageEmbeddings function. These embeddings capture the visual content of each image in a numerically comparable form. The function automatically uses a GPU if one is available, which significantly reduces computation time. Processing image data on a GPU requires a supported GPU device and Parallel Computing Toolbox™. This operation might take several minutes on CPU.

imageEmbeddingsRaw = extractImageEmbeddings(clip,imds);

Display the size of imageEmbeddingsRaw to verify the embedding dimensions.

disp(size(imageEmbeddingsRaw));
   768   300

The orientation of CLIP embeddings matters more than their location, because CLIP was trained with cosine similarity. Normalize the embeddings to unit length to improve visualization after dimensionality reduction while preserving directional information.

imageEmbeddings = normalize(imageEmbeddingsRaw,"norm");

Visualize Embeddings

To visualize the high-dimensional embeddings, reduce them to 2 or 3 dimensions to determine how similar images cluster together in the embedding space.

When you compress high-dimensional embeddings into a low-dimensional space, you discard some information. Aim to preserve relative distances between the embeddings while discarding noise.

Specify the dimensionality reduction method by using one of these functions:

  • tsne (Statistics and Machine Learning Toolbox) — t-distributed stochastic neighbor embedding (t-SNE). Preserves local neighborhood structure, making it effective for revealing tight clusters.

  • pca (Statistics and Machine Learning Toolbox) — Principal component analysis. A linear method that preserves global variance and runs faster than nonlinear alternatives.

  • umap (Statistics and Machine Learning Toolbox) — Uniform Manifold Approximation and Projection (UMAP). Balances local and global structure, often producing well-separated clusters with meaningful inter-cluster distances.

useMethod = "umap";

Perform the dimensionality reduction by using the helperReduceDims helper function, included in the supporting project file attached to this example. For the t-SNE and UMAP methods, this helper sets the Distance name-value argument to "cosine" because CLIP was trained by using cosine similarity.

embeddingsMatrix = imageEmbeddings';
reduction2D = helperReduceDims(embeddingsMatrix,useMethod,2);
reduction3D = helperReduceDims(embeddingsMatrix,useMethod,3);

Plot the embeddings colored by ground truth class label in 2-D or 3-D, depending on the dimensionality of the reduced data, by using the helperScatterND helper function, included in the supporting project file attached to this example. Similar images cluster together because the CLIP encoder maps them to nearby points.

figure
hold on
classes = categories(classLabels);
colors = lines(numel(classes));

for c = 1:numel(classes)
    idx = classLabels == classes(c);
    helperScatterND(reduction2D(idx,:),30,colors(c,:),"o", ...
        "filled",DisplayName=string(classes(c)));
end
hold off

legend(Location="best")
title("2D Image Embeddings — Ground Truth Labels")

Figure contains an axes object. The axes object with title 2D Image Embeddings — Ground Truth Labels contains 6 objects of type scatter. These objects represent candle, pills, cashew, chewing gum, macaroni pasta, printed circuit board.

Now plot in three dimensions.

figure
hold on
classes = categories(classLabels);
colors = lines(numel(classes));

for c = 1:numel(classes)
    idx = classLabels == classes(c);
    helperScatterND(reduction3D(idx,:),30,colors(c,:),"o", ...
        "filled",DisplayName=string(classes(c)));
end
hold off
legend(Location="best")
title("3D Image Embeddings — Ground Truth Labels")

Figure contains an axes object. The axes object with title 3D Image Embeddings — Ground Truth Labels contains 6 objects of type scatter. These objects represent candle, pills, cashew, chewing gum, macaroni pasta, printed circuit board.

Classify Images Using Embeddings

Consider a realistic scenario: you have collected a data set of images but have not labeled them. You have only a list of images with no metadata. One of the challenges in processing the images is to classify them into categories. Using image embeddings for this task saves time that you would otherwise spend on manual annotation and labeling.

Plot the same embeddings without color to illustrate this challenge by using the helperScatterND helper function.

figure
helperScatterND(reduction2D,30,[0.5 0.5 0.5],"o","filled")
title("Image Embeddings — Unlabeled (The Problem)")

Figure contains an axes object. The axes object with title Image Embeddings — Unlabeled (The Problem) contains an object of type scatter.

Classify Images Using Text Prompts

Because CLIP maps images and text into the same embedding space, you can classify images by comparing them to text descriptions of each class, without requiring any training images as reference. The text descriptions are open-vocabulary and are not limited to a fixed set of descriptions.

To classify images by using text prompts:

  1. Encode each class name as a text embedding (for example, "A photo of a candle").

  2. Compute cosine similarity between each image embedding and each text embedding.

  3. Assign each image to the class whose text embedding is most similar.

The embedding model might rank a particular image higher for one phrasing of a text prompt than for a synonymous phrasing. For example, an image might score higher with the prompt "an image of a cat" than with "a photo of a cat". Prompt ensembling reduces this sensitivity. When you use ensembled prompts, the classify function averages embeddings from multiple prompt templates per class (for example, "A photo of a [class]", "An image of a [class]", and so on) for more robust classification. With a single prompt, the function uses only "A photo of [class]".

Extract the text embeddings from the prompts for visualization in the next section. If you use simple prompts, compute similarity scores in single precision by using the pdist2 (Statistics and Machine Learning Toolbox) function with cosine distance.

ensembleTextPrompts = true;
simplePrompt = "A photo of " + classNames;
textEmbForVisualization = extractTextEmbeddings(clip,simplePrompt);
textEmbForVisualization = normalize(textEmbForVisualization,"norm");

if ensembleTextPrompts
    [~,textSimScores] = classify(clip,imds,classNames);
else
    textSimScores = 1 - pdist2(single(imageEmbeddings'),single(textEmbForVisualization'),"cosine");
end

Display the size of textSimScores. The text cosine similarity scores include one row per image. Each column in that row contains the cosine similarity between the image and one of the classes.

disp(size(textSimScores));
   300     6

Predict image classes by assigning each image to the class with the maximum cosine similarity.

[~,predictedIdxText] = max(textSimScores,[],2);
predictedLabelsText = classNames(predictedIdxText)';

Visualize Text and Image Embeddings in Shared Space

Visualize the text prompt embeddings alongside the image embeddings in the shared space. The star markers indicate where each text prompt lands relative to the image clusters. This visualization uses only the simple prompt embeddings, not the ensembled prompt embeddings.

To preserve relative locations, reduce both the text and image embeddings together. Specify a combined matrix as input to the helperReduceDims helper function.

allEmbeddings = [embeddingsMatrix; textEmbForVisualization'];
reductionWithText2D = helperReduceDims(allEmbeddings,useMethod,2);

nImages = size(embeddingsMatrix,1);
reductionImages2D = reductionWithText2D(1:nImages,:);
reductionText2D = reductionWithText2D(nImages+1:end,:);

Plot the image embeddings as dots by using the helperScatterND helper function.

figure
hold on
for c = 1:numel(classes)
    idx = classLabels == classes(c);
    helperScatterND(reductionImages2D(idx,:),30,colors(c,:),"o", ...
        "filled",HandleVisibility="off")
end

Visualize the text embeddings as stars.

for c = 1:numel(classNames)
    colorIdx = find(classes == classNames(c));
    helperScatterND(reductionText2D(c,:),300,colors(colorIdx,:),"pentagram", ...
        "filled",DisplayName=simplePrompt(c),MarkerEdgeColor='w');
end
hold off
legend(Location="bestoutside")
title("2D Image + Text Embeddings in Shared Space")

Figure contains an axes object. The axes object with title 2D Image + Text Embeddings in Shared Space contains 6 objects of type scatter. These objects represent A photo of candle, A photo of pills, A photo of cashew, A photo of chewing gum, A photo of macaroni pasta, A photo of printed circuit board.

Now plot in three dimensions.

reductionWithText3D = helperReduceDims(allEmbeddings,useMethod,3);
reductionImages3D = reductionWithText3D(1:nImages,:);
reductionText3D = reductionWithText3D(nImages+1:end,:);

figure
hold on
for c = 1:numel(classes)
    idx = classLabels == classes(c);
    helperScatterND(reductionImages3D(idx,:),30,colors(c,:),"o", ...
        "filled",HandleVisibility="off")
end

for c = 1:numel(classNames)
    colorIdx = find(classes == classNames(c));
    helperScatterND(reductionText3D(c,:),300,colors(colorIdx,:),"pentagram", ...
        "filled",DisplayName=simplePrompt(c),MarkerEdgeColor='w');
end
hold off
legend(Location="bestoutside")
title("3D Image + Text Embeddings in Shared Space")

Figure contains an axes object. The axes object with title 3D Image + Text Embeddings in Shared Space contains 6 objects of type scatter. These objects represent A photo of candle, A photo of pills, A photo of cashew, A photo of chewing gum, A photo of macaroni pasta, A photo of printed circuit board.

Evaluate Text Prompt Classification Accuracy

Evaluate classification accuracy by using a confusion matrix. Because CLIP was trained on internet-scale image-text pairs, it can often distinguish visually distinct categories with no task-specific training.

figure
trueLabels = string(classLabels);
confusionchart(trueLabels,predictedLabelsText)
title("Confusion Matrix — Text-Prompted Classification")

Figure contains an object of type ConfusionMatrixChart. The chart of type ConfusionMatrixChart has title Confusion Matrix — Text-Prompted Classification.

The model misclassifies only 7 of 250 images.

Examine a misclassification to understand where text-prompted classification struggles. The bar chart shows the softmax of similarity scores for all classes, computed by using the softmax (Deep Learning Toolbox) function. Ideally, the true class (green) dominates.

misclassIdxText = find(predictedLabelsText ~= trueLabels,1);
if ~isempty(misclassIdxText)
    figure
    tiledlayout(1,2)
    nexttile
    imshow(readimage(imds,misclassIdxText))
    title("Misclassified Image (True: " + string(classLabels(misclassIdxText)) + ")")
    nexttile
    barColors = repmat([0.4 0.4 0.8],numel(classNames),1);
    trueClassIdx = find(classNames == string(classLabels(misclassIdxText)));
    barColors(trueClassIdx,:) = [0 0.7 0];
    classProbabilities = softmax(dlarray(textSimScores(misclassIdxText,:)),DataFormat='BC');
    b = bar(extractdata(classProbabilities));
    b.FaceColor = "flat";
    b.CData = barColors;
    set(gca,XTickLabel=classNames)
    ylabel("Probability")
    title("Softmax of Similarity Scores")
end

Figure contains 2 axes objects. Axes object 1 with title Softmax of Similarity Scores, ylabel Probability contains an object of type bar. Hidden axes object 2 with title Misclassified Image (True: candle) contains an object of type image.

The true class ranks as the third most likely class for this image. The top two predicted classes, pills and chewing gum, are also plausible given the shape and number of candles in the image.

Classify Images by Using Image Exemplars

Instead of text, you can classify images by comparing them to a representative image from each class. This is useful when you have example images but cannot easily describe the categories in words.

To classify images by using exemplars:

  1. Select one exemplar image per class.

  2. Compute cosine similarity between each image embedding and each exemplar embedding.

  3. Assign each image to the class whose exemplar is most similar.

Select one exemplar image per class. For this example, selecting exemplars is automated by using the VisA class labels. In a real-world scenario, you typically select exemplars manually because class labels are not available.

exemplarEmbeddings = zeros(size(imageEmbeddings,1),numel(classes));
for c = 1:numel(classes)
    idx = find(classLabels == classes(c),1);
    exemplarEmbeddings(:,c) = imageEmbeddings(:,idx);
end

Compute cosine similarity between each image embedding and each exemplar embedding by using the pdist2 (Statistics and Machine Learning Toolbox) function with cosine distance.

simScores = 1 - pdist2(single(imageEmbeddings'),single(exemplarEmbeddings'),"cosine");

Assign each image to the class whose exemplar is most similar.

[~,predictedIdxImage] = max(simScores,[],2);
predictedLabelsImage = string(classes(predictedIdxImage));

Evaluate Image Exemplar Classification Accuracy

Evaluate classification accuracy by using a confusion matrix.

figure
confusionchart(trueLabels,predictedLabelsImage)
title("Confusion Matrix — Image-Prompted Classification")

Figure contains an object of type ConfusionMatrixChart. The chart of type ConfusionMatrixChart has title Confusion Matrix — Image-Prompted Classification.

The image-prompted classification achieves 100% accuracy.

In this example, you classified images by using two different methods, text prompts and exemplar images, both without any model training. This is possible because CLIP was trained on internet-scale image-text data, giving it broad visual and semantic understanding. The classification is open-vocabulary and zero-shot: you can specify arbitrary class names without retraining or fine-tuning.

Outlook

Extend this procedure to other embedding models, such as DINOv2, for fine-grained visual similarity tasks. For data sets with unknown class labels, apply unsupervised clustering methods such as k-means or spectral clustering directly on the embedding vectors to discover groupings. Beyond classification, embeddings enable other capabilities such as image retrieval and anomaly detection.

Define Helper Functions

helperExtractClassLabels

Use this function to extract the class name from each file path based on the VisA data set folder structure. The VisA data set stores files in the path format VisA/className/test/good/ABCD.jpg.

function classLabels = helperExtractClassLabels(filePaths)
    classLabels = strings(numel(filePaths),1);
    for i = 1:numel(filePaths)
        parts = split(filePaths{i},filesep);
        classLabels(i) = parts{end-3};
    end
    classLabels = categorical(classLabels);
end

helperPreviewClasses

Use this function to display a montage with one image per class from the provided datastore.

function helperPreviewClasses(classNames,classLabels,imds)
    figure
    tiledlayout
    for c = 1:numel(classNames)
        idx = find(classLabels == classNames(c),1);
        nexttile
        imshow(readimage(imds,idx))
        title(classNames(c))
    end
end

helperReduceDims

Use this function to reduce the dimensionality of embedding data by using the specified method and number of output dimensions. To tune hyperparameters, see tsne (Statistics and Machine Learning Toolbox), pca (Statistics and Machine Learning Toolbox), or umap (Statistics and Machine Learning Toolbox).

function reduction = helperReduceDims(data,method,numDims)
    switch method
        case "tsne"
            reduction = tsne(data,NumDimensions=numDims,Distance="cosine");
        case "pca"
            [~,reduction] = pca(data,NumComponents=numDims);
        case "umap"
            reduction = umap(data,NumDimensions=numDims,Distance="cosine", ...
                Reproducible=true,EmbeddingDensity=0.5);
    end
end

helperScatterND

Use this function to create a scatter plot in either 2-D or 3-D depending on the number of columns in the input data.

function helperScatterND(pts,sz,color,varargin)
    if size(pts,2) == 3
        scatter3(pts(:,1),pts(:,2),pts(:,3),sz,color,varargin{:});
        view(3); 
    else
        scatter(pts(:,1),pts(:,2),sz,color,varargin{:});
    end
end

References

[1] Radford, Alec, Jong Wook Kim, Chris Hallacy, Aditya Ramesh, Gabriel Goh, Sandhini Agarwal, Girish Sastry, Amanda Askell, Pamela Mishkin, Jack Clark, Gretchen Krueger, and Ilya Sutskever. "Learning Transferable Visual Models from Natural Language Supervision." In Proceedings of the 38th International Conference on Machine Learning, 8748–8763. PMLR, 2021. https://doi.org/10.48550/arXiv.2103.00020.

[2] Zou, Yang, Jongheon Jeong, Latha Pemula, Dongqing Zhang, and Onkar Dabeer. "SPot-the-Difference Self-Supervised Pre-Training for Anomaly Detection and Segmentation." arXiv preprint arXiv:2207.14315 (2022). https://doi.org/10.48550/arXiv.2207.14315.

See Also

| |

Topics