首页 > 编程语言 >C# Onnx Chinese CLIP 通过一句话从图库中搜出来符合要求的图片

C# Onnx Chinese CLIP 通过一句话从图库中搜出来符合要求的图片

时间:2024-01-09 15:06:26浏览次数:43  
标签:Chinese CLIP C# text image float int new input

C# Onnx Chinese CLIP 通过一句话从图库中搜出来符合要求的图片

效果

生成图片特征

C# Onnx Chinese CLIP 通过一句话从图库中搜出来符合要求的图片_人工智能

查找踢足球的小孩

C# Onnx Chinese CLIP 通过一句话从图库中搜出来符合要求的图片_深度学习_02

测试图片

C# Onnx Chinese CLIP 通过一句话从图库中搜出来符合要求的图片_人工智能_03

模型信息

image_model.onnx

Inputs
-------------------------
name:image
tensor:Float[1, 3, 224, 224]
---------------------------------------------------------------

Outputs
-------------------------
name:unnorm_image_features
tensor:Float[1, 512]
---------------------------------------------------------------

text_model.onnx

Inputs
-------------------------
name:text
tensor:Int64[1, 52]
---------------------------------------------------------------

Outputs
-------------------------
name:unnorm_text_features
tensor:Float[1, 512]
---------------------------------------------------------------

项目

C# Onnx Chinese CLIP 通过一句话从图库中搜出来符合要求的图片_人工智能_04

代码

Form1.cs

 
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Windows.Forms;
 
namespace Onnx_Demo
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
 
        Clip mynet = new Clip("model/image_model.onnx", "model/text_model.onnx", "model/myvocab.txt");
 
        float[] imagedir_features;
        string image_dir = "test_img";
        StringBuilder sb = new StringBuilder();
 
        private void button2_Click(object sender, EventArgs e)
        {
            //特征向量 可以存二进制文件或者向量数据库
            imagedir_features = mynet.generate_imagedir_features(image_dir);
            txtInfo.Text = "生成完成!";
            txtInfo.Text += "有" + mynet.imgnum + "张图片,特征向量长度=" + imagedir_features.Length;
        }
 
        private void button3_Click(object sender, EventArgs e)
        {
            if (imagedir_features == null)
            {
                MessageBox.Show("请先生成图片特征!");
                return;
            }
 
            sb.Clear();
            txtInfo.Text = "";
            lblInfo.Text = "";
            pictureBox1.Image = null;
 
            string input_text = txt_input_text.Text;
            if (string.IsNullOrEmpty(input_text))
            {
                return;
            }
            List<Dictionary<string, float>> top5imglist = mynet.input_text_search_image(input_text, imagedir_features, mynet.imglist);
            sb.AppendLine("top5:");
            foreach (var item in top5imglist)
            {
                sb.AppendLine(Path.GetFileName(item.Keys.First()) + "  相似度:" + item[item.Keys.First()].ToString("F2"));
            }
 
            txtInfo.Text = sb.ToString();
            lblInfo.Text = Path.GetFileName(top5imglist[0].Keys.First());
            pictureBox1.Image = new Bitmap(top5imglist[0].Keys.First());
 
        }
 
        private void Form1_Load(object sender, EventArgs e)
        {
 
        }
    }
}

Clip.cs

