Browse Source

feat: 实验对比

pull/86/head
cp3hnu 1 year ago
parent
commit
7514f04f0c
10 changed files with 298 additions and 14 deletions
  1. +5
    -0
      react-ui/config/routes.ts
  2. +1
    -1
      react-ui/src/pages/Dataset/components/ResourceIntro/index.tsx
  3. +9
    -1
      react-ui/src/pages/DevelopmentEnvironment/List/index.tsx
  4. +21
    -0
      react-ui/src/pages/Experiment/Comparison/index.less
  5. +212
    -0
      react-ui/src/pages/Experiment/Comparison/index.tsx
  6. +31
    -2
      react-ui/src/pages/Experiment/index.jsx
  7. +1
    -1
      react-ui/src/pages/Experiment/index.less
  8. +1
    -1
      react-ui/src/requestConfig.ts
  9. +14
    -0
      react-ui/src/services/experiment/index.js
  10. +3
    -8
      react-ui/src/services/session.ts

+ 5
- 0
react-ui/config/routes.ts View File

@@ -96,6 +96,11 @@ export default [
path: ':workflowId/:id', path: ':workflowId/:id',
component: './Experiment/training/index', component: './Experiment/training/index',
}, },
{
name: '实验对比',
path: 'compare',
component: './Experiment/Comparison/index',
},
], ],
}, },
], ],


+ 1
- 1
react-ui/src/pages/Dataset/components/ResourceIntro/index.tsx View File

