Browse Source

feat: 完成超参数寻优参数范围组件

pull/171/head
cp3hnu 11 months ago
parent
commit
bd4d57f398
8 changed files with 232 additions and 136 deletions
  1. BIN
      react-ui/src/assets/img/popover-bg.png
  2. +1
    -1
      react-ui/src/iconfont/iconfont.js
  3. +43
    -9
      react-ui/src/pages/HyperParameter/components/CreateForm/ParameterRange/index.less
  4. +109
    -98
      react-ui/src/pages/HyperParameter/components/CreateForm/ParameterRange/index.tsx
  5. +31
    -8
      react-ui/src/pages/HyperParameter/components/CreateForm/PopParameterRange/index.less
  6. +18
    -11
      react-ui/src/pages/HyperParameter/components/CreateForm/PopParameterRange/index.tsx
  7. +1
    -1
      react-ui/src/pages/HyperParameter/components/CreateForm/index.less
  8. +29
    -8
      react-ui/src/pages/HyperParameter/components/CreateForm/utils.ts

BIN
react-ui/src/assets/img/popover-bg.png View File

Before After
Width: 1200  |  Height: 452  |  Size: 49 kB

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


+ 43
- 9
react-ui/src/pages/HyperParameter/components/CreateForm/ParameterRange/index.less View File

