train_gpt2_fp32.cu - layernorm_forward_kernel3

源码

__global__ void layernorm_forward_kernel3(float* __restrict__ out, float* __restrict__ mean, float* __restrict__ rstd,const float*  __restrict__ inp, const float*  __restrict__ weight,const float* __restrict__ bias, int N, int C) {cg::thread_block block = cg::this_thread_block();cg::thread_block_tile<32> warp = cg::tiled_partition<32>(block);int idx = blockIdx.x * warp.meta_group_size() + warp.meta_group_rank();if(idx >= N) {return;}// the row of input that this group of threads is responsible forconst float* x = inp + idx * C;// meanfloat sum = 0.0f;for (int i = warp.thread_rank(); i < C; i += warp.size()) {sum += x[i];}sum = cg::reduce(warp, sum, cg::plus<float>{});float m = sum / C;if(warp.thread_rank() == 0 && mean != nullptr) {__stcs(mean + idx, m);}// rstdsum = 0.0f;for (int i = warp.thread_rank(); i < C; i += warp.size()) {float diff = x[i] - m;sum += diff * diff;}sum = cg::reduce(warp, sum, cg::plus<float>{});float s = rsqrtf(sum / C + 1e-5f);if(warp.thread_rank() == 0 && rstd != nullptr) {__stcs(rstd + idx, s);}// final normalization and scaling by weight/biasfloat* o = out + idx * C;for (int c = warp.thread_rank(); c < C; c += warp.size()) {// load and store using the .cs "streaming" hint to the compiler,// indicating that this data will not be reused soon, and can be streamed through the caches// this allows the threads to get more cache-hits for the (shared) weight and bias parametersfloat n = s * (__ldcs(x+c) - m);__stcs(o+c, n * weight[c] + bias[c]);}
}

注释

/*** @brief 层归一化前向传播内核函数** 执行层归一化的前向传播操作,并输出归一化后的结果。** @param out 归一化后的输出数组* @param mean 均值数组* @param rstd 归一化后的标准差数组* @param inp 输入数组* @param weight 权重数组* @param bias 偏置数组* @param N 样本数量* @param C 通道数量*/

/*** 在给定输入数据上执行层归一化操作的GPU内核函数。* * @param out 输出数据的指针。* @param mean 计算出的平均值的指针,如果为nullptr,则不计算和保存平均值。* @param rstd 计算出的标准差的倒数的指针,如果为nullptr,则不计算和保存标准差的倒数。* @param inp 输入数据的指针。* @param weight 权重参数的指针,用于对输出数据的每个元素进行缩放。* @param bias 偏置参数的指针,用于对输出数据的每个元素增加偏置。* @param N 输入数据的批处理大小。* @param C 输入数据的每个样本的特征数量。* * 该函数首先计算输入数据的每个特征维度的平均值,然后计算该维度的标准差的倒数,* 最后对输入数据进行归一化、缩放和偏置添加,生成输出数据。*/
__global__ void layernorm_forward_kernel3(float* __restrict__ out, float* __restrict__ mean, float* __restrict__ rstd,const float*  __restrict__ inp, const float*  __restrict__ weight,const float* __restrict__ bias, int N, int C) {cg::thread_block block = cg::this_thread_block();cg::thread_block_tile<32> warp = cg::tiled_partition<32>(block);int idx = blockIdx.x * warp.meta_group_size() + warp.meta_group_rank();if(idx >= N) {return;}// 计算负责处理的输入行const float* x = inp + idx * C;// 计算平均值float sum = 0.0f;for (int i = warp.thread_rank(); i < C; i += warp.size()) {sum += x[i];}sum = cg::reduce(warp, sum, cg::plus<float>{});float m = sum / C;if(warp.thread_rank() == 0 && mean != nullptr) {__stcs(mean + idx, m);}// 计算标准差的倒数sum = 0.0f;for (int i = warp.thread_rank(); i < C; i += warp.size()) {float diff = x[i] - m;sum += diff * diff;}sum = cg::reduce(warp, sum, cg::plus<float>{});float s = rsqrtf(sum / C + 1e-5f);if(warp.thread_rank() == 0 && rstd != nullptr) {__stcs(rstd + idx, s);}// 执行最终的归一化、缩放和偏置添加float* o = out + idx * C;for (int c = warp.thread_rank(); c < C; c += warp.size()) {// 使用.cs提示加载和存储数据,指示该数据不久将不会被重用,可以被缓存流式传输,以提高权重和偏置参数的缓存命中率float n = s * (__ldcs(x+c) - m);__stcs(o+c, n * weight[c] + bias[c]);}
}

