CUTLASS 1.3.3中的 Volta884_h884gemm

CUTLASS 是 CUDA C++ 模板抽象的集合,用于在 CUDA 内的所有级别和规模上实现高性能矩阵-矩阵乘法 (GEMM) 和相关计算。它采用了类似于 cuBLAS 和 cuDNN 中实现的分层分解和数据移动策略。

CUTLASS 最新版本为3.3,相比1.3.3变动较大。然而重温一下1.3.3仍然是有意义的。因为它更易于理解:

  • 与 PROGRAMMING TENSOR CORES: NATIVE VOLTA TENSOR CORES WITH CUTLASS 中介绍的内容相匹配;
  • 仅支持 Volta 一种 Tensor Core 架构;
  • Tensor Core 仅支持 half 一种数据类型;
  • 仅采用HMMA.884.F16.F16一种指令。

Demystifying Tensor Cores to Optimize Half-Precision Matrix Multiply 中提到 T4 GPU 在引入 Tensor Core 之后,原来重计算瓶颈的 GEMM 也变成了 IO 瓶颈。虽然 V100的带宽是 T4的三倍,然而带宽不足问题同样存在。因此,CUTLASS 对于数据路径进行了如下优化:

  • 全路径128 bit 的访问粒度:LDG.128STS.128LDS.128STD.128
  • 无冲突共享内存排列:转置时无需填充 Shared Memory;
  • Software Pipelining:LDG.128LDS.128HMMA.884.F16.F16三种指令并行,隐藏数据移动。

下面以一个矩阵乘测例为例,介绍 Volta884_h884gemm 的实现。

TEST(Volta884_h884gemm_128x64x32_nt, 520x264x136)

OutputTile即 threadblock tile,该测例下设置为32x64x128。WarpGemmShape为32x64x64,这个是固定值。
run_gemm 初始化 Volta884GemmTraits::Params 和 GemmTestbed,调用 Gemm::launch 运行后比对结果。

TEST(Volta884_h884gemm_64x64x32_nt, 520x264x136) {

  typedef cutlass::gemm::Volta884GemmTraits<
    cutlass::MatrixLayout::kColumnMajor,
    cutlass::MatrixLayout::kRowMajor,
    cutlass::Shape<32, 64, 128>,
    cutlass::Shape<32, 64, 64>,
    half,
    half,
    half,
    2
  > GemmTraits;

  run_gemm<GemmTraits>(520, 264, 136);
}

CUTLASS 中 Volta884实现的层次结构如下图所示

Gemm
Volta884GemmTraits
Volta884MultiplyAdd
GemmMainloop
Volta884Multiplicand
IdentityBlockSwizzle
GlobalLoadStreamPair
SharedStreamPair
MMAEpilogue
Volta884EpilogueTraits
PredicatedTileLoadStream
PredicatedTileStoreStream
TileStoreStream
TileLoadStream
mma
TileLoadIterator
Volta884ThreadblockMultiplicandStoreIterator
Volta884WarpMultiplicandLoadIterator
MMAGlobalLoadStream
Copy
MMASharedLoadStream

gemm_kernel_nolb

gemm_kernel_nolb
GemmMainloop::multiply_add

Kernel 函数申请动态 Shared Memory,并传递给 GemmMainloop,然后调用 GemmMainloop::multiply_add 进行计算。

/// GEMM kernel without launch bounds specified
template <typename Gemm_>
__global__ /* __launch_bounds__(Gemm_::kThreads) */
void gemm_kernel_nolb(typename Gemm_::Params params) {

  // Dynamic shared memory base pointer
  extern __shared__ int GemmSharedStorageBase[];

  // Declare pointer to dynamic shared memory.
  typename Gemm_::SharedStorage *shared_storage = 
    reinterpret_cast<typename Gemm_::SharedStorage *>(GemmSharedStorageBase);

  // Construct the GEMM object.
  Gemm_ gemm(params, *shared_storage);

  // Run GEMM.
  gemm.multiply_add();
}

GemmMainloop

GemmMainloop 实现了软流水,如下图所示:
在这里插入图片描述

