<p>I don't think there is single authoritative documentation saying what to use and when. You need to experiment and measure what is best for your task. Recent observations about BERT are nicely summarized in this paper: <a href="https://arxiv.org/pdf/2002.12327.pdf" rel="noreferrer">https://arxiv.org/pdf/2002.12327.pdf</a>.</p>
<p>I think the rule of thumb is:</p>
<ul>
<li><p>Use the last layer if you are going to fine-tune the model for your specific task. And finetune whenever you can, several hundred or even dozens of training examples are enough.</p>
</li>
<li><p>Use some of the middle layers (7-th or 8-th) if you cannot finetune the model. The intuition behind that is that the layers first develop a more and more abstract and general representation of the input. At some point, the representation starts to be more target to the pre-training task.</p>
</li>
</ul>
<p>Bert-as-services uses the last layer by default (but it is configurable). Here, it would be <code>[:, -1]</code>. However, it always returns a list of vectors for all input tokens. The vector corresponding to the first special (so-called <code>[CLS]</code>) token is considered to be the sentence embedding. This where the <code>[0]</code> comes from in the snipper you refer to.</p>
BERT sentence embeddings from transformers
<p>I'm trying to get sentence vectors from hidden states in a BERT model.  Looking at the huggingface BertModel instructions <a href="https://huggingface.co/bert-base-multilingual-cased?text=This%20sentence%20etc" rel="noreferrer">here</a>, which say:</p>
<pre><code>from transformers import BertTokenizer, BertModel
tokenizer = BertTokenizer.from_pretrained('bert-base-multilingual-cased')
model = BertModel.from_pretrained(&quot;bert-base-multilingual-cased&quot;)
text = &quot;Replace me by any text you'd like.&quot;
encoded_input = tokenizer(text, return_tensors='pt') 
output = model(**encoded_input)
</code></pre>
<p>So first note, as it is on the website, this does /not/ run. You get:</p>
<pre><code>&gt;&gt;&gt; Traceback (most recent call last):
  File &quot;&lt;stdin&gt;&quot;, line 1, in &lt;module&gt;
TypeError: 'BertTokenizer' object is not callable
</code></pre>
<p>But it looks like a minor change fixes it, in that you don't call the tokenizer directly, but ask it to encode the input:</p>
<pre><code>encoded_input = tokenizer.encode(text, return_tensors=&quot;pt&quot;)
output = model(encoded_input)
</code></pre>
<p>OK, that aside, the tensors I get, however, have a different shape than I expected:</p>
<pre><code>&gt;&gt;&gt; output[0].shape
torch.Size([1,11,768])
</code></pre>
<p>This is a lot of layers.  Which is the correct layer to use for sentence embeddings?  <code>[0]</code>?  <code>[-1]</code>?  Averaging several?  I have the goal of being able to do cosine similarity with these, so I need a proper 1xN vector rather than an NxK tensor.</p>
<p>I see that the popular <a href="https://github.com/hanxiao/bert-as-service#building-a-qa-semantic-search-engine-in-3-minutes" rel="noreferrer">bert-as-a-service project</a> appears to use <code>[0]</code></p>
<p>Is this correct? Is there documentation for what each of the layers are?</p>