解释

该函数是一个用于层归一化操作的CUDA内核函数,用于计算输入数据的归一化、标准化和加权求和。具体来说,它接受6个输入参数和1个输出参数,其中输入参数包括待处理的输入数据inp、缩放因子weight和偏置bias,以及待计算的均值mean和标准差rstd,输出参数为处理后的输出数据out。该函数以块的形式对输入数据进行处理,每个块处理N个数据行,每行包含C个数据列。具体步骤如下:

  1. 根据当前块的索引blockIdx.x和每个块中线程的元组数量warp.meta_group_size()计算当前线程组处理的数据行索引idx
  2. idx超出输入数据行数的范围,则直接返回。
  3. 计算当前线程组处理的输入数据行的起始地址x
  4. 分别计算该行数据的均值m和调整后标准差s,其中均值的计算采用线程块内同步的方式进行累加求和,并通过cg::reduce()函数进行归约;标准差的计算同样采用线程块内同步的方式进行累加求和,并对结果进行开方运算,并添加了一个小的常数以防止除以零。
  5. meanrstd非空,则将计算得到的均值和标准差分别写入相应的输出地址。
  6. 最后,根据计算得到的均值、标准差、权重和偏置,对输入数据进行归一化、标准化和加权求和操作,并将结果写入输出地址。

该函数使用了CUDA C++的协同计算(Cooperative Groups)库cg来进行线程块级别的同步和归约操作,并使用了CUDA的流式加载和存储指令__ldcs__stcs来优化数据加载和存储的效率。

这段 C++ 代码是一个 CUDA kernel,用于执行层归一化(Layer Normalization)的前向传播操作。层归一化是一种常用于神经网络中的技术,它用于规范化神经元的激活值,从而加速训练过程。

以下是代码的详细解释:

  1. 函数声明:
__global__ void layernorm_forward_kernel3(float* __restrict__ out, float* __restrict__ mean, float* __restrict__ rstd,const float*  __restrict__ inp, const float*  __restrict__ weight,const float* __restrict__ bias, int N, int C)
* `__global__`:这是一个 CUDA 关键字,表示这是一个 GPU 上运行的 kernel 函数。
* 函数接受以下参数:+ `out`:输出张量,存储归一化后的结果。+ `mean`:均值张量,如果提供了(即不是 `nullptr`),则存储每个输入元素的均值。+ `rstd`:规范化标准差张量,如果提供了(即不是 `nullptr`),则存储每个输入元素的规范化标准差。+ `inp`:输入张量。+ `weight`:权重张量,用于缩放归一化后的结果。+ `bias`:偏置张量,用于添加到归一化后的结果上。+ `N` 和 `C`:分别表示输入张量的高度和宽度(例如,在批量大小为 `N`、特征数为 `C` 的 2D 输入张量中)。

2. 线程索引和同步:

cg::thread_block block = cg::this_thread_block();
cg::thread_block_tile<32> warp = cg::tiled_partition<32>(block);
int idx = blockIdx.x * warp.meta_group_size() + warp.meta_group_rank();
if(idx >= N) {return;
}
* 这部分代码用于获取当前线程块的索引和线程索引,以及同步线程块中的线程。

3. 计算均值 (mean):

const float* x = inp + idx * C;
float sum = 0.0f;
for (int i = warp.thread_rank(); i < C; i += warp.size()) {sum += x[i];
}
sum = cg::reduce(warp, sum, cg::plus<float>{});
float m = sum / C;
if(warp.thread_rank() == 0 && mean != nullptr) {__stcs(mean + idx, m);
}
* 这部分代码计算输入张量中每个元素的均值。
* `cg::reduce` 用于同步线程块中的所有线程,并将它们的部分和合并为一个总和。
* 如果提供了 `mean` 张量,则将计算出的均值存储在其中。

