How to feed string data to a GPU to encode data? SentenceTransformers

username: rjurney
cooked: <p>I am using Bert sentence transformers to encode strings into sentence embeddings in a scalable way and I’ve run into a blocking problem: I can’t get the code to run on a GPU.</p>
<p>Without using a GPU I can pass individual strings to SentenceTransformer.encode() (a Model) and get vector representations. When I use a GPU I get a GPU error that arguments are located on different machines. How do I get string data to the GPU? The docs I find indicate this can’t be done and I need to find a way to batch a bunch of strings to get encoded at once on the GPU. When I pass a numpy array of strings to Model.encode(), I get an exception: <code>arguments are located on different GPUs</code>. How do you get string data on a GPU?</p>
<p>Please help! <img src="https://discuss.pytorch.org/images/emoji/apple/slight_smile.png?v=9" title=":slight_smile:" class="emoji" alt=":slight_smile:"></p>
<p>I looked up how to send a numpy array of strings to a GPU using PyTorch and there seems to be no way to do that. I looked at <a href="https://github.com/UKPLab/sentence-transformers/issues/33" rel="nofollow noopener"><code>DataParallel</code></a> and it doesn’t seem to encode data, and I can’t get it to work.</p>
<p>I start out creating a SentenceTransformer using a pooling model and I can run it on one string at a time. The <code>encode()</code> method takes a string or list of strings as an argument. Without sending it to the GPU it works fine. I can’t figure out how to get a list or numpy array of strings to the GPU! It is maddening, there is nothing out there on this. It must be possible because sentence transformers operate on strings. But how?</p>
<pre><code class="lang-python">device = torch.device("cuda:0")
...

sentence_model = SentenceTransformer(
    modules=[bert_model, pooling_model]
)
sentence_model = sentence_model.to(device)
</code></pre>
<pre><code class="lang-python">RuntimeError: arguments are located on different GPUs at /opt/conda/conda-bld/pytorch_1579022034529/work/aten/src/THC/generic/THCTensorIndex.cu:400
</code></pre>
<p>When I look at the series, it is a numpy array of .</p>
<pre><code class="lang-python">In [21]: series.dtype
Out[21]: dtype('O')

In [22]: series.values
Out[22]:
array(['I like cats but also dogs', 'I like cars full of cats',
       'I like apples but not oranges', ..., 'I like cars full of cats',
       'I like apples but not oranges', 'I like tutus on ballerinas.'],
      dtype=object)
</code></pre>
<p>When I try to create a tensor to get the data on a GPU, I run into this problem:</p>
<pre><code class="lang-python">In [20]: torch.from_numpy(series.values)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
&lt;ipython-input-20-d0a262ca0b02&gt; in &lt;module&gt;
----&gt; 1 torch.from_numpy(series.values)

TypeError: can't convert np.ndarray of type numpy.object_. The only supported types are: float64, float32, float16, int64, int32, int16, int8, uint8, and bool.
</code></pre>
<p>So I am very much stuck. How do you encode multiple strings on a GPU?</p>

username: vdw
cooked: <p>PyTorch tensors can only contain numerical values. You try to use strings. For NLP task, the required steps is to map your vocabulary of words to indexes and than map your strings to lists of indexes.</p>
<p>For example, your mapping might look like {‘I’: 0, ‘like’: 1, ‘cats’: 2, ‘but’: 3, …"}. Then you can convert your strings to something like</p>
<pre><code>array([ [0 1 2 3 4 5] [0 1 32 16 8 3], ...], dtype=int_)
</code></pre>
<p>Now you can <code>torch.from_numpy()</code> on this. Once you have proper tensor, moving it to the GPU should be now problem.</p>
<p>You might look into <code>torchtext</code>. It comes with a lot of these basic functionalities to handle text (i.e., creating the vocabulary, creating the mappings, convert your strings to list of indexes, etc.)</p>

username: rjurney
cooked: <p>Thank you, I am aware of how to use encode from the tokenizer first. This is just very confusing because <code>SentenceTransformers.encode()</code> takes a list of strings. I don’t know why it does that. Thanks, I’ll look at <code>torchtext</code>.</p>

username: rjurney
cooked: <p>What I’ve found is that <code>SentenceTransformers</code> is not scalable because it doesn’t use a GPU for encoding records as it uses strings and you can’t create a tensor of these strings to put on a GPU because PyTorch has no string Tensor type. In my application I have to encode the data in BERT on many cores as it isn’t GPU accelerated and then feed in integer encoded data into <code>SentenceTransormers</code>. I’m having to alter the library to do this.</p>

username: Chandrayee
cooked: <p>I converted the model to device and that automatically sped up the encoding with SentenceTransformer. I did not have to change the data to device.</p>