当前位置: 首页 > news >正文

信息熵 条件熵 交叉熵 联合熵 相对熵(KL散度) 互信息(信息增益)

粗略版快速总结

条件熵 H ( Q ∣ P ) = 联合熵 H ( P , Q ) − H ( P ) 条件熵H(Q∣P)=联合熵H(P,Q)−H(P) 条件熵H(QP)=联合熵H(P,Q)H(P)

信息增益 I ( P , Q ) = H ( P ) − H ( P ∣ Q ) = H ( P ) + H ( Q ) − H ( P , Q ) 信息增益 I(P,Q)=H(P)−H(P∣Q)=H(P)+H(Q)-H(P,Q) 信息增益I(P,Q)=H(P)H(PQ)=H(P)+H(Q)H(P,Q),也就是Information Gain,互信息

KL散度(相对熵) K L ( P , Q ) = − H ( P ) + 交叉熵 C E ( P , Q ) KL(P,Q)=-H(P)+交叉熵CE(P,Q) KL(P,Q)=H(P)+交叉熵CE(P,Q)

详细定义

如果一个样本是n类其中之一,也就是说target是onehot形式,例如三类那么target=[0,0,1],拿target=[0,0,1]来说就是 p 0 = 0 p_0=0 p0=0 p 1 = 0 p_1=0 p1=0 p 2 = 1 p_2=1 p2=1。写成表达式可以是 p i p_i pi,n=3
那么经过神经网络运算出来的Logits可能是在(-inf,inf)之间,那么一般会通过softmax归一化到(0,1)之间,这个归一化到(0,1)之间的数我们可以用 q i q_i qi来表示,当然对于上面有3类的例子来说,n=3
好了,既然明确了 p i p_i pi是第i个类的在(0,1)之间target q i q_i qi是第i个类的logit归一化到(0,1)之间的结果,那么开始各种定义了

相对熵(KL散度)

K L ( P , Q ) = ∑ i ∈ [ 0 , n − 1 ] p i l o g p i q i KL(P,Q)=\sum _{i \in[0,n-1]}p_i log \frac{p_i}{q_i} KL(P,Q)=i[0,n1]pilogqipi

交叉熵(CE Loss)

C E ( P , Q ) = − ∑ i ∈ [ 0 , n − 1 ] p i l o g q i K L ( P , Q ) = H ( P ) + C E ( P , Q ) CE(P,Q)=-\sum _{i \in[0,n-1]}p_i log q_i \\ KL(P,Q) = H(P)+CE(P,Q) CE(P,Q)=i[0,n1]pilogqiKL(P,Q)=H(P)+CE(P,Q)
来看一下Pytorch里的交叉熵是怎么实现的,手动验证下:

import torch
from torch import nn
import mathloss_f = nn.CrossEntropyLoss(reduction='mean')
output = torch.randn(2,3) #表示2个样本,3个类别
# target = torch.from_numpy(np.array([1, 0])).type(torch.LongTensor)
target = torch.LongTensor([0,2]) #表示label0和label2
loss = loss_f(output, target)print('CrossEntropy loss: ', loss)
print(f'reduction=none,所以可以看到每一个样本loss,输出为[{loss}]')def manual_cal(sample_index, target, output):#输入是样本下标sample_output = output[sample_index]sample_target = target[sample_index]x_class = sample_output[sample_target]sample_output_len = len(sample_output)log_sigma_exp_x = math.log(sum(math.exp(sample_output[i]) for i in range(sample_output_len)))sample_loss = -x_class + log_sigma_exp_xprint(f'交叉熵手动计算loss{sample_index}{sample_loss}')return sample_lossfor i in range(2):manual_cal(i, target, output)# 如果nn.CrossEntropyLoss(reduction='mean')模式,刚好是手动计算的每个样本的loss取平均,最后输出的是一个值
# 如果nn.CrossEntropyLoss(reduction='none')模式,手动计算的loss0和loss1都会被列出来

在这里插入图片描述