4. 计算规范化标准差 (rstd):

sum = 0.0f;
for (int i = warp.thread_rank(); i < C; i += warp.size()) {float diff = x[i] - m;sum += diff * diff;
}
sum = cg::reduce(warp, sum, cg::plus<float>{});
float s = rsqrtf(sum / C + 1e-5f);
if(warp.thread_rank() == 0 && rstd != nullptr) {__stcs(rstd + idx, s);
}
* 这部分代码计算输入张量中每个元素的规范化标准差。
* `rsqrtf` 用于计算平方根的倒数(即规范化标准差)。
* 如果提供了 `rstd` 张量,则将计算出的规范化标准差存储在其中。

5. 最终归一化和缩放:

float* o = out + idx * C;
for (int c = warp.thread_rank(); c < C; c += warp.size()) {float n = s * (__ldcs(x+c) - m);__stcs(o+c, n * weight[c] + bias[c]);
}
* 这部分代码使用前面计算出的均值和规范化标准差对输入张量进行归一化,并使用权重和偏置进行缩放。
* `__ldcs` 和 `__stcs` 是流加载和存储操作,用于指示编译器这些数据不会很快被重用,可以通过缓存流进行传输,从而提高缓存命中率。

在 CUDA 编程中,__stcs 和类似的流操作(如 __ldcs)通常用于优化内存访问模式,特别是在处理全局内存时。这些操作提示编译器使用特定的内存访问模式,以避免缓存冲突并提高性能。然而,它们并不是必需的,并且在某些情况下可能不会被使用。

在提供的代码示例中,__stcs 用于将结果写入全局内存。如果您不使用 __stcs,而是使用普通的赋值操作(例如 *o = value;),CUDA 运行时仍然能够正确地将结果写入全局内存。但是,这可能会错过一些性能优化机会,因为编译器不会自动应用与流操作相关的优化。

是否使用 __stcs 取决于您的具体需求和性能目标。如果您对性能有严格要求,并且您的代码在全局内存访问方面遇到了瓶颈,那么使用流操作可能有助于提升性能。另一方面,如果您的代码已经足够快,或者流操作的使用过于复杂,那么您可能选择不使用它们。

请注意,__stcs 和其他类似的流操作是特定于某些 CUDA 编程模型或库的,并不是 CUDA 的标准 API 的一部分。因此,它们的使用可能取决于您所使用的具体编程环境和工具链。

总的来说,__stcs 可以在某些情况下用于优化性能,但并不是必需的。您可以根据自己的需求和目标来决定是否使用它。如果您对性能没有特殊要求,或者不熟悉这些流操作的使用,那么您可以选择不使用它们。

在 AMD GPU 编程中,没有直接对应于 NVIDIA CUDA 中的 __stcs 这样的流操作指令。AMD GPU 编程主要使用 OpenCL、HIP(Heterogeneous-compute Interface for Portability)或者 AMD 的专有工具如 AMD GPUOpen。

在 AMD GPU 上优化内存访问和进行数据传输,您通常会依赖不同的机制和工具:

  1. OpenCL 内存对象: 在 OpenCL 中,您可以使用不同的内存对象(如缓冲区对象)来管理 GPU 上的内存,并通过异步数据传输(如 clEnqueueWriteBuffer 和 clEnqueueReadBuffer)来优化数据传输。

  2. HIP: 如果您在使用 CUDA 代码并且希望将其移植到 AMD GPU,HIP 可以帮助您实现这一点。HIP 提供了一个类似于 CUDA 的 API,它会自动将 CUDA 调用映射到相应的 AMD GPU 调用。在 HIP 中,您可能会使用类似于 CUDA 的内存管理函数,但不会有 __stcs 这样的特定指令。

  3. AMD GPUOpen: AMD 提供了一套开源库和工具,用于在 AMD GPU 上进行高效编程。这些库可能提供了特定的内存管理和优化策略,但这些策略可能不同于 CUDA 的流操作。

  4. 内存访问模式: 无论使用哪种编程模型,优化内存访问模式都是关键。这包括确保数据对齐、减少内存碎片、使用适当的内存布局以及避免不必要的内存传输。

  5. 同步和调度: 在 GPU 编程中,同步和调度是重要的考虑因素。AMD GPU 编程模型通常提供了一些机制来同步不同内核之间的执行和内存访问,这对于实现高效的内存操作至关重要。

  6. 性能分析工具: 使用 AMD GPU 的性能分析工具可以帮助您识别潜在的瓶颈和优化机会,这些工具可以提供关于内存访问模式、数据传输和内核执行的有用信息。

