海思ss928部署手写数字识别模型

news2025/2/11 9:13:47

大致流程---------------------------------------------------------------------------------------------------------------------

模型转换----------------------------------------------------------------------------------------------------

1:准备MNIST的onnx模型---> https://kdocs.cn/l/ctULnY8mxXuE

github地址--> GitHub - warren-wzw/MNIST-pytorch

搭建好ATC的环境--> https://kdocs.cn/l/cjeQxGjfojsX

首先设置环境变量

source /home/warren/Ascend/ascend-toolkit/latest/x86_64-linux/bin/setenv.bash

转化模型

atc --model=/home/warren/Ascend/yolov5/model/yolov5s.onnx \

--soc_version=OPTG  --framework=5 \

--output=/home/warren/Ascend/yolov5/model/yolov5s \

--input_shape="input0:1,2,64,64"  

atc --model=/home/warren/ss928/NNN_PC/amct/amct_onnx/sample/MNIST/outputs/calibration/MNIST_deploy_model.onnx \

> --soc_version=OPTG  --framework=5 \

> --output=/home/warren/ss928/NNN_PC/amct/amct_onnx/sample/MNIST/outputs/calibration/MNIST \

> --input_shape="input0:1,3,640,640"

模型转化成功后得到以下文件

        

模型量化--------------------------------------------------------------------------------------------------------------

目录结构

import os
import argparse
import cv2
import numpy as np
import onnxruntime as ort
import time
import torch

import amct_onnx as amct

PATH = os.path.realpath('./')
DATA_DIR = os.path.join(PATH, 'data')
PARSER = argparse.ArgumentParser(description='amct_onnx MNIST quantization sample.')
ARGS = PARSER.parse_args()
OUTPUTS = os.path.join(PATH, 'outputs/calibration')
TMP = os.path.join(OUTPUTS, 'tmp')

def onnx_forward(onnx_model, batch_size=1, iterations=100):
    ort_session = ort.InferenceSession(onnx_model, amct.AMCT_SO)
    with open("./data/train-images-idx3-ubyte","rb") as f:
        file = f.read()
        num = -1
        j=0
        inference_time =[0]
        for j in range(100):
            num=num+1
            i = 16+784*num
            image1 = [int(str(item).encode('ascii'),16) for item in file[i:i+784]]
            input_data = np.array(image1,dtype=np.float32).reshape(1,1,28,28)
            #np.set_printoptions(linewidth=150)
            #print(input_data)
            input_name = ort_session.get_inputs()[0].name
            # inference
            start_time = time.time()
            output = ort_session.run(None, {input_name: input_data})
            end_time = time.time()
            inference_time.append(end_time - start_time)
            # 处理输出结果
            output = torch.tensor(output[0])  # 将输出转换为 PyTorch 张量
                #print(output_tensor)
            # 输出结果处理和后续操作...
            pred =np.argmax(output)
            print("------------------------The num of this pic is ",pred,"use time ",inference_time[num]*1000,"ms",j)

def main():
    model_file = './model/model.onnx'
    print('[INFO] Do original model test:')
    onnx_forward(model_file,1,1)
    config_json_file = os.path.join(TMP, 'config.json')
    skip_layers = []
    amct.create_quant_config(
            config_file=config_json_file, model_file=model_file, skip_layers=skip_layers, batch_num=1,
            activation_offset=True, config_defination=None)
    # Phase1: do conv+bn fusion, weights calibration and generate
    #         calibration model
    scale_offset_record_file = os.path.join(TMP, 'record.txt')
    modified_model = os.path.join(TMP, 'modified_model.onnx')
    amct.quantize_model(
        config_file=config_json_file, model_file=model_file, modified_onnx_file=modified_model,
        record_file=scale_offset_record_file)
    onnx_forward(modified_model, 32, 1)
    # Phase3: save final model, one for onnx do fake quant test, one
    #         deploy model for ATC
    result_path = os.path.join(OUTPUTS, 'MNIST')
    amct.save_model(modified_model, scale_offset_record_file, result_path)
    # Phase4: run fake_quant model test
    print('[INFO] Do quantized model test:')
    onnx_forward('%s_%s' % (result_path, 'fake_quant_model.onnx'), 1, 1)
