扫描

扫描 - 23

版本

  • 名称: Scan (GitHub)

  • 域名: main

  • since_version: 23

  • 函数: False

  • support_level: SupportType.COMMON

  • 形状推断: True

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

摘要

Scan 可用于迭代一个或多个 scan_input 张量,构建零个或多个 scan_output 张量。它结合了来自一般递归、函数式编程结构(如 scan、fold、map 和 zip)的思想,旨在实现对序列到序列处理的类似 RNN 结构的泛化。其他张量(在此称为 state_variables)可用于在从一个元素迭代到另一个元素时携带状态(类似于 RNN 中的隐藏状态,在循环上下文中也称为循环携带依赖)。许多常见用法涉及单个 scan_input 张量(可以获得类似于 scan、fold 和 map 的功能)。当使用多个 scan_input 时,可以获得类似于 zip 的行为。

属性 body 必须是一个图,指定每次迭代中要执行的计算。它以 state_variables 的当前值和 scan_inputs 的当前迭代元素作为输入。它必须返回 state_variables 的(更新)值和零个或多个 scan_output_element 张量。scan_output_element 张量的值在所有迭代中连接起来,生成 scan 结构的 scan_output 值(类似于 RNN 类结构的连接中间隐藏状态值)。所有输出张量(state_variables 以及 scan_output_element 张量)在循环的每次迭代中都必须具有相同的形状(这是为了启用高效内存分配而施加的限制)。

请注意,传递给body子图的迭代元素没有序列轴。它的秩将比相应的scan_input的秩少一。

扫描操作返回state_variables的最终值以及scan_outputs。

可选属性scan_input_directions指定每个扫描输入的方向(向前或向后)。如果省略此属性,所有序列将按向前方向扫描。可以通过在scan_inputs中指定相同的张量输入两次来执行双向扫描,一次为向前方向,一次为向后方向。

操作的scan_output是通过将每次迭代中body生成的scan_output_element值连接起来生成的。可选的属性scan_output_directions指定了每个scan_output的构建方向(通过每次迭代将scan_output_element附加或前置到scan_output中)。如果省略此属性,则每次迭代将scan_output_element附加到scan_output中。

可选属性 scan_input_axes 指定了每个 scan_input 要扫描的轴。 如果省略,每个 scan_input 将在轴 0 上扫描。例如,如果轴 0 是批次轴,轴 1 是时间轴(要扫描的轴),则指定轴值为 1。 请注意,扫描非零轴可能比扫描零轴效率低。

可选属性 scan_output_axes 指定了每个 scan_output 沿哪个轴进行累积。例如,如果轴 1 是输入和输出的时间轴(将被扫描),则指定 scan_input 轴和 scan_output 轴的值为 1。

请注意,由于ONNX限制,只有运算符的最后一个参数可以是可变参数,因此初始状态和扫描输入被列为一个输入参数。同样,最终状态和扫描输出被列为一个输出参数。属性num_scan_inputs表示扫描输入的数量M。

的行为

Scan <
    num_scan_inputs = m,
    body = loop-body,
    scan_input_axes = [axis_1, ..., axis_m]
> (init_1, ..., init_n, scan_1, ..., scan_m)

等同于以下伪代码:

// scan_i.shape[axis_i] denotes the (max) sequence-length of scan_i
// scan_i.shape[axis_i] is required to be equal to scan_j.shape[axis_j] for all i,j.
sequence_length = scan_1.shape[axis_1];

// initialize state-variables
st_1 = init_1; ... st_n = init_n;
// initialize scan-output variables: [] denotes an empty tensor
scan_out_1 = []; ...; scan_out_k = [];
// identify number of iterations:

// execute loop
for (int t = 0; t < sequence_length; ++t) {
    // generate the scan-input elements: the notation T<axis=k>[t] indicates the sub-tensor
    // of rank one less than T obtained by indexing T at position t along axis k.
    si_1 = scan_1<axis=axis_1>[t];
    ... ;
    si_m = scan_m<axis=axis_m>[t];
    // execute loop-body
    st_1, ..., st_n, so_1, ..., so_k = loop-body(st_1, ..., st_n, si_1, ..., si_m)
    // accumulate the scan-output elements
    scan_out_1 = Concat<axis=0>(scan_out_1, so_1); ... ; scan_out_k = Concat<axis=0>(scan_out_k, so_k);
}

return st_1, ..., st_n, scan_out_1, ..., scan_out_k;

示例用法:使用Scan编码RNN

以下示例展示了如何将输入张量 %X、权重张量 %Wi、递归权重张量 %Ri、偏置张量 %Wbi 和 %Rbi 以及初始隐藏状态 %H_0 的简单 RNN 编码为 ScanLoop。请注意,循环体是一个嵌套图,它直接计算

值是在外部图中计算的,它们需要作为额外的state_variables传入。

graph rnn-encoding {
  %H_0 = ...
  %X = ...
  %Y_h, %Y = Scan[body = <graph rnn-cell-1>, num_scan_inputs=1](%H_0, %X)
  return %Y, %Y_h
}

graph rnn-cell-1 (
  %H_tminus1[FLOAT, tensor]
  %X_t[FLOAT, tensor]
) {
  %Wi = ...
  %Ri = ...
  %Wbi = ...
  %Rbi = ...
  %t1 = X_t * (Wi^T)
  %t2 = H_tminus1*(Ri^T)
  %t3 = Add(%t1, %t2)
  %t4 = Add(%t3, %Wbi)
  %t5 = Add(%t4, %Rbi)
  %Ht = Tanh(%t5)
  %Accumulate = Identity(%Ht)
  return %Ht, %Accumulate
}

属性

  • body - GRAPH (必填) :

    图形每次迭代运行。它有N+M个输入:(循环状态变量…,扫描输入元素…)。它有N+K个输出:(循环状态变量…,扫描输出元素…)。每个扫描输出是通过在每次循环迭代结束时连接指定的扫描输出元素值来创建的。如果这些值的维度在循环迭代中发生变化,则会出现错误。

  • num_scan_inputs - INT (必填) :

    一个指定scan_inputs数量M的属性。

  • scan_input_axes - INTS :

    一个可选的M标志列表。列表的第i个元素指定了第i个scan_input要扫描的轴(序列轴)。如果省略,则每个scan_input将使用0作为扫描轴。轴的负值表示从后向前计算维度。接受的范围是[-r, r-1],其中r = rank(input)。

  • scan_input_directions - INTS :

    一个可选的M标志列表。列表的第i个元素指定了第i个scan_input张量的扫描方向:0表示正向,1表示反向。如果省略,所有scan_input张量将按正向扫描。

  • scan_output_axes - INTS :

    一个可选的K标志列表。列表的第i个元素指定了第i个scan_output的轴。扫描输出沿着指定的轴进行累积。如果省略,则每个scan_output将使用0作为扫描轴。轴的负值意味着从后向前计算维度。可接受的范围是[-r, r-1]。

  • scan_output_directions - INTS :

    一个可选的K标志列表,每个scan_output对应一个。列表中的第i个元素指定了第i个scan_output是否应在每次迭代中通过追加或前置一个新值来构建:0表示追加,1表示前置。如果省略,所有scan_output张量将在每次迭代中通过追加一个值来生成。

