在kernel中使用half类型可以在牺牲一定精度的代价下来提升运算速度. 在kernel中, 可以比较方便的对half数据进行计算, 但在host上的, 对half的使用就没那么方便了. 查看cl_float的定义:typedef uint16_t cl_half __attribute__((aligned(2)));可知其本质是一个uint16_t. 所以, 如果直接拿cl_float的内存的值来使用的话, 系统会把它当做一个uint16_t来解析. 一般来说, 我们遇到最多的情况可能是在kernel中保为half, 然后把该内存数据复制到host, 然后在host中使用. 关于half和float的转换, 主要有如下几个方面值得注意.

使用vstore_half和vload_half

OpenCL 1.1文档中是这么说的:

Loads from a pointer to a half and stores to a pointer to a half can be performed using the **vload_half, vload_halfn, vloada_halfn and vstore_half, vstore_halfn, vstorea_halfn **functions

respectively as described in section 6.11.7. The load functions read scalar or vector half values

from memory and convert them to a scalar or vector float value. The store functions take a

scalar or vector float value as input, convert it to a half scalar or vector value (with appropriate

rounding mode) and write the half scalar or vector value to memory

函数申明如下: vector类型类似

  1. float vload_half (size_t offset, const __global half *p);
  2. void vstore_half (float data, size_t offset, __global half *p);

可以知道, load时接受的half的内存数据, 然后vload_half会自动把他们变成float. store时接手的float数据, 然后vstore_half会自动把float数据变成half类型数据写入内存.

使用read_imageh和write_imageh

来看定义:

  1. half4 read_imageh (image2d_t image, sampler_t sampler, int2 coord);
  2. half4 read_imageh (image2d_t image, sampler_t sampler, float2 coord);
  3. void write_imageh (image2d_t image, int2 coord, half4 color);

其中, 对于read_iamgeh, 其返回值与image2d_t的image_channel_data_type类型有关:

image_channel_data_type 返回值
CL_UNORM_INT8,or CL_UNORM_INT16 [0.0 , 1.0]
CL_SNORM_INT8, or CL_SNORM_INT16 [-1.0, 1.0]
CL_HALF_FLOAT half精度的值

如果image2d_t的类型定义不是表格中所表示的类型, 那么read的返回值将是undefined. 同理, write写入的iamge对象也只能是定义为表格中类型.

在host中进行float和half的转换

