Halide示例学习四

Halide简介 Halide是用C++作为宿主语言的一个图像处理相关的DSL(Domain Specified Language)语言,全称领域专用语言。主要的作用为在软硬层面上(与算法本身的设计无关)实现对算法的底层加速,我们有必要对其有一定的了解。因为不论是 传统的图像处理方法亦或是深度学习应用 都使用到了halide的思想。 来自 https://www.codercto.com/a/67796.html ... 阅读详情

多阶段计算图

#include "Halide.h"
#include <stdio.h>

using namespace Halide;

int main(int argc, char **argv) {
    Var x("x"), y("y");
    // 两阶段的计算图
    {
        Func producer("producer_default"), consumer("consumer_default");
        // 第一阶段:数学计算
        producer(x, y) = sin(x * y);
        // 第二阶段:求平均
        consumer(x, y) = (producer(x, y) +
                          producer(x, y + 1) +
                          producer(x + 1, y) +
                          producer(x + 1, y + 1)) / 4;
        // 开启追踪
        consumer.trace_stores();
        producer.trace_stores();
        // 实例化为4x4的空间
        printf("\nEvaluating producer-consumer pipeline with default schedule\n");
        // 从这里也可以看出,这两个阶段不是先计算完producer然后再计算consumer
        // 而是最后组成了consumer这个整体的计算公式
        consumer.realize({4, 4});
        // 同下述的公式一致
        // consumer(x, y) = (sin(x * y) +
        //                   sin(x * (y + 1)) +
        //                   sin((x + 1) * y) +
        //                   sin((x + 1) * (y + 1))/4);
        // 等效C代码如下所示
        float result[4][4];
        for (int y = 0; y < 4; y++) {
            for (int x = 0; x < 4; x++) {
                result[y][x] = (sin(x * y) +
                                sin(x * (y + 1)) +
                                sin((x + 1) * y) +
                                sin((x + 1) * (y + 1))) / 4;
            }
        }
        printf("\n");
        // 使用print_loop_nest,将不会出现producer的任何信息,因为被内建再consumer中
        printf("Pseudo-code for the schedule:\n");
        consumer.print_loop_nest();
        printf("\n");
    }

    return 0;
}
# 结果如下所示
# 默认是全部使用内建函数
Store consumer_default.0(0, 0) = 0.210368
Store consumer_default.0(1, 0) = 0.437692
Store consumer_default.0(2, 0) = 0.262604
Store consumer_default.0(3, 0) = -0.153921
Store consumer_default.0(0, 1) = 0.437692
Store consumer_default.0(1, 1) = 0.475816
Store consumer_default.0(2, 1) = 0.003550
Store consumer_default.0(3, 1) = 0.023565
Store consumer_default.0(0, 2) = 0.262604
Store consumer_default.0(1, 2) = 0.003550
Store consumer_default.0(2, 2) = -0.225879
Store consumer_default.0(3, 2) = 0.146372
Store consumer_default.0(0, 3) = -0.153921
Store consumer_default.0(1, 3) = 0.023565
Store consumer_default.0(2, 3) = 0.146372
Store consumer_default.0(3, 3) = -0.237233

多计算图组合示例

#include "Halide.h"
#include <stdio.h>

using namespace Halide;

