专栏电商日志财经减肥爱情
投稿投诉
爱情常识
搭配分娩
减肥两性
孕期塑形
财经教案
论文美文
日志体育
养生学堂
电商科学
头戴业界
专栏星座
用品音乐

DiveintoTensorFlow系列(3)揭开Tenso

  TensorFlow计算图是由op和tensor组成,那么tensor一般都用来代表什么呢?显然,像模型的输入数据、网络权重、输入数据经op处理后的输出结果都需要用张量或特殊张量进行表达。既然tensor在TensorFlow体系架构中如此重要,因此本文将带领大家由浅入深地学习tensor的三个话题:用户眼中的tensor、TensorFlow系统中的tensor、tensor高阶用法DLPack(跨框架编程,如:TensorFlowPyTorch)。
  注:本文基于TensorFlowv1。15。5进行编写。一、小白眼中的Tensor1。1TensorHelloWorld
  定义两个张量,然后对其求加法,相关代码如下:segment1atf。constant(3。0,dtypetf。float32)btf。constant(4。0)alsotf。float32implicitlytotalabprint(a)print(b)print(total)三个print的输出如下:Tensor(Const:0,shape(),dtypefloat32)Tensor(Const1:0,shape(),dtypefloat32)Tensor(add:0,shape(),dtypefloat32)说明:此时的Tenosr尚不能产生真正的结果。以上代码创建了计算图,Tensor只是代表op运行的结果(但此时op未运行)。
  如果想看到最终total的计算结果,则应该创建Session对象并运行计算图,具体代码如下(在segment1基础上增加代码):withtf。Session()assess:resultsess。run(total)print(result,type(result),type(total))输出结果7。0classnumpy。float32classtensorflow。python。framework。ops。Tensor
  由此可见,Tensor代表尚未执行的结果表示,创建Session对象并运行计算图可得total结果7。0,并且结果的数据类型已变为numpy。最后说明一下,本小节代码输出的Tensor是指tf。Tensor,对应的代码实现是tensorflow。python。framework。ops。Tensor。1。2张量属性及特殊张量
  从用户视角看tf。Tensor主要有三个属性:name、dtype、shape。除此之外,还有三个属性比较重要(不常用或者不直接可见):op、graph、device。其中op属性记录产生此Tensor的操作名称,graph属性记录包含此Tensor的计算图,device属性记录产生此Tensor的设备名称。
  在TensorFlow体系中有四种特殊的张量(此处暂不严格区分Tensor与产生此Tensor的op),具体如下:
  tf。Variable:定义内容可变的张量,一般用来定义模型权重。
  tf。constant:一般来说,张量内容不可变,此API可用来定义常规张量。
  tf。placeholder:占位符张量,用于描述静态图输入规格。静态图采用先编译后执行的方式,因此在定义计算图时要知道输入规格。
  tf。SparseTensor:为稀疏数据定制的张量结构。1。3Tensor与op的关系
  我们多次提到,Tensor可以作为op的输入,经op一系列处理后产生新的Tensor作为输出。为了深入理解这一点,我们回头重新审视segment1中的代码片段(请大家注意Tensor的命名):segment1atf。constant(3。0,dtypetf。float32)btf。constant(4。0)alsotf。float32implicitlytotalabprint(a)print(b)print(total)三个print的输出如下:Tensor(Const:0,shape(),dtypefloat32)Tensor(Const1:0,shape(),dtypefloat32)Tensor(add:0,shape(),dtypefloat32)说明:此时的Tenosr尚不能产生真正的结果。以上代码创建了计算图,Tensor只是代表op运行的结果(但此时op未运行)。
  针对上述代码,我们先来看看哪些是Tensor,哪些是op,然后基于此分别描述每一个操作的执行过程。为回答第一个问题,我们先看一段TensorFlow官方注释:tf。constantcreatesaConstnodeinthecomputationgraphwiththeexactvalueatgraphconstructiontime。
  由此可见,segment1的代码中有两种op,分别为Const和add,前者出现了两次,而后者1次。基于此,我们得知segment1依次向计算图中添加了三个op,与此同时也可以回答第二个问题,即每个操作的过程。具体如下:三个print的输出如下(a,b,total):Tensor(Const:0,shape(),dtypefloat32)Tensor(Const1:0,shape(),dtypefloat32)Tensor(add:0,shape(),dtypefloat32)向计算图添加第一个op(Const),输入是一个标量,输出是Tensora,其名称由两部分组成,即op名称:a在op输出的索引位置。向计算图添加第二个op(Const1,因为op名称要唯一),输入标量,输出Tensorb,其命名规则同上。向计算图添加第三个op(add),输入是Tensora和b,输出Tensortotal,其命名规则同上。二、一探tensor究竟2。1前后端Tensor映射
  在TensorFlow的白皮书〔7〕中提到CAPI是连接前端用户代码和后端执行引擎的桥梁,为深入理解这个概念,建议读者参照TensorFlow官网从头编译源代码。TensorFlowv1。15。5基于Bazel进行编译,前端python与后端C通过SWIG进行交互。实际上在系统编译之前会先启动SWIG代码生成过程,通过解析tensorflow。i自动生成两个wrapper文件:pywraptensorflowinternal。py和pywraptensorflowinternal。cc,前者对接前端python调用,后者对接后端CAPI调用。大家安装tensorflow官方二进制包后,只能看到py文件而没有cc文件。如果自己编译TensorFlow源码,可在项目根目录下的bazelbin中找到相应的py和cc文件,如下图所示:
  上图红框中的so文件是由cc文件编译得到,黄框中的py模块首次被导入时,会自动加载so动态链接库。而在so对应的cc文件中,静态注册了一个函数映射表,实现python函数到C函数的映射。此映射表结构大致如下:staticPyMethodDefSwigMethods〔〕{{(char)SWIGPyInstanceMethodNew,(PyCFunction)SWIGPyInstanceMethodNew,METHO,NULL},{(char)TFOKswigconstant,TFOKswigconstant,METHVARARGS,NULL},{(char)TFCANCELLEDswigconstant,TFCANCELLEDswigconstant,METHVARARGS,NULL},{(char)TFUNKNOWNswigconstant,TFUNKNOWNswigconstant,METHVARARGS,NULL},{(char)TFINVALIDARGUMENTswigconstant,TFINVALIDARGUMENTswigconstant,METHVARARGS,NULL},此处省略许多代码};
  如果没有亲身实践,上面这些文字读起来多少有些吃力。为便于大家理解,我们把上述文字用如下简图进行总结:
  有些好奇宝宝可能会说:上面讲得太宏观,好像懂了,又好像没懂。没关系,接下来我们以静态图的运行接口session。run()为例,结合TensorFlow源码详细梳理一下前后端的映射过程,具体过程见下图:
  由上图我们可清晰看到CAPI层把前后端给隔离开了,当然CAPI层包括pywraptensorflowinternal。hcc、tfsessionhelper。hcc、capi。hcc。至此session。run()从前端映射到后端的流程讲完了,那接下来回答前端tensor如何映射至后端Tensor,请看如下代码:tfsessionhelper。ccline351voidTFSessionRunwrapperhelper(TFSessionsession,constcharhandle,constTFBufferrunoptions,conststd::vectorTFOutputinputs,conststd::vectorPyObjectinputndarrays,conststd::vectorTFOutputoutputs,conststd::vectorTFOperationtargets,TFBufferrunmetadata,TFStatusoutstatus,std::vectorPyObjectpyoutputs){DCHECKEQ(inputs。size(),inputndarrays。size());DCHECK(pyoutputs!nullptr);DCHECK(pyoutputsempty());Statuss;ConvertinputndarrayPyObjectstoTFTensors。WemaintainacontinuousarrayofTFTensorsaswellasscopedcontainerstomakesuretheyrecleanedupproperly。省略了很多代码,可以看到此处把前端类ndarray的对象转化成了TFTensors。}capi。ccline2274voidTFSessionRun(TFSessionsession,constTFBufferrunoptions,constTFOutputinputs,TFTensorconstinputvalues,intninputs,constTFOutputoutputs,TFTensoroutputvalues,intnoutputs,constTFOperationconsttargetopers,intntargets,TFBufferrunmetadata,TFStatusstatus){TODO(josh11b,mrry):ChangeSessiontobeabletouseaGraphdirectly,insteadofrequiringustoserializetoaGraphDefandcallSession::Extend()。if(sessionextendbeforerun!ExtendSessionGraphHelper(session,status)){return;}TFRunSetup(noutputs,outputvalues,status);ConvertfromTFOutputandTFTensortoastringandTensor。看这里,此外TensorFlow把TFTensor转化成cTensorstd::vectorstd::pairstring,Tensorinputpairs(ninputs);if(!TFRunInputs(inputvalues,inputpairs,status))return;for(inti0;ininputs;i){inputpairs〔i〕。firstOutputName(inputs〔i〕);}ConvertfromTFOutputtostringnames。std::vectorstringoutputnames(noutputs);for(inti0;inoutputs;i){outputnames〔i〕OutputName(outputs〔i〕);}}2。2CTensor类
  查看参考文献5,我们找到了CTensor类的定义,其重要片段(seg1)如下:classTensor{public:Tensor序列化反序列化相关,在2。3节详细介绍boolFromProto(constTensorProtoother)TFMUSTUSERESULT;voidAsProtoField(TensorProtoproto)const;voidAsProtoTensorContent(TensorProtoproto)const;Tensor实际为底层数据的一种视图,可用vec或matrix进行展示templatetypenameTtypenameTTypesT::Vecvec(){returntensorT,1();}templatetypenameTtypenameTTypesT::Matrixmatrix(){returntensorT,2();}templatetypenameT,sizetNDIMStypenameTTypesT,NDIMS::Tensortensor();private:TensorShapeshape;维护Tensor的形状和数据类型TensorBufferbuf;底层数据的指针}
  我们先来分析下两个私有成员。首先看一下TensorBuffer类,它是一个继承引用计数类的虚拟类,不包含任何实现。通过查看参考文献6,我们得知BufferBase继承TensorBuffer类,且维护了一个内存分配器指针。而Buffer类继承BufferBase类,且维护了指向实际数据的指针data和元素数量elem。上述类的继承关系如下图所示(为便于理解图中给出成员定义,而非标准的UML图):
  接下来我们分析TensorShape类。它也有自己的类继承体系,其核心逻辑定义在父类TensorShapeRep中,相关的类继承体系如下图:
  为深入理解TensorShape的作用,以下结合TensorShapeRep的部分代码(seg2)进行分析:classTensorShapeRep{private:如下buf共计16字节表示TensorShape,其中前12字节用来存储形状(Rep16、Rep32、Rep64)第13字节作用不清楚,第14、15、16字节分别表示数据类型编号、张量的维度数目、张量维度的表示类型union{uint8buf〔16〕;Rep64unusedaligner;Forcedatatobealignedenoughforapointer。}u;public:理论上可定义任意维的张量,但1维、2维、3维张量最常见。所以给出如下三种维度表示方法(12字节)structRep16{uint16dims〔6〕;最多可表示6维的张量,每一维的长度不超过2161};structRep32{uint32dims〔3〕;最多可表示3维的张量,每一维的长度不超过2321};structRep64{gtl::InlinedVectorint64,4dims;支持任意维度的张量};}
  本小节最后,我们再来看一下Tensor类定义中的vector()和matrix()。查看两个方法的实现,发现调用了共同的方法tensor(),而tensor()的返回类型为TTypesT,NDIMS::Tensor,而TTypes正是衔接TFTensor与Eigen库的关键。请看如下代码(seg3):tensorflow1。15。5ensorflowcoreframeworkensor。hclassTensor{public:Returnstheshapeofthetensor。constTensorShapeshape()const{returnshape;}templatetypenameTtypenameTTypesT::Vecvec(){returntensorT,1();}templatetypenameTtypenameTTypesT::Matrixmatrix(){returntensorT,2();}templatetypenameT,sizetNDIMStypenameTTypesT,NDIMS::Tensortensor();}tensorflow1。15。5ensorflowcoreframeworkensortypes。htemplatetypenameT,intNDIMS1,typenameIndexTypeEigen::DenseIndexstructTTypes{RankNDIMStensorofscalartypeT。typedefEigen::TensorMapEigen::TensorT,NDIMS,Eigen::RowMajor,IndexType,Eigen::AlignedTensor;省略了许多代码}tensorflow1。15。5ensorflowcoreframeworkensor。hTFTensor的shape()返回TensorShape。base()返回指向实际数据的指针。templatetypenameT,sizetNDIMStypenameTTypesT,NDIMS::TensorTensor::tensor(){CheckTypeAndIsAligned(DataTypeToEnumT::v());returntypenameTTypesT,NDIMS::Tensor(baseT(),shape()。AsEigenDSizesNDIMS());}
  由上述代码可见,调用tensor()是把TFTensor转化成了TTypesT,NDIMS::Tensor,而后者本质上是Eigen::TensorMap。至此,我们搞清楚了TFTensor与Eigen库的关系,可以认为TFCTensor是对Eigen::TensorMap的一种封装。因为Eigen::TensorMap构造函数的参数来自于TFTensor中保存的信息(base()和shape()对应的信息)。2。3CTensor序列化
  在TensorFlow的分布式训练环境中涉及大量的跨机通信,通信的内容就是序列化后的张量(通过sendrecvop对协同工作)。本小节我们将一起学习Tensor的序列化机制,以及Tensor与序列化对象的互编程。TensorFlow中Tensor对应的序列化对象叫TensorProto,它是由对应的proto文件生成。具体代码如下(seg4):tensorflow1。15。5ensorflowcoreframeworkensor。protosyntaxproto3;messageTensorProto{DataTypedtype1;TensorShapePrototensorshape2;int32versionnumber3;bytestensorcontent4;repeatedint32halfval13〔packedtrue〕;DTFLOAT。repeatedfloatfloatval5〔packedtrue〕;DTDOUBLE。repeateddoubledoubleval6〔packedtrue〕;DTINT32,DTINT16,DTINT8,DTUINT8。repeatedint32intval7〔packedtrue〕;DTSTRINGrepeatedbytesstringval8;DTCOMPLEX64。scomplexval(2i)andscomplexval(2i1)arerealandimaginarypartsofithsingleprecisioncomplex。repeatedfloatscomplexval9〔packedtrue〕;DTINT64repeatedint64int64val10〔packedtrue〕;DTBOOLrepeatedboolboolval11〔packedtrue〕;DTCOMPLEX128。dcomplexval(2i)anddcomplexval(2i1)arerealandimaginarypartsofithdoubleprecisioncomplex。repeateddoubledcomplexval12〔packedtrue〕;DTRESOURCErepeatedResourceHandleProtoresourcehandleval14;DTVARIANTrepeatedVariantTensorDataProtovariantval15;DTUINT32repeateduint32uint32val16〔packedtrue〕;DTUINT64repeateduint64uint64val17〔packedtrue〕;};
  大家可用protoc编译器来编译tensor。proto文件,结果生成tensor。pb。h和tensor。pb。cc两个文件,他们分别声明了TensorProto类定义、TensorProto成员方法的实现。我们可以粗略地将TensorProto看作Tensor的二进制对象,基于此它们相互之间的转换代码如下所示(seg5):Tensor的序列化过程autotensorprotonewTensorProto();Fillsinprotowiththistensorscontent。AsProtoField()fillsintherepeatedfieldforproto。dtype(),whileAsProtoTensorContent()encodesthecontentinproto。tensorcontent()inacompactform。tensorAsProtoField(tensorproto);tensorAsProtoTensorContent(tensorproto);Tensor的反序列化过程Tensortensor;tensor。FromProto(tensorproto);三、跨框架编程通用内存张量DLPack3。1什么是DLPack
  DLPack是一种开放的内存张量结构,用于在AI框架之间共享张量。多框架整合解决AI问题,能充分发挥各框架优势(一些运算在某框架中支持更好),并最终取得整体最佳性能。但这里有一个关键问题要解决:如何将内存中的张量从一个框架传递到另一个框架,而不发生任何数据拷贝?幸运的是,陈天奇团队给出了DLPack这个答案。
  DLPack的设计理念是尽可能的轻量化,它不考虑内存分配、设备API,仅仅关注张量数据结构。它可以运行在多个硬件平台上,目前支持的框架有:NumPy、CuPy、PyTorch、Tensorflow、MXNet、TVM、mpi4py。DLPack的开发者不打算实现Tensor和Ops,而是将其用作跨框架重用张量和操作的公共桥梁。深入理解DLPack,要掌握两大模块:CAPI与PythonAPI。DLPackCAPI体系结构如下:
  上图中深蓝色的结构体均定义在〔13〕中。DLTensor代表普通CTensor对象,但不负责内存管理。DLManagedTensor也是一个CTensor对象,负责DLTensor的内存管理,它被设计用来帮助其他框架借用此DLTensor。接下来,我们将目光转向DLPack的PythonAPI。
  DLPackPython接口是Pythonarray的标准API。用DLPackPython接口进行数据交换的接口有两个:
  fromdlpack(x):输入一个包含dlpack方法的数组对象,用这个方法构建一个包含x数据域的新数组对象。
  dlpack(self,streamNone)anddlpackdevice():在fromdlpack(x)内部调用x的这两个方法,分别用于获取x的数据域以及定位x数组对象在哪个设备上。
  从语义层面理解yfromdlpack(x)的话,生成x的库叫生产者,包含fromdlpack()的库叫做消费者。其中生产者提供了访问x数据域的途径,通常来说生产者和消费者之间关于相应的数据是零拷贝的,也即y可视为x的视图。如果深入fromdlpack(x)内部,则x。dlpack方法生成包含DLManagedTensor的PyCapsule对象(或称capsule),这个对象只能被消费一次。生产者必须将PyCapsule对象名称设为dltensor,以方便按名称检索。同时也要设置DLManagedTensor的deleter方法给PyCapsuleDestructor,这个设置是当名为dltensor的capsule对象不再需要时使用。消费者把DLManagedTensor的所有权从capsule对象转移至自己,这是通过把capsule对象改名为useddltensor以确保PyCapsuleDestructor不会被调用来实现的。但当capsule对象把DLManagedTensor所有权转移至消费者对象时,消费者对象的destructor方法仍然可以调用DLManagedTensor的deleter方法。3。2TensorFlow中的dlpack
  笔者发现TensorFlow对DLPack的支持是从v2。2。0开始的,更早的版本没有dlpack相应的库。TensorFlow的dlpack接口与3。1遵守相同的语义描述,相应的API测试语句如下:importtensorflowastfxtf。constant(5)xtf。Tensor:shape(),dtypeint32,numpy5rtf。experimental。dlpack。todlpack(x)print(r,type(r))capsuleobjectdltensorat0x7f55a0431c30classPyCapsulexothertf。experimental。dlpack。fromdlpack(r)xothertf。Tensor:shape(),dtypeint32,numpy53。3TVM与DLPack的关系
  如果你想开发一款跨AI框架的深度学习编译器,DLPack就是一种可行的方案(TVM就是这条技术路线)。比如,我们在TVM中声明并编译一个矩阵乘法算子,然后基于DLPack表示构建一个包装器,该包装器能让此矩阵乘法算子支持PyTorchTensor。对MxNet可以采用类似的操作。DLPack提供在AI框架和TVM之间共享的中间包装器的原理如下图所示:
  上述原理可以参考如下代码举例:前提说明:在PyTorch中计算矩阵乘法importtorchxtorch。rand(56,56)ytorch。rand(56,56)zx。mm(y)第一步,定义并构建一个TVM矩阵乘法算子ntvm。convert(56)Xtvm。placeholder((n,n),nameX)Ytvm。placeholder((n,n),nameY)ktvm。reduceaxis((0,n),namek)Ztvm。compute((n,n),lambdai,j:tvm。sum(X〔i,k〕Y〔k,j〕,axisk))stvm。createschedule(Z。op)fmmtvm。build(s,〔X,Y,Z〕,targethostllvm,namefmm)第二步,对TVM函数进行包装以支持PyTorchTensor,并验证结果fromtvm。contrib。dlpackimporttopytorchfuncfmmisthepreviouslybuiltTVMfunction(Pythonfunction)fmmisthewrappedTVMfunction(Pythonfunction)fmmpytorchtopytorchfunc(fmm)z2torch。empty(56,56)fmmpytorch(x,y,z2)np。testing。assertallclose(z。numpy(),z2。numpy())第三步,参照第二步对MxNet进行类似包装处理importmxnetfromtvm。contrib。mxnetimporttomxnetfuncctxmxnet。cpu(0)xmxnet。nd。uniform(shape(56,56),ctxctx)ymxnet。nd。uniform(shape(56,56),ctxctx)zmxnet。nd。empty(shape(56,56),ctxctx)ftvm。build(s,〔X,Y,Z〕,targethostllvm,namef)fmxnettomxnetfunc(f)fmxnet(x,y,z)np。testing。assertallclose(z。asnumpy(),x。asnumpy()。dot(y。asnumpy()))第四步,topytorchfunc()的详细定义TVM提供了dlpacktensor和TVMNDArray互转的函数。TVM函数在最底层调用的是TVMNDArray。此包装器的大致流程是:AITensordlpacktensorTVMNDArraycallTVMfunctiondefconvertfunc(tvmfunc,tensortype,todlpackfunc):assertcallable(tvmfunc)defwrapper(args):argstuple(ndarray。fromdlpack(todlpackfunc(arg))ifisinstance(arg,tensortype)elseargforarginargs)returntvmfunc(args)returnwrapperdeftopytorchfunc(tvmfunc):importtorchimporttorch。utils。dlpackreturnconvertfunc(tvmfunc,torch。Tensor,torch。utils。dlpack。todlpack)四、总结
  本文内容较多且烧脑,建议读者反复阅读几遍,定能有所收获。我们在此对通篇内容作个总结,本文主要讲了三个主题:
  第一部分讲解小白眼中的Tensor,重点分析了Tensor的属性和OP的关系。
  第二部分讲解系统开发者眼中的Tensor,重点讲解Tensor前后端映射,以及Tensor的C定义及序列化。
  第三部分讲解通用内存张量DLPack,重点讲解了DLPack的定义及在TensorFlow中的使用,以及DLPack在TVM中扮演的角色。
  作者:李杰参考文献
  1。TensorFlowIntroduction:https:github。comtensorflowdocsblobmastersiteenr1guidelowlevelintro。md
  2。TensorFlowTensors:https:github。comtensorflowdocsblobmastersiteenr1guidetensors。md
  3。tf。constant源码:https:github。comtensorflowtensorflowblobv1。15。5tensorflowpythonframeworkconstantop。pyL165
  4。tensorflow源码解析之frameworktensor:https:www。cnblogs。comjicanghaip9537282。html
  5。TensorFlowcTensorsourcecode:https:github。comtensorflowtensorflowblobv1。15。5tensorflowcoreframeworktensor。h
  6。TensorFlowcTensorsourcecode:https:github。comtensorflowtensorflowblobv1。15。5tensorflowcoreframeworktensor。cc
  7。《TensorFlow:ASystemforLargeScaleMachineLearning》:https:www。usenix。orgsystemfilesconferenceosdi16osdi16abadi。pdf
  8。tensorflowinternals。pdf:https:github。comhoranceliutensorflowinternals
  9。DLPackdoc:https:dmlc。github。iodlpacklatest
  10。DLPackgithub:https:github。comdmlcdlpack
  11。DLPackCAPI:https:dmlc。github。iodlpacklatestcapi。html
  12。PythonSpecificationforDLPack:https:dmlc。github。iodlpacklatestpythonspec。html
  13。dlpack。h:https:github。comdmlcdlpackblobmainincludedlpackdlpack。h
  14。BuildingaCrossFrameworkDeepLearningCompilerviaDLPack:https:tvm。apache。org20180810DLPackBridge