@@ -58,7 +58,7 @@ const ResourceIntro = ({ resourceType }: ResourceIntroProps) => {
}; };
}), }),
); );
if (versionParam) {
if (versionParam && res.data.includes(versionParam)) {
setVersion(versionParam); setVersion(versionParam);
versionParam = null; versionParam = null;
} else { } else {


+ 9
- 1
react-ui/src/pages/DevelopmentEnvironment/List/index.tsx View File

@@ -38,6 +38,7 @@ export type EditorData = {
computing_resource: string; computing_resource: string;
update_by: string; update_by: string;
create_time: string; create_time: string;
url: string;
}; };


function EditorList() { function EditorList() {
@@ -140,7 +141,14 @@ function EditorList() {
dataIndex: 'name', dataIndex: 'name',
key: 'name', key: 'name',
width: '30%', width: '30%',
render: CommonTableCell(),
render: (text, record) =>
record.url ? (
<a href={record.url} target="_blank" rel="noreferrer">
{text}
</a>
) : (
<span>{text ?? '--'}</span>
),
}, },
{ {
title: '状态', title: '状态',


+ 21
- 0
react-ui/src/pages/Experiment/Comparison/index.less View File

@@ -0,0 +1,21 @@
.experiment-comparison {
height: 100%;
&__header {
display: flex;
align-items: center;
height: 50px;
margin-bottom: 10px;
padding: 0 30px;
background-image: url(@/assets/img/page-title-bg.png);
background-repeat: no-repeat;
background-position: top center;
background-size: 100% 100%;
}

&__table {
height: calc(100% - 60px);
padding: 20px 30px 0;
background-color: white;
border-radius: 10px;
}
}

+ 212
- 0
react-ui/src/pages/Experiment/Comparison/index.tsx View File

@@ -0,0 +1,212 @@
import CommonTableCell from '@/components/CommonTableCell';
import { useCacheState } from '@/hooks/pageCacheState';
import { getExpEvaluateInfosReq, getExpTrainInfosReq } from '@/services/experiment';
import { to } from '@/utils/promise';
import { useSearchParams } from '@umijs/max';
import { Button, Table, TablePaginationConfig, TableProps } from 'antd';
import classNames from 'classnames';
import { useEffect, useState } from 'react';
import styles from './index.less';

export enum ComparisonType {
Train = 'train',
Evaluate = 'evaluate',
}

function ExperimentComparison() {
const [searchParams] = useSearchParams();
const comparisonType = searchParams.get('type');
const experimentId = searchParams.get('experimentId');
const [tableData, setTableData] = useState([]);
const [cacheState, setCacheState] = useCacheState();
const [total, setTotal] = useState(0);
const [selectedRowKeys, setSelectedRowKeys] = useState<React.Key[]>([]);
const [pagination, setPagination] = useState<TablePaginationConfig>(
cacheState?.pagination ?? {
current: 1,
pageSize: 10,
},
);

useEffect(() => {
getComparisonData();
}, [experimentId]);

// 获取对比数据列表
const getComparisonData = async () => {
const request =
comparisonType === ComparisonType.Train ? getExpTrainInfosReq : getExpEvaluateInfosReq;
const [res] = await to(request(experimentId));
if (res && res.data) {
const { content = [], totalElements = 0 } = res.data;
setTableData(content);
setTotal(totalElements);
}
};

// 分页切换
const handleTableChange: TableProps['onChange'] = (pagination, filters, sorter, { action }) => {
if (action === 'paginate') {
setPagination(pagination);
}
// console.log(pagination, filters, sorter, action);
};

const rowSelection: TableProps['rowSelection'] = {
type: 'checkbox',
selectedRowKeys,
onChange: (selectedRowKeys: React.Key[], selectedRows: any[]) => {
console.log(`selectedRowKeys: ${selectedRowKeys}`, 'selectedRows: ', selectedRows);
setSelectedRowKeys(selectedRowKeys);
},
};

const columns: TableProps['columns'] = [
{
title: '基本信息',
children: [
{
title: '实例ID',
dataIndex: 'name',
key: 'name',
width: '30%',
render: CommonTableCell(),
},
{
title: '运行时间',
dataIndex: 'name',
key: 'name',
width: '30%',
render: CommonTableCell(),
},
{
title: '运行状态',
dataIndex: 'name',
key: 'name',
width: '30%',
render: CommonTableCell(),
},
{
title: '训练数据集',
dataIndex: 'name',
key: 'name',
width: '30%',
render: CommonTableCell(),
},
{
title: '增量训练',
dataIndex: 'name',
key: 'name',
width: '30%',
render: CommonTableCell(),
},
],
},
{
title: '训练参数',
children: [
{
title: 'batchsize',
dataIndex: 'name',
key: 'name',
width: '30%',
render: CommonTableCell(),
},
{
title: 'config',
dataIndex: 'name',
key: 'name',
width: '30%',
render: CommonTableCell(),
},
{
title: 'epoch',
dataIndex: 'name',
key: 'name',
width: '30%',
render: CommonTableCell(),
},
{
title: 'lr',
dataIndex: 'name',
key: 'name',
width: '30%',
render: CommonTableCell(),
},
{
title: 'warmup_iters',
dataIndex: 'name',
key: 'name',
width: '30%',
render: CommonTableCell(),
},
],
},
{
title: '训练指标',
children: [
{
title: 'metrc_name',
dataIndex: 'name',
key: 'name',
width: '30%',
render: CommonTableCell(),
},
{
title: 'test_1',
dataIndex: 'name',
key: 'name',
width: '30%',
render: CommonTableCell(),
},
{
title: 'test_2',
dataIndex: 'name',
key: 'name',
width: '30%',
render: CommonTableCell(),
},
{
title: 'test_3',
dataIndex: 'name',
key: 'name',
width: '30%',
render: CommonTableCell(),
},
{
title: 'test_4',
dataIndex: 'name',
key: 'name',
width: '30%',
render: CommonTableCell(),
},
],
},
];

return (
<div className={styles['experiment-comparison']}>
<div className={styles['experiment-comparison__header']}>
<Button type="default">可视化对比</Button>
</div>
<div className={classNames('vertical-scroll-table', styles['experiment-comparison__table'])}>
<Table
dataSource={tableData}
columns={columns}
rowSelection={rowSelection}
scroll={{ y: 'calc(100% - 55px)' }}
pagination={{
...pagination,
total: total,
showSizeChanger: true,
showQuickJumper: true,
}}
onChange={handleTableChange}
rowKey="id"
/>
</div>
</div>
);
}

export default ExperimentComparison;

+ 31
- 2
react-ui/src/pages/Experiment/index.jsx View File

@@ -18,11 +18,12 @@ import themes from '@/styles/theme.less';
import { elapsedTime, formatDate } from '@/utils/date'; import { elapsedTime, formatDate } from '@/utils/date';
import { to } from '@/utils/promise'; import { to } from '@/utils/promise';
import { modalConfirm } from '@/utils/ui'; import { modalConfirm } from '@/utils/ui';
import { App, Button, ConfigProvider, Space, Table, Tooltip } from 'antd';
import { App, Button, ConfigProvider, Dropdown, Space, Table, Tooltip } from 'antd';
import classNames from 'classnames'; import classNames from 'classnames';
import { useEffect, useRef, useState } from 'react'; import { useEffect, useRef, useState } from 'react';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import AddExperimentModal from './components/AddExperimentModal'; import AddExperimentModal from './components/AddExperimentModal';
import { ComparisonType } from './components/ComparisonModal/config';
import TensorBoardStatus, { TensorBoardStatusEnum } from './components/TensorBoardStatus'; import TensorBoardStatus, { TensorBoardStatusEnum } from './components/TensorBoardStatus';
import Styles from './index.less'; import Styles from './index.less';
import { experimentStatusInfo } from './status'; import { experimentStatusInfo } from './status';
@@ -270,6 +271,26 @@ function Experiment() {
window.open(experimentIn.tensorboardUrl, '_blank'); window.open(experimentIn.tensorboardUrl, '_blank');
} }
}; };

// 实验对比菜单
const getComparisonMenu = (experimentId) => {
return {
items: [
{
label: <span>训练对比</span>,
key: ComparisonType.Train,
},
{
label: <span>评估对比</span>,
key: ComparisonType.Evaluate,
},
],
onClick: ({ key }) => {
navgite(`/pipeline/experiment/compare?type=${key}&id=${experimentId}`);
},
};
};

const columns = [ const columns = [
{ {
title: '实验名称', title: '实验名称',
@@ -320,7 +341,7 @@ function Experiment() {
{ {
title: '操作', title: '操作',
key: 'action', key: 'action',
width: 300,
width: 350,
render: (_, record) => ( render: (_, record) => (
<Space size="small"> <Space size="small">
<Button <Button
@@ -345,6 +366,14 @@ function Experiment() {
> >
编辑 编辑
</Button> </Button>
<Dropdown key="comparison" menu={getComparisonMenu(record.id)}>
<a onClick={(e) => e.preventDefault()}>
<Space style={{ padding: '0 7px' }}>
<KFIcon type="icon-shiyanduibi" />
实验对比
</Space>
</a>
</Dropdown>
<ConfigProvider <ConfigProvider
theme={{ theme={{
token: { token: {


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

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


.operation { .operation {
width: 284px;
width: 334px;
} }
} }
.tableExpandBoxContent { .tableExpandBoxContent {


+ 1
- 1
react-ui/src/requestConfig.ts View File

@@ -40,7 +40,7 @@ export const requestConfig: RequestConfig = {
[ [
(response: AxiosResponse) => { (response: AxiosResponse) => {
const { status, data } = response || {}; const { status, data } = response || {};
console.log(message, data);
// console.log(message, data);
if (status >= 200 && status < 300) { if (status >= 200 && status < 300) {
if (data && (data instanceof Blob || data.code === 200)) { if (data && (data instanceof Blob || data.code === 200)) {
return response; return response;


+ 14
- 0
react-ui/src/services/experiment/index.js View File

@@ -116,3 +116,17 @@ export function getTensorBoardStatusReq(data) {
data, data,
}); });
} }

// 获取当前实验的模型推理指标信息
export function getExpEvaluateInfosReq(experimentId) {
return request(`/api/mmp/aim/getExpEvaluateInfos/${experimentId}`, {
method: 'GET',
});
}

// 获取当前实验的模型训练指标信息
export function getExpTrainInfosReq(experimentId) {
return request(`/api/mmp//aim/getExpTrainInfos/${experimentId}`, {
method: 'GET',
});
}

+ 3
- 8
react-ui/src/services/session.ts View File

@@ -60,8 +60,8 @@ function patchRouteItems(route: any, menu: any, parentPath: string) {
element: React.createElement(lazy(() => import('@/pages/' + path))), element: React.createElement(lazy(() => import('@/pages/' + path))),
path: parentPath + menuItem.path, path: parentPath + menuItem.path,
}; };
console.log(newRoute);
// console.log(newRoute);
route.children.push(newRoute); route.children.push(newRoute);
route.routes.push(newRoute); route.routes.push(newRoute);
} }
@@ -74,10 +74,7 @@ export function patchRouteWithRemoteMenus(routes: any) {
} }
let proLayout = null; let proLayout = null;
for (const routeItem of routes) { for (const routeItem of routes) {

if (routeItem.id === 'ant-design-pro-layout') { if (routeItem.id === 'ant-design-pro-layout') {
proLayout = routeItem; proLayout = routeItem;
break; break;
} }
@@ -101,7 +98,6 @@ export async function refreshToken() {
} }


export function convertCompatRouters(childrens: API.RoutersMenuItem[]): any[] { export function convertCompatRouters(childrens: API.RoutersMenuItem[]): any[] {

return childrens.map((item: API.RoutersMenuItem) => { return childrens.map((item: API.RoutersMenuItem) => {
return { return {
path: item.path, path: item.path,
@@ -149,12 +145,11 @@ export function getMatchMenuItem(
const subpath = path.substr(item.path.length + 1); const subpath = path.substr(item.path.length + 1);
const subItem: MenuDataItem[] = getMatchMenuItem(subpath, item.routes); const subItem: MenuDataItem[] = getMatchMenuItem(subpath, item.routes);
items = items.concat(subItem); items = items.concat(subItem);

} else { } else {
const paths = path.split('/'); const paths = path.split('/');
if (paths.length >= 2 && paths[0] === item.path && paths[1] === 'index') { if (paths.length >= 2 && paths[0] === item.path && paths[1] === 'index') {
console.log(item); console.log(item);
items.push(item); items.push(item);
} }
} }


Loading…
Cancel
Save