From d2b268d2c1284f91042a5e5c1e6f5df69106a3ce Mon Sep 17 00:00:00 2001 From: ZeYi Lin <944270057@qq.com> Date: Tue, 3 Dec 2024 19:40:10 +0800 Subject: [PATCH] examples en --- .vitepress/en.ts | 204 +++++---- en/api/api-index.md | 13 + en/api/cli-swanlab-convert.md | 32 ++ en/api/cli-swanlab-login.md | 37 ++ en/api/cli-swanlab-logout.md | 7 + en/api/cli-swanlab-other.md | 4 + en/api/cli-swanlab-remote-gpu.md | 382 +++++++++++++++++ en/api/cli-swanlab-watch.md | 55 +++ en/api/py-Audio.md | 71 ++++ en/api/py-Image.md | 181 ++++++++ en/api/py-Text.md | 46 ++ en/api/py-converter.md | 6 + en/api/py-init.md | 108 +++++ en/api/py-integration.md | 15 + en/api/py-log.md | 33 ++ en/api/py-login.md | 24 ++ en/examples/audio_classification.md | 364 ++++++++++++++++ en/examples/bert.md | 150 +++++++ en/examples/cats_dogs_classification.md | 7 + en/examples/fashionmnist.md | 270 ++++++++++++ en/examples/hello_world.md | 35 ++ en/examples/lstm_stock.md | 274 ++++++++++++ en/examples/mnist.md | 200 +++++++++ en/examples/pretrain_llm.md | 397 ++++++++++++++++++ en/examples/qwen_finetune.md | 256 +++++++++++ en/examples/qwen_vl_coco.md | 7 + en/examples/yolo.md | 55 +++ en/guide_cloud/community/contributing-code.md | 168 ++++++++ en/guide_cloud/community/contributing-docs.md | 42 ++ en/guide_cloud/community/contributor.md | 20 + en/guide_cloud/community/emotion-machine.md | 8 + en/guide_cloud/community/github-badge.md | 11 + en/guide_cloud/community/online-support.md | 28 ++ en/guide_cloud/community/paper-cite.md | 14 + 34 files changed, 3420 insertions(+), 104 deletions(-) create mode 100644 en/api/api-index.md create mode 100644 en/api/cli-swanlab-convert.md create mode 100644 en/api/cli-swanlab-login.md create mode 100644 en/api/cli-swanlab-logout.md create mode 100644 en/api/cli-swanlab-other.md create mode 100644 en/api/cli-swanlab-remote-gpu.md create mode 100644 en/api/cli-swanlab-watch.md create mode 100644 en/api/py-Audio.md create mode 100644 en/api/py-Image.md create mode 100644 en/api/py-Text.md create mode 100644 en/api/py-converter.md create mode 100644 en/api/py-init.md create mode 100644 en/api/py-integration.md create mode 100644 en/api/py-log.md create mode 100644 en/api/py-login.md create mode 100644 en/examples/audio_classification.md create mode 100644 en/examples/bert.md create mode 100644 en/examples/cats_dogs_classification.md create mode 100644 en/examples/fashionmnist.md create mode 100644 en/examples/hello_world.md create mode 100644 en/examples/lstm_stock.md create mode 100644 en/examples/mnist.md create mode 100644 en/examples/pretrain_llm.md create mode 100644 en/examples/qwen_finetune.md create mode 100644 en/examples/qwen_vl_coco.md create mode 100644 en/examples/yolo.md create mode 100644 en/guide_cloud/community/contributing-code.md create mode 100644 en/guide_cloud/community/contributing-docs.md create mode 100644 en/guide_cloud/community/contributor.md create mode 100644 en/guide_cloud/community/emotion-machine.md create mode 100644 en/guide_cloud/community/github-badge.md create mode 100644 en/guide_cloud/community/online-support.md create mode 100644 en/guide_cloud/community/paper-cite.md diff --git a/.vitepress/en.ts b/.vitepress/en.ts index 1c1fab2..fc5bafb 100644 --- a/.vitepress/en.ts +++ b/.vitepress/en.ts @@ -27,20 +27,20 @@ export const en = defineConfig({ link: base_path_guide_cloud + '/general/what-is-swanlab', activeMatch: '/en/guide_cloud/', }, - // { - // text: '案例', - // link: base_path_examples + '/mnist', - // activeMatch: '/en/examples/', - // }, - // { - // text: 'API', - // link: base_path_api + '/api-index', - // activeMatch: '/en/api/', - // }, + { + text: 'Example', + link: base_path_examples + '/mnist', + activeMatch: '/en/examples/', + }, + { + text: 'API', + link: base_path_api + '/api-index', + activeMatch: '/en/api/', + }, { text: 'v0.3.27', items: [ { text: 'changelog', link: base_path_guide_cloud + '/general/changelog' }, - // { text: '参与贡献', link: 'https://github.com/SwanHubX/SwanLab/blob/main/CONTRIBUTING.md' }, - // { text: '建议反馈', link: 'https://geektechstudio.feishu.cn/share/base/form/shrcn8koDFRcH2mMcBYMh9tiKfI'} + { text: 'Contribution', link: 'https://github.com/SwanHubX/SwanLab/blob/main/CONTRIBUTING.md' }, + { text: 'Feedback', link: 'https://geektechstudio.feishu.cn/share/base/form/shrcn8koDFRcH2mMcBYMh9tiKfI'} ] }, // { text: '在线交流', link: '/en/guide_cloud/community/online-support'}, { text: 'Website', link: 'https://swanlab.cn' }, @@ -70,8 +70,8 @@ export const en = defineConfig({ // 侧边栏配置 sidebar: { '/en/guide_cloud/':{base: '/en/guide_cloud/', items: sidebarGuideCloud(),}, - // '/en/examples/':{base: '/en/examples/', items: sidebarExamples(),}, - // '/en/api/':{base: '/en/api/', items: sidebarAPI(),}, + '/en/examples/':{base: '/en/examples/', items: sidebarExamples(),}, + '/en/api/':{base: '/en/api/', items: sidebarAPI(),}, }, // 页脚配置 @@ -155,98 +155,94 @@ function sidebarGuideCloud(): DefaultTheme.SidebarItem[] { { text: 'ZhipuAI', link: 'integration/integration-zhipuai'}, ] }, -] + { + text: '👥 Community', + // collapsed: false, + items: [ + { text: 'Online support', link: 'community/online-support'}, + { text: 'Github badge', link: 'community/github-badge'}, + { text: 'Paper citation', link: 'community/paper-cite'}, + { text: 'Contributing code', link: 'community/contributing-code'}, + { text: 'Contributing docs', link: 'community/contributing-docs'}, + { text: 'Contributor', link: 'community/contributor'}, + { text: 'About us', link: 'community/emotion-machine'}, + ] + },] } +function sidebarExamples(): DefaultTheme.SidebarItem[] { + return [{ + text: 'Quick Start', + // collapsed: false, + items: [ + { text: 'Hello_World', link: 'hello_world' }, + { text: 'MNIST Handwriting Recognition', link: 'mnist' }, + ] + }, + { + text: 'Computer Vision', + // collapsed: false, + items: [ + { text: 'FashionMNIST', link: 'fashionmnist' }, + { text: 'Cats and Dogs Classification', link: 'cats_dogs_classification' }, + { text: 'Yolo Object Detection', link: 'yolo' }, + ] + }, + { + text: 'NLP', + // collapsed: false, + items: [ + { text: 'BERT Text Classification', link: 'bert' }, + { text: 'Qwen Finetune Case', link: 'qwen_finetune' }, + { text: 'LLM Pretraining', link: 'pretrain_llm' }, + ] + }, + { + text: 'Audio', + // collapsed: false, + items: [ + { text: 'Audio Classification', link: 'audio_classification' }, + ] + }, + { + text: 'Time Series', + // collapsed: false, + items: [ + { text: 'LSTM Stock Prediction', link: 'lstm_stock'}, + ] + }, +] +} -// { -// text: '👥 社区', -// // collapsed: false, -// items: [ -// { text: '在线支持', link: 'community/online-support'}, -// { text: 'Github徽章', link: 'community/github-badge'}, -// { text: '论文引用', link: 'community/paper-cite'}, -// { text: '贡献代码', link: 'community/contributing-code'}, -// { text: '贡献官方文档', link: 'community/contributing-docs'}, -// { text: '贡献者', link: 'community/contributor'}, -// { text: '关于我们', link: 'community/emotion-machine'}, -// ] -// },] -// } - -// function sidebarExamples(): DefaultTheme.SidebarItem[] { -// return [{ -// text: '入门', -// // collapsed: false, -// items: [ -// { text: 'Hello_World', link: 'hello_world' }, -// { text: 'MNIST手写体识别', link: 'mnist' }, -// ] -// }, -// { -// text: '计算机视觉', -// // collapsed: false, -// items: [ -// { text: 'FashionMNIST', link: 'fashionmnist' }, -// { text: 'Resnet猫狗分类', link: 'cats_dogs_classification' }, -// { text: 'Yolo目标检测', link: 'yolo' }, -// ] -// }, -// { -// text: '自然语言处理', -// // collapsed: false, -// items: [ -// { text: 'BERT文本分类', link: 'bert' }, -// { text: 'Qwen微调案例', link: 'qwen_finetune' }, -// { text: 'LLM预训练', link: 'pretrain_llm' }, -// ] -// }, -// { -// text: '音频', -// // collapsed: false, -// items: [ -// { text: '音频分类', link: 'audio_classification' }, -// ] -// }, -// { -// text: '时间序列', -// // collapsed: false, -// items: [ -// { text: 'LSTM股票预测', link: 'lstm_stock'}, -// ] -// }, -// ] -// } - -// function sidebarAPI(): DefaultTheme.SidebarItem[] { -// return [{ -// text: 'CLI', -// // collapsed: false, -// items: [ -// { text: 'swanlab watch', link: 'cli-swanlab-watch' }, -// { text: 'swanlab login', link: 'cli-swanlab-login' }, -// { text: 'swanlab logout', link: 'cli-swanlab-logout' }, -// { text: 'swanlab convert', link: 'cli-swanlab-convert' }, -// { text: '(内测中) swanlab remote gpu', link: 'cli-swanlab-remote-gpu' }, -// { text: '其他', link: 'cli-swanlab-other' }, -// ] -// }, -// { -// text: 'Python SDK', -// // collapsed: false, -// items: [ -// { text: 'init', link: 'py-init' }, -// { text: 'log', link: 'py-log' }, -// { text: '多媒体数据', items: [ -// { text: 'Image', link: 'py-Image' }, -// { text: 'Audio', link: 'py-Audio' }, -// { text: 'Text', link: 'py-Text' }, -// ]}, -// { text: 'login', link: 'py-login' }, -// { text: 'integration', link: 'py-integration' }, -// { text: 'converter', link: 'py-converter' }, -// ] -// },] -// } \ No newline at end of file +function sidebarAPI(): DefaultTheme.SidebarItem[] { + return [{ + text: 'CLI', + // collapsed: false, + items: [ + { text: 'swanlab watch', link: 'cli-swanlab-watch' }, + { text: 'swanlab login', link: 'cli-swanlab-login' }, + { text: 'swanlab logout', link: 'cli-swanlab-logout' }, + { text: 'swanlab convert', link: 'cli-swanlab-convert' }, + { text: '(Beta) swanlab remote gpu', link: 'cli-swanlab-remote-gpu' }, + { text: 'Other', link: 'cli-swanlab-other' }, + ] + }, + { + text: 'Python SDK', + // collapsed: false, + items: [ + { text: 'init', link: 'py-init' }, + { text: 'log', link: 'py-log' }, + { text: 'Media data', items: [ + { text: 'Image', link: 'py-Image' }, + { text: 'Audio', link: 'py-Audio' }, + { text: 'Text', link: 'py-Text' }, + ]}, + { text: 'login', link: 'py-login' }, + { text: 'integration', link: 'py-integration' }, + { text: 'converter', link: 'py-converter' }, + ] + },] +} \ No newline at end of file diff --git a/en/api/api-index.md b/en/api/api-index.md new file mode 100644 index 0000000..db7f870 --- /dev/null +++ b/en/api/api-index.md @@ -0,0 +1,13 @@ +# API Docs + +## CLI +- [swanlab watch](/en/api/cli-swanlab-watch.md): Start offline experiment board +- [swanlab login](/en/api/cli-swanlab-login.md): Login to SwanLab +- [swanlab convert](/en/api/cli-swanlab-convert.md): Convert external logs to SwanLab project + +## Python SDK +- [init](/en/api/py-init.md) +- [login](/en/api/py-login.md) +- [Image](/en/api/py-Image.md) +- [Audio](/en/api/py-Audio.md) +- [Text](/en/api/py-Text.md) \ No newline at end of file diff --git a/en/api/cli-swanlab-convert.md b/en/api/cli-swanlab-convert.md new file mode 100644 index 0000000..d8f7e89 --- /dev/null +++ b/en/api/cli-swanlab-convert.md @@ -0,0 +1,32 @@ +# swanlab convert + +```bash +swanlab convert [OPTIONS] +``` + +| Option | Description | +| --- | --- | +| `-t`, `--type` | Select the conversion type, options include `tensorboard`, `wandb`, default is `tensorboard`. | +| `-p`, `--project` | Set the SwanLab project name for the conversion, default is None. | +| `-w`, `--workspace` | Set the workspace where the SwanLab project is located, default is None. | +| `-l`, `--logdir` | Set the log file save path for the SwanLab project, default is None. | +| `--cloud` | Set whether the SwanLab project logs are uploaded to the cloud, default is True. | +| `--tb-logdir` | Path to the Tensorboard log files (tfevent) to be converted. | +| `--wb-project` | Name of the Wandb project to be converted. | +| `--wb-entity` | Entity where the Wandb project to be converted is located. | +| `--wb-runid` | ID of the Wandb Run to be converted. | + +## Introduction + +Convert content from other logging tools into SwanLab projects. +Supported tools for conversion include: `Tensorboard`, `Weights & Biases`. + +## Usage Examples + +### Tensorboard + +[Integration - Tensorboard](/en/guide_cloud/integration/integration-tensorboard.md) + +### Weights & Biases + +[Integration - Weights & Biases](/en/guide_cloud/integration/integration-wandb.md) \ No newline at end of file diff --git a/en/api/cli-swanlab-login.md b/en/api/cli-swanlab-login.md new file mode 100644 index 0000000..9fad8d5 --- /dev/null +++ b/en/api/cli-swanlab-login.md @@ -0,0 +1,37 @@ +# swanlab login + +``` bash +swanlab login [OPTIONS] +``` + +| Option | Description | +| --- | --- | +| `--relogin` | Re-login. | + +## Introduction + +Log in to your SwanLab account to synchronize experiments to the cloud. + +After running the following command, if it's your first login, you will be prompted to fill in your [API_KEY](#): + +```bash +swanlab login +``` + +After the first login, the credentials will be saved locally, and you won't need to log in again via `swanlab.login` or `swanlab login`. + +## Re-login + +If you need to log in with a different account, use the following command: + +```bash +swanlab login --relogin +``` + +This will prompt you to enter a new API Key to re-login. + +## Logout + +```bash +swanlab logout +``` \ No newline at end of file diff --git a/en/api/cli-swanlab-logout.md b/en/api/cli-swanlab-logout.md new file mode 100644 index 0000000..8b2d939 --- /dev/null +++ b/en/api/cli-swanlab-logout.md @@ -0,0 +1,7 @@ +# swanlab + +```bash +swanlab logout +``` + +Logout from the programming environment. diff --git a/en/api/cli-swanlab-other.md b/en/api/cli-swanlab-other.md new file mode 100644 index 0000000..110d73c --- /dev/null +++ b/en/api/cli-swanlab-other.md @@ -0,0 +1,4 @@ +# Other CLI Commands + +- `swanlab -v`: Check the version of the SwanLab library. +- `swanlab --help`: API help. \ No newline at end of file diff --git a/en/api/cli-swanlab-remote-gpu.md b/en/api/cli-swanlab-remote-gpu.md new file mode 100644 index 0000000..1e5b723 --- /dev/null +++ b/en/api/cli-swanlab-remote-gpu.md @@ -0,0 +1,382 @@ +# SwanLab Remote Task Deployment Documentation (Beta Feature) + +::: danger +Warning: This feature is currently in beta testing. Please thoroughly read the Feature Testing Instructions section of this document before using this feature. **Some limitations during the beta phase:** + +1. Maximum task duration is 4 hours. +2. For more information about the beta phase, please contact or (Product Manager's Email). +::: + +Launch Experiment Command + +``` bash +swanlab launch [OPTIONS] +``` + +| Option | Description | +| --- | --- | +| `-f,--file ` | Execute the task based on the configuration file. | +| `--help ` | Print help information. | + +View and Pause Task Commands + +``` bash +swanlab task [OPTIONS] +``` + +| Option | Description | +| --- | --- | +| `list` | View the status of started training tasks. | +| `search ` | View the running status of a specific task. | +| `stop ` | Stop a running command. | +| `--help` | Print help information. | + +For detailed usage, please refer to [SwanLab Remote Task Deployment Commands](#swanlab-remote-task-deployment-commands). + +## SwanLab Task Quick Start Tutorial in 3 Minutes + +This tutorial will help readers understand how to use the **SwanLab Remote Task Deployment Documentation** feature through a simple quadratic function regression task. + +### Preliminary Steps: Login and Obtain Key + +Register and log in to [SwanLab](http://swanlab.cn/), and obtain your [API Key](https://swanlab.cn/settings/overview). + +Install swanlab locally (ensure the version number is 0.3.15 or higher): + +```bash +pip install -U swanlab +``` + +You can check the swanlab version number with the following command: + +```bash +swanlab -v +# 0.3.15 +``` + +### Step 1: Prepare the Code + +Use the prepared open-source example, download the [SwanLab Remote Task Deployment Test Code](https://github.com/SwanHubX/SwanLab-LaunchExample.git) using git, and navigate to the project's root directory: + +```bash +# Download the project +git clone https://github.com/SwanHubX/SwanLab-LaunchExample.git +# Enter the project root directory +cd SwanLab-LaunchExample +``` + +If you cannot use [Github](https://github.com), you can find the complete code in the [Appendix](#training-example-code). + +### Step 2: Run the Code on the Cloud + +Use the `swanlab task launch` command to execute the training entry function as follows: + +```bash +swanlab task launch -f swanlab.yaml +``` + +**SwanLab Remote Task Deployment Documentation** will automatically package and upload the local code to the GPU server and start the training based on the configuration file. + +![launch-upload](../../assets/api/cli-swanlab-task/launch.png) + +For detailed functions of the configuration file (such as specifying the environment, mounting datasets, etc.), please refer to [YAML Configuration File and Functions](#yaml-configuration-file-and-functions). + +### Step 3: View the Experiment + +You can use the following command to view the started experiments: + +```bash +swanlab task list +``` + +This will open a table in the terminal (as shown below), with the top one being the current experiment. The *Status* indicates the current status of the experiment (refer to the [swanlab task list](#swanlab-task-list) section for status details). + +![task-list](../../assets/api/cli-swanlab-task/task-list.png) + +When the training starts (*Status* switches to *RUNNING*), you can click the link in *URL* to view the started experiment on [swanlab.cn](https://swanlab.cn). + +:::info +Only when the code includes using `swanlab` for online experiment metric tracking will the URL be automatically obtained and displayed. + +For training metric tracking using `swanlab`, refer to [Create an Experiment](../guide_cloud/experiment_track/create-experiment.md). +::: + +You can view the tracked experiment metrics online: + +![launch-remote-exp](../../assets/task-remote-exp.png) + +Click Logs to view the terminal output information on the cloud: + +![launch-remote-logs](../../assets/task-remote-log.png) + +On the SwanLab cloud experiment dashboard interface (as shown below), click Environments -> System Hardware to see the current cloud server hardware: + +![launch-remote-device](../../assets/task-remote-device.png) + +For commands related to debugging and stopping ongoing experiments, refer to [SwanLab Remote Task Deployment Commands](#swanlab-remote-task-deployment-commands). + +## Design Philosophy + +The **SwanLab Remote Task Deployment Documentation** feature aims to help AI researchers easily and efficiently utilize multiple different local GPU servers and conveniently plan their training tasks. Therefore, the **SwanLab Remote Task Deployment Documentation** feature focuses on solving how to make it easier for users to quickly deploy training to GPU servers. + +![launch comparison](../../assets/task-compare.png) + +Usually, using a remote GPU server to complete training requires three steps (see the left side of the image above): + +1. Write code locally. +2. Synchronize to the GPU server. +3. Use ssh to start the experiment. + +However, if you have a multi-card GPU server or multiple GPU servers, the problem becomes more complicated, including: + +* Need to check which GPU is idle. +* If the new server has not installed the environment, you need to configure the environment. +* Need to upload and download datasets. +* Multi-node experiments require repeating these actions on multiple servers. +* ... + +Using the **SwanLab Remote Task Deployment Documentation** feature only requires the following operations (see the right side of the image above): + +1. The GPU server runs **SwanLab Agent** in the background. +2. Complete the experiment script writing and environment dependency formulation locally. +3. Use the `swanlab launch ...` command to deploy to the GPU server and start training. + +SwanLab will automatically complete the local code packaging and uploading, GPU server environment installation, and allocate corresponding GPU cards for training based on the GPU server's graphics card idle status. Researchers do not need to do tedious environment configuration, check server idle status, etc., and can focus on training itself. + +## SwanLab Remote Task Deployment Commands + +:::warning +Due to ongoing development, CLI commands and interfaces may change at any time. You can view the latest commands by using `--help` after any command. +::: + +### Function Navigation + +| Requirement | Navigation | +| --- | --- | +| Upload dataset | [swanlab upload](#swanlab-upload) | +| Deploy remote GPU training task | [swanlab launch](#swanlab-launch) | +| View uploaded tasks, datasets | [swanlab task list](#swanlab-task-list) | +| View task running status, failure logs | [swanlab task search](#swanlab-task-search) | +| Stop running task | [swanlab task stop](#swanlab-task-stop) | +| View command usage | Any command followed by `--help` parameter | + +### swanlab launch + +```bash +swanlab task launch -f +``` + +Package and upload the tasks in the folder to the remote GPU server and execute the entry training function. + +### YAML Configuration File and Functions + +Below is a complete YAML file and its function description. + +```yaml +apiVersion: swanlab/v1 # Interface version, no need to change +kind: Folder # Task loading type, will support more types in the future +metadata: + name: "Launch-Example" # Task name + desc: "" # Description of the experiment, optional + combo: RTX3090-1 # Compute power queue, options include RTX3090-1 and H800-1 queues +spec: + python: "3.10" # Currently only supports 3.8, 3.9, 3.10 + entry: "train.py" # Entry function to be executed + volumes: + - id: "" # Fill in the mounted storage ID + exclude: + - "" # Files to be ignored during packaging and uploading (used to shield unnecessary files such as datasets and model weights in the current folder) +``` + +For a new experiment, you need to pay attention to the following configuration information: + +* **combo** Used to specify the GPU type, options include "H800-1" and "RTX3090-1", both single-card +* **entry** Used to specify the entry function to start training +* **volumes** For larger files, it is recommended to load them in the form of storage mounting + +### swanlab upload + +This command is used to upload larger files that need to be reused in multiple experiments. The command is as follows: + +```bash +swanlab upload +``` + +The effect is as follows: + +![upload](../../assets/api/cli-swanlab-task/upload.png) + +After the upload is completed, the `dataset id` will be displayed, which can be mounted in the [YAML configuration file](#yaml-configuration-file-and-functions). + +The mounted files will be located in the `/data/` folder. + +You can also view the mounted files (red box part) using the command `swanlab task list`: + +![upload-list](../../assets/api/cli-swanlab-task/upload-list.png) + +### swanlab download (In Development) + +(To be supplemented) + +### swanlab task list + +```bash +swanlab task list +``` + +Prints out completed or running experiments (default prints the latest 10). The effect is as follows: + +![task-list](../../assets/api/cli-swanlab-task/task-list.png) + +Where: + +* **TASK ID**: Unique identifier of the task +* **Task Name**: Task name +* **URL**: Link to the SwanLab online experiment log tracking (only when the experiment script sets `swanlab.init` and enables cloud synchronization of experiment data) +* **Started Time**: Experiment deployment start time +* **Finished Time**: Experiment completion time + +The tasks in the dashboard have three states: + +* **QUEUING**: Remote GPU is busy, waiting in queue +* **PREPARE**: Deploying remote environment +* **RUNNING**: Running training +* **COMPLETED**: Completed tasks +* **CRASHED**: Environment deployment failure or code error + +Use `ctrl+c` to exit the dashboard. + +### swanlab task search + +```bash +swanlab task search +``` + +This command is used to view the start and end time of the experiment, as well as the cluster type, execution environment, etc. The `TASK_ID` can be viewed using [swanlab task list](#swanlab-task-list). + +```bash +Task Info +Task Name: Task_Jul31_02-44-38 +Python Version: python3.10 +Entry File: train.py +Status: ✅ COMPLETED +Combo: RTX3090-1 +Created At: 2024-07-30 18:44:40 +Started At: 2024-07-30 18:45:02 +Finished At: 2024-07-30 18:52:49 +``` + +This command can also be used to view error information for failed tasks (tasks with execution status CRASHED). For example, when I intentionally add error code to the test code in the [Quick Start section](#swanlab-task-quick-start-tutorial-in-3-minutes): + +![error-code](../../assets/task-error-code.png) + +After using the `swanlab task search ` command for the started task, the effect is as follows: + +![task-search](../../assets/task-search-error.png) + +Of course, you can also view the error information in the [SwanLab online experiment dashboard](https://swanlab.cn) under the log: + +![remote-error-log](../../assets/task-remote-error-log.png) + +## swanlab task stop + +Terminate a started task using the following method: + +```bash +swanlab task stop +``` + +## SwanLab Agent Installation (In Development) + +(To be supplemented) + +> Currently, this feature is under development and testing. To facilitate usage, SwanLab provides free cloud testing compute power. You can directly use cloud compute power to run and deploy via `swanlab launch`. + +## Working Process and Principles + +(To be supplemented) + +## Feature Testing Instructions + +:::info +It is strongly recommended to [click the link](https://geektechstudio.feishu.cn/wiki/Te1EwcLbrimD7Zk1fsrcCovanyg) to join the testing group before using this feature. We will respond to and solve any issues encountered in the group in a timely manner. +::: + +The **SwanLab Remote Task Deployment Documentation** feature involves uploading the required running code and datasets to a public cloud server. We strive to ensure your data security, but there is still a risk of data leakage or loss during the testing phase. **Do not upload important data to the testing feature**. + +The iteration of the **SwanLab Remote Task Deployment Documentation** feature depends on active feedback from community users. If you encounter any issues, please feel free to contact us. You can use [Github Issue](https://github.com/SwanHubX/SwanLab/issues), contact email , or join the [WeChat testing group](https://geektechstudio.feishu.cn/wiki/NIZ9wp5LRiSqQykizbGcVzUKnic?fromScene=spaceOverview) to communicate directly with us. + +To facilitate smooth testing, the **SwanLab Remote Task Deployment Documentation** provides free testing running servers for users participating in the test. We strive to meet the testing and compute power needs of every user, but due to limited team resources and feature iteration, there may still be situations such as task queuing and training forced termination. + +## Acknowledgments + +🙏 We are extremely grateful to the users who are willing to participate in the feature testing, and we will continue to work hard. + +🙏 We are also grateful to [H3C](https://www.h3c.com/cn/) for providing us with compute power support. + +## Appendix + +### Training Example Code + +Step 1: Create an empty folder in the directory and navigate to the folder: + +```bash +# Linux & Mac & Windows command +mkdir SwanLabLaunchExample +``` + +Step 2: Create `train.py` in the `SwanLabLaunchExample` folder and paste the following training code: + +```python +################################ +# File Name: train.py +################################ + +import torch +import torch.nn as nn +import torch.optim as optim +import swanlab +import logging + +# 0. Initialize experiment environment +swanlab.init("Launch-Example", experiment_name="test-remote") # Initialize swanlab +device = "cuda" +if not torch.cuda.is_available(): # Check if a GPU is available, if not, use CPU and log a warning + device = "cpu" + logging.warning("CUDA IS NOT AVAILIABLE, use cpu instead") + +# 1. Define the function, target is a simple quadratic function, domain and range are both [0,1] +func = lambda x: (2 * x - 1) ** 2 + +# 2. Define the model, a 3-layer neural network (increasing parameters or layers will yield better results) +model = nn.Sequential(nn.Linear(1, 16), nn.Sigmoid(), nn.Linear(16, 1)) +model = model.to(device) + +# 3. Define the loss function and optimizer +criterion = nn.MSELoss().to(device) +optimizer = optim.AdamW(model.parameters(), lr=0.001) + +# 4. Train the model +iters = 8000 +batch_num = 256 +for i in range(iters): + # Generate data + x = torch.rand(batch_num, 1) + y = func(x) + x, y = x.to(device), y.to(device) + + optimizer.zero_grad() # Clear gradients + outputs = model(x) # Forward propagation + loss = criterion(outputs, y) # Calculate loss + loss.backward() # Backward propagation + optimizer.step() # Update parameters + + if i % 5 == 0: + print(f"Iter [{i+1}/{iters}], Loss: {loss.item():.4f}") + swanlab.log({"loss": loss.item()}, step=i) + +# 5. Validate the model +model.eval() +with torch.no_grad(): + sample_num = 101 + inputs = torch.linspace(0, 1, sample_num).unsqueeze(1).to(device) \ No newline at end of file diff --git a/en/api/cli-swanlab-watch.md b/en/api/cli-swanlab-watch.md new file mode 100644 index 0000000..ba1f894 --- /dev/null +++ b/en/api/cli-swanlab-watch.md @@ -0,0 +1,55 @@ +# swanlab watch + +``` bash +swanlab watch [OPTIONS] +``` + +| Option | Description | Example | +| --- | --- | --- | +| `-p`, `--port` | Set the port for the experiment dashboard web service to run on, default is **5092**. | `swanlab watch -p 8080`: Set the experiment dashboard web service to port 8080 | +| `-h`, `--host` | Set the IP address for the experiment dashboard web service to run on, default is **127.0.0.1**. | `swanlab watch -h 0.0.0.0`: Set the experiment dashboard web service IP address to 0.0.0.0 | +| `-l`, `--logdir` | Set the log file path for the experiment dashboard web service to read from, default is `swanlog`. | `swanlab watch --logdir ./logs`: Set the logs folder in the current directory as the log file read path | +| `--help` | View terminal help information. | `swanlab watch --help` | + +## Introduction + +Start the SwanLab experiment dashboard locally. +When creating a SwanLab experiment, a log folder is created locally (default name is `swanlog`). Using `swanlab watch` allows you to open the experiment dashboard offline locally to view metric charts and configurations. + +## Usage Examples + +### Open SwanLab Offline Dashboard + +First, locate the log folder (default name is `swanlog`), then execute the following command in the terminal: + +```bash +swanlab watch -l [logfile_path] +``` + +Where `logfile_path` is the path to the log folder, which can be an absolute or relative path. If your log folder name is the default `swanlog`, you can also start it directly with `swanlab watch` without the `-l` option. + +After executing the command, you will see the following output: +```bash{6} +swanlab watch -l [logfile_path] + +*swanlab: Try to explore the swanlab experiment logs in: [logfile_path] +*swanlab: SwanLab Experiment Dashboard ready in 465ms + + ➜ Local: http://127.0.0.1:5092 +``` + +Visit the provided URL to access the SwanLab offline dashboard. + +### Set IP and Port Number + +We can set the IP with the `-h` parameter and the port number with the `-p` parameter. +For example, if we want to access the offline dashboard on a cloud server locally, we need to set the IP to 0.0.0.0 when starting the experiment dashboard on the cloud server: + +```bash +swanlab watch -h 0.0.0.0 +``` + +If you need to set the port: +```bash +swanlab watch -h 0.0.0.0 -p 8080 +``` \ No newline at end of file diff --git a/en/api/py-Audio.md b/en/api/py-Audio.md new file mode 100644 index 0000000..f61bcc3 --- /dev/null +++ b/en/api/py-Audio.md @@ -0,0 +1,71 @@ +# swanlab.Audio + +[Github Source Code](https://github.com/SwanHubX/SwanLab/blob/main/swanlab/data/modules/audio.py) + +```python +Audio( + data_or_path: Union[str, np.ndarray], + sample_rate: int = 44100, + caption: str = None, +) -> None +``` + +| Parameter | Description | +|--------------|--------------------------------------------------------------------------------------------------------| +| data_or_path | (Union[str, np.ndarray]) Accepts an audio file path or a numpy array. The Audio class will determine the received data type and perform the appropriate conversion. | +| sample_rate | (int) The sample rate of the audio, default is 44100. | +| caption | (str) The label for the audio. Used to mark the audio when displayed in the experiment dashboard. | + +## Introduction + +Convert various types of audio data to be recorded by `swanlab.log()`. + +![](/assets/media-audio-1.jpg) + +### Creating from numpy array + +Logging a single audio: + +```python +import numpy as np +import swanlab + +run = swanlab.init() + +# Create an audio of numpy array type +white_noise = np.random.randn(2, 100000) +# Pass it to swanlab.Audio, set the sample rate +audio = swanlab.Audio(white_noise, caption="white_noise") + +run.log({"examples": audio}) +``` + +Logging multiple audios: + +```python +import numpy as np +import swanlab + +run = swanlab.init() + +# Create a list +examples = [] +for i in range(3): + white_noise = np.random.randn(100000) + audio = swanlab.Audio(white_noise, caption=f"audio_{i}") + # Add swanlab.Audio type objects to the list + examples.append(audio) + +run.log({"examples": examples}) +``` + +### Creating from file path + +```python +import swanlab + +run = swanlab.init() +audio = swanlab.Audio("path/to/file") + +run.log({"examples": audio}) +``` \ No newline at end of file diff --git a/en/api/py-Image.md b/en/api/py-Image.md new file mode 100644 index 0000000..0604db7 --- /dev/null +++ b/en/api/py-Image.md @@ -0,0 +1,181 @@ +# swanlab.Image + +[Github Source Code](https://github.com/SwanHubX/SwanLab/blob/main/swanlab/data/modules/image.py) + +```python +Image( + data_or_path: Union[str, np.ndarray, PILImage.Image], + mode: str = "RGB", + caption: str = None, + file_type: str = None, + size: Union[int, list, tuple] = None, +) -> None +``` + +| Parameter | Description | +|--------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| data_or_path | (Union[str, np.ndarray, PILImage.Image]) Accepts an image file path, numpy array, or PIL image. The Image class will determine the received data type and perform the appropriate conversion. | +| mode | (str) The PIL mode of the image. The most common are "L", "RGB", "RGBA". For a complete explanation, see: [Pillow mode](https://pillow.readthedocs.io/en/stable/handbook/concepts.html#modes) | +| caption | (str) The label for the image. Used to mark the image when displayed in the experiment dashboard. | +| file_type | (str) Set the image format, options include ['png', 'jpg', 'jpeg', 'bmp'], default is 'png'. | +| size | (Union[int, list, tuple]) Set the image size, default is to keep the original size. If size is set to an int type, such as 512, the image will be scaled based on the longest side not exceeding 512. [More usage for size](#resize-the-input-image) | + +## Introduction + +Convert various types of image data to be recorded by `swanlab.log()`. + +![](/assets/media-image-1.jpg) + +### Creating from numpy array + +Logging a single image: + +```python +import numpy as np +import swanlab + +run = swanlab.init() + +# 1. Create a numpy array +random_image = np.random.randint(low=0, high=256, size=(100, 100, 3), dtype=np.uint8) +# 2. Pass it to swanlab.Image +image = swanlab.Image(random_image, caption="random image") + +run.log({"examples": image}) +``` + +Logging multiple images: + +```python +import numpy as np +import swanlab + +run = swanlab.init() + +# Create a list +examples = [] +for i in range(3): + random_image = np.random.randint(low=0, high=256, size=(100, 100, 3), dtype=np.uint8) + image = swanlab.Image(random_image, caption="random image") + # Add swanlab.Image type objects to the list + examples.append(image) + +# Log the list of images +run.log({"examples": examples}) +``` + +### Creating from PyTorch Tensor + +`swanlab.Image` supports tensors with dimensions [B, C, H, W] and [C, H, W]. + +```python +import torch +import swanlab + +run = swanlab.init() +··· +for batch, ground_truth in train_dataloader(): + # Assume batch is a tensor with dimensions [16, 3, 256, 256] + tensors = swanlab.Image(batch) + run.log({"examples": tensors}) +``` + +### Creating from PIL Image + +```python +import numpy as np +from PIL import Image +import swanlab + +run = swanlab.init() + +# Create a list +examples = [] +for i in range(3): + random_image = np.random.randint(low=0, high=256, size=(100, 100, 3), dtype=np.uint8) + pil_image = Image.fromarray(random_image) + image = swanlab.Image(pil_image, caption="random image") + examples.append(image) + +run.log({"examples": examples}) +``` + +### Creating from file path + +```python +import swanlab + +run = swanlab.init() +image = swanlab.Image("path/to/file", caption="random image") + +run.log({"examples": image}) +``` + +By default, `swanlab.Image` converts and stores images in `png` format. + +If you want to use `jpg` format: + +```python{3} +image = swanlab.Image("path/to/file", + caption="random image", + file_type="jpg") +``` + +### Resize the Input Image + +By default, `swanlab.Image` does not resize the image. + +If you need to resize the image, you can adjust the image size by setting the `size` parameter. + +The resizing rules are: + +1. Default: No resizing of the image. + +2. `size` as an int type: If the longest side exceeds `size`, set the longest side to `size` and scale the other side proportionally; otherwise, no resizing. + +3. `size` as a list/tuple type: + + - (int, int): Resize the image to width `size[0]` and height `size[1]`. + - (int, None): Resize the image to width `size[0]` and scale the height proportionally. + - (None, int): Resize the image to height `size[1]` and scale the width proportionally. + +```python +print(im_array.shape) +# [1024, 512, 3] + +im1 = swanlab.Image(im_array, size=512) +# [512, 256, 3] + +im2 = swanlab.Image(im_array, size=(512, 512)) +# [512, 512, 3] + +im3 = swanlab.Image(im_array, size=(None, 1024)) +# [2048, 1024, 3] + +im4 = swanlab.Image(im_array, size=(256, None)) +# [256, 128, 3] +``` + +### Logging Matplotlib Plots + +```python +import swanlab +import matplotlib.pyplot as plt + +# Define the data for the x and y axes +x = [1, 2, 3, 4, 5] +y = [2, 3, 5, 7, 11] + +# Create a line plot with plt +plt.plot(x, y) + +# Add title and labels +plt.title("Examples") +plt.xlabel("X-axis") +plt.ylabel("Y-axis") + +swanlab.init() + +# Log the plt plot +swanlab.log({"example": swanlab.Image(plt)}) +``` \ No newline at end of file diff --git a/en/api/py-Text.md b/en/api/py-Text.md new file mode 100644 index 0000000..a32869f --- /dev/null +++ b/en/api/py-Text.md @@ -0,0 +1,46 @@ +# swanlab.Text + +[Github Source Code](https://github.com/SwanHubX/SwanLab/blob/main/swanlab/data/modules/text.py) + +```python +Text( + data: Union[str], + caption: str = None, +) -> None +``` + +| Parameter | Description | +|-----------|-------------| +| data | (Union[str]) Accepts a string. | +| caption | (str) The label for the text. Used to mark the data in the experiment dashboard. | + +## Introduction + +Convert text data to be recorded by `swanlab.log()`. + +### Logging String Text + +Logging a single string text: + +```python{4} +import swanlab + +swanlab.init() +text = swanlab.Text("an awesome text.") +swanlab.log({"examples": text}) +``` + +Logging multiple string texts: + +```python +import swanlab + +swanlab.init() + +examples = [] +for i in range(3): + text = swanlab.Text("an awesome text.") + examples.append(text) + +swanlab.log({"examples": examples}) +``` \ No newline at end of file diff --git a/en/api/py-converter.md b/en/api/py-converter.md new file mode 100644 index 0000000..4e0bd26 --- /dev/null +++ b/en/api/py-converter.md @@ -0,0 +1,6 @@ +# swanlab.converter + +Convert the content of other log tools to the API of the SwanLab project. + +- [swanlab.converter.TFBConverter](/en/guide_cloud/integration/integration-tensorboard#方式二-代码内转换) +- [swanlab.converter.WandbConverter](/en/guide_cloud/integration/integration-wandb#方式二-代码内转换) diff --git a/en/api/py-init.md b/en/api/py-init.md new file mode 100644 index 0000000..100da8b --- /dev/null +++ b/en/api/py-init.md @@ -0,0 +1,108 @@ +# swanlab.init + +```python +init( + project: str = None, + workspace: str = None, + experiment_name: str = None, + description: str = None, + config: Union[dict, str] = None, + logdir: str = None, + suffix: str = "default", + mode: str = "cloud", + load: str = None, + public: bool = None, + **kwargs, +) +``` + +| Parameter | Description | +|---------------|-------------| +| project | (str) Project name. If not specified, the name of the running directory is used. | +| workspace | (str) Workspace. By default, the experiment is synchronized to your personal space. If you want to upload to an organization, fill in the organization's username. | +| experiment_name | (str) Experiment name. If not specified, it defaults to "exp". The full experiment name is composed of `experiment_name + "_" + suffix`. | +| description | (str) Experiment description. If not specified, it defaults to None. | +| config | (dict, str) Experiment configuration. You can record some hyperparameters and other information here. Supports passing in configuration file paths, supports yaml and json files. | +| logdir | (str) Log file storage path. Defaults to `swanlog`. | +| suffix | (str, None, bool) Suffix for `experiment_name`. The full experiment name is composed of `experiment_name` and `suffix`.
The default value is "default", which means the default suffix rule is `'%b%d-%h-%m-%s'`, for example: `Feb03_14-45-37`.
Setting it to `None` or `False` will not add a suffix. | +| mode | (str) Sets the mode for creating the SwanLab experiment. Options include "cloud", "local", "disabled". Defaults to "cloud".
`cloud`: Uploads the experiment to the cloud.
`local`: Does not upload to the cloud but records the experiment locally.
`disabled`: Does not upload or record. | +| load | (str) Path to the configuration file to load. Supports yaml and json files. | +| public | (bool) Sets the visibility of the SwanLab project created directly by code. Defaults to False, i.e., private. | + +## Introduction + +- In the machine learning training process, we can add `swandb.init()` at the beginning of the training and testing scripts. SwanLab will track each step of the machine learning process. + +- `swanlab.init()` generates a new background process to record data into the experiment. By default, it also synchronizes the data to swanlab.pro so that you can see the visualization results online in real-time. + +- Before using `swanlab.log()` to record data, you need to call `swanlab.init()`: + +```python +import swanlab + +swanlab.init() +swanlab.log({"loss": 0.1846}) +``` + +- Calling `swanlab.init()` returns an object of type `SwanLabRun`, which can also perform `log` operations: + +```python +import swanlab + +run = swanlab.init() +run.log({"loss": 0.1846}) +``` + +- At the end of the script, we will automatically call `swanlab.finish` to end the SwanLab experiment. However, if `swanlab.init()` is called from a subprocess, such as in a Jupyter notebook, you must explicitly call `swanlab.finish` at the end of the subprocess. + +```python +import swanlab + +swanlab.init() +swanlab.finish() +``` + +## More Usage + +### Setting Project, Experiment Name, and Description + +```python +swanlab.init( + project="cats-detection", + experiment_name="YoloX-baseline", + description="Baseline experiment for the YoloX detection model, mainly used for subsequent comparisons.", +) +``` + +### Setting the Log File Save Location + +The following code demonstrates how to save log files to a custom directory: + +```python +swanlab.init( + logdir="path/to/my_custom_dir" +) +``` + +### Adding Experiment-related Metadata to the Experiment Configuration + +```python +swanlab.init( + config={ + "learning-rate": 1e-4, + "model": "CNN", + } +) +``` + +### Uploading to an Organization + +```python +swanlab.init( + workspace="[organization's username]" +) +``` + +## Deprecated Parameters + +- `cloud`: Replaced by the `mode` parameter in v0.3.4. The parameter is still available but will override the `mode` setting. \ No newline at end of file diff --git a/en/api/py-integration.md b/en/api/py-integration.md new file mode 100644 index 0000000..97c3fa3 --- /dev/null +++ b/en/api/py-integration.md @@ -0,0 +1,15 @@ +# swanlab.integration + +API for integrating SwanLab with external projects. + +- [swanlab.integration.pytorch_lightning](/en/guide_cloud/integration/integration-pytorch-lightning.md) +- [swanlab.integration.huggingface](/en/guide_cloud/integration/integration-huggingface-transformers.md) +- [swanlab.integration.accelerate](/en/guide_cloud/integration/integration-huggingface-accelerate.md) +- [swanlab.integration.ultralytics](/en/guide_cloud/integration/integration-ultralytics.md) +- [swanlab.integration.fastai](/en/guide_cloud/integration/integration-fastai.md) +- [swanlab.integration.openai](/en/guide_cloud/integration/integration-openai.md) +- [swanlab.integration.zhipuai](/en/guide_cloud/integration/integration-zhipuai.md) +- [swanlab.integration.sb3](/en/guide_cloud/integration/integration-sb3.md) +- [swanlab.integration.keras](/en/guide_cloud/integration/integration-keras.md) +- [swanlab.integration.mmengine](/en/guide_cloud/integration/integration-mmengine.md) +- [swanlab.integration.torchtune](/en/guide_cloud/integration/integration-pytorch-torchtune.md) diff --git a/en/api/py-log.md b/en/api/py-log.md new file mode 100644 index 0000000..68083a8 --- /dev/null +++ b/en/api/py-log.md @@ -0,0 +1,33 @@ +# log + +[Github Source Code](https://github.com/SwanHubX/SwanLab/blob/main/swanlab/data/sdk.py) + +```python +log( + data: Dict[str, DataType], + step: int = None, +) +``` + +| Parameter | Description | +|-----------|-------------| +| data | (Dict[str, DataType]) Required. Pass in a dictionary of key-value pairs, where the key is the metric name and the value is the metric value. The value supports int, float, types that can be converted by float(), or any `BaseType` type. | +| step | (int) Optional. This parameter sets the step number for the data. If step is not set, it will start from 0 and increment by 1 for each subsequent step. | + +## Introduction + +`swanlab.log` is the core API for metric logging. Use it to record data in experiments, such as scalars, images, audio, and text. + +The most basic usage is as shown in the following code, which will record the accuracy and loss values into the experiment, generate visual charts, and update the summary values of these metrics: + +```python +swanlab.log({"acc": 0.9, "loss":0.1462}) +``` + +In addition to scalars, `swanlab.log` supports logging multimedia data, including images, audio, text, etc., and has a good display effect in the UI. + +## More Usage + +- Logging [Images](/en/api/py-Image.md) +- Logging [Audio](/en/api/py-Audio.md) +- Logging [Text](/en/api/py-Text.md) \ No newline at end of file diff --git a/en/api/py-login.md b/en/api/py-login.md new file mode 100644 index 0000000..6a985be --- /dev/null +++ b/en/api/py-login.md @@ -0,0 +1,24 @@ +# swanlab.login + +``` bash +login( + api_key: str + ): +``` + +| Parameter | Description | +| --- | --- | +| `api_key` | If already logged in, force a re-login. | + +## Introduction + +Log in to your SwanLab account to synchronize experiments to the cloud. [API_KEY Retrieval Address](#) + +```python +import swanlab + +swanlab.login(api_key='your-api-key') + +``` + +After logging in once, the credentials are saved locally, so you do not need to log in again via `swanlab.login` or `swanlab login`. \ No newline at end of file diff --git a/en/examples/audio_classification.md b/en/examples/audio_classification.md new file mode 100644 index 0000000..96d30ff --- /dev/null +++ b/en/examples/audio_classification.md @@ -0,0 +1,364 @@ +# Audio Classification + +:::info +Introduction to Audio Classification and Audio Processing +::: + +Audio classification tasks involve categorizing audio signals based on their content. For example, distinguishing whether an audio clip is music, speech, environmental sounds (like bird chirps, rain, or machine noises), or animal sounds. The goal is to efficiently organize, retrieve, and understand large amounts of audio data through automatic classification. + +![alt text](/assets/examples/audio_classification/example-audio-classification-1.png) + +In current audio classification applications, it is often used for audio annotation and recommendation. It is also a great task for getting started with audio model training. + +In this article, we will train a ResNet series model on the GTZAN dataset using the PyTorch framework, and use [SwanLab](https://swanlab.cn) to monitor the training process and evaluate the model's performance. + +* Github: [https://github.com/Zeyi-Lin/PyTorch-Audio-Classification](https://github.com/Zeyi-Lin/PyTorch-Audio-Classification) +* Dataset: [https://pan.baidu.com/s/14CTI_9MD1vXCqyVxmAbeMw?pwd=1a9e](https://pan.baidu.com/s/14CTI_9MD1vXCqyVxmAbeMw?pwd=1a9e) Extraction Code: 1a9e +* SwanLab Experiment Logs: [https://swanlab.cn/@ZeyiLin/PyTorch\_Audio\_Classification-simple/charts](https://swanlab.cn/@ZeyiLin/PyTorch\_Audio\_Classification-simple/charts) +* More Experiment Logs: [https://swanlab.cn/@ZeyiLin/PyTorch\_Audio\_Classification/charts](https://swanlab.cn/@ZeyiLin/PyTorch\_Audio\_Classification/charts) + +## 1. Audio Classification Logic + +The logic for this tutorial's audio classification task is as follows: + +1. Load the audio dataset, which consists of audio WAV files and corresponding labels. +2. Split the dataset into training and testing sets in an 8:2 ratio. +3. Use the `torchaudio` library to convert audio files into Mel spectrograms, essentially transforming it into an image classification task. +4. Train the ResNet model on the Mel spectrograms. +5. Use SwanLab to record the loss and accuracy changes during the training and testing phases, and compare the effects of different experiments. + +## 2. Environment Setup + +This example is based on **Python>=3.8**. Please ensure Python is installed on your computer. + +We need to install the following Python libraries: + +```python +torch +torchvision +torchaudio +swanlab +pandas +scikit-learn +``` + +One-click installation command: + +```shellscript +pip install torch torchvision torchaudio swanlab pandas scikit-learn +``` + +## 3. GTZAN Dataset Preparation + +The dataset used in this task is GTZAN, a commonly used public dataset in music genre recognition research. The GTZAN dataset contains 1000 audio clips, each 30 seconds long, divided into 10 music genres: Blues, Classical, Country, Disco, Hip Hop, Jazz, Metal, Pop, Reggae, and Rock, with 100 clips per genre. + +![alt text](/assets/examples/audio_classification/example-audio-classification-2.png) + +The GTZAN dataset was collected from various sources between 2000-2001, including personal CDs, radio, and microphone recordings, representing sounds under various recording conditions. + +**Dataset Download Method (1.4GB in size):** + +1. Baidu Netdisk Download: Link: [https://pan.baidu.com/s/14CTI_9MD1vXCqyVxmAbeMw?pwd=1a9e](https://pan.baidu.com/s/14CTI_9MD1vXCqyVxmAbeMw?pwd=1a9e) Extraction Code: 1a9e +2. Download via Kaggle: [https://www.kaggle.com/datasets/andradaolteanu/gtzan-dataset-music-genre-classification](https://www.kaggle.com/datasets/andradaolteanu/gtzan-dataset-music-genre-classification) +3. Download via Hyper AI website using BT seed: [https://hyper.ai/cn/datasets/32001](https://hyper.ai/cn/datasets/32001) + +> Note: There is one corrupted audio in the dataset, which has been removed in the Baidu Netdisk version. + +After downloading, unzip it to the project root directory. + +## 4. Generate Dataset CSV File + +We will process the audio file paths and corresponding labels in the dataset into an `audio_dataset.csv` file, where the first column is the file path and the second column is the label: + +(This part is not executed first, it will be included in the complete code) + +```python +import os +import pandas as pd + +def create_dataset_csv(): + # Dataset root directory + data_dir = './GTZAN/genres_original' + data = [] + + # Traverse all subdirectories + for label in os.listdir(data_dir): + label_dir = os.path.join(data_dir, label) + if os.path.isdir(label_dir): + # Traverse all wav files in the subdirectory + for audio_file in os.listdir(label_dir): + if audio_file.endswith('.wav'): + audio_path = os.path.join(label_dir, audio_file) + data.append([audio_path, label]) + + # Create DataFrame and save as CSV + df = pd.DataFrame(data, columns=['path', 'label']) + df.to_csv('audio_dataset.csv', index=False) + return df + +# Generate or load dataset CSV file +if not os.path.exists('audio_dataset.csv'): + df = create_dataset_csv() +else: + df = pd.read_csv('audio_dataset.csv') +``` + +After processing, you will see an `audio_dataset.csv` file in the root directory: + +![alt text](/assets/examples/audio_classification/example-audio-classification-3.png) + +## 5. Configure Training Tracking Tool SwanLab + +SwanLab is an open-source, lightweight AI experiment tracking tool that provides a platform for tracking, comparing, and collaborating on experiments. SwanLab offers friendly APIs and a beautiful interface, combining hyperparameter tracking, metric recording, online collaboration, experiment link sharing, and more, allowing you to quickly track AI experiments, visualize processes, record hyperparameters, and share them with your peers. + +![alt text](/assets/examples/audio_classification/example-audio-classification-4.png) + +Configuring SwanLab is simple: + +1. Register an account: [https://swanlab.cn](https://swanlab.cn) +2. After installing swanlab (pip install swanlab), log in: + +```bash +swanlab login +``` + +When prompted to enter the API Key, go to the [settings page](https://swanlab.cn/settings/overview), copy the API Key, paste it, and press Enter. + +![alt text](/assets/examples/audio_classification/example-audio-classification-5.png) + +## 6. Complete Code + +Directory structure before starting training: + +``` +|--- train.py +|--- GTZAN +``` + +`train.py` does the following: + +1. Generate the dataset CSV file. +2. Load the dataset and ResNet18 model (pre-trained on ImageNet). +3. Train for 20 epochs, with training and evaluation for each epoch. +4. Record loss and accuracy, as well as the learning rate changes, and visualize them in SwanLab. + +`train.py`: + +```python +import torch +import torch.nn as nn +import torch.optim as optim +import torchaudio +import torchvision.models as models +from torch.utils.data import Dataset, DataLoader +import os +import pandas as pd +from sklearn.model_selection import train_test_split +import swanlab + +def create_dataset_csv(): + # Dataset root directory + data_dir = './GTZAN/genres_original' + data = [] + + # Traverse all subdirectories + for label in os.listdir(data_dir): + label_dir = os.path.join(data_dir, label) + if os.path.isdir(label_dir): + # Traverse all wav files in the subdirectory + for audio_file in os.listdir(label_dir): + if audio_file.endswith('.wav'): + audio_path = os.path.join(label_dir, audio_file) + data.append([audio_path, label]) + + # Create DataFrame and save as CSV + df = pd.DataFrame(data, columns=['path', 'label']) + df.to_csv('audio_dataset.csv', index=False) + return df + +# Custom dataset class +class AudioDataset(Dataset): + def __init__(self, df, resize, train_mode=True): + self.audio_paths = df['path'].values + # Convert labels to numerical values + self.label_to_idx = {label: idx for idx, label in enumerate(df['label'].unique())} + self.labels = [self.label_to_idx[label] for label in df['label'].values] + self.resize = resize + self.train_mode = train_mode # Add training mode flag + def __len__(self): + return len(self.audio_paths) + + def __getitem__(self, idx): + # Load audio file + waveform, sample_rate = torchaudio.load(self.audio_paths[idx]) + + # Convert audio to Mel spectrogram + transform = torchaudio.transforms.MelSpectrogram( + sample_rate=sample_rate, + n_fft=2048, + hop_length=640, + n_mels=128 + ) + mel_spectrogram = transform(waveform) + + # Ensure values are within a reasonable range + mel_spectrogram = torch.clamp(mel_spectrogram, min=0) + + # Convert to 3-channel image format (to fit ResNet) + mel_spectrogram = mel_spectrogram.repeat(3, 1, 1) + + # Ensure consistent size + resize = torch.nn.AdaptiveAvgPool2d((self.resize, self.resize)) + mel_spectrogram = resize(mel_spectrogram) + + return mel_spectrogram, self.labels[idx] + +# Modify ResNet model +class AudioClassifier(nn.Module): + def __init__(self, num_classes): + super(AudioClassifier, self).__init__() + # Load pre-trained ResNet + self.resnet = models.resnet18(weights=models.ResNet18_Weights.IMAGENET1K_V1) + # Modify the final fully connected layer + self.resnet.fc = nn.Linear(512, num_classes) + + def forward(self, x): + return self.resnet(x) + +# Training function +def train_model(model, train_loader, val_loader, criterion, optimizer, num_epochs, device): + + for epoch in range(num_epochs): + model.train() + running_loss = 0.0 + correct = 0 + total = 0 + + for i, (inputs, labels) in enumerate(train_loader): + inputs, labels = inputs.to(device), labels.to(device) + + outputs = model(inputs) + loss = criterion(outputs, labels) + + loss.backward() + + optimizer.step() + optimizer.zero_grad() + + running_loss += loss.item() + + _, predicted = outputs.max(1) + total += labels.size(0) + correct += predicted.eq(labels).sum().item() + + train_loss = running_loss/len(train_loader) + train_acc = 100.*correct/total + + # Validation phase + model.eval() + val_loss = 0.0 + correct = 0 + total = 0 + with torch.no_grad(): + for inputs, labels in val_loader: + inputs, labels = inputs.to(device), labels.to(device) + outputs = model(inputs) + loss = criterion(outputs, labels) + + val_loss += loss.item() + _, predicted = outputs.max(1) + total += labels.size(0) + correct += predicted.eq(labels).sum().item() + + val_loss = val_loss/len(val_loader) + val_acc = 100.*correct/total + + current_lr = optimizer.param_groups[0]['lr'] + + # Record training and validation metrics + swanlab.log({ + "train/loss": train_loss, + "train/acc": train_acc, + "val/loss": val_loss, + "val/acc": val_acc, + "train/epoch": epoch, + "train/lr": current_lr + }) + + print(f'Epoch {epoch+1}:') + print(f'Train Loss: {train_loss:.4f} | Train Acc: {train_acc:.2f}%') + print(f'Val Loss: {val_loss:.4f} | Val Acc: {val_acc:.2f}%') + print(f'Learning Rate: {current_lr:.6f}') + +# Main function +def main(): + # Set device + device = torch.device("cuda" if torch.cuda.is_available() else "cpu") + + run = swanlab.init( + project="PyTorch_Audio_Classification-simple", + experiment_name="resnet18", + config={ + "batch_size": 16, + "learning_rate": 1e-4, + "num_epochs": 20, + "resize": 224, + }, + ) + + # Generate or load dataset CSV file + if not os.path.exists('audio_dataset.csv'): + df = create_dataset_csv() + else: + df = pd.read_csv('audio_dataset.csv') + + # Split training and validation sets + train_df = pd.DataFrame() + val_df = pd.DataFrame() + + for label in df['label'].unique(): + label_df = df[df['label'] == label] + label_train, label_val = train_test_split(label_df, test_size=0.2, random_state=42) + train_df = pd.concat([train_df, label_train]) + val_df = pd.concat([val_df, label_val]) + + # Create dataset and data loader + train_dataset = AudioDataset(train_df, resize=run.config.resize, train_mode=True) + val_dataset = AudioDataset(val_df, resize=run.config.resize, train_mode=False) + + train_loader = DataLoader(train_dataset, batch_size=run.config.batch_size, shuffle=True) + val_loader = DataLoader(val_dataset, batch_size=1, shuffle=False) + + # Create model + num_classes = len(df['label'].unique()) # Set based on actual classification number + print("num_classes", num_classes) + model = AudioClassifier(num_classes).to(device) + + # Define loss function and optimizer + criterion = nn.CrossEntropyLoss() + optimizer = optim.Adam(model.parameters(), lr=run.config.learning_rate) + + # Train model + train_model(model, train_loader, val_loader, criterion, optimizer, num_epochs=run.config.num_epochs, device=device) + +if __name__ == "__main__": + main() +``` + +If you see the following output, training has started: + +![alt text](/assets/examples/audio_classification/example-audio-classification-6.png) + +Visit the printed SwanLab link to see the entire training process: + +![alt text](/assets/examples/audio_classification/example-audio-classification-7.png) + +You can see that the ResNet18 model, without any strategies, achieves 99.5% accuracy on the training set and a maximum of 71.5% accuracy on the validation set. The validation loss starts to rise after the 3rd epoch, showing a trend of "overfitting." + +## 7. Advanced Code + +Below is the experiment where I achieved 87.5% validation accuracy. The specific strategies include: + +1. Switching the model to resnext101_32x8d. +2. Increasing the Mel spectrogram resize to 512. +3 \ No newline at end of file diff --git a/en/examples/bert.md b/en/examples/bert.md new file mode 100644 index 0000000..89c1dcc --- /dev/null +++ b/en/examples/bert.md @@ -0,0 +1,150 @@ +# BERT Text Classification + +:::info +Introduction to Natural Language Processing, Text Classification, and Machine Learning +::: + +[Online Demo](https://swanlab.cn/@ZeyiLin/BERT/charts) | [Zhihu](https://zhuanlan.zhihu.com/p/699441531) | [Meituan Waimai Review Classification](https://zhuanlan.zhihu.com/p/701460910) + +## Overview + +**BERT** (Bidirectional Encoder Representations from Transformers) is a pre-trained natural language processing model proposed by Google, widely used in various natural language processing tasks. BERT captures contextual relationships between words by pre-training on large-scale corpora, achieving excellent results in many tasks. + +In this task, we will use the BERT model to classify IMDB movie reviews into "positive" or "negative" sentiments. + +![IMDB](/assets/example-bert-1.png) + +The **IMDB movie review dataset** contains 50,000 movie reviews, divided into 25,000 training and 25,000 test data, each with 50% positive and 50% negative reviews. We will use the pre-trained BERT model to fine-tune these reviews for sentiment classification. + +## Environment Setup + +This example is based on `Python>=3.8`. Please ensure Python is installed on your computer. Environment dependencies: + +```txt +transformers +datasets +swanlab +``` + +Quick installation command: + +```bash +pip install transformers datasets swanlab +``` + +> The code in this article is tested with transformers==4.41.0, datasets==2.19.1, swanlab==0.3.3 + +## Complete Code + +```python +""" +Fine-tune a pre-trained BERT model on the IMDB dataset and use the SwanLabCallback callback function to upload the results to SwanLab. +The IMDB dataset labels 1 as positive and 0 as negative. +""" + +import torch +from datasets import load_dataset +from transformers import AutoTokenizer, AutoModelForSequenceClassification, Trainer, TrainingArguments +from swanlab.integration.huggingface import SwanLabCallback +import swanlab + +def predict(text, model, tokenizer, CLASS_NAME): + inputs = tokenizer(text, return_tensors="pt") + + with torch.no_grad(): + outputs = model(**inputs) + logits = outputs.logits + predicted_class = torch.argmax(logits).item() + + print(f"Input Text: {text}") + print(f"Predicted class: {int(predicted_class)} {CLASS_NAME[int(predicted_class)]}") + return int(predicted_class) + +# Load the IMDB dataset +dataset = load_dataset('imdb') + +# Load the pre-trained BERT tokenizer +tokenizer = AutoTokenizer.from_pretrained('bert-base-uncased') + +# Define the tokenize function +def tokenize(batch): + return tokenizer(batch['text'], padding=True, truncation=True) + +# Tokenize the dataset +tokenized_datasets = dataset.map(tokenize, batched=True) + +# Set the model input format +tokenized_datasets = tokenized_datasets.rename_column("label", "labels") +tokenized_datasets.set_format('torch', columns=['input_ids', 'attention_mask', 'labels']) + +# Load the pre-trained BERT model +model = AutoModelForSequenceClassification.from_pretrained('bert-base-uncased', num_labels=2) + +# Set training arguments +training_args = TrainingArguments( + output_dir='./results', + eval_strategy='epoch', + save_strategy='epoch', + learning_rate=2e-5, + per_device_train_batch_size=8, + per_device_eval_batch_size=8, + logging_first_step=100, + # Total number of training epochs + num_train_epochs=3, + weight_decay=0.01, + report_to="none", + # Single GPU training +) + +CLASS_NAME = {0: "negative", 1: "positive"} + +# Set the swanlab callback function +swanlab_callback = SwanLabCallback(project='BERT', + experiment_name='BERT-IMDB', + config={'dataset': 'IMDB', "CLASS_NAME": CLASS_NAME}) + +# Define the Trainer +trainer = Trainer( + model=model, + args=training_args, + train_dataset=tokenized_datasets['train'], + eval_dataset=tokenized_datasets['test'], + callbacks=[swanlab_callback], +) + +# Train the model +trainer.train() + +# Save the model +model.save_pretrained('./sentiment_model') +tokenizer.save_pretrained('./sentiment_model') + +# Test the model +test_reviews = [ + "I absolutely loved this movie! The storyline was captivating and the acting was top-notch. A must-watch for everyone.", + "This movie was a complete waste of time. The plot was predictable and the characters were poorly developed.", + "An excellent film with a heartwarming story. The performances were outstanding, especially the lead actor.", + "I found the movie to be quite boring. It dragged on and didn't really go anywhere. Not recommended.", + "A masterpiece! The director did an amazing job bringing this story to life. The visuals were stunning.", + "Terrible movie. The script was awful and the acting was even worse. I can't believe I sat through the whole thing.", + "A delightful film with a perfect mix of humor and drama. The cast was great and the dialogue was witty.", + "I was very disappointed with this movie. It had so much potential, but it just fell flat. The ending was particularly bad.", + "One of the best movies I've seen this year. The story was original and the performances were incredibly moving.", + "I didn't enjoy this movie at all. It was confusing and the pacing was off. Definitely not worth watching." +] + +model.to('cpu') +text_list = [] +for review in test_reviews: + label = predict(review, model, tokenizer, CLASS_NAME) + text_list.append(swanlab.Text(review, caption=f"{label}-{CLASS_NAME[label]}")) + +if text_list: + swanlab.log({"predict": text_list}) + +swanlab.finish() +``` + +## Demonstration Effect + +![](/assets/example-bert-2.png) \ No newline at end of file diff --git a/en/examples/cats_dogs_classification.md b/en/examples/cats_dogs_classification.md new file mode 100644 index 0000000..b4e0631 --- /dev/null +++ b/en/examples/cats_dogs_classification.md @@ -0,0 +1,7 @@ +# Cat and Dog Classification + +:::info +Introduction to Image Classification, Machine Learning, RGB Images, and Custom Datasets +::: + +For detailed tutorials, refer to: https://zhuanlan.zhihu.com/p/676430630 \ No newline at end of file diff --git a/en/examples/fashionmnist.md b/en/examples/fashionmnist.md new file mode 100644 index 0000000..9d36e12 --- /dev/null +++ b/en/examples/fashionmnist.md @@ -0,0 +1,270 @@ +# FashionMNIST + +:::info +Image Classification, Machine Learning Introduction, Grayscale Images +::: + +## Overview + +FashionMNIST is a widely used image dataset for testing machine learning algorithms, particularly in the field of image recognition. It was released by Zalando and is designed to replace the traditional MNIST dataset, which primarily contains images of handwritten digits. The purpose of FashionMNIST is to provide a slightly more challenging problem while maintaining the same image size (28x28 pixels) and structure (60,000 images for the training set and 10,000 images for the test set) as the original MNIST dataset. + +![fashion-mnist](/assets/example-fashionmnist.png) + +FashionMNIST contains grayscale images of clothing and footwear items from 10 categories. These categories include: + +1. T-shirt/top +2. Trouser +3. Pullover +4. Dress +5. Coat +6. Sandal +7. Shirt +8. Sneaker +9. Bag +10. Ankle boot + +Each category has an equal number of images, making this dataset a balanced dataset. The simplicity and standardized size of these images make FashionMNIST an ideal choice for entry-level tasks in computer vision and machine learning. The dataset is widely used for education and research to test the effectiveness of various image recognition methods. + +This case study primarily focuses on: + +- Using `pytorch` to build, train, and evaluate a [ResNet34](https://arxiv.org/abs/1512.03385) (Residual Neural Network) model. +- Using `swanlab` to track hyperparameters, record metrics, and visualize monitoring throughout the training cycle. + +## Environment Setup + +This case study is based on `Python>=3.8`. Please ensure Python is installed on your computer. +Environment dependencies: +``` +torch +torchvision +swanlab +``` +Quick installation command: +```bash +pip install torch torchvision swanlab +``` + +## Complete Code + +```python +import os +import torch +from torch import nn, optim, utils +import torch.nn.functional as F +from torchvision.datasets import FashionMNIST +from torchvision.transforms import ToTensor + +import swanlab + +# ResNet network construction +class Basicblock(nn.Module): + def __init__(self, in_planes, planes, stride=1): + super(Basicblock, self).__init__() + self.conv1 = nn.Sequential( + nn.Conv2d(in_channels=in_planes, out_channels=planes, kernel_size=3, stride=stride, padding=1, bias=False), + nn.BatchNorm2d(planes), + nn.ReLU() + ) + self.conv2 = nn.Sequential( + nn.Conv2d(in_channels=planes, out_channels=planes, kernel_size=3, stride=1, padding=1, bias=False), + nn.BatchNorm2d(planes), + ) + + if stride != 1 or in_planes != planes: + self.shortcut = nn.Sequential( + nn.Conv2d(in_channels=in_planes, out_channels=planes, kernel_size=3, stride=stride, padding=1), + nn.BatchNorm2d(planes) + ) + else: + self.shortcut = nn.Sequential() + + def forward(self, x): + out = self.conv1(x) + out = self.conv2(out) + out += self.shortcut(x) + out = F.relu(out) + return out + + +class ResNet(nn.Module): + def __init__(self, block, num_block, num_classes): + super(ResNet, self).__init__() + self.in_planes = 16 + self.conv1 = nn.Sequential( + nn.Conv2d(in_channels=1, out_channels=16, kernel_size=3, stride=1, padding=1), + nn.BatchNorm2d(16), + nn.ReLU() + ) + self.maxpool = nn.MaxPool2d(kernel_size=3, stride=1, padding=1) + + self.block1 = self._make_layer(block, 16, num_block[0], stride=1) + self.block2 = self._make_layer(block, 32, num_block[1], stride=2) + self.block3 = self._make_layer(block, 64, num_block[2], stride=2) + # self.block4 = self._make_layer(block, 512, num_block[3], stride=2) + + self.outlayer = nn.Linear(64, num_classes) + + def _make_layer(self, block, planes, num_block, stride): + layers = [] + for i in range(num_block): + if i == 0: + layers.append(block(self.in_planes, planes, stride)) + else: + layers.append(block(planes, planes, 1)) + self.in_planes = planes + return nn.Sequential(*layers) + + def forward(self, x): + x = self.maxpool(self.conv1(x)) + x = self.block1(x) # [200, 64, 28, 28] + x = self.block2(x) # [200, 128, 14, 14] + x = self.block3(x) # [200, 256, 7, 7] + # out = self.block4(out) + x = F.avg_pool2d(x, 7) # [200, 256, 1, 1] + x = x.view(x.size(0), -1) # [200,256] + out = self.outlayer(x) + return out + + +# Capture and visualize the first 20 images +def log_images(loader, num_images=16): + images_logged = 0 + logged_images = [] + for images, labels in loader: + # images: batch of images, labels: batch of labels + for i in range(images.shape[0]): + if images_logged < num_images: + # Use swanlab.Image to convert images to wandb visualization format + logged_images.append(swanlab.Image(images[i], caption=f"Label: {labels[i]}", size=(128, 128))) + images_logged += 1 + else: + break + if images_logged >= num_images: + break + swanlab.log({"Preview/MNIST": logged_images}) + + +if __name__ == "__main__": + # Set device + try: + use_mps = torch.backends.mps.is_available() + except AttributeError: + use_mps = False + + if torch.cuda.is_available(): + device = "cuda" + elif use_mps: + device = "mps" + else: + device = "cpu" + + # Initialize swanlab + run = swanlab.init( + project="FashionMNIST", + experiment_name="Resnet34-Adam", + config={ + "model": "Resnet34", + "optim": "Adam", + "lr": 0.001, + "batch_size": 32, + "num_epochs": 10, + "train_dataset_num": 55000, + "val_dataset_num": 5000, + "device": device, + "num_classes": 10, + }, + ) + + # Set up training, validation, and test sets + dataset = FashionMNIST(os.getcwd(), train=True, download=True, transform=ToTensor()) + train_dataset, val_dataset = utils.data.random_split( + dataset, [run.config.train_dataset_num, run.config.val_dataset_num] + ) + + train_loader = utils.data.DataLoader(train_dataset, batch_size=run.config.batch_size, shuffle=True) + val_loader = utils.data.DataLoader(val_dataset, batch_size=1, shuffle=False) + + # Initialize model, loss function, and optimizer + if run.config.model == "Resnet18": + model = ResNet(Basicblock, [1, 1, 1, 1], 10) + elif run.config.model == "Resnet34": + model = ResNet(Basicblock, [2, 3, 5, 2], 10) + elif run.config.model == "Resnet50": + model = ResNet(Basicblock, [3, 4, 6, 3], 10) + elif run.config.model == "Resnet101": + model = ResNet(Basicblock, [3, 4, 23, 3], 10) + elif run.config.model == "Resnet152": + model = ResNet(Basicblock, [3, 8, 36, 3], 10) + + model.to(torch.device(device)) + + criterion = nn.CrossEntropyLoss() + optimizer = optim.Adam(model.parameters(), lr=run.config.lr) + + # (Optional) Take a look at the first 16 images in the dataset + log_images(train_loader, 16) + + # Start training + for epoch in range(1, run.config.num_epochs+1): + swanlab.log({"train/epoch": epoch}, step=epoch) + # Training loop + for iter, batch in enumerate(train_loader): + x, y = batch + x, y = x.to(device), y.to(device) + optimizer.zero_grad() + output = model(x) + loss = criterion(output, y) + loss.backward() + optimizer.step() + + if iter % 40 == 0: + print( + f"Epoch [{epoch}/{run.config.num_epochs}], Iteration [{iter + 1}/{len(train_loader)}], Loss: {loss.item()}" + ) + swanlab.log({"train/loss": loss.item()}, step=(epoch - 1) * len(train_loader) + iter) + + # Validate every 4 epochs + if epoch % 2 == 0: + model.eval() + correct = 0 + total = 0 + with torch.no_grad(): + for batch in val_loader: + x, y = batch + x, y = x.to(device), y.to(device) + output = model(x) + _, predicted = torch.max(output, 1) + total += y.size(0) + correct += (predicted == y).sum().item() + + accuracy = correct / total + swanlab.log({"val/accuracy": accuracy}, step=epoch) +``` + +## Switching to Other ResNet Models + +The above code supports switching to the following ResNet models: +- ResNet18 +- ResNet34 +- ResNet50 +- ResNet101 +- ResNet152 + +Switching is very simple; just modify the `model` parameter in the `config` to the corresponding model name. For example, to switch to ResNet50: + +```python (5) + # Initialize swanlab + run = swanlab.init( + ... + config={ + "model": "Resnet50", + ... + }, + ) +``` + +- How does `config` work? 👉 [Set Experiment Configuration](/zh/guide_cloud/experiment_track/set-experiment-config) + +## Demonstration of Results + +![](/assets/example-fashionmnist-show.jpg) \ No newline at end of file diff --git a/en/examples/hello_world.md b/en/examples/hello_world.md new file mode 100644 index 0000000..1d8a9b9 --- /dev/null +++ b/en/examples/hello_world.md @@ -0,0 +1,35 @@ +# Hello World + +This is an introductory case, a minimal simulation of deep learning training. + +## Environment Setup + +```bash +pip install swanlab +``` + +## Complete Code + +```python +import swanlab +import random + +offset = random.random() / 5 + +# Initialize SwanLab +run = swanlab.init( + project="my-project", + config={ + "learning_rate": 0.01, + "epochs": 10, + }, +) + +# Simulate the training process +for epoch in range(2, run.config.epochs): + acc = 1 - 2**-epoch - random.random() / epoch - offset + loss = 2**-epoch + random.random() / epoch + offset + print(f"epoch={epoch}, accuracy={acc}, loss={loss}") + + swanlab.log({"accuracy": acc, "loss": loss}) # Record metrics +``` \ No newline at end of file diff --git a/en/examples/lstm_stock.md b/en/examples/lstm_stock.md new file mode 100644 index 0000000..ed5cbde --- /dev/null +++ b/en/examples/lstm_stock.md @@ -0,0 +1,274 @@ +# LSTM Stock Prediction + +:::info +Time Series, Quantitative Trading, Time Series Model +::: + +[Online Demo](https://swanlab.cn/@ZeyiLin/Google-Stock-Prediction/runs/0c2ci59aje4rb54r2z4y5/chart) | [Zhihu Tutorial](https://zhuanlan.zhihu.com/p/702114810) + +## Overview + +LSTM (Long Short-Term Memory), a special type of RNN (Recurrent Neural Network), improves the traditional RNN's issues of gradient vanishing and gradient explosion when handling long sequence data. Proposed by Hochreiter and Schmidhuber in 1997, LSTM has become one of the classic models for processing **time series data**. + +![](/assets/example-lstm-1.png) + +Stock prediction tasks involve predicting the current and future stock price changes based on past data of a stock using AI models. This is also a practical time series task. Here, we use the Google stock price dataset from 2016 to 2021 for training and inference. + +## Environment Setup + +This case study is based on `Python>=3.8`. Please ensure Python is installed on your computer. Environment dependencies: + +```txt +pandas +torch +matplotlib +swanlab +scikit-learn +``` + +Quick installation command: + +```bash +pip install pandas torch matplotlib swanlab scikit-learn +``` + +> This code is tested on torch==2.3.0, pandas==2.0.3, matplotlib==3.8.2, swanlab==0.3.8, scikit-learn==1.3.2 + +## Complete Code + +Please download the Google Stock Prediction dataset from [Kaggle](https://www.kaggle.com/datasets/shreenidhihipparagi/google-stock-prediction) to the root directory. + +```python +import os +import swanlab +import torch +import torch.nn as nn +import torch.optim as optim +from torch.utils.data import DataLoader +import matplotlib.pyplot as plt +from copy import deepcopy as dc +import numpy as np +import pandas as pd +from torch.utils.data import Dataset +from sklearn.preprocessing import MinMaxScaler + + +class LSTMModel(nn.Module): + """ + Define the model class + """ + def __init__(self, input_size=1, hidden_size1=50, hidden_size2=64, fc1_size=32, fc2_size=16, output_size=1): + super(LSTMModel, self).__init__() + self.lstm1 = nn.LSTM(input_size, hidden_size1, batch_first=True) + self.lstm2 = nn.LSTM(hidden_size1, hidden_size2, batch_first=True) + self.fc1 = nn.Linear(hidden_size2, fc1_size) + self.fc2 = nn.Linear(fc1_size, fc2_size) + self.fc3 = nn.Linear(fc2_size, output_size) + + def forward(self, x): + x, _ = self.lstm1(x) + x, _ = self.lstm2(x) + x = self.fc1(x[:, -1, :]) + x = self.fc2(x) + x = self.fc3(x) + return x + + +class TimeSeriesDataset(Dataset): + """ + Define the dataset class + """ + def __init__(self, X, y): + self.X = X + self.y = y + + def __len__(self): + return len(self.X) + + def __getitem__(self, i): + return self.X[i], self.y[i] + + +def prepare_dataframe_for_lstm(df, n_steps): + """ + Process the dataset to be suitable for LSTM model + """ + df = dc(df) + df['date'] = pd.to_datetime(df['date']) + df.set_index('date', inplace=True) + + for i in range(1, n_steps+1): + df[f'close(t-{i})'] = df['close'].shift(i) + + df.dropna(inplace=True) + return df + + +def get_dataset(file_path, lookback, split_ratio=0.9): + """ + Normalize data and split into training and test sets + """ + data = pd.read_csv(file_path) + data = data[['date','close']] + + shifted_df_as_np = prepare_dataframe_for_lstm(data, lookback) + + scaler = MinMaxScaler(feature_range=(-1,1)) + shifted_df_as_np = scaler.fit_transform(shifted_df_as_np) + + X = shifted_df_as_np[:, 1:] + y = shifted_df_as_np[:, 0] + + X = dc(np.flip(X,axis=1)) + + # Split into training and test sets + split_index = int(len(X) * split_ratio) + + X_train = X[:split_index] + X_test = X[split_index:] + + y_train = y[:split_index] + y_test = y[split_index:] + + X_train = X_train.reshape((-1, lookback, 1)) + X_test = X_test.reshape((-1, lookback, 1)) + + y_train = y_train.reshape((-1, 1)) + y_test = y_test.reshape((-1, 1)) + + # Convert to Tensor + X_train = torch.tensor(X_train).float() + y_train = torch.tensor(y_train).float() + X_test = torch.tensor(X_test).float() + y_test = torch.tensor(y_test).float() + + return scaler, X_train, X_test, y_train, y_test + + +def train(model, train_loader, optimizer, criterion): + model.train() + running_loss = 0 + # Training + for i, batch in enumerate(train_loader): + x_batch, y_batch = batch[0].to(device), batch[1].to(device) + y_pred = model(x_batch) + loss = criterion(y_pred, y_batch) + running_loss += loss.item() + optimizer.zero_grad() + loss.backward() + optimizer.step() + + avg_loss_epoch = running_loss / len(train_loader) + print(f'Epoch: {epoch}, Batch: {i}, Avg. Loss: {avg_loss_epoch}') + swanlab.log({"train/loss": running_loss}, step=epoch) + running_loss = 0 + + +def validate(model, test_loader, criterion, epoch): + model.eval() + val_loss = 0 + with torch.no_grad(): + for _, batch in enumerate(test_loader): + x_batch, y_batch = batch[0].to(device), batch[1].to(device) + y_pred = model(x_batch) + loss = criterion(y_pred, y_batch) + val_loss += loss.item() + avg_val_loss = val_loss / len(test_loader) + print(f'Epoch: {epoch}, Validation Loss: {avg_val_loss}') + swanlab.log({"val/loss": avg_val_loss}, step=epoch) + + +def inverse_transform_and_extract(scaler, data, lookback): + dummies = np.zeros((data.shape[0], lookback + 1)) + dummies[:, 0] = data.flatten() + return dc(scaler.inverse_transform(dummies)[:, 0]) + + +def plot_predictions(actual, predicted, title, xlabel='Date', ylabel='Close Price'): + """ + Plot the final stock price prediction versus the actual values + """ + plt.figure(figsize=(10, 6)) + plt.plot(actual, color='red', label='Actual Close Price') + plt.plot(predicted, color='blue', label='Predicted Close Price', alpha=0.5) + plt.xlabel(xlabel) + plt.ylabel(ylabel) + plt.title(title) + plt.legend() + return swanlab.Image(plt, caption=title) + + +def visualize_predictions(train_predictions, val_predictions, scaler, y_train, y_test, lookback): + train_predictions = inverse_transform_and_extract(scaler, train_predictions, lookback) + val_predictions = inverse_transform_and_extract(scaler, val_predictions, lookback) + new_y_train = inverse_transform_and_extract(scaler, y_train, lookback) + new_y_test = inverse_transform_and_extract(scaler, y_test, lookback) + + plt_image = [] + plt_image.append(plot_predictions(new_y_train, train_predictions, '(TrainSet) Google Stock Price Prediction with LSTM')) + plt_image.append(plot_predictions(new_y_test, val_predictions, '(TestSet) Google Stock Price Prediction with LSTM')) + + swanlab.log({"Prediction": plt_image}) + + +if __name__ == '__main__': + # ------------------- Initialize a SwanLab experiment ------------------- + swanlab.init( + project='Google-Stock-Prediction', + experiment_name="LSTM", + description="Predict the next day's stock price based on the previous 7 days' data", + config={ + "learning_rate": 1e-3, + "epochs": 100, + "batch_size": 32, + "lookback": 7, + "spilt_ratio": 0.9, + "save_path": "./checkpoint", + "optimizer": "Adam", + "device": 'cuda' if torch.cuda.is_available() else 'cpu', + }, + ) + + config = swanlab.config + device = torch.device(config.device) + + # ------------------- Define the dataset ------------------- + scaler, X_train, X_test, y_train, y_test = get_dataset(file_path='./GOOG.csv', + lookback=config.lookback, + split_ratio=config.spilt_ratio,) + + train_dataset = TimeSeriesDataset(X_train, y_train) + test_dataset = TimeSeriesDataset(X_test, y_test) + + train_loader = DataLoader(train_dataset, batch_size=config.batch_size, shuffle=True) + test_loader = DataLoader(test_dataset, batch_size=config.batch_size, shuffle=False) + + # ------------------- Define the model and hyperparameters ------------------- + model = LSTMModel(input_size=1, output_size=1) + + model = model.to(device) + optimizer = optim.Adam(model.parameters(), lr=config.learning_rate) + criterion = nn.MSELoss() + + # ------------------- Training and validation ------------------- + for epoch in range(1, config.epochs+1): + train(model, train_loader, optimizer, criterion) + validate(model, test_loader, criterion, epoch) + + # ------------------- Use the best model for inference and generate visualization results ------------------- + with torch.no_grad(): + model.eval() + train_predictions = model(X_train.to(device)).to('cpu').numpy() + val_predictions = model(X_test.to(device)).to('cpu').numpy() + visualize_predictions(train_predictions, val_predictions, scaler, y_train, y_test, config.lookback) + + # ------------------- Save the model ------------------- + model_save_path = os.path.join(config.save_path, 'lstm.pth') + if not os.path.exists(config.save_path): + os.makedirs(config.save_path) + torch.save(model.state_dict(), model_save_path) +``` + +## Demonstration of Results + +![](/assets/example-lstm-2.png) \ No newline at end of file diff --git a/en/examples/mnist.md b/en/examples/mnist.md new file mode 100644 index 0000000..1da9f71 --- /dev/null +++ b/en/examples/mnist.md @@ -0,0 +1,200 @@ +# MNIST Handwritten Digit Recognition + +:::info +Image Classification, Machine Learning Introduction, Grayscale Images +::: + +[Online Experiment Demo](https://swanlab.cn/@ZeyiLin/MNIST-example/runs/4plp6w0qehoqpt0uq2tcy/chart) + +[![Colab](/assets/colab.svg)](https://colab.research.google.com/drive/1Au8aXxU2o0QNWSzGXGsTdHggighXQMNu?usp=sharing) + +## Overview + +MNIST handwritten digit recognition is one of the most classic introductory tasks in deep learning, proposed by LeCun et al. +This task is based on the [MNIST dataset](https://paperswithcode.com/dataset/mnist), where researchers build machine learning models to recognize 10 handwritten digits (0-9). + +![mnist](/assets/mnist.jpg) + +This case study primarily focuses on: +- Using `pytorch` to build, train, and evaluate a CNN (Convolutional Neural Network). +- Using `swanlab` to track hyperparameters, record metrics, and visualize monitoring throughout the training cycle. + +## Environment Setup + +This case study is based on `Python>=3.8`. Please ensure Python is installed on your computer. +Environment dependencies: +``` +torch +torchvision +swanlab +``` +Quick installation command: +```bash +pip install torch torchvision swanlab +``` + +## Complete Code + +```python +import os +import torch +from torch import nn, optim, utils +import torch.nn.functional as F +import torchvision +from torchvision.datasets import MNIST +from torchvision.transforms import ToTensor +import swanlab + +# CNN network construction +class ConvNet(nn.Module): + def __init__(self): + super().__init__() + # 1,28x28 + self.conv1 = nn.Conv2d(1, 10, 5) # 10, 24x24 + self.conv2 = nn.Conv2d(10, 20, 3) # 128, 10x10 + self.fc1 = nn.Linear(20 * 10 * 10, 500) + self.fc2 = nn.Linear(500, 10) + + def forward(self, x): + in_size = x.size(0) + out = self.conv1(x) # 24 + out = F.relu(out) + out = F.max_pool2d(out, 2, 2) # 12 + out = self.conv2(out) # 10 + out = F.relu(out) + out = out.view(in_size, -1) + out = self.fc1(out) + out = F.relu(out) + out = self.fc2(out) + out = F.log_softmax(out, dim=1) + return out + + +# Capture and visualize the first 20 images +def log_images(loader, num_images=16): + images_logged = 0 + logged_images = [] + for images, labels in loader: + # images: batch of images, labels: batch of labels + for i in range(images.shape[0]): + if images_logged < num_images: + # Use swanlab.Image to convert images to wandb visualization format + logged_images.append(swanlab.Image(images[i], caption=f"Label: {labels[i]}")) + images_logged += 1 + else: + break + if images_logged >= num_images: + break + swanlab.log({"MNIST-Preview": logged_images}) + + +def train(model, device, train_dataloader, optimizer, criterion, epoch, num_epochs): + model.train() + # 1. Loop through train_dataloader, fetching images and labels in batches + for iter, (inputs, labels) in enumerate(train_dataloader): + inputs, labels = inputs.to(device), labels.to(device) + optimizer.zero_grad() + # 2. Pass inputs through the model to get predictions + outputs = model(inputs) + # 3. Calculate the cross-entropy loss between predictions and labels + loss = criterion(outputs, labels) + # 4. Compute the backward pass based on the loss + loss.backward() + # 5. Update model parameters using the optimizer + optimizer.step() + print('Epoch [{}/{}], Iteration [{}/{}], Loss: {:.4f}'.format(epoch, num_epochs, iter + 1, len(train_dataloader), + loss.item())) + # 6. Log the loss with SwanLab every 20 iterations + if iter % 20 == 0: + swanlab.log({"train/loss": loss.item()}) + +def test(model, device, val_dataloader, epoch): + model.eval() + correct = 0 + total = 0 + with torch.no_grad(): + # 1. Loop through val_dataloader, fetching images and labels in batches + for inputs, labels in val_dataloader: + inputs, labels = inputs.to(device), labels.to(device) + # 2. Pass inputs through the model to get predictions + outputs = model(inputs) + # 3. Get the predicted digits + _, predicted = torch.max(outputs, 1) + total += labels.size(0) + # 4. Calculate the number of correct predictions + correct += (predicted == labels).sum().item() + + # 5. Get the final test accuracy + accuracy = correct / total + # 6. Log the accuracy with SwanLab + swanlab.log({"val/accuracy": accuracy}, step=epoch) + + +if __name__ == "__main__": + + # Check if mps is supported + try: + use_mps = torch.backends.mps.is_available() + except AttributeError: + use_mps = False + + # Check if cuda is supported + if torch.cuda.is_available(): + device = "cuda" + elif use_mps: + device = "mps" + else: + device = "cpu" + + # Initialize swanlab + run = swanlab.init( + project="MNIST-example", + experiment_name="PlainCNN", + config={ + "model": "ResNet18", + "optim": "Adam", + "lr": 1e-4, + "batch_size": 256, + "num_epochs": 10, + "device": device, + }, + ) + + # Set up MNIST training and validation sets + dataset = MNIST(os.getcwd(), train=True, download=True, transform=ToTensor()) + train_dataset, val_dataset = utils.data.random_split(dataset, [55000, 5000]) + + train_dataloader = utils.data.DataLoader(train_dataset, batch_size=run.config.batch_size, shuffle=True) + val_dataloader = utils.data.DataLoader(val_dataset, batch_size=8, shuffle=False) + + # (Optional) Take a look at the first 16 images in the dataset + log_images(train_dataloader, 16) + + # Initialize the model + model = ConvNet() + model.to(torch.device(device)) + + # Print the model + print(model) + + # Define the loss function and optimizer + criterion = nn.CrossEntropyLoss() + optimizer = optim.Adam(model.parameters(), lr=run.config.lr) + + # Start training and testing loop + for epoch in range(1, run.config.num_epochs+1): + swanlab.log({"train/epoch": epoch}, step=epoch) + train(model, device, train_dataloader, optimizer, criterion, epoch, run.config.num_epochs) + if epoch % 2 == 0: + test(model, device, val_dataloader, epoch) + + # Save the model + # Automatically create a checkpoint folder if it doesn't exist + if not os.path.exists("checkpoint"): + os.makedirs("checkpoint") + torch.save(model.state_dict(), 'checkpoint/latest_checkpoint.pth') +``` + +## Demonstration of Results + +![mnist](/assets/example-mnist.jpg) \ No newline at end of file diff --git a/en/examples/pretrain_llm.md b/en/examples/pretrain_llm.md new file mode 100644 index 0000000..011e778 --- /dev/null +++ b/en/examples/pretrain_llm.md @@ -0,0 +1,397 @@ +# Pretraining Your Own Large Model from Scratch + +Large Language Models (LLMs) are deep learning models trained on vast amounts of text data to generate natural language text or understand language text meanings. + +![llm](/assets/examples/pretrain_llm/llm.png) + +While there are numerous tutorials online about transformer theory and fine-tuning large language models, few explain the pretraining process. This article provides a hands-on guide to pretraining a large language model from scratch using a Wikipedia dataset, along with instructions on how to use SwanLab Launch to leverage cloud GPUs for free. + +- Complete tutorial code: [GitHub](https://github.com/ShaohonChen/transformers_from_scratch) +- Experiment logs: [SwanLab](https://swanlab.cn/@ShaohonChen/WikiLLM/overview) +- Dataset download: [Baidu Netdisk (j8ee)](https://pan.baidu.com/s/1p5F52bRlnpSY7F78q0hz7A?pwd=j8ee), [Huggingface](https://huggingface.co/datasets/fjcanyue/wikipedia-zh-cn) + +## Environment Setup + +First, the project recommends using Python 3.10. The required Python packages are as follows: + +```txt +swanlab +transformers +datasets +accelerate +``` + +Install them with the following command: + +```bash +pip install swanlab transformers datasets accelerate modelscope +``` + +## Downloading the Dataset + +This tutorial uses a Chinese Wikipedia dataset. Ideally, the pretraining dataset should be as diverse and large as possible; additional datasets will be added later. + +![dataset](/assets/examples/pretrain_llm/dataset.png) + +Huggingface link: [wikipedia-zh-cn](https://huggingface.co/datasets/fjcanyue/wikipedia-zh-cn) + +Baidu Netdisk download link: [Baidu Netdisk (j8ee)](https://pan.baidu.com/s/1p5F52bRlnpSY7F78q0hz7A?pwd=j8ee) + +After downloading the `wikipedia-zh-cn-20240820.json` file, place it in the project directory under the `./WIKI_CN/` folder. + +The dataset file is approximately 1.99GB in size, containing 1.44 million entries. Although the dataset includes article titles, they are not used in the pretraining phase. Sample text from the dataset: + +```txt +Mathematics is the study of quantity, structure, and space, and their changes, and is a discipline of formal science. Mathematics uses abstraction and logical reasoning to develop concepts from counting, calculating, measuring, and observing the shapes and motions of objects. Mathematicians expand these concepts... +``` + +Load the dataset using the [🤗Huggingface Datasets](https://huggingface.co/docs/datasets/index) library: + +```python +from datasets import load_dataset + +ds = load_dataset("fjcanyue/wikipedia-zh-cn") +``` + +If using the JSON file downloaded from Baidu Netdisk, load it with the following code: + +```python +raw_datasets = datasets.load_dataset( + "json", data_files="data/wikipedia-zh-cn-20240820.json" +) + +raw_datasets = raw_datasets["train"].train_test_split(test_size=0.1, seed=2333) +print("dataset info") +print(raw_datasets) +``` + +## Building Your Own Large Language Model + +This tutorial uses the [🤗Huggingface Transformers](https://huggingface.co/docs/transformers/index) library to build your own large model. + +Since the goal is to train a Chinese large model, we reference the tokenizer and model architecture of [Qwen-2](https://qwen.readthedocs.io/zh-cn/latest/run_locally/mlx-lm.html) and make minor adjustments to make the model smaller and easier to train. + +As direct access to Huggingface is restricted in China, it is recommended to use ModelScope to download the model configuration files and checkpoints locally. Run the following code: + +```python +import modelscope + +modelscope.AutoConfig.from_pretrained("Qwen/Qwen2-0.5B").save_pretrained( + "Qwen2-0.5B" +) +modelscope.AutoTokenizer.from_pretrained("Qwen/Qwen2-0.5B").save_pretrained( + "Qwen2-0.5B" +) +``` + +Configure the parameters and modify the number of attention heads, model layers, and intermediate layer sizes to control the model to approximately 120M parameters (similar to GPT-2). + +```python +import transformers + +tokenizer = transformers.AutoTokenizer.from_pretrained("./Qwen2-0.5B") # Use Qwen-2's tokenizer +config = transformers.AutoConfig.from_pretrained( + "./Qwen2-0.5B", + vocab_size=len(tokenizer), + hidden_size=512, + intermediate_size=2048, + num_attention_heads=8, + num_hidden_layers=12, + n_ctx=context_length, + bos_token_id=tokenizer.bos_token_id, + eos_token_id=tokenizer.eos_token_id, + ) +print("Model Config:") +print(config) +``` + +Initialize the model using the Transformers library: + +```python +model = transformers.Qwen2ForCausalLM(config) +model_size = sum(t.numel() for t in model.parameters()) +print(f"Model Size: {model_size/1000**2:.1f}M parameters") +``` + +## Setting Training Parameters + +Set the pretraining hyperparameters: + +```python +args = transformers.TrainingArguments( + output_dir="checkpoints", + per_device_train_batch_size=24, # Batch size per GPU for training + per_device_eval_batch_size=24, # Batch size per GPU for evaluation + eval_strategy="steps", + eval_steps=5_000, + logging_steps=500, + gradient_accumulation_steps=12, # Total gradient accumulation steps + num_train_epochs=2, # Number of training epochs + weight_decay=0.1, + warmup_steps=1_000, + optim="adamw_torch", # Optimizer using AdamW + lr_scheduler_type="cosine", # Learning rate decay strategy + learning_rate=5e-4, # Base learning rate + save_steps=5_000, + save_total_limit=10, + bf16=True, # Enable bf16 training, replace with fp16=True for non-Ampere architecture GPUs +) +print("Train Args:") +print(args) +``` + +## Initializing Training + Logging with SwanLab + +Use the built-in training from Transformers and integrate SwanLab for visualization and logging: + +```python +from swanlab.integration.huggingface import SwanLabCallback +trainer = transformers.Trainer( + model=model, + tokenizer=tokenizer, + args=args, + data_collator=data_collator, + train_dataset=tokenized_datasets["train"], + eval_dataset=tokenized_datasets["test"], + callbacks=[SwanLabCallback()], +) +trainer.train() +``` + +If this is your first time using SwanLab, log in to the SwanLab website [https://swanlab.cn/](https://swanlab.cn/), register, and find your key as shown below: + +![findkey](/assets/examples/pretrain_llm/findkey.png) + +Then, enter the following command in the terminal: + +```sh +swanlab login +``` + +You will be prompted to enter your key. Paste the key (note that the key will not be displayed in the terminal) to complete the configuration. The result should look like this: + +![login2](/assets/examples/pretrain_llm/login2.png) + +## Complete Code + +Project directory structure: + +```txt +|---data\ +|------wikipedia-zh-cn-20240820.json # Dataset placed in the data folder +|--- pretrain.py +``` + +`pretrain.py` code: + +```python +import datasets +import transformers +import swanlab +from swanlab.integration.huggingface import SwanLabCallback +import modelscope + +def main(): + # using swanlab to save log + swanlab.init("WikiLLM") + + # load dataset + raw_datasets = datasets.load_dataset( + "json", data_files="/data/WIKI_CN/wikipedia-zh-cn-20240820.json" + ) + + raw_datasets = raw_datasets["train"].train_test_split(test_size=0.1, seed=2333) + print("dataset info") + print(raw_datasets) + + # load tokenizers + # Because direct access to HuggingFace is restricted in China, use ModelScope to download the model configuration files and Tokenizer locally + modelscope.AutoConfig.from_pretrained("Qwen/Qwen2-0.5B").save_pretrained( + "Qwen2-0.5B" + ) + modelscope.AutoTokenizer.from_pretrained("Qwen/Qwen2-0.5B").save_pretrained( + "Qwen2-0.5B" + ) + context_length = 512 # use a small context length + # tokenizer = transformers.AutoTokenizer.from_pretrained("Qwen/Qwen2-0.5B") + tokenizer = transformers.AutoTokenizer.from_pretrained( + "./Qwen2-0.5B" + ) # download from local + + # preprocess dataset + def tokenize(element): + outputs = tokenizer( + element["text"], + truncation=True, + max_length=context_length, + return_overflowing_tokens=True, + return_length=True, + ) + input_batch = [] + for length, input_ids in zip(outputs["length"], outputs["input_ids"]): + if length == context_length: + input_batch.append(input_ids) + return {"input_ids": input_batch} + + tokenized_datasets = raw_datasets.map( + tokenize, batched=True, remove_columns=raw_datasets["train"].column_names + ) + print("tokenize dataset info") + print(tokenized_datasets) + tokenizer.pad_token = tokenizer.eos_token + data_collator = transformers.DataCollatorForLanguageModeling(tokenizer, mlm=False) + + # prepare a model from scratch + config = transformers.AutoConfig.from_pretrained( + "./Qwen2-0.5B", + vocab_size=len(tokenizer), + hidden_size=512, + intermediate_size=2048, + num_attention_heads=8, + num_hidden_layers=12, + n_ctx=context_length, + bos_token_id=tokenizer.bos_token_id, + eos_token_id=tokenizer.eos_token_id, + ) + model = transformers.Qwen2ForCausalLM(config) + model_size = sum(t.numel() for t in model.parameters()) + print("Model Config:") + print(config) + print(f"Model Size: {model_size/1000**2:.1f}M parameters") + + # train + args = transformers.TrainingArguments( + output_dir="WikiLLM", + per_device_train_batch_size=32, # Batch size per GPU for training + per_device_eval_batch_size=32, # Batch size per GPU for evaluation + eval_strategy="steps", + eval_steps=5_00, + logging_steps=50, + gradient_accumulation_steps=8, # Total gradient accumulation steps + num_train_epochs=2, # Number of training epochs + weight_decay=0.1, + warmup_steps=2_00, + optim="adamw_torch", # Optimizer using AdamW + lr_scheduler_type="cosine", # Learning rate decay strategy + learning_rate=5e-4, # Base learning rate + save_steps=5_00, + save_total_limit=10, + bf16=True, # Enable bf16 training, replace with fp16=True for non-Ampere architecture GPUs + ) + print("Train Args:") + print(args) + # enjoy training + trainer = transformers.Trainer( + model=model, + tokenizer=tokenizer, + args=args, + data_collator=data_collator, + train_dataset=tokenized_datasets["train"], + eval_dataset=tokenized_datasets["test"], + callbacks=[SwanLabCallback()], + ) + trainer.train() + + # save model + model.save_pretrained("./WikiLLM/Weight") # Save model path + + # generate + pipe = transformers.pipeline("text-generation", model=model, tokenizer=tokenizer) + print("GENERATE:", pipe("人工智能", num_return_sequences=1)[0]["generated_text"]) + prompts = ["牛顿", "北京市", "亚洲历史"] + examples = [] + for i in range(3): + # Generate data based on prompts + text = pipe(prompts[i], num_return_sequences=1)[0]["generated_text"] + text = swanlab.Text(text) + examples.append(text) + swanlab.log({"Generate": examples}) + + +if __name__ == "__main__": + main() +``` + +## Training Results Demonstration + +Run the following command: + +``` +python pretrain.py +``` + +You will see the training logs as shown below. Since the training takes a long time, it is recommended to use tmux to hold the training task. + +![terminal](/assets/examples/pretrain_llm/terminal.png) + +You can view the final training results on [SwanLab](https://swanlab.cn): + +![log](/assets/examples/pretrain_llm/log.png) + + + +## Using the Trained Model for Inference + +Generate content starting with "人工智能" using the following code: + +```python +pipe = transformers.pipeline("text-generation", model=model, tokenizer=tokenizer) +print("GENERATE:", pipe("人工智能", num_return_sequences=1)[0]["generated_text"]) +``` + +Inference results are as follows: + +(The model is still training; you can check the training progress and inference results in real-time at [https://swanlab.cn/@ShaohonChen/WikiLLM/overview](https://swanlab.cn/@ShaohonChen/WikiLLM/overview)) + + +## Using SwanLab Launch to Train on Remote GPUs + +::: info +Ensure the swanlab version is 0.3.19 +::: + +Pretraining LLMs requires significant GPU compute power and memory. This article recommends using [SwanLab Launch](/zh/api/cli-swanlab-remote-gpu) to leverage cloud GPUs for pretraining. + +First, upload the dataset using the `swanlab upload -n WIKI_CN WIKI_CN` command: + +![upload](/assets/examples/pretrain_llm/launch_upload.png) + +After uploading, you will receive the dataset ID (as shown below): + +![upload](/assets/examples/pretrain_llm/launch_upload2.png) + +You can also use `swanlab task list` to view the uploaded dataset ID: + +![show_id](/assets/examples/pretrain_llm/show_id.png) + +Refer to the [SwanLab Launch official documentation](/zh/api/cli-swanlab-remote-gpu) to create a `swanlab.yaml` file locally and enter the following information: + +```yaml +apiVersion: swanlab/v1 +kind: Folder +metadata: + name: WikiLLM + desc: Pretrain LLM using wiki data +spec: + python: "3.10" + entry: "pretrain.py" + volumes: + - name: "WIKI_CN" + id: "" + exclude: + - "WIKI_CN" +``` + +Start remote training with the following command: + +```bash +swanlab launch -f swanlab.yaml +``` + +This will start remote training! You can track the remote experiment logs on SwanLab. + +![remote_log](/assets/examples/pretrain_llm/remote_log.png) + +You can see that \ No newline at end of file diff --git a/en/examples/qwen_finetune.md b/en/examples/qwen_finetune.md new file mode 100644 index 0000000..a510de4 --- /dev/null +++ b/en/examples/qwen_finetune.md @@ -0,0 +1,256 @@ +# Qwen1.5 Fine-Tuning Case Study + +:::info +Text Classification, Large Language Models, Fine-Tuning Large Models +::: + +[Experiment Process](https://swanlab.cn/@ZeyiLin/Qwen-fintune/runs/zy0st4z16sh4bndyehtks/chart) | [Qwen2 Fine-Tuning Tutorial](https://zhuanlan.zhihu.com/p/702491999) + +## Overview + +[Qwen1.5](https://modelscope.cn/models/qwen/Qwen1.5-7B-Chat/summary) is an open-source large language model developed by the Qwen team from Alibaba Cloud's Tongyi Lab. Using Qwen-1.5 as the base model, high-accuracy text classification can be achieved through task-specific fine-tuning, making it an excellent entry task for learning **large language model fine-tuning**. + +![](/assets/example-qwen-1.png) + +Fine-tuning is a process of further training LLMs on a dataset consisting of (input, output) pairs. This process helps the LLM perform better on specific downstream tasks. + +In this task, we will use the [Qwen-1.5-7b](https://modelscope.cn/models/qwen/Qwen1.5-7B-Chat/summary) model to fine-tune on the [zh_cls_fudan-news](https://modelscope.cn/datasets/swift/zh_cls_fudan-news) dataset for instruction fine-tuning tasks, while using SwanLab for monitoring and visualization. + +## Environment Setup + +This case study is based on `Python>=3.10`. Please ensure Python is installed on your computer. + +Environment dependencies: +```txt +swanlab +modelscope +transformers +datasets +peft +accelerat +pandas +``` + +One-click installation command: + +```bash +pip install swanlab modelscope transformers datasets peft pandas +``` + +> This case study is tested with modelscope==1.14.0, transformers==4.41.2, datasets==2.18.0, peft==0.11.1, accelerate==0.30.1, swanlab==0.3.8 + +## Dataset Introduction + +This case study uses the [zh_cls_fudan-news](https://modelscope.cn/datasets/swift/zh_cls_fudan-news) dataset, which is primarily used for training text classification models. + +zh_cls_fudan-news consists of several thousand entries, each containing three columns: text, category, and output. +- text is the training corpus, containing text content from books or news articles. +- category is a list of potential types for the text. +- output is the single true type of the text. + +![](/assets/example-qwen-2.png) + +Example dataset entry: +``` +""" +[PROMPT]Text: The fourth national large enterprise football tournament's knockout stage concluded. Xinhua News Agency, Zhengzhou, May 3rd (Intern Tian Zhaoyun) The Shanghai Dalong Machinery Factory team defeated the Chengdu Metallurgical Experimental Factory team 5:4 in the knockout stage of the fourth Peony Cup national large enterprise football tournament held in Luoyang yesterday, advancing to the top four. The match between Shanghai and Chengdu was evenly matched, with no winner after 90 minutes. Finally, the two teams took turns in penalty kicks, and the Shanghai team won by a one-goal margin. In the other three knockout matches, Qinghai Shanchuan Machine Tool Foundry team defeated the host Luoyang Mining Machinery Factory team 3:0, Qingdao Foundry Machinery Factory team defeated Shijiazhuang First Printing and Dyeing Factory team 3:1, and Wuhan Meat Processing Factory team narrowly defeated Tianjin Second Metallurgical Machinery Factory team 1:0. In today's two matches to determine the 9th to 12th places, Baogang Seamless Steel Tube Factory team and Henan Pingdingshan Mining Bureau No.1 Mine team respectively defeated Henan Pingdingshan Nylon Cord Factory team and Jiangsu Yancheng Radio General Factory team. On the 4th, two semi-final matches will be held, with Qinghai Shanchuan Machine Tool Foundry team and Qingdao Foundry Machinery Factory team facing off against Wuhan Meat Processing Factory team and Shanghai Dalong Machinery Factory team respectively. The tournament will conclude on the 6th. (End) +Category: Sports, Politics +Output:[OUTPUT]Sports +""" + +``` + +Our training task is to fine-tune the large model so that it can predict the correct output based on the prompt consisting of text and category. + +## Preparations + +Before starting the training, ensure that the environment is installed and that you have a GPU with **at least 16GB of VRAM**. + +Next, download the dataset to your local directory. The download method is to go to [zh_cls_fudan-news - ModelScope Community](https://modelscope.cn/datasets/swift/zh_cls_fudan-news/files) and download `train.jsonl` and `test.jsonl` to your local root directory: + +![](/assets/example-qwen-3.png) + +## Complete Code + +Directory structure before starting training: + +```txt +|--- train.py +|--- train.jsonl +|--- test.jsonl +``` + +train.py: + +```python +import json +import pandas as pd +import torch +from datasets import Dataset +from modelscope import snapshot_download, AutoTokenizer +from swanlab.integration.huggingface import SwanLabCallback +from peft import LoraConfig, TaskType, get_peft_model +from transformers import AutoModelForCausalLM, TrainingArguments, Trainer, DataCollatorForSeq2Seq +import os +import swanlab + + +def dataset_jsonl_transfer(origin_path, new_path): + """ + Convert the original dataset to the new dataset format required for large model fine-tuning. + """ + messages = [] + + # Read the old JSONL file + with open(origin_path, "r") as file: + for line in file: + # Parse each line's json data + data = json.loads(line) + context = data["text"] + catagory = data["category"] + label = data["output"] + message = { + "instruction": "You are an expert in text classification. You will receive a piece of text and several potential classification options. Please output the correct type of the text content.", + "input": f"Text: {context}, Type Options: {catagory}", + "output": label, + } + messages.append(message) + + # Save the reconstructed JSONL file + with open(new_path, "w", encoding="utf-8") as file: + for message in messages: + file.write(json.dumps(message, ensure_ascii=False) + "\n") + + +def process_func(example): + """ + Preprocess the dataset. + """ + MAX_LENGTH = 384 + input_ids, attention_mask, labels = [], [], [] + instruction = tokenizer( + f"<|im_start|>system\nYou are an expert in text classification. You will receive a piece of text and several potential classification options. Please output the correct type of the text content.<|im_end|>\n<|im_start|>user\n{example['input']}<|im_end|>\n<|im_start|>assistant\n", + add_special_tokens=False, + ) + response = tokenizer(f"{example['output']}", add_special_tokens=False) + input_ids = instruction["input_ids"] + response["input_ids"] + [tokenizer.pad_token_id] + attention_mask = ( + instruction["attention_mask"] + response["attention_mask"] + [1] + ) + labels = [-100] * len(instruction["input_ids"]) + response["input_ids"] + [tokenizer.pad_token_id] + if len(input_ids) > MAX_LENGTH: # Truncate if necessary + input_ids = input_ids[:MAX_LENGTH] + attention_mask = attention_mask[:MAX_LENGTH] + labels = labels[:MAX_LENGTH] + return {"input_ids": input_ids, "attention_mask": attention_mask, "labels": labels} + + +def predict(messages, model, tokenizer): + device = "cuda" + text = tokenizer.apply_chat_template( + messages, + tokenize=False, + add_generation_prompt=True + ) + model_inputs = tokenizer([text], return_tensors="pt").to(device) + + generated_ids = model.generate( + model_inputs.input_ids, + max_new_tokens=512 + ) + generated_ids = [ + output_ids[len(input_ids):] for input_ids, output_ids in zip(model_inputs.input_ids, generated_ids) + ] + + response = tokenizer.batch_decode(generated_ids, skip_special_tokens=True)[0] + + print(response) + + return response + +# Download Qwen1.5-7B model from modelscope to local directory +model_dir = snapshot_download("qwen/Qwen1.5-7B-Chat", cache_dir="./", revision="master") + +# Load model weights using Transformers +tokenizer = AutoTokenizer.from_pretrained("./qwen/Qwen1___5-7B-Chat/", use_fast=False, trust_remote_code=True) +model = AutoModelForCausalLM.from_pretrained("./qwen/Qwen1___5-7B-Chat/", device_map="auto", torch_dtype=torch.bfloat16) +model.enable_input_require_grads() # Enable gradient checkpointing + +# Load and process the training and test datasets +train_dataset_path = "train.jsonl" +test_dataset_path = "test.jsonl" + +train_jsonl_new_path = "new_train.jsonl" +test_jsonl_new_path = "new_test.jsonl" + +if not os.path.exists(train_jsonl_new_path): + dataset_jsonl_transfer(train_dataset_path, train_jsonl_new_path) +if not os.path.exists(test_jsonl_new_path): + dataset_jsonl_transfer(test_dataset_path, test_jsonl_new_path) + +# Get the training dataset +train_df = pd.read_json(train_jsonl_new_path, lines=True) +train_ds = Dataset.from_pandas(train_df) +train_dataset = train_ds.map(process_func, remove_columns=train_ds.column_names) + +config = LoraConfig( + task_type=TaskType.CAUSAL_LM, + target_modules=["q_proj", "k_proj", "v_proj", "o_proj", "gate_proj", "up_proj", "down_proj"], + inference_mode=False, # Training mode + r=8, # Lora rank + lora_alpha=32, # Lora alpha, refer to Lora theory for details + lora_dropout=0.1, # Dropout ratio +) + +model = get_peft_model(model, config) + +args = TrainingArguments( + output_dir="./output/Qwen1.5", + per_device_train_batch_size=4, + gradient_accumulation_steps=4, + logging_steps=10, + num_train_epochs=2, + save_steps=100, + learning_rate=1e-4, + save_on_each_node=True, + gradient_checkpointing=True, + report_to="none", +) + +swanlab_callback = SwanLabCallback(project="Qwen-fintune", experiment_name="Qwen1.5-7B-Chat") + +trainer = Trainer( + model=model, + args=args, + train_dataset=train_dataset, + data_collator=DataCollatorForSeq2Seq(tokenizer=tokenizer, padding=True), + callbacks=[swanlab_callback], +) + +trainer.train() + +# Test the model with the first 10 entries of the test dataset +test_df = pd.read_json(test_jsonl_new_path, lines=True)[:10] + +test_text_list = [] +for index, row in test_df.iterrows(): + instruction = row['instruction'] + input_value = row['input'] + + messages = [ + {"role": "system", "content": f"{instruction}"}, + {"role": "user", "content": f"{input_value}"} + ] + + response = predict(messages, model, tokenizer) + messages.append({"role": "assistant", "content": f"{response}"}) + result_text = f"{messages[0]}\n\n{messages[1]}\n\n{messages[2]}" + test_text_list.append(swanlab.Text(result_text, caption=response)) + +swanlab.log({"Prediction": test_text_list}) +swanlab.finish() +``` + +## Demonstration of Results + +![](/assets/example-qwen-4.png) \ No newline at end of file diff --git a/en/examples/qwen_vl_coco.md b/en/examples/qwen_vl_coco.md new file mode 100644 index 0000000..810b253 --- /dev/null +++ b/en/examples/qwen_vl_coco.md @@ -0,0 +1,7 @@ +# Qwen2-VL Multimodal Large Model Fine-Tuning Practical Guide + +:::info +Multimodal, Large Language Models, Large Model Fine-Tuning +::: + +[Training Process](https://swanlab.cn/@ZeyiLin/Qwen2-VL-finetune/runs/pkgest5xhdn3ukpdy6kv5/chart) | [Zhihu Tutorial](https://zhuanlan.zhihu.com/p/7144893529) \ No newline at end of file diff --git a/en/examples/yolo.md b/en/examples/yolo.md new file mode 100644 index 0000000..2d229ba --- /dev/null +++ b/en/examples/yolo.md @@ -0,0 +1,55 @@ +# YOLO Object Detection + +:::info +Object Detection, Computer Vision +::: + +[Online Demo](https://swanlab.cn/@ZeyiLin/ultratest/runs/yux7vclmsmmsar9ear7u5/chart) | [YOLO Cat and Dog Detection Tutorial](https://zhuanlan.zhihu.com/p/700347880) + +## Overview + +YOLO (You Only Look Once) is an object detection model proposed by Joseph Redmon et al., widely used in various computer vision tasks. YOLO divides the image into a grid and predicts bounding boxes and class probabilities within each grid cell, enabling real-time object detection and performing well in many tasks. + +In this task, we will use the YOLO model for object detection on the COCO128 dataset while using SwanLab for monitoring and visualization. + +![yolo](/assets/example-yolo-1.png) + +The COCO128 dataset is a small object detection dataset derived from the widely used COCO (Common Objects in Context) dataset. The COCO128 dataset contains 128 images, a subset of the COCO dataset, primarily used for quick testing and debugging of object detection models. + +## Environment Setup + +This case study is based on `Python>=3.8`. Please ensure Python is installed on your computer. Environment dependencies: + +```txt +ultralytics +swanlab +``` + +Quick installation command: + +```bash +pip install ultralytics swanlab +``` + +> The code in this article is tested with ultralytics==8.2.18, swanlab==0.3.6 + +## Complete Code + +```python +from ultralytics import YOLO +from swanlab.integration.ultralytics import add_swanlab_callback + +def main(): + model = YOLO("yolov8n.pt") + add_swanlab_callback(model) + model.train(data="coco128.yaml", epochs=5, imgsz=640, batch=64) + +if __name__ == "__main__": + main() +``` + +## Demonstration of Results + +![yolo-2](/assets/example-yolo-2.png) + +![yolo-3](/assets/example-yolo-3.png) \ No newline at end of file diff --git a/en/guide_cloud/community/contributing-code.md b/en/guide_cloud/community/contributing-code.md new file mode 100644 index 0000000..9fac8df --- /dev/null +++ b/en/guide_cloud/community/contributing-code.md @@ -0,0 +1,168 @@ +# Contributing to SwanLab + +Interested in contributing to SwanLab? We welcome contributions from the community! This guide discusses the development workflow and internal structure of `swanlab`. + +## 📦 Table of Contents + +- [Standard Development Process](#standard-development-process) +- [Local Debugging](#local-debugging) + - [IDE and Plugins](#ide-and-plugins) + - [Configuring Python Environment](#configuring-python-environment) + - [Debugging Scripts](#debugging-scripts) +- [Local Testing](#local-testing) + - [Python Script Debugging](#python-script-debugging) + - [Unit Testing](#unit-testing) + +## Standard Development Process + +1. Browse the [Issues](https://github.com/SwanHubX/SwanLab/issues) on GitHub to see the features you'd like to add or bugs you'd like to fix, and whether they have already been addressed by a Pull Request. + + - If not, create a [new Issue](https://github.com/SwanHubX/SwanLab/issues/new/choose) — this will help the project track feature requests and bug reports and ensure that work is not duplicated. + +2. If you are contributing to an open-source project for the first time, go to the [project homepage](https://github.com/SwanHubX/SwanLab) and click the "Fork" button in the upper right corner. This will create a personal copy of the repository for your development. + + - Clone the forked project to your computer and add a remote link to the `swanlab` project: + + ```bash + git clone https://github.com//swanlab.git + cd swanlab + git remote add upstream https://github.com/swanhubx/swanlab.git + ``` + +3. Develop your contribution + + - Ensure your fork is synchronized with the main repository: + + ```bash + git checkout main + git pull upstream main + ``` + + - Create a `git` branch where you will develop your contribution. Use a reasonable name for the branch, for example: + + ```bash + git checkout -b / + ``` + + - As you make progress, commit your changes locally, for example: + + ```bash + git add changed-file.py tests/test-changed-file.py + git commit -m "feat(integrations): Add integration with the `awesomepyml` library" + ``` + +4. Submit your contribution: + + - [Github Pull Request](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/about-pull-requests) + - When your contribution is ready, push your branch to GitHub: + + ```bash + git push origin / + ``` + + - After the branch is uploaded, `GitHub` will print a URL to submit your contribution as a pull request. Open that URL in your browser, write an informative title and detailed description for your pull request, and submit it. + + - Please link the relevant Issue (existing Issue or the one you created) to your PR. See the right sidebar of the PR page. Alternatively, mention "Fixes issue link" in the PR description — GitHub will automatically link it. + + - We will review your contribution and provide feedback. To merge the changes suggested by the reviewer, commit the edits to your branch and push it again (no need to recreate the pull request, it will automatically track modifications to the branch), for example: + + ```bash + git add tests/test-changed-file.py + git commit -m "test(sdk): Add a test case to address reviewer feedback" + git push origin / + ``` + + - Once your pull request is approved by the reviewer, it will be merged into the main branch of the repository. + +## Local Debugging + +### IDE and Plugins + +1. **Use VSCode as your development IDE** + + The SwanLab repository has already configured the [VSCode](https://code.visualstudio.com/) environment, plugins, and debugging scripts (located in the `.vscode` folder). Developing SwanLab with VSCode will provide the best experience. + +2. **Install VSCode Plugins (Optional)** + + Open the project with VSCode, go to [Extensions], enter "@recommended" in the search box, and a series of recommended plugins will appear. It is recommended to install all these plugins. + + ![vscode-recommend](/assets/guide_cloud/community/contributing-code/vscode_recommend.png) + +### Configuring Python Environment + +The SwanLab project environment requires `python>=3.8`. + +The necessary Python dependencies are centrally recorded in `requirements.txt` in the project root directory. + +Start the terminal in the project root directory and run the following command to install the dependencies: + +```Bash +# Packages required by swanlab +pip install -r requirements.txt +pip install -r requirements-media.txt +``` + +Additional dependencies are required for compilation, development, unit testing, etc.: + +```Bash +# Packages required for compilation, unit testing, etc. +pip install -r requirements-dev.txt +``` + +### Debugging Scripts + +1. **VSCode Debugging Scripts** + +In VSCode - Run and Debug, the project has configured a series of debugging scripts: + +![img](/assets/guide_cloud/community/contributing-code/debug.png) + +- **Start an Experiment**: Run the `test/create_experiment.py` script + +- **Run the Current File**: Use the configured Python environment to run the file you selected + +- **Test the Current File**: Test the file you selected in debug mode + +- **Run All Unit Tests**: Run the scripts in `test/unit` to perform a complete unit test of the basic functions of swanlab + +- **(Skip Cloud) Run All Unit Tests**: Run the scripts in `test/unit` to perform a complete unit test of the basic functions of swanlab, but skip cloud testing + +- **Build the Project**: Package the project into a whl file (pip installation package format) + +Ps: If you do not want to use VSCode for development, you can go to `.vscode/launch.json` to view the command corresponding to each debugging item to understand its configuration. + +## Local Testing + +The prerequisite for testing is that you have installed all the required dependencies. + +### Python Script Debugging + +After completing your changes, you can place your Python test script in the root directory or the `test` folder, and then use the "Run the Current File" in [VSCode Scripts](#debugging-scripts) to run your Python test script. This way, your script will use the modified swanlab. + +### Unit Testing + +You can perform unit testing through [VSCode Scripts](#debugging-scripts) or by running the following command in the project root directory: + +```Bash +export PYTHONPATH=. && pytest test/unit +``` + +Since swanlab involves interaction with the cloud, and the cloud part is closed-source, the simplest way if you are contributing code for the first time is to only perform local testing. +For this situation, create a `.env` file in the local root directory and fill in the following environment variable configuration: + +```dotenv +SWANLAB_RUNTIME=test-no-cloud +``` + +This will skip cloud testing and only perform local part function testing. If you want to perform complete testing, please supplement the following information in `.env`: + +```dotenv +SWANLAB_RUNTIME=test +SWANLAB_API_KEY= +SWANLAB_API_HOST=https://swanlab.cn/api +SWANLAB_WEB_HOST=https://swanlab.cn +``` + +*Note: When performing cloud testing, some useless test experiment data will be generated under your cloud account, which needs to be manually deleted* + +After configuring, you can run the complete test \ No newline at end of file diff --git a/en/guide_cloud/community/contributing-docs.md b/en/guide_cloud/community/contributing-docs.md new file mode 100644 index 0000000..7913e01 --- /dev/null +++ b/en/guide_cloud/community/contributing-docs.md @@ -0,0 +1,42 @@ +# Contributing to SwanLab Official Documentation + +Contributing to the project is not limited to code contributions; maintaining documentation, answering questions in issues and groups, submitting bugs, and more are all ways to contribute to the swanlab project! + +We host the [official documentation](https://docs.swanlab.cn) for SwanLab in our [GitHub repository](https://github.com/SwanHubX/SwanLab-Docs), based on [vitepress](https://vitepress.dev/zh/guide/getting-started). + +### How to Contribute to the Documentation + +It's simple! Just clone the project, add or modify Markdown files, submit them, and create a PR. + +### Environment Setup + +1. Clone this repository + +```bash +git clone https://github.com/SwanHubX/SwanLab-Docs +``` + +2. Install the dependency environment + +You need to install nodejs and npm in advance. For detailed methods, please refer to the [node official tutorial](https://nodejs.org/en/download/package-manager). + +Use the following command to install other dependent projects: + +```bash +npm add -D vitepress +``` + +### Running Documentation Locally + +If you are developing locally or previewing the documentation, you can run the following command in the project root directory: + +```bash +npm run docs:dev +``` + +If you want to perform a complete compilation and packaging, use the following commands: + +```bash +npm run docs:build +npm run docs:preview +``` \ No newline at end of file diff --git a/en/guide_cloud/community/contributor.md b/en/guide_cloud/community/contributor.md new file mode 100644 index 0000000..0dc1f0e --- /dev/null +++ b/en/guide_cloud/community/contributor.md @@ -0,0 +1,20 @@ +# Contributors + +This page acknowledges the developers who have contributed code to SwanLab and its ecosystem projects (in no particular order). + +- [SAKURA-CAT](https://github.com/SAKURA-CAT) +- [swpfY](https://github.com/swpfY) +- [Feudalman](https://github.com/Feudalman) +- [Kaikaikaifang](https://github.com/Kaikaikaifang) +- [KashiwaByte](https://github.com/KashiwaByte) +- [Nexisato](https://github.com/Nexisato) +- [SIMON-TANG-Liu](https://github.com/SIMON-TANG-Liu) +- [little1d](https://github.com/little1d) +- [Zeyi-Lin](https://github.com/Zeyi-Lin) +- [ShaohonChen](https://github.com/ShaohonChen) +- [indevn](https://github.com/indevn) +- [pescn](https://github.com/pescn) +- [66Lau](https://github.com/66Lau) +- [sweetdog123](https://github.com/sweetdog123) +- [clairdelunejs](https://github.com/clairdelunejs) +- [Puiching-Memory](https://github.com/Puiching-Memory) diff --git a/en/guide_cloud/community/emotion-machine.md b/en/guide_cloud/community/emotion-machine.md new file mode 100644 index 0000000..97063d1 --- /dev/null +++ b/en/guide_cloud/community/emotion-machine.md @@ -0,0 +1,8 @@ +# About Us + +Emotion Machine (Beijing) Technology Co., Ltd. is a high-tech enterprise focused on the research and development of underlying tools for artificial intelligence and machine learning. The company is committed to providing basic development tools for AI developers and building an open-source and open technology community. +Mission: To create AI toolchains and empower the global AI developer ecosystem. + +**Company**: Emotion Machine (Beijing) Technology Co., Ltd. +**Location**: Room B205-1, 2nd Floor, Zhongguancun Technology Service Building, No. 1 Building, Courtyard 2, Guanzhuang Road, Chaoyang District, Beijing +**Contact Us**: shaohon_chen@115lab.club \ No newline at end of file diff --git a/en/guide_cloud/community/github-badge.md b/en/guide_cloud/community/github-badge.md new file mode 100644 index 0000000..5f61e0d --- /dev/null +++ b/en/guide_cloud/community/github-badge.md @@ -0,0 +1,11 @@ +# Github README Badge + +If you enjoy using SwanLab in your work and studies, feel free to add the SwanLab badge to your README: + +[![swanlab](https://img.shields.io/badge/powered%20by-SwanLab-438440)](https://github.com/swanhubx/swanlab) + +Copy the following code into your README.md file: + +``` +[![swanlab](https://img.shields.io/badge/powered%20by-SwanLab-438440)](https://github.com/swanhubx/swanlab) +``` \ No newline at end of file diff --git a/en/guide_cloud/community/online-support.md b/en/guide_cloud/community/online-support.md new file mode 100644 index 0000000..fb2ea22 --- /dev/null +++ b/en/guide_cloud/community/online-support.md @@ -0,0 +1,28 @@ +# Online Support + +## Community + +- **WeChat Group**: Discuss SwanLab usage issues and share the latest AI technologies. + +
+ +
+ +- **Feishu Group**: Our daily work communication is on Feishu, and the response in the Feishu group will be more timely. Scan the QR code below with the Feishu App: + +
+ +
+ +## Social Media +- **WeChat Official Account**: + +
+ +
+ +## GitHub and Email +- **[GitHub Issues](https://github.com/SwanHubX/SwanLab/issues)**: Report errors and issues encountered while using SwanLab. +- **Email Support**: Report issues regarding SwanLab usage. + - Product: , (Product Manager's Email) + - Collaboration: , \ No newline at end of file diff --git a/en/guide_cloud/community/paper-cite.md b/en/guide_cloud/community/paper-cite.md new file mode 100644 index 0000000..2963835 --- /dev/null +++ b/en/guide_cloud/community/paper-cite.md @@ -0,0 +1,14 @@ +# Citing SwanLab in Your Papers + +If you find SwanLab helpful in your research journey, please consider citing it in the following format: + +```bibtex +@software{Zeyilin_SwanLab_2023, + author = {Zeyi Lin, Shaohong Chen, Kang Li, Qiushan Jiang, Zirui Cai, Kaifang Ji and {The SwanLab team}}, + doi = {10.5281/zenodo.11100550}, + license = {Apache-2.0}, + title = {{SwanLab}}, + url = {https://github.com/swanhubx/swanlab}, + year = {2023} +} +``` \ No newline at end of file