Browse Source

feat: 自动学习日志改成超参数寻优的方式

pull/204/head
zhaowei 9 months ago
parent
commit
2d3a3dabcd
13 changed files with 112 additions and 47 deletions
  1. +6
    -3
      react-ui/src/pages/ActiveLearn/Instance/index.tsx
  2. +3
    -3
      react-ui/src/pages/ActiveLearn/components/ActiveLearnBasic/index.tsx
  3. +4
    -0
      react-ui/src/pages/ActiveLearn/components/CreateForm/BasicConfig.tsx
  4. +3
    -1
      react-ui/src/pages/ActiveLearn/components/ExperimentLog/index.tsx
  5. +30
    -31
      react-ui/src/pages/AutoML/Instance/index.tsx
  6. +3
    -3
      react-ui/src/pages/AutoML/components/AutoMLBasic/index.tsx
  7. +4
    -0
      react-ui/src/pages/AutoML/components/CreateForm/BasicConfig.tsx
  8. +7
    -0
      react-ui/src/pages/AutoML/components/ExperimentLog/index.less
  9. +37
    -0
      react-ui/src/pages/AutoML/components/ExperimentLog/index.tsx
  10. +5
    -2
      react-ui/src/pages/HyperParameter/Instance/index.tsx
  11. +4
    -0
      react-ui/src/pages/HyperParameter/components/CreateForm/BasicConfig.tsx
  12. +3
    -1
      react-ui/src/pages/HyperParameter/components/ExperimentLog/index.tsx
  13. +3
    -3
      react-ui/src/pages/HyperParameter/components/HyperParameterBasic/index.tsx

+ 6
- 3
react-ui/src/pages/ActiveLearn/Instance/index.tsx View File

