RK3568笔记二:部署手写数字识别模型

news2024/11/17 14:38:33

若该文为原创文章,转载请注明原文出处。

环境搭建参考RK3568笔记一:RKNN开发环境搭建-CSDN博客

一、介绍

部署手写数字识别模型,使用手写数字识别(mnist)数据集训练了一个 LENET 的五层经典网络模型。Lenet是我们的深度学习入门的必学模型,是深度学习领域中的经典卷积神经网络(CNN)架构之一。

过程分为:训练,导出ONNX,转化RKNN,测试

二、训练

数据集训练我是在AutoDL上训练的,AutoDL配置如下:

1、创建虚拟环境

 conda create -n LeNet5_env python==3.8

2、安装轮子

Previous PyTorch Versions | PyTorch

根据官方PyTorch,安装pytorch,使用的是CPU版本,其他版本自行安装,安装命令:

pip install torch==1.7.1+cu110 torchvision==0.8.2+cu110 torchaudio==0.7.2 -f https://download.pytorch.org/whl/torch_stable.html
 -i https://pypi.tuna.tsinghua.edu.cn/simple
pip install matplotlib -i https://pypi.tuna.tsinghua.edu.cn/simple
pip install opencv-python -i https://pypi.tuna.tsinghua.edu.cn/simple

3、数据集下载

http://yann.lecun.com/exdb/mnist/train-images-idx3-ubyte.gz
http://yann.lecun.com/exdb/mnist/train-labels-idx1-ubyte.gz
http://yann.lecun.com/exdb/mnist/t10k-images-idx3-ubyte.gz
http://yann.lecun.com/exdb/mnist/t10k-labels-idx1-ubyte.gz

4、训练

train.py

#!/usr/bin/env python3
import torch
import torch.nn.functional as F
import torch.optim as optim
from   torchvision import datasets , transforms
from   torch.utils.data import  DataLoader
#import cv2
import numpy as np
from simple_net import SimpleModel

#hyperparameter
BATCH_SIZE = 16
DEVICE     = torch.device("cuda" if torch.cuda.is_available() else "cpu")
#DEVICE     = torch.device("cuda")
EPOCH      = 100



#define training ways
def train_model(model,device,train_loader,optimizer,epoch):
    #training
    model.train()
    for batch_index,(data,target) in enumerate(train_loader):
        #deploy to  device
        data,target =data.to(device),target.to(device)
        #init gradient
        optimizer.zero_grad()
        #training results
        output = model(data)
        #calulate loss
        loss = F.cross_entropy(output,target)
        #find the best score's index
        #pred = output.max(1,keepdim = True)
        #backword
        loss.backward()
        optimizer.step()
        if batch_index % 3000 ==0:
            print("Train Epoch :{} \t Loss :{:.6f}".format(epoch,loss.item()))

#test
def test_model(model,device,test_loader):
    model.eval()
    #correct rate
    correct = 0.0
    #test loss
    test_loss=0
    with torch.no_grad(): #do not caculate gradient as well as backward
        for data,target in test_loader:
            datra,target = data.to(device),target.to(device)
            #test data
            output = model(data.to(device))
            #caculte loss
            test_loss += F.cross_entropy(output,target).item()
            #find the index of the best score
            pred =output.max(1,keepdim=True)[1]
            # 累计正确率
            correct += pred.eq(target.view_as(pred)).sum().item()
        test_loss /=len(test_loader.dataset)
        print("TEST - average loss : {: .4f}, Accuracy :{:.3f}\n".format(
            test_loss,100.0*correct /len(test_loader.dataset)))

