ReverseCoder1 commited on
Commit
443c45a
Β·
1 Parent(s): 2d793d9

make reward dynamic based oon action sequence

Browse files
Files changed (5) hide show
  1. Dockerfile +2 -1
  2. README.md +46 -21
  3. environment.py +68 -2
  4. inference.py +4 -0
  5. openenv.yaml +5 -4
Dockerfile CHANGED
@@ -11,7 +11,8 @@ RUN pip install --no-cache-dir \
11
  pandas==2.1.3 \
12
  numpy==1.26.2 \
13
  openai==1.3.7 \
14
- pyyaml==6.0.1
 
15
 
16
  # Copy all project files
17
  COPY . .
 
11
  pandas==2.1.3 \
12
  numpy==1.26.2 \
13
  openai==1.3.7 \
14
+ pyyaml==6.0.1 \
15
+ python-dotenv==1.0.0
16
 
17
  # Copy all project files
18
  COPY . .
README.md CHANGED
@@ -108,7 +108,10 @@ run a complete cleaning pipeline in the right sequence.
108
 
109
  ## πŸ† Reward Function
110
 
111
- Rewards are computed after every step providing dense signal:
 
 
 
112
 
113
  | Component | Description |
114
  |-----------|-------------|
@@ -117,9 +120,47 @@ Rewards are computed after every step providing dense signal:
117
  | dtype_score | Proportion of columns with correct data types |
118
  | outlier_score | How close numeric distributions are to gold |
119
  | schema_score | Proportion of column names matching gold |
120
- | penalty | Small penalty for using too many steps |
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
121
 
122
- **Total reward = weighted sum of components (0.0 to 1.0)**
 
 
 
 
 
 
 
 
 
 
 
 
123
 
124
  ---
125
 
@@ -162,29 +203,13 @@ state = requests.get(
162
  ### Run Baseline Inference
163
  ```bash
164
  export HF_TOKEN=your_token_here
165
- export MODEL_NAME=meta-llama/Llama-3.3-70B-Instruct
166
- export API_BASE_URL=https://router.huggingface.co/v1
167
 
168
  python inference.py
169
  ```
170
 
171
  ---
172
-
173
- ## πŸ“Š Baseline Scores
174
-
175
- Scores produced by `meta-llama/Llama-3.3-70B-Instruct`:
176
-
177
- | Task | Score |
178
- |------|-------|
179
- | easy_dedup_rename | 1.0000 |
180
- | medium_missing_dtype | 1.0000 |
181
- | hard_full_pipeline | 1.0000 |
182
- | expert_sales_pipeline | 1.0000 |
183
- | **Average** | **1.0000** |
184
-
185
- ---
186
-
187
- ## πŸ“ Project Structure
188
  ```
189
  data-cleaning-openenv/
190
  β”œβ”€β”€ main.py # FastAPI server
 
108
 
109
  ## πŸ† Reward Function
110
 
111
+ Rewards are computed after every step providing dense signal for each data quality component.
112
+ **Importantly, the reward function penalizes out-of-order operations**, encouraging agents to follow the optimal data cleaning sequence.
113
+
114
+ ### Reward Components
115
 
116
  | Component | Description |
117
  |-----------|-------------|
 
120
  | dtype_score | Proportion of columns with correct data types |
121
  | outlier_score | How close numeric distributions are to gold |
122
  | schema_score | Proportion of column names matching gold |
123
+ | penalty | Penalty for out-of-order operations or too many steps |
124
+
125
+ ### Sequence Penalties
126
+
127
+ The reward function enforces optimal operation order:
128
+
129
+ ```
130
+ Optimal Sequence:
131
+ 1. Remove Duplicates (clean redundant data first)
132
+ 2. Fix Data Types (understand structure)
133
+ 3. Fill Missing Values (based on correct types)
134
+ 4. Remove Outliers (after understanding distribution)
135
+ 5. Validate Schema (final verification)
136
+ ```
137
+
138
+ **Penalty Rules:**
139
+ - **Out-of-order operation:** -0.08 (e.g., filling missing before fixing types)
140
+ - **Repeated operation:** -0.02 (e.g., filling missing twice in a row)
141
+ - **Exceeded step limit:** -0.05 (using >80% of max_steps)
142
+
143
+ **Total reward = weighted sum of components - penalties (0.0 to 1.0)**
144
+
145
+ For example:
146
+ - Good sequence β†’ Rewards improve with each step toward 1.0 βœ…
147
+ - Bad sequence β†’ Rewards degrade as penalties accumulate ❌
148
+
149
+ ---
150
 
151
+ ## πŸ“Š Baseline Scores
152
+
153
+ Baseline scores with **gpt-4o-mini** (sequence-aware reward function):
154
+
155
+ | Task | Difficulty | Score | Notes |
156
+ |------|-----------|-------|-------|
157
+ | easy_dedup_rename | Easy | 0.9900 | Follows optimal sequence |
158
+ | medium_missing_dtype | Medium | 0.7000 | Some out-of-order operations |
159
+ | hard_full_pipeline | Hard | 0.6636 | Oscillates between operations |
160
+ | **Average** | - | **0.7845** | Room for improvement |
161
+
162
+ **Note:** Scores are lower than original because agents sometimes violate the sequence.
163
+ This is intentionalβ€”it teaches agents the correct workflow!
164
 
165
  ---
166
 
 
203
  ### Run Baseline Inference
204
  ```bash
205
  export HF_TOKEN=your_token_here
206
+ export MODEL_NAME=gpt-4o-mini
207
+ export API_BASE_URL=https://api.openai.com/v1
208
 
209
  python inference.py
210
  ```
211
 
212
  ---
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
213
  ```
214
  data-cleaning-openenv/
215
  β”œβ”€β”€ main.py # FastAPI server
environment.py CHANGED
@@ -32,6 +32,7 @@ class DataCleaningEnv:
32
  self.done: bool = False
33
  self.max_steps: int = 10
34
  self.reward_history = []
 
35
  self._load_task_metadata()
36
 
37
  # ─────────────────────────────────────────
@@ -113,6 +114,62 @@ class DataCleaningEnv:
113
  message=message
114
  )