Shared Memory 和寄存器需要两个缓冲区,通过 SM 上的调度实现三条流水线并行。Global Memory 到 Shared Memory 的加载有同步,而从 Shared Memory 移动到寄存器时不需要同步。由于 Ampere 之前的架构不支持 Global Memory 到 Shared Memory 的直接拷贝,因此整个搬运过程比较复杂。如下图所示,程序中多处调用 Copy::transform 函数生成transformed_fragment。原因应该是为了实现类型转换,但 Volta 只支持 half,也就没有实际作用。

PredicatedTileStoreStreamTileStoreStream::copy
GlobalLoadStream::commit
GlobalLoadStream::copy
Copy::transform
Volta884ThreadblockMultiplicandStoreIterator::store_post_increment
MMASharedLoadStream::copy
MMASharedLoadStream::commit
A/B
TileStoreStream::copy
TileStoreStream::copy
TileStoreStream::commit
AB
D
PredicatedTileLoadStream::copy
TileLoadStream::commit
C
Copy::transform
TileStoreIterator::store_post_increment
source_fragment
transformed_fragment
fetched_fragment
transformed_fragment
Global_Memory
Shared_Memory
fetched
transformed
Volta884MultiplyAdd
accumulators
fetched_fragment
transformed_fragment
LinearScaling
fetched_fragment
transformed_fragment
template <typename Traits_>
struct GemmMainloop {

  //
  // Type definitions
  //

  /// The traits.
  typedef Traits_ Traits;

  /// The GEMM mainloop
  typedef typename Traits::KernelClass KernelClass;

  /// The shared storage.
  typedef typename Traits::SharedStorage SharedStorage;

  /// The scalar for A.
  typedef typename Traits::ScalarA ScalarA;
  /// The scalar for B.
  typedef typename Traits::ScalarB ScalarB;
  /// The scalar in the epilogue.
  typedef typename Traits::Epilogue::Scalar ScalarEpilogue;
  /// The scalar for C.
  typedef typename Traits::Epilogue::ScalarC ScalarC;
  /// The scalar for D.
  typedef typename Traits::Epilogue::ScalarD ScalarD;
  /// The index.
  typedef typename Traits::Index Index;

  /// Define the mainloop iteration size
  typedef typename Traits::MultiplyAdd MultiplyAdd;

  /// The number of threads.
  static int const kThreads = Traits::GemmConfig::kThreads;

AccumulatorsPerWarp为 GemmConfig::AccumulatorsPerWarp 即 Volta884MultiplyAdd::WarpGemmShape,为32x64x64。
Volta884MultiplyAdd::InstructionShape 为4x32x32。因此,kWarpGemmSteps为8。

  // Number of warp-level multiply-accumulate steps executed by each warp.
  static Index const kWarpGemmSteps =
      Traits::GemmConfig::AccumulatorsPerWarp::kD / MultiplyAdd::InstructionShape::kD;

  /*
  // Make sure we have at least 2 unrolling steps or our pipeling is not going to work.
  static_assert(kWarpGemmSteps >= 2, "The pipelining assumes at least two steps");
  */

  /// Use the params object defined in traits
  typedef typename Traits::Params Params;

  //
  // Data members
  //

  /// The params.
  Params const& params;

  /// SharedStorage object
  SharedStorage& shared_storage;
  //
  // Methods
  //

  /// Ctor.
  CUTLASS_DEVICE GemmMainloop(Params const& params_, SharedStorage& shared_storage_)
      : params(params_), shared_storage(shared_storage_) {}

GemmMainloop::fetch_global

GemmMainloop::fetch_global
GlobalLoadStreamPair::residue
GlobalLoadStreamPair::copy

Volta884GemmTraits::GlobalLoadStream 即 GlobalLoadStreamPair 类型。
GlobalLoadStreamPair::residue 函数调用两次 MMAGlobalLoadStream::residue,计算在线程块 tile 最后一次加载所需的预测掩码。
GlobalLoadStreamPair::copy 函数调用两次 MMAGlobalLoadStream::copy 从 Global Memory 拷贝矩阵元素到寄存器。后者调用 TileLoadIterator::load_post_increment 函数。

  /// Fetches global stream pair
  template <bool Residue>
  CUTLASS_DEVICE void fetch_global(typename Traits::GlobalLoadStream& global_to_shared_stream,
                                   Index outer_k) {
    // If residue portion and not calculating residue in prolog, update residue predicates now.
    if (Residue) {
      global_to_shared_stream.residue(outer_k);
    }
    global_to_shared_stream.copy();
  }

GemmMainloop::consume_tile

如果kWarpGemmSteps小于等于4,则为kGlobalStreamFirst,先从 Global Memory 加载下一次迭代的数据。

