AI部署这个词儿大家肯定不陌生,可能有些人还不是很清楚这个是干嘛的,但总归是听过了。近些年来,在深度学习算法已经足够卷之后,深度学习的另一个偏向于工程的方向–部署应用落地,才开始被谈论的多了起来。当然这也是大势所趋,毕竟AI算法那么多,如果用不着,只在学术圈搞研究的话没有意义。因此很多AI部署相关行业和AI芯片相关行业也在迅速发展,现在虽然已经2022年了,但我认为AI部署相关的行业还未到头,AI也远远没有普及,还有很多的场景未能落地。 随着人工智能逐渐普及,使用神经网络处理各种任务的需求越来越多,如何在生产环境中快速、稳定、高效地运行模型,成为很多公司不得不考虑的问题。不论是通过提升模型速度降低latency提高用户的使用体验,还是加速模型降低服务器预算,都是很有用的,很多公司也需要这样的人才。在经历了算法的神仙打架、诸神黄昏, 灰飞烟灭,再到现在的直接车毁人亡、人间地狱,唯有应用部署还能广大工程师留点活路。
最常见的场景,AI算法部署需要涉及三种不同的分工角色,包括算法提供者(算法商,开源算法社区,比如商汤,darknet, github上各类开源算法等等),算力平台提供者(SOC厂商,目的是提供算力平台),以及深度学习IP Vendor(比如算丰,比特大陆,芯原等等).它们的关系简单理解如下:
当然也会有些垂直类的厂商,比如RK,他既可以做神经网络加速器IP,同是也具备集成研发SOC以及部署工具开发的能力,这样的整合同时会加强它的竞争力。比较郁闷的是算法厂商,很难找到一条合适的盈利模式,纯做算法的算法尝试盈利模式单一,再加上各类AI应用场景的碎片化,这些年早已风光不再,生存比较艰难。
扯了这么多,主要是想说明AI部署是需要重视的专业技术方向,今天就以为全志V853部署YOLOV5模型为例,讲一点AI应用部署的干货,抛砖引玉。
V853 平台介绍
根据官网资料得到的数据如下:
YOLOV5S模型介绍
2020年2月,yolo之父Joseph Redmon宣布退出计算机视觉研究的时候,很多人认为目标检测器YOLO系列就此终结,没想到的是,2020年4月份曾经参与YOLO项目维护Alexey Bochkovskiy带着论文《Optimal Speed and Accuracy of Object Detection》和代码在Github上重磅开源,YOLOv4正式发布!令我们更没想到的是,2020年6月份,短短两个月,Ultralytics LLC 公司的创始人兼 CEO Glenn Jocher 在 GitHub 上发布了YOLOV5 的一个开源实现,标志着YOLOv5的到来!
YOLOV5分为多个版本,它们详细的推理数据如下,数据来源于github:
https://github.com/ultralytics/yolov5/releases
这里根据对V853 1T算力的评估,我们部署其中的小模型版本,yolov5s-v6.1,也就是图中的第二行数据代表的模型。yolov5s-v6.1 mAP数据如下图所示,橙色的线就是YOLOV5Sd的数据,可以看到它的最高mAP可以达到45个点,根据mAP的计算方式,这个指标表示它能对数据集中的绝大部分目标进行有效检测了。
下面开始介绍具体的部署操作
部署逻辑
以darknet为例,端侧部署和板端部署的对应关系如下:
模型部署的流程如下图所示:
下面的操作我们会用到两个工具,分别是acuity进行模型编译,优化,而IDE则进行模型的仿真和性能,数据分析。
模型获取
模型的下载地址:
https://github.com/ultralytics/yolov5/releases
使用最新的6.1版本的yolov5s模型,默认是pytorch版。
下载下来后,由于V853部署工具对ONNX模型的支持比较友好,所有按照博客:
pytorch yolov5 推理和训练环境搭建_papaofdoudou的博客-CSDN博客_yolov5推理
中介绍的方式,将其转换为onnx模型,并用工具onnxsim对模型进行优化,得到最终的部署模型yolov5s-sim.onnx.
模型结构:
YOLOV5S是一个但输入,单输出的网络,但是我们可以修改其结构,将其变为多输出网络,这样做是有一定好处的,后文我们将会针对具体问题加以阐述。
模型部署
按照文档要求创建部署目录如下,由于我们的目的是在端侧进行推理部署,使用的是训练好的模型,这里放入dataset数据集的目的是为工具提供量化的依据,我这里只是为了演示,仅仅放置了两张图片,实际产品部署的时候,这里最好放足够多的图像,并且这些图像最好和算法实际部署场景的图像保持同样的像素分布为好。
浮点部署:
进行浮点部署的目的是获取golden tensor,验证原型模型的精度,由于浮点部署不需要经过量化,所以部署后的模型精度就是原始模型的精度(也就是说不会出现掉精度的情况). 依次执行如下命令,导入模型:
pegasus.py import onnx --model yolov5s-sim.onnx --output-data yolov5s-sim.data --output-model yolov5s-sim.jsonpegasus.py import onnx --model yolov5s-sim.onnx --output-data yolov5s-sim.data --output-model yolov5s-sim.json
pegasus.py generate inputmeta --model yolov5s-sim.json --input-meta-output yolov5s-sim-inputmeta.yml
pegasus.py generate postprocess-file --model yolov5s-sim.json --postprocess-file-output yolov5s-sim-postprocess-file.yml
pegasus.py inference --model yolov5s-sim.json --model-data yolov5s-sim.data --batch-size 1 --dtype float32 --device CPU --with-input-meta yolov5s-sim-inputmeta.yml --postprocess-file yolov5s-sim-postprocess-file.yml
pegasus.py export ovxlib --model yolov5s-sim.json --model-data yolov5s-sim.data --dtype float32 --batch-size 1 --save-fused-graph --target-ide-project 'linux64' --with-input-meta yolov5s-sim-inputmeta.yml --postprocess-file yolov5s-sim-postprocess-file.yml --output-path ovxlib/yolov5s/yolov5sprj --pack-nbg-unify --optimize "VIP9000PICO_PID0XEE" --viv-sdk ${VIV_SDK}
需要注意的是,需要在执行第三步结束后,将input yml scale参数设置为1/255=0.0039,为了和训练时保持一致。
这部操作专业的叫法叫做归一化,具体操作是减均值,除标准差,用公式表示就是:
具体原理可以看下面博客的分析,这里不在赘述。
imagenet数据集的归一化参数_papaofdoudou的博客-CSDN博客_imagenet归一化l
非对称UINT8量化版部署:
pegasus.py import onnx --model yolov5s-sim.onnx --output-data yolov5s-sim.data --output-model yolov5s-sim.jsonpegasus.py import onnx --model yolov5s-sim.onnx --output-data yolov5s-sim.data --output-model yolov5s-sim.json
pegasus.py generate inputmeta --model yolov5s-sim.json --input-meta-output yolov5s-sim-inputmeta.yml
pegasus.py generate postprocess-file --model yolov5s-sim.json --postprocess-file-output yolov5s-sim-postprocess-file.yml
pegasus.py quantize --model yolov5s-sim.json --model-data yolov5s-sim.data --batch-size 1 --device CPU --with-input-meta yolov5s-sim-inputmeta.yml --rebuild --model-quantize yolov5s-sim.quantize --quantizer asymmetric_affine --qtype uint8
pegasus.py inference --model yolov5s-sim.json --model-data yolov5s-sim.data --batch-size 1 --dtype quantized --model-quantize yolov5s-sim.quantize --device CPU --with-input-meta yolov5s-sim-inputmeta.yml --postprocess-file yolov5s-sim-postprocess-file.yml
pegasus.py export ovxlib --model yolov5s-sim.json --model-data yolov5s-sim.data --dtype quantized --model-quantize yolov5s-sim.quantize --batch-size 1 --save-fused-graph --target-ide-project 'linux64' --with-input-meta yolov5s-sim-inputmeta.yml --postprocess-file yolov5s-sim-postprocess-file.yml --output-path ovxlib/yolov5s/yolov5sprj --pack-nbg-unify --optimize "VIP9000PICO_PID0XEE" --viv-sdk ${VIV_SDK}
部署结束后,对比输出tensor的相似度,发现量化后,最后一层的相似度精度下降很多:
$ python /home/caozilong/VeriSilicon/acuity-toolkit-whl-6.6.1/bin/tools/compute_tensor_similarity.py ./quant
quant_input.tensor quanti_output.tensor
(vip) caozilong@AwExdroid-AI:~/Workspace/yolov5s-v6.1-deploy$ python /home/caozilong/VeriSilicon/acuity-toolkit-whl-6.6.1/bin/tools/compute_tensor_similarity.py ./quant
quant_input.tensor quanti_output.tensor
(vip) caozilong@AwExdroid-AI:~/Workspace/yolov5s-v6.1-deploy$ python /home/caozilong/VeriSilicon/acuity-toolkit-whl-6.6.1/bin/tools/compute_tensor_similarity.py ./quanti_output.tensor ./iter_0_attach_Concat_Concat_255_out0_0_out0_1_25200_85.tensor
2022-07-02 15:46:43.269805: W tensorflow/stream_executor/platform/default/dso_loader.cc:59] Could not load dynamic library 'libcudart.so.10.1'; dlerror: libcudart.so.10.1: cannot open shared object file: No such file or directory
2022-07-02 15:46:43.269853: I tensorflow/stream_executor/cuda/cudart_stub.cc:29] Ignore above cudart dlerror if you do not have a GPU set up on your machine.
2022-07-02 15:47:09.426509: W tensorflow/stream_executor/platform/default/dso_loader.cc:59] Could not load dynamic library 'libcuda.so.1'; dlerror: libcuda.so.1: cannot open shared object file: No such file or directory
2022-07-02 15:47:09.426556: W tensorflow/stream_executor/cuda/cuda_driver.cc:312] failed call to cuInit: UNKNOWN ERROR (303)
2022-07-02 15:47:09.426580: I tensorflow/stream_executor/cuda/cuda_diagnostics.cc:156] kernel driver does not appear to be running on this host (AwExdroid-AI): /proc/driver/nvidia/version does not exist
2022-07-02 15:47:09.453345: I tensorflow/core/platform/profile_utils/cpu_utils.cc:104] CPU Frequency: 2393990000 Hz
2022-07-02 15:47:09.455335: I tensorflow/compiler/xla/service/service.cc:168] XLA service 0x5598fe9cc010 initialized for platform Host (this does not guarantee that XLA will be used). Devices:
2022-07-02 15:47:09.455375: I tensorflow/compiler/xla/service/service.cc:176] StreamExecutor device (0): Host, Default Version
WARNING:tensorflow:From /home/caozilong/anaconda3/envs/vip/lib/python3.6/site-packages/tensorflow/python/util/dispatch.py:201: calling cosine_distance (from tensorflow.python.ops.losses.losses_impl) with dim is deprecated and will be removed in a future version.
Instructions for updating:
dim is deprecated, use axis instead
euclidean_distance 20061.037
cos_similarity 0.972248
余弦相似度只有97%,欧氏距离也很大,有问题,数据是有形状的,我们在仔细看一下这两笔tensor的分布情况:
量化输入:
浮点输入:
可以看到两笔tensor的形状是非常相似的,这说明量化非常好的保留了输入数据的特征,那再看输出数据呢?
量化输出:
浮点推理输出:
输出数据的特征非常明显,大部分的数值集中在0附近,但是也有个别极大的点分布在0-600之间。虽然量化也很好的保留了原始数据的分布形状,但是这种形态的输出是对量化非常不友好的,量化最prefer那种接近于正态分布的数据分布。针对这个模型来说,如果按照量化方式部署,最终造成的后果,可能就是模型的精度掉的太厉害,无法满足场景要求。
怎么解决这个问题呢?我们要找出症结所在,这个症结就在网络最后几层:
YOLOV5S网络特殊的地方在于,图中被红色框框住的部分,数据分布不适合做量化处理,通常被认为被框住的三个红色分支应属于后处理的部分,应该由CPU去做而不是NPU。所以正确的做法应该是从transpose输出头哪里将输出输出出来,从新定义输出节点,从图中可以看到,这里有三个输出头,就应该有三个输出节点。
之所以能这样做还有一个原因,就是模型部署工具是支持自定义输入层和数层的,你可以通过命令行指定的方式将任何一层定义为输出或者输入层。
指定输出层重新部署
通过命令行指定输出层--outputs "onnx::Sigmoid_339 onnx::Sigmoid_377 onnx::Sigmoid_415"
pegasus.py import onnx --model yolov5s-sim.onnx --output-data yolov5s-sim.data --output-model yolov5s-sim.json --outputs "onnx::Sigmoid_339 onnx::Sigmoid_377 onnx::Sigmoid_415"
pegasus.py generate inputmeta --model yolov5s-sim.json --input-meta-output yolov5s-sim-inputmeta.yml
pegasus.py generate postprocess-file --model yolov5s-sim.json --postprocess-file-output yolov5s-sim-postprocess-file.yml
pegasus.py quantize --model yolov5s-sim.json --model-data yolov5s-sim.data --batch-size 1 --device CPU --with-input-meta yolov5s-sim-inputmeta.yml --rebuild --model-quantize yolov5s-sim.quantize --quantizer asymmetric_affine --qtype uint8
pegasus.py inference --model yolov5s-sim.json --model-data yolov5s-sim.data --batch-size 1 --dtype quantized --model-quantize yolov5s-sim.quantize --device CPU --with-input-meta yolov5s-sim-inputmeta.yml --postprocess-file yolov5s-sim-postprocess-file.yml --iterations 2
pegasus.py export ovxlib --model yolov5s-sim.json --model-data yolov5s-sim.data --dtype quantized --model-quantize yolov5s-sim.quantize --batch-size 1 --save-fused-graph --target-ide-project 'linux64' --with-input-meta yolov5s-sim-inputmeta.yml --postprocess-file yolov5s-sim-postprocess-file.yml --output-path ovxlib/yolov5s/yolov5sprj --pack-nbg-unify --optimize "VIP9000PICO_PID0XEE" --viv-sdk ${VIV_SDK}
得到推理阶段的tensor,由于是现在模型改成了三个输出,所以,data目录中的两张图像对应了六笔输出tensor.
更改输出层后的网络模型结构,可以看到之前需要后处理的那一坨不见了,转而成了三个独立的输出层:
后处理:
参考如下连接的代码,将后处理部分抠出来改成绿色小程序:
https://github.com/OAID/Tengine/blob/tengine-lite/examples/tm_yolov5s_timvx.cpp
代码如下:
#include
#include
#include
#include
#include
#include
#include
using namespace std;
enum Yolov5OutType
{
p8_type = 1,
p16_type = 2,
p32_type = 3,
};
typedef struct __Rect__ {
float x, y, width, height;
} Rect;
struct Object
{
Rect rect;
int label;
float prob;
};
static float overlap(float x1, float w1, float x2, float w2)
{
float l1 = x1 - w1/2;
float l2 = x2 - w2/2;
float left = l1 > l2 ? l1 : l2;
float r1 = x1 + w1/2;
float r2 = x2 + w2/2;
float right = r1 < r2 ? r1 : r2;
return right - left;
}
float box_intersection(Rect a, Rect b)
{
float w = overlap(a.x, a.width, b.x, b.width);
float h = overlap(a.y, a.height, b.y, b.height);
if(w < 0 || h < 0) return 0;
float area = w*h;
return area;
}
static inline float sigmoid(float x)
{
return static_cast(1.f / (1.f + exp(-x)));
}
static inline float intersection_area(const Object& a, const Object& b)
{
return box_intersection(a.rect, b.rect);
}
static void qsort_descent_inplace(std::vector& faceobjects, int left, int right)
{
int i = left;
int j = right;
float p = faceobjects[(left + right) / 2].prob;
while (i <= j)
{
while (faceobjects[i].prob > p)
i++;
while (faceobjects[j].prob < p)
j--;
if (i <= j)
{
// swap
std::swap(faceobjects[i], faceobjects[j]);
i++;
j--;
}
}
#pragma omp parallel sections
{
#pragma omp section
{
if (left < j) qsort_descent_inplace(faceobjects, left, j);
}
#pragma omp section
{
if (i < right) qsort_descent_inplace(faceobjects, i, right);
}
}
}
static void qsort_descent_inplace(std::vector& faceobjects)
{
if (faceobjects.empty())
return;
qsort_descent_inplace(faceobjects, 0, faceobjects.size() - 1);
}
static void nms_sorted_bboxes(const std::vector& faceobjects, std::vector& picked, float nms_threshold)
{
picked.clear();
const int n = faceobjects.size();
std::vector areas(n);
for (int i = 0; i < n; i++)
{
areas[i] = faceobjects[i].rect.width * faceobjects[i].rect.height;;
}
for (int i = 0; i < n; i++)
{
const Object& a = faceobjects[i];
int keep = 1;
for (int j = 0; j < (int)picked.size(); j++)
{
const Object& b = faceobjects[picked[j]];
// intersection over union
float inter_area = intersection_area(a, b);
float union_area = areas[i] + areas[picked[j]] - inter_area;
if (inter_area / union_area > nms_threshold)
keep = 0;
}
if (keep)
picked.push_back(i);
}
}
static void generate_proposals(int stride, const float* feat, float prob_threshold, std::vector& objects,
int letterbox_cols, int letterbox_rows)
{
static float anchors[18] = {10, 13, 16, 30, 33, 23, 30, 61, 62, 45, 59, 119, 116, 90, 156, 198, 373, 326};
int anchor_num = 3;
int feat_w = letterbox_cols / stride;
int feat_h = letterbox_rows / stride;
int cls_num = 80;
int anchor_group;
if (stride == 8)
anchor_group = 1;
if (stride == 16)
anchor_group = 2;
if (stride == 32)
anchor_group = 3;
for (int h = 0; h <= feat_h - 1; h++)
{
for (int w = 0; w <= feat_w - 1; w++)
{
for (int a = 0; a <= anchor_num - 1; a++)
{
//process cls score
int class_index = 0;
float class_score = -FLT_MAX;
for (int s = 0; s <= cls_num - 1; s++)
{
float score = feat[a * feat_w * feat_h * (cls_num + 5) + h * feat_w * (cls_num + 5) + w * (cls_num + 5) + s + 5];
if (score > class_score)
{
class_index = s;
class_score = score;
}
}
//process box score
float box_score = feat[a * feat_w * feat_h * (cls_num + 5) + (h * feat_w) * (cls_num + 5) + w * (cls_num + 5) + 4];
float final_score = sigmoid(box_score) * sigmoid(class_score);
if (final_score >= prob_threshold)
{
int loc_idx = a * feat_h * feat_w * (cls_num + 5) + h * feat_w * (cls_num + 5) + w * (cls_num + 5);
float dx = sigmoid(feat[loc_idx + 0]);
float dy = sigmoid(feat[loc_idx + 1]);
float dw = sigmoid(feat[loc_idx + 2]);
float dh = sigmoid(feat[loc_idx + 3]);
float pred_cx = (dx * 2.0f - 0.5f + w) * stride;
float pred_cy = (dy * 2.0f - 0.5f + h) * stride;
float anchor_w = anchors[(anchor_group - 1) * 6 + a * 2 + 0];
float anchor_h = anchors[(anchor_group - 1) * 6 + a * 2 + 1];
float pred_w = dw * dw * 4.0f * anchor_w;
float pred_h = dh * dh * 4.0f * anchor_h;
float x0 = pred_cx - pred_w * 0.5f;
float y0 = pred_cy - pred_h * 0.5f;
float x1 = pred_cx + pred_w * 0.5f;
float y1 = pred_cy + pred_h * 0.5f;
Object obj;
obj.rect.x = x0;
obj.rect.y = y0;
obj.rect.width = x1 - x0;
obj.rect.height = y1 - y0;
obj.label = class_index;
obj.prob = final_score;
objects.push_back(obj);
}
}
}
}
}
static int detect_yolov5(std::vector& objects, float **output)
{
int size0 = 1*3*80*80*85;
int size1 = 1*3*40*40*85;
int size2 = 1*3*20*50*85;
std::vector p8_data(output[0], &output[0][size0-1]);
std::vector p16_data(output[1], &output[1][size1-1]);
std::vector p32_data(output[2], &output[2][size2-1]);
// set default letterbox size
int letterbox_rows = 640;
int letterbox_cols = 640;
/* postprocess */
const float prob_threshold = 0.4f;
const float nms_threshold = 0.45f;
std::vector proposals;
std::vector objects8;
std::vector objects16;
std::vector objects32;
//std::vector objects;
generate_proposals(32, p32_data.data(), prob_threshold, objects32, letterbox_cols, letterbox_rows);
proposals.insert(proposals.end(), objects32.begin(), objects32.end());
generate_proposals(16, p16_data.data(), prob_threshold, objects16, letterbox_cols, letterbox_rows);
proposals.insert(proposals.end(), objects16.begin(), objects16.end());
generate_proposals(8, p8_data.data(), prob_threshold, objects8, letterbox_cols, letterbox_rows);
proposals.insert(proposals.end(), objects8.begin(), objects8.end());
qsort_descent_inplace(proposals);
std::vector picked;
nms_sorted_bboxes(proposals, picked, nms_threshold);
/* yolov5 draw the result */
float scale_letterbox;
int resize_rows;
int resize_cols;
if ((letterbox_rows * 1.0 / 640) < (letterbox_cols * 1.0 / 640))
{
scale_letterbox = letterbox_rows * 1.0 / 640;
}
else
{
scale_letterbox = letterbox_cols * 1.0 / 640;
}
resize_cols = int(scale_letterbox * 640);
resize_rows = int(scale_letterbox * 640);
int tmp_h = (letterbox_rows - resize_rows) / 2;
int tmp_w = (letterbox_cols - resize_cols) / 2;
float ratio_x = (float)640 / resize_rows;
float ratio_y = (float)640 / resize_cols;
int count = picked.size();
fprintf(stderr, "detection num: %d\n", count);
objects.resize(count);
for (int i = 0; i < count; i++)
{
objects[i] = proposals[picked[i]];
float x0 = (objects[i].rect.x);
float y0 = (objects[i].rect.y);
float x1 = (objects[i].rect.x + objects[i].rect.width);
float y1 = (objects[i].rect.y + objects[i].rect.height);
x0 = (x0 - tmp_w) * ratio_x;
y0 = (y0 - tmp_h) * ratio_y;
x1 = (x1 - tmp_w) * ratio_x;
y1 = (y1 - tmp_h) * ratio_y;
x0 = std::max(std::min(x0, (float)(640 - 1)), 0.f);
y0 = std::max(std::min(y0, (float)(640 - 1)), 0.f);
x1 = std::max(std::min(x1, (float)(640 - 1)), 0.f);
y1 = std::max(std::min(y1, (float)(640 - 1)), 0.f);
objects[i].rect.x = x0;
objects[i].rect.y = y0;
objects[i].rect.width = x1 - x0;
objects[i].rect.height = y1 - y0;
printf("%s line %d, x:%f, y %f, w: %f, h %f.\n", __func__, __LINE__, objects[i].rect.x, objects[i].rect.y, objects[i].rect.width, objects[i].rect.height);
}
return 0;
}
int yolov5s_postprocess(float **output)
{
printf("yolov5s_postprocess.c run. \n");
std::vector objects;
detect_yolov5(objects, output);
return 0;
}
int get_tensor_data(string file_path, float **data)
{
int len = 0;
static float *memory = NULL;
static int max_len = 10*1024*1024;
if (memory == NULL)
{
memory = (float *)malloc(max_len * sizeof(float));
}
FILE *fp = NULL;
if ((fp = fopen(file_path.c_str(), "r")) == NULL)
{
cout << "open tensor file error ! file name : " << file_path << endl;
exit(-1);
}
int file_len = 0;
while (!feof(fp))
{
fscanf(fp, "%f ", &memory[len++]);
}
*data = (float *)malloc(len * sizeof(float));
memcpy(*data, memory, len * sizeof(float));
fclose(fp);
if (len == 0 || *data == NULL)
{
cout << "read tensor error happened ! " << "len : " << len << " data address: " << *data << endl;
exit(-1);
}
return len;
}
int main(int argc, char **argv)
{
float *tensor0;
float *tensor1;
float *tensor2;
float *tensor[3];
get_tensor_data(argv[1], &tensor0);
get_tensor_data(argv[2], &tensor1);
get_tensor_data(argv[3], &tensor2);
tensor[0] = tensor0;
tensor[1] = tensor1;
tensor[2] = tensor2;
yolov5s_postprocess(tensor);
return 0;
}
编译后,对输出的两张图像的tensor做后处理:
可以看到,针对图像1,检测出来了3个目标,坐标狂也被打印出来:
修改输出层后的输出数据分布情况
iter_0_attach_Transpose_Transpose_200_out0_0_out0_1_3_80_80_85.tensor:
iter_0_attach_Transpose_Transpose_219_out0_1_out0_1_3_40_40_85.tensor:
iter_0_attach_Transpose_Transpose_238_out0_2_out0_1_3_20_20_85.tensor:
iter_1_attach_Transpose_Transpose_200_out0_0_out0_1_3_80_80_85.tensor:
iter_1_attach_Transpose_Transpose_219_out0_1_out0_1_3_40_40_85.tensor:
iter_1_attach_Transpose_Transpose_238_out0_2_out0_1_3_20_20_85.tensor:
通过直方图可以看出,新定义的三个输出节点的分布形状很接近于正态分布,就像前文所讲,正态分布对量化是非常友好的。所以能够解决精度丢失的问题。
结束
你可能感兴趣的:(算法,数学,Linux,人工智能,YOLO,YOLOV5,YOLOV5S)
深度学习模型:原理、应用与代码实践
accurater
c++算法笔记 人工智能 深度学习
引言深度学习作为人工智能的核心技术,已在图像识别、自然语言处理、代码生成等领域取得突破性进展。其核心在于通过多层神经网络自动提取数据特征,解决复杂任务。本文将从基础理论、模型架构、优化策略、应用场景及挑战等多个维度展开,结合代码示例,系统解析深度学习模型的技术脉络与实践方法。一、深度学习基础理论神经网络基本原理神经网络由输入层、隐藏层和输出层构成,通过反向传播算法调整权重。以全连接网络为例,前向传
SVN学习笔记
颜洛滨
开发工具 SVN 开发工具 版本管理
SVN学习笔记SVN背景知识SVN,全称Subversion,是一个开放源码的集中式版本控制系统,这里需要注意的一个点就是集中式,所谓的集中式,就是说,SVN管理的所有仓库都位于一个集中的服务器上,如下图所示SVN官网:SVN官网SVN安装:SVN支持多个平台,包括Windows,Mac,Linux等,官网上提供了详细的安装指南,这里我使用的是Centos6,对应的安装步骤如下首先使用svn--v
linux svn创建资源库,CentOS 7搭建svn服务
你的麦克疯
linux svn创建资源库
一、背景自己平时有记笔记的习惯,回到宿舍笔记就同步不了。打算入手下很火的笔记软件,用着觉得不顺手,目录一多查找不方便,没有英文首字母定位快,想想决定用svn同步,整理出来分享给大家。二、搭建svn服务1、安装subversionyum-yinstallsubversion2、创建版本库目录,为创建版本库提供存放位置mkdir-p/home/svn/svnrepos3、创建svn版本库,mynote
linux | Vim 命令快捷操作
斐夷所非
Linux linux Vim
注:本文为过去的“vim使用笔记”。跳转命令跳转命令#:向前查找光标当前所在单词,并跳转到该单词的上一个出现位置。*:向后查找光标当前所在单词,并跳转到该单词的下一个出现位置。行内跳转0:跳转到当前行的行首。[Home]$:跳转到当前行的行尾。[End]^:跳转到当前行的第一个非空字符处。g_:跳转到行尾最后一个非空白字符。|n:跳转到当前行的第n列(例如:|10跳转到第10列)。文件内跳转gg:
山海鲸接入DeepSeek~赋予AI 3D感知“超能力”
山海鲸可视化
数字孪生 数字孪生 AI DeepSeek 通义千问 3D
山海鲸震撼升级,一键直连DeepSeek、通义千问等主流大模型,融合前沿3D-LLM算法,赋予AI3D感知“超能力”,让数字孪生生产力全面爆发,开启无限可能!山海鲸接入DeepSeek~赋予AI3D感知“超能力”
用于网络安全的生成式 AI:利用 AI 增强威胁检测和响应
云上笛暮
AI for Security 人工智能
一、引言技术的进步彻底改变了我们的生活、工作和交流方式。然而,随着这些技术的进步,保护它们免受网络威胁的挑战也随之而来。网络安全已成为任何组织的重要组成部分,随着网络攻击越来越复杂,传统的威胁检测和响应方法已不再足够。这导致了生成人工智能等新技术的发展,这些技术在增强网络安全方面显示出巨大潜力。在这篇博客中,我们将探讨生成式人工智能的概念、它在网络安全中的重要性,以及它如何用于增强威胁检测和响应。
深入探索 Linux 权限维持之 SSH 后门与公私钥技术
阿贾克斯的黎明
网络安全 linux ssh 运维
目录深入探索Linux权限维持之SSH后门与公私钥技术SSH后门:开启隐藏访问通道利用软链接创建SSH后门SSHServerRapper方法公私钥:实现免密登录与权限维持生成与部署公私钥隐藏公私钥操作痕迹其他相关技巧与注意事项SSH键盘记录器SSH隐身登录总结在Linux系统安全领域,权限维持是攻击者在获取初始访问权限后,为长期控制目标系统所采用的关键技术手段。其中,SSH后门的建立以及公私钥的巧
【Linux系统编程】初识系统编程
不被定义的~wolf
Linux linux 服务器 运维
目录一、什么是系统编程1.系统编程的定义2.系统编程的特点3.系统编程的应用领域4.系统编程的核心概念5.系统编程的工具和技术二、操作系统四大基本功能1.进程管理(ProcessManagement)2.内存管理(MemoryManagement)3.文件系统管理(FileSystemManagement)4.设备管理(DeviceManagement)三、计算机系统分层1.硬件层(Hardwar
【svn】批量删除文件夹当中的.SVN
春天的菠菜
SVN svn 服务器 windows
目录一、在Windows环境:1、新建记事本2、复制到对应文件夹二、在Linux环境:一、在Windows环境:1、新建记事本将下面代码,粘贴到记事本中,保存为KillSvn.bat文件@echoon@rem删除SVN版本控制目录@remfor/r.%%ain(.)do@ifexist"%%a\.svn"@echo"%%a\.svn"@for/r.%%ain(.)do@ifexist"%%a\.s
可视化学习:使用WebGL绘制圆形,实现色盘
前言在Canvas2D中实现圆形的绘制比较简单,只要调用arc指令就能在Canvas画布上绘制出一个圆形,类似的,在SVG中我们也只需要一个标签就能在页面上绘制一个圆形。那么在WebGL中我们要怎么去绘制呢?WebGL只能绘制三种形状:点、线段和三角形,它没有提供直接绘制圆形的功能,当然也无法像SVG一样使用标签,所以我们是无法直接绘制圆形曲线的,这个时候我们可以借助相关的数学知识,来实现圆形的绘
整理后端开发用软件合集
acc8226
编辑器 笔记
注:以下开发用软件,谨代表个人观点。一些标签:【便携版】(app,dmg镜像但内部依旧是app这种形式)能选择便携包尽量选择它。【安装版】(pkg这种形式)是便携类软件的补充,可以按需挑选。如果该软件能做到跨平台,我会优先推荐。【应用商店版】【cli】为命令行程序【win】windows平台有【全平台】win、mac、linux平台都有【免费】【有免费版】【付费】【预览版限免】挑选软件我尽量考虑以
深度解构:DeepSeek大模型架构与前沿应用的未来探秘
威哥说编程
架构 ai
随着人工智能(AI)领域的快速发展,深度学习模型逐渐向着更加复杂和强大的方向演进。在这一波技术浪潮中,DeepSeek大模型作为一个重要代表,凭借其卓越的表现和广泛的应用,正在重新定义我们对AI的认知和期待。本篇文章将从架构到应用,全面解析DeepSeek大模型的技术特点,探索其在未来可能带来的创新与变革。1.DeepSeek大模型的架构设计DeepSeek大模型采用的是基于Transformer
RV1126笔记六:人脸识别方案<四>
殷忆枫
RV1126项目实战 人工智能
若该文为原创文章,转载请注明原文出处。一、介绍人脸识别方案设计逻辑流程图,方案代码分为分为三个业务流程,主体代码负责抓取、合成图像,算法代码负责人脸识别功能。通过摄像头实时采集数据,识别人脸,并提取人脸特征,把特征值和数据库对比后,把名字合合到图像上,通过自带的RTSP库推流,在PC端播放。二、流程图说明:程序初始化后,创建了三个线程:线程一、循环获取VI数据,实时检测人脸,识别人脸,提取特征值,
opencv----形态学运算:开运算、闭运算、顶帽、黑帽
郭大侠写leetcode
opencv
一、理论与概念讲解——从现象到本质1.1开运算(OpeningOperation)开运算(OpeningOperation),其实就是先腐蚀后膨胀的过程。其数学表达式如下:开运算可以用来消除小物体、在纤细点处分离物体、平滑较大物体的边界的同时并不明显改变其面积。1.2闭运算(ClosingOperation)先膨胀后腐蚀的过程称为闭运算(ClosingOperation),其数学表达式如下:
linux下jsoncpp编译
虎皮猫大人王
linux系统 linux 系统
折腾了一顿,我使用ubuntu16.04编译的jsoncpp,由于使用的芯片工程需要16.04,无法使用最新的ubuntu系统。发现jsoncpp编译时,CMakeError:CouldnotfindCMAKE_ROOT!!!CMakehasmostlikelynotbeeninstalledcorrectly.Modulesdirectorynotfoundin/usr/local/share/
T41LQ专为人工智能物联网(AIoT)应用设计,适用于智能安防、智能家居、机器视觉等领域 软硬件资料+样品测试
li15817260414
君正 人工智能 物联网 智能家居
君正(Ingenic)T系列芯片涵盖多个型号,每个型号根据不同应用需求提供了多个版本。以下是各型号及其主要版本:1.T23系列:T23N:标准版,适用于移动摄像机、安全监控、视频通话和视频分析等应用。T23ZN:佐罗标准版,功能与T23N类似,针对特定市场需求进行了优化。2.T31系列:T31L:简化版,适用于对成本和功耗有严格要求的应用场景。T31N:标准版,适用于广泛的智能视频应用。T31X:
华为OD机试2025年真题题库(E卷+D卷+C卷+B卷+A卷)(Python/JS/C/C++)
哪 吒
搬砖工逆袭Java架构师 华为od c语言 python
专栏导读本专栏收录于《华为OD机试真题(Python/JS/C/C++)》。刷的越多,抽中的概率越大,私信哪吒,备注华为OD,加入华为OD刷题交流群,每一题都有详细的答题思路、详细的代码注释、3个测试用例、为什么这道题采用XX算法、XX算法的适用场景,发现新题目,随时更新。2024年8月14日,华为官方已经将华为OD机试(D卷)切换为E卷。目前正在考的是E卷,按照华为OD往常的操作,E卷题目是由往
华为OD机试 - 没有回文串(Python/JS/C/C++ 2024 E卷 100分)
哪 吒
华为od python javascript
华为OD机试2024E卷题库疯狂收录中,刷题点这里专栏导读本专栏收录于《华为OD机试真题(Python/JS/C/C++)》。刷的越多,抽中的概率越大,私信哪吒,备注华为OD,加入华为OD刷题交流群,每一题都有详细的答题思路、详细的代码注释、3个测试用例、为什么这道题采用XX算法、XX算法的适用场景,发现新题目,随时更新,全天CSDN在线答疑。一、题目描述回文串Q的定义:正读和反读都一样的字符串。
华为OD机试 - 三阶积幻方(Python/JS/C/C++ 2024 E卷 100分)
哪 吒
华为od python javascript
华为OD机试2024E卷题库疯狂收录中,刷题点这里专栏导读本专栏收录于《华为OD机试真题(Python/JS/C/C++)》。刷的越多,抽中的概率越大,私信哪吒,备注华为OD,加入华为OD刷题交流群,每一题都有详细的答题思路、详细的代码注释、3个测试用例、为什么这道题采用XX算法、XX算法的适用场景,发现新题目,随时更新,全天CSDN在线答疑。一、题目描述九宫格是一款广为流传的游戏,起源于河图洛书
华为OD机试 - 士兵过河 - 二分查找(Python/JS/C/C++ 2024 E卷 100分)
哪 吒
华为od python javascript
华为OD机试2024E卷题库疯狂收录中,刷题点这里专栏导读本专栏收录于《华为OD机试真题(Python/JS/C/C++)》。刷的越多,抽中的概率越大,私信哪吒,备注华为OD,加入华为OD刷题交流群,每一题都有详细的答题思路、详细的代码注释、3个测试用例、为什么这道题采用XX算法、XX算法的适用场景,发现新题目,随时更新,全天CSDN在线答疑。一、题目描述一支N个士兵的军队正在赶夜夜行军,途中遇到
华为OD机试真题 - 精准核酸检测 - 深度优先搜索DFS(Python/JS/C/C++ 2024 D卷 200分)
哪 吒
华为od 深度优先 python
华为OD机试2024E卷题库疯狂收录中,刷题点这里专栏导读本专栏收录于《华为OD机试真题(Python/JS/C/C++)》。刷的越多,抽中的概率越大,私信哪吒,备注华为OD,加入华为OD刷题交流群,每一题都有详细的答题思路、详细的代码注释、3个测试用例、为什么这道题采用XX算法、XX算法的适用场景,发现新题目,随时更新,全天CSDN在线答疑。一、题目描述为了达到新冠疫情精准防控的需要,为了避免全
华为OD机试 - 最优策略组合下的总的系统消耗资源数(Python/JS/C/C++ 2024 D卷 100分)
哪 吒
python 华为od java c c++ javascript
华为OD机试2024E卷题库疯狂收录中,刷题点这里专栏导读本专栏收录于《华为OD机试真题(Python/JS/C/C++)》。刷的越多,抽中的概率越大,私信哪吒,备注华为OD,加入华为OD刷题交流群,每一题都有详细的答题思路、详细的代码注释、3个测试用例、为什么这道题采用XX算法、XX算法的适用场景,发现新题目,随时更新,全天CSDN在线答疑。一、题目描述在通信系统中有一个常见的问题是对用户进行不
华为OD机试 - 信道分配 - 贪心算法(Python/JS/C/C++ 2024 D卷 200分)
哪 吒
python 华为od 贪心算法
一、题目描述算法工程师Q小明面对着这样一个问题,需要将通信用的信道分配给尽量多的用户:信道的条件及分配规则如下:所有信道都有属性"阶"。阶为r的信道的容量为2^r比特;所有用户需要传输的数据量都一样:D比特;一个用户可以分配多个信道,但每个信道只能分配给一个用户;当且仅当分配给一个用户的所有信道的容量和>=D,用户才能传输数据;给出一组信道资源,最多可以为多少用户传输数据?二、输入描述第一行,一个
点云从入门到精通技术详解100篇-基于背包激光雷达点云在城市公园单木参数提取中的应用
格图素书
人工智能
目录前言国内外发展现状(DevelopmentStatusatHomeandAbroad)背包LiDAR技术及其在林业调查中的应用进展单木胸径提取算法研究现状单木树高提取算法研究现状2背包LiDAR城市公园树木数据采集及预处理2.1测区概况(OverviewTestArea)2.2背包LiDAR数据采集与处理(BackpackLiDARDataAcquisitionand2.2.1背包激光雷达系统
人工智能生成内容(AIGC)对程序员的影响
AmHardy
AIGC 人工智能 AIGC 程序员 chatgpt kimi
人工智能生成内容(AIGC)对程序员的影响引言AIGC技术正在深刻影响软件开发行业,给程序员带来诸多机遇和挑战。程序员不仅需要适应这些新兴技术,还要有效利用它们来提升自己的工作效率和创新能力。AIGC技术的优势效率提升代码生成:AI工具如GitHubCopilot可以预测代码片段、自动完成代码和生成文档,从而显著提升编程效率。自动化测试:AI可以自动生成测试用例和检测代码中的潜在问题,减少了手动测
【数学建模技术】路径规划算法-Dijkstra算法
一键难忘
数学建模技术超入门 Dijkstra 数学建模算法 路径规划算法
路径规划算法-Dijkstra算法1.引言路径规划是许多领域中的核心问题,尤其是在机器人导航、地理信息系统(GIS)、交通管理等方面。路径规划算法的主要目标是寻找从起点到终点的最短路径。Dijkstra算法作为一种经典的单源最短路径算法,广泛应用于各种实际问题中。本篇文章将详细探讨Dijkstra算法的原理、应用场景,并通过代码实例进行深入解析。2.Dijkstra算法原理Dijkstra算法是由
【路径规划】基于A算法和Dijkstra算法的路径规划附Python代码
天天Matlab科研工作室
无人机matlab仿真电子资源 算法 python 开发语言
✅作者简介:热爱科研的Matlab仿真开发者,擅长数据处理、建模仿真、程序设计、完整代码获取、论文复现及科研仿真。往期回顾关注个人主页:Matlab科研工作室个人信条:格物致知,完整Matlab代码及仿真咨询内容私信。内容介绍路径规划作为人工智能和机器人技术领域的核心问题之一,在导航、交通运输、游戏开发等领域有着广泛的应用。解决路径规划问题,旨在找到一条从起始点到目标点,并满足特定约束条件(如最短
成为 Android 开发人员的最佳途径 – 完整路线图
大门口的猴子
android应用 android
Android是一个开源操作系统,基于Linux内核,用于智能手机、平板电脑等移动设备。此外,它还为智能手表和AndroidTV开发。它们每个都有一个专门的界面。Android一直是智能手机最畅销的操作系统之一。Android操作系统由谷歌于2005年收购的AndroidInc.开发游戏、音乐播放器、相机等各种应用程序都是为这些智能手机构建的,可在Android上运行。GooglePlayStor
【嵌入式Bluetooth应用开发笔记】第二篇:上手BLUEZ应用开发
林零七
蓝牙开发笔记 bluez Bluetooth linux dbus gdbus
概述BlueZ是一个开源的蓝牙协议栈,提供了丰富的API和工具,支持Linux系统中的蓝牙应用开发。BlueZ提供的API包括D-BusAPI、HCIAPI、L2CAPAPI、RFCOMMAPI、SDPAPI、MGMTAPI等,开发者可以使用这些API实现自己的蓝牙应用程序。BlueZ的架构由多个模块组成,其中主要的模块包括蓝牙协议栈(BluetoothStack)、蓝牙管理器(Bluetooth
蓝牙协议栈BlueZ:Linux下的无线通信利器 /Linux
谢璋声Shirley
蓝牙协议栈BlueZ:Linux下的无线通信利器/LinuxbluezMyblueztree.项目地址:https://gitcode.com/gh_mirrors/bl/bluez项目基础介绍与编程语言BlueZ是一个专为Linux系统设计的蓝牙协议栈,自2000年起,由Qualcomm、MarcelHoltmann等贡献者持续维护与发展。此项目采用C作为主要编程语言,并辅以少量的Python代
Maven
Array_06
eclipse jdk maven
Maven
Maven是基于项目对象模型(POM), 信息来管理项目的构建,报告和文档的软件项目管理工具。
Maven 除了以程序构建能力为特色之外,还提供高级项目管理工具。由于 Maven 的缺省构建规则有较高的可重用性,所以常常用两三行 Maven 构建脚本就可以构建简单的项目。由于 Maven 的面向项目的方法,许多 Apache Jakarta 项目发文时使用 Maven,而且公司
ibatis的queyrForList和queryForMap区别
bijian1013
java ibatis
一.说明
iBatis的返回值参数类型也有种:resultMap与resultClass,这两种类型的选择可以用两句话说明之:
1.当结果集列名和类的属性名完全相对应的时候,则可直接用resultClass直接指定查询结果类
LeetCode[位运算] - #191 计算汉明权重
Cwind
java 位运算 LeetCode Algorithm 题解
原题链接:#191 Number of 1 Bits
要求:
写一个函数,以一个无符号整数为参数,返回其汉明权重。例如,‘11’的二进制表示为'00000000000000000000000000001011', 故函数应当返回3。
汉明权重:指一个字符串中非零字符的个数;对于二进制串,即其中‘1’的个数。
难度:简单
分析:
将十进制参数转换为二进制,然后计算其中1的个数即可。
“
浅谈java类与对象
15700786134
java
java是一门面向对象的编程语言,类与对象是其最基本的概念。所谓对象,就是一个个具体的物体,一个人,一台电脑,都是对象。而类,就是对象的一种抽象,是多个对象具有的共性的一种集合,其中包含了属性与方法,就是属于该类的对象所具有的共性。当一个类创建了对象,这个对象就拥有了该类全部的属性,方法。相比于结构化的编程思路,面向对象更适用于人的思维
linux下双网卡同一个IP
被触发
linux
转自:
http://q2482696735.blog.163.com/blog/static/250606077201569029441/
由于需要一台机器有两个网卡,开始时设置在同一个网段的IP,发现数据总是从一个网卡发出,而另一个网卡上没有数据流动。网上找了下,发现相同的问题不少:
一、
关于双网卡设置同一网段IP然后连接交换机的时候出现的奇怪现象。当时没有怎么思考、以为是生成树
安卓按主页键隐藏程序之后无法再次打开
肆无忌惮_
安卓
遇到一个奇怪的问题,当SplashActivity跳转到MainActivity之后,按主页键,再去打开程序,程序没法再打开(闪一下),结束任务再开也是这样,只能卸载了再重装。而且每次在Log里都打印了这句话"进入主程序"。后来发现是必须跳转之后再finish掉SplashActivity
本来代码:
// 销毁这个Activity
fin
通过cookie保存并读取用户登录信息实例
知了ing
JavaScript html
通过cookie的getCookies()方法可获取所有cookie对象的集合;通过getName()方法可以获取指定的名称的cookie;通过getValue()方法获取到cookie对象的值。另外,将一个cookie对象发送到客户端,使用response对象的addCookie()方法。
下面通过cookie保存并读取用户登录信息的例子加深一下理解。
(1)创建index.jsp文件。在改
JAVA 对象池
矮蛋蛋
java ObjectPool
原文地址:
http://www.blogjava.net/baoyaer/articles/218460.html
Jakarta对象池
☆为什么使用对象池
恰当地使用对象池化技术,可以有效地减少对象生成和初始化时的消耗,提高系统的运行效率。Jakarta Commons Pool组件提供了一整套用于实现对象池化
ArrayList根据条件+for循环批量删除的方法
alleni123
java
场景如下:
ArrayList<Obj> list
Obj-> createTime, sid.
现在要根据obj的createTime来进行定期清理。(释放内存)
-------------------------
首先想到的方法就是
for(Obj o:list){
if(o.createTime-currentT>xxx){
阿里巴巴“耕地宝”大战各种宝
百合不是茶
平台战略
“耕地保”平台是阿里巴巴和安徽农民共同推出的一个 “首个互联网定制私人农场”,“耕地宝”由阿里巴巴投入一亿 ,主要是用来进行农业方面,将农民手中的散地集中起来 不仅加大农民集体在土地上面的话语权,还增加了土地的流通与 利用率,提高了土地的产量,有利于大规模的产业化的高科技农业的 发展,阿里在农业上的探索将会引起新一轮的产业调整,但是集体化之后农民的个体的话语权 将更少,国家应出台相应的法律法规保护
Spring注入有继承关系的类(1)
bijian1013
java spring
一个类一个类的注入
1.AClass类
package com.bijian.spring.test2;
public class AClass {
String a;
String b;
public String getA() {
return a;
}
public void setA(Strin
30岁转型期你能否成为成功人士
bijian1013
成功
很多人由于年轻时走了弯路,到了30岁一事无成,这样的例子大有人在。但同样也有一些人,整个职业生涯都发展得很优秀,到了30岁已经成为职场的精英阶层。由于做猎头的原因,我们接触很多30岁左右的经理人,发现他们在职业发展道路上往往有很多致命的问题。在30岁之前,他们的职业生涯表现很优秀,但从30岁到40岁这一段,很多人
[Velocity三]基于Servlet+Velocity的web应用
bit1129
velocity
什么是VelocityViewServlet
使用org.apache.velocity.tools.view.VelocityViewServlet可以将Velocity集成到基于Servlet的web应用中,以Servlet+Velocity的方式实现web应用
Servlet + Velocity的一般步骤
1.自定义Servlet,实现VelocityViewServl
【Kafka十二】关于Kafka是一个Commit Log Service
bit1129
service
Kafka is a distributed, partitioned, replicated commit log service.这里的commit log如何理解?
A message is considered "committed" when all in sync replicas for that partition have applied i
NGINX + LUA实现复杂的控制
ronin47
lua nginx 控制
安装lua_nginx_module 模块
lua_nginx_module 可以一步步的安装,也可以直接用淘宝的OpenResty
Centos和debian的安装就简单了。。
这里说下freebsd的安装:
fetch http://www.lua.org/ftp/lua-5.1.4.tar.gz
tar zxvf lua-5.1.4.tar.gz
cd lua-5.1.4
ma
java-14.输入一个已经按升序排序过的数组和一个数字, 在数组中查找两个数,使得它们的和正好是输入的那个数字
bylijinnan
java
public class TwoElementEqualSum {
/**
* 第 14 题:
题目:输入一个已经按升序排序过的数组和一个数字,
在数组中查找两个数,使得它们的和正好是输入的那个数字。
要求时间复杂度是 O(n) 。如果有多对数字的和等于输入的数字,输出任意一对即可。
例如输入数组 1 、 2 、 4 、 7 、 11 、 15 和数字 15 。由于
Netty源码学习-HttpChunkAggregator-HttpRequestEncoder-HttpResponseDecoder
bylijinnan
java netty
今天看Netty如何实现一个Http Server
org.jboss.netty.example.http.file.HttpStaticFileServerPipelineFactory:
pipeline.addLast("decoder", new HttpRequestDecoder());
pipeline.addLast(&quo
java敏感词过虑-基于多叉树原理
cngolon
违禁词过虑 替换违禁词 敏感词过虑 多叉树
基于多叉树的敏感词、关键词过滤的工具包,用于java中的敏感词过滤
1、工具包自带敏感词词库,第一次调用时读入词库,故第一次调用时间可能较长,在类加载后普通pc机上html过滤5000字在80毫秒左右,纯文本35毫秒左右。
2、如需自定义词库,将jar包考入WEB-INF工程的lib目录,在WEB-INF/classes目录下建一个
utf-8的words.dict文本文件,
多线程知识
cuishikuan
多线程
T1,T2,T3三个线程工作顺序,按照T1,T2,T3依次进行
public class T1 implements Runnable{
@Override
spring整合activemq
dalan_123
java spring jms
整合spring和activemq需要搞清楚如下的东东1、ConnectionFactory分: a、spring管理连接到activemq服务器的管理ConnectionFactory也即是所谓产生到jms服务器的链接 b、真正产生到JMS服务器链接的ConnectionFactory还得
MySQL时间字段究竟使用INT还是DateTime?
dcj3sjt126com
mysql
环境:Windows XPPHP Version 5.2.9MySQL Server 5.1
第一步、创建一个表date_test(非定长、int时间)
CREATE TABLE `test`.`date_test` (`id` INT NOT NULL AUTO_INCREMENT ,`start_time` INT NOT NULL ,`some_content`
Parcel: unable to marshal value
dcj3sjt126com
marshal
在两个activity直接传递List<xxInfo>时,出现Parcel: unable to marshal value异常。 在MainActivity页面(MainActivity页面向NextActivity页面传递一个List<xxInfo>): Intent intent = new Intent(this, Next
linux进程的查看上(ps)
eksliang
linux ps linux ps -l linux ps aux
ps:将某个时间点的进程运行情况选取下来
转载请出自出处:http://eksliang.iteye.com/admin/blogs/2119469
http://eksliang.iteye.com
ps 这个命令的man page 不是很好查阅,因为很多不同的Unix都使用这儿ps来查阅进程的状态,为了要符合不同版本的需求,所以这个
为什么第三方应用能早于System的app启动
gqdy365
System
Android应用的启动顺序网上有一大堆资料可以查阅了,这里就不细述了,这里不阐述ROM启动还有bootloader,软件启动的大致流程应该是启动kernel -> 运行servicemanager 把一些native的服务用命令启动起来(包括wifi, power, rild, surfaceflinger, mediaserver等等)-> 启动Dalivk中的第一个进程Zygot
App Framework发送JSONP请求(3)
hw1287789687
jsonp 跨域请求 发送jsonp ajax请求 越狱请求
App Framework 中如何发送JSONP请求呢?
使用jsonp,详情请参考:http://json-p.org/
如何发送Ajax请求呢?
(1)登录
/***
* 会员登录
* @param username
* @param password
*/
var user_login=function(username,password){
// aler
发福利,整理了一份关于“资源汇总”的汇总
justjavac
资源
觉得有用的话,可以去github关注:https://github.com/justjavac/awesome-awesomeness-zh_CN 通用
free-programming-books-zh_CN 免费的计算机编程类中文书籍
精彩博客集合 hacke2/hacke2.github.io#2
ResumeSample 程序员简历
用 Java 技术创建 RESTful Web 服务
macroli
java 编程 Web REST
转载:http://www.ibm.com/developerworks/cn/web/wa-jaxrs/
JAX-RS (JSR-311) 【 Java API for RESTful Web Services 】是一种 Java™ API,可使 Java Restful 服务的开发变得迅速而轻松。这个 API 提供了一种基于注释的模型来描述分布式资源。注释被用来提供资源的位
CentOS6.5-x86_64位下oracle11g的安装详细步骤及注意事项
超声波
oracle linux
前言:
这两天项目要上线了,由我负责往服务器部署整个项目,因此首先要往服务器安装oracle,服务器本身是CentOS6.5的64位系统,安装的数据库版本是11g,在整个的安装过程中碰到很多的坑,不过最后还是通过各种途径解决并成功装上了。转别写篇博客来记录完整的安装过程以及在整个过程中的注意事项。希望对以后那些刚刚接触的菜鸟们能起到一定的帮助作用。
安装过程中可能遇到的问题(注
HttpClient 4.3 设置keeplive 和 timeout 的方法
supben
httpclient
ConnectionKeepAliveStrategy kaStrategy = new DefaultConnectionKeepAliveStrategy() {
@Override
public long getKeepAliveDuration(HttpResponse response, HttpContext context) {
long keepAlive
Spring 4.2新特性-@Import注解的升级
wiselyman
spring 4
3.1 @Import
@Import注解在4.2之前只支持导入配置类
在4.2,@Import注解支持导入普通的java类,并将其声明成一个bean
3.2 示例
演示java类
package com.wisely.spring4_2.imp;
public class DemoService {
public void doSomethin