def main():
    #pipeline
    pipeline = transforms.Compose([
        transforms.ToTensor(),
        transforms.Normalize((0.1307,),(0.3081,))
    ])

    #download dataset
    train_set    = datasets.MNIST("data",train=True,download=False,transform=pipeline)
    test_set     = datasets.MNIST("data",train=False,download=False,transform=pipeline)
    #load dataset
    train_loader = DataLoader(train_set,batch_size=BATCH_SIZE,shuffle=True)
    test_loader  = DataLoader(test_set,batch_size=BATCH_SIZE,shuffle=True)

    #show dataset
    with open("./data/MNIST/raw/train-images-idx3-ubyte","rb") as f:
        file =f.read()
    image1 = [int(str(item).encode('ascii'),16) for item in file[16:16+784]]
    #print(image1)
    image1_np=np.array(image1,dtype=np.uint8).reshape(28,28,1)
    #print(image1_np.shape)
    #cv2.imwrite("test.jpg",image1_np)

    #optim
    model     = SimpleModel().to(DEVICE)
    optimizer = optim.Adam(model.parameters())
    #9 recall function to train
    for epoch in range(1,EPOCH+1):
        train_model(model,DEVICE,train_loader,optimizer,epoch)
        test_model(model,DEVICE,test_loader)
    # Create a SimpleModel and save its weight in the current directory
    model_wzw = SimpleModel() 
    torch.save(model.state_dict(), "weight.pth")

if __name__ == "__main__":
    main()

执行python train.py后开始训练,这里需要注意数据集的路径。

训练结束后,会生成一个weight.pth模型。

三、转成ONNX模型

1、转成onnx模型

export_onnx.py

#!/usr/bin/env python3
import torch
from simple_net import SimpleModel


# Load the pretrained model and export it as onnx
model = SimpleModel()
model.eval()
checkpoint = torch.load("weight.pth", map_location="cpu")
model.load_state_dict(checkpoint)

# Prepare input tensor
input = torch.randn(1, 1, 28, 28, requires_grad=True)#batch size-1 input cahnne-1 image size 28*28

# Export the torch model as onnx
torch.onnx.export(model,
            input,
            'model.onnx', # name of the exported onnx model
            opset_version=12,
            export_params=True,
            do_constant_folding=True)

这里需要注意的是算子,在rknn2提及。

使用执行上面代码把weight.pth转成onnx模型。

2、测试onnx模型

test_onnx.py

#!/usr/bin/env python3
import torch
import onnxruntime
import numpy as np
import cv2
import time

# 加载 ONNX 模型
onnx_model = onnxruntime.InferenceSession("model.onnx", providers=['TensorrtExecutionProvider', 'CUDAExecutionProvider', 'CPUExecutionProvider'])
num = -1 
inference_time =[0]
print("--0-5 1-0 2-4 3-1 4-9 5-2 6-1 7-3 8-1 9-4 for example:if num =9 the pic's num is 4")

# 准备输入数据
#show dataset
with open("./data/MNIST/raw/train-images-idx3-ubyte","rb") as f:
    file = f.read()
for i in range(8000):
    num = num+1  
    i = 16+784*num
    image1 = [int(str(item).encode('ascii'),16) for item in file[i:i+784]]
    #print(image1)
    input_data = np.array(image1,dtype=np.float32).reshape(1,1,28,28)
    image1_np = np.array(image1,dtype=np.uint8).reshape(28,28,1)
    file_name = "test_%d.jpg"%num
    #cv2.imwrite(file_name,image1_np)
    #print(input_data)
    input_name = onnx_model.get_inputs()[0].name

    # inference 
    start_time = time.time()
    output = onnx_model.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 ", num, pred,"use time ",inference_time[num]*1000,"ms")

mean = (sum(inference_time) / len(inference_time))*1000
print("loop ",num+1,"times","average time",mean,"ms")

执行上面代码,会生成model.onnx模型

四、转成RKNN并测试

训练和导出onnx是在租用的服务器上操作,转成RKNN模型需要在搭建好的虚拟机里操作。

rknn-toolkit2-master/examples/onnx/目录下新建一个03_RK3568_MNIST文件夹

主要要两个文件model.onnx和test.py,model.onnx为上面导出的模型,test.py代码如下:

test.py

import os
import urllib
import traceback
import time
import sys
import numpy as np
import cv2
from rknn.api import RKNN
 
ONNX_MODEL = 'model.onnx'
RKNN_MODEL = 'model.rknn'
 