115
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
116
  def _compute_reward(self) -> Reward:
117
  df = self.current_df
118
  gold = self.gold_df
@@ -194,10 +251,15 @@ class DataCleaningEnv:
194
  matched = sum(1 for c in gold_cols if c in curr_cols)
195
  schema_score = matched / len(gold_cols) if gold_cols else 0.0
196
 
197
- # ── Penalty for too many steps ───────────────────────────────
198
  step_ratio = self.step_count / self.max_steps
 
199
  if step_ratio > 0.8:
200
- penalty = 0.05
 
 
 
 
201
 
202
  # ── Weighted total ───────────────────────────────────────────
203
  weights = {
@@ -388,6 +450,7 @@ class DataCleaningEnv:
388
  self.step_count = 0
389
  self.done = False
390
  self.reward_history = []
 
391
 
392
  obs = self._get_observation("Environment reset. Start cleaning!")
393
  reward = Reward(total=0.0)
@@ -442,6 +505,9 @@ class DataCleaningEnv:
442
  except Exception as e:
443
  message = f"Operation failed: {str(e)}"
444
 
 
 
 
445
  # ── Check max steps ──────────────────────────────────────────
446
  if self.step_count >= self.max_steps:
447
  self.done = True
 
32
  self.done: bool = False
33
  self.max_steps: int = 10
34
  self.reward_history = []
35
+ self.actions_taken: List[str] = [] # Track sequence of actions
36
  self._load_task_metadata()
37
 
38
  # ─────────────────────────────────────────
 
114
  message=message
115
  )
116
 
