循环

循环 - 23

版本

  • 名称: 循环 (GitHub)

  • : main

  • 自版本: 23

  • 函数: False

  • 支持级别: SupportType.COMMON

  • 形状推断: True

此版本的运算符自版本 23起可用。

摘要

通用循环结构。此循环具有多个终止条件。

  1. 循环次数。在运行时指定的迭代次数。通过指定输入 M 来设置。可选。设置为空字符串以省略。请注意,可以通过为输入 M 传递一个常量节点来指定静态循环次数(在图构建时指定)。

  2. 循环终止条件。这是确定是否运行第一次迭代以及循环携带依赖项的运算符的输入。主体图必须为条件变量生成一个值,无论是否提供此输入。

此表总结了此运算符的操作模式以及等效的 C 样式代码。

运算符输入定义为 (max_trip_count, condition_var)。

  • 输入 (“”, “”): for (int i=0; ; ++i) { cond = … // 注意此值被忽略,但在主体中是必需的 }

  • 输入 (“”, cond) // 注意这类似于 while 循环 bool cond = …; for (int i=0; cond; ++i) { cond = …; }

  • 输入 (“”, 1) // 注意这类似于 do-while 循环 bool cond = true for (int i=0; cond; ++i) { cond = …; }

  • 输入 (trip_count, “”) // 注意这类似于 for 循环 int trip_count = … for (int i=0; i < trip_count; ++i) { cond = …; // 被忽略 }

  • 输入 (trip_count, cond) int trip_count = …; bool cond = …; for (int i=0; i < trip_count && cond; ++i) { cond = …; }

示例用法 - cond 和循环次数

graph predict-net {
  %a = Constant[value = <Scalar Tensor [3]>]()
  %b = Constant[value = <Scalar Tensor [6]>]()
  %keepgoing = Constant[value = <Scalar Tensor [1]>]()
  %max_trip_count = Constant[value = <Scalar Tensor [10]>]()
  %keepgoing_out, %b_out, %user_defined_vals = Loop[body = <graph body-net>](%max_trip_count, %keepgoing, %b)
  return
}

graph body-net (
  %i[INT32, scalar]           // iteration number
  %keepgoing_in[BOOL, scalar] // incoming loop-termination-condition; not used
  %b_in[INT32, scalar]        // incoming value of loop-carried-dependency b
) {
  %my_local = Add(%a, %b_in)
  %b_out = Sub(%a, %b_in) // outgoing value of loop-carried-dependency b
  %keepgoing_out = Greater(%my_local, %b_out) // outgoing loop-termination-condition
  %user_defined_val = Add(%b_in, %b_in) // scan-output value to be accumulated
  return %keepgoing_out, %b_out, %user_defined_val
}

示例等效 C 代码

{
  /* User-defined code (enclosing scope) */
  int a = 3, b = 6;
  bool keepgoing = true; // Analogous to input cond
  /* End user-defined code */

  /* Implicitly-defined code */
  const int max_trip_count = 10; // Analogous to input M
  int user_defined_vals[]; // Imagine this is resizable
  /* End implicitly-defined code */
  /* initialize loop-carried variables and scan-output variables */
  bool keepgoing_out = keepgoing
  int b_out = b

  for (int i=0; i < max_trip_count && keepgoing_out; ++i) {
    /* Implicitly-defined code: bind actual parameter values
       to formal parameter variables of loop-body */
    bool keepgoing_in = keepgoing_out;
    bool b_in = b_out;

    /* User-defined code (loop body) */
    int my_local = a + b_in; // Reading value "a" from the enclosing scope is fine
    b_out = a - b_in;
    keepgoing_out = my_local > b_out;
    user_defined_val = b_in + b_in; // b_in and b_out are different variables
    /* End user-defined code */

    /* Implicitly defined-code */
    user_defined_vals[i] = user_defined_val // accumulate scan-output values
  }
  // int t = my_local; // Can't do this. my_local is not accessible here.

  // The values below are bound to the output variables of the loop and therefore accessible
  // b_out; user_defined_vals; keepgoing_out;
}

此代码片段中需要注意几点。

  1. 来自封闭作用域的值(例如,此处的变量“a”)在作用域内,可以在循环的输入中引用。

  2. 在循环主体中计算的任何需要在后续迭代或循环结束后使用,都使用循环主体中的一对变量建模,该对变量由输入变量(例如,b_in)和输出变量(例如,b_out)组成。这些称为循环携带依赖项。循环运算符节点为第一次迭代提供输入变量的输入值,并返回最后一次迭代产生的输出变量的输出值。

  3. Scan_output 变量用于隐式连接跨所有迭代计算的值。在上面的示例中,在所有迭代中计算的 user_defined_val 的值被连接起来,并在循环结束后作为 user_defined_vals 的值返回。

  4. 在主体中创建的值无法在封闭作用域中访问,除非使用上面描述的机制。

请注意,此运算符的语义支持“对角线”或“波前”执行。(有关示例,请参阅此处的步骤 3:https://devblogs.nvidia.com/optimizing-recurrent-neural-networks-cudnn-5/)。前端应将多层 RNN 发射为一系列 While 运算符(其中时间是内部循环维度),其中每个后续层都使用前一层中的 scan_outputs,可能经过几个逐点运算符(例如,dropout、残差连接、线性层)。

子图(由循环节点生成)输入/输出匹配基于顺序而不是名称。实现将根据此顺序确定名称。

属性

  • body - 图(必需)

    每次迭代运行的图。它有 2+N 个输入:(iteration_num,condition,loop carried dependencies…)。它有 1+N+K 个输出:(condition,loop carried dependencies…,scan_outputs…)。每个 scan_output 通过连接循环每次迭代结束时指定输出值的来创建。如果这些 scan_outputs 的维度或数据类型在循环迭代中发生变化,则会发生错误。

输入

2 到 2147483647 个输入。

  • M(可选,异构) - I

    在运行时指定的循环的最大循环次数。可选。传递空字符串以跳过。

  • cond(可选,异构) - B

    布尔终止条件。可选。传递空字符串以跳过。

  • v_initial(可变) - V

    任何循环携带依赖项(跨循环迭代变化的值)的初始值。

输出

1 到 2147483647 个输出。

  • v_final_and_scan_outputs(可变) - V

    最终 N 个循环携带依赖项值,然后是 K 个 scan_outputs。Scan 输出必须是张量。

类型约束

  • V 的类型为 ( optional(seq(tensor(bfloat16))), optional(seq(tensor(bool))), optional(seq(tensor(complex128))), optional(seq(tensor(complex64))), optional(seq(tensor(double))), optional(seq(tensor(float))), optional(seq(tensor(float16))), optional(seq(tensor(int16))), optional(seq(tensor(int32))), optional(seq(tensor(int64))), optional(seq(tensor(int8))), optional(seq(tensor(string))), optional(seq(tensor(uint16))), optional(seq(tensor(uint32))), optional(seq(tensor(uint64))), optional(seq(tensor(uint8))), optional(tensor(bfloat16)), optional(tensor(bool)), optional(tensor(complex128)), optional(tensor(complex64)), optional(tensor(double)), optional(tensor(float)), optional(tensor(float16)), optional(tensor(float4e2m1)), optional(tensor(float8e4m3fn)), optional(tensor(float8e4m3fnuz)), optional(tensor(float8e5m2)), optional(tensor(float8e5m2fnuz)), optional(tensor(int16)), optional(tensor(int32)), optional(tensor(int4)), optional(tensor(int64)), optional(tensor(int8)), optional(tensor(string)), optional(tensor(uint16)), optional(tensor(uint32)), optional(tensor(uint4)), optional(tensor(uint64)), optional(tensor(uint8)), seq(tensor(bfloat16)), seq(tensor(bool)), seq(tensor(complex128)), seq(tensor(complex64)), seq(tensor(double)), seq(tensor(float)), seq(tensor(float16)), seq(tensor(float4e2m1)), seq(tensor(float8e4m3fn)), seq(tensor(float8e4m3fnuz)), seq(tensor(float8e5m2)), seq(tensor(float8e5m2fnuz)), seq(tensor(int16)), seq(tensor(int32)), seq(tensor(int4)), seq(tensor(int64)), seq(tensor(int8)), seq(tensor(string)), seq(tensor(uint16)), seq(tensor(uint32)), seq(tensor(uint4)), seq(tensor(uint64)), seq(tensor(uint8)), tensor(bfloat16), tensor(bool), tensor(complex128), tensor(complex64), tensor(double), tensor(float), tensor(float16), tensor(float4e2m1), tensor(float8e4m3fn), tensor(float8e4m3fnuz), tensor(float8e5m2), tensor(float8e5m2fnuz), tensor(int16), tensor(int32), tensor(int4), tensor(int64), tensor(int8), tensor(string), tensor(uint16), tensor(uint32), tensor(uint4), tensor(uint64), tensor(uint8) )

    所有张量(Tensor)、张量序列(Sequence(Tensor))、可选张量(Optional(Tensor))和可选张量序列(Optional(Sequence(Tensor)))类型,最高支持到 IRv11 版本。

  • I 的类型为 ( tensor(int64) )

    int64 类型的张量,应为标量。

  • B 的类型为 ( tensor(bool) )

    bool 类型的张量,应为标量。

循环 - 21

版本

  • 名称: 循环 (GitHub)

  • : main

  • since_version: 21

  • 函数: False

  • 支持级别: SupportType.COMMON

  • 形状推断: True

该操作符的此版本自 **版本 21** 起可用。

摘要

通用循环结构。此循环具有多个终止条件。

  1. 循环次数。在运行时指定的迭代次数。通过指定输入 M 来设置。可选。设置为空字符串以省略。请注意,可以通过为输入 M 传递一个常量节点来指定静态循环次数(在图构建时指定)。

  2. 循环终止条件。这是确定是否运行第一次迭代以及循环携带依赖项的运算符的输入。主体图必须为条件变量生成一个值,无论是否提供此输入。

此表总结了此运算符的操作模式以及等效的 C 样式代码。

运算符输入定义为 (max_trip_count, condition_var)。

  • 输入 (“”, “”): for (int i=0; ; ++i) { cond = … // 注意此值被忽略,但在主体中是必需的 }

  • 输入 (“”, cond) // 注意这类似于 while 循环 bool cond = …; for (int i=0; cond; ++i) { cond = …; }

  • 输入 (“”, 1) // 注意这类似于 do-while 循环 bool cond = true for (int i=0; cond; ++i) { cond = …; }

  • 输入 (trip_count, “”) // 注意这类似于 for 循环 int trip_count = … for (int i=0; i < trip_count; ++i) { cond = …; // 被忽略 }

  • 输入 (trip_count, cond) int trip_count = …; bool cond = …; for (int i=0; i < trip_count && cond; ++i) { cond = …; }

示例用法 - cond 和循环次数

graph predict-net {
  %a = Constant[value = <Scalar Tensor [3]>]()
  %b = Constant[value = <Scalar Tensor [6]>]()
  %keepgoing = Constant[value = <Scalar Tensor [1]>]()
  %max_trip_count = Constant[value = <Scalar Tensor [10]>]()
  %keepgoing_out, %b_out, %user_defined_vals = Loop[body = <graph body-net>](%max_trip_count, %keepgoing, %b)
  return
}

graph body-net (
  %i[INT32, scalar]           // iteration number
  %keepgoing_in[BOOL, scalar] // incoming loop-termination-condition; not used
  %b_in[INT32, scalar]        // incoming value of loop-carried-dependency b
) {
  %my_local = Add(%a, %b_in)
  %b_out = Sub(%a, %b_in) // outgoing value of loop-carried-dependency b
  %keepgoing_out = Greater(%my_local, %b_out) // outgoing loop-termination-condition
  %user_defined_val = Add(%b_in, %b_in) // scan-output value to be accumulated
  return %keepgoing_out, %b_out, %user_defined_val
}

示例等效 C 代码

{
  /* User-defined code (enclosing scope) */
  int a = 3, b = 6;
  bool keepgoing = true; // Analogous to input cond
  /* End user-defined code */

  /* Implicitly-defined code */
  const int max_trip_count = 10; // Analogous to input M
  int user_defined_vals[]; // Imagine this is resizable
  /* End implicitly-defined code */
  /* initialize loop-carried variables and scan-output variables */
  bool keepgoing_out = keepgoing
  int b_out = b

  for (int i=0; i < max_trip_count && keepgoing_out; ++i) {
    /* Implicitly-defined code: bind actual parameter values
       to formal parameter variables of loop-body */
    bool keepgoing_in = keepgoing_out;
    bool b_in = b_out;

    /* User-defined code (loop body) */
    int my_local = a + b_in; // Reading value "a" from the enclosing scope is fine
    b_out = a - b_in;
    keepgoing_out = my_local > b_out;
    user_defined_val = b_in + b_in; // b_in and b_out are different variables
    /* End user-defined code */

    /* Implicitly defined-code */
    user_defined_vals[i] = user_defined_val // accumulate scan-output values
  }
  // int t = my_local; // Can't do this. my_local is not accessible here.

  // The values below are bound to the output variables of the loop and therefore accessible
  // b_out; user_defined_vals; keepgoing_out;
}

此代码片段中需要注意几点。

  1. 来自封闭作用域的值(例如,此处的变量“a”)在作用域内,可以在循环的输入中引用。

  2. 在循环主体中计算的任何需要在后续迭代或循环结束后使用,都使用循环主体中的一对变量建模,该对变量由输入变量(例如,b_in)和输出变量(例如,b_out)组成。这些称为循环携带依赖项。循环运算符节点为第一次迭代提供输入变量的输入值,并返回最后一次迭代产生的输出变量的输出值。

  3. Scan_output 变量用于隐式连接跨所有迭代计算的值。在上面的示例中,在所有迭代中计算的 user_defined_val 的值被连接起来,并在循环结束后作为 user_defined_vals 的值返回。

  4. 在主体中创建的值无法在封闭作用域中访问,除非使用上面描述的机制。

请注意,此运算符的语义支持“对角线”或“波前”执行。(有关示例,请参阅此处的步骤 3:https://devblogs.nvidia.com/optimizing-recurrent-neural-networks-cudnn-5/)。前端应将多层 RNN 发射为一系列 While 运算符(其中时间是内部循环维度),其中每个后续层都使用前一层中的 scan_outputs,可能经过几个逐点运算符(例如,dropout、残差连接、线性层)。

子图(由循环节点生成)输入/输出匹配基于顺序而不是名称。实现将根据此顺序确定名称。

属性

  • body - 图(必需)

    每次迭代运行的图。它有 2+N 个输入:(iteration_num,condition,loop carried dependencies…)。它有 1+N+K 个输出:(condition,loop carried dependencies…,scan_outputs…)。每个 scan_output 通过连接循环每次迭代结束时指定输出值的来创建。如果这些 scan_outputs 的维度或数据类型在循环迭代中发生变化,则会发生错误。

输入

2 到 2147483647 个输入。

  • M(可选,异构) - I

    在运行时指定的循环的最大循环次数。可选。传递空字符串以跳过。

  • cond(可选,异构) - B

    布尔终止条件。可选。传递空字符串以跳过。

  • v_initial(可变) - V

    任何循环携带依赖项(跨循环迭代变化的值)的初始值。

输出

1 到 2147483647 个输出。

  • v_final_and_scan_outputs(可变) - V

    最终 N 个循环携带依赖项值,然后是 K 个 scan_outputs。Scan 输出必须是张量。

类型约束

  • V ∈ ( optional(seq(tensor(bfloat16))), optional(seq(tensor(bool))), optional(seq(tensor(complex128))), optional(seq(tensor(complex64))), optional(seq(tensor(double))), optional(seq(tensor(float))), optional(seq(tensor(float16))), optional(seq(tensor(int16))), optional(seq(tensor(int32))), optional(seq(tensor(int64))), optional(seq(tensor(int8))), optional(seq(tensor(string))), optional(seq(tensor(uint16))), optional(seq(tensor(uint32))), optional(seq(tensor(uint64))), optional(seq(tensor(uint8))), optional(tensor(bfloat16)), optional(tensor(bool)), optional(tensor(complex128)), optional(tensor(complex64)), optional(tensor(double)), optional(tensor(float)), optional(tensor(float16)), optional(tensor(float8e4m3fn)), optional(tensor(float8e4m3fnuz)), optional(tensor(float8e5m2)), optional(tensor(float8e5m2fnuz)), optional(tensor(int16)), optional(tensor(int32)), optional(tensor(int4)), optional(tensor(int64)), optional(tensor(int8)), optional(tensor(string)), optional(tensor(uint16)), optional(tensor(uint32)), optional(tensor(uint4)), optional(tensor(uint64)), optional(tensor(uint8)), seq(tensor(bfloat16)), seq(tensor(bool)), seq(tensor(complex128)), seq(tensor(complex64)), seq(tensor(double)), seq(tensor(float)), seq(tensor(float16)), seq(tensor(float8e4m3fn)), seq(tensor(float8e4m3fnuz)), seq(tensor(float8e5m2)), seq(tensor(float8e5m2fnuz)), seq(tensor(int16)), seq(tensor(int32)), seq(tensor(int4)), seq(tensor(int64)), seq(tensor(int8)), seq(tensor(string)), seq(tensor(uint16)), seq(tensor(uint32)), seq(tensor(uint4)), seq(tensor(uint64)), seq(tensor(uint8)), tensor(bfloat16), tensor(bool), tensor(complex128), tensor(complex64), tensor(double), tensor(float), tensor(float16), tensor(float8e4m3fn), tensor(float8e4m3fnuz), tensor(float8e5m2), tensor(float8e5m2fnuz), tensor(int16), tensor(int32), tensor(int4), tensor(int64), tensor(int8), tensor(string), tensor(uint16), tensor(uint32), tensor(uint4), tensor(uint64), tensor(uint8) )

    IRv10 版本之前的所有 Tensor、Sequence(Tensor)、Optional(Tensor) 和 Optional(Sequence(Tensor)) 类型。

  • I 的类型为 ( tensor(int64) )

    int64 类型的张量,应为标量。

  • B 的类型为 ( tensor(bool) )

    bool 类型的张量,应为标量。

循环 - 19

版本

  • 名称: 循环 (GitHub)

  • : main

  • since_version: 19

  • 函数: False

  • 支持级别: SupportType.COMMON

  • 形状推断: True

此运算符版本自 **版本 19** 起可用。

摘要

通用循环结构。此循环具有多个终止条件。

  1. 循环次数。在运行时指定的迭代次数。通过指定输入 M 来设置。可选。设置为空字符串以省略。请注意,可以通过为输入 M 传递一个常量节点来指定静态循环次数(在图构建时指定)。

  2. 循环终止条件。这是确定是否运行第一次迭代以及循环携带依赖项的运算符的输入。主体图必须为条件变量生成一个值,无论是否提供此输入。

此表总结了此运算符的操作模式以及等效的 C 样式代码。

运算符输入定义为 (max_trip_count, condition_var)。

  • 输入 (“”, “”): for (int i=0; ; ++i) { cond = … // 注意此值被忽略,但在主体中是必需的 }

  • 输入 (“”, cond) // 注意这类似于 while 循环 bool cond = …; for (int i=0; cond; ++i) { cond = …; }

  • 输入 (“”, 1) // 注意这类似于 do-while 循环 bool cond = true for (int i=0; cond; ++i) { cond = …; }

  • 输入 (trip_count, “”) // 注意这类似于 for 循环 int trip_count = … for (int i=0; i < trip_count; ++i) { cond = …; // 被忽略 }

  • 输入 (trip_count, cond) int trip_count = …; bool cond = …; for (int i=0; i < trip_count && cond; ++i) { cond = …; }

示例用法 - cond 和循环次数

graph predict-net {
  %a = Constant[value = <Scalar Tensor [3]>]()
  %b = Constant[value = <Scalar Tensor [6]>]()
  %keepgoing = Constant[value = <Scalar Tensor [1]>]()
  %max_trip_count = Constant[value = <Scalar Tensor [10]>]()
  %keepgoing_out, %b_out, %user_defined_vals = Loop[body = <graph body-net>](%max_trip_count, %keepgoing, %b)
  return
}

graph body-net (
  %i[INT32, scalar]           // iteration number
  %keepgoing_in[BOOL, scalar] // incoming loop-termination-condition; not used
  %b_in[INT32, scalar]        // incoming value of loop-carried-dependency b
) {
  %my_local = Add(%a, %b_in)
  %b_out = Sub(%a, %b_in) // outgoing value of loop-carried-dependency b
  %keepgoing_out = Greater(%my_local, %b_out) // outgoing loop-termination-condition
  %user_defined_val = Add(%b_in, %b_in) // scan-output value to be accumulated
  return %keepgoing_out, %b_out, %user_defined_val
}

示例等效 C 代码

{
  /* User-defined code (enclosing scope) */
  int a = 3, b = 6;
  bool keepgoing = true; // Analogous to input cond
  /* End user-defined code */

  /* Implicitly-defined code */
  const int max_trip_count = 10; // Analogous to input M
  int user_defined_vals[]; // Imagine this is resizable
  /* End implicitly-defined code */
  /* initialize loop-carried variables and scan-output variables */
  bool keepgoing_out = keepgoing
  int b_out = b

  for (int i=0; i < max_trip_count && keepgoing_out; ++i) {
    /* Implicitly-defined code: bind actual parameter values
       to formal parameter variables of loop-body */
    bool keepgoing_in = keepgoing_out;
    bool b_in = b_out;

    /* User-defined code (loop body) */
    int my_local = a + b_in; // Reading value "a" from the enclosing scope is fine
    b_out = a - b_in;
    keepgoing_out = my_local > b_out;
    user_defined_val = b_in + b_in; // b_in and b_out are different variables
    /* End user-defined code */

    /* Implicitly defined-code */
    user_defined_vals[i] = user_defined_val // accumulate scan-output values
  }
  // int t = my_local; // Can't do this. my_local is not accessible here.

  // The values below are bound to the output variables of the loop and therefore accessible
  // b_out; user_defined_vals; keepgoing_out;
}

此代码片段中需要注意几点。

  1. 来自封闭作用域的值(例如,此处的变量“a”)在作用域内,可以在循环的输入中引用。

  2. 在循环主体中计算的任何需要在后续迭代或循环结束后使用,都使用循环主体中的一对变量建模,该对变量由输入变量(例如,b_in)和输出变量(例如,b_out)组成。这些称为循环携带依赖项。循环运算符节点为第一次迭代提供输入变量的输入值,并返回最后一次迭代产生的输出变量的输出值。

  3. Scan_output 变量用于隐式连接跨所有迭代计算的值。在上面的示例中,在所有迭代中计算的 user_defined_val 的值被连接起来,并在循环结束后作为 user_defined_vals 的值返回。

  4. 在主体中创建的值无法在封闭作用域中访问,除非使用上面描述的机制。

请注意,此运算符的语义支持“对角线”或“波前”执行。(有关示例,请参阅此处的步骤 3:https://devblogs.nvidia.com/optimizing-recurrent-neural-networks-cudnn-5/)。前端应将多层 RNN 发射为一系列 While 运算符(其中时间是内部循环维度),其中每个后续层都使用前一层中的 scan_outputs,可能经过几个逐点运算符(例如,dropout、残差连接、线性层)。

子图(由循环节点生成)输入/输出匹配基于顺序而不是名称。实现将根据此顺序确定名称。

属性

  • body - 图(必需)

    每次迭代运行的图。它有 2+N 个输入:(iteration_num,condition,loop carried dependencies…)。它有 1+N+K 个输出:(condition,loop carried dependencies…,scan_outputs…)。每个 scan_output 通过连接循环每次迭代结束时指定输出值的来创建。如果这些 scan_outputs 的维度或数据类型在循环迭代中发生变化,则会发生错误。

输入

2 到 2147483647 个输入。

  • M(可选,异构) - I

    在运行时指定的循环的最大循环次数。可选。传递空字符串以跳过。

  • cond(可选,异构) - B

    布尔终止条件。可选。传递空字符串以跳过。

  • v_initial(可变) - V

    任何循环携带依赖项(跨循环迭代变化的值)的初始值。

输出

1 到 2147483647 个输出。

  • v_final_and_scan_outputs(可变) - V

    最终 N 个循环携带依赖项值,然后是 K 个 scan_outputs。Scan 输出必须是张量。

类型约束

  • V ∈ ( optional(seq(tensor(bfloat16))), optional(seq(tensor(bool))), optional(seq(tensor(complex128))), optional(seq(tensor(complex64))), optional(seq(tensor(double))), optional(seq(tensor(float))), optional(seq(tensor(float16))), optional(seq(tensor(int16))), optional(seq(tensor(int32))), optional(seq(tensor(int64))), optional(seq(tensor(int8))), optional(seq(tensor(string))), optional(seq(tensor(uint16))), optional(seq(tensor(uint32))), optional(seq(tensor(uint64))), optional(seq(tensor(uint8))), optional(tensor(bfloat16)), optional(tensor(bool)), optional(tensor(complex128)), optional(tensor(complex64)), optional(tensor(double)), optional(tensor(float)), optional(tensor(float16)), optional(tensor(float8e4m3fn)), optional(tensor(float8e4m3fnuz)), optional(tensor(float8e5m2)), optional(tensor(float8e5m2fnuz)), optional(tensor(int16)), optional(tensor(int32)), optional(tensor(int64)), optional(tensor(int8)), optional(tensor(string)), optional(tensor(uint16)), optional(tensor(uint32)), optional(tensor(uint64)), optional(tensor(uint8)), seq(tensor(bfloat16)), seq(tensor(bool)), seq(tensor(complex128)), seq(tensor(complex64)), seq(tensor(double)), seq(tensor(float)), seq(tensor(float16)), seq(tensor(float8e4m3fn)), seq(tensor(float8e4m3fnuz)), seq(tensor(float8e5m2)), seq(tensor(float8e5m2fnuz)), seq(tensor(int16)), seq(tensor(int32)), seq(tensor(int64)), seq(tensor(int8)), seq(tensor(string)), seq(tensor(uint16)), seq(tensor(uint32)), seq(tensor(uint64)), seq(tensor(uint8)), tensor(bfloat16), tensor(bool), tensor(complex128), tensor(complex64), tensor(double), tensor(float), tensor(float16), tensor(float8e4m3fn), tensor(float8e4m3fnuz), tensor(float8e5m2), tensor(float8e5m2fnuz), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(string), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8) )

    IRv9 版本之前的所有 Tensor、Sequence(Tensor)、Optional(Tensor) 和 Optional(Sequence(Tensor)) 类型。

  • I 的类型为 ( tensor(int64) )

    int64 类型的张量,应为标量。

  • B 的类型为 ( tensor(bool) )

    bool 类型的张量,应为标量。

循环 - 16

版本

  • 名称: 循环 (GitHub)

  • : main

  • since_version: 16

  • 函数: False

  • 支持级别: SupportType.COMMON

  • 形状推断: True

此运算符版本自 **版本 16** 起可用。

摘要

通用循环结构。此循环具有多个终止条件。

  1. 循环次数。在运行时指定的迭代次数。通过指定输入 M 来设置。可选。设置为空字符串以省略。请注意,可以通过为输入 M 传递一个常量节点来指定静态循环次数(在图构建时指定)。

  2. 循环终止条件。这是确定是否运行第一次迭代以及循环携带依赖项的运算符的输入。主体图必须为条件变量生成一个值,无论是否提供此输入。

此表总结了此运算符的操作模式以及等效的 C 样式代码。

运算符输入定义为 (max_trip_count, condition_var)。

  • 输入 (“”, “”): for (int i=0; ; ++i) { cond = … // 注意此值被忽略,但在主体中是必需的 }

  • 输入 (“”, cond) // 注意这类似于 while 循环 bool cond = …; for (int i=0; cond; ++i) { cond = …; }

  • 输入 (“”, 1) // 注意这类似于 do-while 循环 bool cond = true for (int i=0; cond; ++i) { cond = …; }

  • 输入 (trip_count, “”) // 注意这类似于 for 循环 int trip_count = … for (int i=0; i < trip_count; ++i) { cond = …; // 被忽略 }

  • 输入 (trip_count, cond) int trip_count = …; bool cond = …; for (int i=0; i < trip_count && cond; ++i) { cond = …; }

示例用法 - cond 和循环次数

graph predict-net {
  %a = Constant[value = <Scalar Tensor [3]>]()
  %b = Constant[value = <Scalar Tensor [6]>]()
  %keepgoing = Constant[value = <Scalar Tensor [1]>]()
  %max_trip_count = Constant[value = <Scalar Tensor [10]>]()
  %keepgoing_out, %b_out, %user_defined_vals = Loop[body = <graph body-net>](%max_trip_count, %keepgoing, %b)
  return
}

graph body-net (
  %i[INT32, scalar]           // iteration number
  %keepgoing_in[BOOL, scalar] // incoming loop-termination-condition; not used
  %b_in[INT32, scalar]        // incoming value of loop-carried-dependency b
) {
  %my_local = Add(%a, %b_in)
  %b_out = Sub(%a, %b_in) // outgoing value of loop-carried-dependency b
  %keepgoing_out = Greater(%my_local, %b_out) // outgoing loop-termination-condition
  %user_defined_val = Add(%b_in, %b_in) // scan-output value to be accumulated
  return %keepgoing_out, %b_out, %user_defined_val
}

示例等效 C 代码

{
  /* User-defined code (enclosing scope) */
  int a = 3, b = 6;
  bool keepgoing = true; // Analogous to input cond
  /* End user-defined code */

  /* Implicitly-defined code */
  const int max_trip_count = 10; // Analogous to input M
  int user_defined_vals[]; // Imagine this is resizable
  /* End implicitly-defined code */
  /* initialize loop-carried variables and scan-output variables */
  bool keepgoing_out = keepgoing
  int b_out = b

  for (int i=0; i < max_trip_count && keepgoing_out; ++i) {
    /* Implicitly-defined code: bind actual parameter values
       to formal parameter variables of loop-body */
    bool keepgoing_in = keepgoing_out;
    bool b_in = b_out;

    /* User-defined code (loop body) */
    int my_local = a + b_in; // Reading value "a" from the enclosing scope is fine
    b_out = a - b_in;
    keepgoing_out = my_local > b_out;
    user_defined_val = b_in + b_in; // b_in and b_out are different variables
    /* End user-defined code */

    /* Implicitly defined-code */
    user_defined_vals[i] = user_defined_val // accumulate scan-output values
  }
  // int t = my_local; // Can't do this. my_local is not accessible here.

  // The values below are bound to the output variables of the loop and therefore accessible
  // b_out; user_defined_vals; keepgoing_out;
}

此代码片段中需要注意几点。

  1. 来自封闭作用域的值(例如,此处的变量“a”)在作用域内,可以在循环的输入中引用。

  2. 在循环主体中计算的任何需要在后续迭代或循环结束后使用,都使用循环主体中的一对变量建模,该对变量由输入变量(例如,b_in)和输出变量(例如,b_out)组成。这些称为循环携带依赖项。循环运算符节点为第一次迭代提供输入变量的输入值,并返回最后一次迭代产生的输出变量的输出值。

  3. Scan_output 变量用于隐式连接跨所有迭代计算的值。在上面的示例中,在所有迭代中计算的 user_defined_val 的值被连接起来,并在循环结束后作为 user_defined_vals 的值返回。

  4. 在主体中创建的值无法在封闭作用域中访问,除非使用上面描述的机制。

请注意,此运算符的语义支持“对角线”或“波前”执行。(有关示例,请参阅此处的步骤 3:https://devblogs.nvidia.com/optimizing-recurrent-neural-networks-cudnn-5/)。前端应将多层 RNN 发射为一系列 While 运算符(其中时间是内部循环维度),其中每个后续层都使用前一层中的 scan_outputs,可能经过几个逐点运算符(例如,dropout、残差连接、线性层)。

子图(由循环节点生成)输入/输出匹配基于顺序而不是名称。实现将根据此顺序确定名称。

属性

  • body - 图(必需)

    每次迭代运行的图。它有 2+N 个输入:(iteration_num,condition,loop carried dependencies…)。它有 1+N+K 个输出:(condition,loop carried dependencies…,scan_outputs…)。每个 scan_output 通过连接循环每次迭代结束时指定输出值的来创建。如果这些 scan_outputs 的维度或数据类型在循环迭代中发生变化,则会发生错误。

输入

2 到 2147483647 个输入。

  • M(可选,异构) - I

    在运行时指定的循环的最大循环次数。可选。传递空字符串以跳过。

  • cond(可选,异构) - B

    布尔终止条件。可选。传递空字符串以跳过。

  • v_initial(可变) - V

    任何循环携带依赖项(跨循环迭代变化的值)的初始值。

输出

1 到 2147483647 个输出。

  • v_final_and_scan_outputs(可变) - V

    最终 N 个循环携带依赖项值,然后是 K 个 scan_outputs。Scan 输出必须是张量。

类型约束

  • V 的类型可以是 ( optional(seq(tensor(bfloat16))), optional(seq(tensor(bool))), optional(seq(tensor(complex128))), optional(seq(tensor(complex64))), optional(seq(tensor(double))), optional(seq(tensor(float))), optional(seq(tensor(float16))), optional(seq(tensor(int16))), optional(seq(tensor(int32))), optional(seq(tensor(int64))), optional(seq(tensor(int8))), optional(seq(tensor(string))), optional(seq(tensor(uint16))), optional(seq(tensor(uint32))), optional(seq(tensor(uint64))), optional(seq(tensor(uint8))), optional(tensor(bfloat16)), optional(tensor(bool)), optional(tensor(complex128)), optional(tensor(complex64)), optional(tensor(double)), optional(tensor(float)), optional(tensor(float16)), optional(tensor(int16)), optional(tensor(int32)), optional(tensor(int64)), optional(tensor(int8)), optional(tensor(string)), optional(tensor(uint16)), optional(tensor(uint32)), optional(tensor(uint64)), optional(tensor(uint8)), seq(tensor(bfloat16)), seq(tensor(bool)), seq(tensor(complex128)), seq(tensor(complex64)), seq(tensor(double)), seq(tensor(float)), seq(tensor(float16)), seq(tensor(int16)), seq(tensor(int32)), seq(tensor(int64)), seq(tensor(int8)), seq(tensor(string)), seq(tensor(uint16)), seq(tensor(uint32)), seq(tensor(uint64)), seq(tensor(uint8)), tensor(bfloat16), tensor(bool), tensor(complex128), tensor(complex64), tensor(double), tensor(float), tensor(float16), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(string), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8) )

    在 IRv4 之前,所有 Tensor、Sequence(Tensor)、Optional(Tensor) 和 Optional(Sequence(Tensor)) 类型。

  • I 的类型为 ( tensor(int64) )

    int64 类型的张量,应为标量。

  • B 的类型为 ( tensor(bool) )

    bool 类型的张量,应为标量。

循环 - 13

版本

  • 名称: 循环 (GitHub)

  • : main

  • since_version: 13

  • 函数: False

  • 支持级别: SupportType.COMMON

  • 形状推断: True

此运算符版本自版本 13起可用。

摘要

通用循环结构。此循环具有多个终止条件。

  1. 循环次数。在运行时指定的迭代次数。通过指定输入 M 来设置。可选。设置为空字符串以省略。请注意,可以通过为输入 M 传递一个常量节点来指定静态循环次数(在图构建时指定)。

  2. 循环终止条件。这是确定是否运行第一次迭代以及循环携带依赖项的运算符的输入。主体图必须为条件变量生成一个值,无论是否提供此输入。

此表总结了此运算符的操作模式以及等效的 C 样式代码。

Operator inputs defined as (max_trip_count, condition_var).

input ("", ""):
    for (int i=0; ; ++i) {
      cond = ... // Note this value is ignored, but is required in the body
    }

input ("", cond) // Note this is analogous to a while loop
    bool cond = ...;
    for (int i=0; cond; ++i) {
      cond = ...;
    }

input ("", 1) // Note this is analogous to a do-while loop
    bool cond = true
    for (int i=0; cond; ++i) {
      cond = ...;
    }

input (trip_count, "") // Note this is analogous to a for loop
    int trip_count = ...
    for (int i=0; i < trip_count; ++i) {
      cond = ...; // ignored
    }

input (trip_count, cond)
    int trip_count = ...;
    bool cond = ...;
    for (int i=0; i < trip_count && cond; ++i) {
      cond = ...;
    }

示例用法 - cond 和循环次数

graph predict-net {
  %a = Constant[value = <Scalar Tensor [3]>]()
  %b = Constant[value = <Scalar Tensor [6]>]()
  %keepgoing = Constant[value = <Scalar Tensor [1]>]()
  %max_trip_count = Constant[value = <Scalar Tensor [10]>]()
  %keepgoing_out, %b_out, %user_defined_vals = Loop[body = <graph body-net>](%max_trip_count, %keepgoing, %b)
  return
}

graph body-net (
  %i[INT32, scalar]           // iteration number
  %keepgoing_in[BOOL, scalar] // incoming loop-termination-condition; not used
  %b_in[INT32, scalar]        // incoming value of loop-carried-dependency b
) {
  %my_local = Add(%a, %b_in)
  %b_out = Sub(%a, %b_in) // outgoing value of loop-carried-dependency b
  %keepgoing_out = Greater(%my_local, %b_out) // outgoing loop-termination-condition
  %user_defined_val = Add(%b_in, %b_in) // scan-output value to be accumulated
  return %keepgoing_out, %b_out, %user_defined_val
}

示例等效 C 代码

{
  /* User-defined code (enclosing scope) */
  int a = 3, b = 6;
  bool keepgoing = true; // Analogous to input cond
  /* End user-defined code */

  /* Implicitly-defined code */
  const int max_trip_count = 10; // Analogous to input M
  int user_defined_vals[]; // Imagine this is resizable
  /* End implicitly-defined code */
  /* initialize loop-carried variables and scan-output variables */
  bool keepgoing_out = keepgoing
  int b_out = b

  for (int i=0; i < max_trip_count && keepgoing_out; ++i) {
    /* Implicitly-defined code: bind actual parameter values
       to formal parameter variables of loop-body */
    bool keepgoing_in = keepgoing_out;
    bool b_in = b_out;

    /* User-defined code (loop body) */
    int my_local = a + b_in; // Reading value "a" from the enclosing scope is fine
    b_out = a - b_in;
    keepgoing_out = my_local > b_out;
    user_defined_val = b_in + b_in; // b_in and b_out are different variables
    /* End user-defined code */

    /* Implicitly defined-code */
    user_defined_vals[i] = user_defined_val // accumulate scan-output values
  }
  // int t = my_local; // Can't do this. my_local is not accessible here.

  // The values below are bound to the output variables of the loop and therefore accessible
  // b_out; user_defined_vals; keepgoing_out;
}

此代码片段中需要注意几点。

  1. 来自封闭作用域的值(例如,此处的变量“a”)在作用域内,可以在循环的输入中引用。

  2. 在循环主体中计算的任何需要在后续迭代或循环结束后使用,都使用循环主体中的一对变量建模,该对变量由输入变量(例如,b_in)和输出变量(例如,b_out)组成。这些称为循环携带依赖项。循环运算符节点为第一次迭代提供输入变量的输入值,并返回最后一次迭代产生的输出变量的输出值。

  3. Scan_output 变量用于隐式连接跨所有迭代计算的值。在上面的示例中,在所有迭代中计算的 user_defined_val 的值被连接起来,并在循环结束后作为 user_defined_vals 的值返回。

  4. 在主体中创建的值无法在封闭作用域中访问,除非使用上面描述的机制。

请注意,此运算符的语义支持“对角线”或“波前”执行。(有关示例,请参阅此处的步骤 3:https://devblogs.nvidia.com/optimizing-recurrent-neural-networks-cudnn-5/)。前端应将多层 RNN 发射为一系列 While 运算符(其中时间是内部循环维度),其中每个后续层都使用前一层中的 scan_outputs,可能经过几个逐点运算符(例如,dropout、残差连接、线性层)。

子图(由循环节点生成)输入/输出匹配基于顺序而不是名称。实现将根据此顺序确定名称。

属性

  • body - 图(必需)

    每次迭代运行的图。它有 2+N 个输入:(iteration_num,condition,loop carried dependencies…)。它有 1+N+K 个输出:(condition,loop carried dependencies…,scan_outputs…)。每个 scan_output 通过连接循环每次迭代结束时指定输出值的来创建。如果这些 scan_outputs 的维度或数据类型在循环迭代中发生变化,则会发生错误。

输入

2 到 2147483647 个输入。

  • M(可选,异构) - I

    在运行时指定的循环的最大循环次数。可选。传递空字符串以跳过。

  • cond(可选,异构) - B

    布尔终止条件。可选。传递空字符串以跳过。

  • v_initial(可变) - V

    任何循环携带依赖项(跨循环迭代变化的值)的初始值。

输出

1 到 2147483647 个输出。

  • v_final_and_scan_outputs(可变) - V

    最终 N 个循环携带依赖项值,然后是 K 个 scan_outputs。Scan 输出必须是张量。

类型约束

  • V 的类型可以是 ( seq(tensor(bool)), seq(tensor(complex128)), seq(tensor(complex64)), seq(tensor(double)), seq(tensor(float)), seq(tensor(float16)), seq(tensor(int16)), seq(tensor(int32)), seq(tensor(int64)), seq(tensor(int8)), seq(tensor(string)), seq(tensor(uint16)), seq(tensor(uint32)), seq(tensor(uint64)), seq(tensor(uint8)), tensor(bool), tensor(complex128), tensor(complex64), tensor(double), tensor(float), tensor(float16), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(string), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8) )

    所有 Tensor 和 Sequence 类型

  • I 的类型为 ( tensor(int64) )

    int64 类型的张量,应为标量。

  • B 的类型为 ( tensor(bool) )

    bool 类型的张量,应为标量。

循环 - 11

版本

  • 名称: 循环 (GitHub)

  • : main

  • since_version: 11

  • 函数: False

  • 支持级别: SupportType.COMMON

  • 形状推断: True

此运算符版本自版本 11起可用。

摘要

通用循环结构。此循环具有多个终止条件。

  1. 循环次数。在运行时指定的迭代次数。通过指定输入 M 来设置。可选。设置为空字符串以省略。请注意,可以通过为输入 M 传递一个常量节点来指定静态循环次数(在图构建时指定)。

  2. 循环终止条件。这是确定是否运行第一次迭代以及循环携带依赖项的运算符的输入。主体图必须为条件变量生成一个值,无论是否提供此输入。

此表总结了此运算符的操作模式以及等效的 C 样式代码。

Operator inputs defined as (max_trip_count, condition_var).

input ("", ""):
    for (int i=0; ; ++i) {
      cond = ... // Note this value is ignored, but is required in the body
    }

input ("", cond) // Note this is analogous to a while loop
    bool cond = ...;
    for (int i=0; cond; ++i) {
      cond = ...;
    }

input ("", 1) // Note this is analogous to a do-while loop
    bool cond = true
    for (int i=0; cond; ++i) {
      cond = ...;
    }

input (trip_count, "") // Note this is analogous to a for loop
    int trip_count = ...
    for (int i=0; i < trip_count; ++i) {
      cond = ...; // ignored
    }

input (trip_count, cond)
    int trip_count = ...;
    bool cond = ...;
    for (int i=0; i < trip_count && cond; ++i) {
      cond = ...;
    }

示例用法 - cond 和循环次数

graph predict-net {
  %a = Constant[value = <Scalar Tensor [3]>]()
  %b = Constant[value = <Scalar Tensor [6]>]()
  %keepgoing = Constant[value = <Scalar Tensor [1]>]()
  %max_trip_count = Constant[value = <Scalar Tensor [10]>]()
  %keepgoing_out, %b_out, %user_defined_vals = Loop[body = <graph body-net>](%max_trip_count, %keepgoing, %b)
  return
}

graph body-net (
  %i[INT32, scalar]           // iteration number
  %keepgoing_in[BOOL, scalar] // incoming loop-termination-condition; not used
  %b_in[INT32, scalar]        // incoming value of loop-carried-dependency b
) {
  %my_local = Add(%a, %b_in)
  %b_out = Sub(%a, %b_in) // outgoing value of loop-carried-dependency b
  %keepgoing_out = Greater(%my_local, %b_out) // outgoing loop-termination-condition
  %user_defined_val = Add(%b_in, %b_in) // scan-output value to be accumulated
  return %keepgoing_out, %b_out, %user_defined_val
}

示例等效 C 代码

{
  /* User-defined code (enclosing scope) */
  int a = 3, b = 6;
  bool keepgoing = true; // Analogous to input cond
  /* End user-defined code */

  /* Implicitly-defined code */
  const int max_trip_count = 10; // Analogous to input M
  int user_defined_vals[]; // Imagine this is resizable
  /* End implicitly-defined code */
  /* initialize loop-carried variables and scan-output variables */
  bool keepgoing_out = keepgoing
  int b_out = b

  for (int i=0; i < max_trip_count && keepgoing_out; ++i) {
    /* Implicitly-defined code: bind actual parameter values
       to formal parameter variables of loop-body */
    bool keepgoing_in = keepgoing_out;
    bool b_in = b_out;

    /* User-defined code (loop body) */
    int my_local = a + b_in; // Reading value "a" from the enclosing scope is fine
    b_out = a - b_in;
    keepgoing_out = my_local > b_out;
    user_defined_val = b_in + b_in; // b_in and b_out are different variables
    /* End user-defined code */

    /* Implicitly defined-code */
    user_defined_vals[i] = user_defined_val // accumulate scan-output values
  }
  // int t = my_local; // Can't do this. my_local is not accessible here.

  // The values below are bound to the output variables of the loop and therefore accessible
  // b_out; user_defined_vals; keepgoing_out;
}

此代码片段中需要注意几点。

  1. 来自封闭作用域的值(例如,此处的变量“a”)在作用域内,可以在循环的输入中引用。

  2. 在循环主体中计算的任何需要在后续迭代或循环结束后使用,都使用循环主体中的一对变量建模,该对变量由输入变量(例如,b_in)和输出变量(例如,b_out)组成。这些称为循环携带依赖项。循环运算符节点为第一次迭代提供输入变量的输入值,并返回最后一次迭代产生的输出变量的输出值。

  3. Scan_output 变量用于隐式连接跨所有迭代计算的值。在上面的示例中,在所有迭代中计算的 user_defined_val 的值被连接起来,并在循环结束后作为 user_defined_vals 的值返回。

  4. 在主体中创建的值无法在封闭作用域中访问,除非使用上面描述的机制。

请注意,此运算符的语义支持“对角线”或“波前”执行。(有关示例,请参阅此处的步骤 3:https://devblogs.nvidia.com/optimizing-recurrent-neural-networks-cudnn-5/)。前端应将多层 RNN 发射为一系列 While 运算符(其中时间是内部循环维度),其中每个后续层都使用前一层中的 scan_outputs,可能经过几个逐点运算符(例如,dropout、残差连接、线性层)。

属性

  • body - 图(必需)

    每次迭代运行的图。它有 2+N 个输入:(iteration_num,condition,loop carried dependencies…)。它有 1+N+K 个输出:(condition,loop carried dependencies…,scan_outputs…)。每个 scan_output 通过连接循环每次迭代结束时指定输出值的来创建。如果这些 scan_outputs 的维度或数据类型在循环迭代中发生变化,则会发生错误。

输入

2 到 2147483647 个输入。

  • M(可选,异构) - I

    在运行时指定的循环的最大循环次数。可选。传递空字符串以跳过。

  • cond(可选,异构) - B

    布尔终止条件。可选。传递空字符串以跳过。

  • v_initial(可变) - V

    任何循环携带依赖项(跨循环迭代变化的值)的初始值。

输出

1 到 2147483647 个输出。

  • v_final_and_scan_outputs(可变) - V

    最终 N 个循环携带的依赖项值,然后是 K 个 scan_outputs。

类型约束

  • V 的类型可以是 ( tensor(bool), tensor(complex128), tensor(complex64), tensor(double), tensor(float), tensor(float16), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(string), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8) )

    所有 Tensor 类型

  • I 的类型为 ( tensor(int64) )

    int64 类型的张量,应为标量。

  • B 的类型为 ( tensor(bool) )

    bool 类型的张量,应为标量。

循环 - 1

版本

  • 名称: 循环 (GitHub)

  • : main

  • since_version: 1

  • 函数: False

  • 支持级别: SupportType.COMMON

  • 形状推断: True

此运算符版本自版本 1起可用。

摘要

通用循环结构。此循环具有多个终止条件。

  1. 循环次数。在运行时指定的迭代次数。通过指定输入 M 来设置。可选。设置为空字符串以省略。请注意,可以通过为输入 M 传递一个常量节点来指定静态循环次数(在图构建时指定)。

  2. 循环终止条件。这是确定是否运行第一次迭代以及循环携带依赖项的运算符的输入。主体图必须为条件变量生成一个值,无论是否提供此输入。

此表总结了此运算符的操作模式以及等效的 C 样式代码。

Operator inputs defined as (max_trip_count, condition_var).

input ("", ""):
    for (int i=0; ; ++i) {
      cond = ... // Note this value is ignored, but is required in the body
    }

input ("", cond) // Note this is analogous to a while loop
    bool cond = ...;
    for (int i=0; cond; ++i) {
      cond = ...;
    }

input ("", 1) // Note this is analogous to a do-while loop
    bool cond = true
    for (int i=0; cond; ++i) {
      cond = ...;
    }

input (trip_count, "") // Note this is analogous to a for loop
    int trip_count = ...
    for (int i=0; i < trip_count; ++i) {
      cond = ...; // ignored
    }

input (trip_count, cond)
    int trip_count = ...;
    bool cond = ...;
    for (int i=0; i < trip_count && cond; ++i) {
      cond = ...;
    }

示例用法 - cond 和循环次数

graph predict-net {
  %a = Constant[value = <Scalar Tensor [3]>]()
  %b = Constant[value = <Scalar Tensor [6]>]()
  %keepgoing = Constant[value = <Scalar Tensor [1]>]()
  %max_trip_count = Constant[value = <Scalar Tensor [10]>]()
  %keepgoing_out, %b_out, %user_defined_vals = Loop[body = <graph body-net>](%max_trip_count, %keepgoing, %b)
  return
}

graph body-net (
  %i[INT32, scalar]
  %keepgoing[BOOL, scalar]
  %b[INT32, scalar]
) {
  %my_local = Add(%a, %b)
  %b_out = Sub(%a, %b)
  %keepgoing_out = Greater(%my_local, %b_out)
  %user_defined_vals = Add(%b, %b)
  return %keepgoing_out, %b_out, %user_defined_vals
}

示例等效 C 代码

{
  /* User-defined code (enclosing scope) */
  int a = 3, b = 6;
  bool keepgoing = true; // Analogous to input cond
  /* End user-defined code */

  /* Implicitly-defined code */
  const int max_trip_count = 10; // Analogous to input M
  int user_defined_vals[]; // Imagine this is resizable
  /* End implicitly-defined code */
  for (int i=0; i < max_trip_count && keepgoing; ++i) {
    /* User-defined code (loop body) */
    int my_local = a + b; // Reading values in the enclosing scope is fine
    b = a - b; // writes fine if we specify b as a loop-carried dependency
    keepgoing = my_local > b; // keepgoing is a loop-carried dependency
    user_defined_vals[i] = b + b;
    /* End user-defined code */
  }
  // my_local = 123; // Can't do this. my_local was defined in the body

  // These below values are live-out from the loop and therefore accessible
  b_out; user_defined_vals; keepgoing_out;
}

此代码片段中需要注意几点。

  1. 来自封闭作用域的值(例如,此处的变量 a)在作用域内,可以在循环的输入中引用。

  2. 您希望在封闭作用域中可用的任何变量(例如,变量 b 和 keepgoing)必须声明为循环携带的依赖项(在运算符输入和输出以及主体网络输入和输出处)或 scan_outputs。

  3. 主体中创建的值无法在封闭作用域中访问。

请注意,此运算符的语义支持“对角线”或“波前”执行。(有关示例,请参阅此处的步骤 3:https://devblogs.nvidia.com/optimizing-recurrent-neural-networks-cudnn-5/)。前端应将多层 RNN 发射为一系列 While 运算符(其中时间是内部循环维度),其中每个后续层都使用前一层中的 scan_outputs,可能经过几个逐点运算符(例如,dropout、残差连接、线性层)。

属性

  • body - 图(必需)

    每次迭代运行的图。它有 2+N 个输入:(iteration_num,condition,loop carried dependencies…)。它有 1+N+K 个输出:(condition,loop carried dependencies…,scan_outputs…)。每个 scan_output 通过连接循环每次迭代结束时指定输出值的来创建。如果这些 scan_outputs 的维度或数据类型在循环迭代中发生变化,则会发生错误。

输入

3 到 2147483647 个输入之间。

  • M(可选,异构) - I

    在运行时指定的循环的最大循环次数。可选。传递空字符串以跳过。

  • cond(可选,异构) - B

    布尔终止条件。可选。传递空字符串以跳过。

  • v_initial(可变) - V

    任何循环携带依赖项(跨循环迭代变化的值)的初始值。

输出

1 到 2147483647 个输出。

  • v_final_and_scan_outputs(可变) - V

    最终 N 个循环携带的依赖项值,然后是 K 个 scan_outputs。

类型约束

  • V 的类型可以是 ( tensor(bool), tensor(complex128), tensor(complex64), tensor(double), tensor(float), tensor(float16), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(string), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8) )

    所有 Tensor 类型

  • I 的类型为 ( tensor(int64) )

    int64 类型的张量,应为标量。

  • B 的类型为 ( tensor(bool) )

    bool 类型的张量,应为标量。