int main(int argc, char **argv) {
    Var x("x"), y("y");
    // 使用compute_root来强制使得计算图进行计算
    {
        Func producer("producer_root"), consumer("consumer_root");
        producer(x, y) = sin(x * y);
        consumer(x, y) = (producer(x, y) +
                          producer(x, y + 1) +
                          producer(x + 1, y) +
                          producer(x + 1, y + 1)) / 4;
        // 让Halide在计算consumer前先计算producer
        producer.compute_root();
        consumer.trace_stores();
        producer.trace_stores();
        printf("\nEvaluating producer.compute_root()\n");
        consumer.realize({4, 4});
        // 输出的计算过程中将会出现producer的计算过程
        // 等效C代码
        float result[4][4];
        float producer_storage[5][5];
        // 先计算producer_storage
        for (int y = 0; y < 5; y++) {
            for (int x = 0; x < 5; x++) {
                producer_storage[y][x] = sin(x * y);
            }
        }
        // 然后计算result
        for (int y = 0; y < 4; y++) {
            for (int x = 0; x < 4; x++) {
                result[y][x] = (producer_storage[y][x] +
                                producer_storage[y + 1][x] +
                                producer_storage[y][x + 1] +
                                producer_storage[y + 1][x + 1]) / 4;
            }
        }
        // 实例化最终的输出尺寸4x4的时候,Halide会自动进行尺寸的反向推导
        // 知道producer的尺寸为5x5
        printf("Pseudo-code for the schedule:\n");
        consumer.print_loop_nest();
        printf("\n");
    }

    /* 现在来比较上述两者的差别,特别是数据存取次数、计算次数方面
    全内建计算图 (默认的调度):
    - 分配的临时内存: 0
    - 取数操作: 0
    - 存数操作: 16
    - sin函数的调用次数: 64

    分步计算:
    - 分配的临时内存: 25 floats
    - 取数操作: 64
    - 存数操作: 41
    - sin函数的调用次数: 25
    return 0;
}

#结果
Store producer_root.0(0, 0) = 0.000000
Store producer_root.0(1, 0) = 0.000000
Store producer_root.0(2, 0) = 0.000000
Store producer_root.0(3, 0) = 0.000000
Store producer_root.0(4, 0) = 0.000000
Store producer_root.0(0, 1) = 0.000000
Store producer_root.0(1, 1) = 0.841471
Store producer_root.0(2, 1) = 0.909297
Store producer_root.0(3, 1) = 0.141120
Store producer_root.0(4, 1) = -0.756802
Store producer_root.0(0, 2) = 0.000000
Store producer_root.0(1, 2) = 0.909297
Store producer_root.0(2, 2) = -0.756802
Store producer_root.0(3, 2) = -0.279415
Store producer_root.0(4, 2) = 0.989358
Store producer_root.0(0, 3) = 0.000000
Store producer_root.0(1, 3) = 0.141120
Store producer_root.0(2, 3) = -0.279415
Store producer_root.0(3, 3) = 0.412118
Store producer_root.0(4, 3) = -0.536573
Store producer_root.0(0, 4) = 0.000000
Store producer_root.0(1, 4) = -0.756802
Store producer_root.0(2, 4) = 0.989358
Store producer_root.0(3, 4) = -0.536573
Store producer_root.0(4, 4) = -0.287903
Store consumer_root.0(0, 0) = 0.210368
Store consumer_root.0(1, 0) = 0.437692
Store consumer_root.0(2, 0) = 0.262604
Store consumer_root.0(3, 0) = -0.153921
Store consumer_root.0(0, 1) = 0.437692
Store consumer_root.0(1, 1) = 0.475816
Store consumer_root.0(2, 1) = 0.003550
Store consumer_root.0(3, 1) = 0.023565
Store consumer_root.0(0, 2) = 0.262604
Store consumer_root.0(1, 2) = 0.003550
Store consumer_root.0(2, 2) = -0.225879
Store consumer_root.0(3, 2) = 0.146372
Store consumer_root.0(0, 3) = -0.153921
Store consumer_root.0(1, 3) = 0.023565
Store consumer_root.0(2, 3) = 0.146372
Store consumer_root.0(3, 3) = -0.237233

示意图显示结果如下所示:

在这里插入图片描述

compute_at使用方法

#include "Halide.h"
#include <stdio.h>

using namespace Halide;

int main(int argc, char **argv) {
    Var x("x"), y("y");
    // 介于内建和非内建之间的部分
    {
        Func producer("producer_y"), consumer("consumer_y");
        producer(x, y) = sin(x * y);
        consumer(x, y) = (producer(x, y) +
                          producer(x, y + 1) +
                          producer(x + 1, y) +
                          producer(x + 1, y + 1)) / 4;
        // 当compute_at(consumer,x)时跟全内建的形式非常相同
        /*
        a.compute_at(b,y):表示在y这个循环块内插入一块计算在y固定的时候,计算必要的a的代码
        */
        producer.compute_at(consumer, y);
        producer.trace_stores();
        consumer.trace_stores();
        printf("\nEvaluating producer.compute_at(consumer, y)\n");
        consumer.realize({4, 4});
        // 等效C代码如下所示
        float result[4][4];
        for (int y = 0; y < 4; y++) {
            // 为了能够满足计算结果一行的需求,我们知道中间输入至少要两行
            float producer_storage[2][5];
            for (int py = y; py < y + 2; py++) {
                for (int px = 0; px < 5; px++) {
                    producer_storage[py - y][px] = sin(px * py);
                }
            }
            // Compute a scanline of the consumer.
            for (int x = 0; x < 4; x++) {
                result[y][x] = (producer_storage[0][x] +
                                producer_storage[1][x] +
                                producer_storage[0][x + 1] +
                                producer_storage[1][x + 1]) / 4;
            }
        }
        printf("Pseudo-code for the schedule:\n");
        consumer.print_loop_nest();
        printf("\n");

        // 这种做法介于内建和非内建之间,好处就是可以利用数据的局部性
        // 不仅减少了中间结果缓存空间,同时利用了高速缓存实现快速读取

        // producer.compute_at(consumer, y):
        // - 缓存空间: 10 floats
        // - 读: 64
        // - 存: 56
        // - sin调用次数: 40
    }
    return 0;
}

