Browse Source

feat: 完成自动机器学习实验实例详情

pull/146/head
cp3hnu 1 year ago
parent
commit
1b70a295f4
23 changed files with 368 additions and 278 deletions
  1. +4
    -4
      react-ui/src/app.tsx
  2. BIN
      react-ui/src/assets/img/resample-icon.png
  3. +1
    -1
      react-ui/src/enums/index.ts
  4. +1
    -1
      react-ui/src/global.less
  5. +1
    -1
      react-ui/src/iconfont/iconfont.js
  6. +19
    -4
      react-ui/src/pages/AutoML/Create/index.tsx
  7. +3
    -14
      react-ui/src/pages/AutoML/Info/index.tsx
  8. +33
    -8
      react-ui/src/pages/AutoML/Instance/index.less
  9. +115
    -33
      react-ui/src/pages/AutoML/Instance/index.tsx
  10. +62
    -5
      react-ui/src/pages/AutoML/components/AutoMLBasic/index.tsx
  11. +2
    -2
      react-ui/src/pages/AutoML/components/ConfigInfo/index.less
  12. +1
    -0
      react-ui/src/pages/AutoML/components/ConfigTitle/index.less
  13. +47
    -41
      react-ui/src/pages/AutoML/components/CreateForm/ExecuteConfig.tsx
  14. +1
    -135
      react-ui/src/pages/AutoML/components/CreateForm/index.less
  15. +3
    -3
      react-ui/src/pages/AutoML/components/ExperimentHistory/index.less
  16. +27
    -6
      react-ui/src/pages/AutoML/components/ExperimentResult/index.less
  17. +14
    -9
      react-ui/src/pages/AutoML/components/ExperimentResult/index.tsx
  18. +2
    -1
      react-ui/src/pages/AutoML/types.ts
  19. +6
    -0
      react-ui/src/pages/Experiment/components/ExperimentDrawer/index.less
  20. +10
    -8
      react-ui/src/pages/Experiment/components/ExperimentDrawer/index.tsx
  21. +1
    -1
      react-ui/src/pages/Experiment/components/LogGroup/index.tsx
  22. +5
    -1
      react-ui/src/pages/Experiment/components/LogList/index.less
  23. +10
    -0
      react-ui/src/types.ts

+ 4
- 4
react-ui/src/app.tsx View File