贵州首富兄弟身家合计达到305亿元,却靠着75岁老干妈救场根据2022胡润百富榜显示,贵州仅有2人上榜,李妙行排在第387位,李贵山排在第399位,身家分别为155亿元150亿元。有的人可能对这两个名字不是很熟悉,但提及他们的母亲国民女神贵州又新建一条新高速,6车道全长为160。7公里,对当地有啥影响?有一句俗话说得好要想富,先修路。如果一个地区想要发展起来,解决交通成为了首要问题。特别是随着近几年旅游业的发展,人们对于远方十分的向往。贵州位于我国西南部,当地独特的人文风景也吸引给婆婆买的衣服,又被我脱了下来读人间故事,品百味人生欢迎关注萝月小主阅读更多情感故事邻居王姨进来院子,没看到梦瑶的婆婆,正准备转身走的时候,梦瑶喊住了咋啦王姨,有事吗?王姨有些忸怩,不好意思地说瑶瑶,我是来找你研究发现,西兰花可改善肠道微生物群并减少IBD的炎症炎症性疾病显著增加了患者的发病率和死亡率。最常见的慢性炎症性疾病之一是炎症性肠病(IBD),它严重影响患者的日常生活。IBD可影响肠道上皮屏障功能,并促进肠道微生物组的改变。最近,疯传!世界杯直播时忽然背景传来女主播不明杂音,浮想联翩?这个事情应该很多网友都知道了,主要后续官方出了个说明大家未必知道,我们一并串起来和大家说下。事情其实相当的简单,也是相当的狗血。先介绍一下女主,疑似是这位,目前超人气的网络体育女主世界杯女主播杂音让人浮想联翩?官方道歉,当事人身份曝光11月29日,2022年卡塔尔世界杯开赛的第9天,第二轮小组赛全部结束,法国巴西葡萄牙队2场比赛全胜,稳居DGH组小组排名的第1位,提前一轮晋级世界杯16强赛,而东道主卡塔尔队2场40岁左右的妈妈,试试这几款羊羔毛皮毛一体外套,休闲保暖减龄头条创作挑战赛现在的人喜欢把流行称为时尚,而这种流行的势头总是一个接着一个,似乎从来没有厌倦的时候。嘻哈风牛仔风欧美风职业风皮草风百搭嘻皮淑女韩流哈日,时尚到底是什么?时尚其实是都老实人周勃有救国和从龙之功,为何最后却不得善终呢?刘邦同志在生前曾说安刘氏天下者,必勃也!这一句话实际上在历史上成就了两个人,一是刘邦,因为一说到这事,大家都会说刘邦眼光独到,识人有方另一个便是周勃,大多数人都会因为这样一句话认为再见,不平凡的2022年再见,不平凡的2022年当时光踏着沉重的脚步与我们依依不舍,挥手告别的时刻,心中无比辛酸与惆怅。因为岁月伴随我们与疫情作斗争,共同经历了煎熬和痛苦的时刻。今天它将离我们而去,深深镌永远不要指点别人的人生有人说,人生就是一场戏,每个人都在里面扮演着各自不同的角色。虽然每个人都会有着多重身份,但最重要的角色始终是自己。在滚滚的物欲洪流中,或许很多人早已丢失了内心,听不到初心的声音。然几招教你经期悄悄变美月经是大多数女性每个月都要经历的生理阶段,往往伴随着身体不适皮肤恶化心情暴躁等不愉快的现象,这让很多女生一想到月经就头疼。但其实在这个特殊的生理期,只要把握好,也可以悄悄变美注意皮
人事处官员读亚当森博士邵阳学院以84。4万元作为高层次人才引进编者按Jim博士经过详细调查,证明邵阳学院还有更大规模的海外批发计划,并先后披露了邵阳学院体育系的大规模批判水博士计划,以及在菲律宾圣保罗大学的委培博士。然而,2022年8月1日,阵容顶配,颜值在线,这几部剧强烈推荐沧笙踏歌,听飒爽古风。热情似火,享悠悠泰韵。乘一缕清风,度岁月长河。循人间光芒,赏不同风情。广西都市频道晚间剧场全新编排古风泰韵清凉季承包您的整个夏天。敲重点敲重点敲重点敲重点八月武器进化史01hr火枪是军事历史上里程碑式的重要发明。以火枪的出现为标志,人类战争逐渐由冷兵器向热兵器时代过渡,战争的规模和血腥程度快速升级,战场上的死亡人数也开始呈几何倍数增长。在大部分人河北神童申怡飞15岁考入东南大学,22岁5G方案被华为采用2012年6月底,河北高考放榜,15岁的申怡飞第一时间查到了自己的高考成绩,总分603分。一时间,这个小男孩被人们称为神童。没多久,东南大学吴健雄学院的少年班向申怡飞发来了录取通知河北唐山烧烤店打人,前因后果都在这了,还有什么底线吗?河北唐山烧烤店打人,前因后果都在这了,还有什么底线吗?唐山打人事件主犯陈继志的家人花了50万巨资请了一个知名的律师为陈继志的罪行辩护,但是律师刚接了案子就被网友公布了!盘点唐山烧烤三艘大陆豪华客轮突然南下,目标疑似台湾海峡,美军专家感到紧张3艘豪华客轮脱离渤海航路南下,竟让美国专家感到紧张,称这些民船的威胁比军舰还大。近日,美国军事专家退役海军中校托马斯舒加特在援引开源情报在社交平台上发布消息,称中国3艘豪华客轮脱离台媒称佩洛西或明日疑似窜访台湾与台高层会面,较量才刚刚开始据报道,佩洛西搭乘的SPAR19美国空军C40C(军用B737)运输机于7月31日晚上8点40分降落在关岛安德森空军基地,但专机未在关岛过夜,而是在晚间10点29分起飞,于1日清晨分享六道可以出摊的美食,想出去摆摊的赶紧看过来一凉粉食材准备一杯豌豆粉6杯水,3个小米辣,2根葱,香菜适量制作方法11杯绿豆粉6杯水倒入锅中搅拌均匀,中火加热不停地搅拌,煮至粘稠状冒泡后转小火,继续煮12分钟左右,不停地搅拌至江西周公子红了,国企人事制度改革也快了最近江西周公子爆红,吸引了全国人民的眼球。而大家的愤怒背后,则是对体制内优质资源门阀化的愤慨。其实体制门阀化,可以说是广泛存在,甚至习以为常。尤其是国企,父退子继几乎成为明规则。这台湾有事,日本先溜?台海局势升温,日本政客倡拟定撤侨方案文柳扶风工作室李不言台湾有事,就是日本有事?日本前首相安倍晋三去世的消息传出之后,岛内绿营可谓一片哀嚎,纷纷哭嚷着失去了一个支持台湾的好朋友。台当局领导人蔡英文不仅下令降半旗,还派大快人心!那个曾侮国誓死要加入美国籍的博士赵潘书,已成黑户曾几何时,中国国力和经济都很弱,一些中国人选择去美国淘金为生为了掌握更多的知识,也有很多学生们纷纷出国追逐自己的梦想。为了淘金和求知,我们都可以理解,但有些人为了自己的美国梦恶意抹
友情链接:快好找快生活快百科快传网中准网文好找聚热点快软网