(libtorch) How to use torch::data::datasets for custom dataset?

username: Hengd
cooked: <p>Hi everyone,</p>
<p>Following the <a href="https://github.com/goldsborough/examples/blob/cpp/cpp/mnist/mnist.cpp" rel="nofollow noopener">https://github.com/goldsborough/examples/blob/cpp/cpp/mnist/mnist.cpp</a>, I am trying to write my own program for training using libtorch.</p>
<p>However, I don’t find any documents about how to load my own dataset.<br>
It seems that the C++ API is similar to Python API.</p>
<p>First, using torch::data::datasets to create a object of dataset.<br>
Second, using torch::data::make_data_loader to create a pointer of loader.</p>
<p>But, I don’t know how to define custom dataset using torch::data::datasets. Does anyone can help me?</p>

username: mhubii
cooked: <p>Hi <a class="mention" href="/u/hengd">@Hengd</a>,</p>
<p>well actually it is super easy <img src="https://discuss.pytorch.org/images/emoji/apple/slight_smile.png?v=6" title=":slight_smile:" class="emoji" alt=":slight_smile:">. Just as in this example for the <a href="https://github.com/pytorch/pytorch/blob/master/torch/csrc/api/include/torch/data/datasets/mnist.h" rel="nofollow noopener">MNIST</a> dataset, you can implement a <code>torch::data::datasets::Dataset&lt;Self, SingleExample&gt;</code>. Therefore, you need to override the <code>get(size_t index)</code> method from <code>Dataset</code>. What you need to do, is to get your data from somewhere and convert it into a <code>Tensor</code>, but this is up to you.</p>
<pre><code class="lang-cpp">#include &lt;torch/torch.h&gt;

// You can for example just read your data and directly store it as tensor.
torch::Tensor read_data(const std::string&amp; loc)
{
    torch::Tensor tensor = ...

    // Here you need to get your data.

    return tensor;
};

class MyDataset : public torch::data::Dataset&lt;MyDataset&gt;
{
    private:
        torch::Tensor states_, labels_;

    public:
        explicit MyDataset(const std::string&amp; loc_states, const std::string&amp; loc_labels) 
            : states_(read_data(loc_states)),
              labels_(read_data(loc_labels) {   };

        torch::data::Example&lt;&gt; get(size_t index) override;
};

torch::data::Example&lt;&gt; MyDataset::get(size_t index)
{
    // You may for example also read in a .csv file that stores locations
    // to your data and then read in the data at this step. Be creative.
    return {states_[index], labels_[index]};
} 
</code></pre>
<p>Then, you want to generate a data loader from it, just do</p>
<pre><code class="lang-auto">// Generate your data set. At this point you can add transforms to you data set, e.g. stack your
// batches into a single tensor.
auto data_set = MyDataset(loc_states, loc_labels).map(torch::data::transforms::Stack&lt;&gt;());

// Generate a data loader.
auto data_loader = torch::data::make_data_loader&lt;torch::data::samplers::SequentialSampler&gt;(
    std::move(data_set), 
    batch_size);

// In a for loop you can now use your data.
for (auto&amp; batch : data_loader) {
    auto data = batch.data;
    auto labels = batch.target;
    // do your usual stuff
}

</code></pre>
<p>Hopefully this helps, although I don’t know the kind of data you are  trying to read in.</p>
<p>Martin</p>

username: dambo
cooked: <p>Hello,<br>
Were you able to come up with a working example that mimics that of the PyTorch-based dataset for reading images?</p>
<pre><code class="lang-auto">class GenericDataset(torch.utils.data.Dataset):
  def __init__(self, labels, root_dir, subset=False, transform=None):
    self.labels = labels
    self.root_dir = root_dir
    self.transform = transform

  def __len__(self):
    return len(self.labels)