  /// Computes a warp-level GEMM on data held in shared memory
  template <bool Residue, bool LastIteration>
  CUTLASS_DEVICE void consume_tile(typename Traits::GlobalLoadStream& global_to_shared_stream,
                                   typename Traits::SharedStream& shared_load_stream,
                                   typename MultiplyAdd::Accumulators& accumulators,
                                   Index outer_k) {

    // Whether to load global stream before loading shared stream
    const bool kGlobalStreamFirst = (kWarpGemmSteps <= 4);

    // Load data for the next iteration of the main loop (unless it's the last iteration).
    if (kGlobalStreamFirst && !LastIteration) {
      fetch_global<Residue>(global_to_shared_stream, outer_k);
    }

首先从 Shared Memory 加载下一次迭代的输入。拥有双缓冲区。
MMASharedLoadStream::copy 调用 Volta884WarpMultiplicandLoadIterator::load 函数加载数据到寄存器中。
问题是前一步如果没有调用 GemmMainloop::fetch_global,从 Shared Memory 拷贝不会有问题吗?

    CUTLASS_PRAGMA_UNROLL
    for (int step = 0; step < kWarpGemmSteps; ++step) {

      // Trigger the copy from shared memory for the next A/B values.
      shared_load_stream.copy((step + 1) % kWarpGemmSteps);

如果不是kGlobalStreamFirst , 在循环的第一步时调用GemmMainloop::fetch_global 函数加载输入。

      // Load data for the next iteration of the main loop (unless it's the last iteration).
      if (!kGlobalStreamFirst && (step == 0) && !LastIteration) {
        fetch_global<Residue>(global_to_shared_stream, outer_k);
      }

如果是倒数第2步,需要确保数据已经加载到了 Shared Memory。
Volta884GemmTraits::shared_load_fence 根据外部传入的StageCount来确定是否同步线程。
GlobalLoadStreamPair::commit 函数会分别调用两个矩阵的 GlobalLoadStream::commit 拷贝到 Shared Memory。
Volta884GemmTraits::shared_store_fence 同步线程。
MMASharedLoadStream::inc_stage 递增stage_index

      if (step == kWarpGemmSteps - 2) {
          // Make sure the data from shared memory has been entirely consumed.
          Traits::shared_load_fence(true);

          global_to_shared_stream.commit();

          // Make sure the data is in shared memory.
          Traits::shared_store_fence(true);

          // Move to the next stage for the load (if it makes sense).
          shared_load_stream.inc_stage();
      }

MMASharedLoadStream::commit 调用 Copy 进行拷贝。Volta884WarpMultiplicandLoadIterator::Fragment 即 Fragment 。
Volta884MultiplyAdd::multiply_add 完成 Warp Tile 的计算。

      // Make sure the values are available for the current iteration to do the multiply-add.
      shared_load_stream.commit(step);

      // Do the math on the fragments of the current iteration.
      MultiplyAdd multiply_add;
      multiply_add.multiply_add(shared_load_stream.fragment_a(step),
                                shared_load_stream.fragment_b(step),
                                accumulators,
                                accumulators);
    }
  }

GemmMainloop::multiply_add

Created with Raphaël 2.3.0 GemmMainloop::multiply_add IdentityBlockSwizzle::get_threadblock_offset IdentityBlockSwizzle::get_threadblock_bounds IdentityBlockSwizzle::get_batch_id GlobalLoadStreamPair::add_batch_offset GlobalLoadStreamPair::move_to_residue GlobalLoadStreamPair::copy GlobalLoadStreamPair::commit Volta884GemmTraits::shared_store_fence GlobalLoadStreamPair::rollback SharedLoadStream::copy ClearAccumulators::clear GemmMainloop::consume_tile GemmEpilogue::epilogue End

make_Coord_from_shape 根据形状创建一个 Coord 对象。

IdentityBlockSwizzle::get_threadblock_offset 获得当前线程块在输出二维图上的偏移。
Volta884GemmTraits::ClearAccumulators 即 ClearAccumulators。
IdentityBlockSwizzle::get_threadblock_bounds 返回 threadblock 的三维边界。