输入

介于1到2147483647之间的输入。

  • initial_state_and_scan_inputs (可变参数) - V:

    循环的N个状态变量的初始值,后跟M个扫描输入

输出

输出在1到2147483647之间。

  • final_state_and_scan_outputs (可变参数) - V:

    循环的N个状态变量的最终值,后跟K个扫描输出

类型约束

  • V 在 ( 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类型,直到IRv11。

扫描 - 21

版本

  • 名称: Scan (GitHub)

  • 域名: main

  • since_version: 21

  • 函数: False

  • support_level: SupportType.COMMON

  • 形状推断: True

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

摘要

Scan 可用于迭代一个或多个 scan_input 张量,构建零个或多个 scan_output 张量。它结合了来自一般递归、函数式编程结构(如 scan、fold、map 和 zip)的思想,旨在实现对序列到序列处理的类似 RNN 结构的泛化。其他张量(在此称为 state_variables)可用于在从一个元素迭代到另一个元素时携带状态(类似于 RNN 中的隐藏状态,在循环上下文中也称为循环携带依赖)。许多常见用法涉及单个 scan_input 张量(可以获得类似于 scan、fold 和 map 的功能)。当使用多个 scan_input 时,可以获得类似于 zip 的行为。

属性 body 必须是一个图,指定每次迭代中要执行的计算。它以 state_variables 的当前值和 scan_inputs 的当前迭代元素作为输入。它必须返回 state_variables 的(更新)值和零个或多个 scan_output_element 张量。scan_output_element 张量的值在所有迭代中连接起来,生成 scan 结构的 scan_output 值(类似于 RNN 类结构的连接中间隐藏状态值)。所有输出张量(state_variables 以及 scan_output_element 张量)在循环的每次迭代中都必须具有相同的形状(这是为了启用高效内存分配而施加的限制)。

请注意,传递给body子图的迭代元素没有序列轴。它的秩将比相应的scan_input的秩少一。

扫描操作返回state_variables的最终值以及scan_outputs。

可选属性scan_input_directions指定每个扫描输入的方向(向前或向后)。如果省略此属性,所有序列将按向前方向扫描。可以通过在scan_inputs中指定相同的张量输入两次来执行双向扫描,一次为向前方向,一次为向后方向。

操作的scan_output是通过将每次迭代中body生成的scan_output_element值连接起来生成的。可选的属性scan_output_directions指定了每个scan_output的构建方向(通过每次迭代将scan_output_element附加或前置到scan_output中)。如果省略此属性,则每次迭代将scan_output_element附加到scan_output中。

可选属性 scan_input_axes 指定了每个 scan_input 要扫描的轴。 如果省略,每个 scan_input 将在轴 0 上扫描。例如,如果轴 0 是批次轴,轴 1 是时间轴(要扫描的轴),则指定轴值为 1。 请注意,扫描非零轴可能比扫描零轴效率低。

可选属性 scan_output_axes 指定了每个 scan_output 沿哪个轴进行累积。例如,如果轴 1 是输入和输出的时间轴(将被扫描),则指定 scan_input 轴和 scan_output 轴的值为 1。

请注意,由于ONNX限制,只有运算符的最后一个参数可以是可变参数,因此初始状态和扫描输入被列为一个输入参数。同样,最终状态和扫描输出被列为一个输出参数。属性num_scan_inputs表示扫描输入的数量M。

的行为

Scan <
    num_scan_inputs = m,
    body = loop-body,
    scan_input_axes = [axis_1, ..., axis_m]
> (init_1, ..., init_n, scan_1, ..., scan_m)

等同于以下伪代码:

// scan_i.shape[axis_i] denotes the (max) sequence-length of scan_i
// scan_i.shape[axis_i] is required to be equal to scan_j.shape[axis_j] for all i,j.
sequence_length = scan_1.shape[axis_1];

// initialize state-variables
st_1 = init_1; ... st_n = init_n;
// initialize scan-output variables: [] denotes an empty tensor
scan_out_1 = []; ...; scan_out_k = [];
// identify number of iterations:

// execute loop
for (int t = 0; t < sequence_length; ++t) {
    // generate the scan-input elements: the notation T<axis=k>[t] indicates the sub-tensor
    // of rank one less than T obtained by indexing T at position t along axis k.
    si_1 = scan_1<axis=axis_1>[t];
    ... ;
    si_m = scan_m<axis=axis_m>[t];
    // execute loop-body
    st_1, ..., st_n, so_1, ..., so_k = loop-body(st_1, ..., st_n, si_1, ..., si_m)
    // accumulate the scan-output elements
    scan_out_1 = Concat<axis=0>(scan_out_1, so_1); ... ; scan_out_k = Concat<axis=0>(scan_out_k, so_k);
}

return st_1, ..., st_n, scan_out_1, ..., scan_out_k;

示例用法:使用Scan编码RNN

以下示例展示了如何将输入张量 %X、权重张量 %Wi、递归权重张量 %Ri、偏置张量 %Wbi 和 %Rbi 以及初始隐藏状态 %H_0 的简单 RNN 编码为 ScanLoop。请注意,循环体是一个嵌套图,它直接计算

值是在外部图中计算的,它们需要作为额外的state_variables传入。

graph rnn-encoding {
  %H_0 = ...
  %X = ...
  %Y_h, %Y = Scan[body = <graph rnn-cell-1>, num_scan_inputs=1](%H_0, %X)
  return %Y, %Y_h
}

graph rnn-cell-1 (
  %H_tminus1[FLOAT, tensor]
  %X_t[FLOAT, tensor]
) {
  %Wi = ...
  %Ri = ...
  %Wbi = ...
  %Rbi = ...
  %t1 = X_t * (Wi^T)
  %t2 = H_tminus1*(Ri^T)
  %t3 = Add(%t1, %t2)
  %t4 = Add(%t3, %Wbi)
  %t5 = Add(%t4, %Rbi)
  %Ht = Tanh(%t5)
  %Accumulate = Identity(%Ht)
  return %Ht, %Accumulate
}

属性

  • body - GRAPH (必填) :

    图形每次迭代运行。它有N+M个输入:(循环状态变量…,扫描输入元素…)。它有N+K个输出:(循环状态变量…,扫描输出元素…)。每个扫描输出是通过在每次循环迭代结束时连接指定的扫描输出元素值来创建的。如果这些值的维度在循环迭代中发生变化,则会出现错误。

  • num_scan_inputs - INT (必填) :

    一个指定scan_inputs数量M的属性。

  • scan_input_axes - INTS :

    一个可选的M标志列表。列表的第i个元素指定了第i个scan_input要扫描的轴(序列轴)。如果省略,则每个scan_input将使用0作为扫描轴。轴的负值表示从后向前计算维度。接受的范围是[-r, r-1],其中r = rank(input)。

  • scan_input_directions - INTS :

    一个可选的M标志列表。列表的第i个元素指定了第i个scan_input张量的扫描方向:0表示正向,1表示反向。如果省略,所有scan_input张量将按正向扫描。

  • scan_output_axes - INTS :

    一个可选的K标志列表。列表的第i个元素指定第i个scan_output的轴。扫描输出沿着指定的轴累积。如果省略,则每个scan_output将使用0作为扫描轴。轴的负值表示从后向前计算维度。可接受的范围是[-r, r-1]。

  • scan_output_directions - INTS :

    一个可选的K标志列表,每个scan_output对应一个。列表中的第i个元素指定了第i个scan_output是否应在每次迭代中通过追加或前置一个新值来构建:0表示追加,1表示前置。如果省略,所有scan_output张量将在每次迭代中通过追加一个值来生成。

输入

介于1到2147483647之间的输入。

  • initial_state_and_scan_inputs (可变参数) - V:

    循环的N个状态变量的初始值,后跟M个扫描输入

输出

输出在1到2147483647之间。

  • final_state_and_scan_outputs (可变参数) - V:

    循环的N个状态变量的最终值,后跟K个扫描输出

类型约束

  • V 在 ( 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) ):

    所有Tensor类型,直到IRv10。