if __name__ == '__main__':
    main()

推理代码编写---------------------------------------------------------------------------------------------------

将官方的sample复制一份改为MNIST,目录结构如下图所示

更改camke文件

1:添加环境变量:

export DDK_PATH=$HOME/Ascend/ascend-toolkit/latest

export NPU_HOST_LIB=$DDK_PATH/runtime/lib64/stub

2:创建build目录

mkdir -p build/intermediates/host

3:cmake ../../../src -DCMAKE_CXX_COMPILER=aarch64-mix210-linux-g++ -DCMAKE_SKIP_RPATH=TRUE

将整个MNIST文件夹拷贝至板端,添加库文件路径的环境变量

export ASCEND_GLOBAL_EVENT_ENABLE=0

export ASCEND_AACPU_KERNEL_PATH=/opt/sd/lib

export ASCEND_AICPU_KERNEL_PATH=/opt/sd/lib

export LD_LIBRARY_PATH=/opt/sd/lib

执行可执行文件main

执行成功。

代码讲解-------------------------------------------------------------------------

大致逻辑

 

main.cpp

#include "main.h"
#include "acl/acl.h"

#define INFO_LOG(fmt, ...)  fprintf(stdout, "[INFO]  " fmt "\n", ##__VA_ARGS__)
#define WARN_LOG(fmt, ...)  fprintf(stdout, "[WARN]  " fmt "\n", ##__VA_ARGS__)
#define ERROR_LOG(fmt, ...) fprintf(stderr, "[ERROR]  " fmt "\n", ##__VA_ARGS__)
const int MODEL_CHANNEL = 1;
const int MODEL_IN_WIDTH = 28;
const int MODEL_IN_HEIGHT = 28;
const int loop_count = 1000;

typedef enum Result {
    SUCCESS = 0,
    FAILED = 1
} Result;