# 结果如下所示
Store producer_y.0(0, 0) = 0.000000
Store producer_y.0(1, 0) = 0.000000
Store producer_y.0(2, 0) = 0.000000
Store producer_y.0(3, 0) = 0.000000
Store producer_y.0(4, 0) = 0.000000
Store producer_y.0(0, 1) = 0.000000
Store producer_y.0(1, 1) = 0.841471
Store producer_y.0(2, 1) = 0.909297
Store producer_y.0(3, 1) = 0.141120
Store producer_y.0(4, 1) = -0.756802
Store consumer_y.0(0, 0) = 0.210368
Store consumer_y.0(1, 0) = 0.437692
Store consumer_y.0(2, 0) = 0.262604
Store consumer_y.0(3, 0) = -0.153921
Store producer_y.0(0, 1) = 0.000000
Store producer_y.0(1, 1) = 0.841471
Store producer_y.0(2, 1) = 0.909297
Store producer_y.0(3, 1) = 0.141120
Store producer_y.0(4, 1) = -0.756802
Store producer_y.0(0, 2) = 0.000000
Store producer_y.0(1, 2) = 0.909297
Store producer_y.0(2, 2) = -0.756802
Store producer_y.0(3, 2) = -0.279415
Store producer_y.0(4, 2) = 0.989358
Store consumer_y.0(0, 1) = 0.437692
Store consumer_y.0(1, 1) = 0.475816
Store consumer_y.0(2, 1) = 0.003550
Store consumer_y.0(3, 1) = 0.023565
Store producer_y.0(0, 2) = 0.000000
Store producer_y.0(1, 2) = 0.909297
Store producer_y.0(2, 2) = -0.756802
Store producer_y.0(3, 2) = -0.279415
Store producer_y.0(4, 2) = 0.989358
Store producer_y.0(0, 3) = 0.000000
Store producer_y.0(1, 3) = 0.141120
Store producer_y.0(2, 3) = -0.279415
Store producer_y.0(3, 3) = 0.412118
Store producer_y.0(4, 3) = -0.536573
Store consumer_y.0(0, 2) = 0.262604
Store consumer_y.0(1, 2) = 0.003550
Store consumer_y.0(2, 2) = -0.225879
Store consumer_y.0(3, 2) = 0.146372
Store producer_y.0(0, 3) = 0.000000
Store producer_y.0(1, 3) = 0.141120
Store producer_y.0(2, 3) = -0.279415
Store producer_y.0(3, 3) = 0.412118
Store producer_y.0(4, 3) = -0.536573
Store producer_y.0(0, 4) = 0.000000
Store producer_y.0(1, 4) = -0.756802
Store producer_y.0(2, 4) = 0.989358
Store producer_y.0(3, 4) = -0.536573
Store producer_y.0(4, 4) = -0.287903
Store consumer_y.0(0, 3) = -0.153921
Store consumer_y.0(1, 3) = 0.023565
Store consumer_y.0(2, 3) = 0.146372
Store consumer_y.0(3, 3) = -0.237233

示意图显示结果:

在这里插入图片描述

store_root配合compute_at使用方法

#include "Halide.h"
#include <stdio.h>

using namespace Halide;

int main(int argc, char **argv) {
    Var x("x"), y("y");
    // 下述展示了强制中间buffer保持计算结果的情况
    {
        Func producer("producer_root_y"), consumer("consumer_root_y");
        producer(x, y) = sin(x * y);
        consumer(x, y) = (producer(x, y) +
                          producer(x, y + 1) +
                          producer(x + 1, y) +
                          producer(x + 1, y + 1)) / 4;

        // 让producer保持中间计算值
        producer.store_root();
        // ... but compute it as needed per y coordinate of the
        // consumer.
        producer.compute_at(consumer, y);

        producer.trace_stores();
        consumer.trace_stores();

        printf("\nEvaluating producer.store_root().compute_at(consumer, y)\n");
        consumer.realize({4, 4});

        // result/lesson_08_store_root_compute_y.gif
        // 等效C代码如下所示
        float result[4][4];
        float producer_storage[5][5];
        for (int y = 0; y < 4; y++) {

            // Compute enough of the producer to satisfy this scanline
            // of the consumer.
            for (int py = y; py < y + 2; py++) {

                // 跳过已经经过计算的prouducer点
                if (y > 0 && py == y) continue;

                for (int px = 0; px < 5; px++) {
                    producer_storage[py][px] = sin(px * py);
                }
            }

            // Compute a scanline of the consumer.
            for (int x = 0; x < 4; x++) {
                result[y][x] = (producer_storage[y][x] +
                                producer_storage[y + 1][x] +
                                producer_storage[y][x + 1] +
                                producer_storage[y + 1][x + 1]) / 4;
            }
        }

        printf("Pseudo-code for the schedule:\n");
        consumer.print_loop_nest();
        printf("\n");

        // producer.store_root().compute_at(consumer, y):
        // - 分配的中间缓存: 10 floats
        // - 取数: 64 = 4 * 4 * 4
        // - 存数: 41 = 5 * 5 + 4 * 4
        // - sin调用次数: 25 = 5 * 5
        // 关于分配的中间缓存为何是10floats
        // 主要是因为实际的Halide使用了如下所示的循环中间缓存作为缓存
        {
            // Actually store 2 scanlines instead of 5
            float producer_storage[2][5];
            for (int y = 0; y < 4; y++) {
                for (int py = y; py < y + 2; py++) {
                    if (y > 0 && py == y) continue;
                    for (int px = 0; px < 5; px++) {
                        // 循环缓存
                        producer_storage[py & 1][px] = sin(px * py);
                    }
                }
                for (int x = 0; x < 4; x++) {
                    // 循环调用
                    result[y][x] = (producer_storage[y & 1][x] +
                                    producer_storage[(y + 1) & 1][x] +
                                    producer_storage[y & 1][x + 1] +
                                    producer_storage[(y + 1) & 1][x + 1]) / 4;
                }
            }
        }
    }
    return 0;
}