  /// Do the GEMM.
  CUTLASS_DEVICE void multiply_add() {
    // Swizzle the IDs of the block (to enable better cache behavior).
    typename Traits::BlockSwizzle block_swizzle;
    Coord<3> threadblock_offset =
        block_swizzle.get_threadblock_offset(make_Coord_from_shape<typename Traits::OutputTile>());

    // We may want to use shared memory to clear the registers.
    typedef typename Traits::ClearAccumulators ClearAccumulators;

    // Get the bounds for each thread, it maybe different than problem_size
    Coord<3> bounds = block_swizzle.get_threadblock_bounds(params.problem_size,
                                                        params.partitionK_range);

params.global_to_shared_stream即 GlobalLoadStreamPair::Params。
shared_storage.main_loop.global_to_shared_stream为 GlobalLoadStreamPair::SharedStorage。
shared_storage.main_loop.threadblock_tile为 GlobalLoadStreamPair::ThreadblockTileStorage,即 ZipTileAllocation。ZipTileAllocation::reference 返回指向数据的 ZipTensorRef 对象。
global_to_shared_stream为 Volta884GemmTraits::GlobalLoadStream 即 GlobalLoadStreamPair。
GlobalLoadStreamPair::add_batch_offset 调用 GlobalLoadStreamPair::add_batch_offset GlobalLoadStream::add_batch_offset 函数设置迭代器的 batch 偏移。

    // The streams to read A/B from global memory to shared memory.
    typename Traits::GlobalLoadStream global_to_shared_stream(
        params.global_to_shared_stream,
        shared_storage.main_loop.global_to_shared_stream,
        shared_storage.main_loop.threadblock_tile.reference(),
        bounds,
        threadblock_offset);

    // update A and B pointer offset based on batch_id and batch_stride_offset
    global_to_shared_stream.add_batch_offset(block_swizzle.get_batch_id());

    // Create the accumulator clear.
    ClearAccumulators clear;

GlobalLoadStreamPair::move_to_residue 如果是在序幕中执行余数则调用 MMAGlobalLoadStream::move_to_residue 移动指针,否则直接调用 GlobalLoadStreamPair::residue 函数。
GlobalLoadStreamPair::copy 调用 MMAGlobalLoadStream::copy 函数,后者调用 TileLoadIterator::load_post_increment 加载 A 和 B 矩阵的片段到 Fragment 寄存器。
GlobalLoadStreamPair::commit 调用 MMAGlobalLoadStream::commit 函数,后者调用 Copy.transform 进行拷贝,然后调用
Volta884ThreadblockMultiplicandStoreIterator::store_post_increment 保存到 Shared Memory。
Volta884GemmTraits::shared_store_fence 同步 threadblock 内的线程。
GlobalLoadStreamPair::rollback 调用 MMAGlobalLoadStream::rollback 函数,后者调用 TileLoadIterator::initialize_predicates 初始化预测向量,然后移动偏移。

    // Deal with residue in prolog.
    // global_to_shared_stream.move_to_residue(params.problem_size[0], Traits::OutputTile::kD);
    global_to_shared_stream.move_to_residue(bounds[0], Traits::OutputTile::kD);

    // Fetch the fragments for A and B from global memory.
    global_to_shared_stream.copy();

    // Copy the elements to shared memory (after transformation if needed).
    global_to_shared_stream.commit();

    // Make sure the data is in shared memory.
    Traits::shared_store_fence(false);

    // Rollback to the beginning of the first tile (if residue exists).
    // global_to_shared_stream.rollback(params.problem_size[0] % Traits::OutputTile::kD);
    global_to_shared_stream.rollback(bounds[0] % Traits::OutputTile::kD);

shared_load_stream为 Volta884GemmTraits::SharedStream 类型,即 SharedStreamPair。
SharedStreamPair::copy 调用 MMASharedLoadStream::copy,后者调用 Volta884WarpMultiplicandLoadIterator::load 从 Shared Memory 加载。
accumulators为 Volta884MultiplyAdd::Accumulators 类型,即 Fragment。
ClearAccumulators::clear 调用 Fragment::clear 将存储清零。
outer_k是什么?

    // The stream of data from shared memory to fragments.
    typename Traits::SharedStream shared_load_stream(
        params.shared_stream,
        shared_storage.main_loop.threadblock_tile.reference());

    // Trigger the copy from shared memory for the 1st stream.
    shared_load_stream.copy(0);

    // Allocate the accumulators.
    typename MultiplyAdd::Accumulators accumulators;

    // Clear the accumulators.
    clear.clear(accumulators);

    // Initial index
    // Index outer_k = params.problem_size[0] - Traits::OutputTile::kD;
    // problem_size[0] might be bigger than bounds[0]
    Index outer_k = bounds[0] - Traits::OutputTile::kD;

如果在序幕中计算了剩余,则仅最后一次处理余数。
GemmMainloop::consume_tile 计算k = Traits::OutputTile::kD的分块。

    // Check if we are computing residue in prolog or not.
    if (Traits::GemmConfig::kResidueInProlog) {
      // Execute all mainloop iterations but the last one.

      CUTLASS_GEMM_LOOP
      for (; outer_k > 0; outer_k -= Traits::OutputTile::kD) {
        CUTLASS_GEMM_LOOP_HEADER
        consume_tile<false, false>(
            global_to_shared_stream, shared_load_stream, accumulators, outer_k);
      }

      consume_tile<false, true>(
          global_to_shared_stream, shared_load_stream, accumulators, outer_k);

否则,每次迭代都考虑余数。

    } else {
      // When kResidueSeparate = true, execute all mainloop iterations but the last two without any
      // consideration for K-residue or predicate updates. This improves the steady state of some
      // kernels.
      if (Traits::GemmConfig::kResidueSeparate) {

        CUTLASS_GEMM_LOOP
        for (; outer_k > Traits::OutputTile::kD; outer_k -= Traits::OutputTile::kD) {
          CUTLASS_GEMM_LOOP_HEADER
          consume_tile<false, false>(
              global_to_shared_stream, shared_load_stream, accumulators, outer_k);
        }
      }

      // Execute remaining tiles with K-residue predicate updates enabled.
      CUTLASS_GEMM_LOOP
      for (; outer_k > -Traits::OutputTile::kD; outer_k -= Traits::OutputTile::kD) {
        CUTLASS_GEMM_LOOP_HEADER
        consume_tile<true, false>(
            global_to_shared_stream, shared_load_stream, accumulators, outer_k);
      }
    }

创建 MMAEpilogue 对象,然后调用 MMAEpilogue::epilogue 函数。

    typedef typename Traits::Epilogue Epilogue;
    Epilogue epilogue(params.epilogue, shared_storage.epilogue, params.problem_size.knm());
    epilogue.epilogue(accumulators, threadblock_offset, block_swizzle.get_batch_id());
  }
};