static inline int64_t getCurrentTimeUs()
{
    struct timeval tv;
    gettimeofday(&tv, NULL);
    return tv.tv_sec * 1000000 + tv.tv_usec;
}
void Load_data(int num,unsigned char * input_image)
{
    int j=16+784*num;
    FILE *file = fopen("../data/train-images-idx3-ubyte", "rb");
    if (file == NULL) {
        printf("can't open the file!\n");
    }
    fseek(file,j,SEEK_SET);
    fread(input_image,sizeof(char),784,file);
    //print
/*     for(int i=0;i<MODEL_IN_WIDTH;i++){
        for(int j=0;j<MODEL_IN_WIDTH;j++){
            printf("%4d",input_image[i*28+j]);
        }
        printf("\n");
    }  */
    fclose(file);
}
void Bubble_sort(float *buffer,int num)
{
    float temp;
    for(int i=0; i<num;i++){
        for(int j=0; j<num-i-1;j++){
            if(buffer[j]>buffer[j+1]){
                temp = buffer[j];
                buffer[j]=buffer[j+1];
                buffer[j+1]=temp;
            }
        }
    }
}
int main()
{
/***************************************************/
/*****************define var************************/
/***************************************************/
    int num=0;
    aclError ret=1;
    const char *aclConfigPath = "../src/acl.json";
    int32_t deviceId_=0;
    aclrtContext context_=nullptr;
    aclrtStream stream_=nullptr;
    aclrtRunMode runMode;
    uint32_t modelId_=0;
    const char* modelPath = "../model/MNIST.om";
    aclmdlDesc *modelDesc_;
    aclmdlDataset *output_;
    aclmdlDataset *input_;
    void * inputDataBuffer = nullptr;
    size_t size = 784;
    void* input_image_original;
    void* time_ori;
    int64_t sum=0;
    int64_t start_time=0;
    int64_t end_time=0;
/***************************************************/
/*****************Init ACL**************************/
/***************************************************/
    ret = aclInit(aclConfigPath);
    if (ret != ACL_SUCCESS) {
        ERROR_LOG("acl init failed, errorCode = %d", static_cast<int32_t>(ret));
        return FAILED;
    }
    INFO_LOG("--------------------acl init success");
/***************************************************/
/*****************apply resource********************/
/***************************************************/
    // set device only one device    
    ret = aclrtSetDevice(deviceId_);
    if (ret != ACL_SUCCESS) {
        ERROR_LOG("acl set device %d failed, errorCode = %d", deviceId_, static_cast<int32_t>(ret));
        return FAILED;
    }
    INFO_LOG("set device %d success", deviceId_);
    // create context (set current)
    ret = aclrtCreateContext(&context_, deviceId_);
    if (ret != ACL_SUCCESS) {
        ERROR_LOG("acl create context failed, deviceId = %d, errorCode = %d",
            deviceId_, static_cast<int32_t>(ret));
        return FAILED;
    }
    INFO_LOG("create context success");
    // create stream
    ret = aclrtCreateStream(&stream_);
    if (ret != ACL_SUCCESS) {
        ERROR_LOG("acl create stream failed, deviceId = %d, errorCode = %d",
            deviceId_, static_cast<int32_t>(ret));
        return FAILED;
    }
    INFO_LOG("create stream success");
    // get run mode
    ret = aclrtGetRunMode(&runMode);
    if (ret != ACL_SUCCESS) {
        ERROR_LOG("acl get run mode failed, errorCode = %d", static_cast<int32_t>(ret));
        return FAILED;
    } 
/***************************************************/
/********load model and get infos of model**********/
/***************************************************/
    ret = aclmdlLoadFromFile(modelPath,&modelId_);
    if (ret != ACL_SUCCESS) {
        ERROR_LOG("load model from file failed, model file is %s, errorCode is %d",
            modelPath, static_cast<int32_t>(ret));
        return FAILED;
    }
    INFO_LOG("load model %s success id is %d\n", modelPath,modelId_);
    
    //get model describe
    modelDesc_ = aclmdlCreateDesc();
    if (modelDesc_ == nullptr) {
        ERROR_LOG("create model description failed");
        return FAILED;
    }
    ret = aclmdlGetDesc(modelDesc_, modelId_);
    if (ret != ACL_SUCCESS) {
        ERROR_LOG("get model description failed, modelId is %u, errorCode is %d",
            modelId_, static_cast<int32_t>(ret));
        return FAILED;
    }
    INFO_LOG("create model description success");
/***************************************************/
/******************print input tensor***************/
/***************************************************/     
/*     aclmdlIODims *dim;
    ret=aclmdlGetInputDims(modelDesc_,0,dim);
    printf("----------------in dims is %d \n",dim->dimCount);
    printf("----------------in dims name is: %s dims: \n",dim->name);
    for(int num=0;num<dim->dimCount;num++){
        printf("%d ",num,dim->dims[num]);
    }
    ret = aclmdlGetOutputDims(modelDesc_,0,dim);
    printf("----------------out dims is %d \n",dim->dimCount);
    printf("----------------out dims name is: %s dims:\n",dim->name);
    for(int num=0;num<dim->dimCount;num++){
        printf("%d \n",num,dim->dims[num]);
    } 
    deviceId_=0;*/
/***************************************************/
/******************prepare output data buffer***************/
/***************************************************/
    output_ = aclmdlCreateDataset();
    if (output_ == nullptr) {
        ERROR_LOG("can't create dataset, create output failed");
        return FAILED;
    }
    size_t outputSize = aclmdlGetNumOutputs(modelDesc_); 
    for (size_t i = 0; i < outputSize; ++i) {
        size_t modelOutputSize = aclmdlGetOutputSizeByIndex(modelDesc_, i);
        void *outputBuffer = nullptr;
        ret = aclrtMalloc(&outputBuffer, modelOutputSize, ACL_MEM_MALLOC_NORMAL_ONLY);
        if (ret != ACL_SUCCESS) {
            ERROR_LOG("can't malloc buffer, size is %zu, create output failed, errorCode is %d",
                modelOutputSize, static_cast<int32_t>(ret));
            return FAILED;
        }
        //apply output buffer
        aclDataBuffer *outputData = aclCreateDataBuffer(outputBuffer, modelOutputSize);
        if (outputData == nullptr) {
            ERROR_LOG("can't create data buffer, create output failed");
            (void)aclrtFree(outputBuffer);
            return FAILED;
        }
        ret = aclmdlAddDatasetBuffer(output_, outputData);
        if (ret != ACL_SUCCESS) {
            ERROR_LOG("can't add data buffer, create output failed, errorCode is %d",
                static_cast<int32_t>(ret));
            (void)aclrtFree(outputBuffer);
            (void)aclDestroyDataBuffer(outputData);
            return FAILED;
        }
    }
    INFO_LOG("create model output success");
/***************************************************/
/******************prepare input data***************/
/***************************************************/    
     if (modelDesc_ == nullptr) {
        ERROR_LOG("no model description, create input failed");
        return FAILED;
    }
    input_ = aclmdlCreateDataset();
    if (input_ == nullptr) {
        ERROR_LOG("can't create dataset, create input failed");
        return FAILED;
    }
    size_t modelInputSize = aclmdlGetInputSizeByIndex(modelDesc_, 0);
    ret = aclrtMalloc(&input_image_original, 784, ACL_MEM_MALLOC_NORMAL_ONLY);
    if (ret != ACL_SUCCESS) {
        ERROR_LOG("malloc device buffer failed. size is %zu, errorCode is %d",
            size, static_cast<int32_t>(ret));
        return FAILED;
    }
    unsigned char * input_image = static_cast<unsigned char*>(input_image_original);
    void* input_image_float_ori;
    ret = aclrtMalloc(&input_image_float_ori, 784*sizeof(float), ACL_MEM_MALLOC_NORMAL_ONLY);
    if (ret != ACL_SUCCESS) {
        ERROR_LOG("malloc device buffer failed. size is %zu, errorCode is %d",
            size, static_cast<int32_t>(ret));
        return FAILED;
    }
    float * input_image_float = static_cast<float*>(input_image_float_ori);;
    Load_data(num,input_image);
    for(int num=0;num<784;num++){
        input_image_float[num]=(float)input_image[num];
    }
/*     aclrtFree(input_image);
    input_image=nullptr; */
    aclDataBuffer *inputData = aclCreateDataBuffer(input_image_float, modelInputSize);
    if (inputData == nullptr) {
        ERROR_LOG("can't create data buffer, create input failed");
        return FAILED;
    }
    ret = aclmdlAddDatasetBuffer(input_, inputData);
    if (ret != ACL_SUCCESS) {
        ERROR_LOG("add input dataset buffer failed, errorCode is %d", static_cast<int32_t>(ret));
        (void)aclDestroyDataBuffer(inputData);
        inputData = nullptr;
        return FAILED;
    }
    INFO_LOG("create model input success");
    ret = aclrtMalloc(&time_ori, loop_count*sizeof(int64_t), ACL_MEM_MALLOC_NORMAL_ONLY);
        if (ret != ACL_SUCCESS) {
            ERROR_LOG("malloc device buffer failed. size is %zu, errorCode is %d",
                loop_count*sizeof(int64_t), static_cast<int32_t>(ret));
            return FAILED;
        }
        int64_t * time = static_cast<int64_t*>(time_ori);
    for(int loop_time=0;loop_time < loop_count;loop_time++){
        num++;
        Load_data(num,input_image);
        for(int loop_num=0;loop_num<784;loop_num++){
            input_image_float[loop_num]=(float)input_image[loop_num];
        }
        void* data = aclGetDataBufferAddr(inputData);
        uint32_t len = aclGetDataBufferSizeV2(inputData);     
        float *indata = NULL;  
        indata = reinterpret_cast<float*>(data);  
    /***************************************************/
    /******************inference************************/
    /***************************************************/
        start_time = getCurrentTimeUs();
        ret = aclmdlExecute(modelId_, input_, output_);
        end_time = getCurrentTimeUs();
        time[loop_time]=end_time-start_time;
        sum=sum+time[loop_time];
        printf("---Elapse Time = %.3f ms \n", (end_time-start_time) / 1000.f);   
/***************************************************/
/******************post process*********************/
/***************************************************/
        // get model output data
        aclDataBuffer* dataBuffer = aclmdlGetDatasetBuffer(output_, 0);
        void* data_1 = aclGetDataBufferAddr(dataBuffer);
        uint32_t len_1 = aclGetDataBufferSizeV2(dataBuffer);     
        float *outData = NULL;  
        outData = reinterpret_cast<float*>(data_1);  
        void* buffer_copy_ori;
        ret = aclrtMalloc(&buffer_copy_ori, len_1*sizeof(float), ACL_MEM_MALLOC_NORMAL_ONLY);
        if (ret != ACL_SUCCESS) {
            ERROR_LOG("malloc device buffer failed. size is %zu, errorCode is %d",
                len_1, static_cast<int32_t>(ret));
            return FAILED;
        }
        float * buffer_copy = static_cast<float*>(buffer_copy_ori);
        for(int i_1 = 0; i_1 < len_1/sizeof(*outData);i_1++){
            buffer_copy[i_1]=outData[i_1];
        }
        Bubble_sort(outData,len_1/sizeof(*outData));
        for(int i_2 =0;i_2<len_1/sizeof(*outData);i_2++){
            if(buffer_copy[i_2]==outData[9]){
                printf("------------------------------------------%d time the pic value is %d \n",loop_time,i_2);
            }
        } 
        aclrtFree(buffer_copy);
        buffer_copy=nullptr;
    }
    printf("--------loop %d times sum is %.4f ms average time is %.3f ms\n", loop_count,sum / 1000.f,(sum / 1000.f)/loop_count);
    aclrtFree(time);
    time=nullptr;
    aclrtFree(input_image);
    input_image=nullptr;
    aclrtFree(input_image_float);
    input_image_float=nullptr;
    
/***************************************************/
/*******************destroy model input*************/
/***************************************************/
    for(size_t i = 0; i < aclmdlGetDatasetNumBuffers(input_); ++i) {
        aclDataBuffer *dataBuffer = aclmdlGetDatasetBuffer(input_, i);
        (void)aclDestroyDataBuffer(dataBuffer);
    }
    (void)aclmdlDestroyDataset(input_);
    input_ = nullptr;
    INFO_LOG("destroy model input success");
/***************************************************/
/*********************destroy model output*********/
/***************************************************/
    for (size_t i = 0; i < aclmdlGetDatasetNumBuffers(output_); ++i) {
        aclDataBuffer* dataBuffer = aclmdlGetDatasetBuffer(output_, i);
        void* data = aclGetDataBufferAddr(dataBuffer);
        (void)aclrtFree(data);
        (void)aclDestroyDataBuffer(dataBuffer);
    }
    (void)aclmdlDestroyDataset(output_);
    output_ = nullptr;
    INFO_LOG("destroy model output success");
/***************************************************/
/******uninstall model and release resource*********/
/***************************************************/
    modelId_=1;
    ret = aclmdlUnload(modelId_);
    // releasemodelDesc_
    if (modelDesc_ != nullptr) {
        aclmdlDestroyDesc(modelDesc_);
        modelDesc_ = nullptr;
    }
    INFO_LOG("unload model success, modelId is %u", modelId_);
    // release resorce
    if (stream_ != nullptr) {
        ret = aclrtDestroyStream(stream_);
        if (ret != ACL_SUCCESS) {
            ERROR_LOG("destroy stream failed, errorCode = %d", static_cast<int32_t>(ret));
        }
        stream_ = nullptr;
    }
    INFO_LOG("end to destroy stream");

    if (context_ != nullptr) {
        ret = aclrtDestroyContext(context_);
        if (ret != ACL_SUCCESS) {
            ERROR_LOG("destroy context failed, errorCode = %d", static_cast<int32_t>(ret));
        }
        context_ = nullptr;
    }
    INFO_LOG("end to destroy context");
    
    ret = aclrtResetDevice(deviceId_);
    if (ret != ACL_SUCCESS) {
        ERROR_LOG("reset device %d failed, errorCode = %d", deviceId_, static_cast<int32_t>(ret));
    }
    INFO_LOG("end to reset device %d", deviceId_);

    ret = aclFinalize();
    if (ret != ACL_SUCCESS) {
        ERROR_LOG("finalize acl failed, errorCode = %d", static_cast<int32_t>(ret));
    }
    INFO_LOG("end to finalize acl");
}

 

