Seeding a torch::Generator in C++

username: PatrickV
cooked: <p>In Python, we create and seed a random generator like this</p>
<pre><code class="lang-auto">  gen = torch.Generator()
  gen.manual_seed( 42 )
</code></pre>
<p>to be used for example in</p>
<pre><code class="lang-auto">  x = torch.multinomial( x, num_samples=1, generator=gen )
</code></pre>
<p>Now, I would like to do the same thing in C++. So, I tried</p>
<pre><code class="lang-auto">  auto gen = torch::Generator();
  gen.manual_seed( 42 );  // Does not exist !!!
</code></pre>
<p>but the method <strong>manual_seed</strong> does not exist.<br>
I found another method called <strong>set_current_seed</strong> but it crashes at execution!</p>
<pre><code class="lang-auto">  auto gen = torch::Generator();
  gen.set_current_seed( 42 );  // Crashes !!!
</code></pre>
<p>Any idea ?</p>

username: ptrblck
cooked: <p>I don’t know why your code crashes, so you would need to try to get the stacktraces etc. as the same code is used e.g. <a href="https://github.com/pytorch/pytorch/blob/c9c66819a16057a3a5223a15e4f12f81cf7603a8/torch/csrc/Generator.cpp#L151-L154">here</a> with an additional lock.</p>

username: PatrickV
cooked: <p>It appears that in C++ the <strong>torch::Generator()</strong> class is just an empty wrapper.<br>
The <strong>set_current_seed</strong> method is defined as</p>
<pre><code class="lang-auto">  void set_current_seed(uint64_t seed) { impl_-&gt;set_current_seed(seed); }
</code></pre>
<p>and of course, when the <strong>impl_</strong> pointer is null, the app craches!</p>
<p>I finally found a default generator equivalent to the Python one.</p>
<p>So, the following code in Python</p>
<pre><code class="lang-auto">  gen = torch.Generator().manual_seed( 42 )
  p = torch.rand( 5, generator=gen )
  print(p)
  x = torch.multinomial(p, num_samples=10, replacement=True, generator=gen)
  print(x)
</code></pre>
<p>prints exactly the same result as the following C++ code</p>
<pre><code class="lang-auto">  auto gen = at::detail::createCPUGenerator( 42 );
  auto p = torch::rand( {5}, gen );
  std::cout &lt;&lt; p &lt;&lt; std::endl;
  auto x = torch::multinomial( p, /*n_samples*/10, /*replac*/true, gen );
  std::cout &lt;&lt; x &lt;&lt; std::endl;
</code></pre>
<p>outputs</p>
<pre><code class="lang-auto">tensor([0.8823, 0.9150, 0.3829, 0.9593, 0.3904])
tensor([3, 1, 0, 3, 2, 1, 2, 0, 2, 3])
</code></pre>

username: PatrickV
cooked: <p>Unfortunately, and surprisingly, if the number of samples is 1 the Python version and C++ version does NOT give the same result! So, to solve that, I ask two samples and keep the first one…</p>

username: phetdam
cooked: <p>I think the non-<code>at::detail::</code> (because stuff in a library’s <code>detail::</code> namespace is likely not under any API stability guarantees) method of doing this is with <a href="https://github.com/pytorch/pytorch/blob/36c6ad71ba9fd00a85838ac328fd9b01e440d4b6/aten/src/ATen/core/Generator.h#L144" rel="noopener nofollow ugc"><code>at::make_generator&lt;Impl&gt;</code></a>, where for CPU generators the <a href="https://github.com/pytorch/pytorch/blob/36c6ad71ba9fd00a85838ac328fd9b01e440d4b6/aten/src/ATen/CPUGeneratorImpl.h#L10" rel="noopener nofollow ugc"><code>at::CPUGeneratorImpl</code></a> seems like the type to use. E.g.</p>
<pre data-code-wrap="cpp"><code class="lang-cpp">auto gen = at::make_generator&lt;at::CPUGeneratorImpl&gt;(/*seed*/);
auto ten = torch::randn({2, 3, 4}, gen);
</code></pre>
<p>This seems to work nicely and for PyTorch 2.4.1+cpu is matching up with the Python way:</p>
<pre data-code-wrap="python"><code class="lang-python">ten = torch.randn((2, 3, 4), generator=torch.Generator())
</code></pre>