参考资料:

  • # [DOC] Where does cutlass’ detailed GEMM kernel? #526
  • Dissecting the NVIDIA Volta GPU Architecture via Microbenchmarking
  • Modeling Deep Learning Accelerator Enabled GPUs
  • gpgpu-sim_distribution
  • 理解Tensor Core
  • Flexible Performant GEMM Kernels on GPUs
  • CUDA Tensor Core编程
  • PROGRAMMING TENSOR CORES: NATIVE VOLTA TENSOR CORES WITH CUTLASS
  • The NVIDIA Titan V Deep Learning Deep Dive: It’s All About The Tensor Cores
  • 9.7.13.4.1. Matrix Fragments for mma.m8n8k4 with .f16 floating point type
  • Numerical Behavior of NVIDIA Tensor Cores
  • CUDA Ampere Tensor Core HGEMM 矩阵乘法优化笔记 —— Up To 131 TFLOPS!
  • If we have two or four memory requests by a warp, do they need coalesced access/contiguity? #328
  • Do bank conflicts increase when using more shared memory?
  • How does parameter computeType affect the computation?
  • 2.1.10. GEMM Algorithms Numerical Behavior
  • cuBLAS的使用
  • RAFT在Knowhere上的一些评估测试[1]
  • How does parameter computeType affect the computation?
  • cudnn-frontend/tree/main/samples/samples/conv_sample.cpp
  • Is a union in C++ actually a class?
  • A Generalized Micro-kernel Abstraction for GPU Linear Algebra
  • Implementing Strassen’s Algorithm with CUTLASS on NVIDIA Volta GPUs
  • Double-buffering in shared memory, details? #227
  • Efficient GEMM in CUDA
  • Thread synchronization with syncwarp
  • Using CUDA Warp-Level Primitives
  • CUDA微架构与指令集(3)-SASS指令集分类
  • VOLTA Architecture and performance optimization
  • How to Optimize a CUDA Matmul Kernel for cuBLAS-like Performance: a Worklog
  • Determining registers holding the data after executing LDG.E.128
  • 刘冰、郑鹏|GPU编程和优化-最佳实践分享

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/178896.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Django 创建项目时找不到数据库sqlite3