执行结果:

fp32

int8

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/864497.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

QPainter - 八卦时钟

QPainter - 八卦时钟 上一篇我们在画时钟的时候&#xff0c;已经把基本的钟表指针和刻度都绘制过了 想要完成八卦时钟&#xff0c;就要绘制这个里面的八卦了。 先上个图&#xff1a; 有人和我说八卦不能转 再来一张图&#xff1a; 背景的绘制 我们需要删除之前所绘制的白色…

攻防世界-web-getit

1. 题目描述 菜鸡发现这个程序偷偷摸摸在自己的机器上搞事情&#xff0c;它决定一探究竟。 获取到文件后&#xff0c;先查看文件信息 说明是一个可执行程序&#xff0c;没啥思路&#xff0c;先逆向 2. 思路分析 逆向后&#xff0c;找到main函数&#xff0c;查看逻辑 通过逆…

智安网络|网络安全:危机下的创新与合作

随着信息技术的迅猛发展和互联网的普及&#xff0c;我们进入了一个高度网络化的社会。网络在提供便利和连接的同时&#xff0c;也带来了许多安全隐患和挑战。 一、网络安全的危险 **1.数据泄露和隐私侵犯&#xff1a;**网络上的个人和机构数据存在遭受泄露和盗取的风险&#…

