C++ APIには、同等のレイヤーライブラリがありません。私はC++の静的型付けの性質がすべてのオプションをサポートするのを難しくしているので、これを行うには苦労しました。 Layersライブラリと同じようにGRUを作成するC++コードのプライベートな部分を共有してみましょう(すべてのオプションなし)。
申し訳ありませんが、これは直接コピー可能です。戻り値をFunctionに変更し、2つのPlaceholderVariables、dh、およびxを作成してラムダシグネチャを変更してください。その面白いlet
はconst auto
の略です。
static BinaryModel GRU(size_t outputDim, const DeviceDescriptor& device)
{
let activation = [](const Variable& x) { return Tanh(x); };
auto W = Parameter({ outputDim * 3, NDShape::InferredDimension }, DataType::Float, GlorotUniformInitializer(), device, L"W");
auto R = Parameter({ outputDim * 2, outputDim }, DataType::Float, GlorotUniformInitializer(), device, L"R");
auto R1 = Parameter({ outputDim , outputDim }, DataType::Float, GlorotUniformInitializer(), device, L"R1");
auto b = Parameter({ outputDim * 3 }, 0.0f, device, L"b");
let stackAxis = vector<Axis>{ Axis(0) };
let stackedDim = (int)outputDim;
let one = Constant::Scalar(1.0f, device); // for "1 -"...
// e.g. https://en.wikipedia.org/wiki/Gated_recurrent_unit
return BinaryModel({ W, R, R1, b }, [=](const Variable& dh, const Variable& x)
{
let& dhs = dh;
// projected contribution from input(s), hidden, and bias
let projx3 = b + Times(W, x);
let projh2 = Times(R, dh);
let zt_proj = Slice(projx3, stackAxis, 0 * stackedDim, 1 * stackedDim) + Slice(projh2, stackAxis, 0 * stackedDim, 1 * stackedDim);
let rt_proj = Slice(projx3, stackAxis, 1 * stackedDim, 2 * stackedDim) + Slice(projh2, stackAxis, 1 * stackedDim, 2 * stackedDim);
let ct_proj = Slice(projx3, stackAxis, 2 * stackedDim, 3 * stackedDim);
let zt = Sigmoid(zt_proj)->Output(); // fun update gate z(t)
let rt = Sigmoid(rt_proj); // reset gate r(t)
let rs = dhs * rt; // "cell" c
let ct = activation(ct_proj + Times(R1, rs));
let ht = (one - zt) * ct + zt * dhs; // hidden state ht/output
return ht;
});
}
申し訳ありませんが、私は、スライス()関数は、ベクトル {0 * stackeDim}のように、ベクトルとしてすべての3つの引数を渡す必要があることに気づきました。小さなラッパー関数静的スライス(const変数&、const Axis&、int、int)を書くことをお勧めします。 –