ayushi0430 commited on
Commit
64e3457
1 Parent(s): d409109

shopping pipeline

Browse files
Files changed (6) hide show
  1. .gitignore +1 -0
  2. Dockerfile +12 -2
  3. generation.py +158 -0
  4. run-adhoc.sh +12 -1
  5. run-pipeline.sh +15 -0
  6. start.sh +10 -1
.gitignore CHANGED
@@ -11,3 +11,4 @@ eval-results/
11
  eval-queue-bk/
12
  eval-results-bk/
13
  logs/
 
 
11
  eval-queue-bk/
12
  eval-results-bk/
13
  logs/
14
+ output-data/
Dockerfile CHANGED
@@ -1,4 +1,4 @@
1
- FROM python:3.9
2
 
3
  WORKDIR /code
4
 
@@ -6,7 +6,17 @@ COPY ./requirements.txt /code/requirements.txt
6
 
7
  RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt
8
 
9
- COPY . .
 
 
 
 
 
 
 
 
 
 
10
 
11
 
12
  EXPOSE 7860
 
1
+ FROM python:3.10
2
 
3
  WORKDIR /code
4
 
 
6
 
7
  RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt
8
 
9
+ COPY scripts /code/scripts
10
+ COPY src /code/src
11
+
12
+ COPY app.py /code/app.py
13
+ COPY main_backend.py /code/main_backend.py
14
+
15
+ # to generate adhoc result files --> to be deleted once generation pipeline is stable
16
+ COPY adhoc.py /code/adhoc.py
17
+
18
+ # answer and score generation pipeline
19
+ COPY generation.py /code/generation.py
20
 
21
 
22
  EXPOSE 7860
generation.py ADDED
@@ -0,0 +1,158 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from lamini.generation.generation_node import GenerationNode
2
+ from lamini.generation.generation_pipeline import GenerationPipeline
3
+ from lamini.generation.base_prompt_object import PromptObject
4
+ from typing import Union, Iterator, AsyncIterator
5
+ from src.backend.lamini_eval.datasets.ecommerce.shopping_dataset import load_shopping_dataset
6
+ from src.envs import DATASET_PATH, LAMINI_API_KEY
7
+ import logging
8
+ import asyncio
9
+ import lamini
10
+ import jsonlines
11
+ from tqdm import tqdm
12
+
13
+
14
+ lamini.api_key = LAMINI_API_KEY
15
+
16
+ logger = logging.getLogger(__name__)
17
+
18
+ logging.basicConfig(
19
+ level=logging.DEBUG,
20
+ format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
21
+ )
22
+
23
+
24
+ class AnswerScorePipeline(GenerationPipeline):
25
+ def __init__(self):
26
+ super(AnswerScorePipeline, self).__init__()
27
+
28
+ self.answer_generator = AnswerGenerator()
29
+ self.score_generator = ScoreGenerator()
30
+
31
+ def forward(self, x):
32
+ ans = self.answer_generator(x)
33
+ score = self.score_generator(ans)
34
+ return score
35
+
36
+
37
+ class AnswerGenerator(GenerationNode):
38
+ def __init__(self):
39
+ super(AnswerGenerator, self).__init__(
40
+ model_name="mistralai/Mistral-7B-Instruct-v0.1", max_tokens=200
41
+ )
42
+
43
+ def generate(
44
+ self,
45
+ prompt: Union[Iterator[PromptObject], AsyncIterator[PromptObject]],
46
+ *args,
47
+ **kwargs,
48
+ ):
49
+ prompts = self.transform_prompt(prompt)
50
+ op_type = {
51
+ "product_name": "str",
52
+ "product_description": "str",
53
+ "product_id": "str"
54
+ }
55
+ results = super(AnswerGenerator, self).generate(prompts, output_type=op_type, *args, **kwargs)
56
+ processed_results = self.process_results(results)
57
+ return processed_results
58
+
59
+ async def process_results(self, results):
60
+ async for result in results:
61
+ logger.info(f"Generated answer for {result}")
62
+ if result is None:
63
+ continue
64
+ yield result
65
+
66
+ async def transform_prompt(self, prompts):
67
+ async for prompt in prompts:
68
+ prompt.prompt = self.make_prompt(prompt)
69
+ yield prompt
70
+
71
+ def make_prompt(self, chunk):
72
+ prompt = (
73
+ "You are an expert shopper at Instacart."
74
+ )
75
+ prompt += "You are helping a customer find a product. "
76
+ prompt += "Include the product name, id, and detailed description in your answer. "
77
+ prompt += "A product id is a number between 0 and 100,000. "
78
+ prompt += "The customer asks\n"
79
+ prompt += chunk.data["question"]
80
+ print("prompt:", prompt)
81
+ return prompt
82
+
83
+
84
+ class ScoreGenerator(GenerationNode):
85
+ def __init__(self):
86
+ super(ScoreGenerator, self).__init__(
87
+ model_name="mistralai/Mistral-7B-Instruct-v0.1", max_tokens=200
88
+ )
89
+
90
+ def generate(
91
+ self,
92
+ prompt: Union[Iterator[PromptObject], AsyncIterator[PromptObject]],
93
+ *args,
94
+ **kwargs,
95
+ ):
96
+ prompts = self.transform_prompt(prompt)
97
+ results = super(ScoreGenerator, self).generate(prompts, *args, **kwargs)
98
+ processed_results = self.process_results(results)
99
+ return processed_results
100
+
101
+ async def process_results(self, results):
102
+ async for result in results:
103
+ logger.info(f"Generated score for {result}")
104
+ if result is None:
105
+ continue
106
+ yield result
107
+
108
+ async def transform_prompt(self, prompts):
109
+ async for prompt in prompts:
110
+ prompt.data["question"] = prompt.prompt
111
+ prompt.prompt = self.make_prompt(prompt)
112
+ yield prompt
113
+
114
+ def make_prompt(self, chunk):
115
+ prompt = (
116
+ "A model is going to answer a question. Your job is to score the answer, comparing it to a golden reference. You are an expert scorer.\n\n"
117
+ )
118
+ prompt += f"Rate the answer using a score from 1 (lowest match) to 5 (highest match).\n"
119
+ prompt += chunk.data["rubric"]
120
+ prompt += "Use the full range. Read the gold answer carefully. "
121
+ prompt += "Explain your score in 2-3 short sentences not exceeding 100 words each, then assign a score. "
122
+ prompt += "Output your score as a JSON object in the format {\"explanation\" : str, \"score\" : int}\n"
123
+ prompt += "Use single quotes within your explanation. End your explanation with a double quote.\n"
124
+ prompt += "Prefer answers that are most similar to the gold answer, even if the gold answer refused to answer the question.\n\n"
125
+ prompt += f"========== question =========\n{chunk.data['question']}\n\n"
126
+ prompt += f"========== gold answer =========\n{chunk.data['expected_response']}\n\n"
127
+ prompt += f"========== model answer =========\n{chunk.data['response']}\n\n"
128
+ prompt += "=" * 40 + "\n\n"
129
+ prompt += f"How would you score the model's answer compared to the gold answer (using the 1-5 scale defined above)?\n\n"
130
+ print("prompt:", prompt)
131
+ return prompt
132
+
133
+
134
+ async def main():
135
+ dataset = load_shopping_dataset(DATASET_PATH)
136
+
137
+ answers = AnswerScorePipeline().call(dataset)
138
+ await print_answers(answers)
139
+
140
+
141
+ async def print_answers(answers):
142
+ path = "/code/data/model-answers.jsonl"
143
+
144
+ with jsonlines.open(path, "w") as writer:
145
+ pbar = tqdm(desc="Saving answers", unit=" answers")
146
+ async for answer in answers:
147
+ answer = {
148
+ "prompt": answer.prompt,
149
+ "question": answer.data["question"],
150
+ "answer": answer.response,
151
+ }
152
+ print(f"\n\n=======\n{answer}\n\n")
153
+ writer.write(answer)
154
+ pbar.update()
155
+
156
+
157
+ if __name__ == "__main__":
158
+ asyncio.run(main())
run-adhoc.sh CHANGED
@@ -1,2 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
1
  docker buildx build --platform=linux/amd64 -t adhoc .
