早上来之后,在配置公司的内部中转,教程里面的模型名字是gpt-5-codex,但是提示模型名不支持,之后问了IT说找我mentor解决,估摸着应该是他负责搭建的这个中转站。之后我也没去问mentor,把模型改成了gpt-5.4就跑通了。

之后就在看transformer的那个网站,还添加了webai-lite的日志接收功能,之后mentor就把他用claude design设计的原型图发我了(一个单html页面),说为了保证我大方向不出错,接下来的一些细节需要我自己去调整,我还以为我变成测试了呢

打算上午剩下的时间先修一修原型图(肯定是修不完的),今天下午看什么时候把图修完,在等Ai的过程中可以刷刷L站,之后修完了就准备刷刷力扣,看看八股,看看transformer,愉快的工作就结束了,回去做有氧,做完有氧之后就开始鼓捣自己的TrimTalk小工具,争取今天做个demo出来

公司的GPT模型好慢啊,删个字段删了10min,时不时还会重新连接

wk,下午准备开始改了,发现报 429 Too Many Request 错误,问了下说是额度还没重置说是还有10min就好了

下午基本就改了几个功能,调整了推理页面中日志子页面和结果子页面的顺序,训练页面中的日志子页面可以查看分割和分类模型的日志,删除训练页面中的完成子页面中的查看验证报告按钮(训练之后没有报告,只可以下载模型),新建工作区只能选择“分割+分类”、“实例分割”、“OCR“、”仅分类“

改完这些才三点不到,打算用公司额度做一下自己的东西。

我想学习英语,高考英语100左右,大一的时候过了四级,之后考过两次六级都没过,心思都花在别的上面了,现在出来实习之后发现英语真的是世界的入口,前段时间我说我以后一定要去看世界杯,去看世界杯肯定得和外国人交流,肯定得会英语啊,主要是我听不懂别人在说什么,但是能读懂意思,似乎眼睛认识这个词,但是耳朵不认识

括号生成

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
// 暴力后判断
class Solution {
bool valid(const string& str) {
int balance = 0;
for (char c : str) {
if (c == '(')
++balance;
else
--balance;
if (balance < 0)
return false;
}
return balance == 0;
}

void generate_all(string current, int n, vector<string>& result) {
if (n == current.size()) {
if (valid(current)) {
result.push_back(current);
}
return;
}
generate_all(current + "(", n, result);
generate_all(current + ")", n, result);
}

public:
vector<string> generateParenthesis(int n) {
vector<string> result;
string current;
generate_all(current, n * 2, result);
return result;
}
};
// dfs 回溯 + 剪枝
class Solution {
public:
vector<string> ans;
vector<string> generateParenthesis(int n) {
string output = "";
dfs(output, 0, 0, n);
return ans;
}
void dfs(string output, int left, int right, int n) {
if (right > left || left > n) // 减枝 出现 ())) 这种 或者n = 3 但output为(((( 都不要
return;
if (left == n && right == n) {
ans.emplace_back(output);
return;
}
dfs(output + '(', left + 1, right, n);
dfs(output + ')', left, right + 1, n);
}
};

为什么下面这段判断是否合法的代码不能用在括号匹配上?