原因:PyCharm创建Django项目,找不到数据库sqlite3 解决&#xff1a;如果没有默认的db文件&#xff0c;则应在PyCharm终端中执行以下命令&#xff1a; python manage.py makemigrations python manage.py migrate

实现点击一个选框 使得一个组件的可选性修改

实现效果 代码 html <div class"divrow"><el-checkbox-group v-model"isSendTag" :max"1"><el-checkbox v-for"(item, index) in isSendTagOptions" :key"index" :label"item.value">{{item.…

PDF转Word,1行Python代码就够了,免费用

大家好&#xff0c;这里是程序员晚枫。 今年十一假期没出去旅游&#xff0c;在家里更新一套原创课程&#xff0c;&#x1f449;给小白的《50讲Python自动化办公》。 所有功能&#xff0c;都只需要1行代码&#xff0c;非常适合非程序员入门Python使用。 目前全网播放量直逼100…

Android RecyclerView点击宫格处于选择态外框变方框线,Kotlin

Android RecyclerView点击宫格处于选择态外框变方框线&#xff0c;Kotlin <uses-permission android:name"android.permission.READ_EXTERNAL_STORAGE" /><uses-permission android:name"android.permission.READ_MEDIA_IMAGES" /> implementa…

一起学docker系列之六如何搭建私服版本的Docker镜像仓库

目录 前言1 下载并运行私服版本的Docker镜像仓库2 准备上传私服的Docker镜像3 为镜像打上符合私服规范的标签4 修改Docker守护进程的配置文件5 推送镜像到私服版本的Docker镜像仓库6 验证私服的镜像结语 前言 Docker是一种开源的容器技术&#xff0c;可以让开发者和运维人员快…

分类预测 | Matlab实现KPCA-IDBO-LSSVM基于核主成分分析-改进蜣螂算法优化最小二乘支持向量机的分类预测

分类预测 | Matlab实现KPCA-IDBO-LSSVM基于核主成分分析-改进蜣螂算法优化最小二乘支持向量机的分类预测 目录 分类预测 | Matlab实现KPCA-IDBO-LSSVM基于核主成分分析-改进蜣螂算法优化最小二乘支持向量机的分类预测分类效果基本描述程序设计参考资料 分类效果 基本描述 1.多特…

HarmonyOS(三)—— 应用程序入口—UIAbility

前言 学习过android的同学都是知道Activity&#xff0c;Activity是Android组件中最基本也是最为常见用的四大组件之一&#xff0c;用户可以用来交互为了完成某项任务。 Activity中所有操作都与用户密切相关&#xff0c;是一个负责与用户交互的组件&#xff0c;可以通过setCon…

Nevron Vision for .NET 2023.1 Crack

Nevron Vision for .NET 适用于桌面和 Web 应用程序的高级数据可视化 Nevron Vision for .NET提供最全面的组件&#xff0c;用于构建面向 Web 和桌面的企业级数据可视化应用程序。 该套件中的组件具有连贯的 2D 和 3D 数据可视化效果&#xff0c;对观众产生巨大的视觉冲击力。我…

阅读记录【arXiv2020】 Adaptive Personalized Federated Learning

Adaptive Personalized Federated Learning 论文地址&#xff1a; https://arxiv.org/abs/2003.13461 摘要 对联邦学习算法个性化程度的研究表明&#xff0c;只有最大化全局模型的性能才会限制局部模型的个性化能力。在本文中&#xff0c;我们提倡自适应个性化联合学习&…

springboot前后端分离项目配置https接口(ssl证书)

文章目录 说明vue.js前端部署vue.js项目axios请求配置本地创建日志文件创建Dockerfile文件配置ssl证书nginx.confvue项目打包上传创建容器部署 后端springboot项目部署配置ssl证书打包部署 补充&#xff1a;jsk证书和pfx证书补充&#xff1a;两种证书的转化JKS转PFXPFX 转 JKS …

基于蛇优化算法优化概率神经网络PNN的分类预测 - 附代码

基于蛇优化算法优化概率神经网络PNN的分类预测 - 附代码 文章目录 基于蛇优化算法优化概率神经网络PNN的分类预测 - 附代码1.PNN网络概述2.变压器故障诊街系统相关背景2.1 模型建立 3.基于蛇优化优化的PNN网络5.测试结果6.参考文献7.Matlab代码 摘要&#xff1a;针对PNN神经网络…

docker报错standard init linux.go:228 exec user process caused: exec format error

1、报错 使用Dockerfile自己做的服务镜像&#xff0c;docker run时启动失败&#xff0c;报错如下&#xff1a; standard init linux.go:228 exec user process caused: exec format error2、原因一 当前服务器的CPU架构和构建镜像时的CPU架构不兼容。比如做镜像是在arm机器下…

图形数据库的实战应用:如何在 Neo4j 中有效管理复杂关系

关系数据库管理系统( RDBMS ) 代表了最先进的技术&#xff0c;这在一定程度上要归功于其由周边技术、工具和广泛的专业技能组成的完善的生态系统。 在这个涵盖信息技术(IT) 和运营技术(OT) 的技术革命时代&#xff0c;人们普遍认识到性能方面出现了重大挑战&#xff0c;特别是…

Elasticsearch:将最大内积引入 Lucene

作者&#xff1a;Benjamin Trent 目前&#xff0c;Lucene 限制 dot_product (点积) 只能在标准化向量上使用。 归一化迫使所有向量幅度等于一。 虽然在许多情况下这是可以接受的&#xff0c;但它可能会导致某些数据集的相关性问题。 一个典型的例子是 Cohere 构建的嵌入&#x…

CSS特效016:天窗扬起合上的效果

CSS常用示例100专栏目录 本专栏记录的是经常使用的CSS示例与技巧&#xff0c;主要包含CSS布局&#xff0c;CSS特效&#xff0c;CSS花边信息三部分内容。其中CSS布局主要是列出一些常用的CSS布局信息点&#xff0c;CSS特效主要是一些动画示例&#xff0c;CSS花边是描述了一些CSS…

计算3个点的6种分布在平面上的占比

假设平面的尺寸是6*6&#xff0c;用11的方式构造2&#xff0c;在用21的方式构造3 2 2 2 1 2 2 2 2 2 1 2 2 2 2 2 1 2 2 3 3 3 x 3 3 2 2 2 1 2 2 2 2 2 1 2 2 在平面上有一个点x&#xff0c;11的操作吧平面分成了3部分2a1&#xff0c;2a…

OCR是什么意思,有哪些好用的OCR识别软件?

1. 什么是OCR&#xff1f; OCR&#xff08;Optical Character Recognition&#xff09;是一种光学字符识别技术&#xff0c;它可以将印刷体文字转换为可编辑的电子文本。OCR技术通过扫描和分析图像中的文字&#xff0c;并将其转化为计算机可识别的文本格式&#xff0c;从而…

DataFunSummit:2023年OLAP引擎架构峰会-核心PPT资料下载

一、峰会简介 OLAP技术是当前大数据领域的热门方向&#xff0c;该领域在各个行业都有广泛的使用场景&#xff0c;对OLAP引擎的功能有丰富多样的需求。同时&#xff0c;在性能、稳定性和成本方面&#xff0c;也有诸多挑战。目前&#xff0c;OLAP技术没有形成统一的事实标准&…

使用SpringBoot集成MyBatis对管理员的查询操作

增删改查中的查询操作&#xff0c;对所有的普通管理员进行查询操作。 效果展示&#xff1a; 不仅可以在打开页面时进行对管理员的自动查询操作&#xff0c;还可以在输入框进行查询。 首先是前端向后端发送POST请求&#xff0c;后端接收到请求&#xff0c;如果是有参数传到后端…

Py之wikipedia-api:wikipedia-api的简介、安装、使用方法之详细攻略

Py之wikipedia-api&#xff1a;wikipedia-api的简介、安装、使用方法之详细攻略 目录 wikipedia-api的简介 wikipedia-api的安装 wikipedia-api的使用方法 1、 创建 Wikipedia并进行查询 wikipedia-api的简介 Wikipedia-API是一个易于使用的Python封装&#xff0c;用于访…