本文从四个切入点为你介绍faster r-cnn网络。
经过r-cnn和fast rcnn的积淀,ross b. girshick在2016年提出了新的faster rcnn,在结构上,faster rcnn已经将特征抽取(feature extraction),proposal提取,bounding box regression(rect refine),classification都整合在了一个网络中,使得综合性能有较大提高,在检测速度方面尤为明显。
目录
1 conv layers 2 region proposal networks(rpn) - 2.1 多通道图像卷积基础知识介绍 - 2.2 anchors - 2.3 softmax判定positive与negative - 2.4 bounding box regression原理 - 2.5 对proposals进行bounding box regression - 2.6 proposal layer 3 roi pooling - 3.1 为何需要roi pooling - 3.2 roi pooling原理 4 classification 5 faster rcnn训练 - 5.1 训练rpn网络 - 5.2 通过训练好的rpn网络收集proposals - 5.3 训练faster rcnn网络 questions and answer
图1 faster rcnn基本结构(来自原论文)
依作者看来,如图1,faster rcnn其实可以分为4个主要内容:
conv layers。作为一种cnn网络目标检测方法,faster rcnn首先使用一组基础的conv+relu+pooling层提取image的feature maps。该feature maps被共享用于后续rpn层和全连接层。
region proposal networks。rpn网络用于生成region proposals。该层通过softmax判断anchors属于positive或者negative,再利用bounding box regression修正anchors获得精确的proposals。
roi pooling。该层收集输入的feature maps和proposals,综合这些信息后提取proposal feature maps,送入后续全连接层判定目标类别。
classification。利用proposal feature maps计算proposal的类别,同时再次bounding box regression获得检测框最终的精确位置。
所以本文以上述4个内容作为切入点介绍faster r-cnn网络。 图2展示了python版本中的vgg16模型中的faster_rcnn_test.pt的网络结构,可以清晰的看到该网络对于一副任意大小pxq的图像:
首先缩放至固定大小mxn,然后将mxn图像送入网络;
而conv layers中包含了13个conv层+13个relu层+4个pooling层;
rpn网络首先经过3x3卷积,再分别生成positive anchors和对应bounding box regression偏移量,然后计算出proposals;
而roi pooling层则利用proposals从feature maps中提取proposal feature送入后续全连接和softmax网络作classification(即分类proposal到底是什么object)。
图2 faster_rcnn_test.pt网络结构 (pascal_voc/vgg16/faster_rcnn_alt_opt/faster_rcnn_test.pt)
本文不会讨论任何关于r-cnn家族的历史,分析清楚最新的faster r-cnn就够了,并不需要追溯到那么久。实话说我也不了解r-cnn,更不关心。有空不如看看新算法。
新出炉的pytorch官方faster rcnn代码导读:
捋一捋pytorch官方fasterrcnn代码
https://zhuanlan.zhihu.com/p/31426458
1 conv layers
conv layers包含了conv,pooling,relu三种层。以python版本中的vgg16模型中的faster_rcnn_test.pt的网络结构为例,如图2,conv layers部分共有13个conv层,13个relu层,4个pooling层。这里有一个非常容易被忽略但是又无比重要的信息,在conv layers中:
所有的conv层都是:kernel_size=3,pad=1,stride=1
所有的pooling层都是:kernel_size=2,pad=0,stride=2
为何重要?在faster rcnn conv layers中对所有的卷积都做了扩边处理( pad=1,即填充一圈0),导致原图变为 (m+2)x(n+2)大小,再做3x3卷积后输出mxn 。正是这种设置,导致conv layers中的conv层不改变输入和输出矩阵大小。如图3:
图3 卷积示意图
类似的是,conv layers中的pooling层kernel_size=2,stride=2。这样每个经过pooling层的mxn矩阵,都会变为(m/2)x(n/2)大小。综上所述,在整个conv layers中,conv和relu层不改变输入输出大小,只有pooling层使输出长宽都变为输入的1/2。 那么,一个mxn大小的矩阵经过conv layers固定变为(m/16)x(n/16)!这样conv layers生成的feature map中都可以和原图对应起来。
2 region proposal networks(rpn)
经典的检测方法生成检测框都非常耗时,如opencv adaboost使用滑动窗口+图像金字塔生成检测框;或如r-cnn使用ss(selective search)方法生成检测框。而faster rcnn则抛弃了传统的滑动窗口和ss方法,直接使用rpn生成检测框,这也是faster r-cnn的巨大优势,能极大提升检测框的生成速度。
图4 rpn网络结构
上图4展示了rpn网络的具体结构。可以看到rpn网络实际分为2条线,上面一条通过softmax分类anchors获得positive和negative分类,下面一条用于计算对于anchors的bounding box regression偏移量,以获得精确的proposal。而最后的proposal层则负责综合positive anchors和对应bounding box regression偏移量获取proposals,同时剔除太小和超出边界的proposals。其实整个网络到了proposal layer这里,就完成了相当于目标定位的功能。
2.1 多通道图像卷积基础知识介绍
在介绍rpn前,还要多解释几句基础知识,已经懂的看官老爷跳过就好。
对于单通道图像+单卷积核做卷积,第一章中的图3已经展示了;
对于多通道图像+多卷积核做卷积,计算方式如下:
图5 多通道卷积计算方式
如图5,输入有3个通道,同时有2个卷积核。对于每个卷积核,先在输入3个通道分别作卷积,再将3个通道结果加起来得到卷积输出。所以对于某个卷积层,无论输入图像有多少个通道,输出图像通道数总是等于卷积核数量! 对多通道图像做1x1卷积,其实就是将输入图像于每个通道乘以卷积系数后加在一起,即相当于把原图像中本来各个独立的通道“联通”在了一起。
2.2 anchors
提到rpn网络,就不能不说anchors。所谓anchors,实际上就是一组由rpn/generate_anchors.py生成的矩形。直接运行作者demo中的generate_anchors.py可以得到以下输出:
[[ -84. -40. 99. 55.] [-176. -88. 191. 103.] [-360. -184. 375. 199.] [ -56. -56. 71. 71.] [-120. -120. 135. 135.] [-248. -248. 263. 263.] [ -36. -80. 51. 95.] [ -80. -168. 95. 183.] [-168. -344. 183. 359.]] 其中每行的4个值 表矩形左上和右下角点坐标。9个矩形共有3种形状,长宽比为大约为 三种,如图6。实际上通过anchors就引入了检测中常用到的多尺度方法。
图6 anchors示意图
注:关于上面的anchors size,其实是根据检测图像设置的。在python demo中,会把任意大小的输入图像reshape成800x600(即图2中的m=800,n=600)。再回头来看anchors的大小,anchors中长宽1:2中最大为352x704,长宽2:1中最大736x384,基本是cover了800x600的各个尺度和形状。 那么这9个anchors是做什么的呢?借用faster rcnn论文中的原图,如图7,遍历conv layers计算获得的feature maps,为每一个点都配备这9种anchors作为初始的检测框。这样做获得检测框很不准确,不用担心,后面还有2次bounding box regression可以修正检测框位置。
图7
解释一下上面这张图的数字。
在原文中使用的是zf model中,其conv layers中最后的conv5层num_output=256,对应生成256张特征图,所以相当于feature map每个点都是256-dimensions
在conv5之后,做了rpn_conv/3x3卷积且num_output=256,相当于每个点又融合了周围3x3的空间信息(猜测这样做也许更鲁棒?反正我没测试),同时256-d不变(如图4和图7中的红框)
假设在conv5 feature map中每个点上有k个anchor(默认k=9),而每个anhcor要分positive和negative,所以每个点由256d feature转化为cls=2•k scores;而每个anchor都有(x, y, w, h)对应4个偏移量,所以reg=4•k coordinates
补充一点,全部anchors拿去训练太多了,训练程序会在合适的anchors中随机选取128个postive anchors+128个negative anchors进行训练(什么是合适的anchors下文5.1有解释)
注意,在本文讲解中使用的vgg conv5 num_output=512,所以是512d,其他类似。 其实rpn最终就是在原图尺度上,设置了密密麻麻的候选anchor。然后用cnn去判断哪些anchor是里面有目标的positive anchor,哪些是没目标的negative anchor。所以,仅仅是个二分类而已! 那么anchor一共有多少个?原图800x600,vgg下采样16倍,feature map每个点设置9个anchor,所以:
其中ceil()表示向上取整,是因为vgg输出的feature map size= 50*38。
图8 gernerate anchors
2.3 softmax判定positive与negative
一副mxn大小的矩阵送入faster rcnn网络后,到rpn网络变为(m/16)x(n/16),不妨设 w=m/16,h=n/16。在进入reshape与softmax之前,先做了1x1卷积,如图9:
图9 rpn中判定positive/negative网络结构
该1x1卷积的caffe prototxt定义如下:
layer { name: rpn_cls_score type: convolution bottom: rpn/output top: rpn_cls_score convolution_param { num_output: 18 # 2(positive/negative) * 9(anchors) kernel_size: 1 pad: 0 stride: 1 }} 可以看到其num_output=18,也就是经过该卷积的输出图像为wxhx18大小(注意第二章开头提到的卷积计算方式)。这也就刚好对应了feature maps每一个点都有9个anchors,同时每个anchors又有可能是positive和negative,所有这些信息都保存wxhx(9*2)大小的矩阵。为何这样做?后面接softmax分类获得positive anchors,也就相当于初步提取了检测目标候选区域box(一般认为目标在positive anchors中)。 那么为何要在softmax前后都接一个reshape layer?其实只是为了便于softmax分类,至于具体原因这就要从caffe的实现形式说起了。在caffe基本数据结构blob中以如下形式保存数据: blob=[batch_size, channel,height,width]
对应至上面的保存positive/negative anchors的矩阵,其在caffe blob中的存储形式为[1, 2x9, h, w]。而在softmax分类时需要进行positive/negative二分类,所以reshape layer会将其变为[1, 2, 9xh, w]大小,即单独“腾空”出来一个维度以便softmax分类,之后再reshape回复原状。贴一段caffe softmax_loss_layer.cpp的reshape函数的解释,非常精辟:
number of labels must match number of predictions; e.g., if softmax axis == 1 and prediction shape is (n, c, h, w), label count (number of labels) must be n*h*w, with integer values in {0, 1, ..., c-1}.; 综上所述,rpn网络中利用anchors和softmax初步提取出positive anchors作为候选区域(另外也有实现用sigmoid代替softmax,输出[1, 1, 9xh, w]后接sigmoid进行positive/negative二分类,原理一样)。 2.4 bounding box regression原理
如图9所示绿色框为飞机的ground truth(gt),红色为提取的positive anchors,即便红色的框被分类器识别为飞机,但是由于红色的框定位不准,这张图相当于没有正确的检测出飞机。所以我们希望采用一种方法对红色的框进行微调,使得positive anchors和gt更加接近。
图10
对于窗口一般使用四维向量 表示,分别表示窗口的中心点坐标和宽高。对于图 11,红色的框a代表原始的positive anchors,绿色的框g代表目标的gt,我们的目标是寻找一种关系,使得输入原始的anchor a经过映射得到一个跟真实窗口g更接近的回归窗口g',即:
给定anchor ;
寻找一种变换f,使得:,其中。
图11
那么经过何种变换f才能从图10中的anchor a变为g'呢?比较简单的思路就是:
先做平移:
再做缩放:
观察上面4个公式发现,需要学习的是这四个变换。当输入的anchor a与gt相差较小时,可以认为这种变换是一种线性变换, 那么就可以用线性回归来建模对窗口进行微调(注意,只有当anchors a和gt比较接近时,才能使用线性回归模型,否则就是复杂的非线性问题了)。 接下来的问题就是如何通过线性回归获得 了。线性回归就是给定输入的特征向量x, 学习一组参数w, 使得经过线性回归后的值跟真实值y非常接近,即y=wx。对于该问题,输入x是cnn feature map,定义为φ;同时还有训练传入a与gt之间的变换量,即。输出是四个变换。那么目标函数可以表示为:
其中是对应anchor的feature map组成的特征向量, 是需要学习的参数,是得到的预测值(*表示 x,y,w,h,也就是每一个变换对应一个上述目标函数)。为了让预测值与真实值差距最小,设计l1损失函数:
函数优化目标为:
为了方便描述,这里以l1损失为例介绍,而真实情况中一般使用soomth-l1损失。 需要说明,只有在gt与需要回归框位置比较接近时,才可近似认为上述线性变换成立。
说完原理,对应于faster rcnn原文,positive anchor与ground truth之间的平移量 与尺度因子 如下:
对于训练bouding box regression网络回归分支,输入是cnn feature φ,监督信号是anchor与gt的差距 ,即训练目标是:输入 φ的情况下使网络输出与监督信号尽可能接近。那么当bouding box regression工作时,再输入φ时,回归网络分支的输出就是每个anchor的平移量和变换尺度,显然即可用来修正anchor位置了。
2.5 对proposals进行bounding box regression
在了解bounding box regression后,再回头来看rpn网络第二条线路,如图12。
图12 rpn中的bbox reg
先来看一看上图11中1x1卷积的caffe prototxt定义:
layer { name: rpn_bbox_pred type: convolution bottom: rpn/output top: rpn_bbox_pred convolution_param { num_output: 36 # 4 * 9(anchors) kernel_size: 1 pad: 0 stride: 1 }} 可以看到其 num_output=36,即经过该卷积输出图像为wxhx36,在caffe blob存储为[1, 4x9, h, w],这里相当于feature maps每个点都有9个anchors,每个anchors又都有4个用于回归的变换量。 回到图8,vgg输出 50*38*512 的特征,对应设置 50*38*k 个anchors,而rpn输出:
大小为50*38*2k 的positive/negative softmax分类特征矩阵;
大小为 50*38*4k 的regression坐标回归特征矩阵。
恰好满足rpn完成positive/negative分类+bounding box regression坐标回归。
2.6 proposal layer
proposal layer负责综合所有 变换量和positive anchors,计算出精准的proposal,送入后续roi pooling layer。还是先来看看proposal layer的caffe prototxt定义:
layer { name: 'proposal' type: 'python' bottom: 'rpn_cls_prob_reshape' bottom: 'rpn_bbox_pred' bottom: 'im_info' top: 'rois' python_param { module: 'rpn.proposal_layer' layer: 'proposallayer' param_str: 'feat_stride': 16 }} proposal layer有3个输入:positive vs negative anchors分类器结果rpn_cls_prob_reshape,对应的bbox reg的 变换量rpn_bbox_pred,以及im_info;另外还有参数feat_stride=16,这和图4是对应的。 首先解释im_info。对于一副任意大小pxq图像,传入faster rcnn前首先reshape到固定mxn,im_info=[m, n, scale_factor]则保存了此次缩放的所有信息。然后经过conv layers,经过4次pooling变为wxh=(m/16)x(n/16)大小,其中feature_stride=16则保存了该信息,用于计算anchor偏移量。
图13
proposal layer forward(caffe layer的前传函数)按照以下顺序依次处理:
生成anchors,利用对所有的anchors做bbox regression回归(这里的anchors生成和训练时完全一致);
按照输入的positive softmax scores由大到小排序anchors,提取前pre_nms_topn(e.g. 6000)个anchors,即提取修正位置后的positive anchors;
限定超出图像边界的positive anchors为图像边界,防止后续roi pooling时proposal超出图像边界(见文章底部qa部分图21);
剔除尺寸非常小的positive anchors;
对剩余的positive anchors进行nms(nonmaximum suppression)
proposal layer有3个输入:positive和negative anchors分类器结果rpn_cls_prob_reshape,对应的bbox reg的(e.g. 300)结果作为proposal输出。
之后输出proposal=[x1, y1, x2, y2],注意,由于在第三步中将anchors映射回原图判断是否超出边界,所以这里输出的proposal是对应mxn输入图像尺度的,这点在后续网络中有用。另外我认为,严格意义上的检测应该到此就结束了,后续部分应该属于识别了。 rpn网络结构就介绍到这里,总结起来就是:
生成anchors -> softmax分类器提取positvie anchors -> bbox reg回归positive anchors -> proposal layer生成proposals
3 roi pooling
而roi pooling层则负责收集proposal,并计算出proposal feature maps,送入后续网络。从图2中可以看到rol pooling层有2个输入:
原始的feature maps
rpn输出的proposal boxes(大小各不相同)
3.1 为何需要roi pooling
先来看一个问题:对于传统的cnn(如alexnet和vgg),当网络训练好后输入的图像尺寸必须是固定值,同时网络输出也是固定大小的vector or matrix。如果输入图像大小不定,这个问题就变得比较麻烦。有2种解决办法:
从图像中crop一部分传入网络;
将图像warp成需要的大小后传入网络。
两种办法的示意图如图14,可以看到无论采取那种办法都不好,要么crop后破坏了图像的完整结构,要么warp破坏了图像原始形状信息。 回忆rpn网络生成的proposals的方法:对positive anchors进行bounding box regression,那么这样获得的proposals也是大小形状各不相同,即也存在上述问题。所以faster r-cnn中提出了roi pooling解决这个问题。不过roi pooling确实是从spatial pyramid pooling发展而来,但是限于篇幅这里略去不讲,有兴趣的读者可以自行查阅相关论文。
3.2 roi pooling原理
分析之前先来看看roi pooling layer的caffe prototxt的定义:
layer { name: roi_pool5 type: roipooling bottom: conv5_3 bottom: rois top: pool5 roi_pooling_param { pooled_w: 7 pooled_h: 7 spatial_scale: 0.0625 # 1/16 }} 其中有新参数pooled_w和pooled_h,另外一个参数spatial_scale认真阅读的读者肯定已经知道知道用途。roi pooling layer forward过程:
由于proposal是对应mxn尺度的,所以首先使用spatial_scale参数将其映射回(m/16)x(n/16)大小的feature map尺度;
再将每个proposal对应的feature map区域水平分为pooled_w x pooled_h 的网格;
对网格的每一份都进行max pooling处理。
这样处理后,即使大小不同的proposal输出结果都是 pooled_w x pooled_h 固定大小,实现了固定长度输出。
图15 proposal示意图
4 classification
classification部分利用已经获得的proposal feature maps,通过full connect层与softmax计算每个proposal具体属于那个类别(如人,车,电视等),输出cls_prob概率向量;同时再次利用bounding box regression获得每个proposal的位置偏移量bbox_pred,用于回归更加精确的目标检测框。classification部分网络结构如图16。
图16 classification部分网络结构图
从roi pooling获取到7x7=49大小的proposal feature maps后,送入后续网络,可以看到做了如下2件事:
通过全连接和softmax对proposals进行分类,这实际上已经是识别的范畴了;
再次对proposals进行bounding box regression,获取更高精度的rect box。
这里来看看全连接层innerproduct layers,简单的示意图如图17:
图17 全连接层示意图
其计算公式如下:
其中w和bias b都是预先训练好的,即大小是固定的,当然输入x和输出y也就是固定大小。所以,这也就印证了之前roi pooling的必要性。到这里,我想其他内容已经很容易理解,不在赘述了。
5 faster rcnn训练
faster r-cnn的训练,是在已经训练好的model(如vgg_cnn_m_1024,vgg,zf)的基础上继续进行训练。实际中训练过程分为6个步骤:
在已经训练好的model上,训练rpn网络,对应stage1_rpn_train.pt
利用步骤1中训练好的rpn网络,收集proposals,对应rpn_test.pt
第一次训练fast rcnn网络,对应stage1_fast_rcnn_train.pt
第二训练rpn网络,对应stage2_rpn_train.pt
再次利用步骤4中训练好的rpn网络,收集proposals,对应rpn_test.pt
第二次训练fast rcnn网络,对应stage2_fast_rcnn_train.pt
可以看到训练过程类似于一种“迭代”的过程,不过只循环了2次。至于只循环了2次的原因是应为作者提到:a similar alternating training can be run for more iterations, but we have observed negligible improvements,即循环更多次没有提升了。接下来本章以上述6个步骤讲解训练过程。 下面是一张训练过程流程图,应该更加清晰:
5.1 训练rpn网络
在该步骤中,首先读取rbg提供的预训练好的model(本文使用vgg),开始迭代训练。来看看stage1_rpn_train.pt网络结构,如图19。
图19 stage1_rpn_train.pt(考虑图片大小,conv layers中所有的层都画在一起了,如红圈所示,后续图都如此处理)
与检测网络类似的是,依然使用conv layers提取feature maps。整个网络使用的loss如下:
上述公式中 i 表示anchors index,表示positive softmax probability, 代表对应的gt predict概率(即当第i个anchor与gt间iou>0.7,认为是该anchor是positive,;反之iou<0.3时,认为是该anchor是negative,;至于那些0.3
cls loss,即rpn_cls_loss层计算的softmax loss,用于分类anchors为positive与negative的网络训练;
reg loss,即rpn_loss_bbox层计算的soomth l1 loss,用于bounding box regression网络训练。注意在该loss中乘了 ,相当于只关心positive anchors的回归(其实在回归中也完全没必要去关心negative)。
由于在实际过程中,和差距过大,用参数λ平衡二者(如,时设置 ),使总的网络loss计算过程中能够均匀考虑2种loss。这里比较重要是 使用的soomth l1 loss,计算公式如下:
了解数学原理后,反过来看图18:
在rpn训练阶段,rpn-data(python anchortargetlayer)层会按照和test阶段proposal层完全一样的方式生成anchors用于训练;
对于rpn_loss_cls,输入的rpn_cls_scors_reshape和rpn_labels分别对应 与 ,参数隐含在与的caffe blob的大小中;
对于rpn_loss_bbox,输入的rpn_bbox_pred和rpn_bbox_targets分别对应 t 与 t* ,rpn_bbox_inside_weigths对应 ,rpn_bbox_outside_weigths未用到(从smooth_l1_loss layer代码中可以看到),而同样隐含在caffe blob大小中。
这样,公式与代码就完全对应了。特别需要注意的是,在训练和检测阶段生成和存储anchors的顺序完全一样,这样训练结果才能被用于检测!
5.2 通过训练好的rpn网络收集proposals
在该步骤中,利用之前的rpn网络,获取proposal rois,同时获取positive softmax probability,如图20,然后将获取的信息保存在python pickle文件中。该网络本质上和检测中的rpn网络一样,没有什么区别。
图20 rpn_test.pt
5.3 训练faster rcnn网络
读取之前保存的pickle文件,获取proposals与positive probability。从data层输入网络。然后:
将提取的proposals作为rois传入网络,如图21蓝框;
计算bbox_inside_weights+bbox_outside_weights,作用与rpn一样,传入soomth_l1_loss layer,如图21绿框。
这样就可以训练最后的识别softmax与最终的bounding box regression了。
图21 stage1_fast_rcnn_train.pt
之后的stage2训练都是大同小异,不再赘述了。faster r-cnn还有一种end-to-end的训练方式,可以一次完成train,有兴趣请自己看作者github吧。 rbgirshick py-faster-rcn: github.com/rbgirshick/py-faster-rcnn
q&a
此篇文章初次成文于2016年内部学习分享,再后来经多次修正和完善成为现在的样子。感谢大家一直以来的支持,现在总结常见疑问回答如下:
为什么anchor坐标中有负数?
回顾anchor生成步骤:首先生成9个base anchor,然后通过坐标偏移在50*38 大小的 1/16下采样featuremap每个点都放上这9个base anchor,就形成了 50*38*k 个anhcors。至于这9个base anchor坐标是什么其实并不重要,不同代码实现也许不同。 显然这里面有一部分边缘anchors会超出图像边界,而真实中不会有超出图像的目标,所以会有clip anchor步骤。
图21 clip anchor
anchor到底与网络输出如何对应?
vgg输出 50*38*512 的特征,对应设置 50*38*k 个anchors,而rpn输出 50*38*2k 的分类特征矩阵和 50*38*4k 的坐标回归特征矩阵。
图22 anchor与网络输出如何对应方式
其实在实现过程中,每个点的 2k 个分类特征与 4k 回归特征,与 k 个anchor逐个对应即可,这实际是一种“人为设置的逻辑映射”。当然,也可以不这样设置,但是无论如何都需要保证在训练和测试过程中映射方式必须一致。
为何有roi pooling还要把输入图片resize到固定大小的mxn?
由于引入roi pooling,从原理上说faster r-cnn确实能够检测任意大小的图片。但是由于在训练的时候需要使用大batch训练网络,而不同大小输入拼batch在实现的时候代码较为复杂,而且当时以caffe为代表的第一代深度学习框架也不如tensorflow和pytorch灵活,所以作者选择了把输入图片resize到固定大小的800x600。这应该算是历史遗留问题。 另外很多问题,都是属于具体实现问题,真诚的建议读者阅读代码自行理解。
在线自动雷达水位雨量监测系统功能的简介
杭州聚佳科技有限公司
跑步戴什么耳机比较好,最适合跑步用的平价耳机
4K能否引领投影仪未来风向?4K家用投影机推荐
机械光开关和MEMS光开关的介绍
faster rcnn网络结构详解(四个切入点)
一般FPC产品类型及性能介绍
在人工智能的创造智慧方面,人类永远最有发言权
穷到亚洲倒数,该国却消耗7吨黄金建黄金塔,连市区公路都要让路
32位单片机智能门锁解决方案的详细介绍
HIL测试技术在汽车ECU开发流程中的应用
MRI技术可量化非酒精性脂肪性肝炎患者的肝脏反应
MOTO 4G双核XT860 开始发布
意法半导体推出新款汽车级高边驱动器
pcb怎么改变走线角度?
中国通信学会量子计算委员会成立
新能源和智能化 未来汽车的发展方向
测试万用表是否正常工作的方法
关于三种无线局域网的定位技术
框架与芯片粘接中两种涂胶