C#,入门教程(42)——各种括号“()[]{}<>“的用法总结

&#xff08;成对的&#xff09;括号是各种编程语言的核心要素。很多年前就想着写这样一篇专门关于各种括号的技术文章。一直未动笔&#xff0c;因为总想着偷懒&#xff0c;但凡有一个人写了&#xff0c;就无需我动手了。可惜的是&#xff0c;等了十多年&#xff0c;也没有出现…

集成接近和环境光传感器市场调查报告

集成接近和环境光传感器在单个传感器中集成接近和环境光感应功能。该传感器广泛应用于物联网 (IoT) 设备、消费电子产品和可穿戴设备&#xff0c;集成接近和环境光传感器可以自动调整屏幕亮度并根据接近情况打开/关闭屏幕&#xff0c;以降低设备功耗。集成接近和环境光传感器广…

【嵌入式学习笔记】嵌入式入门4——独立看门狗IWDG

1.IWDG简介 IWDG的全称&#xff1a;Independent watchdog&#xff0c;即独立看门狗&#xff0c;IWDG的本能&#xff1a;产生系统复位信号的计数器IWDG的特性&#xff1a;递减的计数器&#xff0c;时钟由独立的RC振荡器提供&#xff08;可在待机和停止模式下运行&#xff09; 看…