117
+ def _compute_sequence_penalty(self) -> float:
118
+ """
119
+ Penalize illogical action sequences.
120
+
121
+ Optimal sequence:
122
+ 1. remove_duplicates (clean up redundant data)
123
+ 2. fix_dtype (understand structure)
124
+ 3. fill_missing (based on correct types)
125
+ 4. remove_outliers (after understanding distribution)
126
+ 5. validate_schema (final check)
127
+
128
+ Penalties:
129
+ - Doing operations out of order: -0.05 per violation
130
+ - Repeating same operation: -0.02 per repeat
131
+ """
132
+ OPTIMAL_ORDER = [
133
+ "remove_duplicates",
134
+ "fix_dtype",
135
+ "fill_missing_mean",
136
+ "fill_missing_mode",
137
+ "fill_missing_median",
138
+ "remove_outliers",
139
+ "validate_schema",
140
+ ]
141
+
142
+ penalty = 0.0
143
+ last_order_idx = -1
144
+ prev_action = None
145
+
146
+ # Track positions of operations in optimal order
147
+ for action in self.actions_taken:
148
+ if action == "finish":
149
+ continue
150
+
151
+ # Penalize repeated same actions (doing same thing twice in a row)
152
+ if action == prev_action and action not in ["fill_missing_mean", "fill_missing_mode", "fill_missing_median", "remove_outliers"]:
153
+ penalty += 0.02
154
+
155
+ # Find this action in optimal order
156
+ if action in OPTIMAL_ORDER:
157
+ current_idx = OPTIMAL_ORDER.index(action)
158
+
159
+ # Penalize out-of-order operations
160
+ if current_idx < last_order_idx:
161
+ # Going backward in sequence (e.g., doing remove_duplicates after fill_missing)
162
+ penalty += 0.08
163
+
164
+ last_order_idx = current_idx
165
+ else:
166
+ # Unknown operation
167
+ penalty += 0.01
168
+
169
+ prev_action = action
170
+
171
+ return min(0.25, penalty) # Cap penalty at 0.25
172
+
173
  def _compute_reward(self) -> Reward:
174
  df = self.current_df
175
  gold = self.gold_df
 
251
  matched = sum(1 for c in gold_cols if c in curr_cols)
252
  schema_score = matched / len(gold_cols) if gold_cols else 0.0
253
 
254
+ # ── Penalty for too many steps + sequence violations ─────────────
255
  step_ratio = self.step_count / self.max_steps
256
+ base_penalty = 0.0
257
  if step_ratio > 0.8:
258
+ base_penalty = 0.05
259
+
260
+ # Add sequence-based penalty
261
+ sequence_penalty = self._compute_sequence_penalty()
262
+ penalty = base_penalty + sequence_penalty
263
 
264
  # ── Weighted total ───────────────────────────────────────────
265
  weights = {
 
450
  self.step_count = 0
451
  self.done = False
452
  self.reward_history = []
453
+ self.actions_taken = [] # Reset action history
454
 
455
  obs = self._get_observation("Environment reset. Start cleaning!")
456
  reward = Reward(total=0.0)
 
505
  except Exception as e:
506
  message = f"Operation failed: {str(e)}"
507
 
508
+ # ── Track action for sequence penalties ───────────────────────────
509
+ self.actions_taken.append(action.operation)
510
+
511
  # ── Check max steps ──────────────────────────────────────────
512
  if self.step_count >= self.max_steps:
513
  self.done = True
inference.py CHANGED
@@ -15,9 +15,13 @@ import sys
15
  import json
16
  import time
17
  from typing import List, Dict, Any
 
18
 
19
  from openai import OpenAI
20
 
 
 
 
21
  # ─────────────────────────────────────────
22
  # CONFIG
23
  # ─────────────────────────────────────────
 
15
  import json
16
  import time
17
  from typing import List, Dict, Any
18
+ from dotenv import load_dotenv
19
 
20
  from openai import OpenAI
21
 
22
+ # Load environment variables from .env file
23
+ load_dotenv()
24
+
25
  # ─────────────────────────────────────────
26
  # CONFIG
27
  # ─────────────────────────────────────────
openenv.yaml CHANGED
@@ -97,10 +97,11 @@ reward_space:
97
 
98
  baseline_scores:
99
  model: gpt-4o-mini
100
- easy_dedup_rename: 1.0000
101
- medium_missing_dtype: 0.6643
102
- hard_full_pipeline: 0.8386
103
- average: 0.8343
 
104
 
105
  runtime:
106
  language: python
 
97
 
98
  baseline_scores:
99
  model: gpt-4o-mini
100
+ description: Sequence-aware reward function (rewards optimal order of operations)
101
+ easy_dedup_rename: 0.9900
102
+ medium_missing_dtype: 0.7000
103
+ hard_full_pipeline: 0.6636
104
+ average: 0.7845
105
 
106
  runtime:
107
  language: python