示意图显示结果:

在这里插入图片描述

tile配合compute_at使用方法

#include "Halide.h"
#include <stdio.h>

using namespace Halide;

int main(int argc, char **argv) {
    Var x("x"), y("y");
    {
        Func producer("producer_tile"), consumer("consumer_tile");
        producer(x, y) = sin(x * y);
        consumer(x, y) = (producer(x, y) +
                          producer(x, y + 1) +
                          producer(x + 1, y) +
                          producer(x + 1, y + 1)) / 4;
        Var x_outer, y_outer, x_inner, y_inner;
        consumer.tile(x, y, x_outer, y_outer, x_inner, y_inner, 4, 4);
        producer.compute_at(consumer, x_outer);
        producer.trace_stores();
        consumer.trace_stores();

        printf("\nEvaluating:\n"
               "consumer.tile(x, y, x_outer, y_outer, x_inner, y_inner, 4, 4);\n"
               "producer.compute_at(consumer, x_outer);\n");
        consumer.realize({8, 8});

        float result[8][8];

        // For every tile of the consumer:
        for (int y_outer = 0; y_outer < 2; y_outer++) {
            for (int x_outer = 0; x_outer < 2; x_outer++) {
                // 瓦片下标配合
                int x_base = x_outer * 4;
                int y_base = y_outer * 4;
                // 下面这个内循环就是因为compute_as(,x_outer)的缘故,在此处进行了producer的必要的部分计算
                float producer_storage[5][5];
                for (int py = y_base; py < y_base + 5; py++) {
                    for (int px = x_base; px < x_base + 5; px++) {
                        producer_storage[py - y_base][px - x_base] = sin(px * py);
                    }
                }
                // 一个瓦片的内容
                for (int y_inner = 0; y_inner < 4; y_inner++) {
                    for (int x_inner = 0; x_inner < 4; x_inner++) {
                        int x = x_base + x_inner;
                        int y = y_base + y_inner;
                        result[y][x] =
                            (producer_storage[y - y_base][x - x_base] +
                             producer_storage[y - y_base + 1][x - x_base] +
                             producer_storage[y - y_base][x - x_base + 1] +
                             producer_storage[y - y_base + 1][x - x_base + 1]) / 4;
                    }
                }
            }
        }

        printf("Pseudo-code for the schedule:\n");
        consumer.print_loop_nest();
        printf("\n");
    }
    return 0;
}

示意图显示结果:

在这里插入图片描述

compute_at和store_at以及之前的混合技使用方法

#include "Halide.h"
#include <stdio.h>

using namespace Halide;