综上所述,尽管 AMD GPU 编程没有直接的 __stcs 替代指令,但您仍然可以通过使用适当的内存管理策略、优化内存访问模式以及利用提供的编程模型和工具来在 AMD GPU 上实现高效的内存操作。

单元测试

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <float.h>
#include <string.h>#include <cuda_runtime.h>
#include <cublas_v2.h>
#include <cublaslt_v2.h>#include "utils.h"
#include "testing_utils.h"
#include "gpt2_encoder_decoder.h"#define MAX_T 20
#define MAX_B 8extern "C" void layernorm_forward_kernel3(float* out, float* mean, float* rstd,const float* inp, const float* weight,const float* bias, int B, int T, int C);void test_layernorm_forward_kernel3() {int B = 1;int T = 2;int C = 3;size_t inp_size = B * T * C;size_t out_size = inp_size;float* d_inp;float* d_out;float* d_weight;float* d_bias;float* d_mean;float* d_rstd;float* h_inp;float* h_out;float* h_weight;float* h_bias;float* h_mean;float* h_rstd;h_inp = (float*)malloc(inp_size * sizeof(float));h_out = (float*)malloc(out_size * sizeof(float));h_weight = (float*)malloc(C * sizeof(float));h_bias = (float*)malloc(C * sizeof(float));h_mean = (float*)malloc(B * C * sizeof(float));h_rstd = (float*)malloc(B * C * sizeof(float));cudaMalloc(&d_inp, inp_size * sizeof(float));cudaMalloc(&d_out, out_size * sizeof(float));cudaMalloc(&d_weight, C * sizeof(float));cudaMalloc(&d_bias, C * sizeof(float));cudaMalloc(&d_mean, B * C * sizeof(float));cudaMalloc(&d_rstd, B * C * sizeof(float));for (int i = 0; i < inp_size; i++) {h_inp[i] = i * 1.0f;}for (int i = 0; i < C; i++) {h_weight[i] = 1.0f;h_bias[i] = 0.0f;}cudaMemcpy(d_inp, h_inp, inp_size * sizeof(float), cudaMemcpyHostToDevice);cudaMemcpy(d_weight, h_weight, C * sizeof(float), cudaMemcpyHostToDevice);cudaMemcpy(d_bias, h_bias, C * sizeof(float), cudaMemcpyHostToDevice);layernorm_forward_kernel3<<<B, C>>>(d_out, d_mean, d_rstd, d_inp, d_weight, d_bias, B, T, C);cudaDeviceSynchronize();cudaMemcpy(h_out, d_out, out_size * sizeof(float), cudaMemcpyDeviceToHost);cudaMemcpy(h_mean, d_mean, B * C * sizeof(float), cudaMemcpyDeviceToHost);cudaMemcpy(h_rstd, d_rstd, B * C * sizeof(float), cudaMemcpyDeviceToHost);for (int b = 0; b < B; b++) {for (int c = 0; c < C; c++) {float expected = (c * T * B + b * T + 0.5f) * 1.0f;float got = h_out[b * C + c];float tolerance = 1e-5f;if (fabs(expected - got) > tolerance) {printf("layernorm_forward_kernel3 test failed at index %d, %d\n", b, c);printf("expected %f but got %f\n", expected, got);exit(1);}}}free(h_inp);free(h_out);free(h_weight);free(h_bias);free(h_mean);free(h_rstd);cudaFree(d_inp);cudaFree(d_out);cudaFree(d_weight);cudaFree(d_bias);cudaFree(d_mean);cudaFree(d_rstd);
}int main(int argc, char *argv[]) {test_layernorm_forward_kernel3();printf("layernorm_forward_kernel3 test ok\n");return 0;
}

下面是使用Google Test框架生成的单元测试代码,用于测试layernorm_forward_kernel3函数的功能:

