CNTK通常提供了很棒的C ++ API,但我很难找到如何从C ++ API构建LSTM或GRU层。我能找到的唯一功能是OptimizedRNNStack
。除weights
变量外,该函数似乎不言自明。到目前为止,我还没有设法弄清楚如何初始化weights
变量。查看CNTK.core.bs
,似乎用以下内容初始化权重:
ParameterTensor {0:0, initFilterRank=0, initOutputRank=-1, init=init,
initValueScale=initValueScale}`
但我无法弄清楚如何将其转换为C ++。对于上下文 - 我正在尝试使用CTC来构建OCR管道。使用C ++构建所有内容非常棒,因为我可以使用所有本机数据综合工具,并且可以对整个管道进行端到端的培训和测试。但是,如果我必须在Brainscript中构建模型,我想这也很好。
答案 0 :(得分:1)
C ++ API没有等效的图层库。我一直在努力做到这一点,因为C ++的静态类型性质使得很难支持所有这些选项。让我分享一段私有的C ++代码,创建一个类似于图层库的GRU(没有所有选项)。
对不起,这不是直接可复制的;请尝试将返回值更改为Function,并通过创建两个PlaceholderVariables,dh和x来更改lambda签名。有趣的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;
});
}