int main(int argc, char **argv) {
    Var x("x"), y("y");
    {
        Func producer("producer_mixed"), consumer("consumer_mixed");
        producer(x, y) = sin(x * y);
        consumer(x, y) = (producer(x, y) +
                          producer(x, y + 1) +
                          producer(x + 1, y) +
                          producer(x + 1, y + 1)) / 4;
        // y轴拆分成内16的双层循环
        Var yo, yi;
        consumer.split(y, yo, yi, 16);
        // 并行化最外层循环yo
        consumer.parallel(yo);
        // consumer进行x轴进行4位向量化
        consumer.vectorize(x, 4);
        // 在yo轴内,创建一个中间缓存来保存prouducer计算结果
        producer.store_at(consumer, yo);
        // 在yi轴内,创建一个代码块计算yi内consumer所需的prouducer
        producer.compute_at(consumer, yi);
        // producer的x轴也进行4位向量化
        producer.vectorize(x, 4);


        Buffer<float> halide_result = consumer.realize({160, 160});

        // 自己理解的C等效代码
        {
            float Consumer[160][160];
            // omp loop
            for(int yo = 0; yo < 10; yo++){
                float producer_storage[17][161];// store_at
                for(int yi = 0; yi < 16; yi++){
                    int yy = yo * 16 + yi;
                    // 计算所需的producer_storage
                    // compute_at
                    for(int x4 = 0; x4 < 160; x4++){
                        // 1部分内部应该是向量化4
                        producer_storage[yy&15][x4] = sin(yy*x4);
                        producer_storage[yy&15][x4 + 1] = sin(yy*(x4+1));
                        producer_storage[(yy + 1)&15][x4] = sin((yy + 1)*x4);
                        producer_storage[(yy+1)&15][(x4+1)] = sin((yy+1)*(x4+1));
                    }
                    for(int x4 = 0; x4 < 160; x4++){
                        Consumer[yy][x4] = producer_storage[yy&15][x4];
                        Consumer[yy][x4 + 1] = producer_storage[yy&15][x4 + 1];
                        Consumer[(yy + 1)][x4] = producer_storage[(yy + 1)&15][x4];
                        Consumer[(yy+1)][(x4+1)] = producer_storage[(yy+1)&15][(x4+1)];
                    }
                    
                }
            }
        }
        // 下述是官方的C等效代码
        float c_result[160][160];

        // For every strip of 16 scanlines (this loop is parallel in
        // the Halide version)
        for (int yo = 0; yo < 160 / 16; yo++) {
            int y_base = yo * 16;

            // Allocate a two-scanline circular buffer for the producer
            float producer_storage[2][161];

            // For every scanline in the strip of 16:
            for (int yi = 0; yi < 16; yi++) {
                int y = y_base + yi;

                for (int py = y; py < y + 2; py++) {
                    // store_at的影响
                    if (yi > 0 && py == y) continue;
                    for (int x_vec = 0; x_vec < 160 / 4 + 1; x_vec++) {
                        int x_base = x_vec * 4;
                        // 4 doesn't divide 161, so push the last vector left
                        // (see lesson 05).
                        if (x_base > 161 - 4) x_base = 161 - 4;
                        // If you're on x86, Halide generates SSE code for this part:
                        int x[] = {x_base, x_base + 1, x_base + 2, x_base + 3};
                        float vec[4] = {sinf(x[0] * py), sinf(x[1] * py),
                                        sinf(x[2] * py), sinf(x[3] * py)};
                        producer_storage[py & 1][x[0]] = vec[0];
                        producer_storage[py & 1][x[1]] = vec[1];
                        producer_storage[py & 1][x[2]] = vec[2];
                        producer_storage[py & 1][x[3]] = vec[3];
                    }
                }

                // Now compute consumer for this scanline:
                for (int x_vec = 0; x_vec < 160 / 4; x_vec++) {
                    int x_base = x_vec * 4;
                    // Again, Halide's equivalent here uses SSE.
                    int x[] = {x_base, x_base + 1, x_base + 2, x_base + 3};
                    float vec[] = {
                        (producer_storage[y & 1][x[0]] +
                         producer_storage[(y + 1) & 1][x[0]] +
                         producer_storage[y & 1][x[0] + 1] +
                         producer_storage[(y + 1) & 1][x[0] + 1]) /
                            4,
                        (producer_storage[y & 1][x[1]] +
                         producer_storage[(y + 1) & 1][x[1]] +
                         producer_storage[y & 1][x[1] + 1] +
                         producer_storage[(y + 1) & 1][x[1] + 1]) /
                            4,
                        (producer_storage[y & 1][x[2]] +
                         producer_storage[(y + 1) & 1][x[2]] +
                         producer_storage[y & 1][x[2] + 1] +
                         producer_storage[(y + 1) & 1][x[2] + 1]) /
                            4,
                        (producer_storage[y & 1][x[3]] +
                         producer_storage[(y + 1) & 1][x[3]] +
                         producer_storage[y & 1][x[3] + 1] +
                         producer_storage[(y + 1) & 1][x[3] + 1]) /
                            4};

                    c_result[y][x[0]] = vec[0];
                    c_result[y][x[1]] = vec[1];
                    c_result[y][x[2]] = vec[2];
                    c_result[y][x[3]] = vec[3];
                }
            }
        }
        printf("Pseudo-code for the schedule:\n");
        consumer.print_loop_nest();
        printf("\n");

        // Look on my code, ye mighty, and despair!

        // Let's check the C result against the Halide result. Doing
        // this I found several bugs in my C implementation, which
        // should tell you something.
        for (int y = 0; y < 160; y++) {
            for (int x = 0; x < 160; x++) {
                float error = halide_result(x, y) - c_result[y][x];
                // It's floating-point math, so we'll allow some slop:
                if (error < -0.001f || error > 0.001f) {
                    printf("halide_result(%d, %d) = %f instead of %f\n",
                           x, y, halide_result(x, y), c_result[y][x]);
                    return -1;
                }
            }
        }
    }
    return 0;
}