@@ -50,7 +50,7 @@ export async function getInitialState(): Promise<GlobalInitialState> {
// 如果不是登录页面,执行 // 如果不是登录页面,执行
const { location } = history; const { location } = history;


console.log('getInitialState', needAuth(location.pathname));
// console.log('getInitialState', needAuth(location.pathname));
if (needAuth(location.pathname)) { if (needAuth(location.pathname)) {
const currentUser = await fetchUserInfo(); const currentUser = await fetchUserInfo();
return { return {
@@ -163,7 +163,7 @@ export const layout: RuntimeConfig['layout'] = ({ initialState }) => {
export const onRouteChange: RuntimeConfig['onRouteChange'] = async (e) => { export const onRouteChange: RuntimeConfig['onRouteChange'] = async (e) => {
const { location } = e; const { location } = e;
const menus = getRemoteMenu(); const menus = getRemoteMenu();
console.log('onRouteChange', menus);
// console.log('onRouteChange', menus);
if (menus === null && needAuth(location.pathname)) { if (menus === null && needAuth(location.pathname)) {
history.go(0); history.go(0);
} }
@@ -174,12 +174,12 @@ export const patchRoutes: RuntimeConfig['patchRoutes'] = (e) => {
}; };


export const patchClientRoutes: RuntimeConfig['patchClientRoutes'] = (e) => { export const patchClientRoutes: RuntimeConfig['patchClientRoutes'] = (e) => {
console.log('patchClientRoutes', e);
// console.log('patchClientRoutes', e);
patchRouteWithRemoteMenus(e.routes); patchRouteWithRemoteMenus(e.routes);
}; };


export function render(oldRender: () => void) { export function render(oldRender: () => void) {
console.log('render');
// console.log('render');
const token = getAccessToken(); const token = getAccessToken();
if (!token || token?.length === 0) { if (!token || token?.length === 0) {
oldRender(); oldRender();


BIN
react-ui/src/assets/img/resample-icon.png View File

Before After
Width: 51  |  Height: 51  |  Size: 1.3 kB

+ 1
- 1
react-ui/src/enums/index.ts View File

@@ -18,9 +18,9 @@ export enum AvailableRange {


// 实验状态 // 实验状态
export enum ExperimentStatus { export enum ExperimentStatus {
Pending = 'Pending', // 启动中
Running = 'Running', // 运行中 Running = 'Running', // 运行中
Succeeded = 'Succeeded', // 成功 Succeeded = 'Succeeded', // 成功
Pending = 'Pending', // 启动中
Failed = 'Failed', // 失败 Failed = 'Failed', // 失败
Error = 'Error', // 错误 Error = 'Error', // 错误
Terminated = 'Terminated', // 终止 Terminated = 'Terminated', // 终止


+ 1
- 1
react-ui/src/global.less View File

@@ -43,7 +43,7 @@ body {
} }


.ant-pro-layout .ant-pro-sider-menu { .ant-pro-layout .ant-pro-sider-menu {
padding-top: 40px;
padding-top: 15px;
} }
.ant-pro-global-header-logo-mix { .ant-pro-global-header-logo-mix {
padding-left: 12px; padding-left: 12px;


+ 1
- 1
react-ui/src/iconfont/iconfont.js
File diff suppressed because it is too large
View File


+ 19
- 4
react-ui/src/pages/AutoML/Create/index.tsx View File

@@ -104,10 +104,15 @@ function CreateAutoML() {
const exclude_classifier = formData['exclude_classifier']?.join(','); const exclude_classifier = formData['exclude_classifier']?.join(',');
const exclude_feature_preprocessor = formData['exclude_feature_preprocessor']?.join(','); const exclude_feature_preprocessor = formData['exclude_feature_preprocessor']?.join(',');
const exclude_regressor = formData['exclude_regressor']?.join(','); const exclude_regressor = formData['exclude_regressor']?.join(',');
const metrics = formData['metrics']?.reduce((acc, cur) => {
acc[cur.name] = cur.value;
return acc;
}, {} as Record<string, number>);
const formMetrics = formData['metrics'];
const metrics =
formMetrics && Array.isArray(formMetrics) && formMetrics.length > 0
? formMetrics.reduce((acc, cur) => {
acc[cur.name] = cur.value;
return acc;
}, {} as Record<string, number>)
: undefined;

const target_columns = trimCharacter(formData['target_columns'], ','); const target_columns = trimCharacter(formData['target_columns'], ',');


// 根据后台要求,修改表单数据 // 根据后台要求,修改表单数据
@@ -174,6 +179,16 @@ function CreateAutoML() {
shuffle: false, shuffle: false,
ensemble_class: AutoMLEnsembleClass.Default, ensemble_class: AutoMLEnsembleClass.Default,
greater_is_better: true, greater_is_better: true,
ensemble_size: 50,
ensemble_nbest: 50,
max_models_on_disc: 50,
memory_limit: 3072,
per_run_time_limit: 600,
time_left_for_this_task: 3600,
resampling_strategy: 'holdout',
test_size: 0.25,
train_size: 0.67,
seed: 1,
}} }}
> >
<BasicConfig /> <BasicConfig />


+ 3
- 14
react-ui/src/pages/AutoML/Info/index.tsx View File

@@ -4,16 +4,14 @@
* @Description: 自主机器学习详情 * @Description: 自主机器学习详情
*/ */
import KFIcon from '@/components/KFIcon'; import KFIcon from '@/components/KFIcon';
import PageTitle from '@/components/PageTitle';
import { CommonTabKeys } from '@/enums'; import { CommonTabKeys } from '@/enums';
import { getAutoMLInfoReq } from '@/services/autoML'; import { getAutoMLInfoReq } from '@/services/autoML';
import themes from '@/styles/theme.less';
import { safeInvoke } from '@/utils/functional'; import { safeInvoke } from '@/utils/functional';
import { to } from '@/utils/promise'; import { to } from '@/utils/promise';
import { useParams } from '@umijs/max'; import { useParams } from '@umijs/max';
import { Tabs } from 'antd';
import { useEffect, useState } from 'react'; import { useEffect, useState } from 'react';
import AutoMLBasic from '../components/AutoMLBasic'; import AutoMLBasic from '../components/AutoMLBasic';
import AutoMLTable from '../components/AutoMLTable';
import { AutoMLData } from '../types'; import { AutoMLData } from '../types';
import styles from './index.less'; import styles from './index.less';


@@ -52,19 +50,10 @@ function AutoMLInfo() {


return ( return (
<div className={styles['auto-ml-info']}> <div className={styles['auto-ml-info']}>
<div className={styles['auto-ml-info__tabs']}>
<Tabs items={tabItems} activeKey={activeTab} onChange={setActiveTab} />
</div>
<PageTitle title="实验详情"></PageTitle>
<div className={styles['auto-ml-info__content']}> <div className={styles['auto-ml-info__content']}>
{activeTab === CommonTabKeys.Public && <AutoMLBasic info={autoMLInfo} />}
{activeTab === CommonTabKeys.Private && <AutoMLTable />}
<AutoMLBasic info={autoMLInfo} />
</div> </div>
{activeTab === CommonTabKeys.Private && (
<div className={styles['auto-ml-info__tips']}>
<KFIcon type="icon-tishi" color={themes['warningColor']} font={17} />
<span style={{ marginLeft: '4px' }}>Trial是一次独立的尝试,他会使用某组超参来运行</span>
</div>
)}
</div> </div>
); );
} }


+ 33
- 8
react-ui/src/pages/AutoML/Instance/index.less View File

@@ -2,16 +2,41 @@
height: 100%; height: 100%;


&__tabs { &__tabs {
height: 50px;
padding-left: 25px;
background-image: url(@/assets/img/page-title-bg.png);
background-repeat: no-repeat;
background-position: top center;
background-size: 100% 100%;
height: 100%;
:global {
.ant-tabs-nav-list {
width: 100%;
height: 50px;
padding-left: 15px;
background-image: url(@/assets/img/page-title-bg.png);
background-repeat: no-repeat;
background-position: top center;
background-size: 100% 100%;
}

.ant-tabs-content-holder {
height: calc(100% - 50px);
.ant-tabs-content {
height: 100%;
.ant-tabs-tabpane {
height: 100%;
}
}
}
}
}

&__basic {
height: calc(100% - 10px);
margin-top: 10px;
} }


&__content {
height: calc(100% - 60px);
&__log {
height: calc(100% - 10px);
margin-top: 10px; margin-top: 10px;
padding: 20px calc(@content-padding - 8px);
overflow-y: visible;
background-color: white;
border-radius: 10px;
} }
} }

+ 115
- 33
react-ui/src/pages/AutoML/Instance/index.tsx View File

@@ -2,12 +2,13 @@ import KFIcon from '@/components/KFIcon';
import { AutoMLTaskType, ExperimentStatus } from '@/enums'; import { AutoMLTaskType, ExperimentStatus } from '@/enums';
import LogList from '@/pages/Experiment/components/LogList'; import LogList from '@/pages/Experiment/components/LogList';
import { getExperimentInsReq } from '@/services/autoML'; import { getExperimentInsReq } from '@/services/autoML';
import { NodeStatus } from '@/types';
import { parseJsonText } from '@/utils'; import { parseJsonText } from '@/utils';
import { safeInvoke } from '@/utils/functional'; import { safeInvoke } from '@/utils/functional';
import { to } from '@/utils/promise'; import { to } from '@/utils/promise';
import { useParams } from '@umijs/max'; import { useParams } from '@umijs/max';
import { Tabs } from 'antd'; import { Tabs } from 'antd';
import { useEffect, useState } from 'react';
import { useEffect, useRef, useState } from 'react';
import AutoMLBasic from '../components/AutoMLBasic'; import AutoMLBasic from '../components/AutoMLBasic';
import ExperimentHistory from '../components/ExperimentHistory'; import ExperimentHistory from '../components/ExperimentHistory';
import ExperimentResult from '../components/ExperimentResult'; import ExperimentResult from '../components/ExperimentResult';
@@ -28,11 +29,15 @@ function AutoMLInstance() {
const params = useParams(); const params = useParams();
// const autoMLId = safeInvoke(Number)(params.autoMLId); // const autoMLId = safeInvoke(Number)(params.autoMLId);
const instanceId = safeInvoke(Number)(params.id); const instanceId = safeInvoke(Number)(params.id);
const evtSourceRef = useRef<EventSource | null>(null);


useEffect(() => { useEffect(() => {
if (instanceId) { if (instanceId) {
getExperimentInsInfo(); getExperimentInsInfo();
} }
return () => {
closeSSE();
};
}, []); }, []);


// 获取实验实例详情 // 获取实验实例详情
@@ -40,7 +45,7 @@ function AutoMLInstance() {
const [res] = await to(getExperimentInsReq(instanceId)); const [res] = await to(getExperimentInsReq(instanceId));
if (res && res.data) { if (res && res.data) {
const info = res.data as AutoMLInstanceData; const info = res.data as AutoMLInstanceData;
const { param, node_status } = info;
const { param, node_status, argo_ins_name, argo_ins_ns, status } = info;
// 解析配置参数 // 解析配置参数
const paramJson = parseJsonText(param); const paramJson = parseJsonText(param);
if (paramJson) { if (paramJson) {
@@ -52,65 +57,142 @@ function AutoMLInstance() {
Object.keys(nodeStatusJson).forEach((key) => { Object.keys(nodeStatusJson).forEach((key) => {
if (key.startsWith('auto-ml')) { if (key.startsWith('auto-ml')) {
const value = nodeStatusJson[key]; const value = nodeStatusJson[key];
value.nodeId = key;
info.nodeStatus = value; info.nodeStatus = value;
} }
}); });
} }
setInstanceInfo(info); setInstanceInfo(info);
// 运行中或者等待中,开启 SSE
if (status === ExperimentStatus.Pending || status === ExperimentStatus.Running) {
setupSSE(argo_ins_name, argo_ins_ns);
}
} }
}; };


const tabItems = [
const setupSSE = (name: string, namespace: string) => {
let { origin } = location;
if (process.env.NODE_ENV === 'development') {
origin = 'http://172.20.32.181:31213';
}
const params = encodeURIComponent(`metadata.namespace=${namespace},metadata.name=${name}`);
const evtSource = new EventSource(
`${origin}/api/v1/realtimeStatus?listOptions.fieldSelector=${params}`,
{ withCredentials: false },
);
evtSource.onmessage = (event) => {
const data = event?.data;
if (!data) {
return;
}
const dataJson = parseJsonText(data);
if (dataJson) {
const nodes = dataJson?.result?.object?.status?.nodes;
if (nodes) {
const statusData = Object.values(nodes).find((node: any) =>
node.displayName.startsWith('auto-ml'),
) as NodeStatus;
if (statusData) {
setInstanceInfo((prev) => ({
...(prev as AutoMLInstanceData),
nodeStatus: statusData,
}));

// 实验结束,关闭 SSE
if (
statusData.phase !== ExperimentStatus.Pending &&
statusData.phase !== ExperimentStatus.Running
) {
closeSSE();
getExperimentInsInfo();
}
}
}
}
};
evtSource.onerror = (error) => {
console.error('SSE error: ', error);
};

evtSourceRef.current = evtSource;
};

const closeSSE = () => {
if (evtSourceRef.current) {
evtSourceRef.current.close();
evtSourceRef.current = null;
}
};

const basicTabItems = [
{ {
key: TabKeys.Params, key: TabKeys.Params,
label: '参数信息',
label: '基本信息',
icon: <KFIcon type="icon-jibenxinxi" />, icon: <KFIcon type="icon-jibenxinxi" />,
children: (
<AutoMLBasic
className={styles['auto-ml-instance__basic']}
info={autoMLInfo}
runStatus={instanceInfo?.nodeStatus}
isInstance
/>
),
}, },
{ {
key: TabKeys.Log, key: TabKeys.Log,
label: '日志', label: '日志',
icon: <KFIcon type="icon-Trialliebiao" />,
icon: <KFIcon type="icon-rizhi" />,
children: (
<div className={styles['auto-ml-instance__log']}>
{instanceInfo && instanceInfo.nodeStatus && (
<LogList
instanceName={instanceInfo.argo_ins_name}
instanceNamespace={instanceInfo.argo_ins_ns}
pipelineNodeId={instanceInfo.nodeStatus.displayName}
workflowId={instanceInfo.nodeStatus.id}
instanceNodeStartTime={instanceInfo.nodeStatus.startedAt}
instanceNodeStatus={instanceInfo.nodeStatus.phase as ExperimentStatus}
></LogList>
)}
</div>
),
}, },
];

const resultTabItems = [
{ {
key: TabKeys.Result, key: TabKeys.Result,
label: '实验结果', label: '实验结果',
icon: <KFIcon type="icon-Trialliebiao" />,
icon: <KFIcon type="icon-shiyanjieguo1" />,
children: (
<ExperimentResult fileUrl={instanceInfo?.result_path} imageUrl={instanceInfo?.img_path} />
),
}, },
{ {
key: TabKeys.History, key: TabKeys.History,
label: '运行历史',
label: 'Trial列表',
icon: <KFIcon type="icon-Trialliebiao" />, icon: <KFIcon type="icon-Trialliebiao" />,
children: (
<ExperimentHistory
fileUrl={instanceInfo?.run_history_path}
isClassification={autoMLInfo?.task_type === AutoMLTaskType.Classification}
/>
),
}, },
]; ];


const tabItems =
instanceInfo?.status === ExperimentStatus.Succeeded
? [...basicTabItems, ...resultTabItems]
: basicTabItems;

return ( return (
<div className={styles['auto-ml-instance']}> <div className={styles['auto-ml-instance']}>
<div className={styles['auto-ml-instance__tabs']}>
<Tabs items={tabItems} activeKey={activeTab} onChange={setActiveTab} />
</div>
<div className={styles['auto-ml-instance__content']}>
{activeTab === TabKeys.Params && <AutoMLBasic info={autoMLInfo} hasBasicInfo={false} />}
{activeTab === TabKeys.Log && instanceInfo && instanceInfo.nodeStatus && (
<LogList
instanceName={instanceInfo.argo_ins_name}
instanceNamespace={instanceInfo.argo_ins_ns}
pipelineNodeId={instanceInfo.nodeStatus.nodeId}
workflowId={instanceInfo.nodeStatus.id}
instanceNodeStartTime={instanceInfo.nodeStatus.startedAt}
instanceNodeStatus={instanceInfo.nodeStatus.phase as ExperimentStatus}
></LogList>
)}
{activeTab === TabKeys.Result && (
<ExperimentResult fileUrl={instanceInfo?.result_path} imageUrl={instanceInfo?.img_path} />
)}
{activeTab === TabKeys.History && (
<ExperimentHistory
fileUrl={instanceInfo?.run_history_path}
isClassification={autoMLInfo?.task_type === AutoMLTaskType.Classification}
/>
)}
</div>
<Tabs
className={styles['auto-ml-instance__tabs']}
items={tabItems}
activeKey={activeTab}
onChange={setActiveTab}
/>
</div> </div>
); );
} }


+ 62
- 5
react-ui/src/pages/AutoML/components/AutoMLBasic/index.tsx View File

@@ -1,6 +1,11 @@
import { AutoMLTaskType, autoMLEnsembleClassOptions, autoMLTaskTypeOptions } from '@/enums'; import { AutoMLTaskType, autoMLEnsembleClassOptions, autoMLTaskTypeOptions } from '@/enums';
import { AutoMLData } from '@/pages/AutoML/types'; import { AutoMLData } from '@/pages/AutoML/types';
import { experimentStatusInfo } from '@/pages/Experiment/status';
import { type NodeStatus } from '@/types';
import { parseJsonText } from '@/utils'; import { parseJsonText } from '@/utils';
import { elapsedTime } from '@/utils/date';
import { Flex } from 'antd';
import classNames from 'classnames';
import { useMemo } from 'react'; import { useMemo } from 'react';
import ConfigInfo, { import ConfigInfo, {
formatBoolean, formatBoolean,
@@ -38,10 +43,12 @@ const formatMetricsWeight = (value: string) => {


type AutoMLBasicProps = { type AutoMLBasicProps = {
info?: AutoMLData; info?: AutoMLData;
hasBasicInfo?: boolean;
className?: string;
isInstance?: boolean;
runStatus?: NodeStatus;
}; };


function AutoMLBasic({ info, hasBasicInfo = true }: AutoMLBasicProps) {
function AutoMLBasic({ info, className, runStatus, isInstance = false }: AutoMLBasicProps) {
const basicDatas: BasicInfoData[] = useMemo(() => { const basicDatas: BasicInfoData[] = useMemo(() => {
if (!info) { if (!info) {
return []; return [];
@@ -142,7 +149,7 @@ function AutoMLBasic({ info, hasBasicInfo = true }: AutoMLBasicProps) {
ellipsis: true, ellipsis: true,
}, },
{ {
label: '时间限制(秒)',
label: '单次时间限制(秒)',
value: info.per_run_time_limit, value: info.per_run_time_limit,
ellipsis: true, ellipsis: true,
}, },
@@ -227,9 +234,59 @@ function AutoMLBasic({ info, hasBasicInfo = true }: AutoMLBasicProps) {
]; ];
}, [info]); }, [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: (
<Flex align="center">
<img
style={{ width: '17px', marginRight: '7px' }}
src={experimentStatusInfo[runStatus.phase]?.icon}
draggable={false}
alt=""
/>
<div
style={{
color: experimentStatusInfo[runStatus?.phase]?.color,
fontSize: '15px',
lineHeight: 1.6,
}}
>
{experimentStatusInfo[runStatus?.phase]?.label}
</div>
</Flex>
),
ellipsis: true,
},
];
}, [runStatus]);

return ( return (
<div className={styles['auto-ml-basic']}>
{hasBasicInfo && (
<div className={classNames(styles['auto-ml-basic'], className)}>
{isInstance && runStatus ? (
<ConfigInfo
title="运行信息"
data={instanceDatas}
labelWidth={70}
threeColumn
style={{ marginBottom: '20px' }}
/>
) : (
<ConfigInfo <ConfigInfo
title="基本信息" title="基本信息"
data={basicDatas} data={basicDatas}


+ 2
- 2
react-ui/src/pages/AutoML/components/ConfigInfo/index.less View File

@@ -1,13 +1,13 @@
.config-info { .config-info {
flex: 1; flex: 1;
min-width: 0; min-width: 0;
border: 1px solid @border-color-base;
border-radius: 4px;


&__content { &__content {
padding: 20px; padding: 20px;
padding: 20px @content-padding; padding: 20px @content-padding;
background-color: white; background-color: white;
border: 1px solid @border-color-base;
border-radius: 0 0 4px 4px;
} }


:global { :global {


+ 1
- 0
react-ui/src/pages/AutoML/components/ConfigTitle/index.less View File

@@ -8,6 +8,7 @@
rgba(22, 100, 255, 0.04) 100% rgba(22, 100, 255, 0.04) 100%
); );
border: 1px solid #e8effb; border: 1px solid #e8effb;
border-radius: 4px 4px 0 0;


&__img { &__img {
width: 16px; width: 16px;


+ 47
- 41
react-ui/src/pages/AutoML/components/CreateForm/ExecuteConfig.tsx View File

@@ -315,7 +315,7 @@ function ExecuteConfig() {
<Form.Item <Form.Item
label="内存限制(MB)" label="内存限制(MB)"
name="memory_limit" name="memory_limit"
tooltip="机器学习算法的内存限制(MB)。如果auto-sklearn试图分配超过memory_limit MB,它将停止拟合机器学习算法。默认3072"
tooltip="机器学习算法的内存限制(MB)。如果自动机器学习试图分配超过memory_limit MB,它将停止拟合机器学习算法。默认3072"
> >
<InputNumber placeholder="请输入内存限制" min={0} precision={0} /> <InputNumber placeholder="请输入内存限制" min={0} precision={0} />
</Form.Item> </Form.Item>
@@ -325,7 +325,7 @@ function ExecuteConfig() {
<Row gutter={8}> <Row gutter={8}>
<Col span={10}> <Col span={10}>
<Form.Item <Form.Item
label="时间限制(秒)"
label="单次时间限制(秒)"
name="per_run_time_limit" name="per_run_time_limit"
tooltip="单次调用机器学习模型的时间限制(以秒为单位)。如果机器学习算法运行超过时间限制,将终止模型拟合,默认600" tooltip="单次调用机器学习模型的时间限制(以秒为单位)。如果机器学习算法运行超过时间限制,将终止模型拟合,默认600"
> >
@@ -339,13 +339,56 @@ function ExecuteConfig() {
<Form.Item <Form.Item
label="搜索时间限制(秒)" label="搜索时间限制(秒)"
name="time_left_for_this_task" name="time_left_for_this_task"
tooltip="搜索合适模型的时间限制(以秒为单位)。通过增加这个值,auto-sklearn有更高的机会找到更好的模型。默认3600。"
tooltip="搜索合适模型的时间限制(以秒为单位)。通过增加这个值,自动机器学习有更高的机会找到更好的模型。默认3600。"
> >
<InputNumber placeholder="请输入搜索时间限制" min={0} precision={0} /> <InputNumber placeholder="请输入搜索时间限制" min={0} precision={0} />
</Form.Item> </Form.Item>
</Col> </Col>
</Row> </Row>


<Row gutter={8}>
<Col span={10}>
<Form.Item
label="测试集比率"
name="test_size"
tooltip="将数据划分为训练数据和测试数据,测试数据集所占比例,0到1之间"
>
<InputNumber placeholder="请输入测试集比率" min={0} max={1} />
</Form.Item>
</Col>
</Row>

<Row gutter={8}>
<Col span={10}>
<Form.Item label="计算指标" name="scoring_functions" tooltip="需要计算并打印的指标">
<Select
allowClear
placeholder="请选择计算指标"
options={
task_type === AutoMLTaskType.Classification
? classificationMetrics
: regressionMetrics
}
showSearch
/>
</Form.Item>
</Col>
</Row>

<Row gutter={8}>
<Col span={10}>
<Form.Item label="随机种子" name="seed" tooltip="随机种子,将决定输出文件名">
<InputNumber placeholder="请输入随机种子" min={0} precision={0} />
</Form.Item>
</Col>
</Row>

<SubAreaTitle
title="重采样策略"
image={require('@/assets/img/resample-icon.png')}
style={{ marginTop: '20px', marginBottom: '24px' }}
></SubAreaTitle>

<Row gutter={8}> <Row gutter={8}>
<Col span={10}> <Col span={10}>
<Form.Item <Form.Item
@@ -399,50 +442,13 @@ function ExecuteConfig() {
<Form.Item <Form.Item
label="训练集比率" label="训练集比率"
name="train_size" name="train_size"
tooltip="将数据划分为训练数据和测试数据,训练数据集所占比例,0到1之间"
tooltip="重采样划分训练集和验证集,训练集的比率,0到1之间"
> >
<InputNumber placeholder="请输入训练集比率" min={0} max={1} /> <InputNumber placeholder="请输入训练集比率" min={0} max={1} />
</Form.Item> </Form.Item>
</Col> </Col>
</Row> </Row>


<Row gutter={8}>
<Col span={10}>
<Form.Item
label="测试集比率"
name="test_size"
tooltip="将数据划分为训练数据和测试数据,测试数据集所占比例,0到1之间"
>
<InputNumber placeholder="请输入测试集比率" min={0} max={1} />
</Form.Item>
</Col>
</Row>

<Row gutter={8}>
<Col span={10}>
<Form.Item label="计算指标" name="scoring_functions" tooltip="需要计算并打印的指标">
<Select
allowClear
placeholder="请选择计算指标"
options={
task_type === AutoMLTaskType.Classification
? classificationMetrics
: regressionMetrics
}
showSearch
/>
</Form.Item>
</Col>
</Row>

<Row gutter={8}>
<Col span={10}>
<Form.Item label="随机种子" name="seed" tooltip="随机种子,将决定输出文件名">
<InputNumber placeholder="请输入随机种子" min={0} precision={0} />
</Form.Item>
</Col>
</Row>

{/* <Row gutter={8}> {/* <Row gutter={8}>
<Col span={10}> <Col span={10}>
<Form.Item <Form.Item


+ 1
- 135
react-ui/src/pages/AutoML/components/CreateForm/index.less View File

@@ -7,7 +7,7 @@
} }


.add-weight { .add-weight {
margin-bottom: 0;
margin-bottom: 0 !important;


// 增加样式权重 // 增加样式权重
& &__button { & &__button {
@@ -18,137 +18,3 @@
} }
} }
} }

// .command {
// width: 83.33%;
// margin-bottom: 20px;
// border: 1px solid rgba(234, 234, 234, 0.8);
// border-radius: 4px;
// &__header {
// height: 50px;
// padding-left: 8px;
// color: @text-color;
// font-size: @font-size;
// background: #f8f8f9;
// border-radius: 4px 4px 0px 0px;

// &__name {
// flex: none;
// width: 100px;
// }
// &__command {
// flex: 1;
// margin-right: 15px;
// }

// &__operation {
// flex: none;
// width: 100px;
// }
// }
// &__body {
// padding: 8px;
// border-bottom: 1px solid rgba(234, 234, 234, 0.8);

// &:last-child {
// border-bottom: none;
// }

// &__name {
// flex: none;
// width: 100px;
// }

// &__command {
// flex: 1;
// margin-right: 15px;
// margin-bottom: 0 !important;
// }

// &__operation {
// flex: none;
// width: 100px;
// }
// }

// &__add {
// display: flex;
// align-items: center;
// justify-content: center;
// padding: 15px 0;
// }
// }

// .hyper-parameter {
// width: 83.33%;
// margin-bottom: 20px;
// border: 1px solid rgba(234, 234, 234, 0.8);
// border-radius: 4px;
// &__header {
// height: 50px;
// padding-left: 8px;
// color: @text-color;
// font-size: @font-size;
// background: #f8f8f9;
// border-radius: 4px 4px 0px 0px;

// &__name,
// &__type,
// &__space {
// flex: 1;
// margin-right: 15px;
// }

// &__operation {
// flex: none;
// width: 100px;
// }
// }
// &__body {
// padding: 8px;
// border-bottom: 1px solid rgba(234, 234, 234, 0.8);

// &:last-child {
// border-bottom: none;
// }

// &__name,
// &__type,
// &__space {
// flex: 1;
// margin-right: 15px;
// margin-bottom: 0 !important;
// }

// &__operation {
// flex: none;
// width: 100px;
// }
// }

// &__add {
// display: flex;
// align-items: center;
// justify-content: center;
// padding: 15px 0;
// }
// }

// .trial-metrics {
// width: calc(41.67% - 6px);
// margin-bottom: 20px;
// padding: 0 20px;
// border: 1px dashed #e0e0e0;
// border-radius: 8px;
// }

// .upload-tip {
// margin-top: 5px;
// color: @text-color-secondary;
// font-size: 14px;
// }

// .upload-button {
// height: 46px;
// font-size: 15px;
// }

+ 3
- 3
react-ui/src/pages/AutoML/components/ExperimentHistory/index.less View File

@@ -1,9 +1,9 @@
.experiment-history { .experiment-history {
height: 100%;
height: calc(100% - 10px);
margin-top: 10px;
&__content { &__content {
height: 100%; height: 100%;
margin-top: 10px;
padding: 20px @content-padding 0;
padding: 20px @content-padding;
background-color: white; background-color: white;
border-radius: 10px; border-radius: 10px;




+ 27
- 6
react-ui/src/pages/AutoML/components/ExperimentResult/index.less View File

@@ -1,18 +1,39 @@
.experiment-result { .experiment-result {
height: 100%;
height: calc(100% - 10px);
margin-top: 10px; margin-top: 10px;
padding: 20px @content-padding 0;
padding: 20px @content-padding;
overflow-y: auto; overflow-y: auto;
background-color: white; background-color: white;
border-radius: 10px; border-radius: 10px;


&__text { &__text {
margin-bottom: 20px;
width: 100%;
height: 460px;
margin-bottom: 16px;
padding: 20px @content-padding;
overflow: auto;
white-space: pre-wrap; white-space: pre-wrap;
border: 1px solid @border-color-base;
border-radius: 0 0 4px 4px;
} }


&__image {
display: block;
height: 200px;
&__image-container {
display: flex;
align-items: flex-start;
width: 100%;
padding: 20px @content-padding;
overflow-x: auto;
border: 1px solid @border-color-base;
border-radius: 0 0 4px 4px;

&__image {
height: 248px;
margin-right: 20px;
border: 1px solid rgba(96, 107, 122, 0.3);

&:last-child {
margin-right: 0;
}
}
} }
} }

+ 14
- 9
react-ui/src/pages/AutoML/components/ExperimentResult/index.tsx View File

@@ -1,6 +1,7 @@
import { getFileReq } from '@/services/file'; import { getFileReq } from '@/services/file';
import { to } from '@/utils/promise'; import { to } from '@/utils/promise';
import { useEffect, useMemo, useState } from 'react'; import { useEffect, useMemo, useState } from 'react';
import ConfigTitle from '../ConfigTitle';
import styles from './index.less'; import styles from './index.less';


type ExperimentResultProps = { type ExperimentResultProps = {
@@ -34,16 +35,20 @@ function ExperimentResult({ fileUrl, imageUrl }: ExperimentResultProps) {


return ( return (
<div className={styles['experiment-result']}> <div className={styles['experiment-result']}>
<ConfigTitle title="实验结果"></ConfigTitle>
<div className={styles['experiment-result__text']}>{result}</div> <div className={styles['experiment-result__text']}>{result}</div>
{images.map((item, index) => (
<img
key={index}
className={styles['experiment-result__image']}
src={item}
draggable={false}
alt=""
/>
))}
<ConfigTitle title="可视化结果"></ConfigTitle>
<div className={styles['experiment-result__image-container']}>
{images.map((item, index) => (
<img
key={index}
className={styles['experiment-result__image-container__image']}
src={item}
draggable={false}
alt=""
/>
))}
</div>
</div> </div>
); );
} }


+ 2
- 1
react-ui/src/pages/AutoML/types.ts View File

@@ -1,4 +1,5 @@
import { type ParameterInputObject } from '@/components/ResourceSelect'; import { type ParameterInputObject } from '@/components/ResourceSelect';
import { type NodeStatus } from '@/types';


// 操作类型 // 操作类型
export enum OperationType { export enum OperationType {
@@ -80,5 +81,5 @@ export type AutoMLInstanceData = {
create_time: string; create_time: string;
update_time: string; update_time: string;
finish_time: string; finish_time: string;
nodeStatus?: { [key: string]: string };
nodeStatus?: NodeStatus;
}; };

+ 6
- 0
react-ui/src/pages/Experiment/components/ExperimentDrawer/index.less View File

@@ -39,4 +39,10 @@
margin-right: 6px; margin-right: 6px;
border-radius: 50%; border-radius: 50%;
} }

&__log {
height: 100%;
padding: 8px;
background: white;
}
} }

+ 10
- 8
react-ui/src/pages/Experiment/components/ExperimentDrawer/index.tsx View File

@@ -48,14 +48,16 @@ const ExperimentDrawer = ({
key: '1', key: '1',
label: '日志详情', label: '日志详情',
children: ( children: (
<LogList
instanceName={instanceName}
instanceNamespace={instanceNamespace}
pipelineNodeId={instanceNodeData.id}
workflowId={workflowId}
instanceNodeStartTime={instanceNodeStartTime}
instanceNodeStatus={instanceNodeStatus}
></LogList>
<div className={styles['experiment-drawer__log']}>
<LogList
instanceName={instanceName}
instanceNamespace={instanceNamespace}
pipelineNodeId={instanceNodeData.id}
workflowId={workflowId}
instanceNodeStartTime={instanceNodeStartTime}
instanceNodeStatus={instanceNodeStatus}
></LogList>
</div>
), ),
icon: <ProfileOutlined />, icon: <ProfileOutlined />,
}, },


+ 1
- 1
react-ui/src/pages/Experiment/components/LogGroup/index.tsx View File

@@ -90,7 +90,7 @@ function LogGroup({
start_time: startTime, start_time: startTime,
}; };
const res = await getExperimentPodsLog(params); const res = await getExperimentPodsLog(params);
const { log_detail } = res.data;
const { log_detail } = res.data || {};
if (log_detail) { if (log_detail) {
setLogList((oldList) => oldList.concat(log_detail)); setLogList((oldList) => oldList.concat(log_detail));




+ 5
- 1
react-ui/src/pages/Experiment/components/LogList/index.less View File

@@ -1,7 +1,7 @@
.log-list { .log-list {
height: 100%; height: 100%;
padding: 8px;
overflow-y: auto; overflow-y: auto;
background: #19253b;


&__empty { &__empty {
padding: 15px; padding: 15px;
@@ -12,4 +12,8 @@
word-break: break-all; word-break: break-all;
background: #19253b; background: #19253b;
} }

&::-webkit-scrollbar-thumb {
background: rgba(255, 255, 255, 0.5);
}
} }

+ 10
- 0
react-ui/src/types.ts View File

@@ -114,3 +114,13 @@ export type ComputingResource = {
standard: string; standard: string;
create_by: string; create_by: string;
}; };

// 实验运行节点状态
export type NodeStatus = {
id: string; // workflow Id
displayName: string;
name: string;
phase: ExperimentStatus;
startedAt: string;
finishedAt: string;
};

Loading…
Cancel
Save