扫描 - 19

版本

  • 名称: Scan (GitHub)

  • 域名: main

  • since_version: 19

  • 函数: False

  • support_level: SupportType.COMMON

  • 形状推断: True

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

总结

Scan 可用于迭代一个或多个 scan_input 张量,构建零个或多个 scan_output 张量。它结合了来自一般递归、函数式编程结构(如 scan、fold、map 和 zip)的思想,旨在实现对序列到序列处理的类似 RNN 结构的泛化。其他张量(在此称为 state_variables)可用于在从一个元素迭代到另一个元素时携带状态(类似于 RNN 中的隐藏状态,在循环上下文中也称为循环携带依赖)。许多常见用法涉及单个 scan_input 张量(可以获得类似于 scan、fold 和 map 的功能)。当使用多个 scan_input 时,可以获得类似于 zip 的行为。

属性 body 必须是一个图,指定每次迭代中要执行的计算。它以 state_variables 的当前值和 scan_inputs 的当前迭代元素作为输入。它必须返回 state_variables 的(更新)值和零个或多个 scan_output_element 张量。scan_output_element 张量的值在所有迭代中连接起来,生成 scan 结构的 scan_output 值(类似于 RNN 类结构的连接中间隐藏状态值)。所有输出张量(state_variables 以及 scan_output_element 张量)在循环的每次迭代中都必须具有相同的形状(这是为了启用高效内存分配而施加的限制)。

请注意,传递给body子图的迭代元素没有序列轴。它的秩将比相应的scan_input的秩少一。

扫描操作返回state_variables的最终值以及scan_outputs。

可选属性scan_input_directions指定每个扫描输入的方向(向前或向后)。如果省略此属性,所有序列将按向前方向扫描。可以通过在scan_inputs中指定相同的张量输入两次来执行双向扫描,一次为向前方向,一次为向后方向。

操作的scan_output是通过将每次迭代中body生成的scan_output_element值连接起来生成的。可选的属性scan_output_directions指定了每个scan_output的构建方向(通过每次迭代将scan_output_element附加或前置到scan_output中)。如果省略此属性,则每次迭代将scan_output_element附加到scan_output中。

可选属性 scan_input_axes 指定了每个 scan_input 要扫描的轴。 如果省略,每个 scan_input 将在轴 0 上扫描。例如,如果轴 0 是批次轴,轴 1 是时间轴(要扫描的轴),则指定轴值为 1。 请注意,扫描非零轴可能比扫描零轴效率低。

可选属性 scan_output_axes 指定了每个 scan_output 沿哪个轴进行累积。例如,如果轴 1 是输入和输出的时间轴(将被扫描),则指定 scan_input 轴和 scan_output 轴的值为 1。

请注意,由于ONNX限制,只有运算符的最后一个参数可以是可变参数,因此初始状态和扫描输入被列为一个输入参数。同样,最终状态和扫描输出被列为一个输出参数。属性num_scan_inputs表示扫描输入的数量M。

的行为

Scan <
    num_scan_inputs = m,
    body = loop-body,
    scan_input_axes = [axis_1, ..., axis_m]
> (init_1, ..., init_n, scan_1, ..., scan_m)

等同于以下伪代码:

// scan_i.shape[axis_i] denotes the (max) sequence-length of scan_i
// scan_i.shape[axis_i] is required to be equal to scan_j.shape[axis_j] for all i,j.
sequence_length = scan_1.shape[axis_1];

// initialize state-variables
st_1 = init_1; ... st_n = init_n;
// initialize scan-output variables: [] denotes an empty tensor
scan_out_1 = []; ...; scan_out_k = [];
// identify number of iterations:

// execute loop
for (int t = 0; t < sequence_length; ++t) {
    // generate the scan-input elements: the notation T<axis=k>[t] indicates the sub-tensor
    // of rank one less than T obtained by indexing T at position t along axis k.
    si_1 = scan_1<axis=axis_1>[t];
    ... ;
    si_m = scan_m<axis=axis_m>[t];
    // execute loop-body
    st_1, ..., st_n, so_1, ..., so_k = loop-body(st_1, ..., st_n, si_1, ..., si_m)
    // accumulate the scan-output elements
    scan_out_1 = Concat<axis=0>(scan_out_1, so_1); ... ; scan_out_k = Concat<axis=0>(scan_out_k, so_k);
}

return st_1, ..., st_n, scan_out_1, ..., scan_out_k;

示例用法:使用Scan编码RNN

