Skip to main content

简化版机器学习项目结构

我将为您提供一个更简洁的项目结构,同时保留核心功能。这个简化版本包含所有必要的组件,但减少了目录层级和文件数量。

简化后的项目结构

ml-project-simple/
├── backend/
│ ├── main.py # FastAPI主应用
│ ├── auth.py # 认证相关
│ ├── models.py # 所有机器学习模型
│ ├── requirements.txt # Python依赖
│ └── Dockerfile # 后端Docker配置
├── frontend/
│ ├── src/
│ │ ├── App.tsx # 主应用组件
│ │ ├── main.tsx # 入口文件
│ │ ├── api.ts # API请求封装
│ │ ├── auth.ts # 认证逻辑
│ │ └── pages/ # 所有页面组件
│ │ ├── Login.tsx
│ │ ├── Dashboard.tsx
│ │ └── algorithms/ # 算法页面
│ │ ├── Linear.tsx
│ │ ├── Logistic.tsx
│ │ ├── RandomForest.tsx
│ │ ├── KMeans.tsx
│ │ └── KNN.tsx
│ ├── package.json
│ ├── tsconfig.json
│ └── Dockerfile # 前端Docker配置
├── docker-compose.yml # 整体部署配置
├── Caddyfile # 反向代理配置
└── README.md # 项目说明

关键文件内容

1. 后端主文件 (backend/main.py)

from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from auth import router as auth_router
from models import router as algo_router

app = FastAPI(title="Simple ML API", version="1.0")

# 允许跨域
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)

# 包含路由
app.include_router(auth_router, prefix="/auth")
app.include_router(algo_router, prefix="/algorithms")

@app.get("/")
def home():
return {"message": "Simple ML API is running"}

2. 后端模型文件 (backend/models.py)

from fastapi import APIRouter
import torch
import numpy as np
from sklearn.datasets import make_regression

router = APIRouter()

# 线性回归模型
class LinearModel:
def __init__(self):
self.model = None

def train(self, X, y):
X_tensor = torch.tensor(X, dtype=torch.float32)
y_tensor = torch.tensor(y, dtype=torch.float32).view(-1, 1)

self.model = torch.nn.Linear(X.shape[1], 1)
criterion = torch.nn.MSELoss()
optimizer = torch.optim.SGD(self.model.parameters(), lr=0.01)

for _ in range(1000):
optimizer.zero_grad()
outputs = self.model(X_tensor)
loss = criterion(outputs, y_tensor)
loss.backward()
optimizer.step()

return {"loss": loss.item()}

# 示例数据准备
def prepare_data():
X, y = make_regression(n_samples=100, n_features=1, noise=10, random_state=42)
return {"X": X.tolist(), "y": y.tolist()}

# 路由
linear_model = LinearModel()

@router.get("/linear/data")
def get_data():
return prepare_data()

@router.post("/linear/train")
def train_model(data: dict):
X = np.array(data["X"])
y = np.array(data["y"])
result = linear_model.train(X, y)
return result

3. 前端主应用 (frontend/src/App.tsx)

import { BrowserRouter, Routes, Route } from 'react-router-dom'
import { Layout, Menu } from 'antd'
import { Dashboard, Login } from './pages'
import { Linear, Logistic, RandomForest, KMeans, KNN } from './pages/algorithms'

const { Header, Content, Sider } = Layout

function App() {
return (
<BrowserRouter>
<Layout style={{ minHeight: '100vh' }}>
<Sider>
<Menu theme="dark" mode="inline">
<Menu.Item key="dashboard">Dashboard</Menu.Item>
<Menu.SubMenu key="algorithms" title="Algorithms">
<Menu.Item key="linear">Linear Regression</Menu.Item>
<Menu.Item key="logistic">Logistic Regression</Menu.Item>
<Menu.Item key="randomforest">Random Forest</Menu.Item>
<Menu.Item key="kmeans">K-Means</Menu.Item>
<Menu.Item key="knn">KNN</Menu.Item>
</Menu.SubMenu>
</Menu>
</Sider>
<Layout>
<Header style={{ background: '#fff' }} />
<Content style={{ margin: '16px' }}>
<Routes>
<Route path="/" element={<Dashboard />} />
<Route path="/login" element={<Login />} />
<Route path="/algorithms/linear" element={<Linear />} />
<Route path="/algorithms/logistic" element={<Logistic />} />
<Route path="/algorithms/randomforest" element={<RandomForest />} />
<Route path="/algorithms/kmeans" element={<KMeans />} />
<Route path="/algorithms/knn" element={<KNN />} />
</Routes>
</Content>
</Layout>
</Layout>
</BrowserRouter>
)
}

export default App

4. 线性回归页面 (frontend/src/pages/algorithms/Linear.tsx)

import { Card, Button, Table, Typography } from 'antd'
import { useState } from 'react'
import api from '../../api'

const { Title } = Typography

export default function LinearRegression() {
const [data, setData] = useState<any>(null)
const [loading, setLoading] = useState(false)
const [trained, setTrained] = useState(false)

const loadData = async () => {
setLoading(true)
try {
const res = await api.get('/algorithms/linear/data')
setData(res.data)
} finally {
setLoading(false)
}
}

const trainModel = async () => {
setLoading(true)
try {
await api.post('/algorithms/linear/train', data)
setTrained(true)
} finally {
setLoading(false)
}
}

return (
<Card loading={loading}>
<Title level={3}>Linear Regression</Title>
<Button onClick={loadData}>Load Data</Button>
{data && (
<>
<Button onClick={trainModel} style={{ marginLeft: 16 }}>
Train Model
</Button>
{trained && <span style={{ marginLeft: 16 }}>Training completed!</span>}
<Table
dataSource={data.X.map((x: number[], i: number) => ({
key: i,
x: x[0],
y: data.y[i]
}))}
columns={[
{ title: 'X', dataIndex: 'x' },
{ title: 'Y', dataIndex: 'y' }
]}
style={{ marginTop: 16 }}
/>
</>
)}
</Card>
)
}

5. Docker Compose 文件

version: '3.8'

services:
backend:
build: ./backend
ports:
- "8000:8000"
environment:
- PORT=8000
restart: unless-stopped

frontend:
build: ./frontend
ports:
- "3000:3000"
restart: unless-stopped

caddy:
image: caddy:latest
ports:
- "80:80"
- "443:443"
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile
depends_on:
- backend
- frontend

6. 简化版 Caddyfile

yourdomain.com {
reverse_proxy frontend:3000
}

api.yourdomain.com {
reverse_proxy backend:8000
}

如何运行

  1. 开发模式:

    • 后端: cd backend && uvicorn main:app --reload
    • 前端: cd frontend && npm start
  2. 生产部署:

    docker-compose up -d --build

简化说明

  1. 后端简化:

    • 将所有模型合并到一个文件
    • 减少中间件和依赖
    • 简化认证流程
  2. 前端简化:

    • 减少状态管理复杂度
    • 合并相似组件
    • 简化路由结构
  3. 部署简化:

    • 减少不必要的服务
    • 简化配置

这个简化版本保留了核心功能:

  • 5种机器学习算法实现
  • 基本的前后端交互
  • 容器化部署
  • 认证功能
  • 响应式界面

您可以根据需要在此基础上进行扩展。