Spaces:
Running
Running
adds update attribute for trl compatibility
Browse files- docs/TRACKIO_UPDATE_FIX.md +90 -0
- src/trackio.py +14 -0
- tests/test_trackio_update_fix.py +127 -0
- tests/test_update_fix.py +27 -0
docs/TRACKIO_UPDATE_FIX.md
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# TrackioConfig Update Method Fix
|
| 2 |
+
|
| 3 |
+
## Problem Description
|
| 4 |
+
|
| 5 |
+
The error `'TrackioConfig' object has no attribute 'update'` occurred because the TRL library (specifically SFTTrainer) expects the Trackio configuration object to have an `update` method, but our custom `TrackioConfig` class didn't implement it.
|
| 6 |
+
|
| 7 |
+
## Root Cause
|
| 8 |
+
|
| 9 |
+
Based on the [Trackio documentation](https://github.com/gradio-app/trackio?tab=readme-ov-file), Trackio is designed to be API compatible with `wandb.init`, `wandb.log`, and `wandb.finish`. However, the TRL library has additional expectations for the configuration object, including an `update` method that allows dynamic configuration updates.
|
| 10 |
+
|
| 11 |
+
## Solution Implementation
|
| 12 |
+
|
| 13 |
+
### 1. Added Update Method to TrackioConfig
|
| 14 |
+
|
| 15 |
+
Modified `src/trackio.py` to add the missing `update` method:
|
| 16 |
+
|
| 17 |
+
```python
|
| 18 |
+
class TrackioConfig:
|
| 19 |
+
"""Configuration class for trackio (TRL compatibility)"""
|
| 20 |
+
|
| 21 |
+
def __init__(self):
|
| 22 |
+
self.project_name = os.environ.get('EXPERIMENT_NAME', 'smollm3_experiment')
|
| 23 |
+
self.experiment_name = os.environ.get('EXPERIMENT_NAME', 'smollm3_experiment')
|
| 24 |
+
self.trackio_url = os.environ.get('TRACKIO_URL')
|
| 25 |
+
self.trackio_token = os.environ.get('TRACKIO_TOKEN')
|
| 26 |
+
self.hf_token = os.environ.get('HF_TOKEN')
|
| 27 |
+
self.dataset_repo = os.environ.get('TRACKIO_DATASET_REPO', 'tonic/trackio-experiments')
|
| 28 |
+
|
| 29 |
+
def update(self, config_dict: Dict[str, Any]):
|
| 30 |
+
"""
|
| 31 |
+
Update configuration with new values (TRL compatibility)
|
| 32 |
+
|
| 33 |
+
Args:
|
| 34 |
+
config_dict: Dictionary of configuration values to update
|
| 35 |
+
"""
|
| 36 |
+
for key, value in config_dict.items():
|
| 37 |
+
if hasattr(self, key):
|
| 38 |
+
setattr(self, key, value)
|
| 39 |
+
else:
|
| 40 |
+
# Add new attributes dynamically
|
| 41 |
+
setattr(self, key, value)
|
| 42 |
+
```
|
| 43 |
+
|
| 44 |
+
### 2. Key Features of the Fix
|
| 45 |
+
|
| 46 |
+
- **Dynamic Attribute Updates**: The `update` method can update existing attributes and add new ones dynamically
|
| 47 |
+
- **TRL Compatibility**: Satisfies TRL's expectation for a config object with an `update` method
|
| 48 |
+
- **Backward Compatibility**: Doesn't break existing functionality
|
| 49 |
+
- **Flexible Configuration**: Allows runtime configuration updates
|
| 50 |
+
|
| 51 |
+
### 3. Usage Example
|
| 52 |
+
|
| 53 |
+
```python
|
| 54 |
+
import trackio
|
| 55 |
+
|
| 56 |
+
# Access the config
|
| 57 |
+
config = trackio.config
|
| 58 |
+
|
| 59 |
+
# Update configuration
|
| 60 |
+
config.update({
|
| 61 |
+
'project_name': 'my_experiment',
|
| 62 |
+
'experiment_name': 'test_run_1',
|
| 63 |
+
'custom_setting': 'value'
|
| 64 |
+
})
|
| 65 |
+
|
| 66 |
+
# New attributes are added dynamically
|
| 67 |
+
print(config.custom_setting) # Output: 'value'
|
| 68 |
+
```
|
| 69 |
+
|
| 70 |
+
## Verification
|
| 71 |
+
|
| 72 |
+
The fix has been verified to work correctly:
|
| 73 |
+
|
| 74 |
+
1. **Import Test**: `import trackio` works without errors
|
| 75 |
+
2. **Config Access**: `trackio.config` is available
|
| 76 |
+
3. **Update Method**: `trackio.config.update()` method exists and works
|
| 77 |
+
4. **TRL Compatibility**: All TRL-expected methods are available
|
| 78 |
+
|
| 79 |
+
## Benefits
|
| 80 |
+
|
| 81 |
+
1. **Resolves Training Error**: Fixes the `'TrackioConfig' object has no attribute 'update'` error
|
| 82 |
+
2. **Maintains TRL Compatibility**: Ensures SFTTrainer can use Trackio for logging
|
| 83 |
+
3. **Dynamic Configuration**: Allows runtime configuration updates
|
| 84 |
+
4. **Future-Proof**: Supports additional TRL requirements
|
| 85 |
+
|
| 86 |
+
## Related Documentation
|
| 87 |
+
|
| 88 |
+
- [Trackio TRL Fix Summary](TRACKIO_TRL_FIX_SUMMARY.md)
|
| 89 |
+
- [Trackio Integration Guide](TRACKIO_INTEGRATION.md)
|
| 90 |
+
- [Monitoring Integration Guide](MONITORING_INTEGRATION_GUIDE.md)
|
src/trackio.py
CHANGED
|
@@ -213,6 +213,20 @@ class TrackioConfig:
|
|
| 213 |
self.trackio_token = os.environ.get('TRACKIO_TOKEN')
|
| 214 |
self.hf_token = os.environ.get('HF_TOKEN')
|
| 215 |
self.dataset_repo = os.environ.get('TRACKIO_DATASET_REPO', 'tonic/trackio-experiments')
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 216 |
|
| 217 |
# Create config instance
|
| 218 |
config = TrackioConfig()
|
|
|
|
| 213 |
self.trackio_token = os.environ.get('TRACKIO_TOKEN')
|
| 214 |
self.hf_token = os.environ.get('HF_TOKEN')
|
| 215 |
self.dataset_repo = os.environ.get('TRACKIO_DATASET_REPO', 'tonic/trackio-experiments')
|
| 216 |
+
|
| 217 |
+
def update(self, config_dict: Dict[str, Any]):
|
| 218 |
+
"""
|
| 219 |
+
Update configuration with new values (TRL compatibility)
|
| 220 |
+
|
| 221 |
+
Args:
|
| 222 |
+
config_dict: Dictionary of configuration values to update
|
| 223 |
+
"""
|
| 224 |
+
for key, value in config_dict.items():
|
| 225 |
+
if hasattr(self, key):
|
| 226 |
+
setattr(self, key, value)
|
| 227 |
+
else:
|
| 228 |
+
# Add new attributes dynamically
|
| 229 |
+
setattr(self, key, value)
|
| 230 |
|
| 231 |
# Create config instance
|
| 232 |
config = TrackioConfig()
|
tests/test_trackio_update_fix.py
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""
|
| 3 |
+
Test script to verify TrackioConfig update method fix
|
| 4 |
+
"""
|
| 5 |
+
|
| 6 |
+
import sys
|
| 7 |
+
import os
|
| 8 |
+
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
| 9 |
+
|
| 10 |
+
def test_trackio_config_update():
|
| 11 |
+
"""Test that TrackioConfig update method works correctly"""
|
| 12 |
+
print("π§ͺ Testing TrackioConfig update method...")
|
| 13 |
+
|
| 14 |
+
try:
|
| 15 |
+
# Import trackio module
|
| 16 |
+
import trackio
|
| 17 |
+
|
| 18 |
+
# Test that config attribute exists
|
| 19 |
+
assert hasattr(trackio, 'config'), "trackio.config not found"
|
| 20 |
+
print("β
trackio.config exists")
|
| 21 |
+
|
| 22 |
+
# Test that config has update method
|
| 23 |
+
config = trackio.config
|
| 24 |
+
assert hasattr(config, 'update'), "TrackioConfig.update method not found"
|
| 25 |
+
print("β
TrackioConfig.update method exists")
|
| 26 |
+
|
| 27 |
+
# Test update method functionality
|
| 28 |
+
test_config = {
|
| 29 |
+
'project_name': 'test_project',
|
| 30 |
+
'experiment_name': 'test_experiment',
|
| 31 |
+
'new_attribute': 'test_value'
|
| 32 |
+
}
|
| 33 |
+
|
| 34 |
+
# Call update method
|
| 35 |
+
config.update(test_config)
|
| 36 |
+
|
| 37 |
+
# Verify updates
|
| 38 |
+
assert config.project_name == 'test_project', f"Expected 'test_project', got '{config.project_name}'"
|
| 39 |
+
assert config.experiment_name == 'test_experiment', f"Expected 'test_experiment', got '{config.experiment_name}'"
|
| 40 |
+
assert config.new_attribute == 'test_value', f"Expected 'test_value', got '{config.new_attribute}'"
|
| 41 |
+
|
| 42 |
+
print("β
TrackioConfig.update method works correctly")
|
| 43 |
+
print("β
All attributes updated successfully")
|
| 44 |
+
|
| 45 |
+
return True
|
| 46 |
+
|
| 47 |
+
except Exception as e:
|
| 48 |
+
print(f"β Test failed: {e}")
|
| 49 |
+
return False
|
| 50 |
+
|
| 51 |
+
def test_trackio_trl_compatibility():
|
| 52 |
+
"""Test that trackio is fully compatible with TRL expectations"""
|
| 53 |
+
print("\nπ Testing TRL Compatibility...")
|
| 54 |
+
|
| 55 |
+
try:
|
| 56 |
+
import trackio
|
| 57 |
+
|
| 58 |
+
# Test all required functions exist
|
| 59 |
+
required_functions = ['init', 'log', 'finish']
|
| 60 |
+
for func_name in required_functions:
|
| 61 |
+
assert hasattr(trackio, func_name), f"trackio.{func_name} not found"
|
| 62 |
+
print(f"β
trackio.{func_name} exists")
|
| 63 |
+
|
| 64 |
+
# Test config attribute exists and has update method
|
| 65 |
+
assert hasattr(trackio, 'config'), "trackio.config not found"
|
| 66 |
+
assert hasattr(trackio.config, 'update'), "trackio.config.update not found"
|
| 67 |
+
print("β
trackio.config.update exists")
|
| 68 |
+
|
| 69 |
+
# Test that init can be called without arguments (TRL compatibility)
|
| 70 |
+
try:
|
| 71 |
+
experiment_id = trackio.init()
|
| 72 |
+
print(f"β
trackio.init() called successfully: {experiment_id}")
|
| 73 |
+
except Exception as e:
|
| 74 |
+
print(f"β trackio.init() failed: {e}")
|
| 75 |
+
return False
|
| 76 |
+
|
| 77 |
+
# Test that log can be called
|
| 78 |
+
try:
|
| 79 |
+
trackio.log({'test_metric': 1.0})
|
| 80 |
+
print("β
trackio.log() called successfully")
|
| 81 |
+
except Exception as e:
|
| 82 |
+
print(f"β trackio.log() failed: {e}")
|
| 83 |
+
return False
|
| 84 |
+
|
| 85 |
+
# Test that finish can be called
|
| 86 |
+
try:
|
| 87 |
+
trackio.finish()
|
| 88 |
+
print("β
trackio.finish() called successfully")
|
| 89 |
+
except Exception as e:
|
| 90 |
+
print(f"β trackio.finish() failed: {e}")
|
| 91 |
+
return False
|
| 92 |
+
|
| 93 |
+
print("β
All TRL compatibility tests passed")
|
| 94 |
+
return True
|
| 95 |
+
|
| 96 |
+
except Exception as e:
|
| 97 |
+
print(f"β TRL compatibility test failed: {e}")
|
| 98 |
+
return False
|
| 99 |
+
|
| 100 |
+
def main():
|
| 101 |
+
"""Run all tests"""
|
| 102 |
+
print("π§ͺ TrackioConfig Update Fix Test")
|
| 103 |
+
print("=" * 40)
|
| 104 |
+
|
| 105 |
+
# Test 1: Update method functionality
|
| 106 |
+
test1_passed = test_trackio_config_update()
|
| 107 |
+
|
| 108 |
+
# Test 2: TRL compatibility
|
| 109 |
+
test2_passed = test_trackio_trl_compatibility()
|
| 110 |
+
|
| 111 |
+
# Summary
|
| 112 |
+
print("\n" + "=" * 40)
|
| 113 |
+
print("π Test Results Summary")
|
| 114 |
+
print("=" * 40)
|
| 115 |
+
print(f"β
Update Method Test: {'PASSED' if test1_passed else 'FAILED'}")
|
| 116 |
+
print(f"β
TRL Compatibility Test: {'PASSED' if test2_passed else 'FAILED'}")
|
| 117 |
+
|
| 118 |
+
if test1_passed and test2_passed:
|
| 119 |
+
print("\nπ All tests passed! TrackioConfig update fix is working correctly.")
|
| 120 |
+
return True
|
| 121 |
+
else:
|
| 122 |
+
print("\nβ Some tests failed. Please check the implementation.")
|
| 123 |
+
return False
|
| 124 |
+
|
| 125 |
+
if __name__ == "__main__":
|
| 126 |
+
success = main()
|
| 127 |
+
sys.exit(0 if success else 1)
|
tests/test_update_fix.py
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""
|
| 3 |
+
Simple test for TrackioConfig update method fix
|
| 4 |
+
"""
|
| 5 |
+
|
| 6 |
+
import trackio
|
| 7 |
+
|
| 8 |
+
print("Testing TrackioConfig update method...")
|
| 9 |
+
|
| 10 |
+
# Test that config exists and has update method
|
| 11 |
+
config = trackio.config
|
| 12 |
+
print(f"Config type: {type(config)}")
|
| 13 |
+
print(f"Has update method: {hasattr(config, 'update')}")
|
| 14 |
+
|
| 15 |
+
# Test update functionality
|
| 16 |
+
test_data = {
|
| 17 |
+
'project_name': 'test_project',
|
| 18 |
+
'experiment_name': 'test_experiment',
|
| 19 |
+
'new_attribute': 'test_value'
|
| 20 |
+
}
|
| 21 |
+
|
| 22 |
+
print(f"Before update - project_name: {config.project_name}")
|
| 23 |
+
config.update(test_data)
|
| 24 |
+
print(f"After update - project_name: {config.project_name}")
|
| 25 |
+
print(f"New attribute: {config.new_attribute}")
|
| 26 |
+
|
| 27 |
+
print("β
Update method works correctly!")
|