以下示例展示了如何将输入张量 %X、权重张量 %Wi、递归权重张量 %Ri、偏置张量 %Wbi 和 %Rbi 以及初始隐藏状态 %H_0 的简单 RNN 编码为 ScanLoop。请注意,循环体是一个嵌套图,它直接计算

值是在外部图中计算的,它们需要作为额外的state_variables传入。

graph rnn-encoding {
  %H_0 = ...
  %X = ...
  %Y_h, %Y = Scan[body = <graph rnn-cell-1>, num_scan_inputs=1](%H_0, %X)
  return %Y, %Y_h
}

graph rnn-cell-1 (
  %H_tminus1[FLOAT, tensor]
  %X_t[FLOAT, tensor]
) {
  %Wi = ...
  %Ri = ...
  %Wbi = ...
  %Rbi = ...
  %t1 = X_t * (Wi^T)
  %t2 = H_tminus1*(Ri^T)
  %t3 = Add(%t1, %t2)
  %t4 = Add(%t3, %Wbi)
  %t5 = Add(%t4, %Rbi)
  %Ht = Tanh(%t5)
  %Accumulate = Identity(%Ht)
  return %Ht, %Accumulate
}

属性

  • body - GRAPH (必填) :

    图形每次迭代运行。它有N+M个输入:(循环状态变量…,扫描输入元素…)。它有N+K个输出:(循环状态变量…,扫描输出元素…)。每个扫描输出是通过在每次循环迭代结束时连接指定的扫描输出元素值来创建的。如果这些值的维度在循环迭代中发生变化,则会出现错误。

  • num_scan_inputs - INT (必填) :

    一个指定scan_inputs数量M的属性。

  • scan_input_axes - INTS :

    一个可选的M标志列表。列表的第i个元素指定了第i个scan_input要扫描的轴(序列轴)。如果省略,则每个scan_input将使用0作为扫描轴。轴的负值表示从后向前计算维度。接受的范围是[-r, r-1],其中r = rank(input)。

  • scan_input_directions - INTS :

    一个可选的M标志列表。列表的第i个元素指定了第i个scan_input张量的扫描方向:0表示正向,1表示反向。如果省略,所有scan_input张量将按正向扫描。

  • scan_output_axes - INTS :

    一个可选的K标志列表。列表的第i个元素指定了第i个scan_output的轴。扫描输出沿着指定的轴进行累积。如果省略,则每个scan_output将使用0作为扫描轴。轴的负值意味着从后向前计算维度。可接受的范围是[-r, r-1]。

  • scan_output_directions - INTS :

    一个可选的K标志列表,每个scan_output对应一个。列表中的第i个元素指定了第i个scan_output是否应在每次迭代中通过追加或前置一个新值来构建:0表示追加,1表示前置。如果省略,所有scan_output张量将在每次迭代中通过追加一个值来生成。

输入

介于1到2147483647之间的输入。

  • initial_state_and_scan_inputs (可变参数) - V:

    循环的N个状态变量的初始值,后跟M个扫描输入

输出

输出在1到2147483647之间。

  • final_state_and_scan_outputs (可变参数) - V:

    循环的N个状态变量的最终值,后跟K个扫描输出

类型约束

  • V 在 ( 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) ):

    所有Tensor类型,直到IRv9。

扫描 - 16

版本

  • 名称: Scan (GitHub)

  • 域名: main

  • since_version: 16

  • 函数: False

  • support_level: SupportType.COMMON

  • 形状推断: True

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

摘要

Scan 可用于迭代一个或多个 scan_input 张量,构建零个或多个 scan_output 张量。它结合了来自一般递归、函数式编程结构(如 scan、fold、map 和 zip)的思想,旨在实现对序列到序列处理的类似 RNN 结构的泛化。其他张量(在此称为 state_variables)可用于在从一个元素迭代到另一个元素时携带状态(类似于 RNN 中的隐藏状态,在循环上下文中也称为循环携带依赖)。许多常见用法涉及单个 scan_input 张量(可以获得类似于 scan、fold 和 map 的功能)。当使用多个 scan_input 时,可以获得类似于 zip 的行为。

属性 body 必须是一个图,指定每次迭代中要执行的计算。它以 state_variables 的当前值和 scan_inputs 的当前迭代元素作为输入。它必须返回 state_variables 的(更新)值和零个或多个 scan_output_element 张量。scan_output_element 张量的值在所有迭代中连接起来,生成 scan 结构的 scan_output 值(类似于 RNN 类结构的连接中间隐藏状态值)。所有输出张量(state_variables 以及 scan_output_element 张量)在循环的每次迭代中都必须具有相同的形状(这是为了启用高效内存分配而施加的限制)。

请注意,传递给body子图的迭代元素没有序列轴。它的秩将比相应的scan_input的秩少一。

扫描操作返回state_variables的最终值以及scan_outputs。

可选属性scan_input_directions指定每个扫描输入的方向(向前或向后)。如果省略此属性,所有序列将按向前方向扫描。可以通过在scan_inputs中指定相同的张量输入两次来执行双向扫描,一次为向前方向,一次为向后方向。

操作的scan_output是通过将每次迭代中body生成的scan_output_element值连接起来生成的。可选的属性scan_output_directions指定了每个scan_output的构建方向(通过每次迭代将scan_output_element附加或前置到scan_output中)。如果省略此属性,则每次迭代将scan_output_element附加到scan_output中。

可选属性 scan_input_axes 指定了每个 scan_input 要扫描的轴。 如果省略,每个 scan_input 将在轴 0 上扫描。例如,如果轴 0 是批次轴,轴 1 是时间轴(要扫描的轴),则指定轴值为 1。 请注意,扫描非零轴可能比扫描零轴效率低。

可选属性 scan_output_axes 指定了每个 scan_output 沿哪个轴进行累积。例如,如果轴 1 是输入和输出的时间轴(将被扫描),则指定 scan_input 轴和 scan_output 轴的值为 1。

请注意,由于ONNX限制,只有运算符的最后一个参数可以是可变参数,因此初始状态和扫描输入被列为一个输入参数。同样,最终状态和扫描输出被列为一个输出参数。属性num_scan_inputs表示扫描输入的数量M。

的行为

Scan <
    num_scan_inputs = m,
    body = loop-body,
    scan_input_axes = [axis_1, ..., axis_m]
> (init_1, ..., init_n, scan_1, ..., scan_m)

等同于以下伪代码:

// scan_i.shape[axis_i] denotes the (max) sequence-length of scan_i
// scan_i.shape[axis_i] is required to be equal to scan_j.shape[axis_j] for all i,j.
sequence_length = scan_1.shape[axis_1];