2
- docker run -it --rm --platform=linux/amd64 -e TOKEN=$TOKEN adhoc python adhoc.py
 
1
+ #!/bin/bash
2
+
3
+ # Safely execute this bash script
4
+ # e exit on first failure
5
+ # x all executed commands are printed to the terminal
6
+ # u unset variables are errors
7
+ # a export all variables to the environment
8
+ # E any trap on ERR is inherited by shell functions
9
+ # -o pipefail | produces a failure code if any stage fails
10
+ set -Eeuoxa pipefail
11
+
12
  docker buildx build --platform=linux/amd64 -t adhoc .
13
+ docker run -it --rm --platform=linux/amd64 adhoc python adhoc.py
run-pipeline.sh ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/bin/bash
2
+
3
+ # Safely execute this bash script
4
+ # e exit on first failure
5
+ # x all executed commands are printed to the terminal
6
+ # u unset variables are errors
7
+ # a export all variables to the environment
8
+ # E any trap on ERR is inherited by shell functions
9
+ # -o pipefail | produces a failure code if any stage fails
10
+ set -Eeuoxa pipefail
11
+
12
+ LOCAL_DIRECTORY="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
13
+
14
+ docker buildx build --platform=linux/amd64 -t pipeline .
15
+ docker run -it --rm --platform=linux/amd64 -v $LOCAL_DIRECTORY/output-data:/code/data pipeline python3 generation.py
start.sh CHANGED
@@ -1,5 +1,14 @@
1
  #!/bin/bash
2
 
 
 
 
 
 
 
 
 
 
3
  for ARGUMENT in "$@"
4
  do
5
  KEY=$(echo $ARGUMENT | cut -f1 -d=)
@@ -15,4 +24,4 @@ echo "Run mode is: $RUN_MODE"
15
  echo "Model passed is: $LOCAL_MODEL_NAME"
16
 
17
  docker buildx build --platform=linux/amd64 -t ldr .
18
- docker run -it --rm -p 7860:7860 --platform=linux/amd64 -e TOKEN=$TOKEN -e RUN_MODE=$RUN_MODE -e LOCAL_MODEL_NAME=$LOCAL_MODEL_NAME ldr python app.py
 
1
  #!/bin/bash
2
 
3
+ # Safely execute this bash script
4
+ # e exit on first failure
5
+ # x all executed commands are printed to the terminal
6
+ # u unset variables are errors
7
+ # a export all variables to the environment
8
+ # E any trap on ERR is inherited by shell functions
9
+ # -o pipefail | produces a failure code if any stage fails
10
+ set -Eeuoxa pipefail
11
+
12
  for ARGUMENT in "$@"
13
  do
14
  KEY=$(echo $ARGUMENT | cut -f1 -d=)
 
24
  echo "Model passed is: $LOCAL_MODEL_NAME"
25
 
26
  docker buildx build --platform=linux/amd64 -t ldr .
27
+ docker run -it --rm -p 7860:7860 --platform=linux/amd64 -e RUN_MODE=$RUN_MODE -e LOCAL_MODEL_NAME=$LOCAL_MODEL_NAME ldr python app.py