prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  bug: BentoML Sklearn Example won't work on >= bentoml==1.0.20
  ### Describe the bug
  
  Following steps from [example](https://github.com/bentoml/BentoML/tree/main/examples/sklearn/pipeline)
   
  bentoml serve service.py:svc will produce 
  
  2023-06-08T08:24:26+0000 [ERROR] [runner:20_news_group:1] Traceback (most recent call last):
    File "/usr/local/lib/python3.10/dist-packages/starlette/routing.py", line 671, in lifespan
      async with self.lifespan_context(app):
    File "/usr/local/lib/python3.10/dist-packages/starlette/routing.py", line 566, in __aenter__
      await self._router.startup()
    File "/usr/local/lib/python3.10/dist-packages/starlette/routing.py", line 650, in startup
      handler()
    File "/usr/local/lib/python3.10/dist-packages/bentoml/_internal/server/runner_app.py", line 74, in _init_metrics_wrappers
      self.legacy_adaptive_batch_size_hist_map = {
    File "/usr/local/lib/python3.10/dist-packages/bentoml/_internal/server/runner_app.py", line 75, in <dictcomp>
      method.name: metrics_client.Histogram(
    File "/usr/local/lib/python3.10/dist-packages/prometheus_client/metrics.py", line 558, in __init__
      super().__init__(
    File "/usr/local/lib/python3.10/dist-packages/prometheus_client/metrics.py", line 130, in __init__
      raise ValueError('Invalid metric name: ' + self._name)
  ValueError: Invalid metric name: 20_news_group_1_predict_adaptive_batch_size
  
  ValueError not appeared on pip3 install bentoml==1.0.19
  
  ### To reproduce
  
  pip install bentoml==1.0.21
  follow instructions from https://github.com/bentoml/BentoML/tree/main/examples/sklearn/pipeline
  
  ### Expected behavior
  
  _No response_
  
  ### Environment
  
  bentoml==1.0.20 or bentoml==1.0.21
  Python 3.10.7
  Ubuntu 22.10
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `examples/sklearn/pipeline/service.py`
  Content:
  ```
  1 import bentoml
  2 from bentoml.io import JSON
  3 from bentoml.io import Text
  4 
  5 bento_model = bentoml.sklearn.get("20_news_group:latest")
  6 
  7 target_names = bento_model.custom_objects["target_names"]
  8 model_runner = bento_model.to_runner()
  9 
  10 svc = bentoml.Service("doc_classifier", runners=[model_runner])
  11 
  12 
  13 @svc.api(input=Text(), output=JSON())
  14 async def predict(input_doc: str):
  15     predictions = await model_runner.predict.async_run([input_doc])
  16     return {"result": target_names[predictions[0]]}
  17 
  18 
  19 @svc.api(input=Text(), output=JSON())
  20 async def predict_proba(input_doc: str):
  21     predictions = await model_runner.predict_proba.async_run([input_doc])
  22     return predictions[0]
  23
  ```
  
  Path: `examples/sklearn/pipeline/train.py`
  Content:
  ```
  1 import logging
  2 from time import time
  3 from pprint import pprint
  4 
  5 from sklearn.datasets import fetch_20newsgroups
  6 from sklearn.pipeline import Pipeline
  7 from sklearn.linear_model import SGDClassifier
  8 from sklearn.model_selection import GridSearchCV
  9 from sklearn.feature_extraction.text import CountVectorizer
  10 from sklearn.feature_extraction.text import TfidfTransformer
  11 
  12 import bentoml
  13 
  14 # Display progress logs on stdout
  15 logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)s %(message)s")
  16 
  17 # Load some categories from the training set
  18 categories = [
  19     "alt.atheism",
  20     "talk.religion.misc",
  21 ]
  22 
  23 # Uncomment the following to do the analysis on all the categories
  24 # categories = None
  25 
  26 print("Loading 20 newsgroups dataset for categories:")
  27 print(categories)
  28 
  29 data = fetch_20newsgroups(subset="train", categories=categories)
  30 print("%d documents" % len(data.filenames))
  31 print("%d categories" % len(data.target_names))
  32 print()
  33 
  34 # Define a pipeline combining a text feature extractor with a simple classifier
  35 pipeline = Pipeline(
  36     [
  37         ("vect", CountVectorizer()),
  38         ("tfidf", TfidfTransformer()),
  39         ("clf", SGDClassifier(loss="log_loss")),
  40     ]
  41 )
  42 
  43 # Parameters to use for grid search. Uncommenting more parameters will give
  44 # better exploring power but will increase processing time in a combinatorial
  45 # way
  46 parameters = {
  47     "vect__max_df": (0.5, 0.75, 1.0),
  48     # 'vect__max_features': (None, 5000, 10000, 50000),
  49     "vect__ngram_range": ((1, 1), (1, 2)),  # unigrams or bigrams
  50     # 'tfidf__use_idf': (True, False),
  51     # 'tfidf__norm': ('l1', 'l2'),
  52     "clf__max_iter": (20,),
  53     "clf__alpha": (0.00001, 0.000001),
  54     "clf__penalty": ("l2", "elasticnet"),
  55     # 'clf__max_iter': (10, 50, 80),
  56 }
  57 
  58 # Find the best parameters for both the feature extraction and the
  59 # classifier
  60 grid_search = GridSearchCV(pipeline, parameters, n_jobs=-1, verbose=1)
  61 
  62 print("Performing grid search...")
  63 print("pipeline:", [name for name, _ in pipeline.steps])
  64 print("parameters:")
  65 pprint(parameters)
  66 t0 = time()
  67 grid_search.fit(data.data, data.target)
  68 print("done in %0.3fs" % (time() - t0))
  69 print()
  70 
  71 print("Best score: %0.3f" % grid_search.best_score_)
  72 best_parameters = grid_search.best_estimator_.get_params()
  73 best_parameters = {
  74     param_name: best_parameters[param_name] for param_name in sorted(parameters.keys())
  75 }
  76 print(f"Best parameters set: {best_parameters}")
  77 
  78 bento_model = bentoml.sklearn.save_model(
  79     "20_news_group",
  80     grid_search.best_estimator_,
  81     signatures={
  82         "predict": {"batchable": True, "batch_dim": 0},
  83         "predict_proba": {"batchable": True, "batch_dim": 0},
  84     },
  85     custom_objects={
  86         "target_names": data.target_names,
  87     },
  88     metadata=best_parameters,
  89 )
  90 print(f"Model saved: {bento_model}")
  91 
  92 # Test running inference with BentoML runner
  93 test_runner = bentoml.sklearn.get("20_news_group:latest").to_runner()
  94 test_runner.init_local()
  95 assert test_runner.predict.run(["hello"]) == grid_search.best_estimator_.predict(
  96     ["hello"]
  97 )
  98
  ```
  --- END FILES ---
  
  Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.
  
  Here is an example:
  
  ```diff
  diff --git a/examples/server_async.py b/examples/server_async.py
  --- a/examples/server_async.py
  +++ b/examples/server_async.py
  @@ -313,4 +313,4 @@
   
   
   if __name__ == "__main__":
  -    asyncio.run(run_async_server("."), debug=True)
  +    asyncio.run(run_async_server(), debug=True)
  diff --git a/examples/server_sync.py b/examples/server_sync.py
  --- a/examples/server_sync.py
  +++ b/examples/server_sync.py
  @@ -313,5 +313,5 @@
   
   
   if __name__ == "__main__":
  -    server = run_sync_server(".")
  +    server = run_sync_server()
       server.shutdown()
  
  ```
  
golden_diff: diff --git a/examples/sklearn/pipeline/service.py b/examples/sklearn/pipeline/service.py
  --- a/examples/sklearn/pipeline/service.py
  +++ b/examples/sklearn/pipeline/service.py
  @@ -2,7 +2,7 @@
   from bentoml.io import JSON
   from bentoml.io import Text
   
  -bento_model = bentoml.sklearn.get("20_news_group:latest")
  +bento_model = bentoml.sklearn.get("twenty_news_group:latest")
   
   target_names = bento_model.custom_objects["target_names"]
   model_runner = bento_model.to_runner()
  diff --git a/examples/sklearn/pipeline/train.py b/examples/sklearn/pipeline/train.py
  --- a/examples/sklearn/pipeline/train.py
  +++ b/examples/sklearn/pipeline/train.py
  @@ -76,7 +76,7 @@
   print(f"Best parameters set: {best_parameters}")
   
   bento_model = bentoml.sklearn.save_model(
  -    "20_news_group",
  +    "twenty_news_group",
       grid_search.best_estimator_,
       signatures={
           "predict": {"batchable": True, "batch_dim": 0},
  @@ -90,7 +90,7 @@
   print(f"Model saved: {bento_model}")
   
   # Test running inference with BentoML runner
  -test_runner = bentoml.sklearn.get("20_news_group:latest").to_runner()
  +test_runner = bentoml.sklearn.get("twenty_news_group:latest").to_runner()
   test_runner.init_local()
   assert test_runner.predict.run(["hello"]) == grid_search.best_estimator_.predict(
       ["hello"]
  
verification_info: {"golden_diff": "diff --git a/examples/sklearn/pipeline/service.py b/examples/sklearn/pipeline/service.py\n--- a/examples/sklearn/pipeline/service.py\n+++ b/examples/sklearn/pipeline/service.py\n@@ -2,7 +2,7 @@\n from bentoml.io import JSON\n from bentoml.io import Text\n \n-bento_model = bentoml.sklearn.get(\"20_news_group:latest\")\n+bento_model = bentoml.sklearn.get(\"twenty_news_group:latest\")\n \n target_names = bento_model.custom_objects[\"target_names\"]\n model_runner = bento_model.to_runner()\ndiff --git a/examples/sklearn/pipeline/train.py b/examples/sklearn/pipeline/train.py\n--- a/examples/sklearn/pipeline/train.py\n+++ b/examples/sklearn/pipeline/train.py\n@@ -76,7 +76,7 @@\n print(f\"Best parameters set: {best_parameters}\")\n \n bento_model = bentoml.sklearn.save_model(\n-    \"20_news_group\",\n+    \"twenty_news_group\",\n     grid_search.best_estimator_,\n     signatures={\n         \"predict\": {\"batchable\": True, \"batch_dim\": 0},\n@@ -90,7 +90,7 @@\n print(f\"Model saved: {bento_model}\")\n \n # Test running inference with BentoML runner\n-test_runner = bentoml.sklearn.get(\"20_news_group:latest\").to_runner()\n+test_runner = bentoml.sklearn.get(\"twenty_news_group:latest\").to_runner()\n test_runner.init_local()\n assert test_runner.predict.run([\"hello\"]) == grid_search.best_estimator_.predict(\n     [\"hello\"]\n", "issue": "bug: BentoML Sklearn Example won't work on >= bentoml==1.0.20\n### Describe the bug\r\n\r\nFollowing steps from [example](https://github.com/bentoml/BentoML/tree/main/examples/sklearn/pipeline)\r\n \r\nbentoml serve service.py:svc will produce \r\n\r\n2023-06-08T08:24:26+0000 [ERROR] [runner:20_news_group:1] Traceback (most recent call last):\r\n  File \"/usr/local/lib/python3.10/dist-packages/starlette/routing.py\", line 671, in lifespan\r\n    async with self.lifespan_context(app):\r\n  File \"/usr/local/lib/python3.10/dist-packages/starlette/routing.py\", line 566, in __aenter__\r\n    await self._router.startup()\r\n  File \"/usr/local/lib/python3.10/dist-packages/starlette/routing.py\", line 650, in startup\r\n    handler()\r\n  File \"/usr/local/lib/python3.10/dist-packages/bentoml/_internal/server/runner_app.py\", line 74, in _init_metrics_wrappers\r\n    self.legacy_adaptive_batch_size_hist_map = {\r\n  File \"/usr/local/lib/python3.10/dist-packages/bentoml/_internal/server/runner_app.py\", line 75, in <dictcomp>\r\n    method.name: metrics_client.Histogram(\r\n  File \"/usr/local/lib/python3.10/dist-packages/prometheus_client/metrics.py\", line 558, in __init__\r\n    super().__init__(\r\n  File \"/usr/local/lib/python3.10/dist-packages/prometheus_client/metrics.py\", line 130, in __init__\r\n    raise ValueError('Invalid metric name: ' + self._name)\r\nValueError: Invalid metric name: 20_news_group_1_predict_adaptive_batch_size\r\n\r\nValueError not appeared on pip3 install bentoml==1.0.19\r\n\r\n### To reproduce\r\n\r\npip install bentoml==1.0.21\r\nfollow instructions from https://github.com/bentoml/BentoML/tree/main/examples/sklearn/pipeline\r\n\r\n### Expected behavior\r\n\r\n_No response_\r\n\r\n### Environment\r\n\r\nbentoml==1.0.20 or bentoml==1.0.21\r\nPython 3.10.7\r\nUbuntu 22.10\n", "before_files": [{"content": "import bentoml\nfrom bentoml.io import JSON\nfrom bentoml.io import Text\n\nbento_model = bentoml.sklearn.get(\"20_news_group:latest\")\n\ntarget_names = bento_model.custom_objects[\"target_names\"]\nmodel_runner = bento_model.to_runner()\n\nsvc = bentoml.Service(\"doc_classifier\", runners=[model_runner])\n\n\n@svc.api(input=Text(), output=JSON())\nasync def predict(input_doc: str):\n    predictions = await model_runner.predict.async_run([input_doc])\n    return {\"result\": target_names[predictions[0]]}\n\n\n@svc.api(input=Text(), output=JSON())\nasync def predict_proba(input_doc: str):\n    predictions = await model_runner.predict_proba.async_run([input_doc])\n    return predictions[0]\n", "path": "examples/sklearn/pipeline/service.py"}, {"content": "import logging\nfrom time import time\nfrom pprint import pprint\n\nfrom sklearn.datasets import fetch_20newsgroups\nfrom sklearn.pipeline import Pipeline\nfrom sklearn.linear_model import SGDClassifier\nfrom sklearn.model_selection import GridSearchCV\nfrom sklearn.feature_extraction.text import CountVectorizer\nfrom sklearn.feature_extraction.text import TfidfTransformer\n\nimport bentoml\n\n# Display progress logs on stdout\nlogging.basicConfig(level=logging.INFO, format=\"%(asctime)s %(levelname)s %(message)s\")\n\n# Load some categories from the training set\ncategories = [\n    \"alt.atheism\",\n    \"talk.religion.misc\",\n]\n\n# Uncomment the following to do the analysis on all the categories\n# categories = None\n\nprint(\"Loading 20 newsgroups dataset for categories:\")\nprint(categories)\n\ndata = fetch_20newsgroups(subset=\"train\", categories=categories)\nprint(\"%d documents\" % len(data.filenames))\nprint(\"%d categories\" % len(data.target_names))\nprint()\n\n# Define a pipeline combining a text feature extractor with a simple classifier\npipeline = Pipeline(\n    [\n        (\"vect\", CountVectorizer()),\n        (\"tfidf\", TfidfTransformer()),\n        (\"clf\", SGDClassifier(loss=\"log_loss\")),\n    ]\n)\n\n# Parameters to use for grid search. Uncommenting more parameters will give\n# better exploring power but will increase processing time in a combinatorial\n# way\nparameters = {\n    \"vect__max_df\": (0.5, 0.75, 1.0),\n    # 'vect__max_features': (None, 5000, 10000, 50000),\n    \"vect__ngram_range\": ((1, 1), (1, 2)),  # unigrams or bigrams\n    # 'tfidf__use_idf': (True, False),\n    # 'tfidf__norm': ('l1', 'l2'),\n    \"clf__max_iter\": (20,),\n    \"clf__alpha\": (0.00001, 0.000001),\n    \"clf__penalty\": (\"l2\", \"elasticnet\"),\n    # 'clf__max_iter': (10, 50, 80),\n}\n\n# Find the best parameters for both the feature extraction and the\n# classifier\ngrid_search = GridSearchCV(pipeline, parameters, n_jobs=-1, verbose=1)\n\nprint(\"Performing grid search...\")\nprint(\"pipeline:\", [name for name, _ in pipeline.steps])\nprint(\"parameters:\")\npprint(parameters)\nt0 = time()\ngrid_search.fit(data.data, data.target)\nprint(\"done in %0.3fs\" % (time() - t0))\nprint()\n\nprint(\"Best score: %0.3f\" % grid_search.best_score_)\nbest_parameters = grid_search.best_estimator_.get_params()\nbest_parameters = {\n    param_name: best_parameters[param_name] for param_name in sorted(parameters.keys())\n}\nprint(f\"Best parameters set: {best_parameters}\")\n\nbento_model = bentoml.sklearn.save_model(\n    \"20_news_group\",\n    grid_search.best_estimator_,\n    signatures={\n        \"predict\": {\"batchable\": True, \"batch_dim\": 0},\n        \"predict_proba\": {\"batchable\": True, \"batch_dim\": 0},\n    },\n    custom_objects={\n        \"target_names\": data.target_names,\n    },\n    metadata=best_parameters,\n)\nprint(f\"Model saved: {bento_model}\")\n\n# Test running inference with BentoML runner\ntest_runner = bentoml.sklearn.get(\"20_news_group:latest\").to_runner()\ntest_runner.init_local()\nassert test_runner.predict.run([\"hello\"]) == grid_search.best_estimator_.predict(\n    [\"hello\"]\n)\n", "path": "examples/sklearn/pipeline/train.py"}], "after_files": [{"content": "import bentoml\nfrom bentoml.io import JSON\nfrom bentoml.io import Text\n\nbento_model = bentoml.sklearn.get(\"twenty_news_group:latest\")\n\ntarget_names = bento_model.custom_objects[\"target_names\"]\nmodel_runner = bento_model.to_runner()\n\nsvc = bentoml.Service(\"doc_classifier\", runners=[model_runner])\n\n\n@svc.api(input=Text(), output=JSON())\nasync def predict(input_doc: str):\n    predictions = await model_runner.predict.async_run([input_doc])\n    return {\"result\": target_names[predictions[0]]}\n\n\n@svc.api(input=Text(), output=JSON())\nasync def predict_proba(input_doc: str):\n    predictions = await model_runner.predict_proba.async_run([input_doc])\n    return predictions[0]\n", "path": "examples/sklearn/pipeline/service.py"}, {"content": "import logging\nfrom time import time\nfrom pprint import pprint\n\nfrom sklearn.datasets import fetch_20newsgroups\nfrom sklearn.pipeline import Pipeline\nfrom sklearn.linear_model import SGDClassifier\nfrom sklearn.model_selection import GridSearchCV\nfrom sklearn.feature_extraction.text import CountVectorizer\nfrom sklearn.feature_extraction.text import TfidfTransformer\n\nimport bentoml\n\n# Display progress logs on stdout\nlogging.basicConfig(level=logging.INFO, format=\"%(asctime)s %(levelname)s %(message)s\")\n\n# Load some categories from the training set\ncategories = [\n    \"alt.atheism\",\n    \"talk.religion.misc\",\n]\n\n# Uncomment the following to do the analysis on all the categories\n# categories = None\n\nprint(\"Loading 20 newsgroups dataset for categories:\")\nprint(categories)\n\ndata = fetch_20newsgroups(subset=\"train\", categories=categories)\nprint(\"%d documents\" % len(data.filenames))\nprint(\"%d categories\" % len(data.target_names))\nprint()\n\n# Define a pipeline combining a text feature extractor with a simple classifier\npipeline = Pipeline(\n    [\n        (\"vect\", CountVectorizer()),\n        (\"tfidf\", TfidfTransformer()),\n        (\"clf\", SGDClassifier(loss=\"log_loss\")),\n    ]\n)\n\n# Parameters to use for grid search. Uncommenting more parameters will give\n# better exploring power but will increase processing time in a combinatorial\n# way\nparameters = {\n    \"vect__max_df\": (0.5, 0.75, 1.0),\n    # 'vect__max_features': (None, 5000, 10000, 50000),\n    \"vect__ngram_range\": ((1, 1), (1, 2)),  # unigrams or bigrams\n    # 'tfidf__use_idf': (True, False),\n    # 'tfidf__norm': ('l1', 'l2'),\n    \"clf__max_iter\": (20,),\n    \"clf__alpha\": (0.00001, 0.000001),\n    \"clf__penalty\": (\"l2\", \"elasticnet\"),\n    # 'clf__max_iter': (10, 50, 80),\n}\n\n# Find the best parameters for both the feature extraction and the\n# classifier\ngrid_search = GridSearchCV(pipeline, parameters, n_jobs=-1, verbose=1)\n\nprint(\"Performing grid search...\")\nprint(\"pipeline:\", [name for name, _ in pipeline.steps])\nprint(\"parameters:\")\npprint(parameters)\nt0 = time()\ngrid_search.fit(data.data, data.target)\nprint(\"done in %0.3fs\" % (time() - t0))\nprint()\n\nprint(\"Best score: %0.3f\" % grid_search.best_score_)\nbest_parameters = grid_search.best_estimator_.get_params()\nbest_parameters = {\n    param_name: best_parameters[param_name] for param_name in sorted(parameters.keys())\n}\nprint(f\"Best parameters set: {best_parameters}\")\n\nbento_model = bentoml.sklearn.save_model(\n    \"twenty_news_group\",\n    grid_search.best_estimator_,\n    signatures={\n        \"predict\": {\"batchable\": True, \"batch_dim\": 0},\n        \"predict_proba\": {\"batchable\": True, \"batch_dim\": 0},\n    },\n    custom_objects={\n        \"target_names\": data.target_names,\n    },\n    metadata=best_parameters,\n)\nprint(f\"Model saved: {bento_model}\")\n\n# Test running inference with BentoML runner\ntest_runner = bentoml.sklearn.get(\"twenty_news_group:latest\").to_runner()\ntest_runner.init_local()\nassert test_runner.predict.run([\"hello\"]) == grid_search.best_estimator_.predict(\n    [\"hello\"]\n)\n", "path": "examples/sklearn/pipeline/train.py"}]}