code: def _no_beam_search_generate(
      decoder: Seq2SeqDecoder,
      state,
      tokens=None,
      max_length=20,
      max_len_a=0.0,
      temperature=1.0,
      top_k=50,
      top_p=1.0,
      bos_token_id=None,
      eos_token_id=None,
      do_sample=True,
      repetition_penalty=1.0,
      length_penalty=1.0,
      pad_token_id=0,
  ):
      device = _get_model_device(decoder)
      if tokens is None:
          if bos_token_id is None:
              raise RuntimeError(
                  "You have to specify either `tokens` or `bos_token_id`."
              )
          batch_size = state.num_samples
          if batch_size is None:
              raise RuntimeError(
                  "Cannot infer the number of samples from `state`."
              )
          tokens = torch.full(
              [batch_size, 1], fill_value=bos_token_id, dtype=torch.long
          ).to(device)
      batch_size = tokens.size(0)
      if state.num_samples:
          assert (
              state.num_samples == batch_size
          ), "The number of samples in `tokens` and `state` should match."
  
      if eos_token_id is None:
          _eos_token_id = -1
      else:
          _eos_token_id = eos_token_id
  
      scores = decoder.decode(
          tokens=tokens, state=state
      )  # 主要是为了update state
      if _eos_token_id != -1:  # 防止第一个位置为结束
          scores[:, _eos_token_id] = -1e12
      next_tokens = scores.argmax(dim=-1, keepdim=True)
      token_ids = torch.cat([tokens, next_tokens], dim=1)
      cur_len = token_ids.size(1)
      dones = token_ids.new_zeros(batch_size).eq(1)
      # tokens = tokens[:, -1:]
  
      if max_len_a != 0:
          # (bsz x num_beams, )
          if state.encoder_mask is not None:
              max_lengths = (
                  state.encoder_mask.sum(dim=1).float() * max_len_a
              ).long() + max_length
          else:
              max_lengths = tokens.new_full(
                  (tokens.size(0),),
                  fill_value=max_length,
                  dtype=torch.long,
              )
          real_max_length = max_lengths.max().item()
      else:
          real_max_length = max_length
          if state.encoder_mask is not None:
              max_lengths = (
                  state.encoder_mask.new_ones(
                      state.encoder_mask.size(0)
                  ).long()
                  * max_length
              )
          else:
              max_lengths = tokens.new_full(
                  (tokens.size(0),),
                  fill_value=max_length,
                  dtype=torch.long,
              )
  
      while cur_len < real_max_length:
          scores = decoder.decode(
              tokens=token_ids, state=state
          )  # batch_size x vocab_size
  
          if repetition_penalty != 1.0:
              token_scores = scores.gather(dim=1, index=token_ids)
              lt_zero_mask = token_scores.lt(0).float()
              ge_zero_mask = lt_zero_mask.eq(0).float()
              token_scores = (
                  lt_zero_mask * repetition_penalty * token_scores
                  + ge_zero_mask / repetition_penalty * token_scores
              )
              scores.scatter_(dim=1, index=token_ids, src=token_scores)
  
          if eos_token_id is not None and length_penalty != 1.0:
              token_scores = (
                  scores / cur_len**length_penalty
              )  # batch_size x vocab_size
              eos_mask = scores.new_ones(scores.size(1))
              eos_mask[eos_token_id] = 0
              eos_mask = eos_mask.unsqueeze(0).eq(1)
              scores = scores.masked_scatter(
                  eos_mask, token_scores
              )  # 也即除了eos，其他词的分数经过了放大/缩小
  
          if do_sample:
              if temperature > 0 and temperature != 1:
                  scores = scores / temperature
  
              scores = top_k_top_p_filtering(
                  scores, top_k, top_p, min_tokens_to_keep=2
              )
              # 加上1e-12是为了避免https://github.com/pytorch/pytorch/pull/27523
              probs = F.softmax(scores, dim=-1) + 1e-12
  
              next_tokens = torch.multinomial(
                  probs, num_samples=1
              ).squeeze(
                  1
              )  # batch_size
          else:
              next_tokens = torch.argmax(scores, dim=-1)  # batch_size
  
          # 如果已经达到对应的sequence长度了，就直接填为eos了
          if _eos_token_id != -1:
              next_tokens = next_tokens.masked_fill(
                  max_lengths.eq(cur_len + 1), _eos_token_id
              )
          next_tokens = next_tokens.masked_fill(
              dones, pad_token_id
          )  # 对已经搜索完成的sample做padding
          tokens = next_tokens.unsqueeze(1)
  
          token_ids = torch.cat(
              [token_ids, tokens], dim=-1
          )  # batch_size x max_len
  
          end_mask = next_tokens.eq(_eos_token_id)
          dones = dones.__or__(end_mask)
          cur_len += 1
  
          if dones.min() == 1:
              break
  
      # if eos_token_id is not None:
      #     tokens.scatter(index=max_lengths[:, None], dim=1, value=eos_token_id)  # 将最大长度位置设置为eos
      # if cur_len == max_length:
      #     token_ids[:, -1].masked_fill_(~dones, eos_token_id)  # 若到最长长度仍未到EOS，则强制将最后一个词替换成eos
      return token_ids
  
file_path: fastNLP/fastNLP/modules/torch/generator/seq2seq_generator.py
imports: import torch
  from torch import nn
  import torch.nn.functional
  from ..decoder.seq2seq_decoder import Seq2SeqDecoder, State
  from functools import partial
label_desc: Use image node_id 4 for calling a global function with example usage: _no_beam_search_generate(decoder, state, tokens, max_length, max_len_a, temperature, top_k, top_p, bos_token_id, eos_token_id, do_sample, repetition_penalty, length_penalty, pad_token_id) and returns: token_ids