16bit、8 通道、500kSPS、 SAR 型 ADC——MS5188N

MS5188N 是 8 通道、 16bit 、电荷再分配逐次逼近型模数 转换器&#xff0c;采用单电源供电。 MS5188N 拥有多通道、低功耗数据采集系统所需的所有 组成部分&#xff0c;包括&#xff1a;无失码的真 16 位 SAR ADC &#xff1b;用于将输入配 置为单端输入&#xff0…

水力发电厂测量装置配置选型及厂用电管理系统

NB/T 10861-2021《水力发电厂测量装置配置设计规范》对水电厂的测量装置配置做了详细要求和指导。测量装置是水力发电厂运行监测的重要环节&#xff0c;水电厂的测量主要分为电气量测量和非电量测量。电气测量指使用电的方式对电气实时参数进行测量&#xff0c;包括电流、电压、…

linux下实现生产者和消费者 pv操作

线程同步与线程安全 生产者和消费者特点图示理解编程实现测试结果 生产者和消费者 特点 1.解耦:因为多了一个缓冲区&#xff0c;所以生产者和消费者并不直接相互调用&#xff0c;这样生产者和消费者的代码发生变化&#xff0c;都不会对对方产生影响。这样其实就是把生产者和消…

使用 Gradio 构建生成式 AI 应用程序(一): 图片内容读取app

今天我们来学习DeepLearning.AI的在线课程&#xff1a;Building Generative AI Applications with Gradio&#xff0c;该课程主要讲述利用gradio来部署机器学习算法应用程序, 今天我们来学习第一课&#xff1a;Image captioning app&#xff0c;该课程主要讲述如何从图片中读取…