// initialize state-variables
st_1 = init_1; ... st_n = init_n;
// initialize scan-output variables: [] denotes an empty tensor
scan_out_1 = []; ...; scan_out_k = [];
// identify number of iterations:

// execute loop
for (int t = 0; t < sequence_length; ++t) {
    // generate the scan-input elements: the notation T<axis=k>[t] indicates the sub-tensor
    // of rank one less than T obtained by indexing T at position t along axis k.
    si_1 = scan_1<axis=axis_1>[t];
    ... ;
    si_m = scan_m<axis=axis_m>[t];
    // execute loop-body
    st_1, ..., st_n, so_1, ..., so_k = loop-body(st_1, ..., st_n, si_1, ..., si_m)
    // accumulate the scan-output elements
    scan_out_1 = Concat<axis=0>(scan_out_1, so_1); ... ; scan_out_k = Concat<axis=0>(scan_out_k, so_k);
}

return st_1, ..., st_n, scan_out_1, ..., scan_out_k;

示例用法:使用Scan编码RNN

以下示例展示了如何将输入张量 %X、权重张量 %Wi、递归权重张量 %Ri、偏置张量 %Wbi 和 %Rbi 以及初始隐藏状态 %H_0 的简单 RNN 编码为 ScanLoop。请注意,循环体是一个嵌套图,它直接计算

值是在外部图中计算的,它们需要作为额外的state_variables传入。

graph rnn-encoding {
  %H_0 = ...
  %X = ...
  %Y_h, %Y = Scan[body = <graph rnn-cell-1>, num_scan_inputs=1](%H_0, %X)
  return %Y, %Y_h
}

graph rnn-cell-1 (
  %H_tminus1[FLOAT, tensor]
  %X_t[FLOAT, tensor]
) {
  %Wi = ...
  %Ri = ...
  %Wbi = ...
  %Rbi = ...
  %t1 = X_t * (Wi^T)
  %t2 = H_tminus1*(Ri^T)
  %t3 = Add(%t1, %t2)
  %t4 = Add(%t3, %Wbi)
  %t5 = Add(%t4, %Rbi)
  %Ht = Tanh(%t5)
  %Accumulate = Identity(%Ht)
  return %Ht, %Accumulate
}

属性

  • body - GRAPH (必填) :

    图形每次迭代运行。它有N+M个输入:(循环状态变量…,扫描输入元素…)。它有N+K个输出:(循环状态变量…,扫描输出元素…)。每个扫描输出是通过在每次循环迭代结束时连接指定的扫描输出元素值来创建的。如果这些值的维度在循环迭代中发生变化,则会出现错误。

  • num_scan_inputs - INT (必填) :

    一个指定scan_inputs数量M的属性。

  • scan_input_axes - INTS :

    一个可选的M标志列表。列表的第i个元素指定了第i个scan_input要扫描的轴(序列轴)。如果省略,则每个scan_input将使用0作为扫描轴。轴的负值表示从后向前计算维度。接受的范围是[-r, r-1],其中r = rank(input)。

  • scan_input_directions - INTS :

    一个可选的M标志列表。列表的第i个元素指定了第i个scan_input张量的扫描方向:0表示正向,1表示反向。如果省略,所有scan_input张量将按正向扫描。

  • scan_output_axes - INTS :

    一个可选的K标志列表。列表的第i个元素指定了第i个scan_output的轴。扫描输出沿着指定的轴进行累积。如果省略,则每个scan_output将使用0作为扫描轴。轴的负值意味着从后向前计算维度。可接受的范围是[-r, r-1]。

  • scan_output_directions - INTS :

    一个可选的K标志列表,每个scan_output对应一个。列表中的第i个元素指定了第i个scan_output是否应在每次迭代中通过追加或前置一个新值来构建:0表示追加,1表示前置。如果省略,所有scan_output张量将在每次迭代中通过追加一个值来生成。

输入

介于1到2147483647之间的输入。

  • initial_state_and_scan_inputs (可变参数) - V:

    循环的N个状态变量的初始值,后跟M个扫描输入

输出

输出在1到2147483647之间。

  • final_state_and_scan_outputs (可变参数) - V:

    循环的N个状态变量的最终值,后跟K个扫描输出

类型约束

  • V 在 ( 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) ):

    所有Tensor类型,直到IRv4。

扫描 - 11

版本

  • 名称: Scan (GitHub)

  • 域名: main

  • since_version: 11

  • 函数: False

  • support_level: SupportType.COMMON

  • 形状推断: True

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

摘要

Scan 可用于迭代一个或多个 scan_input 张量,构建零个或多个 scan_output 张量。它结合了来自一般递归、函数式编程结构(如 scan、fold、map 和 zip)的思想,旨在实现对序列到序列处理的类似 RNN 结构的泛化。其他张量(在此称为 state_variables)可用于在从一个元素迭代到另一个元素时携带状态(类似于 RNN 中的隐藏状态,在循环上下文中也称为循环携带依赖)。许多常见用法涉及单个 scan_input 张量(可以获得类似于 scan、fold 和 map 的功能)。当使用多个 scan_input 时,可以获得类似于 zip 的行为。

属性 body 必须是一个图,指定每次迭代中要执行的计算。它以 state_variables 的当前值和 scan_inputs 的当前迭代元素作为输入。它必须返回 state_variables 的(更新)值和零个或多个 scan_output_element 张量。scan_output_element 张量的值在所有迭代中连接起来,生成 scan 结构的 scan_output 值(类似于 RNN 类结构的连接中间隐藏状态值)。所有输出张量(state_variables 以及 scan_output_element 张量)在循环的每次迭代中都必须具有相同的形状(这是为了启用高效内存分配而施加的限制)。

请注意,传递给body子图的迭代元素没有序列轴。它的秩将比相应的scan_input的秩少一。

扫描操作返回state_variables的最终值以及scan_outputs。

可选属性scan_input_directions指定每个扫描输入的方向(向前或向后)。如果省略此属性,所有序列将按向前方向扫描。可以通过在scan_inputs中指定相同的张量输入两次来执行双向扫描,一次为向前方向,一次为向后方向。

操作的scan_output是通过将每次迭代中body生成的scan_output_element值连接起来生成的。可选的属性scan_output_directions指定了每个scan_output的构建方向(通过每次迭代将scan_output_element附加或前置到scan_output中)。如果省略此属性,则每次迭代将scan_output_element附加到scan_output中。

可选属性 scan_input_axes 指定了每个 scan_input 要扫描的轴。 如果省略,每个 scan_input 将在轴 0 上扫描。例如,如果轴 0 是批次轴,轴 1 是时间轴(要扫描的轴),则指定轴值为 1。 请注意,扫描非零轴可能比扫描零轴效率低。