我们前面说到在host中, half实际是按照一个unit16_t来存储, 所以我们肯定需要一个算法或者规则来解析其内存数据, 得到我们想要的half-float值. 幸好, 我在高通的opencl sdk中找到了转换方法, 大家可去下载, 贴出代码如下:

  1. //--------------------------------------------------------------------------------------
  2. // File: half_float.cpp
  3. // Desc:
  4. //
  5. // Author: QUALCOMM
  6. //
  7. // Copyright (c) 2018 QUALCOMM Technologies, Inc.
  8. // All Rights Reserved.
  9. // QUALCOMM Proprietary/GTDR
  10. //--------------------------------------------------------------------------------------
  11. #include "half_float.h"
  12. #include <cmath>
  13. #include <limits>
  14. cl_half to_half(float f)
  15. {
  16. static const struct
  17. {
  18. unsigned int bit_size = 16; // total number of bits in the representation
  19. unsigned int num_frac_bits = 10; // number of fractional (mantissa) bits
  20. unsigned int num_exp_bits = 5; // number of (biased) exponent bits
  21. unsigned int sign_bit = 15; // position of the sign bit
  22. unsigned int sign_mask = 1 << 15; // mask to extract sign bit
  23. unsigned int frac_mask = (1 << 10) - 1; // mask to extract the fractional (mantissa) bits
  24. unsigned int exp_mask = ((1 << 5) - 1) << 10; // mask to extract the exponent bits
  25. unsigned int e_max = (1 << (5 - 1)) - 1; // max value for the exponent
  26. int e_min = -((1 << (5 - 1)) - 1) + 1; // min value for the exponent
  27. unsigned int max_normal = ((((1 << (5 - 1)) - 1) + 127) << 23) | 0x7FE000; // max value that can be represented by the 16 bit float
  28. unsigned int min_normal = ((-((1 << (5 - 1)) - 1) + 1) + 127) << 23; // min value that can be represented by the 16 bit float
  29. unsigned int bias_diff = ((unsigned int)(((1 << (5 - 1)) - 1) - 127) << 23); // difference in bias between the float16 and float32 exponent
  30. unsigned int frac_bits_diff = 23 - 10; // difference in number of fractional bits between float16/float32
  31. } float16_params;
  32. static const struct
  33. {
  34. unsigned int abs_value_mask = 0x7FFFFFFF; // ANDing with this value gives the abs value
  35. unsigned int sign_bit_mask = 0x80000000; // ANDing with this value gives the sign
  36. unsigned int e_max = 127; // max value for the exponent
  37. unsigned int num_mantissa_bits = 23; // 23 bit mantissa on single precision floats
  38. unsigned int mantissa_mask = 0x007FFFFF; // 23 bit mantissa on single precision floats
  39. } float32_params;
  40. const union
  41. {
  42. float f;
  43. unsigned int bits;
  44. } value = {f};
  45. const unsigned int f_abs_bits = value.bits & float32_params.abs_value_mask;
  46. const bool is_neg = value.bits & float32_params.sign_bit_mask;
  47. const unsigned int sign = (value.bits & float32_params.sign_bit_mask) >> (float16_params.num_frac_bits + float16_params.num_exp_bits + 1);
  48. cl_half half = 0;
  49. if (std::isnan(value.f))
  50. {
  51. half = float16_params.exp_mask | float16_params.frac_mask;
  52. }
  53. else if (std::isinf(value.f))
  54. {
  55. half = is_neg ? float16_params.sign_mask | float16_params.exp_mask : float16_params.exp_mask;
  56. }
  57. else if (f_abs_bits > float16_params.max_normal)
  58. {
  59. // Clamp to max float 16 value
  60. half = sign | (((1 << float16_params.num_exp_bits) - 1) << float16_params.num_frac_bits) | float16_params.frac_mask;
  61. }
  62. else if (f_abs_bits < float16_params.min_normal)
  63. {
  64. const unsigned int frac_bits = (f_abs_bits & float32_params.mantissa_mask) | (1 << float32_params.num_mantissa_bits);
  65. const int nshift = float16_params.e_min + float32_params.e_max - (f_abs_bits >> float32_params.num_mantissa_bits);
  66. const unsigned int shifted_bits = nshift < 24 ? frac_bits >> nshift : 0;
  67. half = sign | (shifted_bits >> float16_params.frac_bits_diff);
  68. }
  69. else
  70. {
  71. half = sign | ((f_abs_bits + float16_params.bias_diff) >> float16_params.frac_bits_diff);
  72. }
  73. return half;
  74. }
  75. cl_float to_float(cl_half f)
  76. {
  77. static const struct {
  78. uint16_t sign_mask = 0x8000;
  79. uint16_t exp_mask = 0x7C00;
  80. int exp_bias = 15;
  81. int exp_offset = 10;
  82. uint16_t biased_exp_max = (1 << 5) - 1;
  83. uint16_t frac_mask = 0x03FF;
  84. float smallest_subnormal_as_float = 5.96046448e-8f;
  85. } float16_params;
  86. static const struct {
  87. int sign_offset = 31;
  88. int exp_bias = 127;
  89. int exp_offset = 23;
  90. } float32_params;
  91. const bool is_pos = (f & float16_params.sign_mask) == 0;
  92. const uint32_t biased_exponent = (f & float16_params.exp_mask) >> float16_params.exp_offset;
  93. const uint32_t frac = (f & float16_params.frac_mask);
  94. const bool is_inf = biased_exponent == float16_params.biased_exp_max
  95. && (frac == 0);
  96. if (is_inf)
  97. {
  98. return is_pos ? std::numeric_limits<float>::infinity() : -std::numeric_limits<float>::infinity();
  99. }
  100. const bool is_nan = biased_exponent == float16_params.biased_exp_max
  101. && (frac != 0);
  102. if (is_nan)
  103. {
  104. return std::numeric_limits<float>::quiet_NaN();
  105. }
  106. const bool is_subnormal = biased_exponent == 0;
  107. if (is_subnormal)
  108. {
  109. return static_cast<float>(frac) * float16_params.smallest_subnormal_as_float * (is_pos ? 1.f : -1.f);
  110. }
  111. const int unbiased_exp = static_cast<int>(biased_exponent) - float16_params.exp_bias;
  112. const uint32_t biased_f32_exponent = static_cast<uint32_t>(unbiased_exp + float32_params.exp_bias);
  113. union
  114. {
  115. cl_float f;
  116. uint32_t ui;
  117. } res = {0};
  118. res.ui = (is_pos ? 0 : 1 << float32_params.sign_offset)
  119. | (biased_f32_exponent << float32_params.exp_offset)
  120. | (frac << (float32_params.exp_offset - float16_params.exp_offset));
  121. return res.f;
  122. }

关于转换精度

贴出 一组数据给大家感受下:

  1. //原始float数据
  2. 11.15780, -128.9570, 6.154780, 0.9487320, -1327.1247, 256.0, 0.0, -127.597, 917.0, -1.0047
  3. //to_half然后在to_float的数据
  4. 11.156250 -128.875000 6.152344 0.948730 -1327.000000 256.000000 0.000000 -127.562500 917.000000 -1.003906