#include <gtest/gtest.h>
#include <cuda_runtime.h>// Define the test fixture class
class LayerNormTest : public ::testing::Test {
protected:void SetUp() override {// Allocate device memory for input, output, mean, rstd, weight, and biascudaMalloc(&inp, N * C * sizeof(float));cudaMalloc(&out, N * C * sizeof(float));cudaMalloc(&mean, N * sizeof(float));cudaMalloc(&rstd, N * sizeof(float));cudaMalloc(&weight, C * sizeof(float));cudaMalloc(&bias, C * sizeof(float));// Initialize input, weight, and bias data on the hostfloat* host_inp = new float[N * C];float* host_weight = new float[C];float* host_bias = new float[C];for (int i = 0; i < N * C; i++) {host_inp[i] = i;}for (int i = 0; i < C; i++) {host_weight[i] = 1.0f;host_bias[i] = 0.0f;}// Copy host data to devicecudaMemcpy(inp, host_inp, N * C * sizeof(float), cudaMemcpyHostToDevice);cudaMemcpy(weight, host_weight, C * sizeof(float), cudaMemcpyHostToDevice);cudaMemcpy(bias, host_bias, C * sizeof(float), cudaMemcpyHostToDevice);delete[] host_inp;delete[] host_weight;delete[] host_bias;}void TearDown() override {// Free device memorycudaFree(inp);cudaFree(out);cudaFree(mean);cudaFree(rstd);cudaFree(weight);cudaFree(bias);}// Test dataint N = 8;int C = 16;float* inp;float* out;float* mean;float* rstd;float* weight;float* bias;
};// Define a test case
TEST_F(LayerNormTest, Forward) {// Launch the kerneldim3 block(32, 1);dim3 grid((N + block.x - 1) / block.x, 1);layernorm_forward_kernel3<<<grid, block>>>(out, mean, rstd, inp, weight, bias, N, C);// Copy output data from device to hostfloat* host_out = new float[N * C];cudaMemcpy(host_out, out, N * C * sizeof(float), cudaMemcpyDeviceToHost);// TODO: Add assertions to verify the correctness of the outputdelete[] host_out;
}// Run the tests
int main(int argc, char** argv) {::testing::InitGoogleTest(&argc, argv);return RUN_ALL_TESTS();
}

以上是使用Google Test框架生成的单元测试代码,用于测试layernorm_forward_kernel3函数的功能。在测试过程中,需要先为函数的输入和输出分配设备内存,并在测试用例中调用函数来执行计算。然后,将输出数据从设备复制到主机,并在主机端进行断言以验证输出的正确性。

请注意,在上面的代码中,需要根据实际情况添加断言来验证输出的正确性。

优化建议

这份代码是一个用于层归一化(Layer Normalization)的CUDA内核,旨在对深度学习模型中的特征图进行标准化。它计算给定输入的均值、标准差,并应用权重和偏置进行缩放和偏移。下面我将从潜在问题和优化方向两个方面进行详细评审:

潜在问题

  1. 内存访问模式:代码在访问输入inp、输出out、权重weight和偏置bias时,假设了这些数组是连续且对齐的。对于非连续或未对齐的数据,可能会导致性能下降。建议添加对数据对齐的假设说明或检查。

  2. 数据类型限制:当前实现使用float类型进行计算,对于需要更高精度或更低精度的场景可能不适用。考虑提供类型参数化的实现。

  3. 异常处理:代码中未涉及对输入参数的有效性检查(例如NC的值是否合法,weightbias是否为空等)。在实际应用中,应检查这些参数以避免潜在的运行时错误。

  4. 硬编码常量:如1e-5f在计算标准差时用作偏移量,这种硬编码可能会影响算法的泛化能力或适应不同应用场景的能力。建议将其作为参数传递给内核。

优化方向

  1. 代码可读性:虽然内核实现了其功能,但代码中缺乏注释,特别是对于一些不明显的操作,如__stcs__ldcs指令。为了提高代码的可维护性,应在关键操作处添加注释,解释其目的和预期的效果。

  2. 性能优化:尽管使用了CUDA的 Cooperative Groups 和 Thread Block Tiles 功能来改善缓存效率和降低同步开销,但还可以进一步探索以下优化点:

    • 减少内存访问:计算均值和标准差时,每个线程重复访问了输入数据x。可以通过将计算均值和方差的循环合并来减少对输入数据的访问次数。

    • 利用共享内存:考虑将权重和偏置加载到共享内存中,特别是当C较大时,这可以减少全局内存访问的开销。

    • 优化归一化计算:对rsqrtf的结果再次乘以C,可能会引入额外的精度损失。考虑是否有更稳定的算法来执行这种归一化和缩放操作。

  3. 通用性:目前的实现专注于浮点数据的处理。考虑扩展此内核以支持其他数据类型(如半精度浮点类型float16),以满足对计算效率和内存使用有更高要求的应用场景。

  4. 异步执行和流控:在实际应用中,可能需要同时执行多个CUDA内核或在不同内核之间进行数据传输。考虑使用CUDA流来异步执行此内核和其他操作,以提高整体执行效率。

以下是相应的代码修订与优化。请注意,由于涉及的修改较为复杂,一些细节可能需要进一步调整。

根据您的要求,我将针对上述提出的建议逐一进行代码优化。请注意,某些建议(如检查输入参数的有效性、对硬编码常量进行参数化)在内核代码中可能不直接体现,因为它们通常在调用内核之前于主机代码中处理。不过,我会在说明中提及这些优化点。现在让我们关注代码优化:

// 定义一个宏或者常量用于调整算法的敏感度
#define Epsilon 1e-5f__global__ void layernorm_forward_kernel3(float* __restrict__ out, float* __restrict__ mean, float* __restrict__ rstd,const float*  __restrict__ inp, const float*  __restrict__ weight,const float* __restrict__ bias, int N, int C) {cg::thread_block block = cg::this_thread_block();cg::thread_block_tile<32> warp = cg::tiled_partition<32>(block);int idx = blockIdx.x * warp.meta_group_size() + warp.meta_group_rank();// 确保索引在有效范围内if(idx >= N) {return;}const float* x = inp + idx * C;// 合并计算均值和方差的循环以减少对输入的重复访问float sum = 0.0f;float square_sum = 0.0f;for (int i = warp.thread_rank(); i < C; i += warp.size()) {float diff = x[i] - sum * (1.0f / C);sum += diff;square_sum += diff * diff;}sum = cg::reduce(warp, sum, cg::plus<float>{});square_sum = cg::reduce(warp, square_sum, cg::plus<float>{});float m = sum / C;if(warp.thread_rank() == 0 && mean != nullptr) {__stcs(mean + idx, m);}float s = rsqrtf(square_sum / C + Epsilon);if(warp.thread_rank() == 0 && rstd != nullptr) {__stcs(rstd + idx, s);}float* o = out + idx * C;for (int c = warp.thread_rank(); c < C; c += warp.size()) {float n = s * (__ldcs(x+c) - m);__stcs(o+c, n * weight[c] + bias[c]);}
}

解释和应用的优化:

  1. 内存访问模式和数据类型限制:对于内存访问模式和数据类型限制的问题,建议在调用此内核的主机代码中进行检查和处理,例如确保输入输出缓冲区是适当对齐的,以及提供支持不同类型(如doublehalf)的版本。

  2. 异常处理:异常处理主要涉及输入参数的有效性检查,应在调用内核之前的主机代码中完成。例如,确保NC非负,weightbias非空等。

  3. 硬编码常量:通过定义Epsilon宏来替换硬编码的1e-5f,使得代码更易于修改和维护。

  4. 代码可读性:在关键操作处添加了注释,以提高代码的可读性和可维护性。

  5. 性能优化

    • 合并了计算均值和方差的循环,以减少对输入数据的重复访问。
    • 考虑到内核的特性,使用共享内存或异步执行的优化可能需要对整体架构进行较大改动,可能会超出简单优化的范畴。这些优化应根据具体应用场景的需要进行仔细设计和测试。

请注意,对于任何CUDA内核,实际性能优化往往需要针对特定硬件和具体应用场景进行细致的调整和测试。以上优化建议提供了一个出发点,但可能需要根据实际情况进行进一步的优化。此优化后的代码版本仅供参考。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【北京迅为】《iTOP-3588从零搭建ubuntu环境手册》-第8章 安装编译所需要的依赖包