就算把[{(三种括号都维护一个balance依然无法解决类似于[(])括号的嵌套问题,这类序列是不合法的,但是按照下面代码的计算方法得出的结果却是true

1
2
3
4
5
6
7
8
9
10
11
12
13
14
bool valid(const string& str) {
int balance = 0;
for (char c : str) {
if (c == '(') {
++balance;
} else {
--balance;
}
if (balance < 0) {
return false;
}
}
return balance == 0;
}

随机链表的复制

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
/*
// Definition for a Node.
class Node {
public:
int val;
Node* next;
Node* random;

Node(int _val) {
val = _val;
next = NULL;
random = NULL;
}
};
*/

class Solution {
public:
Node* copyRandomList(Node* head) {
if (!head)
return nullptr;
Node* cur = head;
unordered_map<Node*, Node*> map;
// 复制各节点,并建立 “原节点 -> 新节点” 的 Map 映射
while (cur) {
map[cur] = new Node(cur->val);
cur = cur->next;
}
cur = head;
// 构建新链表的 next 和 random 指向
while (cur) {
map[cur]->next = map[cur->next];
map[cur]->random = map[cur->random];
cur = cur->next;
}
// 返回新链表的头节点
return map[head];
}
};

回来了之后再刷了一道算法题,之后把做了一会TrimTalk


今日工作内容

  1. 添加webai-lite后端与推理客户端的日志回传
  2. 修改webai-lite前端原型图

下阶段计划

  1. 对齐webai-lite原型图

python 基础语法

数据类型

1
2
3
4
5
6
7
8
9
age = 21                 # int
price = 19.9 # float
name = "wq" # str
is_student = True # bool
items = [1, 2, 3] # list
point = (10, 20) # tuple 固定内容的结构
user = {"name": "wq"} # dict
ids = {1, 2, 3} # set
nothing = None # NoneType

遍历

1
2
for num in nums:
print(num)

带下标遍历

1
2
for index, num in enumerate(nums):
print(index, num)

字典 map

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
user = {
"name": "wq",
"age": 21,
"major": "robotics"
}

print(user["name"])

user["city"] = "Changzhou"

# 如果 "company" 不存在,get 不会报错,而是返回 None
print(user.get("company"))

# 如果 "company" 不存在,get 不会报错,而是返回 unknown
company = user.get("company", "unknown")

在后端开发里,JSON、接口数据、配置文件,本质上都经常会变成 dict

条件判断

1
2
3
4
5
6
score = 75

if score >= 60:
print("pass")
else:
print("fail")

函数

1
2
def add(a: int, b: int) -> int:
return a + b

self 类似于C++中带this,这里要显示写出来

1
2
3
4
5
6
7
class Student:
def __init__(self, name: str, age: int):
self.name = name
self.age = age

def introduce(self):
print(f"我是 {self.name},今年 {self.age} 岁")

文件读写

with 的作用是自动关闭文件,类似 C++ 里的 RAII 思想

1
2
3
4
5
6
7
with open("hello.txt", "w", encoding="utf-8") as f:
f.write("你好,Python")

with open("hello.txt", "r", encoding="utf-8") as f:
content = f.read()

print(content)

Path 的好处是跨平台更舒服。
比如 Windows 路径是:data\config.json

Linux/macOS 路径是:data/config.json

用 Path 可以少操心这些细节。

1
2
3
from pathlib import Path

file_path = Path("data/config.json")
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from pathlib import Path

# 创建文件
data_dir = Path("data")
data_dir.mkdir(exist_ok=True)

# 写入文件
file_path = Path("hello.txt")

file_path.write_text("你好,Python 文件处理", encoding="utf-8")

# 读取
content = file_path.read_text(encoding="utf-8")
print(content)

json处理

1
2
3
4
5
6
7
8
9
10
11
12
import json

user = {
"name": "wq",
"age": 21
}

text = json.dumps(user, ensure_ascii=False, indent=2)
# ensure_ascii=False 表示保留原始中文,不转义
# indent 表示缩进格数,不写 indent,输出一整行压缩字符串,无换行

print(text)

基础项目管理

1
2
3
4
5
6
python -m venv .venv          创建虚拟环境
source .venv/bin/activate 激活虚拟环境,macOS/Linux
.venv\Scripts\activate 激活虚拟环境,Windows
pip install xxx 安装第三方库
pip freeze > requirements.txt 生成依赖文件
pip install -r requirements.txt 安装项目依赖

类型标注 + dataclass + Pydantic

类型标注

只是在变量后面指定类型,Python 的类型标注默认不会在运行时强制检查,所以你传其他类型也不会报错

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
name: str = "wq"
age: int = 21
score: float = 95.5
is_active: bool = True

scores: list[int] = [85, 90, 72]
names: list[str] = ["张三", "李四"]

user: dict[str, str] = {
"name": "wq",
"city": "Changzhou",
}

model_path: str | None = None # model_path 可以是 str,也可以是 None

def add(a: int, b: int) -> int:
return a + b

dataclass:更轻量的数据类

dataclass 是py标准库中的工具,无需安装

1
2
3
4
5
6
7
8
9
10
11
from dataclasses import dataclass

@dataclass
class TaskConfig:
task_id: str
task_type: str
dataset_path: str
model_name: str
epochs: int
batch_size: int
enable_gpu: bool = False

使用这个数据类(初始化的时候会自动调用自动生成的init函数,类似于默认构造)

1
2
3
4
5
6
7
8
9
10
11
12
config = TaskConfig(
task_id="train_001",
task_type="train",
dataset_path="./datasets/defect_a",
model_name="yolo_defect_v1",
epochs=50,
batch_size=8,
enable_gpu=True,
)

print(config.task_id)
print(config.epochs)

但是虽然 dataclass 很方便,但它不会强制校验类型

Pydantic

Pydantic = Python 里的数据结构定义 + 自动类型转换 + 自动数据校验工具

1
2
3
4
5
6
7
8
9
10
11
from pydantic import BaseModel


class TaskConfig(BaseModel):
task_id: str
task_type: str
dataset_path: str
model_name: str
epochs: int
batch_size: int
enable_gpu: bool = False

使用:

1
2
3
4
5
6
7
8
9
10
11
12
config = TaskConfig(
task_id="train_001",
task_type="train",
dataset_path="./datasets/defect_a",
model_name="yolo_defect_v1",
epochs=50,
batch_size=8,
)

print(config.task_id)
print(config.epochs)
print(config.enable_gpu)

会发现和dataclass的使用是差不多的,只不过Pydantic多了一层数据校验,比如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from pydantic import BaseModel, ValidationError

class TaskConfig(BaseModel):
task_id: str
epochs: int
batch_size: int

try:
config = TaskConfig(
task_id="train_001",
epochs="abc",
batch_size=8,
)
except ValidationError as e:
print(e)

epochs这里传的不是int,会报校验错误

进一步加强校验

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
from typing import Literal
from pydantic import BaseModel, Field

class TaskConfig(BaseModel):
task_id: str
task_type: Literal["train", "infer"]
dataset_path: str
model_name: str
epochs: int = Field(gt=0)
batch_size: int = Field(gt=0)
enable_gpu: bool = False

# Literal 表示当前字段只能从后面的列表中选择

# Field(gt=0) # 大于 0
# Field(ge=0) # 大于等于 0
# Field(lt=100) # 小于 100
# Field(le=100) # 小于等于 100

接下来还学了类似fastAPI的目录结构

1
2
3
4
schemas 负责“数据长什么样”
services 负责“业务怎么做”
utils 负责“通用小工具”
main 负责“把流程串起来”

不要把所有代码都塞进 main.py。

也不要把业务逻辑塞进 utils.py。

utils 应该是比较通用、没有强业务含义的东西,比如:

1
2
3
4
5
6
读写 JSON
路径处理
时间格式化
hash 计算
文件复制
日志格式化

而 services 才是业务逻辑,比如:

1
2
3
4
5
6
创建训练任务
执行推理任务
保存样本集
转换数据集格式
下发任务到客户端
解析训练结果

之后还把今天学到的东西和之前学的FastAPI结合着看了一下,主要就是dataclass和Pydantic

那么接下来我要开始刷leetcode了,主要把常见的题刷一刷