if __name__ == '__main__':
 
    # Create RKNN object
    rknn = RKNN()
 
    # pre-process config
    print('--> Config model')
    rknn.config(target_platform='rk3568')
    print('done')
 
    # Load ONNX model
    print('--> Loading model')
    ret = rknn.load_onnx(model=ONNX_MODEL)
    if ret != 0:
        print('Load model failed!')
        exit(ret)
    print('done')
 
    # Build model
    print('--> Building model')
    ret = rknn.build(do_quantization=False)
    if ret != 0:
        print('Build model failed!')
        exit(ret)
    print('done')
 
    # Export RKNN model
    print('--> Export RKNN model')
    ret = rknn.export_rknn(RKNN_MODEL)
    if ret != 0:
        print('Export resnet50v2.rknn failed!')
        exit(ret)
    print('done')
 
    # Set inputs
    with open("./data/MNIST/raw/train-images-idx3-ubyte","rb") as f:
        file=f.read()
        num=100
        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,28,28,1)
    #save the image
    image1_np = np.array(image1,dtype=np.uint8).reshape(28,28,1)
    file_name = "test.jpg"
    cv2.imwrite(file_name,image1_np)
 
    # init runtime environment
    print('--> Init runtime environment')
    ret = rknn.init_runtime()
    if ret != 0:
        print('Init runtime environment failed')
        exit(ret)
    print('done')
 
    # Inference
    print('--> Running model')
    outputs = rknn.inference(inputs=input_data)
    x = outputs[0]
    output = np.exp(x)/np.sum(np.exp(x))
    outputs = np.argmax([output])
    print("----------outputs----------",outputs)
    print('done')
 
    rknn.release()

运行前要先进入conda的虚拟环境

conda activate rknn2_env

激活环境后,运行转换及测试

python test.py

运行结束后,会在当前目录下生成rknn模型,并测试正常。

五、部署到开发板并测试

测试使用的是CPP方式,我直接拷贝了yolov5的一份代码,替换了main.cc文件,重新编译

main.cc放在src里,model放的是模型,其他文件都是正点原子提供的,可以修改,也可以不改

编译后文件在install里

把rknn_mnist_demo和模型上传到开发板,还有数据集./model/data/MNIST/raw/train-images-idx3-ubyte也通过adb方式上传到开发板,运行测试和在上面测试onnx结果是相同的。

main.cc

/*-------------------------------------------
                Includes
-------------------------------------------*/
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <fstream>
#include <iostream>
#include <sys/time.h>
 
#include "opencv2/core/core.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/imgcodecs.hpp"
#include "rknn_api.h"
 
using namespace std;
using namespace cv;
 
const int MODEL_IN_WIDTH = 28;
const int MODEL_IN_HEIGHT = 28;
const int MODEL_CHANNEL = 1;
 
int ret=0;
int loop_count=8000;
 
/*-------------------------------------------
                  Functions
-------------------------------------------*/
static inline int64_t getCurrentTimeUs()
{
    struct timeval tv;
    gettimeofday(&tv, NULL);
    return tv.tv_sec * 1000000 + tv.tv_usec;
}
static void dump_tensor_attr(rknn_tensor_attr* attr)  //dump tensor message
{
  printf("  index=%d, name=%s, n_dims=%d, dims=[%d, %d, %d, %d], n_elems=%d, size=%d, fmt=%s, type=%s, qnt_type=%s, "
         "zp=%d, scale=%f\n",
         attr->index, attr->name, attr->n_dims, attr->dims[0], attr->dims[1], attr->dims[2], attr->dims[3],
         attr->n_elems, attr->size, get_format_string(attr->fmt), get_type_string(attr->type),
         get_qnt_type_string(attr->qnt_type), attr->zp, attr->scale);
}
 