可选属性 scan_output_axes 指定了每个 scan_output 沿哪个轴进行累积。例如,如果轴 1 是输入和输出的时间轴(将被扫描),则指定 scan_input 轴和 scan_output 轴的值为 1。

请注意,由于ONNX限制,只有运算符的最后一个参数可以是可变参数,因此初始状态和扫描输入被列为一个输入参数。同样,最终状态和扫描输出被列为一个输出参数。属性num_scan_inputs表示扫描输入的数量M。

的行为

Scan <
    num_scan_inputs = m,
    body = loop-body,
    scan_input_axes = [axis_1, ..., axis_m]
> (init_1, ..., init_n, scan_1, ..., scan_m)

等同于以下伪代码:

// scan_i.shape[axis_i] denotes the (max) sequence-length of scan_i
// scan_i.shape[axis_i] is required to be equal to scan_j.shape[axis_j] for all i,j.
sequence_length = scan_1.shape[axis_1];

// initialize state-variables
st_1 = init_1; ... st_n = init_n;
// initialize scan-output variables: [] denotes an empty tensor
scan_out_1 = []; ...; scan_out_k = [];
// identify number of iterations:

// execute loop
for (int t = 0; t < sequence_length; ++t) {
    // generate the scan-input elements: the notation T<axis=k>[t] indicates the sub-tensor
    // of rank one less than T obtained by indexing T at position t along axis k.
    si_1 = scan_1<axis=axis_1>[t];
    ... ;
    si_m = scan_m<axis=axis_m>[t];
    // execute loop-body
    st_1, ..., st_n, so_1, ..., so_k = loop-body(st_1, ..., st_n, si_1, ..., si_m)
    // accumulate the scan-output elements
    scan_out_1 = Concat<axis=0>(scan_out_1, so_1); ... ; scan_out_k = Concat<axis=0>(scan_out_k, so_k);
}

return st_1, ..., st_n, scan_out_1, ..., scan_out_k;

示例用法:使用Scan编码RNN

以下示例展示了如何将输入张量 %X、权重张量 %Wi、递归权重张量 %Ri、偏置张量 %Wbi 和 %Rbi 以及初始隐藏状态 %H_0 的简单 RNN 编码为 ScanLoop。请注意,循环体是一个嵌套图,它直接计算

值是在外部图中计算的,它们需要作为额外的state_variables传入。

graph rnn-encoding {
  %H_0 = ...
  %X = ...
  %Y_h, %Y = Scan[body = <graph rnn-cell-1>, num_scan_inputs=1](%H_0, %X)
  return %Y, %Y_h
}

graph rnn-cell-1 (
  %H_tminus1[FLOAT, tensor]
  %X_t[FLOAT, tensor]
) {
  %Wi = ...
  %Ri = ...
  %Wbi = ...
  %Rbi = ...
  %t1 = X_t * (Wi^T)
  %t2 = H_tminus1*(Ri^T)
  %t3 = Add(%t1, %t2)
  %t4 = Add(%t3, %Wbi)
  %t5 = Add(%t4, %Rbi)
  %Ht = Tanh(%t5)
  %Accumulate = Identity(%Ht)
  return %Ht, %Accumulate
}

属性

  • body - GRAPH (必填) :

    图形每次迭代运行。它有N+M个输入:(循环状态变量…,扫描输入元素…)。它有N+K个输出:(循环状态变量…,扫描输出元素…)。每个扫描输出是通过在每次循环迭代结束时连接指定的扫描输出元素值来创建的。如果这些值的维度在循环迭代中发生变化,则会出现错误。

  • num_scan_inputs - INT (必填) :

    一个指定scan_inputs数量M的属性。

  • scan_input_axes - INTS :

    一个可选的M标志列表。列表的第i个元素指定了第i个scan_input要扫描的轴(序列轴)。如果省略,则每个scan_input将使用0作为扫描轴。轴的负值表示从后向前计算维度。接受的范围是[-r, r-1],其中r = rank(input)。

  • scan_input_directions - INTS :

    一个可选的M标志列表。列表的第i个元素指定了第i个scan_input张量的扫描方向:0表示正向,1表示反向。如果省略,所有scan_input张量将按正向扫描。

  • scan_output_axes - INTS :

    一个可选的K标志列表。列表的第i个元素指定第i个scan_output的轴。扫描输出沿着指定的轴累积。如果省略,则每个scan_output将使用0作为扫描轴。轴的负值表示从后向前计算维度。可接受的范围是[-r, r-1]。

  • scan_output_directions - INTS :

    一个可选的K标志列表,每个scan_output对应一个。列表中的第i个元素指定了第i个scan_output是否应在每次迭代中通过追加或前置一个新值来构建:0表示追加,1表示前置。如果省略,所有scan_output张量将在每次迭代中通过追加一个值来生成。

输入

介于1到2147483647之间的输入。

  • initial_state_and_scan_inputs (可变参数) - V:

    循环的N个状态变量的初始值,后跟M个扫描输入

输出

输出在1到2147483647之间。

  • final_state_and_scan_outputs (可变参数) - V:

    循环的N个状态变量的最终值,后跟K个扫描输出

类型约束

  • 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) ):

    所有张量类型

扫描 - 9

版本

  • 名称: Scan (GitHub)

  • 域名: main

  • since_version: 9

  • 函数: False

  • support_level: SupportType.COMMON

  • 形状推断: True

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

摘要

Scan 可用于迭代一个或多个 scan_input 张量,构建零个或多个 scan_output 张量。它结合了来自一般递归、函数式编程结构(如 scan、fold、map 和 zip)的思想,旨在实现对序列到序列处理的类似 RNN 结构的泛化。其他张量(在此称为 state_variables)可用于在从一个元素迭代到另一个元素时携带状态(类似于 RNN 中的隐藏状态,在循环上下文中也称为循环携带依赖)。许多常见用法涉及单个 scan_input 张量(可以获得类似于 scan、fold 和 map 的功能)。当使用多个 scan_input 时,可以获得类似于 zip 的行为。

属性 body 必须是一个图,指定每次迭代中要执行的计算。它以 state_variables 的当前值和 scan_inputs 的当前迭代元素作为输入。它必须返回 state_variables 的(更新)值和零个或多个 scan_output_element 张量。scan_output_element 张量的值在所有迭代中连接起来,生成 scan 结构的 scan_output 值(类似于 RNN 类结构的连接中间隐藏状态值)。所有输出张量(state_variables 以及 scan_output_element 张量)在循环的每次迭代中都必须具有相同的形状(这是为了启用高效内存分配而施加的限制)。