@@ -27,7 +27,7 @@ const NodePrefix = 'workflow';
function ActiveLearnInstance() {
const [experimentInfo, setExperimentInfo] = useState<ActiveLearnData | undefined>(undefined);
const [instanceInfo, setInstanceInfo] = useState<ActiveLearnInstanceData | undefined>(undefined);
// 超参数寻优运行有3个节点,运行状态取工作流状态,而不是 auto-hpo 节点状态
// 主动学习运行有3个节点,运行状态取工作流状态,而不是 active-learn 节点状态
const [workflowStatus, setWorkflowStatus] = useState<NodeStatus | undefined>(undefined);
const [nodes, setNodes] = useState<Record<string, NodeStatus> | undefined>(undefined);
const params = useParams();
@@ -49,11 +49,14 @@ function ActiveLearnInstance() {
const [res] = await to(getActiveLearnInsReq(instanceId));
if (res && res.data) {
const info = res.data as ActiveLearnInstanceData;
const { param, node_status, argo_ins_name, argo_ins_ns, status } = info;
const { param, node_status, argo_ins_name, argo_ins_ns, status, create_time } = info;
// 解析配置参数
const paramJson = parseJsonText(param);
if (paramJson) {
setExperimentInfo(paramJson.data);
setExperimentInfo({
...paramJson.data,
create_time,
});
}

setInstanceInfo(info);


+ 3
- 3
react-ui/src/pages/ActiveLearn/components/ActiveLearnBasic/index.tsx View File

@@ -206,19 +206,19 @@ function BasicInfo({ info, className, runStatus, isInstance = false }: BasicInfo
}, [info, getResourceDescription]);

const instanceDatas = useMemo(() => {
if (!runStatus) {
if (!info || !runStatus) {
return [];
}

return [
{
label: '启动时间',
value: formatDate(runStatus.startedAt),
value: formatDate(info.create_time),
ellipsis: true,
},
{
label: '执行时长',
value: elapsedTime(runStatus.startedAt, runStatus.finishedAt),
value: elapsedTime(info.create_time, runStatus.finishedAt),
ellipsis: true,
},
{


+ 4
- 0
react-ui/src/pages/ActiveLearn/components/CreateForm/BasicConfig.tsx View File

@@ -19,6 +19,10 @@ function BasicConfig() {
required: true,
message: '请输入实验名称',
},
{
max: 64,
message: '实验名称不能超过64个字符',
},
]}
>
<Input placeholder="请输入实验名称" maxLength={64} showCount allowClear />


+ 3
- 1
react-ui/src/pages/ActiveLearn/components/ExperimentLog/index.tsx View File

@@ -5,6 +5,8 @@ import { NodeStatus } from '@/types';
import { Tabs } from 'antd';
import styles from './index.less';

const NodePrefix = 'active-learn';

type ExperimentLogProps = {
instanceInfo: ActiveLearnInstanceData;
nodes: Record<string, NodeStatus>;
@@ -23,7 +25,7 @@ function ExperimentLog({ instanceInfo, nodes }: ExperimentLogProps) {
})
.forEach((key) => {
const node = nodes[key];
if (node.displayName.startsWith('active-learn')) {
if (node.displayName.startsWith(NodePrefix)) {
hpoNodeStatus = node;
} else if (node.displayName.startsWith('git-clone') && !frameworkCloneNodeStatus) {
frameworkCloneNodeStatus = node;


+ 30
- 31
react-ui/src/pages/AutoML/Instance/index.tsx View File

@@ -1,6 +1,5 @@
import KFIcon from '@/components/KFIcon';
import { AutoMLTaskType, ExperimentStatus } from '@/enums';
import LogList from '@/pages/Experiment/components/LogList';
import { getExperimentInsReq } from '@/services/autoML';
import { NodeStatus } from '@/types';
import { parseJsonText } from '@/utils';
@@ -11,6 +10,7 @@ import { Tabs } from 'antd';
import { useEffect, useRef, useState } from 'react';
import AutoMLBasic from '../components/AutoMLBasic';
import ExperimentHistory from '../components/ExperimentHistory';
import ExperimentLog from '../components/ExperimentLog';
import ExperimentResult from '../components/ExperimentResult';
import { AutoMLData, AutoMLInstanceData } from '../types';
import styles from './index.less';
@@ -22,11 +22,13 @@ enum TabKeys {
History = 'history',
}

const NodePrefix = 'auto-ml';
const NodePrefix = 'workflow';

function AutoMLInstance() {
const [autoMLInfo, setAutoMLInfo] = useState<AutoMLData | undefined>(undefined);
const [instanceInfo, setInstanceInfo] = useState<AutoMLInstanceData | undefined>(undefined);
const [workflowStatus, setWorkflowStatus] = useState<NodeStatus | undefined>(undefined);
const [nodes, setNodes] = useState<Record<string, NodeStatus> | undefined>(undefined);
const params = useParams();
const instanceId = safeInvoke(Number)(params.id);
const evtSourceRef = useRef<EventSource | null>(null);
@@ -46,34 +48,39 @@ function AutoMLInstance() {
const [res] = await to(getExperimentInsReq(instanceId));
if (res && res.data) {
const info = res.data as AutoMLInstanceData;
const { param, node_status, argo_ins_name, argo_ins_ns, status } = info;
const { param, node_status, argo_ins_name, argo_ins_ns, status, create_time } = info;
// 解析配置参数
const paramJson = parseJsonText(param);
if (paramJson) {
setAutoMLInfo(paramJson);
setAutoMLInfo({
...paramJson,
create_time,
});
}

setInstanceInfo(info);

// 这个接口返回的状态有延时,SSE 返回的状态是最新的
// SSE 调用时,不需要解析 node_status, 也不要重新建立 SSE
if (isStatusDetermined) {
setInstanceInfo((prev) => ({
...info,
nodeStatus: prev!.nodeStatus,
}));
return;
}

// 进行节点状态
const nodeStatusJson = parseJsonText(node_status);
if (nodeStatusJson) {
Object.keys(nodeStatusJson).forEach((key) => {
setNodes(nodeStatusJson);
// 工作流
Object.keys(nodeStatusJson).some((key) => {
if (key.startsWith(NodePrefix)) {
const value = nodeStatusJson[key];
info.nodeStatus = value;
const workflowStatus = nodeStatusJson[key];
setWorkflowStatus(workflowStatus);
return true;
}
return false;
});
}
setInstanceInfo(info);
// 运行中或者等待中,开启 SSE
if (status === ExperimentStatus.Pending || status === ExperimentStatus.Running) {
setupSSE(argo_ins_name, argo_ins_ns);
@@ -97,19 +104,20 @@ function AutoMLInstance() {
if (dataJson) {
const nodes = dataJson?.result?.object?.status?.nodes;
if (nodes) {
const statusData = Object.values(nodes).find((node: any) =>
const workflowStatus = Object.values(nodes).find((node: any) =>
node.displayName.startsWith(NodePrefix),
) as NodeStatus;
if (statusData) {
setInstanceInfo((prev) => ({
...prev!,
nodeStatus: statusData,
}));

// 节点
setNodes(nodes);

if (workflowStatus) {
setWorkflowStatus(workflowStatus);

// 实验结束,关闭 SSE
if (
statusData.phase !== ExperimentStatus.Pending &&
statusData.phase !== ExperimentStatus.Running
workflowStatus.phase !== ExperimentStatus.Pending &&
workflowStatus.phase !== ExperimentStatus.Running
) {
closeSSE();
getExperimentInsInfo(true);
@@ -141,7 +149,7 @@ function AutoMLInstance() {
<AutoMLBasic
className={styles['auto-ml-instance__basic']}
info={autoMLInfo}
runStatus={instanceInfo?.nodeStatus}
runStatus={workflowStatus}
isInstance
/>
),
@@ -152,16 +160,7 @@ function AutoMLInstance() {
icon: <KFIcon type="icon-rizhi1" />,
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>
)}
{instanceInfo && nodes && <ExperimentLog instanceInfo={instanceInfo} nodes={nodes} />}
</div>
),
},


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

@@ -193,18 +193,18 @@ function AutoMLBasic({ info, className, runStatus, isInstance = false }: AutoMLB
}, [info]);

const instanceDatas = useMemo(() => {
if (!runStatus) {
if (!info || !runStatus) {
return [];
}

return [
{
label: '启动时间',
value: formatDate(runStatus.startedAt),
value: formatDate(info.create_time),
},
{
label: '执行时长',
value: elapsedTime(runStatus.startedAt, runStatus.finishedAt),
value: elapsedTime(info.create_time, runStatus.finishedAt),
},
{
label: '状态',


+ 4
- 0
react-ui/src/pages/AutoML/components/CreateForm/BasicConfig.tsx View File

@@ -18,6 +18,10 @@ function BasicConfig() {
required: true,
message: '请输入实验名称',
},
{
max: 64,
message: '实验名称不能超过64个字符',
},
]}
>
<Input placeholder="请输入实验名称" maxLength={64} showCount allowClear />


+ 7
- 0
react-ui/src/pages/AutoML/components/ExperimentLog/index.less View File

@@ -0,0 +1,7 @@
.experiment-log {
height: 100%;

&__log {
height: 100%;
}
}

+ 37
- 0
react-ui/src/pages/AutoML/components/ExperimentLog/index.tsx View File

@@ -0,0 +1,37 @@
import { ExperimentStatus } from '@/enums';
import { AutoMLInstanceData } from '@/pages/AutoML/types';
import LogList from '@/pages/Experiment/components/LogList';
import { NodeStatus } from '@/types';
import styles from './index.less';

const NodePrefix = 'auto-ml';

type ExperimentLogProps = {
instanceInfo: AutoMLInstanceData;
nodes: Record<string, NodeStatus>;
};

function ExperimentLog({ instanceInfo, nodes }: ExperimentLogProps) {
const nodeStatus: NodeStatus | undefined = Object.values(nodes).find((node: any) =>
node.displayName.startsWith(NodePrefix),
) as NodeStatus;

return (
<div className={styles['experiment-log']}>
<div className={styles['experiment-log__log']}>
{nodeStatus && (
<LogList
instanceName={instanceInfo.argo_ins_name}
instanceNamespace={instanceInfo.argo_ins_ns}
pipelineNodeId={nodeStatus.displayName}
workflowId={nodeStatus.id}
instanceNodeStartTime={nodeStatus.startedAt}
instanceNodeStatus={nodeStatus.phase as ExperimentStatus}
></LogList>
)}
</div>
</div>
);
}

export default ExperimentLog;

+ 5
- 2
react-ui/src/pages/HyperParameter/Instance/index.tsx View File

@@ -51,7 +51,7 @@ function HyperParameterInstance() {
const [res] = await to(getRayInsReq(instanceId));
if (res && res.data) {
const info = res.data as HyperParameterInstanceData;
const { param, node_status, argo_ins_name, argo_ins_ns, status } = info;
const { param, node_status, argo_ins_name, argo_ins_ns, status, create_time } = info;
// 解析配置参数
const paramJson = parseJsonText(param);
if (paramJson) {
@@ -70,7 +70,10 @@ function HyperParameterInstance() {
if (!Array.isArray(paramJson.points_to_evaluate)) {
paramJson.points_to_evaluate = [];
}
setExperimentInfo(paramJson);
setExperimentInfo({
...paramJson,
create_time,
});
}

setInstanceInfo(info);


+ 4
- 0
react-ui/src/pages/HyperParameter/components/CreateForm/BasicConfig.tsx View File

@@ -19,6 +19,10 @@ function BasicConfig() {
required: true,
message: '请输入实验名称',
},
{
max: 64,
message: '实验名称不能超过64个字符',
},
]}
>
<Input placeholder="请输入实验名称" maxLength={64} showCount allowClear />


+ 3
- 1
react-ui/src/pages/HyperParameter/components/ExperimentLog/index.tsx View File

@@ -5,6 +5,8 @@ import { NodeStatus } from '@/types';
import { Tabs } from 'antd';
import styles from './index.less';

const NodePrefix = 'auto-hpo';

type ExperimentLogProps = {
instanceInfo: HyperParameterInstanceData;
nodes: Record<string, NodeStatus>;
@@ -23,7 +25,7 @@ function ExperimentLog({ instanceInfo, nodes }: ExperimentLogProps) {
})
.forEach((key) => {
const node = nodes[key];
if (node.displayName.startsWith('auto-hpo')) {
if (node.displayName.startsWith(NodePrefix)) {
hpoNodeStatus = node;
} else if (node.displayName.startsWith('git-clone') && !frameworkCloneNodeStatus) {
frameworkCloneNodeStatus = node;


+ 3
- 3
react-ui/src/pages/HyperParameter/components/HyperParameterBasic/index.tsx View File

@@ -143,19 +143,19 @@ function HyperParameterBasic({
}, [info, getResourceDescription]);

const instanceDatas = useMemo(() => {
if (!runStatus) {
if (!info || !runStatus) {
return [];
}

return [
{
label: '启动时间',
value: formatDate(runStatus.startedAt),
value: formatDate(info.create_time),
ellipsis: true,
},
{
label: '执行时长',
value: elapsedTime(runStatus.startedAt, runStatus.finishedAt),
value: elapsedTime(info.create_time, runStatus.finishedAt),
ellipsis: true,
},
{


Loading…
Cancel
Save