示意图显示结果:

在这里插入图片描述

Halide 构建 hello halide 随着人工智能,VR等领域的发展,我们对于高性能图像处理程序的需求越来越大;当前编程工具开发的高性能图像处理程序牺牲了程序的可读性,模块性,可移植性等;其主要原因是,当前程序将算法描述, 数据存储以及计算糅杂在一起。同时手工编写高性能图像处理程序开发效率较低,难以快速构建大量高性能图像处理代码。 在这样的背景下,MIT的研究人员专门为图像处理设计了一种程序语言——Halid... 阅读详情

相关推荐

Halide编译安装与基本数据结构

Overview Halide是为了在现代计算机上编写更高性能的图像处理代码而设计的一种编程语言。目前只吃的目标为: CPU架构:X86, ARM, MIPS, Hexagon, PowerPC 操作系统:Linux, Windows, macOS, Andriod, IOS, Qualcomm QuRT GPU计算API: CUDA,OpenGL, OpenCL, Apple Metal, Microsoft Direction X 12 Halide不是独立的一种编程语言,而是嵌入在C++中,这

亦梦云烟的博客 1745

Halide示例学习二

Halide的调度实操以及说明

Pengcode的博客 587

windows安装Halide

https://github.com/halide/Halide/releases 下载Halide压缩包,解压 添加环境变量,C:\Opencv3.4\halide\Debug;C:\Opencv3.4\halide\Release ①Linker>general>Adiditional Library Directories release C:\lib\halide\Releas...

勉強 1711

Halide示例学习一

Halide示例学习一示例学习基本变量和概念操控图片操作debug操作1 示例学习 基本变量和概念 // 使用Halide,我们只需要包含Halide.h这个头文件就可以了 #include "Halide.h" #include <stdio.h> int main(int argc, char **argv) { // Halide::Func代表了一个计算图,代表了每一个像素值需要进行的计算操作 Halide::Func gradient; // Halide::

Pengcode的博客 763

使用Halide后端提高OpenCV效率的方法

通过上述步骤,我们成功地在OpenCV中启用了Halide后端,并使用Halide后端进行了高斯滤波操作。通过上述步骤,我们成功地在OpenCV中启用了Halide后端,并使用Halide后端进行了高斯滤波操作。通过使用Halide后端,你可以进一步优化和并行化你的图像处理算法,以实现更高的性能。通过使用Halide后端,你可以进一步优化和并行化你的图像处理算法,以实现更高的性能。要启用OpenCV的Halide后端,首先确保已经正确安装了OpenCV和Halide,并配置了正确的编译环境。

PixelNovaO的博客 314

OpenCV如何启用Halide后端以提高效率

OpenCV如何启用Halide后端以提高效率如何启用Halide后端以提高效率介绍要求LLVM编译器Halide语言使用Halide后端构建OpenCV将Halide设置为首选后端 如何启用Halide后端以提高效率 介绍 本教程指导如何使用Halide语言后端在OpenCV深度学习模块中运行模型。Halide是一个开源项目,可以让我们以易于阅读的格式编写图像处理算法,根据特定设备安排计算时间,并以相当高的效率对其进行评估。 要求 LLVM编译器 LLVM编译可能需要很长时间。 从http://relea

希望我的博客,能帮上你解决学习中工作中所遇到的问题 1006

Halide 初步使用

最近开始使用Halide做点事情,说找点资料,结果网上基本都是翻译下官方教程,还得自己摸索。 Halide的目的是更方便地做优化,即不牺牲代码可读性的情况下利用硬件加速代码执行。更详细的说明参考原始论文。这里直接说怎么上手的事情。 Halide的文档确实不如OpenCV,这就是差距吧。就比如说,首先应当介绍下核心的数据结构以及围绕这些数据结构有哪些关键API,《Learning OpenCV》这方面就做得比较好。所以 这篇文章大致按照这个套路来,而不是上来就直奔有哪些优化操作。 看了Tutorial的第一个

haithink的专栏 1630

ALTERA MAX10 FPGA 串口远程升级实战:从原理到烧录的避坑指南