请注意,传递给body子图的迭代元素没有序列轴。它的秩将比相应的scan_input的秩少一。

扫描操作返回state_variables的最终值以及scan_outputs。

可选属性scan_input_directions指定每个扫描输入的方向(向前或向后)。如果省略此属性,所有序列将按向前方向扫描。可以通过在scan_inputs中指定相同的张量输入两次来执行双向扫描,一次为向前方向,一次为向后方向。

操作的scan_output是通过将每次迭代中body生成的scan_output_element值连接起来生成的。可选的属性scan_output_directions指定了每个scan_output的构建方向(通过每次迭代将scan_output_element附加或前置到scan_output中)。如果省略此属性,则每次迭代将scan_output_element附加到scan_output中。

可选属性 scan_input_axes 指定了每个 scan_input 要扫描的轴。 如果省略,每个 scan_input 将在轴 0 上扫描。例如,如果轴 0 是批次轴,轴 1 是时间轴(要扫描的轴),则指定轴值为 1。 请注意,扫描非零轴可能比扫描零轴效率低。

可选属性 scan_output_axes 指定了每个 scan_output 沿哪个轴进行累积。例如,如果轴 1 是输入和输出的时间轴(将被扫描),则指定 scan_input 轴和 scan_output 轴的值为 1。

请注意,由于ONNX限制,只有运算符的最后一个参数可以是可变参数,因此初始状态和扫描输入被列为一个输入参数。同样,最终状态和扫描输出被列为一个输出参数。属性num_scan_inputs表示扫描输入的数量M。

的行为

Scan <
    num_scan_inputs = m,
    body = loop-body,
    scan_input_axes = [axis_1, ..., axis_m]
> (init_1, ..., init_n, scan_1, ..., scan_m)

等同于以下伪代码:

// scan_i.shape[axis_i] denotes the (max) sequence-length of scan_i
// scan_i.shape[axis_i] is required to be equal to scan_j.shape[axis_j] for all i,j.
sequence_length = scan_1.shape[axis_1];

// initialize state-variables
st_1 = init_1; ... st_n = init_n;
// initialize scan-output variables: [] denotes an empty tensor
scan_out_1 = []; ...; scan_out_k = [];
// identify number of iterations:

// execute loop
for (int t = 0; t < sequence_length; ++t) {
    // generate the scan-input elements: the notation T<axis=k>[t] indicates the sub-tensor
    // of rank one less than T obtained by indexing T at position t along axis k.
    si_1 = scan_1<axis=axis_1>[t];
    ... ;
    si_m = scan_m<axis=axis_m>[t];
    // execute loop-body
    st_1, ..., st_n, so_1, ..., so_k = loop-body(st_1, ..., st_n, si_1, ..., si_m)
    // accumulate the scan-output elements
    scan_out_1 = Concat<axis=0>(scan_out_1, so_1); ... ; scan_out_k = Concat<axis=0>(scan_out_k, so_k);
}

return st_1, ..., st_n, scan_out_1, ..., scan_out_k;

示例用法:使用Scan编码RNN

以下示例展示了如何将输入张量 %X、权重张量 %Wi、递归权重张量 %Ri、偏置张量 %Wbi 和 %Rbi 以及初始隐藏状态 %H_0 的简单 RNN 编码为 ScanLoop。请注意,循环体是一个嵌套图,它直接计算

值是在外部图中计算的,它们需要作为额外的state_variables传入。

graph rnn-encoding {
  %H_0 = ...
  %X = ...
  %Y_h, %Y = Scan[body = <graph rnn-cell-1>, num_scan_inputs=1](%H_0, %X)
  return %Y, %Y_h
}

graph rnn-cell-1 (
  %H_tminus1[FLOAT, tensor]
  %X_t[FLOAT, tensor]
) {
  %Wi = ...
  %Ri = ...
  %Wbi = ...
  %Rbi = ...
  %t1 = X_t * (Wi^T)
  %t2 = H_tminus1*(Ri^T)
  %t3 = Add(%t1, %t2)
  %t4 = Add(%t3, %Wbi)
  %t5 = Add(%t4, %Rbi)
  %Ht = Tanh(%t5)
  %Accumulate = Identity(%Ht)
  return %Ht, %Accumulate
}

属性

  • body - GRAPH (必填) :

    图形每次迭代运行。它有N+M个输入:(循环状态变量…,扫描输入元素…)。它有N+K个输出:(循环状态变量…,扫描输出元素…)。每个扫描输出是通过在每次循环迭代结束时连接指定的扫描输出元素值来创建的。如果这些值的维度在循环迭代中发生变化,则会出现错误。

  • num_scan_inputs - INT (必填) :

    一个指定scan_inputs数量M的属性。

  • scan_input_axes - INTS :

    一个可选的M标志列表。列表的第i个元素指定了第i个scan_input要扫描的轴(序列轴)。如果省略,则每个scan_input将使用0作为扫描轴。

  • scan_input_directions - INTS :

    一个可选的M标志列表。列表的第i个元素指定了第i个scan_input张量的扫描方向:0表示正向,1表示反向。如果省略,所有scan_input张量将按正向扫描。

  • scan_output_axes - INTS :

    一个可选的K标志列表。列表的第i个元素指定第i个scan_output的轴。扫描输出沿着指定的轴累积。如果省略,则每个scan_output将使用0作为扫描轴。

  • scan_output_directions - INTS :

    一个可选的K标志列表,每个scan_output对应一个。列表中的第i个元素指定了第i个scan_output是否应在每次迭代中通过追加或前置一个新值来构建:0表示追加,1表示前置。如果省略,所有scan_output张量将在每次迭代中通过追加一个值来生成。

输入

介于1到2147483647之间的输入。

  • initial_state_and_scan_inputs (可变参数) - V:

    循环的N个状态变量的初始值,后跟M个扫描输入

输出

输出在1到2147483647之间。

  • final_state_and_scan_outputs (可变参数) - V:

    循环的N个状态变量的最终值,后跟K个扫描输出

类型约束

  • 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) ):

    所有张量类型

扫描 - 8

版本

  • 名称: Scan (GitHub)

  • 域名: main

  • since_version: 8

  • 函数: False

  • support_level: SupportType.COMMON

  • 形状推断: True

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

总结