public class Clip
    {
        int inpWidth = 224;
        int inpHeight = 224;
        float[] mean = new float[] { 0.48145466f, 0.4578275f, 0.40821073f };
        float[] std = new float[] { 0.26862954f, 0.26130258f, 0.27577711f };
 
        int context_length = 52;
        int len_text_feature = 512;
 
        Net net;
        float[] image_features_input;
 
        SessionOptions options;
        InferenceSession onnx_session;
        Tensor<long> input_tensor;
        List<NamedOnnxValue> input_container;
        IDisposableReadOnlyCollection<DisposableNamedOnnxValue> result_infer;
        DisposableNamedOnnxValue[] results_onnxvalue;
        Tensor<float> result_tensors;
 
        TokenizerBase tokenizer;
 
        int[] text_tokens_input;
        float[,] text_features_input;
 
        public int imgnum = 0;
        public List<string> imglist = new List<string>();
 
        public Clip(string image_modelpath, string text_modelpath, string vocab_path)
        {
            net = CvDnn.ReadNetFromOnnx(image_modelpath);
 
            // 创建输出会话,用于输出模型读取信息
            options = new SessionOptions();
            options.LogSeverityLevel = OrtLoggingLevel.ORT_LOGGING_LEVEL_INFO;
            options.AppendExecutionProvider_CPU(0);// 设置为CPU上运行
            // 创建推理模型类,读取本地模型文件
            onnx_session = new InferenceSession(text_modelpath, options);//model_path 为onnx模型文件的路径
            // 创建输入容器
            input_container = new List<NamedOnnxValue>();
 
            load_tokenizer(vocab_path);
 
        }
 
        void load_tokenizer(string vocab_path)
        {
 
            tokenizer = new TokenizerClipChinese();
            tokenizer.load_tokenize(vocab_path);
            text_tokens_input = new int[1024 * context_length];
        }
 
        Mat normalize_(Mat src)
        {
            Cv2.CvtColor(src, src, ColorConversionCodes.BGR2RGB);
 
            Mat[] bgr = src.Split();
            for (int i = 0; i < bgr.Length; ++i)
            {
                bgr[i].ConvertTo(bgr[i], MatType.CV_32FC1, 1.0 / (255.0 * std[i]), (0.0 - mean[i]) / std[i]);
            }
 
            Cv2.Merge(bgr, src);
 
            foreach (Mat channel in bgr)
            {
                channel.Dispose();
            }
 
            return src;
        }
 
        unsafe void generate_image_feature(Mat srcimg)
        {
            Mat temp_image = new Mat();
            Cv2.Resize(srcimg, temp_image, new Size(inpWidth, inpHeight), 0, 0, InterpolationFlags.Cubic);
            Mat normalized_mat = normalize_(temp_image);
            Mat blob = CvDnn.BlobFromImage(normalized_mat);
            net.SetInput(blob);
            //模型推理,读取推理结果
            Mat[] outs = new Mat[1] { new Mat() };
            string[] outBlobNames = net.GetUnconnectedOutLayersNames().ToArray();
            net.Forward(outs, outBlobNames);
            float* ptr_feat = (float*)outs[0].Data;
            int len_image_feature = outs[0].Size(1);  //忽略第0维batchsize=1, len_image_feature是定值512,跟len_text_feature相等的, 也可以写死在类成员变量里
            image_features_input = new float[len_image_feature];
            float norm = 0.0f;
            for (int i = 0; i < len_image_feature; i++)
            {
                norm += ptr_feat[i] * ptr_feat[i];
            }
            norm = (float)Math.Sqrt(norm);
            for (int i = 0; i < len_image_feature; i++)
            {
                image_features_input[i] = ptr_feat[i] / norm;
            }
        }
 
        unsafe void generate_text_feature(List<string> texts)
        {
            List<List<int>> text_token = new List<List<int>>(texts.Count);
            for (int i = 0; i < texts.Count; i++)
            {
                text_token.Add(new List<int>());
            }
 
            for (int i = 0; i < texts.Count; i++)
            {
                tokenizer.encode_text(texts[i], text_token[i]);
            }
 
            if (text_token.Count * context_length > text_tokens_input.Length)
            {
                text_tokens_input = new int[text_token.Count * context_length];
            }
 
            foreach (int i in text_tokens_input) { text_tokens_input[i] = 0; }
 
            for (int i = 0; i < text_token.Count; i++)
            {
                if (text_token[i].Count > context_length)
                {
                    Console.WriteLine("text_features index " + i + " ,bigger than " + context_length + "\n");
                    continue;
                }
                for (int j = 0; j < text_token[i].Count; j++)
                {
                    text_tokens_input[i * context_length + j] = text_token[i][j];
                }
 
            }
 
            int[] text_token_shape = new int[] { 1, context_length };
 
            text_features_input = new float[text_token.Count, len_text_feature];
 
            long[] text_tokens_input_64 = new long[texts.Count * context_length];
            for (int i = 0; i < text_tokens_input_64.Length; i++)
            {
                text_tokens_input_64[i] = text_tokens_input[i];
            }
 
            for (int i = 0; i < text_token.Count; i++)
            {
                input_tensor = new DenseTensor<long>(text_tokens_input_64, new[] { 1, 52 });
                input_container.Clear();
                input_container.Add(NamedOnnxValue.CreateFromTensor("text", input_tensor));
 
                //运行 Inference 并获取结果
                result_infer = onnx_session.Run(input_container);
 
                // 将输出结果转为DisposableNamedOnnxValue数组
                results_onnxvalue = result_infer.ToArray();
 
                // 读取第一个节点输出并转为Tensor数据
                result_tensors = results_onnxvalue[0].AsTensor<float>();
 
                float[] text_feature_ptr = results_onnxvalue[0].AsTensor<float>().ToArray();
 
                float norm = 0.0f;
                for (int j = 0; j < len_text_feature; j++)
                {
                    norm += text_feature_ptr[j] * text_feature_ptr[j];
                }
                norm = (float)Math.Sqrt(norm);
                for (int j = 0; j < len_text_feature; j++)
                {
                    text_features_input[i, j] = text_feature_ptr[j] / norm;
                }
 
            }
        }
 
        void softmax(float[] input)
        {
            int length = input.Length;
            float[] exp_x = new float[length];
            float maxVal = input.Max();
            float sum = 0;
            for (int i = 0; i < length; i++)
            {
                float expval = (float)Math.Exp(input[i] - maxVal);
                exp_x[i] = expval;
                sum += expval;
            }
            for (int i = 0; i < length; i++)
            {
                input[i] = exp_x[i] / sum;
            }
        }
 
        int[] argsort_ascend(float[] array)
        {
            int array_len = array.Length;
            int[] array_index = new int[array_len];
            for (int i = 0; i < array_len; ++i)
            {
                array_index[i] = i;
            }
 
            var temp = array_index.ToList();
 
            temp.Sort((pos1, pos2) =>
             {
 
                 if (array[pos1] < array[pos2])
                 {
                     return -1;
                 }
                 else if (array[pos1] == array[pos2])
                 {
                     return 0;
                 }
                 else
                 {
                     return 0;
                 }
 
             });
 
            return temp.ToArray();
        }
 
        public List<Dictionary<string, float>> input_text_search_image(string text, float[] image_features, List<string> imglist)
        {
 
            int imgnum = imglist.Count;
            List<string> texts = new List<string> { text };
 
            generate_text_feature(texts);
 
            float[] logits_per_image = new float[imgnum];
 
            for (int i = 0; i < imgnum; i++)
            {
                float sum = 0;
                for (int j = 0; j < len_text_feature; j++)
                {
                    sum += image_features[i * len_text_feature + j] * text_features_input[0, j]; //图片特征向量跟文本特征向量做内积
                }
                logits_per_image[i] = 100 * sum;
            }
 
            softmax(logits_per_image);
 
            int[] index = argsort_ascend(logits_per_image);
 
            List<Dictionary<string, float>> top5imglist = new List<Dictionary<string, float>>(5);
 
            for (int i = 0; i < 5; i++)
            {
                int ind = index[imgnum - 1 - i];
                Dictionary<string, float> result = new Dictionary<string, float>();
                result.Add(imglist[ind], logits_per_image[ind]);
                top5imglist.Add(result);
            }
            return top5imglist;
        }
 
        public float[] generate_imagedir_features(string image_dir)
        {
 
            imglist = Common.listdir(image_dir);
            imgnum = imglist.Count;
            Console.WriteLine("遍历到" + imgnum + "张图片");
 
            float[] imagedir_features = new float[0];
 
            for (int i = 0; i < imgnum; i++)
            {
                string imgpath = imglist[i];
 
                Mat srcimg = Cv2.ImRead(imgpath);
 
                generate_image_feature(srcimg);
 
                imagedir_features = imagedir_features.Concat(image_features_input).ToArray();
 
                srcimg.Dispose();
            }
 
            return imagedir_features;
 
        }
 
    }