优秀项目团队最突出的5项重要特征

一个优秀的开发团队&#xff0c;对于软件项目而言&#xff0c;其重要性不言而喻。否则项目团队一盘散沙&#xff0c;直接影响项目准时保质保量地交付。一般从大家的认可度来说&#xff0c;优秀团队最突出的特征&#xff0c;主要集中在以下几个方面&#xff1a; 1、目标明确 优秀…

oracle连表查询in后边跟另一张表中的字符串字段

今天在做通过in进行连表查询的时候发现以下问题记录下 我的需求是A,B两张表连接查询&#xff0c;A中有一个FOOD_TYPES字段 存的值类型为1&#xff0c;2&#xff0c;3 B表中的字段是FOOD_TYPE 存的是单个数字字符串 我需要where b.food_type in a.food_types 但是无论怎么写都…

Live800:客服常用的6大提问技巧,帮助客服服务更高效

作为企业最前线的客服&#xff0c;提升服务质量是必须要做到的&#xff0c;而如何提升服务质量呢&#xff1f;其中一项关键点就是提问技巧。在客户沟通中&#xff0c;提问的方式和技巧直接影响着客户对企业服务的满意度。下面&#xff0c;本文将介绍客服常用的6大提问技巧&…

go语言的database/sql结合squirrel工具sql生成器完成数据库操作

database/sql database/sql是go语言内置数据库引擎&#xff0c;使用sql查询数据库&#xff0c;配置datasource后使用其数据库操作方法对数据库操作&#xff0c;如下&#xff1a; package mainimport ("database/sql""fmt"_ "github.com/Masterminds…

Android简单封装Matrix工具类

Android简单封装Matrix工具类 1.简介&#xff1a; Matrix 是一款微信研发并日常使用的应用性能接入框架&#xff0c;支持iOS, macOS和Android。 Matrix 通过接入各种性能监控方案&#xff0c;对性能监控项的异常数据进行采集和分析&#xff0c;输出相应的问题分析、定位与优化…

整数中1出现的次数(从1到n整数中1出现的次数)

解题思路1&#xff1a; 设定整数点&#xff08;如1、10、100等等&#xff09;作为位置点i&#xff08;对应n的各位、十位、百位等等&#xff09;&#xff0c;分别对每个数位上有多少包含1的点进行分析。 第一步&#xff1a;对n进行分割&#xff0c;分为两部分&#xff1a;高位…

JavaWeb学习|JavaBean;MVC三层架构;Filter;Listener

1.JavaBean 实体类 JavaBean有特定的写法: 必须要有一个无参构造 属性必须私有化。 必须有对应的get/set方法 用来和数据库的字段做映射 ORM; ORM:对象关系映射 表--->类 字段-->属性 行记录---->对象 2.<jsp&#xff1a;useBean 标签 3. MVC三层架构 4. Filter …

力扣301周赛C~DABC299 D、E、G

第 301 场周赛 C&#xff1a; 思路&#xff1a; 经典双指针问题&#xff0c;用i表示字符串start当前枚举到的位置&#xff0c;用j表示字符串target当前枚举到的位置&#xff1a; i从当前位置向后跑&#xff0c;跑到start串下标i之后的第一个不为_的位置 j从当前位置向后跑&a…

C语言属刷题训练【第八天】

文章目录 &#x1fa97;1、如下程序的运行结果是&#xff08; &#xff09;&#x1f4bb;2、若有定义&#xff1a; int a[2][3]; &#xff0c;以下选项中对 a 数组元素正确引用的是&#xff08; &#xff09;&#x1f9ff;3、在下面的字符数组定义中&#xff0c;哪一个有语法错…

JavaScript、TypeScript、ES5、ES6之间的联系和区别

ECMAScript&#xff1a; 一个由 ECMA International 进行标准化&#xff0c;TC39 委员会进行监督的语言。通常用于指代标准本身。JavaScript&#xff1a; ECMAScript 标准的各种实现的最常用称呼。这个术语并不局限于某个特定版本的 ECMAScript 规范&#xff0c;并且可能被用于…