RK3588是一款低功耗、高性能的处理器&#xff0c;适用于基于arm的PC和Edge计算设备、个人移动互联网设备等数字多媒体应用&#xff0c;RK3588支持8K视频编解码&#xff0c;内置GPU可以完全兼容OpenGLES 1.1、2.0和3.2。RK3588引入了新一代完全基于硬件的最大4800万像素ISP&…

多个文件 import 的相同模块里的对象

多个文件 import 的相同模块里的对象&#xff0c;是否永远都是同一个对象&#xff1f; 在store的index.js中 import vue from ‘vue’ import Vuex from ‘vuex’ 并配置有关对象 然后再app.vue中配置vm 在不同的文件中 import一个vue对象&#xff0c;在任何情况下&#…

vue2项目升级到vue3经历分享5

写到第5篇了&#xff0c;解决了很多问题&#xff0c;还有一些需要调整 1 el-input-number指令兼容性调整 下面这个可编辑的表格&#xff0c;全是0&#xff0c;于是需要一个指令&#xff0c;让它自己实现如果是0&#xff0c;就置空&#xff1b;如果是数字就是格式化为千分位&…

使用docker安装seafile

使用docker安装seafile 1 介绍seafile Seafile 是一款开源的企业云盘&#xff0c;支持全平台&#xff08;浏览器、Windows、Mac、Linux、Android、IPhone等&#xff09;客户端。Seafile 内置协同文档 SeaDoc &#xff0c;让协作撰写、管理和发布文档更便捷。最重要的这是国产…

【网站项目】SpringBoot796水产养殖系统

&#x1f64a;作者简介&#xff1a;拥有多年开发工作经验&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的项目或者毕业设计。 代码可以私聊博主获取。&#x1f339;赠送计算机毕业设计600个选题excel文件&#xff0c;帮助大学选题。赠送开题报告模板&#xff…

【JavaEE初阶系列】——Cookie和Session应用之实现登录页面

目录 &#x1f6a9;本章目标 1.登录页面 2.servlet处理上述的登录请求 3.网站主页(成功登录之后的页面&#xff09; &#x1f6a9;实现过程 &#x1f393;登录页面 &#x1f393;Servlet处理登录请求 &#x1f388;获取请求传来的参数(用户名和密码) &#x1f388;验证…

一件事做了十年

目录 一、背景二、过程1.贫困山区的心理悲哀2.基础差的客观转变3.对于教育的思考4.持续做这件事在路上5.同行人有很早就完成的&#xff0c;有逐渐放弃的&#xff0c;你应该怎么办&#xff1f;6.回头看&#xff0c;什么才是最终留下的东西? 三、总结 一、背景 在哪里出生我们无…

《Linux运维总结:ARM64架构CPU基于docker-compose一离线部署rabbitmq 3.10.25容器版镜像模式集群》

总结&#xff1a;整理不易&#xff0c;如果对你有帮助&#xff0c;可否点赞关注一下&#xff1f; 更多详细内容请参考&#xff1a;《Linux运维篇&#xff1a;Linux系统运维指南》 一、部署背景 由于业务系统的特殊性&#xff0c;我们需要面向不通的客户安装我们的业务系统&…

【ubuntu】ubuntu-18.04开机卡在Starting User Manager for UID 120....问题解决方案

错误截图 解决方案 启动系统&#xff0c;开机界面单击按键esc键&#xff0c;注意需要将鼠标定位到菜单界面&#xff0c;移动键盘上下键选择Advanced options for Ubuntu 进入如下菜单&#xff0c;选择recovery mode 回车之后会弹出如下界面&#xff0c;选择如下root&#xff0…

超详细的胎教级Stable Diffusion使用教程(四)

这套课程分为五节课&#xff0c;会系统性的介绍sd的全部功能和实操案例&#xff0c;让你打下坚实牢靠的基础 一、为什么要学Stable Diffusion&#xff0c;它究竟有多强大&#xff1f; 二、三分钟教你装好Stable Diffusion 三、小白快速上手Stable Diffusion 四、Stable dif…

【C语言/Python】嵌入式常用数据滤波处理:卡尔曼滤波器的简易实现方式(Kalman Filter)

