diff --git a/react-ui/src/enums/index.ts b/react-ui/src/enums/index.ts
index 34d5b51b..bdfe9e00 100644
--- a/react-ui/src/enums/index.ts
+++ b/react-ui/src/enums/index.ts
@@ -118,3 +118,14 @@ export const autoMLResamplingStrategyOptions = [
{ label: 'holdout', value: AutoMLResamplingStrategy.Holdout },
{ label: 'crossValid', value: AutoMLResamplingStrategy.CrossValid },
];
+
+// 超参数自动寻优优化方向
+export enum hyperParameterOptimizedMode {
+ Min = 'min',
+ Max = 'max',
+}
+
+export const hyperParameterOptimizedModeOptions = [
+ { label: '越大越好', value: hyperParameterOptimizedMode.Max },
+ { label: '越小越好', value: hyperParameterOptimizedMode.Min },
+];
diff --git a/react-ui/src/pages/AutoML/Create/index.tsx b/react-ui/src/pages/AutoML/Create/index.tsx
index 30699063..ec016c3c 100644
--- a/react-ui/src/pages/AutoML/Create/index.tsx
+++ b/react-ui/src/pages/AutoML/Create/index.tsx
@@ -190,7 +190,7 @@ function CreateAutoML() {
-
+
diff --git a/react-ui/src/pages/AutoML/Info/index.tsx b/react-ui/src/pages/AutoML/Info/index.tsx
index cc5247e2..0d0ec460 100644
--- a/react-ui/src/pages/AutoML/Info/index.tsx
+++ b/react-ui/src/pages/AutoML/Info/index.tsx
@@ -3,9 +3,7 @@
* @Date: 2024-04-16 13:58:08
* @Description: 自主机器学习详情
*/
-import KFIcon from '@/components/KFIcon';
import PageTitle from '@/components/PageTitle';
-import { CommonTabKeys } from '@/enums';
import { getAutoMLInfoReq } from '@/services/autoML';
import { safeInvoke } from '@/utils/functional';
import { to } from '@/utils/promise';
@@ -16,24 +14,10 @@ import { AutoMLData } from '../types';
import styles from './index.less';
function AutoMLInfo() {
- const [activeTab, setActiveTab] = useState(CommonTabKeys.Public);
const params = useParams();
const autoMLId = safeInvoke(Number)(params.id);
const [autoMLInfo, setAutoMLInfo] = useState(undefined);
- const tabItems = [
- {
- key: CommonTabKeys.Public,
- label: '基本信息',
- icon: ,
- },
- {
- key: CommonTabKeys.Private,
- label: 'Trial列表',
- icon: ,
- },
- ];
-
useEffect(() => {
if (autoMLId) {
getAutoMLInfo();
diff --git a/react-ui/src/pages/AutoML/components/AutoMLBasic/index.tsx b/react-ui/src/pages/AutoML/components/AutoMLBasic/index.tsx
index 854c6035..76d26a75 100644
--- a/react-ui/src/pages/AutoML/components/AutoMLBasic/index.tsx
+++ b/react-ui/src/pages/AutoML/components/AutoMLBasic/index.tsx
@@ -4,6 +4,7 @@ import { experimentStatusInfo } from '@/pages/Experiment/status';
import { type NodeStatus } from '@/types';
import { parseJsonText } from '@/utils';
import { elapsedTime } from '@/utils/date';
+import { formatDataset } from '@/utils/format';
import { Flex } from 'antd';
import classNames from 'classnames';
import { useMemo } from 'react';
@@ -15,14 +16,6 @@ import ConfigInfo, {
} from '../ConfigInfo';
import styles from './index.less';
-// 格式化数据集
-const formatDataset = (dataset: { name: string; version: string }) => {
- if (!dataset || !dataset.name || !dataset.version) {
- return '--';
- }
- return `${dataset.name}:${dataset.version}`;
-};
-
// 格式化优化方向
const formatOptimizeMode = (value: boolean) => {
return value ? '越大越好' : '越小越好';
diff --git a/react-ui/src/pages/AutoML/components/ConfigInfo/index.tsx b/react-ui/src/pages/AutoML/components/ConfigInfo/index.tsx
index 10e042e4..256f7b16 100644
--- a/react-ui/src/pages/AutoML/components/ConfigInfo/index.tsx
+++ b/react-ui/src/pages/AutoML/components/ConfigInfo/index.tsx
@@ -11,13 +11,15 @@ type ConfigInfoProps = {
labelWidth: number;
className?: string;
style?: React.CSSProperties;
+ children?: React.ReactNode;
};
-function ConfigInfo({ title, data, labelWidth, className, style }: ConfigInfoProps) {
+function ConfigInfo({ title, data, labelWidth, className, style, children }: ConfigInfoProps) {
return (
+ {children}
);
diff --git a/react-ui/src/pages/AutoML/components/ExperimentList/index.tsx b/react-ui/src/pages/AutoML/components/ExperimentList/index.tsx
index c0740eee..0da5ca9c 100644
--- a/react-ui/src/pages/AutoML/components/ExperimentList/index.tsx
+++ b/react-ui/src/pages/AutoML/components/ExperimentList/index.tsx
@@ -400,6 +400,7 @@ function ExperimentList({ type }: ExperimentListProps) {
expandable={{
expandedRowRender: (record) => (
gotoInstanceInfo(record, item)}
diff --git a/react-ui/src/pages/Dataset/components/ResourceIntro/index.tsx b/react-ui/src/pages/Dataset/components/ResourceIntro/index.tsx
index b0bad9de..807270a8 100644
--- a/react-ui/src/pages/Dataset/components/ResourceIntro/index.tsx
+++ b/react-ui/src/pages/Dataset/components/ResourceIntro/index.tsx
@@ -1,17 +1,8 @@
import BasicTableInfo, { BasicInfoData } from '@/components/BasicTableInfo';
import SubAreaTitle from '@/components/SubAreaTitle';
-import { ResourceInfoTabKeys } from '@/pages/Dataset/components/ResourceInfo';
-import {
- DataSource,
- DatasetData,
- ModelData,
- ProjectDependency,
- ResourceType,
- TrainTask,
- resourceConfig,
-} from '@/pages/Dataset/config';
+import { DatasetData, ModelData, ResourceType, resourceConfig } from '@/pages/Dataset/config';
import ModelMetrics from '@/pages/Model/components/ModelMetrics';
-import { getGitUrl } from '@/utils';
+import { formatCodeConfig, formatDatasets, formatSource, formatTrainTask } from '@/utils/format';
import classNames from 'classnames';
import styles from './index.less';
@@ -24,55 +15,6 @@ type ResourceIntroProps = {
version?: string;
};
-export const formatDataset = (datasets?: DatasetData[]) => {
- if (!datasets || datasets.length === 0) {
- return undefined;
- }
- return datasets.map((item) => ({
- value: item.name,
- url: `${origin}/dataset/dataset/info/${item.id}?tab=${ResourceInfoTabKeys.Version}&version=${item.version}&name=${item.name}&owner=${item.owner}&identifier=${item.identifier}`,
- }));
-};
-
-export const getProjectUrl = (project?: ProjectDependency) => {
- if (!project || !project.url || !project.branch) {
- return undefined;
- }
- const { url, branch } = project;
- return getGitUrl(url, branch);
-};
-
-export const formatProject = (project?: ProjectDependency) => {
- if (!project) {
- return undefined;
- }
- return {
- value: project.name,
- url: getProjectUrl(project),
- };
-};
-
-export const formatTrainTask = (task?: TrainTask) => {
- if (!task) {
- return undefined;
- }
- return {
- value: task.name,
- url: `${origin}/pipeline/experiment/instance/${task.workflow_id}/${task.ins_id}`,
- };
-};
-
-export const formatSource = (source?: string) => {
- if (source === DataSource.Create) {
- return '用户上传';
- } else if (source === DataSource.HandExport) {
- return '手动导入';
- } else if (source === DataSource.AtuoExport) {
- return '实验自动导入';
- }
- return source;
-};
-
const getDatasetDatas = (data: DatasetData): BasicInfoData[] => [
{
label: '数据集名称',
@@ -109,7 +51,7 @@ const getDatasetDatas = (data: DatasetData): BasicInfoData[] => [
{
label: '处理代码',
value: data.processing_code,
- format: formatProject,
+ format: formatCodeConfig,
ellipsis: true,
},
{
@@ -153,19 +95,19 @@ const getModelDatas = (data: ModelData): BasicInfoData[] => [
{
label: '训练代码',
value: data.project_depency,
- format: formatProject,
+ format: formatCodeConfig,
ellipsis: true,
},
{
label: '训练数据集',
value: data.train_datasets,
- format: formatDataset,
+ format: formatDatasets,
ellipsis: true,
},
{
label: '测试数据集',
value: data.test_datasets,
- format: formatDataset,
+ format: formatDatasets,
ellipsis: true,
},
{
diff --git a/react-ui/src/pages/Dataset/components/VersionCompareModal/index.tsx b/react-ui/src/pages/Dataset/components/VersionCompareModal/index.tsx
index 2ee76e78..7bafdf95 100644
--- a/react-ui/src/pages/Dataset/components/VersionCompareModal/index.tsx
+++ b/react-ui/src/pages/Dataset/components/VersionCompareModal/index.tsx
@@ -8,11 +8,11 @@ import {
resourceConfig,
} from '@/pages/Dataset/config';
import { isEmpty } from '@/utils';
+import { formatSource } from '@/utils/format';
import { to } from '@/utils/promise';
import { Typography, type ModalProps } from 'antd';
import classNames from 'classnames';
import { useEffect, useMemo, useState } from 'react';
-import { formatSource } from '../ResourceIntro';
import styles from './index.less';
type CompareData = {
@@ -47,10 +47,10 @@ const formatProject = (project?: ProjectDependency) => {
if (!project) {
return undefined;
}
- return project.name;
+ return `${project.name}:${project.branch}`;
};
-export const formatTrainTask = (task?: TrainTask) => {
+const formatTrainTask = (task?: TrainTask) => {
if (!task) {
return undefined;
}
diff --git a/react-ui/src/pages/HyperParameter/Create/index.tsx b/react-ui/src/pages/HyperParameter/Create/index.tsx
index dfe367ba..fa5fc8b8 100644
--- a/react-ui/src/pages/HyperParameter/Create/index.tsx
+++ b/react-ui/src/pages/HyperParameter/Create/index.tsx
@@ -41,10 +41,9 @@ function CreateHyperparameter() {
const name = isCopy ? `${name_str}-copy` : name_str;
if (parameters && Array.isArray(parameters)) {
parameters.forEach((item) => {
- item.range = item.bounds || item.values || item.value;
- delete item.bounds;
- delete item.values;
- delete item.value;
+ const paramName = getReqParamName(item.type);
+ item.range = item[paramName];
+ item[paramName] = undefined;
});
}
@@ -63,8 +62,6 @@ function CreateHyperparameter() {
const createExperiment = async (formData: FormData) => {
// 按后台接口要求,修改参数表单数据结构,将 "value" 参数改为 "bounds"/"values"/"value"
const parameters = formData['parameters'];
- // const points_to_evaluate = formData['points_to_evaluate'];
- // const runParameters = formData['parameters'];
parameters.forEach((item) => {
const paramName = getReqParamName(item.type);
item[paramName] = item.range;
@@ -142,7 +139,7 @@ function CreateHyperparameter() {
-
+
diff --git a/react-ui/src/pages/HyperParameter/Info/index.tsx b/react-ui/src/pages/HyperParameter/Info/index.tsx
index 8b2fded3..9a37a68f 100644
--- a/react-ui/src/pages/HyperParameter/Info/index.tsx
+++ b/react-ui/src/pages/HyperParameter/Info/index.tsx
@@ -3,48 +3,34 @@
* @Date: 2024-04-16 13:58:08
* @Description: 自主机器学习详情
*/
-import KFIcon from '@/components/KFIcon';
import PageTitle from '@/components/PageTitle';
-import { CommonTabKeys } from '@/enums';
-import { getAutoMLInfoReq } from '@/services/autoML';
+import { getRayInfoReq } from '@/services/hyperParameter';
import { safeInvoke } from '@/utils/functional';
import { to } from '@/utils/promise';
import { useParams } from '@umijs/max';
import { useEffect, useState } from 'react';
-import AutoMLBasic from '../components/AutoMLBasic';
+import HyperParameterBasic from '../components/HyperParameterBasic';
import { HyperparameterData } from '../types';
import styles from './index.less';
-function AutoMLInfo() {
- const [activeTab, setActiveTab] = useState(CommonTabKeys.Public);
+function HyperparameterInfo() {
const params = useParams();
- const autoMLId = safeInvoke(Number)(params.id);
- const [autoMLInfo, setAutoMLInfo] = useState(undefined);
-
- const tabItems = [
- {
- key: CommonTabKeys.Public,
- label: '基本信息',
- icon: ,
- },
- {
- key: CommonTabKeys.Private,
- label: 'Trial列表',
- icon: ,
- },
- ];
+ const hyperparameterId = safeInvoke(Number)(params.id);
+ const [hyperparameterInfo, setHyperparameterInfo] = useState(
+ undefined,
+ );
useEffect(() => {
- if (autoMLId) {
- getAutoMLInfo();
+ if (hyperparameterId) {
+ getHyperparameterInfo();
}
}, []);
// 获取自动机器学习详情
- const getAutoMLInfo = async () => {
- const [res] = await to(getAutoMLInfoReq({ id: autoMLId }));
+ const getHyperparameterInfo = async () => {
+ const [res] = await to(getRayInfoReq({ id: hyperparameterId }));
if (res && res.data) {
- setAutoMLInfo(res.data);
+ setHyperparameterInfo(res.data);
}
};
@@ -52,10 +38,10 @@ function AutoMLInfo() {
);
}
-export default AutoMLInfo;
+export default HyperparameterInfo;
diff --git a/react-ui/src/pages/HyperParameter/Instance/index.tsx b/react-ui/src/pages/HyperParameter/Instance/index.tsx
index 355ced01..8f7faa33 100644
--- a/react-ui/src/pages/HyperParameter/Instance/index.tsx
+++ b/react-ui/src/pages/HyperParameter/Instance/index.tsx
@@ -9,9 +9,9 @@ import { to } from '@/utils/promise';
import { useParams } from '@umijs/max';
import { Tabs } from 'antd';
import { useEffect, useRef, useState } from 'react';
-import AutoMLBasic from '../components/AutoMLBasic';
import ExperimentHistory from '../components/ExperimentHistory';
import ExperimentResult from '../components/ExperimentResult';
+import HyperParameterBasic from '../components/HyperParameterBasic';
import { AutoMLInstanceData, HyperparameterData } from '../types';
import styles from './index.less';
@@ -140,7 +140,7 @@ function AutoMLInstance() {
label: '基本信息',
icon: ,
children: (
- {
- if (!dataset || !dataset.name || !dataset.version) {
- return '--';
- }
- return `${dataset.name}:${dataset.version}`;
-};
-
-// 格式化优化方向
-const formatOptimizeMode = (value: boolean) => {
- return value ? '越大越好' : '越小越好';
-};
-
-const formatMetricsWeight = (value: string) => {
- if (!value) {
- return '--';
- }
- const json = parseJsonText(value);
- if (!json) {
- return '--';
- }
- return Object.entries(json)
- .map(([key, value]) => `${key}:${value}`)
- .join('\n');
-};
-
-type AutoMLBasicProps = {
- info?: AutoMLData;
- className?: string;
- isInstance?: boolean;
- runStatus?: NodeStatus;
-};
-
-function AutoMLBasic({ info, className, runStatus, isInstance = false }: AutoMLBasicProps) {
- const basicDatas: BasicInfoData[] = useMemo(() => {
- if (!info) {
- return [];
- }
-
- return [
- {
- label: '实验名称',
- value: info.ml_name,
- ellipsis: true,
- },
- {
- label: '实验描述',
- value: info.ml_description,
- ellipsis: true,
- },
- {
- label: '创建人',
- value: info.create_by,
- ellipsis: true,
- },
- {
- label: '创建时间',
- value: info.create_time,
- ellipsis: true,
- format: formatDate,
- },
- {
- label: '更新时间',
- value: info.update_time,
- ellipsis: true,
- format: formatDate,
- },
- ];
- }, [info]);
-
- const configDatas: BasicInfoData[] = useMemo(() => {
- if (!info) {
- return [];
- }
- return [
- {
- label: '任务类型',
- value: info.task_type,
- ellipsis: true,
- format: formatEnum(autoMLTaskTypeOptions),
- },
- {
- label: '特征预处理算法',
- value: info.include_feature_preprocessor,
- ellipsis: true,
- },
- {
- label: '排除的特征预处理算法',
- value: info.exclude_feature_preprocessor,
- ellipsis: true,
- },
- {
- label: info.task_type === AutoMLTaskType.Regression ? '回归算法' : '分类算法',
- value:
- info.task_type === AutoMLTaskType.Regression
- ? info.include_regressor
- : info.include_classifier,
- ellipsis: true,
- },
- {
- label: info.task_type === AutoMLTaskType.Regression ? '排除的回归算法' : '排除的分类算法',
- value:
- info.task_type === AutoMLTaskType.Regression
- ? info.exclude_regressor
- : info.exclude_classifier,
- ellipsis: true,
- },
- {
- label: '集成方式',
- value: info.ensemble_class,
- ellipsis: true,
- format: formatEnum(autoMLEnsembleClassOptions),
- },
- {
- label: '集成模型数量',
- value: info.ensemble_size,
- ellipsis: true,
- },
- {
- label: '集成最佳模型数量',
- value: info.ensemble_nbest,
- ellipsis: true,
- },
- {
- label: '最大数量',
- value: info.max_models_on_disc,
- ellipsis: true,
- },
- {
- label: '内存限制(MB)',
- value: info.memory_limit,
- ellipsis: true,
- },
- {
- label: '单次时间限制(秒)',
- value: info.per_run_time_limit,
- ellipsis: true,
- },
- {
- label: '搜索时间限制(秒)',
- value: info.time_left_for_this_task,
- ellipsis: true,
- },
- {
- label: '重采样策略',
- value: info.resampling_strategy,
- ellipsis: true,
- },
- {
- label: '交叉验证折数',
- value: info.folds,
- ellipsis: true,
- },
- {
- label: '是否打乱',
- value: info.shuffle,
- ellipsis: true,
- format: formatBoolean,
- },
- {
- label: '训练集比率',
- value: info.train_size,
- ellipsis: true,
- },
- {
- label: '测试集比率',
- value: info.test_size,
- ellipsis: true,
- },
- {
- label: '计算指标',
- value: info.scoring_functions,
- ellipsis: true,
- },
- {
- label: '随机种子',
- value: info.seed,
- ellipsis: true,
- },
-
- {
- label: '数据集',
- value: info.dataset,
- ellipsis: true,
- format: formatDataset,
- },
- {
- label: '预测目标列',
- value: info.target_columns,
- ellipsis: true,
- },
- ];
- }, [info]);
-
- const metricsData = useMemo(() => {
- if (!info) {
- return [];
- }
- return [
- {
- label: '指标名称',
- value: info.metric_name,
- ellipsis: true,
- },
- {
- label: '优化方向',
- value: info.greater_is_better,
- ellipsis: true,
- format: formatOptimizeMode,
- },
- {
- label: '指标权重',
- value: info.metrics,
- ellipsis: true,
- format: formatMetricsWeight,
- },
- ];
- }, [info]);
-
- const instanceDatas = useMemo(() => {
- if (!runStatus) {
- return [];
- }
-
- return [
- {
- label: '启动时间',
- value: formatDate(runStatus.startedAt),
- ellipsis: true,
- },
- {
- label: '执行时长',
- value: elapsedTime(runStatus.startedAt, runStatus.finishedAt),
- ellipsis: true,
- },
- {
- label: '状态',
- value: (
-
-
-
- {experimentStatusInfo[runStatus?.phase]?.label}
-
-
- ),
- ellipsis: true,
- },
- ];
- }, [runStatus]);
-
- return (
-
- {isInstance && runStatus && (
-
- )}
- {!isInstance && (
-
- )}
-
-
-
- );
-}
-
-export default AutoMLBasic;
diff --git a/react-ui/src/pages/HyperParameter/components/ConfigInfo/index.less b/react-ui/src/pages/HyperParameter/components/ConfigInfo/index.less
deleted file mode 100644
index 33fb3314..00000000
--- a/react-ui/src/pages/HyperParameter/components/ConfigInfo/index.less
+++ /dev/null
@@ -1,20 +0,0 @@
-.config-info {
- :global {
- .kf-basic-info {
- width: 100%;
-
- &__item {
- width: calc((100% - 80px) / 3);
- &__label {
- font-size: @font-size;
- text-align: left;
- text-align-last: left;
- }
- &__value {
- min-width: 0;
- font-size: @font-size;
- }
- }
- }
- }
-}
diff --git a/react-ui/src/pages/HyperParameter/components/ConfigInfo/index.tsx b/react-ui/src/pages/HyperParameter/components/ConfigInfo/index.tsx
deleted file mode 100644
index 10e042e4..00000000
--- a/react-ui/src/pages/HyperParameter/components/ConfigInfo/index.tsx
+++ /dev/null
@@ -1,26 +0,0 @@
-import BasicInfo, { type BasicInfoData } from '@/components/BasicInfo';
-import InfoGroup from '@/components/InfoGroup';
-import classNames from 'classnames';
-import styles from './index.less';
-export * from '@/components/BasicInfo/format';
-export type { BasicInfoData };
-
-type ConfigInfoProps = {
- title: string;
- data: BasicInfoData[];
- labelWidth: number;
- className?: string;
- style?: React.CSSProperties;
-};
-
-function ConfigInfo({ title, data, labelWidth, className, style }: ConfigInfoProps) {
- return (
-
-
-
-
-
- );
-}
-
-export default ConfigInfo;
diff --git a/react-ui/src/pages/HyperParameter/components/CreateForm/ExecuteConfig.tsx b/react-ui/src/pages/HyperParameter/components/CreateForm/ExecuteConfig.tsx
index 92e7f961..86760130 100644
--- a/react-ui/src/pages/HyperParameter/components/CreateForm/ExecuteConfig.tsx
+++ b/react-ui/src/pages/HyperParameter/components/CreateForm/ExecuteConfig.tsx
@@ -5,6 +5,7 @@ import ResourceSelect, {
requiredValidator,
} from '@/components/ResourceSelect';
import SubAreaTitle from '@/components/SubAreaTitle';
+import { hyperParameterOptimizedModeOptions } from '@/enums';
import { modalConfirm } from '@/utils/ui';
import { MinusCircleOutlined, PlusCircleOutlined } from '@ant-design/icons';
import { Button, Col, Flex, Form, Input, InputNumber, Radio, Row, Select } from 'antd';
@@ -456,10 +457,7 @@ function ExecuteConfig() {
name="mode"
rules={[{ required: true, message: '请选择优化方向' }]}
>
-
- 越大越好
- 越小越好
-
+
@@ -467,16 +465,16 @@ function ExecuteConfig() {
-
+
@@ -484,16 +482,16 @@ function ExecuteConfig() {
-
+
diff --git a/react-ui/src/pages/HyperParameter/components/CreateForm/PopParameterRange/index.less b/react-ui/src/pages/HyperParameter/components/CreateForm/PopParameterRange/index.less
index 01faf3d0..8f0a0f97 100644
--- a/react-ui/src/pages/HyperParameter/components/CreateForm/PopParameterRange/index.less
+++ b/react-ui/src/pages/HyperParameter/components/CreateForm/PopParameterRange/index.less
@@ -1,5 +1,8 @@
.parameter-range {
:global {
+ .ant-popover-inner {
+ padding: 20px 20px 12px;
+ }
.ant-popconfirm-description {
padding-top: 20px;
}
@@ -22,15 +25,6 @@
border-radius: 8px;
cursor: pointer;
- &:hover {
- border-color: #4086ff;
- }
-
- &--disabled {
- background-color: rgba(0, 0, 0, 0.04);
- cursor: not-allowed;
- }
-
&__text {
flex: 1;
margin-right: 10px;
@@ -40,8 +34,22 @@
flex: none;
}
- &--disabled &__icon {
- color: @text-color-tertiary;
+ &:hover {
+ border-color: #4086ff;
+ }
+
+ &:hover &__icon {
+ color: #4086ff;
+ }
+
+ &&--disabled {
+ background-color: rgba(0, 0, 0, 0.04);
+ border-color: rgba(0, 0, 0, 0.04) !important;
+ cursor: not-allowed;
+ }
+
+ &&--disabled &__icon {
+ color: #aaaaaa !important;
}
}
}
diff --git a/react-ui/src/pages/HyperParameter/components/CreateForm/index.less b/react-ui/src/pages/HyperParameter/components/CreateForm/index.less
index fcb77fdd..8f8bae7b 100644
--- a/react-ui/src/pages/HyperParameter/components/CreateForm/index.less
+++ b/react-ui/src/pages/HyperParameter/components/CreateForm/index.less
@@ -92,12 +92,13 @@
.run-parameter {
width: calc(41.66% + 126px);
margin-bottom: 20px;
- border-radius: 8px;
+
&__body {
flex: 1;
margin-right: 10px;
padding: 20px 20px 0;
- border: 1px dashed @border-color-base;
+ border: 1px dashed #dddddd;
+ border-radius: 8px;
}
&__operation {
display: flex;
diff --git a/react-ui/src/pages/HyperParameter/components/AutoMLBasic/index.less b/react-ui/src/pages/HyperParameter/components/HyperParameterBasic/index.less
similarity index 89%
rename from react-ui/src/pages/HyperParameter/components/AutoMLBasic/index.less
rename to react-ui/src/pages/HyperParameter/components/HyperParameterBasic/index.less
index cbd05bcc..f365aa66 100644
--- a/react-ui/src/pages/HyperParameter/components/AutoMLBasic/index.less
+++ b/react-ui/src/pages/HyperParameter/components/HyperParameterBasic/index.less
@@ -1,4 +1,4 @@
-.auto-ml-basic {
+.hyper-parameter-basic {
height: 100%;
padding: 20px @content-padding;
overflow-y: auto;
diff --git a/react-ui/src/pages/HyperParameter/components/HyperParameterBasic/index.tsx b/react-ui/src/pages/HyperParameter/components/HyperParameterBasic/index.tsx
new file mode 100644
index 00000000..167cbbe4
--- /dev/null
+++ b/react-ui/src/pages/HyperParameter/components/HyperParameterBasic/index.tsx
@@ -0,0 +1,207 @@
+import { hyperParameterOptimizedMode } from '@/enums';
+import ConfigInfo, { formatDate, type BasicInfoData } from '@/pages/AutoML/components/ConfigInfo';
+import { experimentStatusInfo } from '@/pages/Experiment/status';
+import { HyperparameterData } from '@/pages/HyperParameter/types';
+import { type NodeStatus } from '@/types';
+import { elapsedTime } from '@/utils/date';
+import { formatDataset, formatSelectCodeConfig } from '@/utils/format';
+import { Flex } from 'antd';
+import classNames from 'classnames';
+import { useMemo } from 'react';
+import ParameterInfo from '../ParameterInfo';
+import styles from './index.less';
+
+// 格式化优化方向
+const formatOptimizeMode = (value: string) => {
+ return value === hyperParameterOptimizedMode.Max ? '越大越好' : '越小越好';
+};
+
+type HyperParameterBasicProps = {
+ info?: HyperparameterData;
+ className?: string;
+ isInstance?: boolean;
+ runStatus?: NodeStatus;
+};
+
+function HyperParameterBasic({
+ info,
+ className,
+ runStatus,
+ isInstance = false,
+}: HyperParameterBasicProps) {
+ const basicDatas: BasicInfoData[] = useMemo(() => {
+ if (!info) {
+ return [];
+ }
+
+ return [
+ {
+ label: '实验名称',
+ value: info.name,
+ ellipsis: true,
+ },
+ {
+ label: '实验描述',
+ value: info.description,
+ ellipsis: true,
+ },
+ {
+ label: '创建人',
+ value: info.create_by,
+ ellipsis: true,
+ },
+ {
+ label: '创建时间',
+ value: info.create_time,
+ ellipsis: true,
+ format: formatDate,
+ },
+ {
+ label: '更新时间',
+ value: info.update_time,
+ ellipsis: true,
+ format: formatDate,
+ },
+ ];
+ }, [info]);
+
+ const configDatas: BasicInfoData[] = useMemo(() => {
+ if (!info) {
+ return [];
+ }
+ return [
+ {
+ label: '代码',
+ value: info.code,
+ ellipsis: true,
+ format: formatSelectCodeConfig,
+ },
+ {
+ label: '主函数代码文件',
+ value: info.main_py,
+ ellipsis: true,
+ },
+ {
+ label: '数据集',
+ value: info.dataset,
+ ellipsis: true,
+ format: formatDataset,
+ },
+
+ {
+ label: '数据集挂载路径',
+ value: info.dataset_path,
+ ellipsis: true,
+ },
+ {
+ label: '总实验次数',
+ value: info.num_samples,
+ ellipsis: true,
+ },
+ {
+ label: '搜索算法',
+ value: info.search_alg,
+ ellipsis: true,
+ },
+ {
+ label: '调度算法',
+ value: info.scheduler,
+ ellipsis: true,
+ },
+ {
+ label: '优化方向',
+ value: info.mode,
+ ellipsis: true,
+ format: formatOptimizeMode,
+ },
+ {
+ label: '指标',
+ value: info.metric,
+ ellipsis: true,
+ },
+ {
+ label: 'CPU 数量',
+ value: info.cpu,
+ ellipsis: true,
+ },
+ {
+ label: 'GPU 数量',
+ value: info.gpu,
+ ellipsis: true,
+ },
+ ];
+ }, [info]);
+
+ const instanceDatas = useMemo(() => {
+ if (!runStatus) {
+ return [];
+ }
+
+ return [
+ {
+ label: '启动时间',
+ value: formatDate(runStatus.startedAt),
+ ellipsis: true,
+ },
+ {
+ label: '执行时长',
+ value: elapsedTime(runStatus.startedAt, runStatus.finishedAt),
+ ellipsis: true,
+ },
+ {
+ label: '状态',
+ value: (
+
+
+
+ {experimentStatusInfo[runStatus?.phase]?.label}
+
+
+ ),
+ ellipsis: true,
+ },
+ ];
+ }, [runStatus]);
+
+ return (
+
+ {isInstance && runStatus && (
+
+ )}
+ {!isInstance && (
+
+ )}
+
+ {info && }
+
+
+ );
+}
+
+export default HyperParameterBasic;
diff --git a/react-ui/src/pages/HyperParameter/components/ParameterInfo/index.less b/react-ui/src/pages/HyperParameter/components/ParameterInfo/index.less
new file mode 100644
index 00000000..81d6fd56
--- /dev/null
+++ b/react-ui/src/pages/HyperParameter/components/ParameterInfo/index.less
@@ -0,0 +1,7 @@
+.parameter-info {
+ &__title {
+ margin: 20px 0;
+ color: @text-color-secondary;
+ font-size: @font-size;
+ }
+}
diff --git a/react-ui/src/pages/HyperParameter/components/ParameterInfo/index.tsx b/react-ui/src/pages/HyperParameter/components/ParameterInfo/index.tsx
new file mode 100644
index 00000000..9b415d85
--- /dev/null
+++ b/react-ui/src/pages/HyperParameter/components/ParameterInfo/index.tsx
@@ -0,0 +1,108 @@
+import {
+ getReqParamName,
+ type FormParameter,
+} from '@/pages/HyperParameter/components/CreateForm/utils';
+import { HyperparameterData } from '@/pages/HyperParameter/types';
+import tableCellRender, { TableCellValueType } from '@/utils/table';
+import { Table, Tooltip, type TableProps } from 'antd';
+import { useMemo } from 'react';
+import styles from './index.less';
+
+type ParameterInfoProps = {
+ info: HyperparameterData;
+};
+
+function ParameterInfo({ info }: ParameterInfoProps) {
+ const parameters = useMemo(() => {
+ if (!info.parameters) {
+ return [];
+ }
+ return info.parameters.map((item) => {
+ const paramName = getReqParamName(item.type);
+ const range = item[paramName];
+ return {
+ ...item,
+ range,
+ };
+ });
+ }, [info]);
+
+ const runParameters = useMemo(() => {
+ if (!info.points_to_evaluate) {
+ return [];
+ }
+ return info.points_to_evaluate.map((item, index) => ({
+ ...item,
+ id: index,
+ }));
+ }, [info]);
+
+ const columns: TableProps['columns'] = [
+ {
+ title: '参数名称',
+ dataIndex: 'name',
+ key: 'type',
+ width: '40%',
+ render: tableCellRender(true),
+ ellipsis: { showTitle: false },
+ },
+ {
+ title: '参数类型',
+ dataIndex: 'type',
+ key: 'type',
+ width: '20%',
+ render: tableCellRender(true),
+ ellipsis: { showTitle: false },
+ },
+ {
+ title: '取值范围',
+ dataIndex: 'range',
+ key: 'range',
+ width: '40%',
+ render: tableCellRender(true, TableCellValueType.Custom, {
+ format: (value) => {
+ return JSON.stringify(value);
+ },
+ }),
+ ellipsis: { showTitle: false },
+ },
+ ];
+
+ const runColumns: TableProps>['columns'] =
+ runParameters.length > 0
+ ? Object.keys(runParameters[0])
+ .filter((key) => key !== 'id')
+ .map((key) => {
+ return {
+ title: (
+
+ {key}
+
+ ),
+ dataIndex: key,
+ key: key,
+ width: 150,
+ render: tableCellRender(true),
+ ellipsis: { showTitle: false },
+ };
+ })
+ : [];
+
+ return (
+
+ );
+}
+
+export default ParameterInfo;
diff --git a/react-ui/src/pages/HyperParameter/types.ts b/react-ui/src/pages/HyperParameter/types.ts
index 3eec723c..bb412c09 100644
--- a/react-ui/src/pages/HyperParameter/types.ts
+++ b/react-ui/src/pages/HyperParameter/types.ts
@@ -16,7 +16,7 @@ export type FormData = {
dataset: ParameterInputObject; // 数据集
dataset_path: string; // 数据集路径
main_py: string; // 主函数代码文件
- metrics: string; // 指标
+ metric: string; // 指标
mode: string; // 优化方向
search_alg?: string; // 搜索算法
scheduler?: string; // 调度算法
diff --git a/react-ui/src/utils/format.ts b/react-ui/src/utils/format.ts
new file mode 100644
index 00000000..579ae103
--- /dev/null
+++ b/react-ui/src/utils/format.ts
@@ -0,0 +1,87 @@
+import { ResourceInfoTabKeys } from '@/pages/Dataset/components/ResourceInfo';
+import { DataSource, DatasetData, ProjectDependency, TrainTask } from '@/pages/Dataset/config';
+import { getGitUrl } from '@/utils';
+
+// 格式化数据集数组
+export const formatDatasets = (datasets?: DatasetData[]) => {
+ if (!datasets || datasets.length === 0) {
+ return undefined;
+ }
+ return datasets.map((item) => ({
+ value: item.name,
+ url: `${origin}/dataset/dataset/info/${item.id}?tab=${ResourceInfoTabKeys.Introduction}&version=${item.version}&name=${item.name}&owner=${item.owner}&identifier=${item.identifier}`,
+ }));
+};
+
+// 格式化数据集
+export const formatDataset = (dataset?: DatasetData) => {
+ if (!dataset) {
+ return undefined;
+ }
+ return {
+ value: dataset.name,
+ url: `${origin}/dataset/dataset/info/${dataset.id}?tab=${ResourceInfoTabKeys.Introduction}&version=${dataset.version}&name=${dataset.name}&owner=${dataset.owner}&identifier=${dataset.identifier}`,
+ };
+};
+
+// 获取代码配置的仓库的 url
+export const getRepoUrl = (project?: ProjectDependency) => {
+ if (!project) {
+ return undefined;
+ }
+ const { url, branch } = project;
+ return getGitUrl(url, branch);
+};
+
+// 格式化代码配置
+export const formatCodeConfig = (project?: ProjectDependency) => {
+ if (!project) {
+ return undefined;
+ }
+ return {
+ value: project.name,
+ url: getRepoUrl(project),
+ };
+};
+
+// 格式化选中的代码配置
+export const formatSelectCodeConfig = (value?: {
+ code_path: string;
+ branch: string;
+ showValue: string;
+}) => {
+ if (!value) {
+ return undefined;
+ }
+ const { showValue, code_path, branch } = value;
+ return {
+ value: showValue,
+ url: getRepoUrl({
+ url: code_path,
+ branch,
+ } as ProjectDependency),
+ };
+};
+
+// 格式化训练任务(实验实例)
+export const formatTrainTask = (task?: TrainTask) => {
+ if (!task) {
+ return undefined;
+ }
+ return {
+ value: task.name,
+ url: `${origin}/pipeline/experiment/instance/${task.workflow_id}/${task.ins_id}`,
+ };
+};
+
+// 格式化数据来源
+export const formatSource = (source?: string) => {
+ if (source === DataSource.Create) {
+ return '用户上传';
+ } else if (source === DataSource.HandExport) {
+ return '手动导入';
+ } else if (source === DataSource.AtuoExport) {
+ return '实验自动导入';
+ }
+ return source;
+};