Compare commits

...

50 Commits

Author SHA1 Message Date
you-n-g ce72d30139 chore(main): release 0.2.1 (#249)
Release-As: 0.2.1
2024-09-10 19:43:54 +08:00
Linlang 92c46a66b6 fix: fix_dotenv_error (#257)
* fix_dotenv_error

* format with isort

* Update rdagent/app/cli.py

---------

Co-authored-by: you-n-g <you-n-g@users.noreply.github.com>
2024-09-10 19:38:35 +08:00
you-n-g df1f5e9390 fix: default model value in config (#256)
* fix: git default model value

* Update README.md
2024-09-10 12:49:06 +08:00
you-n-g 144d0f13b8 docs: Update Link to Papers & Qlib (#253)
* Update README.md

* Update README.md

* Update README.md

* Update README.md

* Update README.md

* Update README.md

* Update README.md

* Update README.md
2024-09-10 12:33:37 +08:00
XianBW d90ad532dc docs: links update (#251)
* add trace download link in README

* update video links in doc
2024-09-09 15:34:26 +08:00
Suhan Cui 3b15bca356 fix: readme (#248)
* Update README.md

* Update model_agent_med.rst
2024-09-08 07:31:39 +08:00
Suhan Cui c6424e5250 Update README.md (#246) 2024-09-07 05:50:13 -04:00
you-n-g 34a63d4b7f chore(main): release 0.2.0 (#202)
Release-As: 0.2.0
2024-09-07 12:58:19 +08:00
Linlang de8e310d6b feat: add collect info (#233)
* add collect info

* fix isort error

* optimize code

* fix black error

* Update rdagent/app/cli.py

* Modify the code according to the comments

* fix isort error

* add docker info

* docs: update contributors (#230)

* fix: package dependency. (#234)

* fix package

* fix lint

* docs: Update development.rst (#235)

* feat: add cross validation for kaggle scenario (#236)

* update cross validation for kaggle scenario

* CI Issues

* delete useless file

* CI issues

* docs: Update README.md (#245)

* docs: refine the README (#244)

* init a scenario for kaggle feature engineering

* update the readme

* Delete rdagent/app/kaggle_feature/conf.py

* update some pictures

* Delete rdagent/app/kaggle_feature/model.py

* change a photo

* add pics to docs

* update the readme

* update the README

* for a try

* for another try

* change the style of the pictures in readme

* fix a small bug

* update the readme and the docs

* update the docs

* fix a typo

* change a website url

* change some styles

* fix a typo

* change the size of the logo

* change two urls

* Update README.md

* Update README.md

* Update README.md

* Update README.md

---------

Co-authored-by: Linlang <Lv.Linlang@hotmail.com>

* move the component to other files

* last container

* optimize rdagent info

* format with isort

* format with black

* format_with_black

* fix pip error

* format with isort

* change requirements

* fix pip error

* fix_pip_error

* fix pip error

* format with black

* fix pip error

---------

Co-authored-by: you-n-g <you-n-g@users.noreply.github.com>
Co-authored-by: Haotian Chen <113661982+Hytn@users.noreply.github.com>
Co-authored-by: Haoran Pan <167847254+TPLin22@users.noreply.github.com>
Co-authored-by: Way2Learn <118058822+Xisen-Wang@users.noreply.github.com>
Co-authored-by: WinstonLiyt <104308117+WinstonLiyt@users.noreply.github.com>
Co-authored-by: Young <afe.young@gmail.com>
2024-09-07 12:37:08 +08:00
Linlang a8f1fc939c test: add test import (#242)
* add test import

* format with isort

* format with black

* merge main

* fix pytest error

* fix pytest error

* fix pytest error

* fix pytest error

* format with black

* fix pytest error

* fix pytest error

* fix pytest error

* fix pytest error

* fix pytest error

* format with isort

* Exclude entrance

* Add offline test

* auto-lint

* update coverage rate

---------

Co-authored-by: Young <afe.young@gmail.com>
2024-09-06 17:18:52 +08:00
WinstonLiyt 55256295c0 docs: refine the README (#244)
* init a scenario for kaggle feature engineering

* update the readme

* Delete rdagent/app/kaggle_feature/conf.py

* update some pictures

* Delete rdagent/app/kaggle_feature/model.py

* change a photo

* add pics to docs

* update the readme

* update the README

* for a try

* for another try

* change the style of the pictures in readme

* fix a small bug

* update the readme and the docs

* update the docs

* fix a typo

* change a website url

* change some styles

* fix a typo

* change the size of the logo

* change two urls

* Update README.md

* Update README.md

* Update README.md

* Update README.md

---------

Co-authored-by: Linlang <Lv.Linlang@hotmail.com>
2024-09-06 15:39:41 +08:00
Way2Learn a64e0c22b6 docs: Update README.md (#245) 2024-09-06 13:16:25 +08:00
Haoran Pan 261fcfb19a feat: add cross validation for kaggle scenario (#236)
* update cross validation for kaggle scenario

* CI Issues

* delete useless file

* CI issues
2024-09-01 17:41:05 +08:00
you-n-g 3d13ba058d docs: Update development.rst (#235) 2024-08-31 20:49:48 +08:00
you-n-g 44d06c2f2c fix: package dependency. (#234)
* fix package

* fix lint
2024-08-31 20:35:04 +08:00
Haotian Chen 1a84b28b6e docs: update contributors (#230) 2024-08-28 16:35:25 +08:00
WinstonLiyt 3c6415f85a feat: piloting of the framework (#227)
* Initial template

* Updated a bit on the framework

* Revised to enable feat training

* Fixed Accuracy

* fixed mcc

* change some files for feature

* update some logics in feat eng

* update some codes

* update some codes

* Revised further to successfully completed a cycle

* Revised further

* Delete two CSVs

* fix some ci errors

---------

Co-authored-by: Young <afe.young@gmail.com>
Co-authored-by: Xisen-Wang <xisen_application@163.com>
2024-08-27 17:27:11 +08:00
Way2Learn 089b45b3e1 feat: update model_experiment.py to support basic EDA (#220)
* Update model_experiment.py to support basic eda

It looks into the data first before the proposal.

* Update model_experiment.py

Revised linting

* Update model_experiment.py by fixing sorting order

* Update model_experiment.py for black linting

* Update model_experiment.py

* Update model_experiment.py

* Update model_experiment.py

* Update model_experiment.py

---------

Co-authored-by: WinstonLiyt <104308117+WinstonLiyt@users.noreply.github.com>
2024-08-26 16:38:49 +08:00
Linlang 5136ec2d57 docs: add badge & Github button & issue template (#208)
* add badge & add Github button

* add issue template

* reformat with black

* fix issue template error

* add edit on github button

* fix issue template

* change conf.py

* Update .github/ISSUE_TEMPLATE/bug-report.md

---------

Co-authored-by: you-n-g <you-n-g@users.noreply.github.com>
2024-08-26 15:14:28 +08:00
Tim 50236d10d6 fix: remove useless line (#177)
* Update Dockerfile

remove unused line

* specify a fixed version of scipy
2024-08-23 16:08:45 +08:00
TPLin22 89d4f92051 feat: support more models for kaggle scenario (#223)
* init commit for XGBoost

* fix some bugs

* CI issues

* CI issues

* CI issue

* edit prompts for kaggle scenario & fix some bugs

* Revised Prompts To Improve Performance on Model Type & Support of Random Forest

* edit prompts & modify evaluator.py to adapt to Kaggle scenario

* edit prompts

* fix some bugs

* CI issues

---------

Co-authored-by: Taozhi Wang <taozhi.mark.wang@gmail.com>
Co-authored-by: Xisen-Wang <xisen_application@163.com>
2024-08-23 15:13:50 +08:00
WinstonLiyt 28166fc4f5 fix: fix some bugs in llm calling (#217)
* fix some bugs in llm calling

* fix a CI error

* fix a small bug in kmeans group number choosing

* fix a ci bug
2024-08-21 16:48:09 +08:00
Xu Yang ce30936aca use sqlite to store session history and enable reproduction in k-means (#219) 2024-08-20 17:49:45 +08:00
Tim e9eb22742a check if gen_df is None (#216) 2024-08-20 12:27:13 +08:00
XianBW aa05ed87bf feat: add progress status for docker env (#215)
* add progress status for docker env
2024-08-19 19:10:30 +08:00
WinstonLiyt 44fd1563a2 feat: Added loop code for Kaggle scene. (#211)
* fuse all code into one commit

* remove container auto

* change remove method

* add kaggle env start

* change kaggle api

* change structure

* add crawler

* add requirements

* refeact the code

* delete mistaken codes

* merge docker settings and crawler

* add chrome install README for crawler usage

* Connect scen with Kaggle to download data

* Reformat some files to pass CI.

* fix some ci errors

* fix a ci error

* fix a ci error

---------

Co-authored-by: Bowen Xian <xianbowen@outlook.com>
2024-08-19 10:58:28 +08:00
you-n-g bc106cd076 docs: update demo link (#212)
* Docs: update demo link

* Update development.rst
2024-08-16 15:50:00 +08:00
Xu Yang 3ee9add2d2 add relevance check to quant factors (#210) 2024-08-15 18:52:37 +08:00
WinstonLiyt f5b1a0d81a Update README with a link to the scen documentation. (#205) 2024-08-12 15:01:30 +08:00
you-n-g 9c0bf60027 docs: Fix log path example (#206)
* docs: Fix log path example

* Update ui.rst
2024-08-11 09:17:46 +08:00
Linlang 564cd26c0c fix build docs error (#204) 2024-08-10 01:32:55 +08:00
WinstonLiyt 7f10f44239 docs: Update README.md. (#203)
* Update README.md
2024-08-09 21:32:32 +08:00
XianBW 4b084f394f feat: Demo display effect and usage (#162)
Demo changes
2024-08-09 20:40:16 +08:00
you-n-g 2f2d959efd docs: Update README.md (#201)
* Update README.md

* Update README.md

* Update README.md

* Update README.md

* Update README.md

* Update README.md
2024-08-09 20:33:59 +08:00
you-n-g ec4daeb5a4 chore(main): release 0.1.0 (#185) 2024-08-09 20:06:30 +08:00
you-n-g eccc860446 docs: Refine docs (#200)
* Update docs

* update one demo video

* update docs

* remove the video

* move configuration file

* fix demo title
2024-08-09 19:55:35 +08:00
WinstonLiyt b5dc5af91e update readme (#194)
Co-authored-by: you-n-g <you-n-g@users.noreply.github.com>
2024-08-09 18:01:46 +08:00
Linlang a1399d65f1 docs: add read the docs yaml (#198)
* add read the docs yaml

* format read the docs yaml
2024-08-09 17:25:38 +08:00
XianBW d82edc9c23 feat: change ui entry (#197)
change ui start cmd
2024-08-09 17:23:45 +08:00
Linlang 048e820d3d fix_docs_warning (#195) 2024-08-09 15:23:56 +08:00
XianBW 2d816035ef docs: add start app command in readme (#196)
add start app command in readme
2024-08-09 14:37:22 +08:00
Xu Yang 1328f45f97 fix: update command line in readme.md (#192)
* update command line

* remove some todo
2024-08-09 14:18:57 +08:00
Suhan Cui 2d5650ef8c med (#193) 2024-08-09 14:01:10 +08:00
WinstonLiyt a75c19b17c docs: Updated documentation for all the major scenarios. (#190)
* Fixed some bugs introduced during refactoring.

* update data_agent_fin_doc

* Updated documentation for the four major scenarios

* feat: remove pdfs and enable online pdf readings (#183)

* remove pdfs and enable online pdf readings

* update doc format

* use url as key

* feat: add entry for rdagent. (#187)

* Add entries

* update entry for rdagent

* lint

* fix typo

* docs: Demo links (#188)

add demo links

* fix: Fix a fail href in readme (#189)

* fix a ci bug

* doc

* feat: remove pdfs and enable online pdf readings (#183)

* remove pdfs and enable online pdf readings

* update doc format

* use url as key

* feat: add entry for rdagent. (#187)

* Add entries

* update entry for rdagent

* lint

* fix typo

* doc

* Updated documentation for med_model scenarios.

* fix a ci bug

---------

Co-authored-by: Xu Yang <peteryang@vip.qq.com>
Co-authored-by: you-n-g <you-n-g@users.noreply.github.com>
Co-authored-by: XianBW <36835909+XianBW@users.noreply.github.com>
Co-authored-by: SH-Src <suhan.c@outlook.com>
2024-08-09 13:27:33 +08:00
Xu Yang 05a3b67aa8 fix: fix quick start problem (#191)
* all update code

* fix a small bug
2024-08-09 12:58:34 +08:00
Linlang 18ec2a259d docs: Add badge (#186)
* add badge

* fix docs version

* fix docs error

* fix docs version
2024-08-09 12:05:45 +08:00
Xu Yang c12a914d39 fix: Fix a fail href in readme (#189) 2024-08-09 11:29:02 +08:00
XianBW 97873dd1a9 docs: Demo links (#188)
add demo links
2024-08-08 18:35:15 +08:00
you-n-g e089456cac feat: add entry for rdagent. (#187)
* Add entries

* update entry for rdagent

* lint

* fix typo
2024-08-08 17:10:37 +08:00
Xu Yang 59c1ace8a2 feat: remove pdfs and enable online pdf readings (#183)
* remove pdfs and enable online pdf readings

* update doc format

* use url as key
2024-08-08 15:20:39 +08:00
90 changed files with 3044 additions and 1044 deletions
+51
View File
@@ -0,0 +1,51 @@
---
name: "\U0001F41B Bug Report"
about: Submit a bug report to help us improve RD-Agent
labels: bug
---
## 🐛 Bug Description
<!-- A clear and concise description of what the bug is. -->
## To Reproduce
Steps to reproduce the behavior:
1.
2.
3.
## Expected Behavior
<!-- A clear and concise description of what you expected to happen. -->
## Screenshot
<!-- A screenshot of the error message or anything shouldn't appear-->
## Environment
**Note**: Users can run `rdagent collect_info` to get system information and paste it directly here.
- Name of current operating system:
- Processor architecture:
- System, version, and hardware information:
- Version number of the system:
- Python version:
- Container ID:
- Container Name:
- Container Status:
- Image ID used by the container:
- Image tag used by the container:
- Container port mapping:
- Container Label:
- Startup Commands:
- RD-Agent version:
- Package version:
## Additional Notes
<!-- Add any other information about the problem here. -->
+9
View File
@@ -0,0 +1,9 @@
---
name: "\U0001F4D6 Documentation"
about: Report an issue related to documentation
---
## 📖 Documentation
<!-- Please specify whether it's tutorial part or API reference part, and describe it.-->
+25
View File
@@ -0,0 +1,25 @@
---
name: "\U0001F31FFeature Request"
about: Request for a new RD-Agent feature
labels: enhancement
---
## 🌟 Feature Description
<!-- A clear and concise description of the feature proposal -->
## Motivation
1. Application scenario
2. Related works (Papers, Github repos etc.):
3. Any other relevant and important information:
<!-- Please describe why the feature is important. -->
## Alternatives
<!-- A short description of any alternative solutions or features you've considered. -->
## Additional Notes
<!-- Add any other context or screenshots about the feature request here. -->
+10
View File
@@ -0,0 +1,10 @@
---
name: "❓Questions & Help"
about: Have some questions? We can offer help.
labels: question
---
## ❓ Questions and Help
We sincerely suggest you to carefully read the [documentation](http://rdagent.readthedocs.io/). After that, if you still feel puzzled, please describe the question clearly under this issue.
+1 -1
View File
@@ -20,7 +20,7 @@ jobs:
- run: env | sort
- run: make dev
- name: lint test docs and build
run: make lint docs-gen # test docs build
run: make lint docs-gen test-offline # test docs build
strategy:
matrix:
python-version:
+26
View File
@@ -0,0 +1,26 @@
# .readthedocs.yml
# Read the Docs configuration file
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
# Required
version: 2
# Set the version of Python and other tools you might need
build:
os: ubuntu-22.04
tools:
python: "3.10"
# Build documentation in the docs/ directory with Sphinx
sphinx:
configuration: docs/conf.py
# Build all formats
formats: all
# Optionally set the version of Python and requirements required to build your docs
python:
install:
- requirements: requirements/docs.txt
- method: pip
path: .
+2
View File
@@ -0,0 +1,2 @@
[client]
showSidebarNavigation = false
+46
View File
@@ -1,5 +1,51 @@
# Changelog
## [0.2.1](https://github.com/microsoft/RD-Agent/compare/v0.2.0...v0.2.1) (2024-09-10)
### Bug Fixes
* default model value in config ([#256](https://github.com/microsoft/RD-Agent/issues/256)) ([c097585](https://github.com/microsoft/RD-Agent/commit/c097585f631f401c2c0966f6ad4c17286924f011))
* fix_dotenv_error ([#257](https://github.com/microsoft/RD-Agent/issues/257)) ([923063c](https://github.com/microsoft/RD-Agent/commit/923063c1fd957c4ed42e97272c72b5e9545451dc))
* readme ([#248](https://github.com/microsoft/RD-Agent/issues/248)) ([8cede22](https://github.com/microsoft/RD-Agent/commit/8cede2209922876490148459e1134da828e1fda0))
## [0.2.0](https://github.com/microsoft/RD-Agent/compare/v0.1.0...v0.2.0) (2024-09-07)
### Features
* add collect info ([#233](https://github.com/microsoft/RD-Agent/issues/233)) ([89f4af9](https://github.com/microsoft/RD-Agent/commit/89f4af90fb4d95a0689bf9efc8ffd9326469c0aa))
* add cross validation for kaggle scenario ([#236](https://github.com/microsoft/RD-Agent/issues/236)) ([e0b03ba](https://github.com/microsoft/RD-Agent/commit/e0b03ba6b5c3d9aa552b99d470e106d4e348e64d))
* add progress status for docker env ([#215](https://github.com/microsoft/RD-Agent/issues/215)) ([538d4ef](https://github.com/microsoft/RD-Agent/commit/538d4ef2e52de795b90d3f75b2e1e877ab85c18d))
* Added loop code for Kaggle scene. ([#211](https://github.com/microsoft/RD-Agent/issues/211)) ([975c327](https://github.com/microsoft/RD-Agent/commit/975c32715e51aec6b49537401f5fc59115e04a01))
* Demo display effect and usage ([#162](https://github.com/microsoft/RD-Agent/issues/162)) ([8cf122a](https://github.com/microsoft/RD-Agent/commit/8cf122a0155f434fa4477ae7a6d616b5caecd3e0))
* piloting of the framework ([#227](https://github.com/microsoft/RD-Agent/issues/227)) ([e9b103e](https://github.com/microsoft/RD-Agent/commit/e9b103e684fdd2b98cd1a89971a3fce2d6e884a1))
* support more models for kaggle scenario ([#223](https://github.com/microsoft/RD-Agent/issues/223)) ([e3a9659](https://github.com/microsoft/RD-Agent/commit/e3a96598c0720fe092ec86d7ca8c195c7d6bcc72))
* update model_experiment.py to support basic EDA ([#220](https://github.com/microsoft/RD-Agent/issues/220)) ([bf2684c](https://github.com/microsoft/RD-Agent/commit/bf2684c4d55ab8e1048ac0291695475ad53b0cd6))
### Bug Fixes
* fix some bugs in llm calling ([#217](https://github.com/microsoft/RD-Agent/issues/217)) ([7b010f8](https://github.com/microsoft/RD-Agent/commit/7b010f8b5940aba65a58f1d78192aa80bcd0e654))
* package dependency. ([#234](https://github.com/microsoft/RD-Agent/issues/234)) ([46be295](https://github.com/microsoft/RD-Agent/commit/46be2952952af534fd8d98a656c704c688d7cbdd))
* remove useless line ([#177](https://github.com/microsoft/RD-Agent/issues/177)) ([64e9a8e](https://github.com/microsoft/RD-Agent/commit/64e9a8e39a2072a962111db18f5b9565df5b0176))
## [0.1.0](https://github.com/microsoft/RD-Agent/compare/v0.0.1...v0.1.0) (2024-08-09)
### Features
* add entry for rdagent. ([#187](https://github.com/microsoft/RD-Agent/issues/187)) ([121b6d9](https://github.com/microsoft/RD-Agent/commit/121b6d98de38cd03be30cbee47b40baf39a2b60b))
* change ui entry ([#197](https://github.com/microsoft/RD-Agent/issues/197)) ([fa5d335](https://github.com/microsoft/RD-Agent/commit/fa5d3354d22240888f4fc4007d9834f7424632aa))
* remove pdfs and enable online pdf readings ([#183](https://github.com/microsoft/RD-Agent/issues/183)) ([18c0501](https://github.com/microsoft/RD-Agent/commit/18c05016a23d694c7b12759cf1322562dcffc56a))
### Bug Fixes
* Fix a fail href in readme ([#189](https://github.com/microsoft/RD-Agent/issues/189)) ([1b89218](https://github.com/microsoft/RD-Agent/commit/1b89218f6bc697494f4a1b8a42ad18963002714f))
* fix quick start problem ([#191](https://github.com/microsoft/RD-Agent/issues/191)) ([44f61bf](https://github.com/microsoft/RD-Agent/commit/44f61bfa1058a8efb59ca48b7f1417765aeea33e))
* update command line in readme.md ([#192](https://github.com/microsoft/RD-Agent/issues/192)) ([9c45d24](https://github.com/microsoft/RD-Agent/commit/9c45d24a192da02f7d9765cb001097da1bc36c61))
## 0.0.1 (2024-08-08)
+14 -3
View File
@@ -141,10 +141,21 @@ test-run:
$(PIPRUN) python -m coverage run --concurrency=multiprocessing -m pytest --ignore test/scripts
$(PIPRUN) python -m coverage combine
test-run-offline:
# some test that does not require api calling
$(PIPRUN) python -m coverage erase
$(PIPRUN) python -m coverage run --concurrency=multiprocessing -m pytest -m "offline" --ignore test/scripts
$(PIPRUN) python -m coverage combine
# Generate coverage report for terminal and xml.
# TODO: we may have higher coverage rate if we have more test
test: test-run
$(PIPRUN) python -m coverage report --fail-under 80
$(PIPRUN) python -m coverage xml --fail-under 80
$(PIPRUN) python -m coverage report --fail-under 20 # 80
$(PIPRUN) python -m coverage xml --fail-under 20 # 80
test-offline: test-run-offline
$(PIPRUN) python -m coverage report --fail-under 20 # 80
$(PIPRUN) python -m coverage xml --fail-under 20 # 80
########################################################################################
# Package
@@ -189,7 +200,7 @@ release-notes:
# Build documentation only from rdagent.
docs-gen:
$(PIPRUN) python -m sphinx.cmd.build docs $(PUBLIC_DIR)
$(PIPRUN) python -m sphinx.cmd.build -W docs $(PUBLIC_DIR)
# Generate mypy reports.
docs-mypy: docs-gen
+132 -79
View File
@@ -1,48 +1,67 @@
<h3 align="center">
<img src="docs/_static/logo.png" alt="RA-Agent logo" style="width:70%; ">
<a href="https://rdagent.azurewebsites.net" target="_blank">🖥️ Live Demo</a> | <a href="https://rdagent.azurewebsites.net/factor_loop" target="_blank">🎥 Demo Video</a> | <a href="https://rdagent.readthedocs.io/en/latest/index.html" target="_blank">📖 Documentation</a> | <a href="#-paperwork-list"> 📃 Papers </a>
</h3>
[![CI](https://github.com/microsoft/RD-Agent/actions/workflows/ci.yml/badge.svg)](https://github.com/microsoft/RD-Agent/actions/workflows/ci.yml)
[![CodeQL](https://github.com/microsoft/RD-Agent/actions/workflows/github-code-scanning/codeql/badge.svg)](https://github.com/microsoft/RD-Agent/actions/workflows/github-code-scanning/codeql)
[![Dependabot Updates](https://github.com/microsoft/RD-Agent/actions/workflows/dependabot/dependabot-updates/badge.svg)](https://github.com/microsoft/RD-Agent/actions/workflows/dependabot/dependabot-updates)
[![Lint PR Title](https://github.com/microsoft/RD-Agent/actions/workflows/pr.yml/badge.svg)](https://github.com/microsoft/RD-Agent/actions/workflows/pr.yml)
[![Readthedocs Preview](https://github.com/microsoft/RD-Agent/actions/workflows/readthedocs-preview.yml/badge.svg)](https://github.com/microsoft/RD-Agent/actions/workflows/readthedocs-preview.yml)
[![Release.yml](https://github.com/microsoft/RD-Agent/actions/workflows/release.yml/badge.svg)](https://github.com/microsoft/RD-Agent/actions/workflows/release.yml)
[![Platform](https://img.shields.io/badge/platform-Linux-blue)](https://pypi.org/project/rdagent/#files)
[![PyPI](https://img.shields.io/pypi/v/rdagent)](https://pypi.org/project/rdagent/)
[![PyPI - Python Version](https://img.shields.io/pypi/pyversions/rdagent)](https://pypi.org/project/rdagent/)
[![Release](https://img.shields.io/github/v/release/microsoft/RD-Agent)](https://github.com/microsoft/RD-Agent/releases)
[![GitHub](https://img.shields.io/github/license/microsoft/RD-Agent)](https://github.com/microsoft/RD-Agent/blob/main/LICENSE)
[![pre-commit](https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit)](https://github.com/pre-commit/pre-commit)
[![Checked with mypy](https://www.mypy-lang.org/static/mypy_badge.svg)](http://mypy-lang.org/)
[![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)
<!-- TODO: License / pypi / PyPI - Python Version -->
[![Readthedocs Preview](https://github.com/microsoft/RD-Agent/actions/workflows/readthedocs-preview.yml/badge.svg)](https://github.com/microsoft/RD-Agent/actions/workflows/readthedocs-preview.yml) <!-- this badge is too long, please place it in the last one to make it pretty -->
# 📰 News
| 🗞️News | 📝Description |
| 🗞️ News | 📝 Description |
| -- | ------ |
| First release | RDAgent are release on Github |
| First release | **RDAgent** is released on Github |
# 🌟 Introduction
<div align="center">
<img src="docs/_static/scen.png" alt="Our focused scenario" style="width:80%; ">
</div>
![Our focused scenario](docs/_static/scen.jpg)
RDAgent aims to automate the most critical and valuable aspects of the industrial R&D process, and we begins with focusing on the data-driven scenarios to streamline the development of models and data.
RDAgent aims to automate the most critical and valuable aspects of the industrial R&D process, and we begin with focusing on the data-driven scenarios to streamline the development of models and data.
Methodologically, we have identified a framework with two key components: 'R' for proposing new ideas and 'D' for implementing them.
We believe that the automatic evolution of R&D will lead to solutions of significant industrial value.
<!-- Tag Cloud -->
R&D is a very general scenario. The advent of RDAgent can be your
- [🎥Automatic Quant Factory]()
- 🤖Data mining agent: iteratively proposing [🎥data]() & [models]() and implementing them by gaining knowledge from data.
- 🦾Research copilot: Auto read [🎥research papers]()/[🎥reports]() and implement model structures or building datasets.
- 💰 **Automatic Quant Factory** [(🎥Demo Video)](https://rdagent.azurewebsites.net/factor_loop)
- 🤖 **Data Mining Agent:** Iteratively proposing data [(🎥Demo Video)](https://rdagent.azurewebsites.net/dmm) & models [(🎥Demo Video)](https://rdagent.azurewebsites.net/model_loop) and implementing them by gaining knowledge from data.
- 🦾 **Research Copilot:** Auto read research papers [(🎥Demo Video)](https://rdagent.azurewebsites.net/report_model) / financial reports [(🎥Demo Video)](https://rdagent.azurewebsites.net/report_factor) and implement model structures or building datasets.
- ...
You can click the [🎥link]() above to view the demo. More methods and scenarios are being added to the project to empower your R&D processes and boost productivity.
You can click the links above to view the demo. We're continuously adding more methods and scenarios to the project to enhance your R&D processes and boost productivity.
We have a quick 🎥demo for one use case of RDAgent.
- TODO: Demo
Additionally, you can take a closer look at the examples in our **[🖥️ Live Demo](https://rdagent.azurewebsites.net/)**.
<div align="center">
<a href="https://rdagent.azurewebsites.net/" target="_blank">
<img src="docs/_static/demo.png" alt="Watch the demo" width="80%">
</a>
</div>
# ⚡Quick start
You can try our demo by running the following command:
# ⚡ Quick start
You can try above demos by running the following command:
### 🐳 Docker installation.
Users must ensure Docker is installed before attempting most scenarios. Please refer to the [official 🐳Docker page](https://docs.docker.com/engine/install/) for installation instructions.
### 🐍 Create a Conda Environment
- Create a new conda environment with Python (3.10 and 3.11 are well tested in our CI):
- Create a new conda environment with Python (3.10 and 3.11 are well-tested in our CI):
```sh
conda create -n rdagent python=3.10
```
@@ -51,89 +70,119 @@ You can try our demo by running the following command:
conda activate rdagent
```
### 🛠️ Run Make Files
TODO: `pip install rdagent` in the future.
- **Navigate to the directory containing the MakeFile** and set up the development environment:
### 🛠️ Install the RDAgent
- You can directly install the RDAgent package from PyPI:
```sh
make dev
pip install rdagent
```
### 📦 Install Pytorch
TODO: use docker in quick start intead.
- Install Pytorch and related libraries:
```sh
pip3 install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cpu
pip3 install torch_geometric
### ⚙️ Configuration
- You have to config your GPT model in the `.env`
```bash
cat << EOF > .env
OPENAI_API_KEY=<your_api_key>
# EMBEDDING_MODEL=text-embedding-3-small
CHAT_MODEL=gpt-4-turbo
EOF
```
### ⚙️ Environment Configuration
- Place the `.env` file in the same directory as the `.env.example` file.
- The `.env.example` file contains the environment variables required for users using the OpenAI API (Please note that `.env.example` is an example file. `.env` is the one that will be finally used.)
- please refer to [Configuration](docs/build/html/installation.html#azure-openai) for the detailed explanation of the `.env`
- Export each variable in the `.env` file:
```sh
export $(grep -v '^#' .env | xargs)
```
### 🚀 Run the Application
TODO: run the front-page demo.
The [🎥demo]() is implemented by the above commands.
The **[🖥️ Live Demo](https://rdagent.azurewebsites.net/)** is implemented by the following commands(each item represents one demo, you can select the one you prefer):
- Run the factor extraction and implementation application based on financial reports:
- Run the **Automated Quantitative Trading & Iterative Factors Evolution**: [Qlib](http://github.com/microsoft/qlib) self-loop factor proposal and implementation application
```sh
python rdagent/app/qlib_rd_loop/factor_from_report_sh.py
rdagent fin_factor
```
- Run the self-loop factor extraction and implementation application:
- Run the **Automated Quantitative Trading & Iterative Model Evolution**: [Qlib](http://github.com/microsoft/qlib) self-loop model proposal and implementation application
```sh
python rdagent/app/qlib_rd_loop/factor.py
rdagent fin_model
```
- Run the self-loop model extraction and implementation application:
- Run the **Automated Medical Prediction Model Evolution**: Medical self-loop model proposal and implementation application
>(1) Apply for an account at [PhysioNet](https://physionet.org/). <br /> (2) Request access to FIDDLE preprocessed data: [FIDDLE Dataset](https://physionet.org/content/mimic-eicu-fiddle-feature/1.0.0/). <br />
(3) Place your username and password in `.env`.
```bash
cat << EOF >> .env
DM_USERNAME=<your_username>
DM_PASSWORD=<your_password>
EOF
```
```sh
python rdagent/app/qlib_rd_loop/model.py
rdagent med_model
```
- Run the **Automated Quantitative Trading & Factors Extraction from Financial Reports**: Run the [Qlib](http://github.com/microsoft/qlib) factor extraction and implementation application based on financial reports
```sh
# 1. Generally, you can run this scenario using the following command:
rdagent fin_factor_report --report_folder=<Your financial reports folder path>
# Scenarios
# 2. Specifically, you need to prepare some financial reports first. You can follow this concrete example:
wget https://github.com/SunsetWolf/rdagent_resource/releases/download/reports/all_reports.zip
unzip all_reports.zip -d git_ignore_folder/reports
rdagent fin_factor_report --report_folder=git_ignore_folder/reports
```
We have applied RD-Agent to multiple valuable data-driven industrial scenarios..
- Run the **Automated Model Research & Development Copilot**: model extraction and implementation application
```sh
# 1. Generally, you can run your own papers/reports with the following command:
rdagent general_model <Your paper URL>
# 2. Specifically, you can do it like this. For more details and additional paper examples, use `rdagent general_model -h`:
rdagent general_model "https://arxiv.org/pdf/2210.09789"
```
### 🖥️ Monitor the Application Results
- You can serve our demo app to monitor the RD loop by running the following command:
```sh
rdagent ui --port 80 --log_dir <your log folder like "log/">
```
# 🏭 Scenarios
We have applied RD-Agent to multiple valuable data-driven industrial scenarios.
## 🎯 Goal: Agent for Data-driven R&D
In this project, we are aiming to build a Agent to automate Data-Driven R\&D that can
+ 📄Read real-world material (reports, papers, etc.) and **extract** key formulas, descriptions of interested **features** and **models**, which are the key components of data-driven R&D .
+ 🛠️**Implement** the extracted formulas (e.g., features, factors, and models) in runnable codes.
+ Due to the limited ability of LLM in implementing at once, evolve the agent to be able to extend abilities by learning from feedback and knowledge and improve the agent's ability to implement more complex models.
+ 💡Propose **new ideas** based on current knowledge and observations.
In this project, we are aiming to build an Agent to automate Data-Driven R\&D that can
+ 📄 Read real-world material (reports, papers, etc.) and **extract** key formulas, descriptions of interested **features** and **models**, which are the key components of data-driven R&D .
+ 🛠️ **Implement** the extracted formulas (e.g., features, factors, and models) in runnable codes.
+ Due to the limited ability of LLM in implementing at once, build an evolving process for the agent to improve performance by learning from feedback and knowledge.
+ 💡 Propose **new ideas** based on current knowledge and observations.
<!-- ![Data-Centric R&D Overview](docs/_static/overview.png) -->
## 📈 Scenarios/Demos
In the two key areas of data-driven scenarios, model implementation and data building, our system aims to serve two main roles: 🦾copilot and 🤖agent.
- The 🦾copilot follows human instructions to automate repetitive tasks.
- The 🤖agent, being more autonomous, actively proposes ideas for better results in the future.
In the two key areas of data-driven scenarios, model implementation and data building, our system aims to serve two main roles: 🦾Copilot and 🤖Agent.
- The 🦾Copilot follows human instructions to automate repetitive tasks.
- The 🤖Agent, being more autonomous, actively proposes ideas for better results in the future.
The supported scenarios are listed below:
| Scenario/Target | Model Implementation | Data Building |
| -- | -- | -- |
| 💹 Finance | 🤖Iteratively Proposing Ideas & Evolving | - 🦾Auto reports reading & implementation <br/> - 🤖Iteratively Proposing Ideas & Evolving |
| 🩺 Medical | 🤖Iteratively Proposing Ideas & Evolving | - |
| 🏭 General | 🦾Auto paper reading & implementation | - |
| **💹 Finance** | 🤖 [Iteratively Proposing Ideas & Evolving](https://rdagent.azurewebsites.net/model_loop) | 🤖 [Iteratively Proposing Ideas & Evolving](https://rdagent.azurewebsites.net/factor_loop) <br/> 🦾 [Auto reports reading & implementation](https://rdagent.azurewebsites.net/report_factor) |
| **🩺 Medical** | 🤖 [Iteratively Proposing Ideas & Evolving](https://rdagent.azurewebsites.net/dmm) | - |
| **🏭 General** | 🦾 [Auto paper reading & implementation](https://rdagent.azurewebsites.net/report_model) | - |
Different scenarios vary in entrance and configuration. Please check the detailed setup tutorial in the scenarios documents.
TODO: Scenario Gallary
- map(scenario) => knowledge list;
Here is a gallery of [successful explorations](https://github.com/SunsetWolf/rdagent_resource/releases/download/demo_traces/demo_traces.zip) (5 traces showed in **[🖥️ Live Demo](https://rdagent.azurewebsites.net/)**). You can download and view the execution trace using the command below:
# ⚙️Framework
```bash
rdagent ui --port 80 --log_dir ./demo_traces
```
![image](https://github.com/user-attachments/assets/98fce923-77ab-4982-93c8-a7a01aece766)
Please refer to **[📖readthedocs_scen](https://rdagent.readthedocs.io/en/latest/scens/catalog.html)** for more details of the scenarios.
# ⚙️ Framework
<div align="center">
<img src="docs/_static/Framework-RDAgent.png" alt="Framework-RDAgent" width="85%">
</div>
Automating the R&D process in data science is a highly valuable yet underexplored area in industry. We propose a framework to push the boundaries of this important research field.
@@ -141,17 +190,18 @@ Automating the R&D process in data science is a highly valuable yet underexplore
The research questions within this framework can be divided into three main categories:
| Research Area | Paper/Work List |
|--------------------|-----------------|
| Benchmark the R&D abilities | [Benchmark](#benchmark) |
| Idea proposal: Explore new ideas or refine existing ones | [Research](#research) |
| Ability to realize ideas: Implement and execute ideas | [Development](#development) |
| **Benchmark the R&D abilities** | [Benchmark](#benchmark) |
| **Idea proposal:** Explore new ideas or refine existing ones | [Research](#research) |
| **Ability to realize ideas:** Implement and execute ideas | [Development](#development) |
We believe that the key to delivering high-quality solutions lies in the ability to evolve R&D capabilities. Agents should learn like human experts, continuously improving their R&D skills.
More documents can be found in the **[📖 readthedocs](https://rdagent.readthedocs.io/)**.
# 📃Paper/Work list
# 📃 Paper/Work list
## Benchmark
- [Towards Data-Centric Automatic R&D](https://arxiv.org/abs/2404.11276);
## 📊 Benchmark
- [Towards Data-Centric Automatic R&D](https://arxiv.org/abs/2404.11276)
```BibTeX
@misc{chen2024datacentric,
title={Towards Data-Centric Automatic R&D},
@@ -164,15 +214,15 @@ We believe that the key to delivering high-quality solutions lies in the ability
```
![image](https://github.com/user-attachments/assets/494f55d3-de9e-4e73-ba3d-a787e8f9e841)
## Research
## 🔍 Research
In a data mining expert's daily research and development process, they propose a hypothesis (e.g., a model structure like RNN can capture patterns in time-series data), design experiments (e.g., finance data contains time-series and we can verify the hypothesis in this scenario), implement the experiment as code (e.g., Pytorch model structure), and then execute the code to get feedback (e.g., metrics, loss curve, etc.). The experts learn from the feedback and improve in the next iteration.
Based on the principles above, we have established a basic method framework that continuously proposes hypotheses, verifies them, and gets feedback from the real-world practice. This is the first scientific research automation framework that supports linking with real-world verification.
[Demos](#📈 Scenarios/Demos) are released.
For more detail, please refer to our **[🖥️ Live Demo page](https://rdagent.azurewebsites.net)**.
## Development
## 🛠️ Development
- [Collaborative Evolving Strategy for Automatic Data-Centric Development](https://arxiv.org/abs/2407.18690)
```BibTeX
@@ -188,18 +238,21 @@ Based on the principles above, we have established a basic method framework that
![image](https://github.com/user-attachments/assets/75d9769b-0edd-4caf-9d45-57d1e577054b)
# Contributing
# 🤝 Contributing
More documents can be found in the [📚readthedocs](). TODO: add link
## Guidance
## 📝 Guidelines
This project welcomes contributions and suggestions.
You can find issues in the issues list or simply running `grep -r "TODO:"`.
Contributing to this project is straightforward and rewarding. Whether it's solving an issue, addressing a bug, enhancing documentation, or even correcting a typo, every contribution is valuable and helps improve RDAgent.
To get started, you can explore the issues list, or search for `TODO:` comments in the codebase by running the command `grep -r "TODO:"`.
Making contributions is not a hard thing. Solving an issue(maybe just answering a question raised in issues list ), fixing/issuing a bug, improving the documents and even fixing a typo are important contributions to RDAgent.
<img src="https://img.shields.io/github/contributors-anon/microsoft/RD-Agent"/>
<a href="https://github.com/microsoft/RD-Agent/graphs/contributors"><img src="https://contrib.rocks/image?repo=microsoft/RD-Agent&max=240&columns=18" /></a>
<a href="https://github.com/microsoft/RD-Agent/graphs/contributors">
<img src="https://contrib.rocks/image?repo=microsoft/RD-Agent&max=100&columns=15" />
</a>
# Disclaimer
**The RD-agent is provided “as is”, without warranty of any kind, express or implied, including but not limited to the warranties of merchantability, fitness for a particular purpose and noninfringement. The RD-agent is aimed to facilitate research and development process in the financial industry and not ready-to-use for any financial investment or advice. Users shall independently assess and test the risks of the RD-agent in a specific use scenario, ensure the responsible use of AI technology, including but not limited to developing and integrating risk mitigation measures, and comply with all applicable laws and regulations in all applicable jurisdictions. The RD-agent does not provide financial opinions or reflect the opinions of Microsoft, nor is it designed to replace the role of qualified financial professionals in formulating, assessing, and approving finance products. The inputs and outputs of the RD-agent belong to the users and users shall assume all liability under any theory of liability, whether in contract, torts, regulatory, negligence, products liability, or otherwise, associated with use of the RD-agent and any inputs and outputs thereof.**
Before we released RD-Agent as an open-source project on GitHub, it was an internal project within our group. Unfortunately, the internal commit history was not preserved when we removed some confidential code. As a result, some contributions from our group members, including Haotian Chen, Wenjun Feng, Haoxue Wang, Zeqi Ye, Xinjie Shen, and Jinhui Li, were not included in the public commits.
# ⚖️ Legal disclaimer
<p style="line-height: 1; font-style: italic;">The RD-agent is provided “as is”, without warranty of any kind, express or implied, including but not limited to the warranties of merchantability, fitness for a particular purpose and noninfringement. The RD-agent is aimed to facilitate research and development process in the financial industry and not ready-to-use for any financial investment or advice. Users shall independently assess and test the risks of the RD-agent in a specific use scenario, ensure the responsible use of AI technology, including but not limited to developing and integrating risk mitigation measures, and comply with all applicable laws and regulations in all applicable jurisdictions. The RD-agent does not provide financial opinions or reflect the opinions of Microsoft, nor is it designed to replace the role of qualified financial professionals in formulating, assessing, and approving finance products. The inputs and outputs of the RD-agent belong to the users and users shall assume all liability under any theory of liability, whether in contract, torts, regulatory, negligence, products liability, or otherwise, associated with use of the RD-agent and any inputs and outputs thereof.</p>
Binary file not shown.

After

Width:  |  Height:  |  Size: 339 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 567 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 94 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 303 KiB

+14 -4
View File
@@ -6,7 +6,9 @@
# -- Project information -----------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information
import importlib.metadata
import subprocess
latest_tag = subprocess.check_output(["git", "describe", "--tags", "--abbrev=0"], text=True).strip()
project = "RDAgent"
copyright = "2024, Microsoft"
@@ -20,7 +22,7 @@ extensions = ["sphinx.ext.autodoc", "sphinxcontrib.autodoc_pydantic"]
autodoc_member_order = "bysource"
# The suffix of source filenames.
source_suffix = ".rst"
source_suffix = {".rst": "restructuredtext"}
# The encoding of source files.
source_encoding = "utf-8"
@@ -33,8 +35,8 @@ master_doc = "index"
# built documents.
#
# The short X.Y version.
version = importlib.metadata.version("rdagent")
release = importlib.metadata.version("rdagent")
version = latest_tag
release = latest_tag
# The language for content autogenerated by Sphinx. Refer to documentation for
# a list of supported languages.
@@ -59,4 +61,12 @@ try:
except ImportError:
html_theme = "default"
html_logo = "_static/logo.png"
html_static_path = ["_static"]
html_favicon = "_static/favicon.ico"
html_theme_options = {
"source_repository": "https://github.com/microsoft/RD-Agent",
"source_branch": "main",
"source_directory": "docs/",
}
+19 -10
View File
@@ -2,26 +2,35 @@
For Development
=========================
If you want to try the latest version or contribute to RD-Agent. You can install it from the source and follow the commands in this page.
.. code-block:: bash
git clone https://github.com/microsoft/RD-Agent
🔧Prepare for development
=========================
- Set up the development environment.
```bash
make dev
```
.. code-block:: bash
make dev
- Run linting and checking.
```bash
make lint
```
.. code-block:: bash
make lint
- Some linting issues can be fixed automatically. We have added a command in the Makefile for easy use.
```bash
make auto-lint
```
.. code-block:: bash
make auto-lint
Code Structure
@@ -73,4 +82,4 @@ File Naming Convention
* - `conf.py`
- The configuration for the module, app, and project.
<!-- TODO: renaming files -->
.. <!-- TODO: renaming files -->
+5
View File
@@ -6,6 +6,9 @@
Welcome to RDAgent's documentation!
===================================
.. image:: _static/logo.png
:alt: RD-Agent Logo
.. toctree::
:maxdepth: 3
:caption: Doctree:
@@ -20,6 +23,8 @@ Welcome to RDAgent's documentation!
api_reference
policy
GitHub <https://github.com/microsoft/RD-Agent>
Indices and tables
==================
+22
View File
@@ -143,3 +143,25 @@ Configuration List
| max_past_message_include | Maximum number of past messages to include | 10 |
+------------------------------+--------------------------------------------------+-------------------------+
Loading Configuration
---------------------
For users' convenience, we provide a CLI interface called `rdagent`, which automatically runs `load_dotenv()` to load environment variables from the `.env` file.
However, this feature is not enabled by default for other scripts. We recommend users load the environment with the following steps:
- ⚙️ Environment Configuration
- Place the `.env` file in the same directory as the `.env.example` file.
- The `.env.example` file contains the environment variables required for users using the OpenAI API (Please note that `.env.example` is an example file. `.env` is the one that will be finally used.)
- Export each variable in the .env file:
.. code-block:: sh
export $(grep -v '^#' .env | xargs)
- If you want to change the default environment variables, you can refer to the above configuration and edith the `.env` file.
+1 -1
View File
@@ -6,7 +6,7 @@ Introduction
In modern industry, research and development (R&D) is crucial for the enhancement of industrial productivity, especially in the AI era, where the core aspects of R&D are mainly focused on data and models. We are committed to automate these high-value generic R&D processes through our open source R&D automation tool RDAgent, which let AI drive data-driven AI.
.. image:: _static/scen.jpg
.. image:: _static/scen.png
:alt: Our focused scenario
+3 -17
View File
@@ -7,7 +7,7 @@ Framework & Components
.. NOTE: This depends on the correctness of `c-v` of github.
.. image:: https://github.com/user-attachments/assets/98fce923-77ab-4982-93c8-a7a01aece766
.. image:: _static/Framework-RDAgent.png
:alt: Components & Feature Level
The image above shows the overall framework of RDAgent.
@@ -23,19 +23,5 @@ We have established a basic method framework that continuously proposes hypothes
The figure above shows the main classes and how they fit into the workflow for those interested in the detailed code.
Detailed Design
=========================
Configuration
-------------
You can manually source the `.env` file in your shell before running the Python script:
Most of the workflow are controlled by the environment variables.
```sh
# Export each variable in the .env file; Please note that it is different from `source .env` without export
export $(grep -v '^#' .env | xargs)
# Run the Python script
python your_script.py
```
.. Detailed Design
.. ===============
+48 -74
View File
@@ -10,17 +10,24 @@ Finance Data Agent
📖 Background
~~~~~~~~~~~~~~
In the dynamic world of quantitative trading, **factors** are the secret weapons that traders use to harness market inefficiencies.
In the dynamic world of quantitative trading, **factors** serve as the strategic tools that enable traders to exploit market inefficiencies.
These factors—ranging from simple metrics like price-to-earnings ratios to complex models like discounted cash flows—are the key to predicting stock prices with a high degree of accuracy.
These powerful tools—ranging from straightforward metrics like price-to-earnings ratios to intricate discounted cash flow models—unlock the potential to predict stock prices with remarkable precision.
By tapping into this rich vein of data, quantitative traders craft sophisticated strategies that not only capitalize on market patterns but also drastically enhance trading efficiency and accuracy.
By leveraging these factors, quantitative traders can develop sophisticated strategies that not only identify market patterns but also significantly enhance trading efficiency and precision.
The ability to systematically analyze and apply these factors is what separates ordinary trading from truly strategic market outmaneuvering.
And this is where the **Finance Model Agent** comes into play.
Embrace the power of factors, and you're not just trading; you're strategically outsmarting the market.
🎥 `Demo <https://rdagent.azurewebsites.net/factor_loop>`_
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. raw:: html
🎥 Demo
~~~~~~~~~~
TODO: Here should put a video of the demo.
<div style="display: flex; justify-content: center; align-items: center;">
<video width="600" controls>
<source src="https://rdagent.azurewebsites.net/media/65bb598f1372c1857ccbf09b2acf5d55830911625048c03102291098.mp4" type="video/mp4">
Your browser does not support the video tag.
</video>
</div>
🌟 Introduction
@@ -76,52 +83,39 @@ Here's an enhanced outline of the steps:
⚡ Quick Start
~~~~~~~~~~~~~~~~~
Please refer to the installation part in :doc:`../installation_and_configuration` to prepare your system dependency.
You can try our demo by running the following command:
- 🐍 Create a Conda Environment
- Create a new conda environment with Python (3.10 and 3.11 are well tested in our CI):
.. code-block:: sh
conda create -n rdagent python=3.10
- Activate the environment:
- Create a new conda environment with Python (3.10 and 3.11 are well tested in our CI):
.. code-block:: sh
conda activate rdagent
- 🛠️ Run Make Files
- Navigate to the directory containing the MakeFile and set up the development environment:
.. code-block:: sh
make dev
- 📦 Install Pytorch
- Install Pytorch and related libraries:
.. code-block:: sh
pip3 install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cpu
pip3 install torch_geometric
- ⚙️ Environment Configuration
- Place the `.env` file in the same directory as the `.env.example` file.
- The `.env.example` file contains the environment variables required for users using the OpenAI API (Please note that `.env.example` is an example file. `.env` is the one that will be finally used.)
- Export each variable in the .env file:
.. code-block:: sh
export $(grep -v '^#' .env | xargs)
- If you want to change the default environment variables, you can refer to `Env Config`_ below
- 🚀 Run the Application
.. code-block:: sh
python rdagent/app/qlib_rd_loop/factor_w_sc.py
conda create -n rdagent python=3.10
- Activate the environment:
.. code-block:: sh
conda activate rdagent
- 📦 Install the RDAgent
- You can install the RDAgent package from PyPI:
.. code-block:: sh
pip install rdagent
- 🚀 Run the Application
- You can directly run the application by using the following command:
.. code-block:: sh
rdagent fin_factor
🛠️ Usage of modules
@@ -132,33 +126,13 @@ You can try our demo by running the following command:
- **Env Config**
The following environment variables can be set in the `.env` file to customize the application's behavior:
- **Path to the folder containing private data (default fundamental data in Qlib):**
.. code-block:: sh
FACTOR_CODER_DATA_FOLDER=/path/to/data/factor_implementation_source_data_all
- **Path to the folder containing partial private data (for debugging):**
.. code-block:: sh
FACTOR_CODER_DATA_FOLDER_DEBUG=/path/to/data/factor_implementation_source_data_debug
- **Maximum time (in seconds) for writing factor code:**
.. code-block:: sh
FACTOR_CODER_FILE_BASED_EXECUTION_TIMEOUT=300
- **Maximum number of factors to write in one experiment:**
.. code-block:: sh
FACTOR_CODER_SELECT_THRESHOLD=5
- **Number of developing loops for writing factors:**
.. code-block:: sh
FACTOR_CODER_MAX_LOOP=10
.. autopydantic_settings:: rdagent.app.qlib_rd_loop.conf.FactorBasePropSetting
:settings-show-field-summary: False
:exclude-members: Config
.. autopydantic_settings:: rdagent.components.coder.factor_coder.config.FactorImplementSettings
:settings-show-field-summary: False
:members: coder_use_cache, data_folder, data_folder_debug, cache_location, enable_execution_cache, file_based_execution_timeout, select_method, select_threshold, max_loop, knowledge_base_path, new_knowledge_base_path
:exclude-members: Config, fail_task_trial_limit, v1_query_former_trace_limit, v1_query_similar_success_limit, v2_query_component_limit, v2_query_error_limit, v2_query_former_trace_limit, v2_error_summary, v2_knowledge_sampler
:no-index:
+69 -69
View File
@@ -17,12 +17,20 @@ Furthermore, rather than hastily replicating factors from a report, it's essenti
Does the factor capture the essential market dynamics? How unique is it compared to the factors already in your library?
Therefore, there is an urgent need for a systematic approach to design a framework that can effectively manage this process.
This is where our RDAgent comes into play.
And this is where the **Finance Data Copilot** steps in.
🎥 Demo
~~~~~~~~~~
TODO: Here should put a video of the demo.
🎥 `Demo <https://rdagent.azurewebsites.net/report_factor>`_
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. raw:: html
<div style="display: flex; justify-content: center; align-items: center;">
<video width="600" controls>
<source src="https://rdagent.azurewebsites.net/media/7b14b2bd3d8771da9cf7eb799b6d96729cec3d35c8d4f68060f3e2fd.mp4" type="video/mp4">
Your browser does not support the video tag.
</video>
</div>
🌟 Introduction
@@ -76,54 +84,64 @@ Here's an enhanced outline of the steps:
⚡ Quick Start
~~~~~~~~~~~~~~~~~
Please refer to the installation part in :doc:`../installation_and_configuration` to prepare your system dependency.
You can try our demo by running the following command:
- 🐍 Create a Conda Environment
- Create a new conda environment with Python (3.10 and 3.11 are well tested in our CI):
.. code-block:: sh
conda create -n rdagent python=3.10
- Activate the environment:
.. code-block:: sh
conda activate rdagent
- 🛠️ Run Make Files
- Navigate to the directory containing the MakeFile and set up the development environment:
.. code-block:: sh
make dev
- 📦 Install Pytorch
- Install Pytorch and related libraries:
.. code-block:: sh
pip3 install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cpu
pip3 install torch_geometric
- ⚙️ Environment Configuration
- Place the `.env` file in the same directory as the `.env.example` file.
- The `.env.example` file contains the environment variables required for users using the OpenAI API (Please note that `.env.example` is an example file. `.env` is the one that will be finally used.)
- Export each variable in the .env file:
.. code-block:: sh
export $(grep -v '^#' .env | xargs)
- Create a new conda environment with Python (3.10 and 3.11 are well tested in our CI):
- If you want to change the default environment variables, you can refer to `Env Config`_ below
.. code-block:: sh
conda create -n rdagent python=3.10
- Activate the environment:
- 🚀 Run the Application
.. code-block:: sh
python rdagent/app/qlib_rd_loop/factor_from_report_w_sc.py
conda activate rdagent
- 📦 Install the RDAgent
- You can install the RDAgent package from PyPI:
.. code-block:: sh
pip install rdagent
- 🚀 Run the Application
- Download the financial reports you wish to extract factors from and store them in your preferred folder.
- Specifically, you can follow this example, or use your own method:
.. code-block:: sh
wget https://github.com/SunsetWolf/rdagent_resource/releases/download/reports/all_reports.zip
unzip all_reports.zip -d git_ignore_folder/reports
- Run the application with the following command:
.. code-block:: sh
rdagent fin_factor_report --report_folder=git_ignore_folder/reports
- Alternatively, you can store the paths of the reports in `report_result_json_file_path`. The format should be:
.. code-block:: json
[
"git_ignore_folder/report/fin_report1.pdf",
"git_ignore_folder/report/fin_report2.pdf",
"git_ignore_folder/report/fin_report3.pdf"
]
- Then, run the application using the following command:
.. code-block:: sh
rdagent fin_factor_report
🛠️ Usage of modules
~~~~~~~~~~~~~~~~~~~~~
@@ -133,32 +151,14 @@ You can try our demo by running the following command:
- **Env Config**
The following environment variables can be set in the `.env` file to customize the application's behavior:
- **Path to the folder containing research reports:**
.. code-block:: sh
.. autopydantic_settings:: rdagent.app.qlib_rd_loop.conf.FactorFromReportPropSetting
:settings-show-field-summary: False
:show-inheritance:
:exclude-members: Config
QLIB_FACTOR_LOCAL_REPORT_PATH=/path/to/research/reports
- **Path to the JSON file listing research reports for factor extraction:**
.. code-block:: sh
QLIB_FACTOR_REPORT_RESULT_JSON_FILE_PATH=/path/to/reports/list.json
- **Maximum time (in seconds) for writing factor code:**
.. code-block:: sh
FACTOR_CODER_FILE_BASED_EXECUTION_TIMEOUT=300
- **Maximum number of factors to write in one experiment:**
.. code-block:: sh
FACTOR_CODER_SELECT_THRESHOLD=5
- **Number of developing loops for writing factors:**
.. code-block:: sh
FACTOR_CODER_MAX_LOOP=10
.. autopydantic_settings:: rdagent.components.coder.factor_coder.config.FactorImplementSettings
:settings-show-field-summary: False
:members: coder_use_cache, data_folder, data_folder_debug, cache_location, enable_execution_cache, file_based_execution_timeout, select_method, select_threshold, max_loop, knowledge_base_path, new_knowledge_base_path
:exclude-members: Config, python_bin, fail_task_trial_limit, v1_query_former_trace_limit, v1_query_similar_success_limit, v2_query_component_limit, v2_query_error_limit, v2_query_former_trace_limit, v2_error_summary, v2_knowledge_sampler
:no-index:
+75 -44
View File
@@ -9,19 +9,33 @@ Finance Model Agent
📖 Background
~~~~~~~~~~~~~~
TODO
In the realm of quantitative finance, both factor discovery and model development play crucial roles in driving performance.
While much attention is often given to the discovery of new financial factors, the **models** that leverage these factors are equally important.
The effectiveness of a quantitative strategy depends not only on the factors used but also on how well these factors are integrated into robust, predictive models.
🎥 Demo
~~~~~~~~~~
TODO: Here should put a video of the demo.
However, the process of developing and optimizing these models can be labor-intensive and complex, requiring continuous refinement and adaptation to ever-changing market conditions.
And this is where the **Finance Model Agent** steps in.
🎥 `Demo <https://rdagent.azurewebsites.net/model_loop>`_
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. raw:: html
<div style="display: flex; justify-content: center; align-items: center;">
<video width="600" controls>
<source src="https://rdagent.azurewebsites.net/media/d85e8cab1da1cd3501d69ce837452f53a971a24911eae7bfa9237137.mp4" type="video/mp4">
Your browser does not support the video tag.
</video>
</div>
🌟 Introduction
~~~~~~~~~~~~~~~~
In this scenario, our automated system proposes hypothesis, constructs model, implements code, receives back-testing, and uses feedbacks.
Hypothesis is iterated in this continuous process.
The system aims to automatically optimise performance metrics from Qlib library thereby finding the optimised code through autonomous research and development.
In this scenario, our automated system proposes hypothesis, constructs model, implements code, conducts back-testing, and utilizes feedback in a continuous, iterative process.
The goal is to automatically optimize performance metrics within the Qlib library, ultimately discovering the most efficient code through autonomous research and development.
Here's an enhanced outline of the steps:
@@ -69,51 +83,68 @@ Here's an enhanced outline of the steps:
⚡ Quick Start
~~~~~~~~~~~~~~~~~
Please refer to the installation part in :doc:`../installation_and_configuration` to prepare your system dependency.
You can try our demo by running the following command:
- 🐍 Create a Conda Environment
- Create a new conda environment with Python (3.10 and 3.11 are well tested in our CI):
- Create a new conda environment with Python (3.10 and 3.11 are well tested in our CI):
.. code-block:: sh
.. code-block:: sh
conda create -n rdagent python=3.10
conda create -n rdagent python=3.10
- Activate the environment:
- Activate the environment:
.. code-block:: sh
conda activate rdagent
- 🛠️ Run Make Files
- Navigate to the directory containing the MakeFile and set up the development environment:
.. code-block:: sh
make dev
- 📦 Install Pytorch
- Install Pytorch and related libraries:
.. code-block:: sh
pip3 install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cpu
pip3 install torch_geometric
- ⚙️ Environment Configuration
- Place the `.env` file in the same directory as the `.env.example` file.
- The `.env.example` file contains the environment variables required for users using the OpenAI API (Please note that `.env.example` is an example file. `.env` is the one that will be finally used.)
- Export each variable in the .env file:
.. code-block:: sh
export $(grep -v '^#' .env | xargs)
- 🚀 Run the Application
.. code-block:: sh
python rdagent/app/qlib_rd_loop/model_w_sc.py
conda activate rdagent
- 📦 Install the RDAgent
- You can install the RDAgent package from PyPI:
.. code-block:: sh
pip install rdagent
- 🚀 Run the Application
- You can directly run the application by using the following command:
.. code-block:: sh
rdagent fin_model
🛠️ Usage of modules
~~~~~~~~~~~~~~~~~~~~~
TODO: Show some examples:
.. _Env Config:
- **Env Config**
The following environment variables can be set in the `.env` file to customize the application's behavior:
.. autopydantic_settings:: rdagent.app.qlib_rd_loop.conf.ModelBasePropSetting
:settings-show-field-summary: False
:exclude-members: Config
- **Qlib Config**
- The `config.yaml` file located in the `model_template` folder contains the relevant configurations for running the developed model in Qlib. The default settings include key information such as:
- **market**: Specifies the market, which is set to `csi300`.
- **fields_group**: Defines the fields group, with the value `feature`.
- **col_list**: A list of columns used, including various indicators such as `RESI5`, `WVMA5`, `RSQR5`, and others.
- **start_time**: The start date for the data, set to `2008-01-01`.
- **end_time**: The end date for the data, set to `2020-08-01`.
- **fit_start_time**: The start date for fitting the model, set to `2008-01-01`.
- **fit_end_time**: The end date for fitting the model, set to `2014-12-31`.
- The default hyperparameters used in the configuration are as follows:
- **n_epochs**: The number of epochs, set to `100`.
- **lr**: The learning rate, set to `1e-3`.
- **early_stop**: The early stopping criterion, set to `10`.
- **batch_size**: The batch size, set to `2000`.
- **metric**: The evaluation metric, set to `loss`.
- **loss**: The loss function, set to `mse`.
- **n_jobs**: The number of parallel jobs, set to `20`.
+125 -2
View File
@@ -1,5 +1,128 @@
.. _model_agent_med:
===================
=======================
Medical Model Agent
===================
=======================
**🤖 Automated Medical Predtion Model Evolution**
------------------------------------------------------------------------------------------
📖 Background
~~~~~~~~~~~~~~
In this scenario, we consider the problem of risk prediction from patients' ICU monitoring data. We use the a public EHR dataset - MIMIC-III and extract a binary classification task for evaluating the framework.
In this task, we aim at predicting the whether the patients will suffer from Acute Respiratory Failure (ARF) based their first 12 hours ICU monitoring data.
🎥 `Demo <https://rdagent.azurewebsites.net/dmm>`_
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. raw:: html
<div style="display: flex; justify-content: center; align-items: center;">
<video width="600" controls>
<source src="https://rdagent.azurewebsites.net/media/1653542fc1b9fa14a306c35c1b1fc48288f980793f38abe82b023af9.mp4" type="video/mp4">
Your browser does not support the video tag.
</video>
</div>
🌟 Introduction
~~~~~~~~~~~~~~~~
In this scenario, our automated system proposes hypothesis, constructs model, implements code, receives back-testing, and uses feedbacks.
Hypothesis is iterated in this continuous process.
The system aims to automatically optimise performance metrics of medical prediction thereby finding the optimised code through autonomous research and development.
Here's an enhanced outline of the steps:
**Step 1 : Hypothesis Generation 🔍**
- Generate and propose initial hypotheses based on previous experiment analysis and domain expertise, with thorough reasoning and justification.
**Step 2 : Model Creation ✨**
- Transform the hypothesis into a model.
- Develop, define, and implement a machine learning model, including its name, description, and formulation.
**Step 3 : Model Implementation 👨‍💻**
- Implement the model code based on the detailed description.
- Evolve the model iteratively as a developer would, ensuring accuracy and efficiency.
**Step 4 : Backtesting with MIMIC-III 📉**
- Conduct backtesting using the newly developed model on the extracted task from MIMIC-III.
- Evaluate the model's effectiveness and performance in terms of AUROC score.
**Step 5 : Feedback Analysis 🔍**
- Analyze backtest results to assess performance.
- Incorporate feedback to refine hypotheses and improve the model.
**Step 6 :Hypothesis Refinement ♻️**
- Refine hypotheses based on feedback from backtesting.
- Repeat the process to continuously improve the model.
⚡ Quick Start
~~~~~~~~~~~~~~~~~
Please refer to the installation part in :doc:`../installation_and_configuration` to prepare your system dependency.
You can try our demo by running the following command:
- 🐍 Create a Conda Environment
- Create a new conda environment with Python (3.10 and 3.11 are well tested in our CI):
.. code-block:: sh
conda create -n rdagent python=3.10
- Activate the environment:
.. code-block:: sh
conda activate rdagent
- 📦 Install the RDAgent
- You can install the RDAgent package from PyPI:
.. code-block:: sh
pip install rdagent
- 📦 Request PhysioNet Account
- Apply for an account at `PhysioNet <https://physionet.org/>`_.
- Request access to FIDDLE preprocessed data: `FIDDLE Dataset <https://physionet.org/content/mimic-eicu-fiddle-feature/1.0.0/>`_.
- Place your username and password in `.env`.
.. code-block:: bash
cat << EOF >> .env
DM_USERNAME=<your_username>
DM_PASSWORD=<your_password>
EOF
- 🚀 Run the Application
- You can directly run the application by using the following command:
.. code-block:: sh
rdagent med_model
🛠️ Usage of modules
~~~~~~~~~~~~~~~~~~~~~
.. _Env Config:
- **Env Config**
The following environment variables can be set in the `.env` file to customize the application's behavior:
.. autopydantic_settings:: rdagent.app.data_mining.conf.PropSetting
:settings-show-field-summary: False
:exclude-members: Config
+40 -64
View File
@@ -9,11 +9,23 @@ General Model Copilot
📖 Background
~~~~~~~~~~~~~~
TODO:
In the fast-paced field of artificial intelligence, the number of academic papers published each year is skyrocketing.
These papers introduce new models, techniques, and approaches that can significantly advance the state of the art.
However, reproducing and implementing these models can be a daunting task, requiring substantial time and expertise.
Researchers often face challenges in extracting the essential details from these papers and converting them into functional code.
And this is where the **General Model Copilot** steps in.
🎥 Demo
~~~~~~~~~~
TODO: Here should put a video of the demo.
🎥 `Demo <https://rdagent.azurewebsites.net/report_model>`_
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. raw:: html
<div style="display: flex; justify-content: center; align-items: center;">
<video width="600" controls>
<source src="https://rdagent.azurewebsites.net/media/b35f904765b05099b0fcddbebe041a04f4d7bde239657e5fc24bf0cc.mp4" type="video/mp4">
Your browser does not support the video tag.
</video>
</div>
🌟 Introduction
~~~~~~~~~~~~~~~~
@@ -45,79 +57,43 @@ This demo automates the extraction and iterative development of models from acad
⚡ Quick Start
~~~~~~~~~~~~~~~~~
Please refer to the installation part in :doc:`../installation_and_configuration` to prepare your system dependency.
You can try our demo by running the following command:
- 🐍 Create a Conda Environment
- Create a new conda environment with Python (3.10 and 3.11 are well tested in our CI):
- Create a new conda environment with Python (3.10 and 3.11 are well tested in our CI):
.. code-block:: sh
.. code-block:: sh
conda create -n rdagent python=3.10
conda create -n rdagent python=3.10
- Activate the environment:
- Activate the environment:
.. code-block:: sh
.. code-block:: sh
conda activate rdagent
conda activate rdagent
- 🛠️ Run Make Files
- Navigate to the directory containing the MakeFile and set up the development environment:
- 📦 Install the RDAgent
- You can install the RDAgent package from PyPI:
.. code-block:: sh
.. code-block:: sh
make dev
pip install rdagent
- 📦 Install Pytorch
- Install Pytorch and related libraries:
.. code-block:: sh
pip3 install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cpu
pip3 install torch_geometric
- ⚙️ Environment Configuration
- Place the `.env` file in the same directory as the `.env.example` file.
- The `.env.example` file contains the environment variables required for users using the OpenAI API (Please note that `.env.example` is an example file. `.env` is the one that will be finally used.)
- Export each variable in the .env file:
.. code-block:: sh
export $(grep -v '^#' .env | xargs)
- 🚀 Run the Application
- Prepare relevant files (in pdf format) by uploading papers to the directory below and copy the path as report_file_path.
.. code-block:: sh
rdagent/scenarios/general_model
- Run the following command in your terminal within the same virtual environment:
- Prepare relevant files (in pdf format) by uploading papers to the directory below and copy the path as report_file_path.
.. code-block:: sh
.. code-block:: sh
rdagent/scenarios/general_model
- Run the following command in your terminal within the same virtual environment:
.. code-block:: sh
python rdagent/app/general_model/general_model.py report_file_path
🛠️ Usage of modules
~~~~~~~~~~~~~~~~~~~~~
There are mainly two modules in this scenario: one that reads the paper and returns a model card & one that reads the model card and returns functional code. The moduldes can also be used separately as components for developers to build up new scenarios.
- Configurations
- The `config.yaml` file located in the `model_template` folder contains the relevant configurations for running the developed model in Qlib. The default settings include key information such as:
- **market**: Specifies the market, which is set to `csi300`.
- **fields_group**: Defines the fields group, with the value `feature`.
- **col_list**: A list of columns used, including various indicators such as `RESI5`, `WVMA5`, `RSQR5`, and others.
- **start_time**: The start date for the data, set to `2008-01-01`.
- **end_time**: The end date for the data, set to `2020-08-01`.
- **fit_start_time**: The start date for fitting the model, set to `2008-01-01`.
- **fit_end_time**: The end date for fitting the model, set to `2014-12-31`.
- The default hyperparameters used in the configuration are as follows:
- **n_epochs**: The number of epochs, set to `100`.
- **lr**: The learning rate, set to `1e-3`.
- **early_stop**: The early stopping criterion, set to `10`.
- **batch_size**: The batch size, set to `2000`.
- **metric**: The evaluation metric, set to `loss`.
- **loss**: The loss function, set to `mse`.
- **n_jobs**: The number of parallel jobs, set to `20`.
rdagent general_model --report_file_path=<path_to_pdf_file>
+4 -1
View File
@@ -18,18 +18,21 @@ In `RD-Agent/` folder, run:
.. code-block:: bash
streamlit run rdagent/log/ui/app.py --server.port <port> -- --log_dir <log_dir>
rdagent ui --port <port> --log_dir <log_dir like "log/"> [--debug]
This will start a web app on `http://localhost:<port>`.
**NOTE**: The log_dir parameter is not required. You can manually enter the log_path in the web app. If you set the log_dir parameter, you can easily select a different log_path in the web app.
--debug is optional, it will show a "Single Step Run" button in sidebar and saved objects info in the web app.
Use Web App
-----------
1. Open the sidebar.
.. TODO: update these
2. Select the scenario you want to show. There are some pre-defined scenarios:
- Qlib Model
- Qlib Factor
+3
View File
@@ -31,6 +31,9 @@ name = "rdagent"
readme = "README.md"
requires-python = ">=3.10"
[project.scripts]
rdagent = "rdagent.app.cli:app"
[project.urls]
homepage = "https://github.com/microsoft/RD-Agent/"
issue = "https://github.com/microsoft/RD-Agent/issues"
+20 -19
View File
@@ -15,27 +15,28 @@ from rdagent.scenarios.qlib.factor_experiment_loader.json_loader import (
FactorTestCaseLoaderFromJsonFile,
)
# 1.read the settings
bs = BenchmarkSettings()
if __name__ == "__main__":
# 1.read the settings
bs = BenchmarkSettings()
# 2.read and prepare the eval_data
test_cases = FactorTestCaseLoaderFromJsonFile().load(bs.bench_data_path)
# 2.read and prepare the eval_data
test_cases = FactorTestCaseLoaderFromJsonFile().load(bs.bench_data_path)
# 3.declare the method to be tested and pass the arguments.
# 3.declare the method to be tested and pass the arguments.
scen: Scenario = import_class(FACTOR_PROP_SETTING.scen)()
generate_method = import_class(bs.bench_method_cls)(scen=scen)
# 4.declare the eval method and pass the arguments.
eval_method = FactorImplementEval(
method=generate_method,
test_cases=test_cases,
scen=scen,
catch_eval_except=True,
test_round=bs.bench_test_round,
)
scen: Scenario = import_class(FACTOR_PROP_SETTING.scen)()
generate_method = import_class(bs.bench_method_cls)(scen=scen)
# 4.declare the eval method and pass the arguments.
eval_method = FactorImplementEval(
method=generate_method,
test_cases=test_cases,
scen=scen,
catch_eval_except=True,
test_round=bs.bench_test_round,
)
# 5.run the eval
res = eval_method.eval()
# 5.run the eval
res = eval_method.eval()
# 6.save the result
logger.log_object(res)
# 6.save the result
logger.log_object(res)
-14
View File
@@ -1,17 +1,3 @@
# Preparation
## Install Pytorch
CPU CUDA will be enough for verify the implementation
Please install pytorch based on your system.
Here is an example on my system
```bash
pip3 install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cpu
pip3 install torch_geometric
```
# Tasks
## Task Extraction
+23 -22
View File
@@ -7,35 +7,36 @@ from rdagent.scenarios.qlib.experiment.model_experiment import (
QlibModelScenario,
)
DIRNAME = Path(__file__).absolute().resolve().parent
if __name__ == "__main__":
DIRNAME = Path(__file__).absolute().resolve().parent
from rdagent.components.coder.model_coder.benchmark.eval import ModelImpValEval
from rdagent.components.coder.model_coder.one_shot import ModelCodeWriter
from rdagent.components.coder.model_coder.benchmark.eval import ModelImpValEval
from rdagent.components.coder.model_coder.one_shot import ModelCodeWriter
bench_folder = DIRNAME.parent.parent / "components" / "coder" / "model_coder" / "benchmark"
mtl = ModelTaskLoaderJson(str(bench_folder / "model_dict.json"))
bench_folder = DIRNAME.parent.parent / "components" / "coder" / "model_coder" / "benchmark"
mtl = ModelTaskLoaderJson(str(bench_folder / "model_dict.json"))
task_l = mtl.load()
task_l = mtl.load()
task_l = [t for t in task_l if t.name == "A-DGN"] # FIXME: other models does not work well
task_l = [t for t in task_l if t.name == "A-DGN"] # FIXME: other models does not work well
model_experiment = QlibModelExperiment(sub_tasks=task_l)
# mtg = ModelCodeWriter(scen=QlibModelScenario())
mtg = ModelCoSTEER(scen=QlibModelScenario())
model_experiment = QlibModelExperiment(sub_tasks=task_l)
# mtg = ModelCodeWriter(scen=QlibModelScenario())
mtg = ModelCoSTEER(scen=QlibModelScenario())
model_experiment = mtg.develop(model_experiment)
model_experiment = mtg.develop(model_experiment)
# TODO: Align it with the benchmark framework after @wenjun's refine the evaluation part.
# Currently, we just handcraft a workflow for fast evaluation.
# TODO: Align it with the benchmark framework after @wenjun's refine the evaluation part.
# Currently, we just handcraft a workflow for fast evaluation.
mil = ModelWsLoader(bench_folder / "gt_code")
mil = ModelWsLoader(bench_folder / "gt_code")
mie = ModelImpValEval()
# Evaluation:
eval_l = []
for impl in model_experiment.sub_workspace_list:
print(impl.target_task)
gt_impl = mil.load(impl.target_task)
eval_l.append(mie.evaluate(gt_impl, impl))
mie = ModelImpValEval()
# Evaluation:
eval_l = []
for impl in model_experiment.sub_workspace_list:
print(impl.target_task)
gt_impl = mil.load(impl.target_task)
eval_l.append(mie.evaluate(gt_impl, impl))
print(eval_l)
print(eval_l)
+55
View File
@@ -0,0 +1,55 @@
"""
CLI entrance for all rdagent application.
This will
- make rdagent a nice entry and
- autoamtically load dotenv
"""
from dotenv import load_dotenv
load_dotenv(".env")
# 1) Make sure it is at the beginning of the script so that it will load dotenv before initializing BaseSettings.
# 2) The ".env" argument is necessary to make sure it loads `.env` from the current directory.
import subprocess
from importlib.resources import path as rpath
import fire
from rdagent.app.data_mining.model import main as med_model
from rdagent.app.general_model.general_model import (
extract_models_and_implement as general_model,
)
from rdagent.app.qlib_rd_loop.factor import main as fin_factor
from rdagent.app.qlib_rd_loop.factor_from_report import main as fin_factor_report
from rdagent.app.qlib_rd_loop.model import main as fin_model
from rdagent.app.utils.info import collect_info
def ui(port=80, log_dir="", debug=False):
"""
start web app to show the log traces.
"""
with rpath("rdagent.log.ui", "app.py") as app_path:
cmds = ["streamlit", "run", app_path, f"--server.port={port}"]
if log_dir or debug:
cmds.append("--")
if log_dir:
cmds.append(f"--log_dir={log_dir}")
if debug:
cmds.append("--debug")
subprocess.run(cmds)
def app():
fire.Fire(
{
"fin_factor": fin_factor,
"fin_factor_report": fin_factor_report,
"fin_model": fin_model,
"med_model": med_model,
"general_model": general_model,
"ui": ui,
"collect_info": collect_info,
}
)
+23 -2
View File
@@ -1,20 +1,38 @@
from pathlib import Path
from pydantic_settings import BaseSettings
from rdagent.components.workflow.conf import BasePropSetting
class PropSetting(BasePropSetting):
class Config:
env_prefix = "DM_" # Use MODEL_CODER_ as prefix for environment variables
protected_namespaces = () # Add 'model_' to the protected namespaces
env_prefix = "DM_"
"""Use `DM_` as prefix for environment variables"""
protected_namespaces = ()
"""Add 'model_' to the protected namespaces"""
# 1) overriding the default
scen: str = "rdagent.scenarios.data_mining.experiment.model_experiment.DMModelScenario"
"""Scenario class for data mining model"""
hypothesis_gen: str = "rdagent.scenarios.data_mining.proposal.model_proposal.DMModelHypothesisGen"
"""Hypothesis generation class"""
hypothesis2experiment: str = "rdagent.scenarios.data_mining.proposal.model_proposal.DMModelHypothesis2Experiment"
"""Hypothesis to experiment class"""
coder: str = "rdagent.scenarios.data_mining.developer.model_coder.DMModelCoSTEER"
"""Coder class"""
runner: str = "rdagent.scenarios.data_mining.developer.model_runner.DMModelRunner"
"""Runner class"""
summarizer: str = "rdagent.scenarios.data_mining.developer.feedback.DMModelHypothesisExperiment2Feedback"
"""Summarizer class"""
evolving_n: int = 10
"""Number of evolutions"""
evolving_n: int = 10
@@ -22,7 +40,10 @@ class PropSetting(BasePropSetting):
# physionet account
# NOTE: You should apply the account in https://physionet.org/
username: str = ""
"""Physionet account username"""
password: str = ""
"""Physionet account password"""
PROP_SETTING = PropSetting()
+2
View File
@@ -11,6 +11,8 @@ class ModelRDLoop(RDLoop):
def main(path=None, step_n=None):
"""
Auto R&D Evolving loop for models in a medical scenario.
You can continue running session by
.. code-block:: python
+20 -10
View File
@@ -1,10 +1,3 @@
# %%
from dotenv import load_dotenv
from rdagent.scenarios.general_model.scenario import GeneralModelScenario
load_dotenv(override=True)
import fire
from rdagent.components.coder.model_coder.task_loader import (
@@ -14,12 +7,29 @@ from rdagent.components.document_reader.document_reader import (
extract_first_page_screenshot_from_pdf,
)
from rdagent.log import rdagent_logger as logger
from rdagent.scenarios.general_model.scenario import GeneralModelScenario
from rdagent.scenarios.qlib.developer.model_coder import QlibModelCoSTEER
def extract_models_and_implement(
report_file_path: str,
) -> None:
def extract_models_and_implement(report_file_path: str) -> None:
"""
This is a research copilot to automatically implement models from a report file or paper.
It extracts models from a given PDF report file and implements the necessary operations.
Parameters:
report_file_path (str): The path to the report file. The file must be a PDF file.
Example URLs of PDF reports:
- https://arxiv.org/pdf/2210.09789
- https://arxiv.org/pdf/2305.10498
- https://arxiv.org/pdf/2110.14446
- https://arxiv.org/pdf/2205.12454
- https://arxiv.org/pdf/2210.16518
Returns:
None
"""
with logger.tag("init"):
scenario = GeneralModelScenario()
logger.log_object(scenario, tag="scenario")
+42
View File
@@ -0,0 +1,42 @@
from pathlib import Path
from pydantic_settings import BaseSettings
from rdagent.components.workflow.conf import BasePropSetting
class PropSetting(BasePropSetting):
class Config:
env_prefix = "KG_"
"""Use `KG_` as prefix for environment variables"""
protected_namespaces = ()
"""Add 'model_' to the protected namespaces"""
# 1) overriding the default
scen: str = "rdagent.scenarios.kaggle.experiment.model_experiment.KGModelScenario"
"""Scenario class for data mining model"""
hypothesis_gen: str = "rdagent.scenarios.kaggle.proposal.model_proposal.KGModelHypothesisGen"
"""Hypothesis generation class"""
hypothesis2experiment: str = "rdagent.scenarios.kaggle.proposal.model_proposal.KGModelHypothesis2Experiment"
"""Hypothesis to experiment class"""
coder: str = "rdagent.scenarios.kaggle.developer.model_coder.KGModelCoSTEER"
"""Coder class"""
runner: str = "rdagent.scenarios.kaggle.developer.model_runner.KGModelRunner"
"""Runner class"""
summarizer: str = "rdagent.scenarios.kaggle.developer.feedback.KGModelHypothesisExperiment2Feedback"
"""Summarizer class"""
evolving_n: int = 10
"""Number of evolutions"""
evolving_n: int = 10
competition: str = ""
PROP_SETTING = PropSetting()
+65
View File
@@ -0,0 +1,65 @@
from collections import defaultdict
import fire
from rdagent.app.kaggle.conf import PROP_SETTING
from rdagent.components.workflow.conf import BasePropSetting
from rdagent.components.workflow.rd_loop import RDLoop
from rdagent.core.exception import ModelEmptyError
from rdagent.core.proposal import (
Hypothesis2Experiment,
HypothesisExperiment2Feedback,
HypothesisGen,
Trace,
)
from rdagent.core.utils import import_class
from rdagent.log import rdagent_logger as logger
class ModelRDLoop(RDLoop):
def __init__(self, PROP_SETTING: BasePropSetting):
with logger.tag("init"):
scen: Scenario = import_class(PROP_SETTING.scen)(PROP_SETTING.competition)
logger.log_object(scen, tag="scenario")
self.hypothesis_gen: HypothesisGen = import_class(PROP_SETTING.hypothesis_gen)(scen)
logger.log_object(self.hypothesis_gen, tag="hypothesis generator")
self.hypothesis2experiment: Hypothesis2Experiment = import_class(PROP_SETTING.hypothesis2experiment)()
logger.log_object(self.hypothesis2experiment, tag="hypothesis2experiment")
self.coder: Developer = import_class(PROP_SETTING.coder)(scen)
logger.log_object(self.coder, tag="coder")
self.runner: Developer = import_class(PROP_SETTING.runner)(scen)
logger.log_object(self.runner, tag="runner")
self.summarizer: HypothesisExperiment2Feedback = import_class(PROP_SETTING.summarizer)(scen)
logger.log_object(self.summarizer, tag="summarizer")
self.trace = Trace(scen=scen)
super(RDLoop, self).__init__()
skip_loop_error = (ModelEmptyError,)
def main(path=None, step_n=None, competition=None):
"""
Auto R&D Evolving loop for models in a kaggle{} scenario.
You can continue running session by
.. code-block:: python
dotenv run -- python rdagent/app/kaggle/model.py [--competition titanic] $LOG_PATH/__session__/1/0_propose --step_n 1 # `step_n` is a optional paramter
"""
if competition:
PROP_SETTING.competition = competition
if path is None:
model_loop = ModelRDLoop(PROP_SETTING)
else:
model_loop = ModelRDLoop.load(path)
model_loop.run(step_n=step_n)
if __name__ == "__main__":
fire.Fire(main)
-112
View File
@@ -1,112 +0,0 @@
import pickle
from rdagent.app.qlib_rd_loop.conf import PROP_SETTING
from rdagent.core.developer import Developer
from rdagent.core.exception import ModelEmptyError
from rdagent.core.proposal import (
Hypothesis2Experiment,
HypothesisExperiment2Feedback,
HypothesisGen,
Trace,
)
from rdagent.core.scenario import Scenario
from rdagent.core.utils import import_class
from rdagent.log import rdagent_logger as logger
# TODO: we can design a workflow that can automatically save session and traceback in the future
class Model_RD_Agent:
def __init__(self):
self.scen: Scenario = import_class(PROP_SETTING.model_scen)()
self.hypothesis_gen: HypothesisGen = import_class(PROP_SETTING.model_hypothesis_gen)(self.scen)
self.hypothesis2experiment: Hypothesis2Experiment = import_class(PROP_SETTING.model_hypothesis2experiment)()
self.qlib_model_coder: Developer = import_class(PROP_SETTING.model_coder)(self.scen)
self.qlib_model_runner: Developer = import_class(PROP_SETTING.model_runner)(self.scen)
self.qlib_model_summarizer: HypothesisExperiment2Feedback = import_class(PROP_SETTING.model_summarizer)(
self.scen
)
self.trace = Trace(scen=self.scen)
def generate_hypothesis(self):
hypothesis = self.hypothesis_gen.gen(self.trace)
self.dump_objects(hypothesis=hypothesis, trace=self.trace, filename="step_hypothesis.pkl")
return hypothesis
def convert_hypothesis(self, hypothesis):
exp = self.hypothesis2experiment.convert(hypothesis, self.trace)
self.dump_objects(exp=exp, hypothesis=hypothesis, trace=self.trace, filename="step_experiment.pkl")
return exp
def generate_code(self, exp):
exp = self.qlib_model_coder.develop(exp)
self.dump_objects(exp=exp, trace=self.trace, filename="step_code.pkl")
return exp
def run_experiment(self, exp):
exp = self.qlib_model_runner.develop(exp)
self.dump_objects(exp=exp, trace=self.trace, filename="step_run.pkl")
return exp
def generate_feedback(self, exp, hypothesis):
feedback = self.qlib_model_summarizer.generate_feedback(exp, hypothesis, self.trace)
self.dump_objects(
exp=exp, hypothesis=hypothesis, feedback=feedback, trace=self.trace, filename="step_feedback.pkl"
)
return feedback
def append_to_trace(self, hypothesis, exp, feedback):
self.trace.hist.append((hypothesis, exp, feedback))
self.dump_objects(trace=self.trace, filename="step_trace.pkl")
def dump_objects(self, exp=None, hypothesis=None, feedback=None, trace=None, filename="dumped_objects.pkl"):
with open(filename, "wb") as f:
pickle.dump((exp, hypothesis, feedback, trace or self.trace), f)
def load_objects(self, filename):
with open(filename, "rb") as f:
return pickle.load(f)
def process_steps(agent):
# Load trace if available
try:
_, _, _, trace = agent.load_objects("step_trace.pkl")
agent.trace = trace
print(trace.get_sota_hypothesis_and_experiment())
except FileNotFoundError:
pass
# # # Step 1: Generate hypothesis
# try:
# _, hypothesis, _, _ = agent.load_objects('step_hypothesis.pkl')
# except FileNotFoundError:
hypothesis = agent.generate_hypothesis()
# # # Step 2: Convert hypothesis
# try:
# exp, _, _, _ = agent.load_objects('step_experiment.pkl')
# except FileNotFoundError:
# exp = agent.convert_hypothesis(hypothesis)
# # # Step 3: Generate code
# try:
# exp, _, _, _ = agent.load_objects('step_code.pkl')
# except FileNotFoundError:
# exp = agent.generate_code(exp)
# # # Step 4: Run experiment
# try:
# exp, _, _, _ = agent.load_objects('step_run.pkl')
# except FileNotFoundError:
# exp = agent.run_experiment(exp)
# # Step 5: Generate feedback
# feedback = agent.generate_feedback(exp, hypothesis)
# # Step 6: Append to trace
# agent.append_to_trace(hypothesis, exp, feedback)
if __name__ == "__main__":
agent = Model_RD_Agent()
process_steps(agent)
+44 -10
View File
@@ -1,45 +1,79 @@
from pydantic_settings import BaseSettings
from rdagent.components.workflow.conf import BasePropSetting
class ModelBasePropSetting(BasePropSetting):
class Config:
env_prefix = "QLIB_MODEL_" # Use MODEL_CODER_ as prefix for environment variables
protected_namespaces = () # Add 'model_' to the protected namespaces
env_prefix = "QLIB_MODEL_"
"""Use `QLIB_MODEL_` as prefix for environment variables"""
protected_namespaces = ()
"""Add 'model_' to the protected namespaces"""
# 1) override base settings
scen: str = "rdagent.scenarios.qlib.experiment.model_experiment.QlibModelScenario"
"""Scenario class for Qlib Model"""
hypothesis_gen: str = "rdagent.scenarios.qlib.proposal.model_proposal.QlibModelHypothesisGen"
"""Hypothesis generation class"""
hypothesis2experiment: str = "rdagent.scenarios.qlib.proposal.model_proposal.QlibModelHypothesis2Experiment"
"""Hypothesis to experiment class"""
coder: str = "rdagent.scenarios.qlib.developer.model_coder.QlibModelCoSTEER"
"""Coder class"""
runner: str = "rdagent.scenarios.qlib.developer.model_runner.QlibModelRunner"
"""Runner class"""
summarizer: str = "rdagent.scenarios.qlib.developer.feedback.QlibModelHypothesisExperiment2Feedback"
"""Summarizer class"""
evolving_n: int = 10
"""Number of evolutions"""
class FactorBasePropSetting(BasePropSetting):
class Config:
env_prefix = "QLIB_FACTOR_" # Use MODEL_CODER_ as prefix for environment variables
protected_namespaces = () # Add 'model_' to the protected namespaces
env_prefix = "QLIB_FACTOR_"
"""Use `QLIB_FACTOR_` as prefix for environment variables"""
protected_namespaces = ()
"""Add 'factor_' to the protected namespaces"""
# 1) override base settings
# TODO: model part is not finished yet
scen: str = "rdagent.scenarios.qlib.experiment.factor_experiment.QlibFactorScenario"
"""Scenario class for Qlib Factor"""
hypothesis_gen: str = "rdagent.scenarios.qlib.proposal.factor_proposal.QlibFactorHypothesisGen"
"""Hypothesis generation class"""
hypothesis2experiment: str = "rdagent.scenarios.qlib.proposal.factor_proposal.QlibFactorHypothesis2Experiment"
"""Hypothesis to experiment class"""
coder: str = "rdagent.scenarios.qlib.developer.factor_coder.QlibFactorCoSTEER"
"""Coder class"""
runner: str = "rdagent.scenarios.qlib.developer.factor_runner.QlibFactorRunner"
"""Runner class"""
summarizer: str = "rdagent.scenarios.qlib.developer.feedback.QlibFactorHypothesisExperiment2Feedback"
"""Summarizer class"""
evolving_n: int = 10
# 2) sub task specific:
report_result_json_file_path: str = "git_ignore_folder/report_list.json"
max_factors_per_exp: int = 10000
"""Number of evolutions"""
class FactorFromReportPropSetting(FactorBasePropSetting):
# Override the scen attribute
# 1) override the scen attribute
scen: str = "rdagent.scenarios.qlib.experiment.factor_from_report_experiment.QlibFactorFromReportScenario"
"""Scenario class for Qlib Factor from Report"""
# 2) sub task specific:
report_result_json_file_path: str = "git_ignore_folder/report_list.json"
"""Path to the JSON file listing research reports for factor extraction"""
max_factors_per_exp: int = 10000
"""Maximum number of factors implemented per experiment"""
FACTOR_PROP_SETTING = FactorBasePropSetting()
@@ -27,11 +27,13 @@ class FactorRDLoop(RDLoop):
def main(path=None, step_n=None):
"""
Auto R&D Evolving loop for fintech factors.
You can continue running session by
.. code-block:: python
dotenv run -- python rdagent/app/qlib_rd_loop/factor_w_sc.py $LOG_PATH/__session__/1/0_propose --step_n 1 # `step_n` is a optional paramter
dotenv run -- python rdagent/app/qlib_rd_loop/factor.py $LOG_PATH/__session__/1/0_propose --step_n 1 # `step_n` is a optional paramter
"""
if path is None:
@@ -6,7 +6,7 @@ import fire
from jinja2 import Environment, StrictUndefined
from rdagent.app.qlib_rd_loop.conf import FACTOR_FROM_REPORT_PROP_SETTING
from rdagent.app.qlib_rd_loop.factor_w_sc import FactorRDLoop
from rdagent.app.qlib_rd_loop.factor import FactorRDLoop
from rdagent.components.document_reader.document_reader import (
extract_first_page_screenshot_from_pdf,
load_and_process_pdfs_by_langchain,
@@ -85,7 +85,7 @@ def extract_hypothesis_and_exp_from_reports(report_file_path: str) -> Tuple[Qlib
pdf_screenshot = extract_first_page_screenshot_from_pdf(report_file_path)
logger.log_object(pdf_screenshot)
docs_dict = load_and_process_pdfs_by_langchain(Path(report_file_path))
docs_dict = load_and_process_pdfs_by_langchain(report_file_path)
factor_result = {
task.factor_name: {
@@ -103,9 +103,15 @@ def extract_hypothesis_and_exp_from_reports(report_file_path: str) -> Tuple[Qlib
class FactorReportLoop(FactorRDLoop, metaclass=LoopMeta):
def __init__(self, PROP_SETTING: FACTOR_FROM_REPORT_PROP_SETTING):
super().__init__(PROP_SETTING=PROP_SETTING)
self.judge_pdf_data_items = json.load(open(PROP_SETTING.report_result_json_file_path, "r"))
def __init__(self, report_folder: str = None):
super().__init__(PROP_SETTING=FACTOR_FROM_REPORT_PROP_SETTING)
if report_folder is None:
self.judge_pdf_data_items = json.load(
open(FACTOR_FROM_REPORT_PROP_SETTING.report_result_json_file_path, "r")
)
else:
self.judge_pdf_data_items = [i for i in Path(report_folder).rglob("*.pdf")]
self.pdf_file_index = 0
self.valid_pdf_file_count = 0
self.current_loop_hypothesis = None
@@ -140,19 +146,22 @@ class FactorReportLoop(FactorRDLoop, metaclass=LoopMeta):
return self.current_loop_exp
def main(path=None, step_n=None):
def main(report_folder=None, path=None, step_n=None):
"""
You can continue running session by
.. code-block:: python
dotenv run -- python rdagent/app/qlib_rd_loop/factor_from_report_w_sc.py $LOG_PATH/__session__/1/0_propose --step_n 1 # `step_n` is a optional parameter
Auto R&D Evolving loop for fintech factors (the factors are extracted from finance reports).
Args:
report_folder (str, optional): The folder contains the report PDF files. Reports will be loaded from this folder.
path (str, optional): The path for loading a session. If provided, the session will be loaded.
step_n (int, optional): Step number to continue running a session.
"""
if path is None:
model_loop = FactorReportLoop(FACTOR_FROM_REPORT_PROP_SETTING)
else:
if path is None and report_folder is None:
model_loop = FactorReportLoop()
elif path is not None:
model_loop = FactorReportLoop.load(path)
else:
model_loop = FactorReportLoop(report_folder=report_folder)
model_loop.run(step_n=step_n)
@@ -15,11 +15,13 @@ class ModelRDLoop(RDLoop):
def main(path=None, step_n=None):
"""
Auto R&D Evolving loop for fintech models
You can continue running session by
.. code-block:: python
dotenv run -- python rdagent/app/qlib_rd_loop/model_w_sc.py $LOG_PATH/__session__/1/0_propose --step_n 1 # `step_n` is a optional paramter
dotenv run -- python rdagent/app/qlib_rd_loop/model.py $LOG_PATH/__session__/1/0_propose --step_n 1 # `step_n` is a optional paramter
"""
if path is None:
+86
View File
@@ -0,0 +1,86 @@
import importlib.metadata
import platform
import sys
from pathlib import Path
import docker
import requests
from setuptools_scm import get_version
from rdagent.log import rdagent_logger as logger
def sys_info():
"""collect system related info"""
method_list = [
["Name of current operating system: ", "system"],
["Processor architecture: ", "machine"],
["System, version, and hardware information: ", "platform"],
["Version number of the system: ", "version"],
]
for method in method_list:
logger.info(f"{method[0]}{getattr(platform, method[1])()}")
return None
def python_info():
"""collect Python related info"""
python_version = sys.version.replace("\n", " ")
logger.info(f"Python version: {python_version}")
return None
def docker_info():
client = docker.from_env()
containers = client.containers.list(all=True)
if containers:
containers.sort(key=lambda c: c.attrs["Created"])
last_container = containers[-1]
logger.info(f"Container ID: {last_container.id}")
logger.info(f"Container Name: {last_container.name}")
logger.info(f"Container Status: {last_container.status}")
logger.info(f"Image ID used by the container: {last_container.image.id}")
logger.info(f"Image tag used by the container: {last_container.image.tags}")
logger.info(f"Container port mapping: {last_container.ports}")
logger.info(f"Container Label: {last_container.labels}")
logger.info(f"Startup Commands: {' '.join(client.containers.get(last_container.id).attrs['Config']['Cmd'])}")
else:
logger.info(f"No run containers.")
def rdagent_info():
"""collect rdagent related info"""
current_version = importlib.metadata.version("rdagent")
logger.info(f"RD-Agent version: {current_version}")
api_url = f"https://api.github.com/repos/microsoft/RD-Agent/contents/requirements.txt?ref=main"
response = requests.get(api_url)
if response.status_code == 200:
files = response.json()
file_url = files["download_url"]
file_response = requests.get(file_url)
if file_response.status_code == 200:
all_file_contents = file_response.text.split("\n")
else:
logger.warning(f"Failed to retrieve {files['name']}, status code: {file_response.status_code}")
else:
logger.warning(f"Failed to retrieve files in folder, status code: {response.status_code}")
package_list = [
item.split("#")[0].strip() for item in all_file_contents if item.strip() and not item.startswith("#")
]
package_version_list = []
for package in package_list:
if package == "typer[all]":
package = "typer"
version = importlib.metadata.version(package)
package_version_list.append(f"{package}=={version}")
logger.info(f"Package version: {package_version_list}")
return None
def collect_info():
"""Prints information about the system and the installed packages."""
sys_info()
python_info()
docker_info()
rdagent_info()
return None
-5
View File
@@ -2,13 +2,8 @@ from dataclasses import field
from pathlib import Path
from typing import Optional
from dotenv import load_dotenv
from pydantic_settings import BaseSettings
# Load environment variables
load_dotenv(verbose=True, override=True)
DIRNAME = Path("./")
@@ -133,7 +133,11 @@ class FactorSingleColumnEvaluator(FactorEvaluator):
gt_implementation: Workspace,
) -> Tuple[str, object]:
_, gen_df = self._get_df(gt_implementation, implementation)
if gen_df is None:
return (
"The source dataframe is None. Please check the implementation.",
False,
)
if len(gen_df.columns) == 1:
return "The source dataframe has only one column which is correct.", True
else:
@@ -241,7 +245,11 @@ class FactorRowCountEvaluator(FactorEvaluator):
gt_implementation: Workspace,
) -> Tuple[str, object]:
gt_df, gen_df = self._get_df(gt_implementation, implementation)
if gen_df is None:
return (
"The source dataframe is None. Please check the implementation.",
False,
)
if gen_df.shape[0] == gt_df.shape[0]:
return "Both dataframes have the same rows count.", True
else:
@@ -258,7 +266,11 @@ class FactorIndexEvaluator(FactorEvaluator):
gt_implementation: Workspace,
) -> Tuple[str, object]:
gt_df, gen_df = self._get_df(gt_implementation, implementation)
if gen_df is None:
return (
"The source dataframe is None. Please check the implementation.",
False,
)
if gen_df.index.equals(gt_df.index):
return "Both dataframes have the same index.", True
else:
@@ -275,7 +287,11 @@ class FactorMissingValuesEvaluator(FactorEvaluator):
gt_implementation: Workspace,
) -> Tuple[str, object]:
gt_df, gen_df = self._get_df(gt_implementation, implementation)
if gen_df is None:
return (
"The source dataframe is None. Please check the implementation.",
False,
)
if gen_df.isna().sum().sum() == gt_df.isna().sum().sum():
return "Both dataframes have the same missing values.", True
else:
@@ -292,7 +308,11 @@ class FactorEqualValueCountEvaluator(FactorEvaluator):
gt_implementation: Workspace,
) -> Tuple[str, object]:
gt_df, gen_df = self._get_df(gt_implementation, implementation)
if gen_df is None:
return (
"The source dataframe is None. Please check the implementation.",
-1,
)
try:
close_values = gen_df.sub(gt_df).abs().lt(1e-6)
result_int = close_values.astype(int)
@@ -323,7 +343,11 @@ class FactorCorrelationEvaluator(FactorEvaluator):
gt_implementation: Workspace,
) -> Tuple[str, object]:
gt_df, gen_df = self._get_df(gt_implementation, implementation)
if gen_df is None:
return (
"The source dataframe is None. Please check the implementation.",
False,
)
concat_df = pd.concat([gen_df, gt_df], axis=1)
concat_df.columns = ["source", "gt"]
ic = concat_df.groupby("datetime").apply(lambda df: df["source"].corr(df["gt"])).dropna().mean()
+26 -13
View File
@@ -8,19 +8,23 @@ SELECT_METHOD = Literal["random", "scheduler"]
class FactorImplementSettings(BaseSettings):
class Config:
env_prefix = "FACTOR_CODER_" # Use FACTOR_CODER_ as prefix for environment variables
env_prefix = "FACTOR_CODER_"
"""Use `FACTOR_CODER_` as prefix for environment variables"""
coder_use_cache: bool = False
data_folder: str = str(
(Path().cwd() / "git_ignore_folder" / "factor_implementation_source_data").absolute(),
)
data_folder_debug: str = str(
(Path().cwd() / "git_ignore_folder" / "factor_implementation_source_data_debug").absolute(),
)
cache_location: str = str(
(Path().cwd() / "git_ignore_folder" / "factor_implementation_execution_cache").absolute(),
)
enable_execution_cache: bool = True # whether to enable the execution cache
"""Indicates whether to use cache for the coder"""
data_folder: str = "git_ignore_folder/factor_implementation_source_data"
"""Path to the folder containing financial data (default is fundamental data in Qlib)"""
data_folder_debug: str = "git_ignore_folder/factor_implementation_source_data_debug"
"""Path to the folder containing partial financial data (for debugging)"""
cache_location: str = "git_ignore_folder/factor_implementation_execution_cache"
"""Path to the cache location"""
enable_execution_cache: bool = True
"""Indicates whether to enable the execution cache"""
# TODO: the factor implement specific settings should not appear in this settings
# Evolving should have a method specific settings
@@ -36,17 +40,26 @@ class FactorImplementSettings(BaseSettings):
v2_error_summary: bool = False
v2_knowledge_sampler: float = 1.0
file_based_execution_timeout: int = 120 # seconds for each factor implementation execution
file_based_execution_timeout: int = 120
"""Timeout in seconds for each factor implementation execution"""
select_method: str = "random"
"""Method for the selection of factors implementation"""
select_method: SELECT_METHOD = "random"
select_threshold: int = 10
"""Threshold for the number of factor selections"""
max_loop: int = 10
"""Maximum number of task implementation loops"""
knowledge_base_path: Union[str, None] = None
"""Path to the knowledge base"""
new_knowledge_base_path: Union[str, None] = None
"""Path to the new knowledge base"""
python_bin: str = "python"
"""Path to the Python binary"""
FACTOR_IMPLEMENT_SETTINGS = FactorImplementSettings()
@@ -26,13 +26,19 @@ evaluate_prompts = Prompts(file_path=Path(__file__).parent.parent / "prompts.yam
def shape_evaluator(prediction: torch.Tensor, target_shape: Tuple = None) -> Tuple[str, bool]:
if target_shape is None or prediction is None:
return "No output generated from the model. No shape evaluation conducted.", False
return (
"No output generated from the model. No shape evaluation conducted.",
False,
)
pre_shape = prediction.shape
if pre_shape == target_shape:
return "The shape of the output is correct.", True
else:
return f"The shape of the output is incorrect. Expected {target_shape}, but got {pre_shape}.", False
return (
f"The shape of the output is incorrect. Expected {target_shape}, but got {pre_shape}.",
False,
)
def reshape_tensor(original_tensor, target_shape):
@@ -50,7 +56,10 @@ def value_evaluator(
if prediction is None:
return "No output generated from the model. Skip value evaluation", False
elif target is None:
return "No ground truth output provided. Value evaluation not impractical", False
return (
"No ground truth output provided. Value evaluation not impractical",
False,
)
else:
# Calculate the mean absolute difference
diff = torch.mean(torch.abs(target - prediction)).item()
@@ -270,7 +279,11 @@ class ModelCoderEvaluator(Evaluator):
else:
gt_tensor = None
shape_feedback, shape_decision = shape_evaluator(gen_tensor, (batch_size, 1))
if target_task.model_type == "XGBoost":
shape_feedback = "Not applicable for XGBoost models"
shape_decision = True
else:
shape_feedback, shape_decision = shape_evaluator(gen_tensor, (batch_size, 1))
value_feedback, value_decision = value_evaluator(gt_tensor, gen_tensor)
code_feedback, _ = ModelCodeEvaluator(scen=self.scen).evaluate(
target_task=target_task,
@@ -1,92 +0,0 @@
"""
This file will be removed in the future and replaced by
- rdagent/app/model_implementation/eval.py
"""
import os
# randomly generate a input graph, node_feature and edge_index
# 1000 nodes, 128 dim node feature, 2000 edges
import torch
from dotenv import load_dotenv
from rdagent.components.coder.model_coder.CoSTEER.evaluators import (
shape_evaluator,
value_evaluator,
)
from rdagent.oai.llm_utils import APIBackend
assert load_dotenv()
formula_info = {
"name": "Anti-Symmetric Deep Graph Network (A-DGN)",
"description": "A framework for stable and non-dissipative DGN design. It ensures long-range information preservation between nodes and prevents gradient vanishing or explosion during training.",
"formulation": "x_u^{(l)} = x_u^{(l-1)} + \\epsilon \\sigma \\left( W^T x_u^{(l-1)} + \\Phi(X^{(l-1)}, N_u) + b \\right)",
"variables": {
"x_u^{(l)}": "The state of node u at layer l",
"\\epsilon": "The step size in the Euler discretization",
"\\sigma": "A monotonically non-decreasing activation function",
"W": "An anti-symmetric weight matrix",
"X^{(l-1)}": "The node feature matrix at layer l-1",
"N_u": "The set of neighbors of node u",
"b": "A bias vector",
},
}
system_prompt = "You are an assistant whose job is to answer user's question."
user_prompt = "With the following given information, write a python code using pytorch and torch_geometric to implement the model. This model is in the graph learning field, only have one layer. The input will be node_feature [num_nodes, dim_feature] and edge_index [2, num_edges], and they should be loaded from the files 'node_features.pt' and 'edge_index.pt'. There is not edge attribute or edge weight as input. The model should detect the node_feature and edge_index shape, if there is Linear transformation layer in the model, the input and output shape should be consistent. The in_channels is the dimension of the node features. You code should contain additional 'if __name__ == '__main__', where you should load the node_feature and edge_index from the files and run the model, and save the output to a file 'llm_output.pt'. Implement the model forward function based on the following information: model formula information. 1. model name: {}, 2. model description: {}, 3. model formulation: {}, 4. model variables: {}. You must complete the forward function as far as you can do.".format(
formula_info["name"],
formula_info["description"],
formula_info["formulation"],
formula_info["variables"],
)
resp = APIBackend(use_chat_cache=False).build_messages_and_create_chat_completion(user_prompt, system_prompt)
print(resp)
# take the code part from the response and save it to a file, the code is covered in the ```python``` block
code = resp.split("```python")[1].split("```")[0]
with open("llm_code.py", "w") as f:
f.write(code)
average_shape_eval = []
average_value_eval = []
for test_mode in ["zeros", "ones", "randn"]:
if test_mode == "zeros":
node_feature = torch.zeros(1000, 128)
elif test_mode == "ones":
node_feature = torch.ones(1000, 128)
elif test_mode == "randn":
node_feature = torch.randn(1000, 128)
edge_index = torch.randint(0, 1000, (2, 2000))
torch.save(node_feature, "node_features.pt")
torch.save(edge_index, "edge_index.pt")
try:
os.system("python llm_code.py")
except:
print("Error in running the LLM code")
os.system("python gt_code.py")
os.system("rm edge_index.pt")
os.system("rm node_features.pt")
# load the output and print the shape
try:
llm_output = torch.load("llm_output.pt")
except:
llm_output = None
gt_output = torch.load("gt_output.pt")
average_shape_eval.append(shape_evaluator(llm_output, gt_output)[1])
average_value_eval.append(value_evaluator(llm_output, gt_output)[1])
print("Shape evaluation: ", average_shape_eval[-1])
print("Value evaluation:super().develop(task_l) ", average_value_eval[-1])
os.system("rm llm_output.pt")
os.system("rm gt_output.pt")
os.system("rm llm_code.py")
print("Average shape evaluation: ", sum(average_shape_eval) / len(average_shape_eval))
print("Average value evaluation: ", sum(average_value_eval) / len(average_value_eval))
+33 -16
View File
@@ -6,7 +6,9 @@ import uuid
from pathlib import Path
from typing import Any, Dict, Optional
import numpy as np
import torch
import xgboost as xgb
from rdagent.components.coder.model_coder.conf import MODEL_IMPL_SETTINGS
from rdagent.core.exception import CodeFormatError
@@ -32,9 +34,7 @@ class ModelTask(Task):
self.architecture: str = architecture
self.variables: str = variables
self.hyperparameters: str = hyperparameters
self.model_type: str = (
model_type # Tabular for tabular model, TimesSeries for time series model, Graph for graph model
)
self.model_type: str = model_type # Tabular for tabular model, TimesSeries for time series model, Graph for graph model, XGBoost for XGBoost model
def get_task_information(self):
return f"""name: {self.name}
@@ -95,9 +95,17 @@ class ModelFBWorkspace(FBWorkspace):
if cache_file_path.exists():
return pickle.load(open(cache_file_path, "rb"))
mod = get_module_by_module_path(str(self.workspace_path / "model.py"))
model_cls = mod.model_cls
if self.target_task.model_type == "Tabular":
if self.target_task.model_type != "XGBoost":
model_cls = mod.model_cls
if self.target_task.model_type == "XGBoost":
X_simulated = np.random.rand(100, num_features) # 100 samples, `num_features` features each
y_simulated = np.random.randint(0, 2, 100) # Binary target for example
params = mod.get_params()
num_round = mod.get_num_round()
dtrain = xgb.DMatrix(X_simulated, label=y_simulated)
elif self.target_task.model_type == "Tabular":
input_shape = (batch_size, num_features)
m = model_cls(num_features=input_shape[1])
data = torch.full(input_shape, input_value)
@@ -113,21 +121,30 @@ class ModelFBWorkspace(FBWorkspace):
else:
raise ValueError(f"Unsupported model type: {self.target_task.model_type}")
# Initialize all parameters of `m` to `param_init_value`
for _, param in m.named_parameters():
param.data.fill_(param_init_value)
# Execute the model
if self.target_task.model_type == "Graph":
out = m(*data)
if self.target_task.model_type == "XGBoost":
bst = xgb.train(params, dtrain, num_round)
y_pred = bst.predict(dtrain)
execution_model_output = y_pred
execution_feedback_str = "Execution successful, model trained and predictions made."
else:
out = m(data)
# Initialize all parameters of `m` to `param_init_value`
for _, param in m.named_parameters():
param.data.fill_(param_init_value)
execution_model_output = out.cpu().detach()
execution_feedback_str = f"Execution successful, output tensor shape: {execution_model_output.shape}"
# Execute the model
if self.target_task.model_type == "Graph":
out = m(*data)
else:
out = m(data)
execution_model_output = out.cpu().detach()
execution_feedback_str = f"Execution successful, output tensor shape: {execution_model_output.shape}"
if MODEL_IMPL_SETTINGS.enable_execution_cache:
pickle.dump((execution_feedback_str, execution_model_output), open(cache_file_path, "wb"))
pickle.dump(
(execution_feedback_str, execution_model_output),
open(cache_file_path, "wb"),
)
except Exception as e:
execution_feedback_str = f"Execution error: {e}\nTraceback: {traceback.format_exc()}"
@@ -15,7 +15,7 @@ extract_model_formulation_system: |-
"hyperparameter_name_2": "value of hyperparameter 2",
"hyperparameter_name_3": "value of hyperparameter 3"
},
"model_type": "Tabular or TimeSeries or Graph" # Should be one of "Tabular", "TimeSeries", or "Graph"
"model_type": "Tabular or TimeSeries or Graph or XGBoost" # Should be one of "Tabular", "TimeSeries", "Graph", or "XGBoost"
}
}
Eg.
@@ -34,7 +34,7 @@ extract_model_formulation_system: |-
"hyperparameter_name_2": "value of hyperparameter 2",
"hyperparameter_name_3": "value of hyperparameter 3"
},
"model_type": "Tabular or TimeSeries or Graph" # Should be one of "Tabular", "TimeSeries", or "Graph"
"model_type": "Tabular or TimeSeries or Graph or RandomForest or XGBoost" # If torch & Neural network models are required, the choice should be one of "Tabular", "TimeSeries", or "Graph"
}
}
such format content should be begin with ```json and end with ``` and the content should be in json format.
@@ -99,7 +99,7 @@ evaluator_code_feedback:
The user will provide the source python code and the execution error message if execution failed.
The user might provide you the ground truth code for you to provide the critic. You should not leak the ground truth code to the user in any form but you can use it to provide the critic.
User has also compared the output generated by the user's code and the ground truth code. The user will provide you some analyze result comparing two output. You may find some error in the code which caused the difference between the two output.
User has also compared the output generated by the user's code and the ground truth code. The user will provide you some analysis results comparing two output. You may find some error in the code which caused the difference between the two output.
If the ground truth code is provided, your critic should only consider checking whether the user's code is align with the ground truth code since the ground truth is definitely correct.
If the ground truth code is not provided, your critic should consider checking whether the user's code is reasonable and correct to the description and to the scenario.
@@ -115,8 +115,8 @@ class ModelExperimentLoaderFromDict(ModelTaskLoader):
class ModelExperimentLoaderFromPDFfiles(ModelTaskLoader):
def load(self, file_or_folder_path: Path) -> dict:
docs_dict = load_and_process_pdfs_by_langchain(Path(file_or_folder_path)) # dict{file_path:content}
def load(self, file_or_folder_path: str) -> dict:
docs_dict = load_and_process_pdfs_by_langchain(file_or_folder_path) # dict{file_path:content}
model_dict = extract_model_from_docs(
docs_dict
) # dict{file_name: dict{model_name: dict{description, formulation, variables}}}
@@ -124,14 +124,3 @@ class ModelExperimentLoaderFromPDFfiles(ModelTaskLoader):
model_dict
) # dict {model_name: dict{description, formulation, variables}}
return ModelExperimentLoaderFromDict().load(model_dict)
def main(path="../test_doc"):
doc_dict = load_and_process_pdfs_by_langchain(Path(path))
print(doc_dict.keys()) # if you run code like "python -u", the print content will be truncated
import fire
if __name__ == "__main__":
fire.Fire(main)
@@ -1,12 +1,14 @@
from __future__ import annotations
import io
from pathlib import Path
from typing import TYPE_CHECKING
import fitz
import requests
from azure.ai.formrecognizer import DocumentAnalysisClient
from azure.core.credentials import AzureKeyCredential
from langchain.document_loaders import PyPDFDirectoryLoader, PyPDFLoader
from langchain_community.document_loaders import PyPDFDirectoryLoader, PyPDFLoader
from PIL import Image
if TYPE_CHECKING:
@@ -15,7 +17,7 @@ if TYPE_CHECKING:
from rdagent.core.conf import RD_AGENT_SETTINGS
def load_documents_by_langchain(path: Path) -> list:
def load_documents_by_langchain(path: str) -> list:
"""Load documents from the specified path.
Args:
@@ -24,7 +26,10 @@ def load_documents_by_langchain(path: Path) -> list:
Returns:
list: A list of loaded documents.
"""
loader = PyPDFDirectoryLoader(str(path), silent_errors=True) if path.is_dir() else PyPDFLoader(str(path))
if Path(path).is_dir():
loader = PyPDFDirectoryLoader(path, silent_errors=True)
else:
loader = PyPDFLoader(path)
return loader.load()
@@ -41,7 +46,10 @@ def process_documents_by_langchain(docs: list[Document]) -> dict[str, str]:
content_dict = {}
for doc in docs:
doc_name = str(Path(doc.metadata["source"]).resolve())
if Path(doc.metadata["source"]).exists():
doc_name = str(Path(doc.metadata["source"]).resolve())
else:
doc_name = doc.metadata["source"]
doc_content = doc.page_content
if doc_name not in content_dict:
@@ -52,7 +60,7 @@ def process_documents_by_langchain(docs: list[Document]) -> dict[str, str]:
return content_dict
def load_and_process_pdfs_by_langchain(path: Path) -> dict[str, str]:
def load_and_process_pdfs_by_langchain(path: str) -> dict[str, str]:
return process_documents_by_langchain(load_documents_by_langchain(path))
@@ -101,8 +109,11 @@ def load_and_process_pdfs_by_azure_document_intelligence(path: Path) -> dict[str
return content_dict
def extract_first_page_screenshot_from_pdf(pdf_path: Path) -> Image:
doc = fitz.open(pdf_path)
def extract_first_page_screenshot_from_pdf(pdf_path: str) -> Image:
if not Path(pdf_path).exists():
doc = fitz.open(stream=io.BytesIO(requests.get(pdf_path).content), filetype="pdf")
else:
doc = fitz.open(pdf_path)
page = doc.load_page(0)
pix = page.get_pixmap()
image = Image.frombytes("RGB", [pix.width, pix.height], pix.samples)
-6
View File
@@ -2,12 +2,6 @@ from __future__ import annotations
from pathlib import Path
from dotenv import load_dotenv
from pydantic_settings import BaseSettings
# make sure that env variable is loaded while calling Config()
load_dotenv(verbose=True, override=True)
from pydantic_settings import BaseSettings
+3 -6
View File
@@ -2,15 +2,11 @@ from __future__ import annotations
from pathlib import Path
from dotenv import load_dotenv
from pydantic_settings import BaseSettings
# TODO: use pydantic for other modules in Qlib
# from pydantic_settings import BaseSettings
# make sure that env variable is loaded while calling Config()
load_dotenv(verbose=True, override=True)
class RDAgentSettings(BaseSettings):
# TODO: (xiao) I think LLMSetting may be a better name.
@@ -38,7 +34,7 @@ class RDAgentSettings(BaseSettings):
chat_openai_api_key: str = ""
chat_azure_api_base: str = ""
chat_azure_api_version: str = ""
chat_model: str = ""
chat_model: str = "gpt-4-turbo"
chat_max_tokens: int = 3000
chat_temperature: float = 0.5
chat_stream: bool = True
@@ -96,8 +92,9 @@ class RDAgentSettings(BaseSettings):
gcr_endpoint_max_token: int = 100
# factor extraction conf
max_input_duplicate_factor_group: int = 600
max_input_duplicate_factor_group: int = 300
max_output_duplicate_factor_group: int = 20
max_kmeans_group_number: int = 40
# workspace conf
workspace_path: Path = Path.cwd() / "git_ignore_folder" / "RD-Agent_workspace"
+307 -226
View File
@@ -2,6 +2,7 @@ import argparse
import textwrap
from collections import defaultdict
from datetime import datetime, timezone
from importlib.resources import files as rfiles
from pathlib import Path
from typing import Callable, Type
@@ -10,9 +11,8 @@ import plotly.express as px
import plotly.graph_objects as go
import streamlit as st
from plotly.subplots import make_subplots
from st_btn_select import st_btn_select
from streamlit import session_state as state
from streamlit.delta_generator import DeltaGenerator
from streamlit_theme import st_theme
from rdagent.components.coder.factor_coder.CoSTEER.evaluators import (
FactorSingleFeedback,
@@ -21,14 +21,15 @@ from rdagent.components.coder.factor_coder.factor import FactorFBWorkspace, Fact
from rdagent.components.coder.model_coder.CoSTEER.evaluators import ModelCoderFeedback
from rdagent.components.coder.model_coder.model import ModelFBWorkspace, ModelTask
from rdagent.core.proposal import Hypothesis, HypothesisFeedback
from rdagent.core.scenario import Scenario
from rdagent.log.base import Message
from rdagent.log.storage import FileStorage
from rdagent.log.ui.qlib_report_figure import report_figure
from rdagent.scenarios.data_mining.experiment.model_experiment import DMModelScenario
from rdagent.scenarios.general_model.scenario import GeneralModelScenario
from rdagent.scenarios.qlib.experiment.factor_experiment import (
QlibFactorExperiment,
QlibFactorScenario,
from rdagent.scenarios.qlib.experiment.factor_experiment import QlibFactorScenario
from rdagent.scenarios.qlib.experiment.factor_from_report_experiment import (
QlibFactorFromReportScenario,
)
from rdagent.scenarios.qlib.experiment.model_experiment import (
QlibModelExperiment,
@@ -41,6 +42,7 @@ st.set_page_config(layout="wide", page_title="RD-Agent", page_icon="🎓", initi
# 获取log_path参数
parser = argparse.ArgumentParser(description="RD-Agent Streamlit App")
parser.add_argument("--log_dir", type=str, help="Path to the log directory")
parser.add_argument("--debug", action="store_true", help="Enable debug mode")
args = parser.parse_args()
if args.log_dir:
main_log_path = Path(args.log_dir)
@@ -58,14 +60,15 @@ SELECTED_METRICS = [
"1day.excess_return_without_cost.max_drawdown",
]
if "log_type" not in state:
state.log_type = "Qlib Model"
if "log_path" not in state:
if main_log_path:
state.log_path = next(main_log_path.iterdir()).relative_to(main_log_path)
else:
state.log_path = ""
state.log_path = None
st.toast(":red[**Please Set Log Path!**]", icon="⚠️")
if "scenario" not in state:
state.scenario = None
if "fs" not in state:
state.fs = None
@@ -104,23 +107,6 @@ if "alpha158_metrics" not in state:
state.alpha158_metrics = None
def refresh():
if main_log_path:
state.fs = FileStorage(main_log_path / state.log_path).iter_msg()
else:
state.fs = FileStorage(state.log_path).iter_msg()
state.msgs = defaultdict(lambda: defaultdict(list))
state.lround = 0
state.erounds = defaultdict(int)
state.e_decisions = defaultdict(lambda: defaultdict(tuple))
state.hypotheses = defaultdict(None)
state.h_decisions = defaultdict(bool)
state.metric_series = []
state.last_msg = None
state.current_tags = []
state.alpha158_metrics = None
def should_display(msg: Message):
for t in state.excluded_tags:
if t in msg.tag.split("."):
@@ -150,7 +136,7 @@ def get_msgs_until(end_func: Callable[[Message], bool] = lambda _: True):
# Update Summary Info
if "model runner result" in tags or "factor runner result" in tags or "runner result" in tags:
# factor baseline exp metrics
if state.log_type == "Qlib Factor" and state.alpha158_metrics is None:
if isinstance(state.scenario, QlibFactorScenario) and state.alpha158_metrics is None:
sms = msg.content.based_experiments[0].result.loc[SELECTED_METRICS]
sms.name = "alpha158"
state.alpha158_metrics = sms
@@ -176,7 +162,9 @@ def get_msgs_until(end_func: Callable[[Message], bool] = lambda _: True):
if "evolving code" in tags:
msg.content = [i for i in msg.content if i]
if "evolving feedback" in tags:
total_len = len(msg.content)
msg.content = [i for i in msg.content if i]
none_num = total_len - len(msg.content)
if len(msg.content) != len(state.msgs[state.lround]["d.evolving code"][-1].content):
st.toast(":red[**Evolving Feedback Length Error!**]", icon="‼️")
right_num = 0
@@ -184,7 +172,11 @@ def get_msgs_until(end_func: Callable[[Message], bool] = lambda _: True):
if wsf.final_decision:
right_num += 1
wrong_num = len(msg.content) - right_num
state.e_decisions[state.lround][state.erounds[state.lround]] = (right_num, wrong_num)
state.e_decisions[state.lround][state.erounds[state.lround]] = (
right_num,
wrong_num,
none_num,
)
state.msgs[state.lround][msg.tag].append(msg)
# Stop Getting Logs
@@ -195,6 +187,38 @@ def get_msgs_until(end_func: Callable[[Message], bool] = lambda _: True):
break
def refresh(same_trace: bool = False):
if state.log_path is None:
st.toast(":red[**Please Set Log Path!**]", icon="⚠️")
return
if main_log_path:
state.fs = FileStorage(main_log_path / state.log_path).iter_msg()
else:
state.fs = FileStorage(state.log_path).iter_msg()
# detect scenario
if not same_trace:
get_msgs_until(lambda m: not isinstance(m.content, str))
if state.last_msg is None or not isinstance(state.last_msg.content, Scenario):
st.toast(":red[**No Scenario Info detected**]", icon="")
state.scenario = None
else:
state.scenario = state.last_msg.content
st.toast(f":green[**Scenario Info detected**] *{type(state.scenario).__name__}*", icon="")
state.msgs = defaultdict(lambda: defaultdict(list))
state.lround = 0
state.erounds = defaultdict(int)
state.e_decisions = defaultdict(lambda: defaultdict(tuple))
state.hypotheses = defaultdict(None)
state.h_decisions = defaultdict(bool)
state.metric_series = []
state.last_msg = None
state.current_tags = []
state.alpha158_metrics = None
def evolving_feedback_window(wsf: FactorSingleFeedback | ModelCoderFeedback):
if isinstance(wsf, FactorSingleFeedback):
ffc, efc, cfc, vfc = st.tabs(
@@ -231,14 +255,30 @@ def evolving_feedback_window(wsf: FactorSingleFeedback | ModelCoderFeedback):
def display_hypotheses(hypotheses: dict[int, Hypothesis], decisions: dict[int, bool], success_only: bool = False):
name_dict = {
"hypothesis": "RD-Agent proposes the hypothesis⬇️",
"concise_justification": "because the reason⬇️",
"concise_observation": "based on the observation⬇️",
"concise_knowledge": "Knowledge⬇️ gained after practice",
}
if success_only:
shd = {k: v.__dict__ for k, v in hypotheses.items() if decisions[k]}
else:
shd = {k: v.__dict__ for k, v in hypotheses.items()}
df = pd.DataFrame(shd).T
if "concise_observation" in df.columns and "concise_justification" in df.columns:
df["concise_observation"], df["concise_justification"] = df["concise_justification"], df["concise_observation"]
df.rename(
columns={"concise_observation": "concise_justification", "concise_justification": "concise_observation"},
inplace=True,
)
if "reason" in df.columns:
df.drop(["reason"], axis=1, inplace=True)
df.columns = df.columns.map(lambda x: x.replace("_", " ").capitalize())
if "concise_reason" in df.columns:
df.drop(["concise_reason"], axis=1, inplace=True)
df.columns = df.columns.map(lambda x: name_dict.get(x, x))
def style_rows(row):
if decisions[row.name]:
@@ -246,7 +286,7 @@ def display_hypotheses(hypotheses: dict[int, Hypothesis], decisions: dict[int, b
return [""] * len(row)
def style_columns(col):
if col.name != "Hypothesis":
if col.name != name_dict.get("hypothesis", "hypothesis"):
return ["font-style: italic;"] * len(col)
return ["font-weight: bold;"] * len(col)
@@ -302,8 +342,12 @@ def metrics_window(df: pd.DataFrame, R: int, C: int, *, height: int = 300, color
def summary_window():
if state.log_type in ["Qlib Model", "Data Mining", "Qlib Factor"]:
if isinstance(
state.scenario, (QlibModelScenario, DMModelScenario, QlibFactorScenario, QlibFactorFromReportScenario)
):
st.header("Summary📊", divider="rainbow", anchor="_summary")
if state.lround == 0:
return
with st.container():
# TODO: not fixed height
with st.container():
@@ -322,7 +366,7 @@ def summary_window():
display_hypotheses(state.hypotheses, state.h_decisions, show_true_only)
with chart_c:
if state.log_type == "Qlib Factor" and state.alpha158_metrics is not None:
if isinstance(state.scenario, QlibFactorScenario) and state.alpha158_metrics is not None:
df = pd.DataFrame([state.alpha158_metrics] + state.metric_series)
else:
df = pd.DataFrame(state.metric_series)
@@ -343,33 +387,34 @@ def summary_window():
else:
metrics_window(df, 1, 4, height=300, colors=["red", "blue", "orange", "green"])
elif state.log_type == "Model from Paper" and len(state.msgs[state.lround]["d.evolving code"]) > 0:
elif isinstance(state.scenario, GeneralModelScenario):
with st.container(border=True):
st.subheader("Summary📊", divider="rainbow", anchor="_summary")
if len(state.msgs[state.lround]["d.evolving code"]) > 0:
# pass
ws: list[FactorFBWorkspace | ModelFBWorkspace] = state.msgs[state.lround]["d.evolving code"][-1].content
# All Tasks
# pass
ws: list[FactorFBWorkspace | ModelFBWorkspace] = state.msgs[state.lround]["d.evolving code"][-1].content
# All Tasks
tab_names = [
w.target_task.factor_name if isinstance(w.target_task, FactorTask) else w.target_task.name
for w in ws
]
for j in range(len(ws)):
if state.msgs[state.lround]["d.evolving feedback"][-1].content[j].final_decision:
tab_names[j] += "✔️"
else:
tab_names[j] += ""
tab_names = [
w.target_task.factor_name if isinstance(w.target_task, FactorTask) else w.target_task.name for w in ws
]
for j in range(len(ws)):
if state.msgs[state.lround]["d.evolving feedback"][-1].content[j].final_decision:
tab_names[j] += "✔️"
else:
tab_names[j] += ""
wtabs = st.tabs(tab_names)
for j, w in enumerate(ws):
with wtabs[j]:
# Evolving Code
for k, v in w.code_dict.items():
with st.expander(f":green[`{k}`]", expanded=False):
st.code(v, language="python")
wtabs = st.tabs(tab_names)
for j, w in enumerate(ws):
with wtabs[j]:
# Evolving Code
for k, v in w.code_dict.items():
with st.expander(f":green[`{k}`]", expanded=False):
st.code(v, language="python")
# Evolving Feedback
evolving_feedback_window(state.msgs[state.lround]["d.evolving feedback"][-1].content[j])
# Evolving Feedback
evolving_feedback_window(state.msgs[state.lround]["d.evolving feedback"][-1].content[j])
def tabs_hint():
@@ -379,7 +424,6 @@ def tabs_hint():
)
# TODO: when tab names are too long, some tabs are not shown
def tasks_window(tasks: list[FactorTask | ModelTask]):
if isinstance(tasks[0], FactorTask):
st.markdown("**Factor Tasks🚩**")
@@ -392,7 +436,7 @@ def tasks_window(tasks: list[FactorTask | ModelTask]):
# st.markdown(f"**Factor Name**: {ft.factor_name}")
st.markdown(f"**Description**: {ft.factor_description}")
st.latex("Formulation")
st.latex(f"{ft.factor_formulation}")
st.latex(ft.factor_formulation)
mks = "| Variable | Description |\n| --- | --- |\n"
for v, d in ft.variables.items():
@@ -411,7 +455,7 @@ def tasks_window(tasks: list[FactorTask | ModelTask]):
st.markdown(f"**Model Type**: {mt.model_type}")
st.markdown(f"**Description**: {mt.description}")
st.latex("Formulation")
st.latex(f"{mt.formulation}")
st.latex(mt.formulation)
mks = "| Variable | Description |\n| --- | --- |\n"
for v, d in mt.variables.items():
@@ -419,151 +463,19 @@ def tasks_window(tasks: list[FactorTask | ModelTask]):
st.markdown(mks)
# Config Sidebar
with st.sidebar:
st.markdown(
"""
# RD-Agent🤖
## [Scenario Description](#_scenario)
## [Summary](#_summary)
- [**Hypotheses**](#_hypotheses)
- [**Metrics**](#_metrics)
## [RD-Loops](#_rdloops)
- [**Research**](#_research)
- [**Development**](#_development)
- [**Feedback**](#_feedback)
"""
)
st.selectbox(
":green[**Scenario**]", ["Qlib Model", "Data Mining", "Qlib Factor", "Model from Paper"], key="log_type"
)
with st.popover(":orange[**Config⚙️**]"):
with st.container(border=True):
st.markdown(":blue[**log path**]")
if main_log_path:
if st.toggle("Manual Input"):
st.text_input("log path", key="log_path", on_change=refresh)
else:
folders = [
folder.relative_to(main_log_path) for folder in main_log_path.iterdir() if folder.is_dir()
]
st.selectbox(f"Select from `{main_log_path}`", folders, key="log_path", on_change=refresh)
else:
st.text_input("log path", key="log_path", on_change=refresh)
with st.container(border=True):
st.markdown(":blue[**excluded configs**]")
st.multiselect("excluded log tags", ["llm_messages"], ["llm_messages"], key="excluded_tags")
st.multiselect("excluded log types", ["str", "dict", "list"], ["str"], key="excluded_types")
if st.button("All Loops"):
if not state.fs:
refresh()
get_msgs_until(lambda m: False)
if st.button("Next Loop"):
if not state.fs:
refresh()
get_msgs_until(lambda m: "ef.feedback" in m.tag)
if st.button("One Evolving"):
if not state.fs:
refresh()
get_msgs_until(lambda m: "d.evolving feedback" in m.tag)
if st.button("refresh logs", help="clear all log messages in cache"):
refresh()
debug = st.toggle("debug", value=False)
if debug:
if st.button("Single Step Run"):
if not state.fs:
refresh()
get_msgs_until()
# Debug Info Window
if debug:
with st.expander(":red[**Debug Info**]", expanded=True):
dcol1, dcol2 = st.columns([1, 3])
with dcol1:
st.markdown(
f"**trace type**: {state.log_type}\n\n"
f"**log path**: {state.log_path}\n\n"
f"**excluded tags**: {state.excluded_tags}\n\n"
f"**excluded types**: {state.excluded_types}\n\n"
f":blue[**message id**]: {sum(sum(len(tmsgs) for tmsgs in rmsgs.values()) for rmsgs in state.msgs.values())}\n\n"
f":blue[**round**]: {state.lround}\n\n"
f":blue[**evolving round**]: {state.erounds[state.lround]}\n\n"
)
with dcol2:
if state.last_msg:
st.write(state.last_msg)
if isinstance(state.last_msg.content, list):
st.write(state.last_msg.content[0])
elif not isinstance(state.last_msg.content, str):
st.write(state.last_msg.content.__dict__)
# Main Window
header_c1, header_c3 = st.columns([1, 6], vertical_alignment="center")
with st.container():
with header_c1:
st.image("https://img-prod-cms-rt-microsoft-com.akamaized.net/cms/api/am/imageFileData/RE1Mu3b?ver=5c31")
with header_c3:
st.markdown(
"""
<h1>
RD-Agent:<br>LLM-based autonomous evolving agents for industrial data-driven R&D
</h1>
""",
unsafe_allow_html=True,
)
# Project Info
with st.container():
image_c, scen_c = st.columns([3, 3], vertical_alignment="center")
with image_c:
st.image("./docs/_static/flow.png")
with scen_c:
st.header("Scenario Description📖", divider="violet", anchor="_scenario")
# TODO: other scenarios
if state.log_type == "Qlib Model":
st.markdown(QlibModelScenario().rich_style_description, unsafe_allow_html=True)
elif state.log_type == "Data Mining":
st.markdown(DMModelScenario().rich_style_description)
elif state.log_type == "Qlib Factor":
st.markdown(QlibFactorScenario().rich_style_description, unsafe_allow_html=True)
elif state.log_type == "Model from Paper":
st.markdown(GeneralModelScenario().rich_style_description, unsafe_allow_html=True)
# Summary Window
summary_window()
# R&D Loops Window
if state.log_type in ["Qlib Model", "Data Mining", "Qlib Factor"]:
st.header("R&D Loops♾️", divider="rainbow", anchor="_rdloops")
if state.log_type in ["Qlib Model", "Data Mining", "Qlib Factor"]:
if len(state.msgs) > 1:
r_options = list(state.msgs.keys())
if 0 in r_options:
r_options.remove(0)
round = st_btn_select(options=r_options, index=state.lround - 1)
else:
round = 1
else:
round = 1
def research_window():
with st.container(border=True):
title = "Research🔍" if state.log_type in ["Qlib Model", "Data Mining", "Qlib Factor"] else "Research🔍 (reader)"
title = (
"Research🔍"
if isinstance(
state.scenario, (QlibModelScenario, DMModelScenario, QlibFactorScenario, QlibFactorFromReportScenario)
)
else "Research🔍 (reader)"
)
st.subheader(title, divider="blue", anchor="_research")
if state.log_type in ["Qlib Model", "Data Mining", "Qlib Factor"]:
if isinstance(
state.scenario, (QlibModelScenario, DMModelScenario, QlibFactorScenario, QlibFactorFromReportScenario)
):
# pdf image
if pim := state.msgs[round]["r.extract_factors_and_implement.load_pdf_screenshot"]:
for i in range(min(2, len(pim))):
@@ -582,7 +494,7 @@ def research_window():
if eg := state.msgs[round]["r.experiment generation"]:
tasks_window(eg[0].content)
elif state.log_type == "Model from Paper":
elif isinstance(state.scenario, GeneralModelScenario):
# pdf image
c1, c2 = st.columns([2, 3])
with c1:
@@ -598,9 +510,18 @@ def research_window():
def feedback_window():
if state.log_type in ["Qlib Model", "Data Mining", "Qlib Factor"]:
if isinstance(
state.scenario, (QlibModelScenario, DMModelScenario, QlibFactorScenario, QlibFactorFromReportScenario)
):
with st.container(border=True):
st.subheader("Feedback📝", divider="orange", anchor="_feedback")
if state.lround > 0 and isinstance(
state.scenario, (QlibModelScenario, QlibFactorScenario, QlibFactorFromReportScenario)
):
with st.expander("**Config⚙️**", expanded=True):
st.markdown(state.scenario.experiment_setting, unsafe_allow_html=True)
if fbr := state.msgs[round]["ef.Quantitative Backtesting Chart"]:
st.markdown("**Returns📈**")
fig = report_figure(fbr[0].content)
@@ -618,23 +539,13 @@ def feedback_window():
)
if state.log_type in ["Qlib Model", "Data Mining", "Qlib Factor"]:
rf_c, d_c = st.columns([2, 2])
elif state.log_type == "Model from Paper":
rf_c = st.container()
d_c = st.container()
with rf_c:
research_window()
feedback_window()
# Development Window (Evolving)
with d_c.container(border=True):
@st.fragment
def evolving_window():
title = (
"Development🛠️"
if state.log_type in ["Qlib Model", "Data Mining", "Qlib Factor"]
if isinstance(
state.scenario, (QlibModelScenario, DMModelScenario, QlibFactorScenario, QlibFactorFromReportScenario)
)
else "Development🛠️ (evolving coder)"
)
st.subheader(title, divider="green", anchor="_development")
@@ -647,17 +558,20 @@ with d_c.container(border=True):
e_status_mks += "|--" * state.erounds[round] + "|\n"
for ei, estatus in es.items():
if not estatus:
estatus = (0, 0)
e_status_mks += "| " + "✔️<br>" * estatus[0] + "❌<br>" * estatus[1] + " "
estatus = (0, 0, 0)
e_status_mks += "| " + "🕙<br>" * estatus[2] + "✔️<br>" * estatus[0] + "❌<br>" * estatus[1] + " "
e_status_mks += "|\n"
st.markdown(e_status_mks, unsafe_allow_html=True)
# Evolving Tabs
if state.erounds[round] > 0:
if state.erounds[round] > 1:
st.markdown("**🔄️Evolving Rounds**")
evolving_round = st_btn_select(
options=range(1, state.erounds[round] + 1), index=state.erounds[round] - 1, key="show_eround"
evolving_round = st.radio(
"**🔄️Evolving Rounds**",
horizontal=True,
options=range(1, state.erounds[round] + 1),
index=state.erounds[round] - 1,
key="show_eround",
)
else:
evolving_round = 1
@@ -691,8 +605,175 @@ with d_c.container(border=True):
evolving_feedback_window(state.msgs[round]["d.evolving feedback"][evolving_round - 1].content[j])
with st.container(border=True):
st.subheader("Disclaimer", divider="gray")
st.markdown(
"This content is AI-generated and may not be fully accurate or up-to-date; please verify with a professional for critical matters."
)
toc = """
## [Scenario Description📖](#_scenario)
## [Summary📊](#_summary)
- [**Metrics📈**](#_metrics)
- [**Hypotheses🏅**](#_hypotheses)
## [RD-Loops♾️](#_rdloops)
- [**Research🔍**](#_research)
- [**Development🛠**](#_development)
- [**Feedback📝**](#_feedback)
"""
if isinstance(state.scenario, GeneralModelScenario):
toc = """
## [Scenario Description📖](#_scenario)
### [Summary📊](#_summary)
### [Research🔍](#_research)
### [Development🛠️](#_development)
"""
# Config Sidebar
with st.sidebar:
st.markdown("# RD-Agent🤖 [:grey[@GitHub]](https://github.com/microsoft/RD-Agent)")
st.subheader(":blue[Table of Content]", divider="blue")
st.markdown(toc)
st.subheader(":orange[Control Panel]", divider="red")
with st.container(border=True):
if main_log_path:
lc1, lc2 = st.columns([1, 2], vertical_alignment="center")
with lc1:
st.markdown(":blue[**Log Path**]")
with lc2:
manually = st.toggle("Manual Input")
if manually:
st.text_input("log path", key="log_path", on_change=refresh, label_visibility="collapsed")
else:
folders = [folder.relative_to(main_log_path) for folder in main_log_path.iterdir() if folder.is_dir()]
st.selectbox(f"**Select from `{main_log_path}`**", folders, key="log_path", on_change=refresh)
else:
st.text_input(":blue[**log path**]", key="log_path", on_change=refresh)
c1, c2 = st.columns([1, 1], vertical_alignment="center")
with c1:
if st.button(":green[**All Loops**]", use_container_width=True):
if not state.fs:
refresh()
get_msgs_until(lambda m: False)
if st.button("**Reset**", use_container_width=True):
refresh(same_trace=True)
with c2:
if st.button(":green[Next Loop]", use_container_width=True):
if not state.fs:
refresh()
get_msgs_until(lambda m: "ef.feedback" in m.tag)
if st.button("Next Step", use_container_width=True):
if not state.fs:
refresh()
get_msgs_until(lambda m: "d.evolving feedback" in m.tag)
with st.popover(":orange[**Config⚙️**]", use_container_width=True):
st.multiselect("excluded log tags", ["llm_messages"], ["llm_messages"], key="excluded_tags")
st.multiselect("excluded log types", ["str", "dict", "list"], ["str"], key="excluded_types")
if args.debug:
debug = st.toggle("debug", value=False)
if debug:
if st.button("Single Step Run", use_container_width=True):
get_msgs_until()
else:
debug = False
# Debug Info Window
if debug:
with st.expander(":red[**Debug Info**]", expanded=True):
dcol1, dcol2 = st.columns([1, 3])
with dcol1:
st.markdown(
f"**log path**: {state.log_path}\n\n"
f"**excluded tags**: {state.excluded_tags}\n\n"
f"**excluded types**: {state.excluded_types}\n\n"
f":blue[**message id**]: {sum(sum(len(tmsgs) for tmsgs in rmsgs.values()) for rmsgs in state.msgs.values())}\n\n"
f":blue[**round**]: {state.lround}\n\n"
f":blue[**evolving round**]: {state.erounds[state.lround]}\n\n"
)
with dcol2:
if state.last_msg:
st.write(state.last_msg)
if isinstance(state.last_msg.content, list):
st.write(state.last_msg.content[0])
elif not isinstance(state.last_msg.content, str):
st.write(state.last_msg.content.__dict__)
if state.log_path and state.fs is None:
refresh()
# Main Window
header_c1, header_c3 = st.columns([1, 6], vertical_alignment="center")
with st.container():
with header_c1:
st.image("https://img-prod-cms-rt-microsoft-com.akamaized.net/cms/api/am/imageFileData/RE1Mu3b?ver=5c31")
with header_c3:
st.markdown(
"""
<h1>
RD-Agent:<br>LLM-based autonomous evolving agents for industrial data-driven R&D
</h1>
""",
unsafe_allow_html=True,
)
# Project Info
with st.container():
image_c, scen_c = st.columns([3, 3], vertical_alignment="center")
with image_c:
img_path = rfiles("rdagent.log.ui").joinpath("flow.png")
st.image(str(img_path), use_column_width=True)
with scen_c:
st.header("Scenario Description📖", divider="violet", anchor="_scenario")
if state.scenario is not None:
theme = st_theme()
if theme:
theme = theme.get("base", "light")
css = f"""
<style>
a[href="#_rdloops"], a[href="#_research"], a[href="#_development"], a[href="#_feedback"], a[href="#_scenario"], a[href="#_summary"], a[href="#_hypotheses"], a[href="#_metrics"] {{
color: {"black" if theme == "light" else "white"};
}}
</style>
"""
st.markdown(state.scenario.rich_style_description + css, unsafe_allow_html=True)
if state.scenario is not None:
summary_window()
# R&D Loops Window
if isinstance(
state.scenario, (QlibModelScenario, DMModelScenario, QlibFactorScenario, QlibFactorFromReportScenario)
):
st.header("R&D Loops♾️", divider="rainbow", anchor="_rdloops")
if len(state.msgs) > 1:
r_options = list(state.msgs.keys())
if 0 in r_options:
r_options.remove(0)
round = st.radio("**Loops**", horizontal=True, options=r_options, index=state.lround - 1)
else:
round = 1
rf_c, d_c = st.columns([2, 2])
elif isinstance(state.scenario, GeneralModelScenario):
rf_c = st.container()
d_c = st.container()
round = 1
else:
st.error("Unknown Scenario!")
st.stop()
with rf_c:
research_window()
feedback_window()
with d_c.container(border=True):
evolving_window()
st.markdown("<br><br><br>", unsafe_allow_html=True)
st.markdown("#### Disclaimer")
st.markdown(
"*This content is AI-generated and may not be fully accurate or up-to-date; please verify with a professional for critical matters.*",
unsafe_allow_html=True,
)

Before

Width:  |  Height:  |  Size: 123 KiB

After

Width:  |  Height:  |  Size: 123 KiB

+1 -1
View File
@@ -586,7 +586,7 @@ class TraceWindow(StWindow):
self.show_llm = show_llm
self.show_common_logs = show_common_logs
image_c, scen_c = container.columns([2, 3], vertical_alignment="center")
image_c.image("scen.jpg")
image_c.image("scen.png")
scen_c.container(border=True).markdown(QlibModelScenario().rich_style_description)
top_container = container.container()
col1, col2 = top_container.columns([2, 3])
+25 -21
View File
@@ -109,6 +109,14 @@ class SQliteLazyCache(SingletonBaseClass):
)
""",
)
self.c.execute(
"""
CREATE TABLE message_cache (
conversation_id TEXT PRIMARY KEY,
message TEXT
)
""",
)
self.conn.commit()
def chat_get(self, key: str) -> str | None:
@@ -144,35 +152,31 @@ class SQliteLazyCache(SingletonBaseClass):
)
self.conn.commit()
def message_get(self, conversation_id: str) -> list[str]:
self.c.execute("SELECT message FROM message_cache WHERE conversation_id=?", (conversation_id,))
result = self.c.fetchone()
if result is None:
return []
return json.loads(result[0])
def message_set(self, conversation_id: str, message_value: list[str]) -> None:
self.c.execute(
"INSERT OR REPLACE INTO message_cache (conversation_id, message) VALUES (?, ?)",
(conversation_id, json.dumps(message_value)),
)
self.conn.commit()
class SessionChatHistoryCache(SingletonBaseClass):
def __init__(self) -> None:
"""load all history conversation json file from self.session_cache_location"""
self.cfg = RD_AGENT_SETTINGS
self.session_cache_location = Path(self.cfg.session_cache_folder_location)
self.cache = {}
if not self.session_cache_location.exists():
logger.warning(f"Directory {self.session_cache_location} does not exist.")
self.session_cache_location.mkdir(parents=True, exist_ok=True)
json_files = [f for f in self.session_cache_location.iterdir() if f.suffix == ".json"]
if not json_files:
logger.info(f"No JSON files found in {self.session_cache_location}.")
for file_path in json_files:
conversation_id = file_path.stem
with file_path.open("r") as f:
conversation_content = json.load(f)
self.cache[conversation_id] = conversation_content["content"]
self.cache = SQliteLazyCache(cache_location=RD_AGENT_SETTINGS.prompt_cache_path)
def message_get(self, conversation_id: str) -> list[str]:
return self.cache.get(conversation_id, [])
return self.cache.message_get(conversation_id)
def message_set(self, conversation_id: str, message_value: list[str]) -> None:
self.cache[conversation_id] = message_value
conversation_path = self.session_cache_location / conversation_id
conversation_path = conversation_path.with_suffix(".json")
current_time = datetime.datetime.now(datetime.timezone.utc).strftime("%Y-%m-%d-%H-%M-%S")
with conversation_path.open("w") as f:
json.dump({"content": message_value, "last_modified_time": current_time}, f)
self.cache.message_set(conversation_id, message_value)
class ChatSession:
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+20
View File
@@ -0,0 +1,20 @@
# Kaggle Crawler
## Install chrome & chromedriver for Linux
In one folder
```shell
# install chrome
wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb
sudo apt install ./google-chrome-stable_current_amd64.deb
google-chrome --version
# install chromedriver
wget https://storage.googleapis.com/chrome-for-testing-public/<chrome-version>/linux64/chromedriver-linux64.zip
unzip chromedriver-linux64.zip
cd chromedriver-linux64
sudo mv chromedriver /usr/local/bin
sudo chmod +x /usr/local/bin/chromedriver
chromedriver --version
```
@@ -0,0 +1,68 @@
import json
from pathlib import Path
from jinja2 import Environment, StrictUndefined
from rdagent.core.experiment import Experiment
from rdagent.core.prompts import Prompts
from rdagent.core.proposal import (
Hypothesis,
HypothesisExperiment2Feedback,
HypothesisFeedback,
Trace,
)
from rdagent.log import rdagent_logger as logger
from rdagent.oai.llm_utils import APIBackend
from rdagent.utils import convert2bool
feedback_prompts = Prompts(file_path=Path(__file__).parent.parent / "prompts.yaml")
DIRNAME = Path(__file__).absolute().resolve().parent
class KGModelHypothesisExperiment2Feedback(HypothesisExperiment2Feedback):
"""Generated feedbacks on the hypothesis from **Executed** Implementations of different tasks & their comparisons with previous performances"""
def generate_feedback(self, exp: Experiment, hypothesis: Hypothesis, trace: Trace) -> HypothesisFeedback:
"""
The `ti` should be executed and the results should be included, as well as the comparison between previous results (done by LLM).
For example: `mlflow` of Qlib will be included.
"""
logger.info("Generating feedback...")
# Define the system prompt for hypothesis feedback
system_prompt = feedback_prompts["model_feedback_generation"]["system"]
# Define the user prompt for hypothesis feedback
context = trace.scen
SOTA_hypothesis, SOTA_experiment = trace.get_sota_hypothesis_and_experiment()
user_prompt = (
Environment(undefined=StrictUndefined)
.from_string(feedback_prompts["model_feedback_generation"]["user"])
.render(
context=context,
last_hypothesis=SOTA_hypothesis,
last_task=SOTA_experiment.sub_tasks[0].get_task_information() if SOTA_hypothesis else None,
last_code=SOTA_experiment.sub_workspace_list[0].code_dict.get("model.py") if SOTA_hypothesis else None,
last_result=SOTA_experiment.result if SOTA_hypothesis else None,
hypothesis=hypothesis,
exp=exp,
)
)
# Call the APIBackend to generate the response for hypothesis feedback
response_hypothesis = APIBackend().build_messages_and_create_chat_completion(
user_prompt=user_prompt,
system_prompt=system_prompt,
json_mode=True,
)
# Parse the JSON response to extract the feedback
response_json_hypothesis = json.loads(response_hypothesis)
return HypothesisFeedback(
observations=response_json_hypothesis.get("Observations", "No observations provided"),
hypothesis_evaluation=response_json_hypothesis.get("Feedback for Hypothesis", "No feedback provided"),
new_hypothesis=response_json_hypothesis.get("New Hypothesis", "No new hypothesis provided"),
reason=response_json_hypothesis.get("Reasoning", "No reasoning provided"),
decision=convert2bool(response_json_hypothesis.get("Decision", "false")),
)
@@ -0,0 +1,3 @@
from rdagent.components.coder.model_coder.CoSTEER import ModelCoSTEER
KGModelCoSTEER = ModelCoSTEER
@@ -0,0 +1,38 @@
import shutil
import uuid
from pathlib import Path
import pandas as pd
from rdagent.components.coder.model_coder.model import ModelExperiment, ModelFBWorkspace
from rdagent.components.runner import CachedRunner
from rdagent.components.runner.conf import RUNNER_SETTINGS
from rdagent.core.developer import Developer
from rdagent.core.exception import ModelEmptyError
from rdagent.log import rdagent_logger as logger
from rdagent.scenarios.kaggle.experiment.model_experiment import KGModelExperiment
from rdagent.utils.env import KGDockerEnv
class KGModelRunner(CachedRunner[KGModelExperiment]):
def develop(self, exp: KGModelExperiment) -> KGModelExperiment:
if RUNNER_SETTINGS.cache_result:
cache_hit, result = self.get_cache_result(exp)
if cache_hit:
exp.result = result
return exp
if exp.sub_workspace_list[0].code_dict.get("model.py") is None:
raise ModelEmptyError("model.py is empty")
# to replace & inject code
exp.experiment_workspace.inject_code(**{"model.py": exp.sub_workspace_list[0].code_dict["model.py"]})
env_to_use = {"PYTHONPATH": "./"}
result = exp.experiment_workspace.execute(run_env=env_to_use)
exp.result = result
if RUNNER_SETTINGS.cache_result:
self.dump_cache_result(exp, result)
return exp
@@ -0,0 +1,25 @@
FROM pytorch/pytorch:latest
# For GPU support, please choose the proper tag from https://hub.docker.com/r/pytorch/pytorch/tags
RUN apt-get clean && apt-get update && apt-get install -y \
curl \
vim \
git \
build-essential \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /workspace
RUN python -m pip install numpy
RUN python -m pip install --upgrade cython
# RUN python -m pip install -e .
RUN python -m pip install pandas
# RUN pip install pyg_lib torch_scatter torch_sparse torch_cluster -f https://data.pyg.org/whl/torch-2.3.0%2Bcu121.html
RUN pip install torch_geometric
RUN pip install ogb
RUN pip install networkx
RUN pip install scikit-learn
RUN pip install catboost
RUN pip install xgboost
RUN pip install sparse
@@ -0,0 +1,6 @@
# Meta template
It is an example of how we organize the workspace of a competition.
We expect all the competitions to align with it so the knowledge in modules (model, feature) can transfer.
The generation process of the initial template is hoped to be conducted by LLM (however, it is based on human efforts currently).
@@ -0,0 +1,89 @@
from pathlib import Path
import numpy as np
import pandas as pd
import xgboost as xgb
from sklearn.metrics import accuracy_score, matthews_corrcoef
from sklearn.model_selection import KFold
from sklearn.preprocessing import LabelEncoder, OneHotEncoder
from rdagent.scenarios.kaggle.experiment.meta_tpl.fea_share_preprocess import preprocess
def compute_metrics_for_classification(y_true, y_pred):
"""Compute MCC for classification."""
from sklearn.metrics import matthews_corrcoef
return matthews_corrcoef(y_true, y_pred)
def perform_kfold_cross_validation(X, y, n_splits=2, random_seed=42):
kf = KFold(n_splits=n_splits, shuffle=True, random_state=random_seed)
fold_metrics = []
DIRNAME = Path(__file__).absolute().resolve().parent
for fold, (train_idx, valid_idx) in enumerate(kf.split(X)):
X_train_fold, X_valid_fold = X.iloc[train_idx], X.iloc[valid_idx]
y_train_fold, y_valid_fold = y[train_idx], y[valid_idx]
# TODO: Preprocess and Feature Engineering before K-Fold CV
# Preprocess the data
X_train_fold = preprocess(X_train_fold)
X_valid_fold = preprocess(X_valid_fold)
# Feature Engineering
X_train_l_fold, X_valid_l_fold = [], []
for f in DIRNAME.glob("feat*.py"):
m = __import__(f.name.strip(".py"))
X_train_fold = m.feat_eng(X_train_fold)
X_valid_fold = m.feat_eng(X_valid_fold)
X_train_l_fold.append(X_train_fold)
X_valid_l_fold.append(X_valid_fold)
X_train_fold = pd.concat(X_train_l_fold, axis=1)
X_valid_fold = pd.concat(X_valid_l_fold, axis=1)
# Align features
X_valid_fold = X_valid_fold.reindex(columns=X_train_fold.columns, fill_value=0)
# Train and evaluate models
mcc_scores = []
model_l = [] # Reinitialize model list
for f in DIRNAME.glob("model*.py"):
m = __import__(f.name.strip(".py"))
model = m.fit(X_train_fold, y_train_fold, X_valid_fold, y_valid_fold)
y_valid_pred = m.predict(model, X_valid_fold)
mcc = compute_metrics_for_classification(y_valid_fold, y_valid_pred)
mcc_scores.append(mcc)
print(f"Fold {fold+1}, Model {f.name}: MCC = {mcc}")
# Store the average MCC score for this fold
avg_mcc = np.mean(mcc_scores)
fold_metrics.append(avg_mcc)
print(f"Fold {fold+1} average MCC: {avg_mcc}")
# Calculate the overall average MCC
overall_avg_mcc = np.mean(fold_metrics)
result_df = pd.DataFrame({"Overall Average MCC": [overall_avg_mcc]})
result_df.to_csv(f"path/to/playground-series-s4e8/cv_score_{f.name.strip('.py')}.csv", index=False)
print(f"Overall Average MCC across all folds: {overall_avg_mcc}")
return overall_avg_mcc
# This allows the script to be run directly
if __name__ == "__main__":
# Load and preprocess the data
data_df = pd.read_csv("path/to/playground-series-s4e8/train.csv")
data_df = data_df.drop(["id"], axis=1)
X = data_df.drop(["class"], axis=1)
y = data_df[["class"]]
label_encoder = LabelEncoder()
# transfrom y to 1D
y = label_encoder.fit_transform(y)
result = perform_kfold_cross_validation(X, y)
@@ -0,0 +1,47 @@
import pandas as pd
from sklearn.compose import ColumnTransformer
from sklearn.impute import SimpleImputer
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import OneHotEncoder
def preprocess(X: pd.DataFrame):
"""
We want the X_train & X_test & X_valid to contain the same number of columns & maintain feature consistency.
"""
# Identify numerical and categorical features
numerical_cols = [cname for cname in X.columns if X[cname].dtype in ["int64", "float64"]]
categorical_cols = [cname for cname in X.columns if X[cname].dtype == "object"]
# Define preprocessors for numerical and categorical features
categorical_transformer = Pipeline(
steps=[
("imputer", SimpleImputer(strategy="most_frequent")),
("onehot", OneHotEncoder(handle_unknown="ignore")),
]
)
numerical_transformer = Pipeline(steps=[("imputer", SimpleImputer(strategy="mean"))])
# Combine preprocessing steps
preprocessor = ColumnTransformer(
transformers=[
("cat", categorical_transformer, categorical_cols),
("num", numerical_transformer, numerical_cols),
]
)
# Fit the preprocessor on the data and transform it
preprocessor.fit(X) # TODO depend on its input shape
X_array = preprocessor.transform(X).toarray()
# Get feature names for the columns in the transformed data
feature_names = (
preprocessor.named_transformers_["cat"]["onehot"].get_feature_names_out(categorical_cols).tolist()
+ numerical_cols
)
# Convert arrays back to DataFrames
X_transformed = pd.DataFrame(X_array, columns=feature_names, index=X.index)
return X_transformed
@@ -0,0 +1,13 @@
import pandas as pd
"""
Here is the feature engineering code for each task, with the function name specified as feat_eng.
The file name should start with feat_, followed by the specific task name.
"""
def feat_eng(X: pd.DataFrame):
"""
return the selected features
"""
return X
@@ -0,0 +1,36 @@
"""
motivation of the model
"""
import pandas as pd
import xgboost as xgb
def select(X):
"""
Select relevant features. To be used in fit & predict function
"""
return X
def fit(X_train: pd.DataFrame, y_train: pd.DataFrame, X_valid: pd.DataFrame, y_valid: pd.DataFrame):
"""Define and train the model. Merge feature_select"""
dtrain = xgb.DMatrix(X_train, label=y_train)
dvalid = xgb.DMatrix(X_valid, label=y_valid)
# TODO: for quick running....
params = {}
num_round = 2
evallist = [(dtrain, "train"), (dvalid, "eval")]
bst = xgb.train(params, dtrain, num_round, evallist)
return bst
def predict(model, X):
"""
Keep feature select's consistency.
"""
dtest = xgb.DMatrix(X)
y_pred_prob = model.predict(dtest)
return y_pred_prob > 0.5 # Apply threshold to get boolean predictions
@@ -0,0 +1,125 @@
import os
import random
from pathlib import Path
import numpy as np
import pandas as pd
import xgboost as xgb
from fea_share_preprocess import preprocess
from sklearn.compose import ColumnTransformer
from sklearn.impute import SimpleImputer
from sklearn.metrics import accuracy_score, matthews_corrcoef
from sklearn.model_selection import train_test_split
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import LabelEncoder, OneHotEncoder
from rdagent.scenarios.kaggle.experiment.meta_tpl.fea_share_preprocess import preprocess
# Set random seed for reproducibility
SEED = 42
random.seed(SEED)
np.random.seed(SEED)
DIRNAME = Path(__file__).absolute().resolve().parent
# support various method for metrics calculation
def compute_metrics_for_classification(y_true, y_pred):
"""Compute accuracy metric for classification."""
accuracy = accuracy_score(y_true, y_pred)
return accuracy
def compute_metrics_for_classification(y_true, y_pred):
"""Compute MCC for classification."""
mcc = matthews_corrcoef(y_true, y_pred)
return mcc
# Load and preprocess the data
data_df = pd.read_csv("/home/v-xisenwang/git_ignore_folder/data/playground-series-s4e8/train.csv")
data_df = data_df.drop(["id"], axis=1)
X = data_df.drop(["class"], axis=1)
y = data_df[["class"]]
label_encoder = LabelEncoder()
y = label_encoder.fit_transform(y) # 将类别标签转换为数值
X_train, X_valid, y_train, y_valid = train_test_split(X, y, test_size=0.10, random_state=SEED)
# 1) Preprocess the data
X_train = preprocess(X_train)
X_valid = preprocess(X_valid)
submission_df = pd.read_csv("/home/v-xisenwang/git_ignore_folder/data/playground-series-s4e8/test.csv")
passenger_ids = submission_df["id"]
submission_df = submission_df.drop(["id"], axis=1)
X_test = preprocess(submission_df)
# 2) Auto feature engineering
X_train_l, X_valid_l = [], []
X_test_l = []
for f in DIRNAME.glob("feat*.py"):
m = __import__(f.name.strip(".py"))
X_train = m.feat_eng(X_train)
X_valid = m.feat_eng(X_valid)
X_test = m.feat_eng(X_test)
X_train_l.append(X_train)
X_valid_l.append(X_valid)
X_test_l.append(X_test)
X_train = pd.concat(X_train_l, axis=1)
X_valid = pd.concat(X_valid_l, axis=1)
X_test = pd.concat(X_test_l, axis=1)
def align_features(train_df, valid_df):
# Align the features of validation data to the training data
valid_df = valid_df.reindex(columns=train_df.columns, fill_value=0)
return valid_df
X_valid = align_features(X_train, X_valid)
X_test = align_features(X_train, X_test)
# 3) Train the model
model_l = [] # list[tuple[model, predict_func,]]
for f in DIRNAME.glob("model*.py"):
# TODO put select() in model.py: fit(X_train, y_train, X_valid, y_valid)
m = __import__(f.name.strip(".py"))
model_l.append((m.fit(X_train, y_train, X_valid, y_valid), m.predict))
# Evaluate the model on the validation set
y_valid_pred_l = []
for model, predict_func in model_l:
y_valid_pred_l.append(predict_func(model, X_valid))
# Ensemble
# TODO: ensemble method in a script
# Average the predictions and apply a threshold to determine class labels
y_valid_pred = np.mean(y_valid_pred_l, axis=0)
y_valid_pred = (y_valid_pred > 0.5).astype(int)
mcc = compute_metrics_for_classification(y_valid, y_valid_pred)
print("Final on validation set: ", mcc)
# Save the validation accuracy
pd.Series(data=[mcc], index=["MCC"]).to_csv(
"/home/v-xisenwang/RD-Agent/rdagent/scenarios/kaggle/experiment/meta_tpl/submission_score.csv"
)
# Make predictions on the test set and save them
y_test_pred_bool_l = []
for m, m_pred in model_l:
y_test_pred_bool_l.append(
m_pred(m, X_test).astype(int)
) # TODO Make this an ensemble. Currently it uses the last prediction
y_test_pred = np.mean(y_test_pred_bool_l, axis=0)
y_test_pred = (y_test_pred > 0.5).astype(int) # TODO Make it a module. Ensemble prediction
y_test_pred_labels = label_encoder.inverse_transform(y_test_pred) # 将整数转换回 'e' 或 'p'
submission_result = pd.DataFrame({"id": passenger_ids, "class": y_test_pred_labels})
# submit predictions for the test set
submission_result.to_csv("./submission.csv", index=False)
@@ -0,0 +1,136 @@
import json
from pathlib import Path
import pandas as pd
from jinja2 import Environment, StrictUndefined
from rdagent.components.coder.model_coder.model import (
ModelExperiment,
ModelFBWorkspace,
ModelTask,
)
from rdagent.core.prompts import Prompts
from rdagent.core.scenario import Scenario
from rdagent.oai.llm_utils import APIBackend
from rdagent.scenarios.kaggle.experiment.workspace import KGFBWorkspace
from rdagent.scenarios.kaggle.kaggle_crawler import crawl_descriptions
prompt_dict = Prompts(file_path=Path(__file__).parent / "prompts.yaml")
class KGModelExperiment(ModelExperiment[ModelTask, KGFBWorkspace, ModelFBWorkspace]):
def __init__(self, *args, **kwargs) -> None:
super().__init__(*args, **kwargs)
self.experiment_workspace = KGFBWorkspace(template_folder_path=Path(__file__).parent / "model_template")
class KGModelScenario(Scenario):
def __init__(self, competition: str) -> None:
super().__init__()
self.competition = competition
self.competition_descriptions = crawl_descriptions(competition)
self.competition_type = None
self.competition_description = None
self.target_description = None
self.competition_features = None
self._analysis_competition_description()
def _analysis_competition_description(self):
# TODO: use gpt to analyze the competition description
sys_prompt = (
Environment(undefined=StrictUndefined)
.from_string(prompt_dict["kg_description_template"]["system"])
.render()
)
user_prompt = (
Environment(undefined=StrictUndefined)
.from_string(prompt_dict["kg_description_template"]["user"])
.render(
competition_descriptions=self.competition_descriptions,
)
)
response_analysis = APIBackend().build_messages_and_create_chat_completion(
user_prompt=user_prompt,
system_prompt=sys_prompt,
json_mode=True,
)
response_json_analysis = json.loads(response_analysis)
self.competition_type = response_json_analysis.get("Competition Type", "No type provided")
self.competition_description = response_json_analysis.get("Competition Description", "No description provided")
self.target_description = response_json_analysis.get("Target Description", "No target provided")
self.competition_features = response_json_analysis.get("Competition Features", "No features provided")
@property
def background(self) -> str:
background_template = prompt_dict["kg_model_background"]
background_prompt = (
Environment(undefined=StrictUndefined)
.from_string(background_template)
.render(
competition_type=self.competition_type,
competition_description=self.competition_description,
target_description=self.target_description,
competition_features=self.competition_features,
)
)
return background_prompt
@property
def source_data(self) -> str:
kaggle_conf = KGDockerConf()
data_path = Path(f"{kaggle_conf.share_data_path}/{self.competition}")
csv_files = list(data_path.glob("*.csv"))
if not csv_files:
return "No CSV files found in the specified path."
dataset = pd.concat([pd.read_csv(file) for file in csv_files], ignore_index=True)
simple_eda = dataset.info(buf=None) # Capture the info output
data_shape = dataset.shape
data_head = dataset.head()
eda = (
f"Basic Info about the data:\n{simple_eda}\n"
f"Shape of the dataset: {data_shape}\n"
f"Sample Data:\n{data_head}\n"
)
data_description = self.competition_descriptions.get("Data Description", "No description provided")
eda += f"\nData Description:\n{data_description}"
return eda
@property
def output_format(self) -> str:
return prompt_dict["kg_model_output_format"]
@property
def interface(self) -> str:
return prompt_dict["kg_model_interface"]
@property
def simulator(self) -> str:
return prompt_dict["kg_model_simulator"]
@property
def rich_style_description(self) -> str:
return """
kaggle scen """
def get_scenario_all_desc(self) -> str:
return f"""Background of the scenario:
{self.background}
The interface you should follow to write the runnable code:
{self.interface}
The output of your code should be in the format:
{self.output_format}
The simulator user can use to test your model:
{self.simulator}
"""
@@ -0,0 +1,3 @@
## This folder is a template to be copied from for each model implementation & running process.
Components: Dummy model.py, versatile conf.yaml, and a result reader.
@@ -0,0 +1,105 @@
import random
import numpy as np
import pandas as pd
import xgboost as xgb
from model import get_num_round, get_params
from sklearn.compose import ColumnTransformer
from sklearn.impute import SimpleImputer
from sklearn.metrics import accuracy_score
from sklearn.model_selection import train_test_split
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import OneHotEncoder
# Set random seed for reproducibility
SEED = 42
random.seed(SEED)
np.random.seed(SEED)
def compute_metrics_for_classification(y_true, y_pred):
"""Compute accuracy metric for classification."""
accuracy = accuracy_score(y_true, y_pred)
return accuracy
def train_model(X_train, y_train, X_valid, y_valid):
"""Define and train the model."""
dtrain = xgb.DMatrix(X_train, label=y_train)
dvalid = xgb.DMatrix(X_valid, label=y_valid)
params = get_params()
num_round = get_num_round()
evallist = [(dtrain, "train"), (dvalid, "eval")]
bst = xgb.train(params, dtrain, num_round, evallist)
return bst
def predict(model, X):
dtest = xgb.DMatrix(X)
y_pred_prob = model.predict(dtest)
return y_pred_prob > 0.5 # Apply threshold to get boolean predictions
if __name__ == "__main__":
# Load and preprocess the data
data_df = pd.read_csv("/root/.data/train.csv")
data_df = data_df.drop(["PassengerId", "Name"], axis=1)
X = data_df.drop(["Transported"], axis=1)
y = data_df.Transported.to_numpy()
# Identify numerical and categorical features
numerical_cols = [cname for cname in X.columns if X[cname].dtype in ["int64", "float64"]]
categorical_cols = [cname for cname in X.columns if X[cname].dtype == "object"]
# Define preprocessors for numerical and categorical features
categorical_transformer = Pipeline(
steps=[
("imputer", SimpleImputer(strategy="most_frequent")),
("onehot", OneHotEncoder(handle_unknown="ignore")),
]
)
numerical_transformer = Pipeline(steps=[("imputer", SimpleImputer(strategy="mean"))])
# Combine preprocessing steps
preprocessor = ColumnTransformer(
transformers=[
("cat", categorical_transformer, categorical_cols),
("num", numerical_transformer, numerical_cols),
]
)
# Split the data into training and validation sets
X_train, X_valid, y_train, y_valid = train_test_split(X, y, test_size=0.10, random_state=SEED)
# Fit the preprocessor on the training data and transform both training and validation data
preprocessor.fit(X_train)
X_train = preprocessor.transform(X_train)
X_valid = preprocessor.transform(X_valid)
# Train the model
model = train_model(X_train, y_train, X_valid, y_valid)
# Evaluate the model on the validation set
y_valid_pred = predict(model, X_valid)
accuracy = compute_metrics_for_classification(y_valid, y_valid_pred)
print("Final Accuracy on validation set: ", accuracy)
# Save the validation accuracy
pd.Series(data=[accuracy], index=["ACC"]).to_csv("./submission_score.csv")
# Load and preprocess the test set
submission_df = pd.read_csv("/root/.data/test.csv")
passenger_ids = submission_df["PassengerId"]
submission_df = submission_df.drop(["PassengerId", "Name"], axis=1)
X_test = preprocessor.transform(submission_df)
# Make predictions on the test set and save them
y_test_pred = predict(model, X_test)
submission_result = pd.DataFrame({"PassengerId": passenger_ids, "Transported": y_test_pred})
# submit predictions for the test set
submission_result.to_csv("./submission.csv", index=False)
@@ -0,0 +1,74 @@
kg_description_template:
system: |-
You are an assistant that extracts structured information from unstructured text.
user: |-
Based on the following competition description, please extract the following details:
1. Competition Type
2. Competition Description
3. Target Description
4. Competition Features
Competition Description: {{ competition_descriptions }}
kg_model_background: |-
You are solving this data science tasks of {{ competition_type }}:
{{competition_description}}
We provide an overall pipeline in train.py. Now fill in the provided train.py script to train a {{ competition_type }} model to get a good performance on this task.
The model is a machine learning or deep learning structure designed to predict {{ target_description }}.
The data is extracted from the competition dataset, focusing on relevant attributes like {{ competition_features }}.
ModelType: The type of the model, "XGBoost" for XGBoost model.
The model is defined in the following parts:
- Name: The name of the model.
- Description: A description of the model.
- Architecture: The detailed architecture of the model, such as neural network layers or tree structures.
The model should provide clear and detailed documentation of its architecture and hyperparameters.
kg_model_interface: |-
Your python code should follow the interface to better interact with the user's system.
You code should contain several parts:
1. The import part: import the necessary libraries.
2. A class that is a subclass of xgboost. This class should have an __init__ function and a forward function, which inputs a tensor and outputs a tensor.
3. Set a variable called "model_cls" to the class you defined.
The user will save your code into a python file called "model.py". Then the user imports model_cls in file "model.py" after setting the cwd into the directory:
```python
from model import get_params, get_num_round
```
So your python code should follow the pattern:
```python
def get_params():
params = {
...
}
return params
def get_num_round():
return xxx
```
The model has one types, "XGBoost" for XGBoost model.
The XGBoost Model leverages two critical hyperparameters: "arams" and "num_round".
"params": This hyperparameter encapsulates various settings that dictate the model's behavior and learning process.
"num_round": This hyperparameter specifies the number of training iterations the model will undergo.
User will initialize the XGBoost model with the following code:
```python
params = get_params()
num_round = get_num_round()
```
No other parameters will be passed to the model so give other parameters a default value or just make them static.
Don't write any try-except block in your python code. The user will catch the exception message and provide the feedback to you. Also, don't write main function in your python code. The user will call the forward method in the model_cls to get the output tensor.
Please notice that your model should only use current features as input. The user will provide the input tensor to the model's forward function.
kg_model_output_format: |-
Your output should be an array with the appropriate number of predictions, each prediction being a single value. The output should be a 2D array with dimensions corresponding to the number of predictions and 1 column (e.g., (8, 1) if there are 8 predictions).
kg_model_simulator: |-
The models will be trained on the competition dataset and evaluated on their ability to predict whether passengers were transported using metrics like accuracy and AUC-ROC.
Model performance will be iteratively improved based on feedback from evaluation results.
@@ -0,0 +1,33 @@
import subprocess
import zipfile
from pathlib import Path
import pandas as pd
from rdagent.app.kaggle.conf import PROP_SETTING
from rdagent.core.experiment import FBWorkspace
from rdagent.log import rdagent_logger as logger
from rdagent.utils.env import DockerEnv, KGDockerEnv
class KGFBWorkspace(FBWorkspace):
def __init__(self, template_folder_path: Path, *args, **kwargs) -> None:
super().__init__(*args, **kwargs)
self.inject_code_from_folder(template_folder_path)
def execute(self, run_env: dict = {}, *args, **kwargs) -> str:
qtde = KGDockerEnv(PROP_SETTING.competition)
qtde.prepare()
execute_log = qtde.run(
local_path=str(self.workspace_path),
entry=f"python train.py",
env=run_env,
)
csv_path = self.workspace_path / "submission.csv"
if not csv_path.exists():
logger.error(f"File {csv_path} does not exist.")
return None
return pd.read_csv(csv_path, index_col=0).iloc[:, 0]
@@ -0,0 +1,77 @@
import json
import time
from pathlib import Path
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By
LOCAL_PATH = "/data/userdata/share/kaggle_competition_descriptions"
options = webdriver.ChromeOptions()
options.add_argument("--no-sandbox")
options.add_argument("--disable-dev-shm-usage")
options.add_argument("--headless")
service = Service("/usr/local/bin/chromedriver")
def crawl_descriptions(competition: str, wait: float = 3.0, force: bool = False) -> dict[str, str]:
if (fp := Path(f"{LOCAL_PATH}/{competition}.json")).exists() and not force:
print(f"Found {competition}.json, loading from local file.")
with fp.open("r") as f:
return json.load(f)
driver = webdriver.Chrome(options=options, service=service)
overview_url = f"https://www.kaggle.com/competitions/{competition}/overview"
driver.get(overview_url)
time.sleep(wait)
site_body = driver.find_element(By.ID, "site-content")
descriptions = {}
# Get the subtitles
elements = site_body.find_elements(By.CSS_SELECTOR, f"a[href^='/competitions/{competition}/overview/']")
subtitles = []
for e in elements:
inner_text = ""
for child in e.find_elements(By.XPATH, ".//*"):
inner_text += child.get_attribute("innerHTML").strip()
subtitles.append(inner_text)
# Get main contents
contents = []
elements = site_body.find_elements(By.CSS_SELECTOR, ".sc-iWlrxG.cMAZdc")
for e in elements:
content = e.get_attribute("innerHTML")
contents.append(content)
assert len(subtitles) == len(contents) + 1 and subtitles[-1] == "Citation"
for i in range(len(subtitles) - 1):
descriptions[subtitles[i]] = contents[i]
# Get the citation
element = site_body.find_element(By.CSS_SELECTOR, ".sc-ifyrTC.sc-fyziuY")
citation = element.get_attribute("innerHTML")
descriptions[subtitles[-1]] = citation
data_url = f"https://www.kaggle.com/competitions/{competition}/data"
driver.get(data_url)
time.sleep(wait)
data_element = driver.find_element(By.CSS_SELECTOR, ".sc-iWlrxG.cMAZdc")
descriptions["Data Description"] = data_element.get_attribute("innerHTML")
driver.quit()
with open(f"{LOCAL_PATH}/{competition}.json", "w") as f:
json.dump(descriptions, f)
return descriptions
if __name__ == "__main__":
from kaggle.api.kaggle_api_extended import KaggleApi
api = KaggleApi()
api.authenticate()
cs = api.competitions_list()
for c in cs:
name = c.ref.split("/")[-1]
crawl_descriptions(name)
+130
View File
@@ -0,0 +1,130 @@
hypothesis_and_feedback: |-
{% for hypothesis, experiment, feedback in trace.hist %}
Hypothesis {{ loop.index }}: {{ hypothesis }}
Corresponding Code (that leads to the difference in performance): {{experiment.sub_workspace_list[0].code_dict.get("model.py")}}
Observation on the result with the hypothesis: {{ feedback.observations }}
Feedback on the original hypothesis: {{ feedback.hypothesis_evaluation }}
New Feedback for Context (For you to agree or improve upon): {{ feedback.new_hypothesis }}
Reasoning for new hypothesis: {{ feedback.reason }}
Did changing to this hypothesis work? (focus on the change): {{ feedback.decision }}
{% endfor %}
hypothesis_output_format: |-
The output should follow JSON format. The schema is as follows:
{
"hypothesis": "The new hypothesis generated based on the information provided.",
"reason": "The reason why you generate this hypothesis. It should be comprehensive and logical. It should cover the other keys below and extend them.",
"concise_reason": "Two-line summary. First line focuses on a concise justification for the change. Second line generalizes a knowledge statement.",
"concise_observation": "One line summary. It focuses on the observation of the given scenario, data characteristics, or previous experiences (failures & succeses).",
"concise_justification": "One line summary. Justify the hypothesis based on theoretical principles or initial assumptions.",
"concise_knowledge": "One line summary. Transferable knowledge based on theoretical principles. Use conditional grammar. eg. "If...., ..; When..., .; and etc" Make sure that you state things clearly without ambiguity. Eg. avoid saying "previous hypothesis", because one wouldn't know what that is."
}
model_hypothesis_specification: |-
Additional Specifications:
Hypotheses should grow and evolve based on the previous hypothesis. If there is no previous hypothesis, start with something simple. Gradually Build Up Upon previous hypothesis & feedbacks. In each round, hypothesis is different. Pay attention to your previous hypothesis.
Ensure that the hypothesis focuses on the architecture of a PyTorch model. Each hypothesis should address specific architectural choices such as the type of layers, activation functions, regularization techniques, and the overall structure of the model. Avoid hypotheses related to input features or optimization processes.
Remember: if there is no hypothesis, start with something simple like MLP.
Usually, a larger model works better than a smaller one.
Logic for generating a new hypothesis: If the previous hypothesis works, try to inherit from it and grow deeper. If the previous hypotheis doesn't work, try to make changes in the current level.
Sample hypothesis evolution loop: (This is the entire loop, see what stage you are at. We want hypothesis to continue growing.) Levels include **Model Type**, **Layer Configuration**, **Activation Functions**, **Regularization Techniques**
1st Round Hypothesis: The model should be a CNN.
2nd Round Hypothesis (If first round worked: CNN is the model type level, which means that we should extend to the next level, like layer configuration): The model should be a CNN. The CNN should have 5 convolutional layers. (Reasoning: As CNN worked, we now specify the layers specification to grow the hypothesis deeper.)
3rd Round Hypothesis (If second round didn't work): The model should be a CNN. The CNN should have 3 convolutional layers. (Reasoning: As 5-layer structure didn't work in the 2nd round hypothesis, try something else within the layer configuration level.)
4th Round Hypothesis (If third round worked): The model should be a CNN. The CNN should have 3 convolutional layers. Use Leaky ReLU activation for all layers. (As last round worked, now proceed to the next level: activation functions)
5th Round Hypothesis (If fourth round worked): The model should be a CNN. The CNN should have 3 convolutional layers. Use Leaky ReLU activation for all layers. Use dropout regularization with a rate of 0.5. (Similar Reasoning & Continuing to Grow to the dropout setup)
6th Round Hypothesis (If fourth round didn't work): The model should be a CNN. The CNN should have 5 convolutional layers. Use Leaky ReLU activation for all layers. Use dropout regularization with a rate of 0.3. (Reasoning: As regularisation rate of 0.5 didn't work, we only change a new regularisation and keep the other elements that worked. This means making changes in the current level.)
model_experiment_output_format: |-
So far please only design one model to test the hypothesis!
The output should follow JSON format. The schema is as follows:
{
"model_name 1 (The name of the model)": {
"description": "A detailed description of the model",
"formulation": "A LaTeX formula representing the model's formulation",
"architecture": "A detailed description of the model's architecture, e.g., neural network layers or tree structures",
"variables": {
"\\hat{y}_u": "The predicted output for node u",
"variable_name_2": "Description of variable 2",
"variable_name_3": "Description of variable 3"
},
"hyperparameters": {
"hyperparameter_name_1": "value of hyperparameter 1",
"hyperparameter_name_2": "value of hyperparameter 2",
"hyperparameter_name_3": "value of hyperparameter 3"
},
"model_type": "XGBoost" # Should be "XGBoost"
},
"model_name 2 (The name of the model)": {
...
}
}
Usually a larger model works better than a smaller one. Hence, the parameters should be larger.
model_feedback_generation:
system: |-
You are a professional result analysis assistant. You will receive a result and a hypothesis.
Your task is to provide feedback on how well the result supports or refutes the hypothesis by judging from the observation of performance increase or decrease.
Please provide detailed and constructive feedback. Note that as hypothesis evolve, a general trend should be that the model grows larger.
Example JSON Structure for Result Analysis:
{
"Observations": "Your overall observations here",
"Feedback for Hypothesis": "Observations related to the hypothesis",
"New Hypothesis": "Put your new hypothesis here.",
"Reasoning": "Provide reasoning for the hypothesis here.",
"Decision": <true or false>,
}
Focus on the changes in hypothesis and justify why do hypothesis evolve like this. Also, increase complexity as the hypothesis evolves (give more layers, more neurons, and etc)
Logic for generating a new hypothesis: If the previous hypothesis works, try to inherit from it and grow deeper. If the previous hypotheis doesn't work, try to make changes in the current level.
Sample hypothesis evolution loop: (This is the entire loop, see what stage you are at. We want hypothesis to continue growing.) Levels include **Model Type**, **Layer Configuration**, **Activation Functions**, **Regularization Techniques**
1st Round Hypothesis: The model should be a CNN.
2nd Round Hypothesis (If first round worked: CNN is the model type level, which means that we should extend to the next level, like layer configuration): The model should be a CNN. The CNN should have 5 convolutional layers. (Reasoning: As CNN worked, we now specify the layers specification to grow the hypothesis deeper.)
3rd Round Hypothesis (If second round didn't work): The model should be a CNN. The CNN should have 3 convolutional layers. (Reasoning: As 5-layer structure didn't work in the 2nd round hypothesis, try something else within the layer configuration level.)
4th Round Hypothesis (If third round worked): The model should be a CNN. The CNN should have 3 convolutional layers. Use Leaky ReLU activation for all layers. (As last round worked, now proceed to the next level: activation functions)
5th Round Hypothesis (If fourth round worked): The model should be a CNN. The CNN should have 3 convolutional layers. Use Leaky ReLU activation for all layers. Use dropout regularization with a rate of 0.5. (Similar Reasoning & Continuing to Grow to the dropout setup)
6th Round Hypothesis (If fourth round didn't work): The model should be a CNN. The CNN should have 5 convolutional layers. Use Leaky ReLU activation for all layers. Use dropout regularization with a rate of 0.3. (Reasoning: As regularisation rate of 0.5 didn't work, we only change a new regularisation and keep the other elements that worked. This means making changes in the current level.)
user: |-
We are in an experiment of finding hypothesis and validating or rejecting them so that in the end we have a powerful model generated.
Here are the context: {{context}}.
{% if last_hypothesis %}
Last Round Information:
Hypothesis: {{last_hypothesis.hypothesis}}
Task: {{last_task}}
Code Implemented: {{last_code}}
Result: {{last_result}}
{% else %}
This is the first round. No previous information available. As long as the performance is not too negative (eg.ICIR is greater than 0), treat it as successful. Do not set the threshold too high.
{% endif %}
Now let's come to this round. You will receive the result and you will evaluate if the performance increases or decreases.
Hypothesis: {{hypothesis.hypothesis}}
Experiment Setup: {{exp.sub_tasks[0]}}
Code Implemented: {{exp.sub_workspace_list[0].code_dict.get("model.py")}}
Relevant Reasoning: {{hypothesis.reason}}
Result: {{exp.result}}
Compare and observe. Which result has a better return and lower risk? If the performance increases, the hypothesis should be considered positive (working).
Hence, with the hypotheses, relevant reasoning, and results in mind (comparison), provide detailed and constructive feedback and suggest a new hypothesis.
@@ -0,0 +1,105 @@
import json
from pathlib import Path
from typing import List, Tuple
from jinja2 import Environment, StrictUndefined
from rdagent.components.coder.model_coder.model import ModelExperiment, ModelTask
from rdagent.components.proposal.model_proposal import (
ModelHypothesis,
ModelHypothesis2Experiment,
ModelHypothesisGen,
)
from rdagent.core.prompts import Prompts
from rdagent.core.proposal import Hypothesis, Scenario, Trace
from rdagent.scenarios.kaggle.experiment.model_experiment import KGModelExperiment
prompt_dict = Prompts(file_path=Path(__file__).parent.parent / "prompts.yaml")
KGModelHypothesis = ModelHypothesis
class KGModelHypothesisGen(ModelHypothesisGen):
"""
# NOTE: we can share this class across different data mining scenarios
# It may better to move the class into components folder like `rdagent/components/proposal/model_proposal.py`
# Here is the use case:
.. code-block:: python
class XXXDMModelHypothesisGen(DMModelHypothesisGen):
prompts: Prompts = a_specifc_prompt_dict
"""
def __init__(self, scen: Scenario) -> Tuple[dict, bool]:
super().__init__(scen)
def prepare_context(self, trace: Trace) -> Tuple[dict, bool]:
hypothesis_feedback = (
Environment(undefined=StrictUndefined)
.from_string(prompt_dict["hypothesis_and_feedback"])
.render(trace=trace)
)
context_dict = {
"hypothesis_and_feedback": hypothesis_feedback,
"RAG": "",
"hypothesis_output_format": prompt_dict["hypothesis_output_format"],
"hypothesis_specification": "...",
}
return context_dict, True
def convert_response(self, response: str) -> ModelHypothesis:
response_dict = json.loads(response)
hypothesis = KGModelHypothesis(
hypothesis=response_dict["hypothesis"],
reason=response_dict["reason"],
concise_reason=response_dict["concise_reason"],
concise_observation=response_dict["concise_observation"],
concise_justification=response_dict["concise_justification"],
concise_knowledge=response_dict["concise_knowledge"],
)
return hypothesis
class KGModelHypothesis2Experiment(ModelHypothesis2Experiment):
def prepare_context(self, hypothesis: Hypothesis, trace: Trace) -> Tuple[dict, bool]:
scenario = trace.scen.get_scenario_all_desc()
experiment_output_format = prompt_dict["model_experiment_output_format"]
hypothesis_and_feedback = (
Environment(undefined=StrictUndefined)
.from_string(prompt_dict["hypothesis_and_feedback"])
.render(trace=trace)
)
experiment_list: List[ModelExperiment] = [t[1] for t in trace.hist]
model_list = []
for experiment in experiment_list:
model_list.extend(experiment.sub_tasks)
return {
"target_hypothesis": str(hypothesis),
"scenario": scenario,
"hypothesis_and_feedback": hypothesis_and_feedback,
"experiment_output_format": experiment_output_format,
"target_list": model_list,
"RAG": ...,
}, True
def convert_response(self, response: str, trace: Trace) -> ModelExperiment:
response_dict = json.loads(response)
tasks = []
for model_name in response_dict:
description = response_dict[model_name]["description"]
formulation = response_dict[model_name]["formulation"]
architecture = response_dict[model_name]["architecture"]
variables = response_dict[model_name]["variables"]
hyperparameters = response_dict[model_name]["hyperparameters"]
model_type = response_dict[model_name]["model_type"]
tasks.append(
ModelTask(model_name, description, formulation, architecture, variables, hyperparameters, model_type)
)
exp = KGModelExperiment(tasks)
exp.based_experiments = [t[1] for t in trace.hist if t[2]]
return exp
+1 -1
View File
@@ -15,9 +15,9 @@ WORKDIR /workspace/qlib
RUN git reset c9ed050ef034fe6519c14b59f3d207abcb693282 --hard
RUN python -m pip install --upgrade numpy
RUN python -m pip install --upgrade cython
RUN python -m pip install -e .
RUN pip install catboost
RUN pip install xgboost
RUN pip install scipy==1.11.4
@@ -12,6 +12,7 @@ from jinja2 import Environment, StrictUndefined
from sklearn.cluster import KMeans
from sklearn.metrics.pairwise import cosine_similarity
from sklearn.preprocessing import normalize
from tqdm.auto import tqdm
from rdagent.components.document_reader.document_reader import (
load_and_process_pdfs_by_langchain,
@@ -62,7 +63,7 @@ def classify_report_from_dict(
res_dict = {}
classify_prompt = document_process_prompts["classify_system"]
for key, value in report_dict.items():
for key, value in tqdm(report_dict.items()):
if not key.endswith(".pdf"):
continue
file_name = key
@@ -273,6 +274,49 @@ def merge_file_to_factor_dict_to_factor_dict(
return factor_dict_simple_deduplication
def __check_factor_dict_relevance(
factor_df_string: str,
) -> dict[str, dict[str, str]]:
extract_result_resp = APIBackend().build_messages_and_create_chat_completion(
system_prompt=document_process_prompts["factor_relevance_system"],
user_prompt=factor_df_string,
json_mode=True,
)
return json.loads(extract_result_resp)
def check_factor_relevance(
factor_dict: dict[str, dict[str, str]],
) -> tuple[dict[str, dict[str, str]], dict[str, dict[str, str]]]:
factor_relevance_dict = {}
factor_df = pd.DataFrame(factor_dict).T
factor_df.index.names = ["factor_name"]
while factor_df.shape[0] > 0:
result_list = multiprocessing_wrapper(
[
(__check_factor_dict_relevance, (factor_df.iloc[i : i + 50, :].to_string(),))
for i in range(0, factor_df.shape[0], 50)
],
n=RD_AGENT_SETTINGS.multi_proc_n,
)
for result in result_list:
for factor_name, relevance in result.items():
factor_relevance_dict[factor_name] = relevance
factor_df = factor_df[~factor_df.index.isin(factor_relevance_dict)]
filtered_factor_dict = {
factor_name: factor_dict[factor_name]
for factor_name in factor_dict
if factor_relevance_dict[factor_name]["relevance"]
}
return factor_relevance_dict, filtered_factor_dict
def __check_factor_dict_viability_simulate_json_mode(
factor_df_string: str,
) -> dict[str, dict[str, str]]:
@@ -319,29 +363,49 @@ def check_factor_viability(
def __check_factor_duplication_simulate_json_mode(
factor_df: pd.DataFrame,
) -> list[list[str]]:
session = APIBackend().build_chat_session(
session_system_prompt=document_process_prompts["factor_duplicate_system"],
)
current_user_prompt = factor_df.to_string()
generated_duplicated_groups = []
for _ in range(10):
extract_result_resp = session.build_chat_completion(
user_prompt=current_user_prompt,
json_mode=True,
)
ret_dict = json.loads(extract_result_resp)
if len(ret_dict) == 0:
return generated_duplicated_groups
working_list = [factor_df]
final_list = []
while len(working_list) > 0:
current_df = working_list.pop(0)
if (
APIBackend().build_messages_and_calculate_token(
user_prompt=current_df.to_string(), system_prompt=document_process_prompts["factor_duplicate_system"]
)
> RD_AGENT_SETTINGS.chat_token_limit
):
working_list.append(current_df.iloc[: current_df.shape[0] // 2, :])
working_list.append(current_df.iloc[current_df.shape[0] // 2 :, :])
else:
generated_duplicated_groups.extend(ret_dict)
current_user_prompt = """Continue to extract duplicated groups. If no more duplicated group found please respond empty dict."""
final_list.append(current_df)
generated_duplicated_groups = []
for current_df in final_list:
current_factor_to_string = current_df.to_string()
session = APIBackend().build_chat_session(
session_system_prompt=document_process_prompts["factor_duplicate_system"],
)
for _ in range(10):
extract_result_resp = session.build_chat_completion(
user_prompt=current_factor_to_string,
json_mode=True,
)
ret_dict = json.loads(extract_result_resp)
if len(ret_dict) == 0:
return generated_duplicated_groups
else:
generated_duplicated_groups.extend(ret_dict)
current_factor_to_string = """Continue to extract duplicated groups. If no more duplicated group found please respond empty dict."""
return generated_duplicated_groups
def __kmeans_embeddings(embeddings: np.ndarray, k: int = 20) -> list[list[str]]:
x_normalized = normalize(embeddings)
np.random.seed(42)
kmeans = KMeans(
n_clusters=k,
init="random",
@@ -359,7 +423,7 @@ def __kmeans_embeddings(embeddings: np.ndarray, k: int = 20) -> list[list[str]]:
return np.argmax(similarity, axis=1)
# Initializes the cluster center
rng = np.random.default_rng()
rng = np.random.default_rng(seed=42)
centroids = rng.choice(x_normalized, size=k, replace=False)
# Iterate until convergence or the maximum number of iterations is reached
@@ -424,7 +488,7 @@ Factor variables: {variables}
else:
for k in range(
len(full_str_list) // RD_AGENT_SETTINGS.max_input_duplicate_factor_group,
30,
RD_AGENT_SETTINGS.max_kmeans_group_number,
):
kmeans_index_group = __kmeans_embeddings(embeddings=embeddings, k=k)
if len(kmeans_index_group[0]) < RD_AGENT_SETTINGS.max_input_duplicate_factor_group:
@@ -435,26 +499,22 @@ Factor variables: {variables}
duplication_names_list = []
pool = mp.Pool(target_k)
result_list = [
pool.apply_async(
__check_factor_duplication_simulate_json_mode,
(factor_df.loc[factor_name_group, :],),
)
for factor_name_group in factor_name_groups
]
result_list = multiprocessing_wrapper(
[
(__check_factor_duplication_simulate_json_mode, (factor_df.loc[factor_name_group, :],))
for factor_name_group in factor_name_groups
],
n=RD_AGENT_SETTINGS.multi_proc_n,
)
pool.close()
pool.join()
duplication_names_list = []
for result in result_list:
deduplication_factor_names_list = result.get()
for deduplication_factor_names in deduplication_factor_names_list:
filter_factor_names = [
factor_name for factor_name in set(deduplication_factor_names) if factor_name in factor_dict
]
if len(filter_factor_names) > 1:
duplication_names_list.append(filter_factor_names)
for deduplication_factor_names_list in result_list:
filter_factor_names = [
factor_name for factor_name in set(deduplication_factor_names_list) if factor_name in factor_dict
]
if len(filter_factor_names) > 1:
duplication_names_list.append(filter_factor_names)
return duplication_names_list
@@ -465,6 +525,8 @@ def deduplicate_factors_by_llm( # noqa: C901, PLR0912
) -> list[list[str]]:
final_duplication_names_list = []
current_round_factor_dict = factor_dict
# handle multi-round deduplication
for _ in range(10):
duplication_names_list = __deduplicate_factor_dict(current_round_factor_dict)
@@ -480,11 +542,13 @@ def deduplicate_factors_by_llm( # noqa: C901, PLR0912
else:
break
# sort the final list of duplicates by their length, largest first
final_duplication_names_list = sorted(final_duplication_names_list, key=lambda x: len(x), reverse=True)
to_replace_dict = {}
to_replace_dict = {} # to map duplicates to the target factor names
for duplication_names in duplication_names_list:
if factor_viability_dict is not None:
# check viability of each factor in the duplicates group
viability_list = [factor_viability_dict[name]["viability"] for name in duplication_names]
if True not in viability_list:
continue
@@ -499,6 +563,7 @@ def deduplicate_factors_by_llm( # noqa: C901, PLR0912
llm_deduplicated_factor_dict = {}
added_lower_name_set = set()
for factor_name in factor_dict:
# only add factors that haven't been replaced and are not duplicates
if factor_name not in to_replace_dict and factor_name.lower() not in added_lower_name_set:
if factor_viability_dict is not None and not factor_viability_dict[factor_name]["viability"]:
continue
@@ -509,9 +574,9 @@ def deduplicate_factors_by_llm( # noqa: C901, PLR0912
class FactorExperimentLoaderFromPDFfiles(FactorExperimentLoader):
def load(self, file_or_folder_path: Path) -> dict:
def load(self, file_or_folder_path: str) -> dict:
with logger.tag("docs"):
docs_dict = load_and_process_pdfs_by_langchain(Path(file_or_folder_path))
docs_dict = load_and_process_pdfs_by_langchain(file_or_folder_path)
logger.log_object(docs_dict)
selected_report_dict = classify_report_from_dict(report_dict=docs_dict, vote_time=1)
@@ -143,6 +143,46 @@ factor_viability_system: |-
}
}
factor_relevance_system: |-
User has designed several factors in quant investment. Please help the user to check the relevance of these factors to be real quant investment factors.
These factors are used to build a daily frequency strategy in China A-share market.
User will provide a pandas dataframe like table containing following information:
1. The name of the factor;
2. The simple description of the factor;
3. The formulation of the factor in latex format;
4. The description to the variables and functions in the formulation of the factor.
A relevant factor should satisfy the following conditions:
1. The factor should be able to be calculated in daily frequency;
2. The factor should be able to be calculated based on each stock;
3. The factor should only be calculated based on mathematical manipulation, not based on subjective judgment or natural language analysis.
You should give decision to each factor provided by the user. You should reject the factor based on very solid reason.
Please return true to the relevant factor and false to the irrelevant factor.
Notice, you can just return part of the factors due to token limit. Your factor name should be the same as the user's factor name.
Please respond with your decision in JSON format. Just respond the output json string without any interaction and explanation.
The JSON schema should include:
{
"Name to factor 1":
{
"relevance": true,
"reason": "The reason to the relevance of this factor"
},
"Name to factor 2":
{
"relevance": false,
"reason": "The reason to the non-relevance of this factor"
}
"Name to factor 3":
{
"relevance": true,
"reason": "The reason to the relevance of this factor"
}
}
factor_duplicate_system: |-
User has designed several factors in quant investment. Please help the user to duplicate these factors.
+86 -2
View File
@@ -6,9 +6,11 @@ Tries to create uniform environment for the agent to run;
"""
# TODO: move the scenario specific docker env into other folders.
import json
import os
import subprocess
import sys
import zipfile
from abc import abstractmethod
from pathlib import Path
from typing import Dict, Generic, Optional, TypeVar
@@ -18,6 +20,7 @@ import docker.models
import docker.models.containers
from pydantic import BaseModel
from pydantic_settings import BaseSettings
from rich.progress import Progress, TextColumn
from rdagent.log import rdagent_logger as logger
@@ -159,6 +162,24 @@ class DMDockerConf(DockerConf):
shm_size: str | None = "16g"
class KGDockerConf(DockerConf):
class Config:
env_prefix = "KG_DOCKER_"
build_from_dockerfile: bool = True
dockerfile_folder_path: Path = Path(__file__).parent.parent / "scenarios" / "kaggle" / "docker"
image: str = "local_kg:latest"
# image: str = "gcr.io/kaggle-gpu-images/python:latest"
mount_path: str = "/workspace/kg_workspace/"
default_entry: str = "python train.py"
extra_volumes: dict = {
# TODO connect to the place where the data is stored
Path("git_ignore_folder/data").resolve(): "/root/.data/"
}
share_data_path: str = "/data/userdata/share/kaggle"
# physionet.org/files/mimic-eicu-fiddle-feature/1.0.0/FIDDLE_mimic3
class DockerEnv(Env[DockerConf]):
# TODO: Save the output into a specific file
@@ -170,14 +191,55 @@ class DockerEnv(Env[DockerConf]):
client = docker.from_env()
if self.conf.build_from_dockerfile and self.conf.dockerfile_folder_path.exists():
logger.info(f"Building the image from dockerfile: {self.conf.dockerfile_folder_path}")
image, logs = client.images.build(
resp_stream = client.api.build(
path=str(self.conf.dockerfile_folder_path), tag=self.conf.image, network_mode=self.conf.network
)
if isinstance(resp_stream, str):
logger.info(resp_stream)
with Progress(TextColumn("{task.description}")) as p:
task = p.add_task("[cyan]Building image...")
for part in resp_stream:
status_dict = json.loads(part)
if "error" in status_dict:
p.update(task, description=f"[red]error: {status_dict['error']}")
raise docker.errors.BuildError(status_dict["error"])
if "stream" in status_dict:
p.update(task, description=status_dict["stream"])
logger.info(f"Finished building the image from dockerfile: {self.conf.dockerfile_folder_path}")
try:
client.images.get(self.conf.image)
except docker.errors.ImageNotFound:
client.images.pull(self.conf.image)
image_pull = client.api.pull(self.conf.image, stream=True, decode=True)
current_status = ""
layer_set = set()
completed_layers = 0
with Progress(TextColumn("{task.description}"), TextColumn("{task.fields[progress]}")) as sp:
main_task = sp.add_task("[cyan]Pulling image...", progress="")
status_task = sp.add_task("[bright_magenta]layer status", progress="")
for line in image_pull:
if "error" in line:
sp.update(status_task, description=f"[red]error", progress=line["error"])
raise docker.errors.APIError(line["error"])
layer_id = line["id"]
status = line["status"]
p_text = line.get("progress", None)
if layer_id not in layer_set:
layer_set.add(layer_id)
if p_text:
current_status = p_text
if status == "Pull complete" or status == "Already exists":
completed_layers += 1
sp.update(main_task, progress=f"[green]{completed_layers}[white]/{len(layer_set)} layers completed")
sp.update(
status_task,
description=f"[bright_magenta]layer {layer_id} [yellow]{status}",
progress=current_status,
)
except docker.errors.APIError as e:
raise RuntimeError(f"Error while pulling the image: {e}")
@@ -284,3 +346,25 @@ class DMDockerEnv(DockerEnv):
os.system(cmd)
else:
logger.info("Data already exists. Download skipped.")
class KGDockerEnv(DockerEnv):
"""Qlib Torch Docker"""
def __init__(self, competition: str, conf: DockerConf = KGDockerConf()):
super().__init__(conf)
self.competition = competition
def prepare(self):
"""
Download image & data if it doesn't exist
"""
super().prepare()
# download data
data_path = f"{self.conf.share_data_path}/{self.competition}"
subprocess.run(["kaggle", "competitions", "download", "-c", self.competition, "-p", data_path])
# unzip data
with zipfile.ZipFile(f"{data_path}/{self.competition}.zip", "r") as zip_ref:
zip_ref.extractall(data_path)
+13 -10
View File
@@ -23,11 +23,12 @@ pandarallel # parallelize pandas
feedparser
matplotlib
langchain
langchain-community
tiktoken
pymupdf # Extract shotsreens from pdf
# azure identity related
azure.identity
azure-identity
# PDF related
pypdf
@@ -38,17 +39,9 @@ azure-ai-formrecognizer
# I think it is for running insteading of implementing. The dependency should be in
statsmodels
# PDF related
pypdf
azure-core
azure-ai-formrecognizer
# factor implementations
tables
# azure identity related
azure.identity
# CI Fix Tool
tree-sitter-python
tree-sitter
@@ -64,4 +57,14 @@ docker
# demo related
streamlit
plotly
st-btn-select
st-theme
# kaggle crawler
selenium
kaggle
seaborn
setuptools-scm
# This is a temporary package installed to pass the test_import test
xgboost
+1
View File
@@ -10,3 +10,4 @@ Sphinx
sphinx-autobuild
sphinx-click
sphinx-togglebutton
sphinx_rtd_theme
+46
View File
@@ -0,0 +1,46 @@
import importlib
import os
import unittest
from pathlib import Path
import pytest
@pytest.mark.offline
class TestRDAgentImports(unittest.TestCase):
@classmethod
def setUpClass(cls):
cls.rdagent_directory = Path(__file__).resolve().parent.parent.parent
cls.modules = list(cls.import_all_modules_from_directory(cls.rdagent_directory))
@staticmethod
def import_all_modules_from_directory(directory):
for file in directory.joinpath("rdagent").rglob("*.py"):
fstr = str(file)
if "meta_tpl" in fstr:
continue
if "_template" in fstr:
continue
if (
fstr.endswith("rdagent/log/ui/app.py")
or fstr.endswith("rdagent/app/cli.py")
or fstr.endswith("rdagent/app/CI/run.py")
):
# the entrance points
continue
yield fstr[fstr.index("rdagent") : -3].replace("/", ".")
def test_import_modules(self):
print(self.modules)
for module_name in self.modules:
with self.subTest(module=module_name):
try:
print(module_name)
importlib.import_module(module_name)
except Exception as e:
self.fail(f"Failed to import {module_name}: {e}")
if __name__ == "__main__":
unittest.main()
+3
View File
@@ -1,5 +1,7 @@
import unittest
import pytest
from rdagent.core.utils import SingletonBaseClass
@@ -15,6 +17,7 @@ class A(SingletonBaseClass):
return self.__str__()
@pytest.mark.offline
class MiscTest(unittest.TestCase):
def test_singleton(self):
print("a1=================")