通常情况下,在端侧的模型推理过程中,使用的是量化后的数据来参与各层计算的,而并非原始的float数据类型,通常的量化数据类型有UINT8/INT8/INT16等等,由于数据表示范围的差异,在量化过程中,必然涉及到精度损失,这种同一个模型相同层之间使用量化推理计算得到的数据经过反量化之后和原始goden版的float数据的差异,我们用相似度表示,用图形化描述如下:
通常相似度的比较可以用余弦距离和空间欧式距离表示,根据线性空间理论,当两个向量相似时,他们的内积较大,我们可以认为内积大小表示两个向量的相似性,cos的结果表示余弦相似度。
用矩阵向量表示就是:
高维空间难以理解,在二维空间就好理解多了,用到的就是中学学的余弦定理。图形化表示如下图所示,可以看到,当向量i和向量u方向大致相同时(夹角为锐角),红色的投影长度比较大,而当两向量垂直时,投影为零,并且当向量夹角为钝角的时候,投影为负的向量,代表差异最大。
下面以两笔同一个模型的不同过程产生的tensor为例,介绍两类统计信息的C语言实现过程。
代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stddef.h>
#include <stdint.h>
#include <fcntl.h>
#include <unistd.h>
#include <math.h>
#include <sys/ioctl.h>
#define DBG(fmt, ...) do { printf("%s line %d, "fmt"\n", __func__, __LINE__, ##__VA_ARGS__); } while (0)
static void dump_memory(uint8_t *buf, int32_t len)
{
int i;
printf("\n\rdump file memory:");
for (i = 0; i < len; i ++)
{
if ((i % 16) == 0)
{
printf("\n\r%p: ", buf + i);
}
printf("0x%02x ", buf[i]);
}
printf("\n\r");
return;
}
int get_tensor_from_txt_file(char *file_path, float **buf)
{
int len = 0;
static float *memory = NULL;
static int max_len = 10 * 1024 * 1024;
FILE *fp = NULL;
if(memory == NULL)
{
memory = (float*) malloc(max_len * sizeof(float));
}
if((fp = fopen(file_path, "r")) == NULL)
{
DBG("open tensor error.");
exit(-1);
}
while(!feof(fp))
{
fscanf(fp, "%f", &memory[len ++]);
}
*buf = (float*)malloc(len * sizeof(float));
if(len == 0 || *buf == NULL)
{
DBG("read tensor error, len %d, *buf %p", len, *buf);
exit(-1);
}
memcpy(*buf, memory, len * sizeof(float));
fclose(fp);
return len;
}
float calculate_ojilide(int tensor_len, float *data0, float *data1)
{
int i;
float sum = 0.00;
for(i = 0; i < tensor_len; i ++)
{
float square = (data0[i]-data1[i]) * (data0[i]-data1[i]);
sum += square;
}
return sqrt(sum);
}
float yuxianxiangsidu(int tensor_len, float *data0, float *data1)
{
int i;
float fenzi = 0.00;
float fenmu = 0.00;
float len_vec0 = 0.00;
float len_vec1 = 0.00;
for(i = 0; i < tensor_l