本文详细解析了ALTERA MAX10 FPGA如何通过串口实现远程升级。文章从工程师实战经验出发,深入剖析了MAX10片内Flash的双镜像备份原理、CONFIG_SEL引脚启动机制,并重点介绍了使用On-Chip Flash IP核进行擦写操作的核心流程。同时,提供了从Quartus工程配置、RPD文件生成、串口协议设计到驱动代码编写的完整避坑指南,旨在帮助开发者稳定、高效地完成远程升级功能部署。

weixin_29197699的博客 273

Halide入门教程第2讲:处理图像

// Halide tutorial lesson 2: Processing images // Halide入门教程第二讲:处理图像 // This lesson demonstrates how to pass in input images and manipulate them. // 本课说明了如何读入及处理图像 // On linux, you can compile and ...

tbzj_2000的博客 2814

深入解析.Net中SM2与sm-crypto的跨平台加解密实践

本文深入探讨了在.Net平台与前端sm-crypto库之间实现SM2国密算法跨平台加解密的实践方案。针对对接中常见的密钥格式、密文拼接顺序(C1C3C2与C1C2C3)等核心难点,提供了基于BouncyCastle的完整工具类实现、前后端联调示例及问题排查指南,旨在帮助开发者构建安全、兼容的数据加密通道。

weixin_29322855的博客 369

【一键搞定】ThinkPHP6.0.2+PHPStudy+Composer极速安装指南——附完整下载包与避坑技巧

本文提供了一份ThinkPHP6.0.2的完整下载包,并详细介绍了如何配合PHPStudy和Composer进行极速安装与配置。指南涵盖了环境准备、Composer国内镜像加速、项目部署及常见避坑技巧,旨在帮助开发者,尤其是内网或网络不佳的用户,快速搭建可运行的TP6开发环境,绕过依赖下载的繁琐步骤。

assembly8low的博客 1006

Halide学习笔记--02--input image

准备 **接上一文, 开始学习lesson_02_input_image** 问题 前面配置好了环境, 直接上手撸代码......撸着, 撸着发现问题: //问题一: 缺少头文件 #include "halide_image_io.h" //这个头是哪里的, 好像不对 ... //问题二:缺少数据 Halide::Buffer<uint8_t> input = load_image("images/rgb.png"); //这里需要数据 ~配置Halide头文件的时候添加一项: --

weixin_45331269的博客 359

c++11 无锁队列