@@ -1,13 +1,47 @@
.parameter-range {
width: 300px;
&__list {
width: 100%;
max-height: 300px;
overflow-x: visible;
overflow-y: auto;
width: 360px;
&__type {
margin-bottom: 10px;
color: @text-color-secondary;
font-size: @font-size-input;
&::before {
display: inline-block;
color: @error-color;
font-size: 14px;
font-family: SimSun, sans-serif;
line-height: 1;
content: '*';
margin-inline-end: 4px;
}
}
&__desc {
margin-bottom: 20px;
padding: 4px 8px;
color: @text-color-tertiary;
font-size: 13px;
background: rgba(62, 96, 163, 0.05);
border-radius: 6px;
}
&__button {
margin-bottom: 0;
text-align: center;
&__form {
width: 100%;
&__list {
width: 100%;
max-height: 300px;
overflow-x: visible;
overflow-y: auto;
}
&__space {
flex: none;
width: 22px;
color: @text-color-tertiary;
font-size: @font-size-input;
line-height: 32px;
text-align: center;
}
&__button {
width: 100%;
margin-bottom: 0;
text-align: center;
}
}
}

+ 109
- 98
react-ui/src/pages/HyperParameter/components/CreateForm/ParameterRange/index.tsx View File

@@ -1,16 +1,16 @@
import { MinusCircleOutlined, PlusCircleOutlined } from '@ant-design/icons';
import { Button, Flex, Form, Input, InputNumber } from 'antd';
import { ParameterType, getFormOptions } from '../utils';
import { ParameterType, getFormOptions, parameterTooltip } from '../utils';
import styles from './index.less';

type ParameterRangeProps = {
type?: ParameterType;
type: ParameterType;
value?: any[];
onCancel?: () => void;
onConfirm?: (value: any[]) => void;
};

function ParameterRange({ type, value, onCancel, onConfirm }: ParameterRangeProps) {
function ParameterRange({ type, value, onConfirm }: ParameterRangeProps) {
const [form] = Form.useForm();
const isList = type === ParameterType.Choice || type === ParameterType.Grid;
const formOptions = getFormOptions(type, value);
@@ -33,108 +33,119 @@ function ParameterRange({ type, value, onCancel, onConfirm }: ParameterRangeProp
};

return (
<Form
labelCol={{ flex: '70px' }}
wrapperCol={{ flex: '1' }}
labelAlign="left"
form={form}
onFinish={handleFinish}
size="middle"
autoComplete="off"
scrollToFirstError
initialValues={initialValues}
className={styles['parameter-range']}
>
{isList ? (
<div className={styles['parameter-range__list']}>
<Form.List name="list">
{(fields, { add, remove }) => (
<>
{fields.map(({ key, name, ...restField }, index) => (
<Flex key={key} align="center">
<Form.Item
style={{ flex: 1, minWidth: 0 }}
{...restField}
name={[name, 'value']}
rules={[{ required: true, message: '必填' }]}
>
<Input placeholder="请输入" allowClear />
</Form.Item>
<Flex
style={{
marginLeft: '10px',
marginBottom: '20px',
flex: 'none',
width: '66px',
}}
align="center"
>
<Button
shape="circle"
size="middle"
type="text"
disabled={fields.length === 1}
icon={<MinusCircleOutlined />}
onClick={() => remove(name)}
></Button>
{index === fields.length - 1 && (
<div className={styles['parameter-range']}>
<div className={styles['parameter-range__type']}>{type}</div>
<div className={styles['parameter-range__desc']}>{parameterTooltip[type]}</div>
<Form
// labelCol={{ flex: '0' }}
// wrapperCol={{ flex: '1' }}
labelAlign="left"
form={form}
onFinish={handleFinish}
size="middle"
autoComplete="off"
scrollToFirstError
initialValues={initialValues}
layout={isList ? 'horizontal' : 'inline'}
className={styles['parameter-range__form']}
>
{isList ? (
<div className={styles['parameter-range__form__list']}>
<Form.List name="list">
{(fields, { add, remove }) => (
<>
{fields.map(({ key, name, ...restField }, index) => (
<Flex key={key} align="center">
<Form.Item
style={{ flex: 1, minWidth: 0 }}
{...restField}
name={[name, 'value']}
rules={[{ required: true, message: '必填' }]}
>
<Input placeholder="请输入" allowClear />
</Form.Item>
<Flex
style={{
marginLeft: '10px',
marginBottom: '20px',
flex: 'none',
width: '66px',
}}
align="center"
>
<Button
shape="circle"
size="middle"
type="text"
onClick={() => add()}
icon={<PlusCircleOutlined />}
disabled={fields.length === 1}
icon={<MinusCircleOutlined />}
onClick={() => remove(name)}
></Button>
)}
{index === fields.length - 1 && (
<Button
shape="circle"
size="middle"
type="text"
onClick={() => add()}
icon={<PlusCircleOutlined />}
></Button>
)}
</Flex>
</Flex>
</Flex>
))}
{fields.length === 0 && (
<Form.Item className={styles['add-weight']}>
<Button
className={styles['add-weight__button']}
color="primary"
variant="dashed"
onClick={() => add()}
block
icon={<PlusCircleOutlined />}
>
添加
</Button>
))}
{fields.length === 0 && (
<Form.Item className={styles['add-weight']}>
<Button
className={styles['add-weight__button']}
color="primary"
variant="dashed"
onClick={() => add()}
block
icon={<PlusCircleOutlined />}
>
添加
</Button>
</Form.Item>
)}
</>
)}
</Form.List>
</div>
) : (
<Flex align="start" style={{ width: '100%', marginBottom: '20px' }}>
{formOptions.map((item, index) => {
return (
<>
<Form.Item
key={item.name}
name={item.name}
style={{ flex: 1, marginInlineEnd: 0 }}
rules={[
{
required: true,
message: `必填`,
},
]}
>
<InputNumber style={{ width: '100%' }} placeholder={item.name} />
</Form.Item>
)}
</>
)}
</Form.List>
</div>
) : (
formOptions.map((item) => {
return (
<Form.Item
key={item.name}
label={item.label}
name={item.name}
rules={[
{
required: true,
message: `请输入${item.label}`,
},
]}
>
<InputNumber style={{ width: '100%' }} placeholder={`请输入${item.label}`} />
</Form.Item>
);
})
)}
<Form.Item className={styles['parameter-range__button']}>
<Button type="default" htmlType="button" onClick={onCancel}>
取消
</Button>
<Button type="primary" htmlType="submit" style={{ marginLeft: '20px' }}>
确定
</Button>
</Form.Item>
</Form>
{index !== formOptions.length - 1 && (
<span className={styles['parameter-range__form__space']}>
{index === 0 ? '-' : ' '}
</span>
)}
</>
);
})}
</Flex>
)}
<Form.Item layout="horizontal" className={styles['parameter-range__form__button']}>
<Button type="primary" htmlType="submit" style={{ width: '100%', height: '36px' }}>
确定
</Button>
</Form.Item>
</Form>
</div>
);
}



+ 31
- 8
react-ui/src/pages/HyperParameter/components/CreateForm/PopParameterRange/index.less View File

@@ -1,14 +1,23 @@
.parameter-range {
border-radius: 18px;
box-shadow: 0px 3px 10px rgba(22, 100, 255, 0.15);
:global {
.ant-popover-inner {
padding: 20px 20px 12px;
}
.ant-popconfirm-description {
padding-top: 20px;
}
.ant-popover-content {
.ant-popover-inner {
width: 400px;
padding: 20px 20px 12px;
background-image: url(@/assets/img/popover-bg.png);
background-repeat: no-repeat;
background-position: top left;
background-size: 100% auto;
}
.ant-popconfirm-description {
margin-top: 20px;
}

.ant-popconfirm-buttons {
display: none;
.ant-popconfirm-buttons {
display: none;
}
}
}

@@ -58,3 +67,17 @@
}
}
}

.parameter-range-title {
color: @text-color;
font-weight: 500;
font-size: @font-size-content;
}

.parameter-range-title-icon {
color: @text-color-secondary;

&:hover {
color: @text-color;
}
}

+ 18
- 11
react-ui/src/pages/HyperParameter/components/CreateForm/PopParameterRange/index.tsx View File

@@ -1,6 +1,6 @@
import KFIcon from '@/components/KFIcon';
import { isEmpty } from '@/utils';
import { Popconfirm, Typography } from 'antd';
import { Flex, Popconfirm, Typography } from 'antd';
import classNames from 'classnames';
import { useEffect, useRef, useState } from 'react';
import ParameterRange from '../ParameterRange';
@@ -8,7 +8,7 @@ import { ParameterType } from '../utils';
import styles from './index.less';

type ParameterRangeProps = {
type?: ParameterType;
type: ParameterType;
value?: any[];
onChange?: (value: any[]) => void;
};
@@ -58,18 +58,11 @@ function PopParameterRange({ type, value, onChange }: ParameterRangeProps) {
<div ref={popconfirmRef}>
<Popconfirm
id="pop-parameter"
title="参数范围"
title={<PopconfirmTitle title="参数范围" onClose={handleCancel} />}
disabled={disabled}
description={
<ParameterRange
type={type}
value={value}
onCancel={handleCancel}
onConfirm={handleConfirm}
></ParameterRange>
<ParameterRange type={type} value={value} onConfirm={handleConfirm}></ParameterRange>
}
okText="确定"
cancelText="取消"
overlayClassName={styles['parameter-range']}
icon={null}
open={open}
@@ -95,4 +88,18 @@ function PopParameterRange({ type, value, onChange }: ParameterRangeProps) {
);
}

function PopconfirmTitle({ title, onClose }: { title: string; onClose: () => void }) {
return (
<Flex align="center" justify="space-between">
<span className={styles['parameter-range-title']}>{title}</span>
<KFIcon
className={styles['parameter-range-title-icon']}
type="icon-guanbi"
font={17}
onClick={onClose}
/>
</Flex>
);
}

export default PopParameterRange;

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

@@ -41,7 +41,7 @@

&::before {
display: inline-block;
color: #c73131;
color: @error-color;
font-size: 14px;
font-family: SimSun, sans-serif;
line-height: 1;


+ 29
- 8
react-ui/src/pages/HyperParameter/components/CreateForm/utils.ts View File

@@ -38,6 +38,27 @@ export const axParameterOptions = ['fixed', 'range', 'choice'].map((name) => ({
value: name,
}));

export const parameterTooltip: Record<ParameterType, string> = {
[ParameterType.Uniform]: '在 low 和 high 之间均匀采样浮点数',
[ParameterType.QUniform]: '在 low 和 high 之间均匀采样浮点数,四舍五入到 q 的倍数',
[ParameterType.LogUniform]: '在 low 和 high 之间均匀采样浮点数,对数空间采样',
[ParameterType.QLogUniform]:
'在 low 和 high 之间均匀采样浮点数,对数空间采样并四舍五入到 q 的倍数',
[ParameterType.Randn]: '在均值为 m,方差为 s 的正态分布中进行随机浮点数抽样',
[ParameterType.QRandn]:
'在均值为 m,方差为 s 的正态分布中进行随机浮点数抽样,四舍五入到 q 的倍数',
[ParameterType.RandInt]: '在 low(包括)到 high(不包括)之间均匀采样整数',
[ParameterType.QRandInt]:
'在 low(包括)到 high(不包括)之间均匀采样整数,四舍五入到 q 的倍数(包括 high)',
[ParameterType.LogRandInt]: '在 low(包括)到 high(不包括)之间对数空间上均匀采样整数',
[ParameterType.QLogRandInt]:
'在 low(包括)到 high(不包括)之间对数空间上均匀采样整数,并四舍五入到 q 的倍数',
[ParameterType.Choice]: '从指定的选项中采样一个选项',
[ParameterType.Grid]: '对选项进行网格搜索,每个值都将被采样',
[ParameterType.Range]: '在 low 和 high 范围内采样取值',
[ParameterType.Fixed]: '固定取值',
};

export type ParameterData = {
label: string;
name: string;
@@ -69,12 +90,12 @@ export const getFormOptions = (type?: ParameterType, value?: number[]): Paramete
case ParameterType.Range:
return [
{
name: 'min',
name: 'low',
label: '最小值',
value: numbers?.[0],
},
{
name: 'max',
name: 'high',
label: '最大值',
value: numbers?.[1],
},
@@ -85,12 +106,12 @@ export const getFormOptions = (type?: ParameterType, value?: number[]): Paramete
case ParameterType.QLogRandInt:
return [
{
name: 'min',
name: 'low',
label: '最小值',
value: numbers?.[0],
},
{
name: 'max',
name: 'high',
label: '最大值',
value: numbers?.[1],
},
@@ -103,12 +124,12 @@ export const getFormOptions = (type?: ParameterType, value?: number[]): Paramete
case ParameterType.Randn:
return [
{
name: 'mean',
name: 'm',
label: '均值',
value: numbers?.[0],
},
{
name: 'std',
name: 's',
label: '方差',
value: numbers?.[1],
},
@@ -116,12 +137,12 @@ export const getFormOptions = (type?: ParameterType, value?: number[]): Paramete
case ParameterType.QRandn:
return [
{
name: 'mean',
name: 'm',
label: '均值',
value: numbers?.[0],
},
{
name: 'std',
name: 's',
label: '方差',
value: numbers?.[1],
},


Loading…
Cancel
Save