【C语言/Python】嵌入式常用数据滤波处理&#xff1a;卡尔曼滤波器的简易实现方式&#xff08;Kalman Filter&#xff09; 文章目录 卡尔曼滤波卡尔曼滤波公式卡尔曼滤波数据处理效果C语言的卡尔曼滤波实现附录&#xff1a;压缩字符串、大小端格式转换压缩字符串浮点数压缩Pack…

Spring-Cloud-OpenFeign源码解析-01-OpenFeign简介

OpenFeign简介 OpenFeign是一种声明式、模板化的HTTP客户端(仅在Application Client中使用)。声明式调用是指&#xff0c;就像调用本地方法一样调用远程方法&#xff0c;无需感知操作远程http请求。 OpenFeign和Feign的区别 Feign是Spring Cloud组件中一个轻量级RESTful的HT…

亚信安全发布《2024年第一季度网络安全威胁报告》

亚信安全2024年第一季度网络安全威胁报告 一季度威胁概览 《亚信安全2024年第一季度网络安全威胁报告》的发布旨在从一个全面的视角解析当前的网络安全威胁环境。此报告通过详尽梳理和总结2024年第一季度的网络攻击威胁&#xff0c;目的是提供一个准确和直观的终端威胁感知。…

LNMP环境部署WordPress——使用源码包安装方式部署环境

目录 一.前提准备 二.源码安装Mysql 1.MySQL类型 2.MySQL 版本说明 3.MySQL 安装方式 3.1 yum 安装 3.2 编译安装 3.3 二进制安装 3.4 rpm 安装 4. 编译安装MySQL5.7 4.1 清理安装环境 4.2 创建mysql用户 4.3 从官网下载tar包 4.4 安装编译工具 4.5 解压 4.6 …

【教学类-55-01】20240511图层顺序挑战(四格长条纸)(4*4)和“手工纸自制参考图”

作品展示 背景需求 空间思维图层挑战2|逻辑推理|空间想象力 - 小红书 (xiaohongshu.com)https://www.xiaohongshu.com/discovery/item/62cbf6c60000000010026aa0?app_platformandroid&ignoreEngagetrue&app_version8.35.0&share_from_user_hiddentrue&typevi…

Django项目运行报错:ModuleNotFoundError: No module named ‘MySQLdb‘

解决方法&#xff1a; 在__init__.py文件下&#xff0c;新增下面这段代码 import pymysql pymysql.install_as_MySQLdb() 注意&#xff1a;确保你的 python 有下载 pymysql 库&#xff0c;没有的话可以使用 pip install pymysql安装 原理&#xff1a;用pymysql来代替mysqlL…

探索人类意识的多样性:从安全感到语感、节奏感的差异

在我们的日常生活中&#xff0c;人类意识表现出多种多样的特点&#xff0c;这些特点往往与个体的天生禀赋和生活经历密切相关。从安全感到语感、节奏感&#xff0c;每个人的表现都有所不同。今天&#xff0c;让我们一起来探索这些差异&#xff0c;感受人类意识的多样性。 首先&…

stable diffusion WebUi本地安装

一、stable diffusion 介绍 Stable Diffusion是一种先进的文本到图像的生成模型&#xff0c;它可以根据给定的文本输入生成高度逼真的图像。 Stable Diffusion模型因其高效性和灵活性&#xff0c;在AI图像生成领域引起了广泛关注&#xff0c;并在实际应用中展示了其强大的能力…

论文盲审吐槽多,谁给盲审不负责的老师买单?如何看待浙江大学「一刀切」的研究生学位论文双盲评审制度?

::: block-1 “时问桫椤”是一个致力于为本科生到研究生教育阶段提供帮助的不太正式的公众号。我们旨在在大家感到困惑、痛苦或面临困难时伸出援手。通过总结广大研究生的经验&#xff0c;帮助大家尽早适应研究生生活&#xff0c;尽快了解科研的本质。祝一切顺利&#xff01;—…

day6Qt作业

人脸识别系统 #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <opencv2/opencv.hpp> #include <iostream> #include <math.h> #include<opencv2/face.hpp> #include <vector> #include <map> #include <QMessag…