(class torch.nn.CrossEntropyLoss(weight=None, size_average=None, ignore_index=-100, reduce=None, reduction=‘elementwise_mean’)
功能: 将输入经过softmax激活函数之后,再计算其与target的交叉熵损失。即该方法将nn.LogSoftmax()和 nn.NLLLoss()进行了结合。严格意义上的交叉熵损失函数应该是nn.NLLLoss()。
在这里插入图片描述
补充:交叉熵损失(cross-entropy Loss) 又称为对数似然损失(Log-likelihood Loss)、对数损失;二分类时还可称之为逻辑斯谛回归损失(Logistic Loss)。交叉熵损失函数表达式为 L = - sigama(y_i * log(x_i))。pytroch这里不是严格意义上的交叉熵损失函数(下面会详细解释,pytorch中交叉熵不够严格主要是因为只能接受one hot),而是先将input经过softmax激活函数,将向量“归一化”成概率形式,然后再与target计算严格意义上交叉熵损失。 在多分类任务中,经常采用softmax激活函数+交叉熵损失函数,因为交叉熵描述了两个概率分布的差异,然而神经网络输出的是向量,并不是概率分布的形式。所以需要softmax激活函数将一个向量进行“归一化”成概率分布的形式,再采用交叉熵损失函数计算loss。 再回顾PyTorch的CrossEntropyLoss(),官方文档中提到时将nn.LogSoftmax()和 nn.NLLLoss()进行了结合,nn.LogSoftmax() 相当于激活函数 , nn.NLLLoss()是损失函数;

来感受一下交叉熵取值的妙处:当 q i q_i qi很接近1时, − l o g q i -logq_i logqi很接近0,如果此时 p i p_i pi是1,这时候整体loss会很小;当 q i q_i qi很接近0时, − l o g q i -logq_i logqi很大, p i p_i pi是1,这时候整体loss会很大。所以 p i p_i pi就是筛选的功能,在Pytorch中CrossEntropyLoss等于LogSoftmax和NLLLoss的结合:LogSoftmax是上面公式里的 l o g ( e x p ( x [ c l a s s ] ) ∑ j e x p ( x [ j ] ) ) log(\frac{exp(x[class])}{\sum_jexp(x[j])}) log(jexp(x[j])exp(x[class])),实现了整个 l o g q i logq_i logqi的效果;NLLLoss就是给前面加了一个负号。所以在torch中的CrossEntropy = NLLLoss(LogSoftmax)
pytorch中交叉熵不够严格主要是因为只能接受one hot,也就是说torch中的target只能明确指明是哪个target,而不是上面公式 p i p_i pi是(0,1)之间,所以在Pytorch中还保留了KLDivLoss这个loss来接受广泛的取值:

import torch.nn.functional as F
import torch
import torch.nn as nn
# nn.CrossEntropyLoss() 和  KLDivLoss 关系y_pred = torch.tensor([[10.0, 0.0, -10.0], [8.0, 8.0, 8.0]])
y_true = torch.tensor([0, 2])
ce = nn.CrossEntropyLoss(reduction="none")(y_pred, y_true)
print(ce)
'''
输出shape是2,tensor([4.5418e-05, 1.0986e+00])
'''# NLLLoss要求target只能是第几类下标,例如[0,2]表示[label0,label2],转成onehot就是[[1,0,0],[0,0,1]]
nll_log_softmax = nn.NLLLoss(reduction="none")(F.log_softmax(y_pred, dim=-1), y_true)
print(nll_log_softmax)
'''
输出shape是2,tensor([4.5418e-05, 1.0986e+00])
'''one_hot = F.one_hot(y_true) #将第几类的下标转换成onehot形式,例如输入[0,2]表示[label0,label2],输出onehot就是[[1,0,0],[0,0,1]]
'''
# KLDivLoss要求target为float形式编码,one_hot是longtensor,所以要one_hot.float();如果是普通的logics,要过一下softmax# KLDivLoss也要求Logits经过LogSoftmax激活。LogSoftmax会把(-inf,inf)的Logits映射到(0,1)再映射到(-inf,0):当用NLLLoss时,刚好多个负号loss变成(0,inf);当用KLDivLoss时,刚好多个熵。回顾klLoss的公式 p_i*log(p_i/q_i),其中p_i是(0,1)范围内的targets
q_i是将logits映射到(0,1)范围内的结果,所以p_i和q_i都是(0,1)之间
KLDivLoss这个函数的特点就是把log(q_i)这一步扔给输入自己算,这个函数管的只是p_i*log(p_i)-p_i*inputNLLLoss这个函数的特点就是把p_i*log(p_i)也没了,只有-p_i*input,所以和LogSoftmax组合起来是CE
'''kl = nn.KLDivLoss(reduction="none")(F.log_softmax(y_pred, dim=-1), one_hot.float())
print(kl) #输出shape是2*3
'''
tensor([[4.5418e-05, 0.0000e+00, 0.0000e+00],[0.0000e+00, 0.0000e+00, 1.0986e+00]])
'''a = F.softmax(torch.randn(2,3))
print(nn.KLDivLoss(reduction="none")(torch.log(a), a))
'''
输出是
tensor([[0., 0., 0.],[0., 0., 0.]])回顾klLoss的公式 p_i*log(p_i/q_i),其中p_i是(0,1)范围内的targets
q_i是将logits映射到(0,1)范围内的结果,所以p_i和q_i都是(0,1)之间
KLDivLoss这个函数的特点就是把log(q_i)这一步扔给输入自己算,这个函数管的只是p_i*log(p_i)-p_i*inputNLLLoss这个函数的特点就是把p_i*log(p_i)也没了,只有-p_i*input,所以和LogSoftmax组合起来是CE
'''

为什么既有 KL 散度又有交叉熵?在信息论中,熵的意义是对 𝑃
事件的随机变量编码所需的最小字节数
,KL 散度的意义是**“额外所需的编码长度”如果我们使用 𝑄的编码来表示 𝑃**,交叉熵指的是当你使用 𝑄作为密码来表示 𝑃 是所需要的 “平均的编码长度”。但是在机器学习评价两个分布之间的差异时,由于分布 𝑃 会是给定的,所以此时 KL 散度和交叉熵的作用其实是一样的,而且因为交叉熵少算一项,更加简单,所以选择交叉熵会更好。

Label Smoothing

Label Smoothing是一种防止网络过拟合的手段,在Pytorch的CrossEntropy中已经自带了这个参数,下图截自Hinton的论文When Does Label Smoothing Help? 从公式来看只把我们上面说的label/target做了一个衰减,更多细节可以参考https://blog.csdn.net/taoqick/article/details/121717218 :
在这里插入图片描述

联合熵

H ( P , Q ) = − ∑ i ∈ [ 0 , n − 1 ] P ( p i , q i ) l o g P ( p i , q i ) H(P,Q)=-\sum _{i \in[0,n-1]}P(p_i,q_i)logP(p_i,q_i) H(P,Q)=i[0,n1]P(pi,qi)logP(pi,qi)

条件熵

注意下面 P ( q i ∣ p i ) P(q_i|p_i) P(qipi)表示 p i p_i pi q i q_i qi对应变量的条件概率, P ( p i , q i ) P(p_i,q_i) P(pi,qi)表示 p i p_i pi q i q_i qi对应变量的联合概率,写成这样只是为了简化但不够严谨。
H ( Q ∣ P ) = ∑ i ∈ [ 0 , n − 1 ] p i H ( Q ∣ P = p i ) H ( Q ∣ P ) = − ∑ i ∈ [ 0 , n − 1 ] p i ∗ P ( q i ∣ p i ) l o g P ( q i ∣ p i ) H ( Q ∣ P ) = − ∑ i ∈ [ 0 , n − 1 ] P ( p i , q i ) l o g P ( q i ∣ p i ) H(Q|P)=\sum _{i \in[0,n-1]}p_iH(Q|P=p_i) \\ H(Q|P)=-\sum _{i \in[0,n-1]}p_i*P(q_i|p_i)logP(q_i|p_i) \\ H(Q|P)=-\sum _{i \in[0,n-1]}P(p_i,q_i)logP(q_i|p_i) H(QP)=i[0,n1]piH(QP=pi)H(QP)=i[0,n1]piP(qipi)logP(qipi)H(QP)=i[0,n1]P(pi,qi)logP(qipi)
上面就解释了为啥log里面是条件,外面是联合,更进一步地把里面也展开
H ( Q ∣ P ) = − ∑ i ∈ [ 0 , n − 1 ] P ( p i , q i ) l o g P ( q i ∣ p i ) H ( Q ∣ P ) = − H ( P , Q ) − ∑ i ∈ [ 0 , n − 1 ] P ( p i , q i ) l o g P ( p i ) H ( Q ∣ P ) = − H ( P , Q ) + H ( P ) H(Q|P)=-\sum _{i \in[0,n-1]}P(p_i,q_i)logP(q_i|p_i) \\ H(Q|P)=-H(P,Q)-\sum _{i \in[0,n-1]}P(p_i,q_i)logP(p_i) \\ H(Q|P)=-H(P,Q)+H(P) H(QP)=i[0,n1]P(pi,qi)logP(qipi)H(QP)=H(P,Q)i[0,n1]P(pi,qi)logP(pi)H(QP)=H(P,Q)+H(P)


至于熵为什么是这个定义请参考 为什么信息熵要定义成 − Σ p ∗ l o g ( p ) -Σp*log(p) Σplog(p)?(https://blog.csdn.net/taoqick/article/details/72852255)。简单来说就是-log§就是信息量,单位用比特表示,例如中国队夺世界杯的信息量远比法国队夺世界杯信息量大。把一个系统里所有的-log§再乘以p就是熵,表示所有信息量加权平均,或者说熵就是信息量的数学期望

还有3个重要结论:

  1. 最小化交叉熵和极大似然本质上是一样的,更多推导参考:最小化交叉熵损失与极大似然 - 知乎(https://zhuanlan.zhihu.com/p/51099880)

  2. 为什么分类问题用相对熵不用MSE,原因之一是求解时相对熵的梯度下降更快一些,这样可以实现错误越大,下降的越快的效果,更多推导请参考: 分类问题中为什么用交叉熵而不用MSE KL散度和交叉熵的关系_taoqick的专栏-CSDN博客_mse和交叉熵 (https://blog.csdn.net/taoqick/article/details/102621605)

  3. 李航老师书里说的最大熵模型是条件熵最大化,想法就是某些知识已经先验知道了,剩下的随机变量尽量等概率随机,这样条件熵最大。学习概率模型时,在满足约束(特征函数)的所有的可能的概率分布中,熵最大的模型就是最大的模型。最大熵模型是判别式模型。

更多推导请参考李航老师的书和数学之美。



相关文章:

信息熵 条件熵 交叉熵 联合熵 相对熵(KL散度) 互信息(信息增益)

粗略版快速总结 条件熵 H ( Q ∣ P ) 联合熵 H ( P , Q ) − H ( P ) 条件熵H(Q∣P)联合熵H(P,Q)−H(P) 条件熵H(Q∣P)联合熵H(P,Q)−H(P) 信息增益 I ( P , Q ) H ( P ) − H ( P ∣ Q ) H ( P ) H ( Q ) − H ( P , Q ) 信息增益 I(P,Q)H(P)−H(P∣Q)H(P)H(Q)-H(P,Q) 信息…...

Fiddler Response私人订制

在客户端接口的测试中,我们经常会需要模拟各种返回状态或者特定的返回值,常见的是用Fiddler模拟各种请求返回值场景,如重定向AutoResponder、请求拦截修改再下发等等。小编在近期的测试中遇到的一些特殊的请求返回模拟的测试场景,…...

【德哥说库系列】-ASM管理Oracle 19C单实例部署

📢📢📢📣📣📣 哈喽!大家好,我是【IT邦德】,江湖人称jeames007,10余年DBA及大数据工作经验 一位上进心十足的【大数据领域博主】!😜&am…...

手写一个简单爬虫--手刃豆瓣top250排行榜

#拿到页面面源代码 request #通过re来提取想要的有效信息 re import requests import re url"https://movie.douban.com/top250"headers{"user-agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/11…...

【word密码】如何限制word文件中部分内容?

Word文件中有一部分内容不想他人编辑,我们可以设置限制编辑,可以对一部分内容设置限制编辑,具体方法如下: 我们将需要将可以编辑的地方选中,然后打开限制编辑功能 然后勾选限制编辑设置界面中的【限制编辑】和【每个人…...

spring 自定义类型转换-ConverterRegistry

1背景介绍 一个应用工程里面,一遍会涉及到很多的模型转换,如DTO模型转DO模型,DO模型转DTO, 或者Request转DTO模型,总的来说,维护起来还是相对比较复杂。每涉及一个转换都需要重新写对应类的get或者set方法&#xff0c…...

springboot实现发送短信验证码

目录 一、选择并注册短信服务提供商: 二、添加依赖: 三、配置短信服务信息: 四、编写发送短信验证码的方法: 五、调用发送短信验证码的方法: 一、选择并注册短信服务提供商: 1、选择一个可靠的短信服…...

2024王道408数据结构P144 T18

2024王道408数据结构P144 T18 思考过程 首先还是先看题目的意思,让我们在中序线索二叉树里查找指定结点在后序的前驱结点,这题有一点难至少对我来说…我讲的不清楚理解一下我做的也有点糊涂。在创建结构体时多两个变量ltag和rtag,当ltag0时…...

在windows下安装配置skywalking

1.下载地址 Downloads | Apache SkyWalkinghttp://skywalking.apache.org/downloads/ 2.文件目录说明 将文件解压后,可看到agent和bin目录: Agent:作为探针,安装在服务器端,进行数据采集和上报。 Config&#xff1a…...

关于大模型参数微调的不同方法

Adapter Tuning 适配器模块(Adapter Moudle)可以生成一个紧凑且可扩展的模型;每个任务只需要添加少量可训练参数,并且可以在不重新访问之前任务的情况下添加新任务。原始网络的参数保持不变,实现了高度的参数共享 Pa…...

方法的引用第一版(method reference)

1、体验方法引用 在使用Lambda表达式的时候,我们实际上传递进去的代码就是一种解决方案:拿参数做操作那么考虑一种情况:如果我们在Lanbda中所指定的操作方案,已经有地方存在相同方案,那是否还有必要再重复逻辑呢&#…...

Android DataBinding 基础入门(学习记录)

目录 一、DataBinding简介二、findViewById 和 DataBinding 原理及优缺点1. findViewById的优缺点2. DataBinding的优缺点 三、Android mvvm 之 databinding 原理1. 简介和三个主要的实体DataViewViewDataBinding 2.三个功能2.1. rebind 行为2.2 observe data 行为2.3 observe …...

spring 错误百科

一、使用Spring出错根源 1、隐式规则的存在 你可能忽略了 Sping Boot 中 SpringBootApplication 是有一个默认的扫描包范围的。这就是一个隐私规则。如果你原本不知道,那么犯错概率还是很高的。类似的案例这里不再赘述。 2、默认配置不合理 3、追求奇技淫巧 4、…...

OpenCV基本操(IO操作,读取、显示、保存)

图像的IO操作,读取和保存方法 1.1 API cv.imread()参数: 要读取的图像 读取图像的方式: cv.IMREAD*COLOR:以彩色模式加载图像,任何图像的图像的透明度都将被忽略。这是默认参数 标志: 1 cv.IMREAD*GRAYSCALE :以…...

1.快速搭建Flask项目

一.Pear Admin Flask 官网文档:http://www.pearadmin.com/doc/index.html 1.1下载安装 # 下 载 git clone https://gitee.com/pear-admin/pear-admin-flask# 安 装 pip install -r requirements.txt1.2修改配置 applications下的config.py docker运行的修改dockerdata/conf…...

编程题四大算法思想(三)——贪心法:找零问题、背包问题、任务调度问题、活动选择问题、Prim算法

文章目录 贪心法找零问题(change-making problem)贪心算法要求基本思想适合求解问题的特征 背包问题0/1背包问题0/1背包问题——贪心法 分数背包问题 任务调度问题活动选择问题活动选择——贪心法最早结束时间优先——最优性证明 Prim算法 贪心法 我在当…...

core dump管理在linux中的前世今生

目录 一、什么是core dump? 二、coredump是怎么来的? 三、怎么限制coredump文件的产生? ulimit 半永久限制 永久限制 四、从源码分析如何对coredump文件的名字和路径管理 命名 管理 一些问题的答案 1、为什么新的ubuntu不能产生c…...

Springboot整合knife4j配置swagger教程-干货

开启swagger文档&#xff0c;直接上教程。 第一步:引入依赖 <!--swagger 依赖--><dependency><groupId>com.github.xiaoymin</groupId><artifactId>knife4j-spring-boot-starter</artifactId><version>3.0.3</version></d…...

C++ 中的 Pimpl 惯用法

C 中的 Pimpl 惯用法 介绍 Pimpl&#xff08;Pointer to Implementation&#xff09;是一种常见的 C 设计模式&#xff0c;用于隐藏类的实现细节&#xff0c;从而减少编译依赖和提高编译速度。本文将通过一个较为复杂的例子&#xff0c;展示如何使用智能指针&#xff08;如 s…...

【个人博客系统网站】统一处理 · 拦截器

【JavaEE】进阶 个人博客系统&#xff08;2&#xff09; 文章目录 【JavaEE】进阶 个人博客系统&#xff08;2&#xff09;1. 统一返回格式处理1.1 统一返回类common.CommonResult1.2 统一返回处理器component.ResponseAdvice 2. 统一异常处理3. 拦截器实现3.1 全局变量SESSI…...

深入探索PHP编程:文件操作与输入/输出(I/O)

深入探索PHP编程&#xff1a;文件操作与输入/输出&#xff08;I/O&#xff09; 在PHP编程中&#xff0c;文件操作和输入/输出&#xff08;I/O&#xff09;是不可或缺的关键部分。无论是读取、写入文件&#xff0c;还是处理上传的文件&#xff0c;这些操作都是Web开发的重要组成…...

基于jeecg-boot的flowable流程自定义业务驳回到发起人的一种处理方式

有些粉丝&#xff0c;希望对自定义业务中&#xff0c;驳回到发起人进行处理&#xff0c;比如可以重新进行发起流程&#xff0c;下面就给出一种方式&#xff0c;当然不一定是最好的方式&#xff0c;只是提供一种参考而已&#xff0c;以后可以考虑动态根据流程状态或节点信息进行…...

【大数据知识】大数据平台和数据中台的定义、区别以及联系

数据行业有太多数据名词&#xff0c;例如大数据、大数据平台、数据中台、数据仓库等等。但大家很容易混淆&#xff0c;也很容易产生疑问&#xff0c;今天我们就来简单聊聊大数据平台和数据中台的定义、区别以及联系。 大数据平台和数据中台的定义 大数据平台&#xff1a;一个…...

华为OD:IPv4地址转换成整数

题目描述&#xff1a; 存在一种虚拟IPv4地址&#xff0c;由4小节组成&#xff0c;每节的范围为0-255&#xff0c;以#号间隔&#xff0c;虚拟IPv4地址可以转换为一个32位的整数&#xff0c;例如&#xff1a; 128#0#255#255&#xff0c;转换为32位整数的结果为2147549183&#…...

2023.9 - java - 浅拷贝

与 js的浅拷贝不同&#xff1a; 在 JavaScript 中&#xff0c; Object.assign() 或 spread 运算符等方法可以实现浅拷贝&#xff0c;但只针对对象的第一层属性进行复制。如果一个对象只包含基本数据类型的属性&#xff0c;那么对浅拷贝出来的对象进行修改不会影响原始对象&…...

STM32f103入门(10)ADC模数转换器

ADC模数转换器 ADC简介AD单通道初始化代码编写第一步开启时钟第二步 RCCCLK分频 6分频 72M/612M第三步 配置GPIO 配置为AIN状态第四步&#xff0c;选择规则组的输入通道第五步 用结构体 初始化ADC第六步 对ADC进行校准编写获取电压函数初始化代码如下 Main函数编写 ADC简介 ADC…...

实训笔记8.28

实训笔记8.28 8.28笔记一、大数据计算场景主要分为两种1.1 离线计算场景1.2 实时计算场景 二、一般情况下大数据项目的开发流程2.1 数据采集存储阶段2.2 数据清洗预处理阶段2.3 数据统计分析阶段2.4 数据挖掘预测阶段2.5 数据迁移阶段2.6 数据可视化阶段 三、纯大数据离线计算项…...

机器学习笔记之最优化理论与方法(五)凸优化问题(上)

机器学习笔记之最优化理论与方法——凸优化问题[上] 引言凸优化问题的基本定义凸优化定义&#xff1a;示例 凸优化与非凸优化问题的区分局部最优解即全局最优解凸优化问题的最优性条件几种特殊凸问题的最优性条件无约束凸优化等式约束凸优化非负约束凸优化 引言 本节将介绍凸优…...

在Windows10上编译grpc工程,得到protoc.exe和grpc_cpp_plugin.exe

grpc是google于2015年发布的一款跨进程、跨语言、开源的RPC(远程过程调用)技术。使用C/S模式&#xff0c;在客户端、服务端共享一个protobuf二进制数据。在点对点通信、微服务、跨语言通信等领域应用很广&#xff0c;下面介绍grpc在windows10上编译&#xff0c;这里以编译grpc …...

一些测试知识

希望能起到帮助&#xff0c;博主主页&#xff1a; https://blog.csdn.net/qq_57785602/category_12023254.html?spm1001.2014.3001.5482 软件测试理论 测试的依据&#xff1a; 需求&#xff0c;规格说明&#xff0c;模型&#xff0c;用户需求等 什么是软件测试 描述一种来…...