  def __getitem__(self, idx):
    img_name = self.labels.iloc[idx, 0]  # file name
    fullname = join(self.root_dir, img_name)
    image = Image.open(fullname).convert('RGB')
    labels = self.labels.iloc[idx, 2]  # category_id
    #         print (labels)
    if self.transform:
      image = self.transform(image)
    return image, labels
</code></pre>
<p>Thanks,</p>

username: mhubii
cooked: <p>Hi <a class="mention" href="/u/dambo">@dambo</a>,</p>
<p>yes, the above example mimics the PyTorch version of a dataset.</p>
<p>I will implement an example which clarifies it further and post the link here.</p>

username: mhubii
cooked: <p>I have now implemented a little classifier with a custom dataset that classifies apples and bananas. You can find it <a href="https://github.com/mhubii/libtorch_custom_dataset.git" rel="nofollow noopener">here</a></p>

username: dambo
cooked: <p>Thanks you very much.</p>

username: jianjianGJ
cooked: <p>help a lot!!<br>
thank you!!</p>

username: abtion
cooked: <p>Hi, I found that the example only contains the data and target, how can i do while my data contains many components. (for example, the sentence simlilarity classfication dataset, every item of this dataset contains 2 sentences and a label, for this dataset, I would like to define sentence1, sentence2 and label rather than image and labels)<br>
How can I do that? thanks!<br>
some python code are follow:</p>
<pre><code class="lang-python">class MyDataset(torch.utils.data.Dataset):
  def __init__(self, text1,text2,labels):
    self.labels = labels
    self.sentence1 = text1
    self.sentence2 = text2
......
</code></pre>

username: mhubii
cooked: <p>how do you encode your sentences? Are they one hot encoded? Or do you read them in as strings, and then encode them somehow?</p>

username: abtion
cooked: <aside class="quote no-group" data-username="mhubii" data-post="9" data-topic="34221">
<div class="title">
<div class="quote-controls"></div>
<img loading="lazy" alt="" width="24" height="24" src="https://discuss.pytorch.org/user_avatar/discuss.pytorch.org/mhubii/48/71033_2.png" class="avatar"> mhubii:</div>
<blockquote>
<p>Are they one hot encoded</p>
</blockquote>
</aside>
<p>yes, they are one hot encoded.</p>

username: shyney7
cooked: <p>Thank you for your example how to use libtorch to create own datasets- loaders. Ive followed your example and created a read_data() function that returns a tensor from a csv file by first creating a vector then flatten the vector and then creating tensors in the right shape by using from_blob.<br>
Here is the output of my input and output vectors and tensors (each row is an observation):</p>
<pre><code class="lang-auto">Data Vector: 
9 1 4 2 6 
2 7 5 2 3 
4 3 7 8 5 
5 2 4 7 9 
Flat Vector: 
9 1 4 2 6 2 7 5 2 3 4 3 7 8 5 5 2 4 7 9 
Input Tensor: 
 9  1  4  2  6
 2  7  5  2  3
 4  3  7  8  5
 5  2  4  7  9
[ CPUDoubleType{4,5} ]
Data Vector: 
22 
19 
27 
27 
Flat Vector: 
22 19 27 27 
Output Tensor (target): 
 22
 19
 27
 27
[ CPUDoubleType{4,1} ]
</code></pre>
<p>Unfortunately if I use the class MyDataset in the main function I get the error:</p>
<blockquote>
<p>a cast to abstract class “MyDataset” is not allowed: – pure virtual function “torch::data::datasets::BatchDataset&lt;Self, Batch, BatchRequest&gt;::size [with Self=MyDataset, Batch=std::vector&lt;torch::data::Example&lt;at::Tensor, at::Tensor&gt;, std::allocator&lt;torch::data::Example&lt;at::Tensor, at::Tensor&gt;&gt;&gt;, BatchRequest=c10::ArrayRef&lt;size_t&gt;]” has no overriderC/C++(389)</p>
</blockquote>
<p>Im using the class like this:<br>
<code>auto data_set = MyDataset(input_loc, output_loc);</code><br>
Can please someone help me out.</p>
<p><strong>EDIT / SOLUTION:</strong><br>
Ok I solved it by also overriding the size() method like this:</p>
<pre><code class="lang-auto">torch::optional&lt;size_t&gt; size() const override {
      return labels_.size(0);
    };
</code></pre>
<p>Something that I also had to do to resolve all compilation errors was to pass the data_loader inside the for range loop by pointer like this:</p>
<pre><code class="lang-auto">for (auto&amp; batch: *data_loader) { ... };
</code></pre>
<p>Otherwise it would not compile.<br>
I really miss more Tutorials for the C++ API in the Documentation area. How Can I contribute to add more tutorials for the C++ API so that beginners like me dont have this issues?</p>

username: glaringlee
cooked: <p><a class="mention" href="/u/shyney7">@shyney7</a><br>
Take a look at this recent dataloader/dataset tutorial PR. You can contribute like this as well <img src="https://discuss.pytorch.org/images/emoji/apple/slight_smile.png?v=9" title=":slight_smile:" class="emoji" alt=":slight_smile:"> <a href="https://github.com/pytorch/tutorials/pull/841#issuecomment-794222275" class="inline-onebox" rel="noopener nofollow ugc">Add custom dataset and dataloader tutorial for C++ by dhpollack · Pull Request #841 · pytorch/tutorials · GitHub</a></p>

username: Jesse_Stone
cooked: <pre><code>git clone --recursive https://github.com/pytorch/pytorch
</code></pre>
<p>these files give you complete example<br>
~/pytorch/torch/csrc/api/include/torch/data/example.h<br>
~/pytorch/torch/csrc/api/include/torch/data/datasets/mnist.h<br>
~/pytorch/torch/csrc/api/src/data/datasets/mnist.cpp<br>
~/pytorch/test/cpp/api/integration.cpp</p>
<p>full example</p><aside class="onebox allowlistedgeneric" data-onebox-src="https://github.com/fatalfeel/emnist_dataset_torch_cpp">
  <header class="source">
      <img src="https://github.githubassets.com/favicons/favicon.svg" class="site-icon" width="32" height="32">

      <a href="https://github.com/fatalfeel/emnist_dataset_torch_cpp" target="_blank" rel="noopener nofollow ugc">GitHub</a>
  </header>

  <article class="onebox-body">
    <div class="aspect-image" style="--aspect-ratio:690/345;"><img src="https://opengraph.githubassets.com/2f2f1eccf9515040329f0bc676eac703be5c6c7db99467f3042df3ea9ea850d6/fatalfeel/emnist_dataset_torch_cpp" class="thumbnail" width="690" height="345"></div>

<h3><a href="https://github.com/fatalfeel/emnist_dataset_torch_cpp" target="_blank" rel="noopener nofollow ugc">GitHub - fatalfeel/emnist_dataset_torch_cpp: emnist dataset for torch c++</a></h3>

  <p>emnist dataset for torch c++. Contribute to fatalfeel/emnist_dataset_torch_cpp development by creating an account on GitHub.</p>


  </article>

  <div class="onebox-metadata">
    
    
  </div>

  <div style="clear: both"></div>
</aside>