Scan 可用于迭代一个或多个 scan_input 张量,构建零个或多个 scan_output 张量。它结合了来自一般递归、函数式编程构造(如 scan、fold、map 和 zip)的思想,旨在实现对序列到序列处理的类似 RNN 构造的泛化。其他张量(在此称为 state_variables)可用于在从一个元素迭代到另一个元素时携带状态(类似于 RNN 中的隐藏状态,在循环上下文中也称为循环携带依赖)。所有这些张量在循环的每次迭代中都需要具有相同的形状(这是为了启用高效内存分配而施加的限制)。许多常见用法涉及单个 scan_input 张量(可以获得类似于 scan、fold 和 map 的功能)。当使用多个 scan_input 时,可以获得类似于 zip 的行为。

属性 body 必须是一个图,指定每次迭代中要执行的计算。它以 state_variables 的当前值和 scan_inputs 的当前迭代元素作为输入。它必须返回 state_variables 的(更新)值和零个或多个 scan_output_element 张量。scan_output_element 张量的值在所有迭代中连接起来,生成 scan 结构的 scan_output 值(类似于 RNN 类结构的连接中间隐藏状态值)。

扫描操作返回state_variables的最终值以及scan_outputs。

该操作支持批处理,且批处理轴必须为0。 当使用多个scan_input张量时,它们必须具有相同的批处理大小, 并且它们必须具有相同的最大序列长度(序列轴或扫描轴的维度)。 序列轴或扫描轴必须为1。

该操作有一个可选的sequence_lens输入(形状为[BATCH_SIZE]),以允许长度小于等于最大序列长度的可变长度序列。如果未指定此输入,则假定所有序列的长度等于最大序列长度。对于可变长度的输入序列,scan_outputs将由与输入长度相同的序列组成,并填充到最大序列长度。

可选属性 directions 可用于以相反方向扫描序列。 如果省略此属性,则所有序列都将以正向扫描。 可以通过在 scan_inputs 中两次指定相同的张量输入来执行双向扫描,一次为正向,一次为反向。

请注意,由于ONNX限制,只有运算符的最后一个参数可以是可变参数,因此初始状态和扫描输入被列为一个输入参数。同样,最终状态和扫描输出被列为一个输出参数。属性num_scan_inputs表示扫描输入的数量M。

的行为

Scan <
    num_scan_inputs = m,
    body = loop-body
> (sequence_lengths, init_1, ..., init_n, scan_1, ..., scan_m)

等同于以下伪代码:

// T.shape[0] denotes the batch-size of T
// The batch-size of scan_1, ..., scan_m are all required to be equal
batch_size = scan_1.shape[0];

// scan_i.shape[1] denotes the (max) sequence-length of scan_i
// scan_i.shape[1] is required to be equal to scan_j.shape[1] for all i,j.
max_sequence_length = scan_1.shape[1];

for (int batch = 0; batch < batch_size; ++batch) {
    // initialize state-variables
    st_1 = init_1; ... st_n = init_n;
    // initialize scan-output variables: [] denotes an empty tensor
    scan_out_1 = []; ...; scan_out_k = [];
    // identify number of iterations:
    N = (sequence_lengths specified) ? sequence_lengths[batch] : max_sequence_length;

    // execute loop
    for (int t = 0; t < N; ++t) {
        // generate the scan-input elements: the notation T<axis=k>[t] indicates the sub-tensor
        // of rank one less than T obtained by indexing T at position t along axis k.
        si_1 = (scan_1<axis=0>[batch])<axis=1>[t];
        ... ;
        si_m = (scan_m<axis=0>[batch])<axis=1>[t];
        // execute loop-body
        st_1, ..., st_n, so_1, ..., so_k = loop-body(st_1, ..., st_n, si_1, ..., si_m)
        // accumulate the scan-output elements
        scan_out_1 = Concat<axis=0>(scan_out_1, so_1); ... ; scan_out_k = Concat<axis=0>(scan_out_k, so_k);
    }
    // accumulate the outputs for this batch:
    bst_1[batch] = st_1; ..., bst_n[batch] = st_n;
    // Note scan-outputs will have size max_sequence_length, but only first N values will be meaningful.
    // The remaining values have an undefined value.
    b_scan_out_1[batch] = scan_out_1; ...; b_scan_out_k[batch] = scan_out_k;
}
return bst_1, ..., bst_n, b_scan_out_1, ..., b_scan_out_k;

示例用法:使用Scan编码RNN

以下示例展示了如何将输入张量 %X、权重张量 %Wi、递归权重张量 %Ri、偏置张量 %Wbi 和 %Rbi 以及初始隐藏状态 %H_0 的简单 RNN 编码为 ScanLoop。请注意,循环体是一个嵌套图,它直接计算

值是在外部图中计算的,它们需要作为额外的state_variables传入。

graph rnn-encoding {
  %H_0 = ...
  %X = ...
  %Y_h, %Y = Scan[body = <graph rnn-cell-1>, num_scan_inputs=1]("", %H_0, %X)
  return %Y, %Y_h
}

graph rnn-cell-1 (
  %H_tminus1[FLOAT, tensor]
  %X_t[FLOAT, tensor]
) {
  %Wi = ...
  %Ri = ...
  %Wbi = ...
  %Rbi = ...
  %t1 = X_t * (Wi^T)
  %t2 = H_tminus1*(Ri^T)
  %t3 = Add(%t1, %t2)
  %t4 = Add(%t3, %Wbi)
  %t5 = Add(%t4, %Rbi)
  %Ht = Tanh(%t5)
  %Accumulate = Identity(%Ht)
  return %Ht, %Accumulate
}

属性

  • body - GRAPH (必填) :

    图形每次迭代运行。它有N+M个输入:(循环状态变量…,扫描输入元素…)。它有N+K个输出:(循环状态变量…,扫描输出元素…)。每个扫描输出是通过在每次循环迭代结束时连接指定的扫描输出元素值来创建的。如果这些值的维度在循环迭代中发生变化,则会出现错误。

  • 方向 - INTS :

    一个可选的M标志列表。列表的第i个元素指定了第i个scan_input张量的扫描方向:0表示正向,1表示反向。如果省略,所有scan_input张量将按正向扫描。

  • num_scan_inputs - INT (必填) :

    一个指定scan_inputs数量M的属性。

输入

输入数量在2到2147483647之间。

  • sequence_lens (可选, 异构) - I:

    可选的张量,用于指定批次中序列的长度。如果未指定此输入,则假定所有序列均为最大序列长度(scan_input张量的序列轴维度)。

  • initial_state_and_scan_inputs (可变参数) - V:

    循环的N个状态变量的初始值,后跟M个扫描输入

输出

输出在1到2147483647之间。

  • final_state_and_scan_outputs (可变参数) - V:

    循环的N个状态变量的最终值,后跟K个扫描输出

类型约束

  • I 在 ( tensor(int64) ) 中:

    Int64 张量

  • 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) ):

    所有张量类型