RandomUniform#

バージョン名: RandomUniform-8

カテゴリー: 生成

簡単な説明: RandomUniform 操作は、一様分布からランダムな値のシーケンスを生成します。

詳細な説明:

RandomUniform 操作は、範囲 [minval, maxval) の一様分布から乱数を生成します。生成アルゴリズムは、Philox アルゴリズムを使用する基礎となるランダム整数ジェネレーターに基づいています。Philox アルゴリズムは、uint32 値を生成するカウンターベースの擬似乱数ジェネレーターです。Philox アルゴリズムを 1 回呼び出すと、指定されたキーカウンターの値に応じて 4 つのランダムな結果値が返されます。キーカウンターはそれぞれ global_seed 属性と op_seed 属性で初期化されます。

両方のシード値がゼロに等しい場合、RandomUniform は非決定論的なシーケンスを生成します。

key=globalseedcounter=opseed

元の論文 Parallel Random Numbers: As Easy as 1, 2, 3 へのリンク。

Philox の結果は、固定数のキーカウンターの更新、いわゆる “ラウンド” を適用することによって計算されます。この実装では、Philox アルゴリズムの 4x32_10 バージョン (ラウンド数 = 10) が使用されます。

ランダムシーケンスの n 番目の 4 要素を決定する n があるとします。各ラウンドキーでは、countern が uint32 値のペアに分割されます:

R=cast_to_uint32(value)L=cast_to_uint32(value>>32),

ここで、cast_to_uint32 - uint32 への静的キャスト、value - uint64 入力値、LR - uint32 結果の値、>> - ビット単位の右シフト。

次に、ncounter が次の式で更新されます:

L=mullo(R,M)R=mulhi(R,M)kLmulhi(a,b)=floor((a×b)/232)mullo(a,b)=(a×b)mod232

ここで、 - ビットごとの xor、k = Rkey - カウンター更新、k = Lkey - n 更新、M = 0xD2511F53 - n 更新、M = 0xCD9E8D57 - カウンター更新。

各ラウンドの後、別の const 値のペアと合計することによってキーが生成されます。

L+=0x9E3779B9R+=0xBB67AE85

Ln,Rn,Lcounter,Rcounter の結果は、4 つの乱数になります。

[0..1) 間の浮動小数点値は、次の規則に従って 32 ビット整数から取得されます。

Float16 は、符号 (1 ビット) 指数 (5 ビット) 仮数 (10 ビット) のようにフォーマットされます。値は次の式で解釈されます:

(1)sign1,mantissa2exponent15

したがって、float16 値を取得するには、符号指数仮数は次のように設定されます:

符号 = 0 指数 = 15 - ゼロ指数の表現。
仮数 = 生成された uint32 ランダム値からの右 10 ビット。

したがって、結果の float16 値は次のようになります:

x_uint16 = x // 上位 16 ビットを切り捨てます。
val = ((指数 << 10) | x_uint16 & 0x3ffu) - 1.0

ここで、x は uint32 で生成されたランダム値です。

Float32 は、符号 (1 ビット) 指数 (8 ビット) 仮数 (23 ビット) のようにフォーマットされます。値は次の式で解釈されます:

(1)sign1,mantissa2exponent127

したがって、float 値を取得するには、符号指数仮数は次のように設定されます:

符号 = 0 指数 = 127 - ゼロ指数の表現。
仮数 = 生成された uint32 ランダム値からの右 23 ビット。

したがって、結果の float 値は次のようになります:

val = ((指数 << 23) | x & 0x7fffffu) - 1.0,

ここで、x は uint32 で生成されたランダム値です。

Double は次のようにフォーマットされます: 符号 (1 ビット) 指数 (11 ビット) 仮数 (52 ビット)。値は次の式で解釈されます:

(1)sign1,mantissa2exponent1023

したがって、double 値を取得するには、符号指数仮数は次のように設定されます:

符号 = 0 指数 = 1023 - ゼロ指数の表現。
仮数 = ランダム整数ジェネレーターからの 2 つの連結された uint32 値の右側の 52 ビット。

したがって、結果の double は次のように取得されます:

mantissa_h = x0 & 0xfffffu; // 仮数の上位 20 ビット 
mantissa_l = x1; // 仮数の下位 32 ビット 
mantissa = (mantissa_h << 32) | mantissa_l; 
val = ((exponent << 52) | mantissa) - 1.0,

ここで、x0、x1 は uint32 で生成されたランダム値です。

指定された範囲の値を取得するには、各値が次の式で処理されます:

float 値の場合:

result=x(maxvalminval)+minval,

ここで、x は [0..1) 間のランダムな float または double 値です。

整数値の場合:

result=xmod(maxvalminval)+minval,

ここで、x は uint32 のランダム値です。

例 1global_seed = 150、op_seed = 10、output_type = f32 の RandomUniform 出力:

 input_shape = [ 3, 3 ] 
output = [[0.7011236 0.30539632 0.93931055] [0.9456035 0.11694777 0.50770056] [0.5197197 0.22727466 0.991374 ]]

例 2global_seed = 80、op_seed = 100、output_type double の RandomUniform 出力:

input_shape = [ 2, 2 ] 
minval = 2 
maxval = 10 
output = [[5.65927959 4.23122376] [2.67008206 2.36423758]]

例 3global_seed = 80、op_seed = 100、output_type = i32 の RandomUniform 出力:

input_shape = [ 2, 3 ] 
minval = 50 
maxval = 100 
output = [[65 70 56] [59 82 92]]

属性:

  • output_type

    • 説明: 出力のタイプ生成アルゴリズムを決定し、結果の値に影響します。output_type の異なる値に対して生成される出力番号は、等しくない場合があります。

    • 値の範囲: “i32”, “i64”, “f16”, “bf16”, “f32”, “f64”

    • タイプ: 文字列

    • 必須: はい

  • global_seed

    • 説明: グローバルシード値。

    • 値の範囲: 正の整数

    • タイプ: int

    • デフォルト値: 0

    • 必須: はい

  • op_seed

    • 説明: 運用シード値。

    • 値の範囲: 正の整数

    • タイプ: int

    • デフォルト値: 0

    • 必須: はい

入力:

  • 1: shape - 出力形状を記述する T_SHAPE タイプの 1D テンソル。必須。

  • 2: minval - 属性 output_type で指定されたタイプを持つ 1 つの要素を持つスカラーまたは 1D テンソルは、生成するランダム値の範囲の下限を定義します (両端を含む)。必須。

  • 3: maxval - 属性 output_type で指定されたタイプを持つ 1 つの要素を持つスカラーまたは 1D テンソルは、生成するランダム値の範囲の上限を定義します (排他的)。必須。

出力:

  • 1: 属性 output_type で指定されたタイプと、shape 入力テンソルで定義された形状を持つテンソル。

タイプ

  • T_SHAPE: int32 または int64

例 1: IR の例。

 <layer ... name="RandomUniform" type="RandomUniform"> 
    <data output_type="f32" global_seed="234" op_seed="148"/> 
    <input> 
        <port id="0" precision="I32">
            <!-- shape 値: [2, 3, 10] --> 
            <dim>3</dim> 
        </port> 
        <port id="1" precision="FP32"/>
            <!-- min 値 --> 
        <port id="2" precision="FP32"/>
            <!-- max 値 --> 
        </input> 
        <output> 
            <port id="3" precision="FP32" names="RandomUniform:0"> 
                <dim>2</dim> 
                <dim>3</dim> 
                <dim>10</dim> 
        </port> 
    </output> 
</layer>