标签:Chinese,CLIP,C#,text,image,float,int,new,input
From: https://blog.51cto.com/lw112190/9138739

相关文章

  • AWS Simple Email Service (SES) 实战指南
    AmazonSimpleEmailService(SES)是一项强大的电子邮件发送服务,适用于数字营销、应用程序通知以及事务性邮件。在这个实战指南中,我们将演示如何设置AWSSES并通过几个示例展示其用法。设置AWSSES1.创建AWS账户首先,您需要创建一个AWS账户并登录AWS管理控制台。2.访问......
  • 深入了解Pytest中的Mocking:简化测试,避免依赖问题
    在软件开发中,测试是确保代码质量的关键步骤之一。而在测试中,经常需要模拟(Mock)一些对象或函数,以确保测试的独立性和可靠性。在Pytest中,Mocking是一个强大的工具,能够简化测试过程,避免对外部依赖的影响。什么是Mocking?Mocking是一种用于测试的技术,它允许我们替代实际对象或函数,以便模......
  • allegro 中如何对任意对象进行镜像mirror操作 Allegro PCB17.2+
    相信使用cadence套件的工程师都知道这块EDA工具的效率和功能时十分强大的。但入门这款工具,相对来讲需要花费的时间和精力时比较多的。allegro提供的众多强大的功能,但这也是这个工具入门不那么容易的一个原因。今天记录一个在布局过程中很实用的一个小功能:AdvancedMirror高级镜......
  • 图解Kubernetes的服务(Service)
    pod准备:不要直接使用和管理Pods:当使用ReplicaSet水平扩展scale时,Pods可能被terminated当使用Deployment时,去更新DockerImageVersion,旧Pods会被terminated,然后创建新Pods0啥是服务(Service)Kubernetes中Service是将运行在一个或一组[Pod]上的网络应用程序公开为网络......
  • Ceph RBD和QEMU块设备qos测试
    微信公众号:运维开发故事作者:wanger关于ceph的qosCeph,作为一个高度可扩展的分布式存储系统,已经成为云计算和大数据时代的关键基石。随着企业和组织对数据存储的需求日益增长,Ceph通过其强大的特性,如可靠性、伸缩性和性能,满足了这些需求。然而,随着集群规模的扩大和工作负载的多样性,如......
  • Linux下PCI设备驱动开发详解(八)
    Linux下PCI设备驱动开发详解(八)RIFFA的Linux驱动文件夹下有6个C源码文件,riffa_driver.c、riffa_driver.h、circ_queue.c、circ_queue.h、riffa.c、riffa.h。其中riffa.c和riffa.h不属于驱动源码,它们是系统函数调用驱动封装的一层接口,属于用户态应用程序的一部分。在讲解riffa之前,我......
  • 数据讲述中国故事!和鲸助力中国综合社会调查(CGSS)数据分析与可视化大赛圆满收官
    中国综合社会调查(ChineseGeneralSocialSurvey,CGSS)始于2003年,由中国人民大学中国调查与数据中心(NSRC)常年负责其相关实施工作,作为我国最早具全国性、综合性、连续性的学术社会调查项目,CGSS以其高质量、连续性的数据见证并记录着中国社会现代化建设的发展之路与所获成就。2023......
  • Hadoop 的 ResourceManager进程占用 CPU 100% 问题排查过程
    1.top命令查看进程占用CPU情况top2.查找该进程号(22054)对应的服务方式一:top命令输入后,再按键盘中的“c”字母即可查看方式二:使用:ps-ef|grepPID命令查看ps-ef|grep220543.找到该进程中占用CPU最高的线程top-Hp220544.将线程的ID转换为16进制(用于排查、匹......
  • 优化CentOS 7.6的HTTP隧道代理网络性能
    在CentOS7.6上,通过HTTP隧道代理优化网络性能是一项复杂且细致的任务。首先,我们要了解HTTP隧道代理的工作原理:通过建立一个安全的隧道,HTTP隧道代理允许用户绕过某些网络限制,提高数据传输的速度和安全性。然而,由于数据需要在中间节点进行转发,因此可能会引入额外的延迟。优化网络性能......
  • 无涯教程-Redis - ZREMRANGEBYSCORE 命令函数
    RedisZREMRANGEBYSCORE命令删除存储在键中的排序集中的所有元素,这些元素的分数介于最小和最大(含)之间。ZREMRANGEBYSCORE-返回值返回删除的元素数量。ZREMRANGEBYSCORE-语法以下是RedisZREMRANGEBYSCORE命令的基本语法。redis127.0.0.1:6379>ZREMRANGEBYSCORE......