/************************************************************************* &gt; File Name: lockfreequeue.cpp &gt; Author: &gt; Mail: &gt; Created Time: Wed 08 Aug 2018 11:38:08 AM CST ********...

qq_35728402的博客 5021

Halide学习

目的:在现代机器上完成高性能的图像处理。 编译器目标:x86/SSE, ARM V7/NEON, CUDA, Native Client, OpenCL, and Metal. 大致流程:用Halide::Var, Halide::Expr, Halide::Func类型的对象完成c++程序,然后调用Halide::Func::compile_to_file来生成对象文件和头文件。或者调用Halide::Func::realize即时编译(JIT)并即刻运行整套pipeline,这有利于测试小的程序。

u011994454的博客 742

YOLO11改进 | 注意力机制 | 添加SimAM注意力机制【全网独家+附完整代码】

yolo11,yolo11改进,yolo11创新,yolo11添加注意力机制

kay_545 1229

AMD SDP 优快云 系列文章设计

摘要 本文档规划了7篇AMD SDP协议解析系列文章的技术博客设计方案。基于《Scalable Data Port (SDP) Specification》1.5.0版本(122页),面向SoC/NoC领域的RTL设计与验证工程师,构建从基础概念到验证实现的知识体系。 系列文章严格遵循协议规范边界,采用五类证据标签区分内容来源(规范原文、勘误、验证推导等),禁止补充未定义的实现细节。包含端口控制、事务传输、一致性协议等核心内容,最终落实到验证平台设计与覆盖率模型。 每篇文章采用统一模板:明确规范依据、问题导

元直的博客 160

为Halide安装opencl支持

打开TargetOpenCL开关,我们可以看到使用opencl进行推理的时候,计算时调用的openclapi是如何的。展示的测速结果如下所示,这里可以看出来,虽然都是使用了cpu进行计算,但是还是intel-cpu-opencl速度更快些。compile_jit进行处理操作。查看主机平台支持的设备平台。设置kernel参数。...

Pengcode的博客 715

RK3576 Buildroot 双机 ADB 异常排障实录:同版 `boot.img`,一台可识别一台不可识别

进程在跑”不等于“USB 枚举成功”,adbd存活只是必要不充分条件。生产环境中的全局别名可能反向污染系统脚本。shell 命令替换中的字符串问题,必须做字节级验证(od -tx1相比“改环境规避”,核心脚本对输入做鲁棒处理更可长期维护。

小灰灰的博客 210

Halide示例学习五

Halide示例学习四函数重定义操作RDom下标使用使用RDom计算直方图调度函数更新多阶段重定义操作使用归化函数进行模糊操作内置的归化函数sum使用归约函数的一个复杂例子 函数重定义操作 #include "Halide.h" #include <stdio.h> using namespace Halide; int main(int argc, char **argv) { Var x("x"), y("y"); Buffer<uint8_t> input

Pengcode的博客 520

基于Simulink的PMSM轮毂电机崎岖路面悬架协同控制仿真

本文完成了基于Simulink的PMSM轮毂电机崎岖路面悬架协同控制仿真,实现了:✅ 构建了四轮独立驱动+主动悬架高保真整车模型✅ 实现了Skyhook主动悬架控制✅ 设计了驱动-悬架状态共享与协同决策机制✅ 验证了5 m/s高速下连续颠簸路面稳定通过能力✅ 为高性能移动机器人提供一体化底盘解决方案。

xiaoheshang_123的博客 190

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

Halide示例学习三

Halide示例学习三改变维度遍历起点多计算图组合示例 改变维度遍历起点 #include "Halide.h" #include <stdio.h> using namespace Halide; int main(int argc, char **argv) { Func gradient("gradient"); Var x("x"), y("y"); gradient(x, y) = x + y; gradient.trace_stores();

Pengcode的博客 296

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

Halide源码编译

Halide源码编译Halide为何要源码编译?源码编译LLVM库源码编译Halide测试Halide是否编译成功生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建一个自定义列表如何创建一个注脚注释也是必不可少的KaTeX数学公式新的甘特图功能,丰富你的文章UML 图表FLowchart流程图导出与导入导出导入 Halide   Halide 算是一种编程模式,主要用于在现代机器上来进行高性能的图像和数组处理。其寄生在C++编程语言中,作为DSL编程语言(特定域语言)来实现高

Pengcode的博客 1942

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

华为的C语言编程规范.pdf

华为技术有限公司内部技术规范。本规范制定了编写C语言程序的基本原则、规则和建议。从代码的清晰、简洁、可测试、安全、程序效率、可移植各个方面对C语言编程作出了具体指导。

(深度学习优化大师)TVM的前辈,介绍下什么是HALIDE

在开始学习之前推荐大家可以多在FlyAI竞赛服务平台多参加训练和竞赛,以此来提升自己的能力。FlyAI是为AI开发者提供数据竞赛并支持GPU离线训练的一站式服务平台。每周免费提供项目开源算法样例,支持算法能力变现以及快速的迭代算法模型。 前言 前几天又用到了TVM,想着是否能够间接替代TensorRT作为GPU服务器部署的一个后端。TensorRT在自家的GPU上确实强大,也是老黄家重点关照的”开源项目“。但TensorRT还是有一点点小缺点的: 经过infer优化后的模型与特定GPU绑定,...

iFlyAI的博客 3284

如何为 Halide 后端安排网络

介绍我们使用的每台设备都是一样的卤化物代码。但是为了达到令人满意的效率,我们应该正确地安排计算。在本教程中,我们将介绍在 OpenCV 深度学习模块中使用 Halide 后端调度网络的方法。为了更好地理解 Halide 调度,您可能需要阅读教程 @。如果这是你第一次在 OpenCV 中与 Halide 会面,我们建议从开始。配置文件您可以通过编写文本配置文件来计划卤化物管道的计算。这意味着您可以轻松地矢量化、并行化和管理层计算的循环顺序。

2301_81888214的博客 927

Halide编程

免责申明:本文所用的材料来自于网络,仅供个人学习和交流之用。如果用作其他用途,那么请自行承担法律负责。 Halide是一种特定领域的编程语言(DSL),专门用于加速图像处理,当前已支持x86 SSE,ARM v7 NEON,CUDA,OpenCL等。Halide的主要特点在于分开算法描述和调度描述。一个算法的Halide算法描述不依赖于硬件,其调度描述使用并行化、向量化(SIMD指令)和处理本地化(block)等函数(为便于表述,本文使用了原语),通过这些原语的某种特定组合,使得算法描述可在选定的硬件计算平

serpentine的博客 633

快速入门Halide

Halide代码流程: 声明函数,变量,表达式 用变量、表达式等实现算法 使用调度策略对算法进行调度调优 调用函数的realize成员函数,对函数进行实现 写出数据 example 1: Halide::Func gradient; // Func对象表示了一个pipeline阶段。它是一个纯函数,定义了每个像素点对应的值。 Halide::Var x, y; // Var对象是Func的定义域,或者说是Func的参数。它们本身没有任何意义。Var用来索引 Halide::Expr e = x

Time_remember的专栏 1290
上一篇: halide调度过程可视化工具
下一篇: Halide示例学习五
慷仔
博客等级 码龄9年 88粉丝 46原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值