static unsigned char *load_model(const char *filename, int *model_size) //load model
{
    FILE *fp = fopen(filename, "rb");
    if(fp == nullptr) {
        printf("fopen %s fail!\n", filename);
        return NULL;
    }
    fseek(fp, 0, SEEK_END);
    int model_len = ftell(fp);
    unsigned char *model = (unsigned char*)malloc(model_len);
    fseek(fp, 0, SEEK_SET);
    if(model_len != fread(model, 1, model_len, fp)) {
        printf("fread %s fail!\n", filename);
        free(model);
        return NULL;
    }
    *model_size = model_len;
    if(fp) {
        fclose(fp);
    }
    return model;
}
 
void Bubble_sort(float *buffer)
{
    float temp=0;
    for(int i = 0; i < 10; i++){
        for(int j=0;j<10-i-1;j++){
            if(buffer[j]>buffer[j+1]){
                temp=buffer[j];
                buffer[j]=buffer[j+1];
                buffer[j+1]=temp;
            }
        }
    }
}
 
void Load_data(int num,unsigned char * input_image)
{
    int j=16+784*num;
    FILE *file = fopen("./model/data/MNIST/raw/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);
/*      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 Array_change(float input_aray[1][MODEL_IN_WIDTH][MODEL_IN_HEIGHT][MODEL_CHANNEL],unsigned char *input_image)
{
   int index=0;
    for (int i = 0; i < 1; i++) {
        for (int j = 0; j < MODEL_IN_WIDTH; j++) {
            for (int k = 0; k < MODEL_IN_HEIGHT; k++) {
                for (int l = 0; l < MODEL_CHANNEL; l++) {
                    input_aray[i][j][k][l] = (float)input_image[index++];
                    if(input_aray[i][j][k][l]==0){
                    }
                }
            }
 
        }
 
    } 
}
void print_Array(int num,float *buffer)
{
    for(int i =0;i<num;i++){
        printf("%f\n",buffer[i]);
    }
}
 
void get_tensor_message(rknn_context ctx,rknn_tensor_attr *attrs,uint32_t num,int io)
{
    for (int i = 0; i < num; i++) {
        attrs[i].index = i;
        if(io==1){
        ret = rknn_query(ctx, RKNN_QUERY_INPUT_ATTR, &(attrs[i]), sizeof(rknn_tensor_attr));
        }
        else{
            ret = rknn_query(ctx, RKNN_QUERY_OUTPUT_ATTR, &(attrs[i]), sizeof(rknn_tensor_attr));
        }
        if (ret != RKNN_SUCC) {
            printf("rknn_query fail! ret=%d\n", ret);
        }
        dump_tensor_attr(&(attrs[i]));
    }
}
/*-------------------------------------------
                  Main Function
-------------------------------------------*/
int main(int argc, char** argv)
{
    int64_t time_sum[loop_count]={};
    int64_t sum=0;
    int num =-1;
       
    rknn_context ctx;
    int model_len = 0;
    unsigned char *model;
    rknn_output outputs[1];
    rknn_input inputs[1];
    const char *model_path = argv[1];
    if (argc != 2)
    {
        printf("Usage: %s <rknn model>  \n", argv[0]);
        return -1;
    }
    // Load RKNN Model
    printf("-------------load rknn model\n");
    model = load_model(model_path, &model_len);
    ret = rknn_init(&ctx, model, model_len, RKNN_FLAG_COLLECT_PERF_MASK, NULL);
    //ret = rknn_init(&ctx, model, model_len, 0, NULL);
    if(ret < 0) {
        printf("rknn_init fail! ret=%d\n", ret);
        return -1;
    }
    printf("--------------done\n");
 
    // Get Model Input and Output Info
    rknn_input_output_num io_num;
    ret = rknn_query(ctx, RKNN_QUERY_IN_OUT_NUM, &io_num, sizeof(io_num));
    if (ret != RKNN_SUCC) {
        printf("rknn_query fail! ret=%d\n", ret);
        return -1;
    }
    printf("model input num: %d, output num: %d\n", io_num.n_input, io_num.n_output);
    //get input tensor message
    printf("input tensors:\n");
    rknn_tensor_attr input_attrs[io_num.n_input];
    memset(input_attrs, 0, sizeof(input_attrs));
    get_tensor_message(ctx,input_attrs,io_num.n_input,1);
    
    //get output tensor message
    printf("output tensors:\n");
    rknn_tensor_attr output_attrs[io_num.n_output];
    memset(output_attrs, 0, sizeof(output_attrs));
    get_tensor_message(ctx,output_attrs,io_num.n_output,0);
    for(int i=0;i<loop_count;i++){
        num++;
        printf("-------------------------------------loop %d \n",i);
        //load data
        unsigned char input_image[784]={};
        float input_aray[1][MODEL_IN_WIDTH][MODEL_IN_HEIGHT][MODEL_CHANNEL]={};
        Load_data(num,input_image);
        Array_change(input_aray,input_image);
 
        // Set Input Data
        memset(inputs, 0, sizeof(inputs));
        inputs[0].index = 0;
        inputs[0].type = RKNN_TENSOR_FLOAT32;
        inputs[0].size = 28*28*4;
        inputs[0].fmt = RKNN_TENSOR_NHWC;
        inputs[0].buf = input_aray;
        ret = rknn_inputs_set(ctx, 1, inputs);
        if(ret < 0) {
            printf("rknn_input_set fail! ret=%d\n", ret);
            return -1;
        }
 
        // Run
        printf("--------------rknn_run\n");
        int64_t start_us = getCurrentTimeUs();
        ret = rknn_run(ctx, nullptr);
        if(ret < 0) {
            printf("rknn_run fail! ret=%d\n", ret);
            return -1;
        }
        time_sum[i] = getCurrentTimeUs() - start_us;
        sum = sum+time_sum[i];
        printf(": Elapse Time = %.2fms sum %.2f \n", time_sum[i] / 1000.f,sum / 1000.f);
 
/*         _rknn_perf_detail perf_run_detail;
        ret = rknn_query(ctx, RKNN_QUERY_PERF_DETAIL, &perf_run_detail, sizeof(perf_run_detail));
        printf("---------the detail of time is %s %d\n",perf_run_detail.perf_data,perf_run_detail.data_len);
        rknn_perf_run perf_run;
        ret = rknn_query(ctx, RKNN_QUERY_PERF_RUN, &perf_run, sizeof(perf_run));
        printf("---------the sum of time is %d us\n",perf_run.run_duration);  */
 
        // Get Output
        memset(outputs, 0, sizeof(outputs));
        outputs[0].want_float = 1;
        ret = rknn_outputs_get(ctx, 1, outputs, NULL);
        if(ret < 0) {
            printf("rknn_outputs_get fail! ret=%d\n", ret);
            return -1;
        }
 
        // Post Process
        float *buffer = (float *)outputs[0].buf;
        float buffer_copy[]={};
        for(int i=0;i<10;i++){
            buffer_copy[i]=buffer[i];      
        }
        Bubble_sort(buffer);
        for(int i =0;i<10;i++){
            if(buffer_copy[i]==buffer[9]){
                printf("----------the pic value is %d \n",i);
            }
        }
        
    }
    // Release rknn_outputs
    ret=rknn_outputs_release(ctx, 1, outputs);
    if(ret < 0) {
        printf("rknn_outputs_release fail! ret=%d\n", ret);
        return -1;
    }
    printf("--------- loop time : %d average time is %.2f ms\n",loop_count,(sum / 1000.f)/loop_count);
    // Release
    if(ctx >= 0) {
        rknn_destroy(ctx);
    }
    if(model) {
        free(model);
    }
     
 
    return 0;
}

如有侵权,或需要完整代码,请及时联系博主。

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

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

相关文章

Step2:Java内存区域与内存溢出异常

文章目录 1.1 概述1. 2 运行时数据区域1. 3 HotSpot虚拟机对象探秘1. 4 作业:OutOfMemoryError异常体验1.1 概述 对于Java程序员来说,再虚拟机自动内存管理机制的帮助下,不再需要为每一个new操作去写配对的delete/free代码,不容易出现内存泄露和内存溢出的问题,看起来由虚…

Jenkins 设置定时任务

1、点击项目后点击Configure 2、点击Build Triggers勾选Build periodically 3、设置规则 # 样例展示&#xff1a; # 每天的22:00 执行 0 22 * * * # 每个月的1号22:00 执行 0 22 1 * *# 每周一到周五的晚上22&#xff1a;00&#xff0c; 1-5 表示周一到周五 0 22 * * 1-5# 每…

短视频平台的那些事

短视频平台的那些事 文章目录 短视频平台的那些事1. 前言2. 概览介绍3. 业务框架4. 关键技术能力4.1 视频处理4.1.1 FFMPEG技术 4.2 视频安全&#xff0c;合规4.2.1 视频安全审核4.2.2 视频MD5校验4.2.3 视频AI指纹 4.3 视频内容理解4.3.1 视频分类4.3.2 视频标签4.3.3 视频质量…

体育场馆能源消耗监测管理平台,为场馆提供能源服务

随着能源问题的不断重视&#xff0c;体育场馆能源问题也被人们广泛的关注。为了让体育场馆的能源高效利用&#xff0c;体育场馆能源消耗监测管理平台应用而生。 该平台通过采集、监测场内数据&#xff0c;并对数据进行实时分析与反馈&#xff0c;从而帮助管理者了解到场内能源…

用 Python 进行数据分析,不懂 Python,求合适的 Python 书籍或资料推荐?

想要学好Python数据分析&#xff0c;打好基础最重要&#xff0c;学习Python语言基础语法知识&#xff0c;推荐菜鸟教程这个网站。 Python 基础教程 | 菜鸟教程 ​www.runoob.com/python/python-tutorial.html 如果觉得文字教程生硬难懂的话&#xff0c;可以看视频教学&#xf…

网络安全工程师需要学习什么?争做网络安全守护使者

文章目录 前言 一、计算机基础知识二、网络安全技术三、信息安全法律法规四、风险评估与管理五、安全运维六、渗透测试与防护七、安全知识演练八、心理承受力与逆向思维九、团队合作与沟通能力十、持续学习和自我提升十一、道德与伦理十二、综合素质与领导力 如何入门学习网络…

LeetCode 143.重排链表

题目链接 力扣&#xff08;LeetCode&#xff09;官网 - 全球极客挚爱的技术成长平台 题目解析 分析题目后我们可以直接进行模拟实现。 具体用到的就是我们之前的知识的结合&#xff0c;首先使用快慢指针找到链表的中间结点。然后将后半段链表给翻转一下&#xff0c;然后再让这…

Kotlin异常处理runCatching,getOrDefault,getOrNull run(2)

Kotlin异常处理runCatching&#xff0c;getOrDefault&#xff0c;getOrNull run&#xff08;2&#xff09; fun main(args: Array<String>) {runCatching {1 / 0 //发生异常}.getOrNull().run {println(this)}println("-")runCatching {1 / 1 //正常}.getOrNul…

2023年失业了,想学一门技术可以学什么?

有一个朋友&#xff0c;大厂毕业了&#xff0c;原本月薪估计有5w吧&#xff0c;年终奖也不错&#xff0c;所以早早的就买了房生了娃&#xff0c;一直是人生赢家的姿态。 但是今年突然就被毕业了&#xff0c;比起房货还有个几百万没还来说&#xff0c;他最想不通的是自己的价值…

“悦己经济”升温,鲜花产业如何利用软文获客

在消费结构升级的大环境下&#xff0c;人们越来越注重精神层面的追求&#xff0c;“悦己消费”正在成为主流&#xff0c;鲜花逐渐成为生活中的必需品&#xff0c;鲜花业务的不断拓宽和鲜花消费场景的丰富将会吸引更多消费者。那么在竞争激烈的鲜花产业中&#xff0c;商家们应该…

账户权限

目录 1. 文件的一般权限 1.1. 文件详细信息 1.2. 文件权限构成 示例&#xff1a; 1.3. chmod命令 1.3.1. 参数 示例&#xff1a; 扩展&#xff1a;隐藏权限(chattr a) 1.4. chown命令 示例&#xff1a; 2. 特殊权限 2.1. 概述 2.2. SUID权限 2.3. SGID 权限 2.4…

深度优先(DFS) (例子:全排列,迷宫)

深度搜索是一种计算机算法&#xff0c;用于在图或树等数据结构中查找目标节点。深度搜索从一个节点出发&#xff0c;依次遍历其所有子节点&#xff0c;直到找到目标节点或遍历完所有节点。如果找到目标节点&#xff0c;则搜索结束&#xff1b;如果遍历完所有节点仍未找到目标节…

文心一言 VS 讯飞星火 VS chatgpt (109)-- 算法导论10.1 7题

七、用go语言&#xff0c;说明如何用两个队列实现一个栈&#xff0c;并分析相关栈操作的运行时间。 文心一言&#xff1a; 在Go语言中&#xff0c;我们可以用两个队列&#xff08;queue1和queue2&#xff09;实现一个栈。以下是实现代码&#xff1a; package main import &…

拉绳位移传感器钢丝绳角度偏离过大就会减少使用寿命

拉绳位移传感器钢丝绳角度偏离过大就会减少使用寿命 拉绳位移传感器还有一种情况就是&#xff0c;如果钢丝绳在恶劣的环境中作业&#xff0c;磨损&#xff0c;挤压&#xff0c;弯折等非正常使用&#xff0c;也更容易使钢丝绳断裂。位移传感器在作业中&#xff0c;钢丝绳角度偏离…

【JavaEE初阶】 线程的状态和转移

文章目录 &#x1f332;线程的状态&#x1f340;观察线程的所有状态&#x1f38d;线程状态和状态转移的意义&#x1f38b;观察线程的状态和转移&#x1f4cc;观察 1:&#x1f4cc;观察 2:&#x1f4cc;观察-3: ⭕总结 &#x1f332;线程的状态 &#x1f340;观察线程的所有状态…

设计模式 - 解释器模式

目录 一. 前言 二. 实现 三. 优缺点 一. 前言 解释器模式&#xff08;Interpreter Pattern&#xff09;指给定一门语言&#xff0c;定义它的文法的一种表示&#xff0c;并定义一个解释器&#xff0c;该解释器使用该表示来解释语言中的句子&#xff0c;属于行为型设计模式。是…

redis 事物

Redis事务 一个队列中&#xff0c;一次性、顺序性、排他性的执行一系列命令 正常执行 放弃事务 在exec执行之前&#xff0c;报错&#xff0c;则所有命令都不会执行 在exec执行后&#xff0c;报错&#xff0c;则其它正确的指令会执行&#xff0c;错误的命令会抛弃 watch 监…

一文搞懂二叉树先序遍历的三种方法

系列文章&#xff1a; 相关题目&#xff1a; 144. 二叉树的前序遍历 先序遍历结果为&#xff1a;1 2 4 5 3 6 7 总体上分为两种框架&#xff0c;递归框架和非递归框架&#xff0c;递归框架又分为两种思路&#xff1a;分解思路和遍历思路。 递归 1、分解思路 【分解为子问题】…

OLED透明拼接屏在乌海湖旅游区的应用探究

作为一名资深的OLED透明拼接屏工程师&#xff0c;我希望通过这篇文章来介绍一下OLED透明拼接屏在乌海这座城市中的表现&#xff0c;并对该城市的历史、景点、管辖范围进行简要介绍。 最后&#xff0c;我将讨论OLED透明拼接屏在乌海适用的行业和领域&#xff0c;并列举一些优缺…

在windows7中运行pycharm报错误“无法定位程序输入点 CreateAppContainerProfile 于动态链接库 USERENV.dll 上

截图&#xff1a; 解决办法&#xff1a; 一时不知道怎么办。一想之前是好好的&#xff0c;不知道被什么破坏了。所以恢复系统解决。