根据文档, 在0~2048范围内的整数是可准确表示的. 然后对于浮点数, 精度大概可以形容为百分比的形式, 即如果数本身绝对值大, 那么相差的绝对值也大, 如果本身小, 相差的绝对值也小. 对于常用的图像处理来说, 精度一般是够了.

OpenCL中的half与float的转换的更多相关文章

  1. Java中几种常用数据类型之间转换的方法

    Java中几种常用的数据类型之间转换方法: 1. short-->int 转换 exp: short shortvar=0; int intvar=0; shortvar= (short) in ...

  2. [ios][swift]swift中如果做基本类型的转换

    在swift中如果做基本类型的转换的?比如Int -> Float(Double)Double -> 保留两位小数String -> IntDouble -> String 有 ...

  3. C++中数字与字符串之间的转换 scanf string总结(复习必读)

    1 string的scanf读入操作 C++里面控制台输入直接使用cin操作就可以了:或者getline(istringstream,string); 字符和数字加减就是字符的ASCII码和数字直接加 ...

  4. 对CSS中的Position、Float属性的一些深入探讨

    对CSS中的Position.Float属性的一些深入探讨 对于Position.Float我们在平时使用上可以说是使用频率非常高的两个CSS属性,对于这两个属性的使用上面可能大多数人存在一些模糊与不 ...

  5. SQL中CONVERT日期不同格式的转换用法

    SQL中CONVERT日期不同格式的转换用法 格式: CONVERT(data_type,expression[,style]) 说明:此样式一般在时间类型(datetime,smalldatetim ...

  6. [转]JS中对象与字符串的互相转换

    原文地址:http://www.cnblogs.com/luminji/p/3617160.html 在使用 JSON2.JS 文件的 JSON.parse(data) 方法时候,碰到了问题: thr ...

  7. JS中对象与字符串的互相转换

    在使用 JSON2.JS 文件的 JSON.parse(data) 方法时候,碰到了问题: throw new SyntaxError('JSON.parse'); 查询资料,大概意思如下: JSON ...

  8. 装载:对CSS中的Position、Float属性的一些深入探讨

    对CSS中的Position.Float属性的一些深入探讨   对CSS中的Position.Float属性的一些深入探讨 对于Position.Float我们在平时使用上可以说是使用频率非常高的两个 ...

  9. ACCESS中类型操作(限制、转换)

    ACCESS如何保留两位小数 1.可以通过修改表结构中字段的“小数位数”即可. 2.可以通过“更新查询”,将所有该字段的值更新为round(字段名,2) ACCESS如何转换类型 每个函数都可以强制将 ...

随机推荐

  1. 前端系列——jquery.i18n.properties前端国际化解决方案“填坑日记”

    前言:最近,新的平台还没有开发完成,原来的老项目又提出了新的需求:系统国际化.如果是前后端完全分离的开发模式,要做国际化,真的太简单了,有现成的解决方案,基于Node构建的时下热门的任何一种技术选型都 ...

  2. [Swift]LeetCode61. 旋转链表 | Rotate List

    Given a linked list, rotate the list to the right by k places, where k is non-negative. Example 1: I ...

  3. [Swift]LeetCode664. 奇怪的打印机 | Strange Printer

    There is a strange printer with the following two special requirements: The printer can only print a ...

  4. [Swift]LeetCode768. 最多能完成排序的块 II | Max Chunks To Make Sorted II

    This question is the same as "Max Chunks to Make Sorted" except the integers of the given ...

  5. [Swift]LeetCode970.强整数 | Powerful Integers

    Given two non-negative integers x and y, an integer is powerful if it is equal to x^i + y^j for some ...

  6. SpringCloud微服务架构

    1.Eureka承载大规模系统每天千万级访问的原理 1).首先每个服务的eureka client组件默认30秒发送一个请求到eureka server拉取最近有变化的服务信息: 2).eureka还 ...

  7. Android Hybrid App自动化测试实战讲解(基于python)

    1.Hybrid App自动化测试概要 什么是Hybrid App? Hybrid App(混合模式移动应用)是指介于web-app.native-app这两者之间的app,兼具“Native App ...

  8. 《HelloGitHub月刊》第 10 期

    前言 这一年感谢大家的支持,小弟这里给大家拜年了! <HelloGitHub月刊>会一直做下去,欢迎大家加入进来提供更多的好的项目. 最后,祝愿大家:鸡年大吉- <HelloGitH ...

  9. PyQt:左侧选项卡

    写在前面 正在用pyqt写我们比赛项目的客户端,针对左侧选项卡,写了一个简单的demo.记录一下. 环境 Python3.5.2 PyQt5 陈述 用的结构是左边一个QListWidget + 右边Q ...

  10. C#3.0导航

    C#3.0主要特性 智能的编译器 编译器,背后的默默付出者 Lamdba表达式与表达式树 匿名方法的革命 扩展方法 优雅的对类进扩展 (待完成) LINQ 还有这种操作? (待完成)