Preface
This book captures development notes, design proposals, and architecture decisions made during the development of Hahaha, including (but not limited to):
- Project overview: what the project is, how the repository is structured
- Implementation notes: high-level APIs and key internal interfaces between layers
- Feature discussions: why we do it, what we do, what we explicitly don’t do, and priorities
- Design trade-offs: comparing alternatives, risk analysis, compatibility, and evolution strategy
- Implementation approach: how to implement critical modules, code organization, pitfalls and postmortems
- Collaboration records: conclusions, follow-ups, and next actions
Intended audience
- New contributors: quickly understand the project’s context and historical decisions
- Feature implementers: align on boundaries, interfaces, and compatibility strategy
- Maintainers: build on existing conclusions and reduce repeated discussions
How to use this book
- Start with “Guide”: conventions and writing style
- Then “Project”: scope, terminology, and overall goals
- Write proposals in “Design”: solutions, interfaces, data structures, and boundaries
- Record conclusions in “ADR”: what we decided and why
- Keep process notes in “Discussions”: meeting notes, reviews, and iteration logs
English
This is the English entry point for the book.
- Start here:
en/README.md - Or browse by topic using the sidebar (Project / Design / Guide / ADR / etc.)
Project Background
This section explains what Hahaha is, what problems it aims to solve, and where the boundaries are, plus cross-cutting basics such as terminology, conventions, and goals.
What belongs here
- Project introduction: goals, scenarios, and target users (who uses it / why)
- Scope and boundaries: define “what we do / what we don’t do” to avoid scope creep
- Glossary / terminology: reduce ambiguity in communication
- Global constraints: compatibility, performance targets, security requirements, release strategy, etc.
What does not belong here
- Detailed designs and interface specs (put them in
en/design/) - Final decisions (put them in
en/adr/) - Process discussions and meeting notes (put them in
en/discussions/)
Maintenance tips
- If a piece of “prerequisite knowledge” keeps coming up in discussions, document it here
- When other chapters reference conventions/terms, prefer linking to the relevant page in this section
Project Introduction
What is Hahaha?
Hahaha is a modern open-source mathematics and machine learning library. It is designed for ML computation while also having strong educational value. Beyond efficient numerical computing, the project aims to make learning machine learning more intuitive and enjoyable.
Vision
Hahaha’s core belief is to make machine learning simple, fun, and easier to understand. We believe that well-designed APIs and clear documentation allow developers to both enjoy programming and deeply understand the essence of machine learning algorithms.
Main goals
-
Build a high-performance math/ML library
- Provide tensor operations, matrix computation, and other foundational math capabilities
- Support automatic differentiation (Autograd)
- Implement common machine learning algorithms and optimizers
-
Keep excellent implementations and design reasoning
- Clear code structure that is easy to read and learn from
- Detailed docs and comments to help understand algorithmic ideas
- Record design patterns and architecture decisions
-
Visualize ML workflows
- Provide tools to visualize training processes
- Support visualization of model structures and computation graphs
- Make complex execution flows easier to grasp
Architecture design
Hahaha uses a layered architecture, ranging from low-level hardware abstraction to high-level user interfaces, forming a complete stack. The overall architecture is based on modular design under the core directory and progresses from low to high:
1. Backend layer
Located under core/include/backend/, responsible for low-level compute:
- Device abstraction:
Device.hprovides a unified hardware interface - SIMD optimizations:
vectorize/containsSimdVector.handVectorizedOp.husing CPU vector instruction sets - GPU compute:
gpu/reserves CUDA hooks (GpuContext.h,GpuKernel.h,GpuMemory.h) - Compute dispatching:
DeviceComputeDispatcher.hschedules compute tasks across devices
2. Common layer
Located under core/include/common/, providing base components:
- Configuration:
Config.hmanages system configuration - Type definitions:
definitions.hdefines data types and constants - Operator interface:
Operator.hdefines operator abstractions - Result handling:
Res.hunifies error handling and return values
3. Math layer
Located under core/include/math/, implementing core math ops:
- Tensor data structures:
ds/includesTensorData.h,TensorShape.h,TensorStride.h - Tensor wrapper:
TensorWrapper.hprovides higher-level tensor operation APIs - Core tensor class:
Tensor.hdefines the main tensor interface
4. Compute layer
Located under core/include/compute/, implementing autograd and computation graphs:
- Computation graph:
graph/contains node definitions and topological sorting - Compute functions:
graph/compute_funs/provides implementations for math operations - Autograd: supports dynamic graphs, gradient computation, and backpropagation
5. ML layer
Located under core/include/ml/, implementing ML algorithms:
- Model architectures:
model/includesLinear.h,LinearRegression.h,KNearestNeighbors.h - Optimizers:
optimizer/contains algorithms likeSGDOptimizer.h - Loss functions:
loss/providesMSELoss.hand others - Datasets:
dataset/abstracts data loading and preprocessing
6. Display layer
Located under core/include/display/, providing visualization:
- Window management:
GlfwWindow.hprovides a GLFW-based window abstraction - Visualizers:
Visualizer.handWindow.hsupport training-process visualization
7. Utils layer
Located under core/include/utils/, providing utilities:
- Logging:
log/contains a full logging framework - Common utilities:
common/provides helper data structures
Tooling and support
- Build system: modern Meson + Ninja based build workflow
- External deps:
extern/externlibs/includes required third-party libs such as ImGui and GLFW - Examples:
examples/contains demos like autograd, basic_usage, ml_basic_usage, and ml_visualizer - Tests:
tests/contains unit and integration tests - Dev tools:
format.shformats and checks code style
Quickstart
Basic usage example
#include <hahaha/Tensor.h>
int main() {
// Create tensors
auto x = hahaha::Tensor<float>::buildFromVector({1.0f, 2.0f, 3.0f, 4.0f});
auto y = hahaha::Tensor<float>::buildFromVector({2.0f, 3.0f, 4.0f, 5.0f});
// Compute
auto z = x + y * 2.0f;
// Autograd
z.backward();
std::cout << "Result shape: (" << z.getShape()[0] << ")" << std::endl;
std::cout << "Gradient shape: (" << x.grad().getShape()[0] << ")" << std::endl;
return 0;
}
Machine learning example
#include <hahaha/Tensor.h>
#include <hahaha/ml/model/LinearRegression.h>
#include <hahaha/ml/optimizer/SGDOptimizer.h>
#include <hahaha/ml/loss/MSELoss.h>
int main() {
// Create a linear regression model
auto model = hahaha::ml::LinearRegression<float>();
// Prepare training data
auto X = hahaha::Tensor<float>::buildFromVector({1.0f, 2.0f, 3.0f, 4.0f});
auto y = hahaha::Tensor<float>::buildFromVector({2.0f, 4.0f, 6.0f, 8.0f});
// Train the model
for (int epoch = 0; epoch < 100; ++epoch) {
model.train(X, y);
}
std::cout << "Training completed!" << std::endl;
return 0;
}
What makes the project special
Education-oriented
- Clear structure: each module has detailed comments and documentation
- Progressive learning path: from basic math to advanced models
- Visualization support: make abstract algorithms more intuitive
High performance
- Multiple backends: CPU, GPU, and distributed computing
- SIMD optimizations: make full use of modern CPU vector instructions
- Memory optimizations: efficient memory management and (planned) GC strategy
Developer-friendly
- Modern C++: based on C++23 with strong type-safety and performance
- Modular design: clear architecture that is easy to extend and maintain
- Solid tests: high-coverage unit and integration tests
Visualization
- Training visualization: real-time curves for loss/accuracy and more
- Model structure visualization: see network architectures directly
- Computation graph visualization: understand how autograd executes
Why the name “Hahaha”?
Why not choose a cool technical name like PyTorch or TensorFlow?
Because Hahaha hopes that when you learn and use machine learning (or deep learning) to assist your daily work, you can genuinely feel happy.
We believe programming should be joyful, and learning should be fun. With well-designed APIs, clear documentation, and intuitive visualization, we hope every developer using Hahaha can enjoy the process while solving real problems.
from Napbad: It's definitely not because the author couldn't think of a good name. Definitely not. Well, that's it.
Core Architecture
Hahaha follows the principles of layered decoupling and unified interfaces, ensuring a smooth path from low-level tensor operations to high-level neural network models.
Tech Stack and Choices
From day one, Hahaha has aimed for education-first and a pragmatic balance with performance, so the technology choices are modern but intentionally restrained.
Core language: C++23
We chose the latest C++23 standard.
- Why so new? C++23 brings stronger template metaprogramming expressiveness (Concepts) and features like
std::stacktrace, which help express tensor operations cleanly and improve debugging. - Educational value: demonstrate how modern C++ tackles complexity in high-performance computing, instead of piling up C-style code.
Build system: Meson + Ninja
The project uses Meson:
- Readability:
meson.buildis easy to follow, lowering the barrier for contributors to understand the build. - Speed: the Ninja backend provides a very fast incremental compile experience.
Core dependencies (extern libs)
We avoid heavy dependencies and only bring in a small set of key components:
- GoogleTest (GTest): ensure each math operator has solid unit tests.
- ImGui + GLFW: for
MLVisualizer, rendering real-time training curves and parameter distribution. - CUDA 13.0 (reserved): architecture hooks are prepared for future GPU acceleration.
Tooling and infrastructure
- Docker/Devcontainer: provide a standardized C++23 build environment.
- clang-format/clang-tidy: enforce style via scripts such as
format.sh.
Roadmap and Task List
Development progress summarized from repo/Hahaha/doc/zh-cn/Task.md:
Completed (v0.0.1)
- Tensor core: dimension management, memory ownership, nested initialization, broadcasting adaptation.
-
Linear algebra basics: matrix multiplication (
matmul), transpose (transpose), sum (sum). - Autograd engine: dynamic graph nodes, topological sorting, backpropagation.
- Optimizer basics: SGD (stochastic gradient descent).
- Visualization: real-time training curve rendering via ImGui.
- Infrastructure: logging system, Docker dev env, Meson build flow.
In progress (v0.1.0 target)
- Better broadcasting: support more complex cross-dimension tensor operations.
- Dataset implementation: create dataset abstraction and finish dataset loading.
- Modern ML models: linear regression, KNN template implementation.
-
Logging enhancements: integrate
std::stacktracefor crash-site tracing.
Future (backlog)
- Backend acceleration: CUDA VRAM management and core kernels.
- Neural network layers: fully-connected, convolution, batch normalization.
- Advanced math: SVD, matrix inverse, eigenvalue computations.
- Python bindings: provide Python API via Pybind11.
Design Docs
This section contains documents that are still in the design phase or worth referencing long-term. It focuses on comparing alternatives and implementation-ready details, but it is not the same as final decisions.
What belongs here
- Requirement breakdown: goals, non-goals, constraints, boundaries
- Alternatives: options, pros/cons, risks, migration paths
- Interface / protocol design: HTTP/RPC/CLI, request/response, error codes, versioning strategy
- Data structures & storage: schema, indexes, compatibility and evolution
- Testing & observability: key cases, regression points, metrics and alerts
What does not belong here
- Final conclusions that have been decided (put them in
en/adr/and link back from here) - Meeting notes and scattered discussions (put them in
en/discussions/)
Suggested template (recommended sections)
- Background and problem statement
- Goals / non-goals
- Options and trade-offs
- Compatibility and evolution
- Delivery plan (milestones / rollback plan)
Tensor (Design)
The corresponding Chinese page (src/zh/design/tensor.md) is currently empty in the source repository. This English page provides a starter outline for future design content.
Suggested topics
- Goals / non-goals (API ergonomics vs performance vs educational clarity)
- Data model: shape, stride, contiguous vs non-contiguous
- Memory ownership and lifetime
- Broadcasting rules and behavior
- Dtype and device abstraction
- Interop: views, slices, and conversions
- Error handling and diagnostics
- Testing strategy (correctness + performance regression)
Autograd (Design)
The corresponding Chinese page (src/zh/design/autograd.md) is currently empty in the source repository. This English page provides a starter outline for future design content.
Suggested topics
- Goals / non-goals (dynamic graph vs static graph; educational clarity)
- Graph data structures: nodes, edges, topological ordering
- Gradient storage and accumulation semantics
- Backward API:
backward()behavior and entry points - Operator definitions and derivative rules
- Memory management and lifetime during backprop
- Debugging: tracing,
std::stacktrace, graph visualization hooks - Testing strategy (numerical gradient checks + edge cases)
Backend (Design)
The corresponding Chinese page (src/zh/design/backend.md) is currently empty in the source repository. This English page provides a starter outline for future design content.
Suggested topics
- Device abstraction and compute dispatching
- CPU backend: threading, vectorization, and kernel organization
- GPU backend plan (CUDA hooks, kernels, memory management)
- Data movement and synchronization
- Error handling, diagnostics, and performance profiling
- Compatibility constraints across platforms/compilers
Display / Visualization (Design)
The corresponding Chinese page (src/zh/design/display.md) is currently empty in the source repository. This English page provides a starter outline for future design content.
Suggested topics
- Visualization goals (training curves, parameter distribution, model structure)
- UI toolkit choices (ImGui + GLFW)
- Data pipeline: what metrics are emitted and how they’re rendered
- Performance considerations (sampling, buffering, async rendering)
- Extensibility (custom panels, plugins, hooks)
Guide
This section explains how to use and maintain this book, aiming to reduce collaboration costs and help new contributors ramp up quickly.
What belongs here
- Getting started & preview: how to install mdBook, run local preview, and build
- Writing style: heading levels, code blocks, links, images, naming conventions
- Collaboration conventions: review flow, how to submit docs, how to split chapters
What does not belong here
- Specific feature designs (put them in
en/design/) - Final decisions (put them in
en/adr/) - Meeting notes / process discussions (put them in
en/discussions/)
Naming tips
- File names: lowercase English words with
-(e.g.writing-style.md) - Titles: keep them short and scannable; include technical terms when helpful
Quickstart
Goals
- Run locally: preview while editing
- Publish on GitHub: host the static site using GitHub Pages
Directory layout (example)
.
├─ book.toml
├─ src/
│ ├─ zh/
│ │ ├─ SUMMARY.md
│ │ ├─ README.md
│ │ ├─ guide/
│ │ ├─ hahaha/
│ │ ├─ design/
│ │ ├─ adr/
│ │ ├─ discussions/
│ │ └─ appendix/
│ └─ en/
│ ├─ SUMMARY.md
│ ├─ README.md
│ ├─ guide/
│ ├─ hahaha/
│ ├─ design/
│ ├─ adr/
│ ├─ discussions/
│ └─ appendix/
└─ .github/workflows/deploy.yml (optional)
Next steps
- For local preview right away: see “Local Preview”
- To keep writing style consistent: see “Writing Style”
Local Preview
Install mdBook
mdBook is a Rust tool. Installing via cargo is recommended:
cargo install mdbook --locked
If you don’t have the Rust toolchain yet, install Rust first (we recommend rustup).
Start the preview server
Run in the repository root:
mdbook serve
By default it listens on http://localhost:3000 and auto-reloads when you edit Markdown under src/ (including src/en/ and src/zh/).
You can access languages via paths:
- English:
/en/... - Chinese:
/zh/...
Build static files
mdbook build
The output directory defaults to book/ (configured by [build].build-dir in book.toml).
Build and Environment Setup
The project strongly recommends a unified development environment to ensure compatibility with C++23 features.
Requirements
- OS: Linux (recommended) / Windows WSL2 / macOS (requires a recent Clang)
- Compiler: GCC 13+ or Clang 16+ (must fully support C++23)
- Build tools: Meson 1.3.2+, Ninja 1.11.1+
- GPU (optional): NVIDIA GPU (CUDA 13.0+)
Recommended approach: Docker / Devcontainer
If you use VS Code, clicking “Reopen in Container” is usually the easiest option.
Build with Docker manually
# Build the image
docker build -t hahaha-dev .
# Enter the environment
docker run --gpus all -it --rm -v $(pwd):/workspace hahaha-dev
Local build workflow
Run in the repo/Hahaha root directory:
# Initialize build directory (Debug)
meson setup builddir --buildtype=debug
# Build
ninja -C builddir
# Run unit tests
meson test -C builddir -v
Common issues
- Missing dependencies: Meson may use
wrapfiles or your system package manager. If it reportsglfw3missing, ensure the corresponding dev package is installed. - C++ standard errors: verify your compiler truly supports
-std=c++23.
Writing Style
This is not a “strict standard”, but a set of conventions that makes long-term maintenance easier.
Recommended structure
- Start with the conclusion: readers usually want “how to do it / what it looks like”
- Then provide steps: from easy to hard, from frequent to rare
- Finally add background: principles, trade-offs, pitfalls
Heading levels
- One document should solve one problem
- Keep headings short so the sidebar is easy to scan
Example:
## One-sentence conclusion
## When to use
## Steps
## FAQ
Code blocks
mdbook serve
[book]
title = "My Book"
Links
- Internal links: use relative paths, e.g.
../appendix/faq.md - External links: add descriptive text; avoid pasting bare URLs
For Developers
Welcome to the Hahaha developer community!
This section is for all developers who want to contribute. Whether you are an experienced engineer or just getting started, there is a place for you here.
Welcome
Hahaha is an open-source machine learning library project. We focus on:
- Education-first: make learning ML more intuitive and fun
- High performance: modern C++ implementation, multiple compute backends
- Code quality: clear, maintainable, and extensible design
Developer roles
Core contributors
- Architects: participate in system design and technical choices
- Core developers: implement and maintain core modules
- Test engineers: ensure quality and stability
Community contributors
- Feature developers: implement new features and improve existing ones
- Documentation maintainers: improve docs and examples
- Problem solvers: fix bugs and performance issues
Newcomer contributors
- Example writers: create usage examples and tutorials
- Test contributors: add unit tests and integration tests
- Translators: provide multilingual documentation
Development environment
Recommended setup
Operating systems:
- Linux (Ubuntu 20.04+, Fedora 34+, Arch Linux)
- macOS (10.15+)
- Windows (WSL2 recommended)
Developer tools:
- IDE: CLion, VS Code, Visual Studio
- Compiler: GCC 11+, Clang 14+, MSVC 2022+
- Build system: Meson + Ninja
- Version control: Git
Setup guide
For detailed steps, see: How to Contribute
Code quality standards
Design principles
- Clarity first: code should be easy to understand; readability comes first
- Modularity: independent functionality, clear interfaces, easy to test
- Performance and safety: keep performance while ensuring memory safety
- Educational value: structure should reflect algorithmic ideas
Coding conventions
- Language version: C++23
- Naming: follow the project conventions
- Docs: every public interface should have documentation comments
- Testing: core functionality should have good unit test coverage
Contribution flow
Quick start
- Understand the project: read the project intro and architecture docs
- Pick a task: check the roadmap and TODO list
- Set up environment: configure your dev environment
- Start coding: follow the contribution guide
Workflow
Pick a task → Create a branch → Write code → Write tests → Open a PR → Review → Merge
For details, see: How to Contribute
Learning resources
Project docs
- Project Introduction: project goals and architecture overview
- Tech Stack: technologies and tools
- Roadmap: planning and direction
- Architecture: deeper architecture context
Developer resources
- Contribution Guide: end-to-end contribution workflow
- Design docs: system designs and architecture notes
- FAQ: common questions
External resources
- C++23 standard: get familiar with modern C++ features
- ML fundamentals: understand the algorithmic basics
- Open-source development: learn OSS collaboration workflows
Community and communication
Channels
- GitHub Issues: bug reports and suggestions
- GitHub Discussions: technical discussions and proposals
- Pull Requests: code contribution and review
Guidelines
- Be respectful: friendly, constructive communication
- Stay problem-focused: focus on solving problems, not debating people
- Be open-minded: welcome different opinions and suggestions
- Contribute proactively: not only report issues, but also propose solutions
Recognition
Types of contributions
- Code: features, bug fixes, performance improvements
- Docs: writing, translating, and improving documentation
- Tests: adding test cases and improving coverage
- Design: architecture design, API design, technical research
How we recognize contributions
- Contributors list
- Authorship in code where relevant
- Documenting design/implementation reasoning
- Community acknowledgement
Growth path
Getting started
- Start by running and understanding existing examples
- Fix small issues and simple bugs
- Add tests for existing functionality
- Improve documentation and comments
Advancing
- Develop new modules and features
- Improve architecture and performance
- Build developer tools and scripts
- Help other contributors grow
Vision
We believe programming should be joyful and learning should be fun. Through Hahaha, we hope to:
- Provide high-quality learning materials for developers
- Build a friendly and open open-source community
- Promote machine learning education
- Create high-performance tools with educational value
Getting help
If you run into issues while developing:
- Read the docs: check relevant pages and the FAQ first
- Search issues: see if someone already reported something similar
- Ask: open a GitHub issue with details
- Reach out: the community will do its best to help
Let’s build a fun and education-oriented ML library together!
Last updated: Jan 2026
How to Contribute
Thanks for your interest in the Hahaha project! We welcome all kinds of contributions—code, documentation, tests, and design suggestions. This guide helps you get started quickly.
Before you contribute
1. Understand the project
Before starting, please:
- Read the Project Introduction to understand goals and architecture
- Check the Roadmap to understand planning
- Read the Tech Stack to understand tools and choices
2. Pick a task
Find a task you’re interested in from doc/TODO.md in the main project repository:
- [ ] Implement optimizer (help wanted)
Once you decide to take it, add your info:
- [/] Implement optimizer - [Your Name](Your GitHub link) (your email)
Development environment
System requirements
- OS: Linux, macOS, or Windows (WSL)
- Compiler: GCC 11+, Clang 14+, or MSVC 2022+
- CMake: 3.20+
- Python: 3.8+ (for build scripts and tests)
Clone and build
- Fork the project
git clone https://github.com/YOUR_USERNAME/Hahaha.git
cd Hahaha
- Create a development branch
Before starting development, please create a new branch based on the dev branch. The branch name should clearly describe your work:
# For new features
git checkout -b feature/[feature-name]-implement
# Example: feature/adam-optimizer-implement
# For bug fixes
git checkout -b bug/[bug-description]-fix
# Example: bug/tensor-broadcast-fix
# For documentation updates
git checkout -b docs/[doc-content]-update
# Example: docs/api-documentation-update
Branch naming suggestions:
- Use lowercase letters and hyphens
- Keep names concise but descriptive
- Avoid overly long branch names
- Install dependencies
# Ubuntu/Debian
sudo apt update
sudo apt install build-essential cmake ninja-build
# macOS (Homebrew)
brew install cmake ninja
# Arch Linux
sudo pacman -S cmake ninja
# Fedora/CentOS
sudo dnf install cmake ninja-build
# or
sudo yum install cmake ninja-build
- Build
# Use Meson (recommended)
meson setup builddir
ninja -C builddir
# After building, the library files will be in the builddir directory
IDE setup
Recommended IDEs:
- CLion: native support for CMake and Meson projects
- VS Code: install C++ extensions and CMake Tools or Meson tools
- Visual Studio: supports CMake projects
Coding standards
For detailed coding standards, please refer to: Code Style Documentation
Commit message format
Commit messages should describe the change clearly:
type(scope): short summary
Details (optional)
Fixes #123
Common types:
feature: new featurefix: bug fixdocs: documentation updates or comment improvementsstyle: formatting onlyrefactor: refactoringtest: testschore: build/tooling
Development workflow
1. Create a branch
# Keep dev branch up to date (if upstream is configured)
git checkout dev
git pull upstream dev
# Create a feature branch (use clear naming)
git checkout -b feature/your-feature-name
# Or a bug fix branch
git checkout -b bug/issue-description-fix
# Or a documentation branch
git checkout -b docs/documentation-update
2. Implement
- Follow the necessary coding standards
- Add necessary comments
- Write unit tests
- Update related docs
3. Test
Run the test suite:
# Build and run tests with Meson
meson setup builddir
ninja -C builddir
ninja -C builddir test
# Or use CMake
mkdir cmake-build && cd cmake-build
cmake .. -GNinja
ninja
ctest
# Run specific test modules
# Tensor tests
ninja -C builddir test-tensor
# Autograd tests
ninja -C builddir test-autograd
# ML tests
ninja -C builddir test-ml
4. Format
Use the project formatting script:
# Format code
./format.sh
# Check formatting
./format.sh --check
Submitting a Pull Request
1. Push your branch
git add .
git commit -m "feature: implement tensor addition
- add Tensor::add method
- support broadcasting
- add corresponding unit tests"
git push origin feature/tensor-add
2. Create the PR
On GitHub:
- Open your fork
- Click “Compare & pull request”
- Fill in the PR description:
- summarize what changed
- link related issues (if any)
- describe how you tested
- @mention appropriate reviewers
3. Review
After the PR is created:
- wait for CI/CD checks to pass
- respond to reviewer comments
- update code based on feedback
- after approval, wait for merge
Other notes
Working on an already-claimed task
If the task you want already has an owner:
- contact the owner (via issue or PR)
- discuss how to split the work
- create a sub-branch based on the owner’s branch:
git checkout feature/optimizer-implementation
git checkout -b feature/optimizer-implementation-adam
Types of contributions
Besides code, we also welcome:
- Docs improvements: fix doc issues, add examples
- Testing: improve coverage, add edge-case tests
- Performance: optimize algorithms or memory usage
- Tooling: build scripts, CI/CD workflows
- Design discussions: record architecture decisions in ADRs
Recognition
Your contributions may be recognized via:
- adding your info to the contributors list
- recording your implementation reasoning in the docs
- participating in project decision discussions
Documenting implementation reasoning (encouraged)
Why we encourage it
Hahaha emphasizes educational value. Great code with clear documentation has a much bigger impact. It helps others understand your work, and also:
- Knowledge transfer: future contributors can learn the ideas and details faster
- Collaboration: improves teamwork and code reviews
- Learning value: provides thinking processes and design decisions for learners
- Maintenance: helps people understand existing logic when changes are needed
What to document
When you implement, optimize, or fix bugs in code, we encourage you to record your reasoning in the relevant documentation.
Document location guidelines:
Documents should be placed in the src/<lang>/explains/ directory (we encourage you to use English), and the directory structure should correspond to the code directory structure. For example:
- If you implement, optimize, or fix bugs in
core/include/ml/optimizer/AdamOptimizer.h, you can add relevant content tosrc/en/explains/ml/optimizer.md - If you implement, optimize, or fix bugs in
core/include/math/TensorWrapper.h, you can add relevant content tosrc/en/explains/math/tensor-wrapper.md - If you implement, optimize, or fix bugs in
core/include/compute/graph/ComputeNode.h, you can add relevant content tosrc/en/explains/compute/graph.md
If the corresponding document file does not exist, you can create a new file. The document directory structure should clearly reflect the design thinking of the code.
We fully support using AI to help with writing: you can describe your ideas verbally and let AI polish them (especially for hard-to-write formulas), or keep your own style with minimal polishing—we respect your choice.
That said, we hope to see real personal understanding and thought, rather than purely AI-generated text that is hard to follow.
1. New feature implementation
Possible things to record:
- Design reasoning: why this approach, and what alternatives existed?
- Algorithm: the math principles and steps
- Architecture: how it integrates with other modules; interface principles
- Performance: time/space complexity and optimizations (if any)
- Edge cases: how special inputs are handled (if needed)
Example doc structure:
## Feature name
### Implementation approach
[describe your design and decisions]
### Algorithm
[math principles and steps]
### Architecture
[integration with the existing system]
### Performance
[complexity and optimization notes]
2. Optimizing existing functionality
When you optimize or refactor code, update docs to record:
- Motivation: why the optimization is needed
- Improvements: measurable wins (speed, memory, etc.)
- Compatibility: whether APIs changed and how you kept backwards compatibility
- Trade-offs: benefits and costs of the change
Example update:
## Optimization notes
### [Feature implemented by the optimization](link-to-your-change)
- **What changed**: [details]
- **Improvement**: compute time -30%, memory -20%
- **How**: [technical details]
- **Compatibility**: fully backwards compatible
3. Bug fixes
When fixing bugs, record:
- Symptoms: observed behavior and impact scope
- Root cause: why it happened
- Fix: why you chose this fix
- Verification: how you validated correctness
Where to place docs
We recommend placing docs in locations corresponding to the code implementation, for example:
- Core algorithm explanations can be placed in
src/<lang>/hahaha/(e.g.src/en/hahaha/) - Architecture design docs can be placed in
src/<lang>/design/(e.g.src/en/design/) - API interface documentation can be in header file comments and synced to relevant docs
Practical tips
- Try writing design docs before implementation—it helps clarify thinking
- Combine docs with code comments: comments for details, docs for overview
- Periodically review docs during code review
- Start small: improve docs for existing features to get familiar
Benefits of documenting
Contributors who document their thinking often get:
- Faster reviews: clear docs help reviewers understand your implementation approach quickly
- Documentation and code sync PRs: you can submit code implementation and documentation as separate PRs, reference the documentation PR in the code PR, and we will merge them together after review
- Community recognition: your thinking becomes valuable knowledge for the project
- Learning opportunities: documentation deepens your own understanding
- More impact: your design ideas may shape the project's future
We believe: good code + good docs = excellent contributions. We don’t strictly require it, but we genuinely encourage it—it increases the value of your work and makes the project better.
Getting help
If you run into issues while contributing:
- check the FAQ
- ask in GitHub Issues
- join community discussions
We aim to make contributing enjoyable and efficient!
ADR: Architecture Decision Records
ADRs capture what we finally decided and why we decided it. Their value is that future readers can quickly understand the constraints and trade-offs at the time, rather than repeating the same discussions again.
What belongs here
- Key decisions that the team has agreed on (e.g. adopting a protocol / storage / architectural split)
- Context, constraints, alternatives, and rationale
- Impact and follow-up actions (migration, compatibility, risks)
What does not belong here
- Drafts that are still undecided (put them in
en/design/) - Raw process notes and review comments (put them in
en/discussions/)
Numbering and naming
- File name:
NNNN-title.md(e.g.0001-cpp23.md) - Title format:
ADR-NNNN: ... - Directory organization: Related ADRs can be organized in subdirectories (e.g.
1-cpp23/,2-basic-project-design/)
ADR List
ADR-0001: Adopt Modern C++23 Features
- Location: 1-cpp23/0001-cpp23.md
- Status: Accepted
- Content: Decision to fully embrace C++23 standard, using modern features like Concepts and stacktrace
ADR-0002: Basic Project Design
- Location: 2-basic-project-design/
- Status: Accepted
- Content: Includes basic design decisions such as project structure, CI/CD requirements, dependency management, testing requirements, feature addition requirements, documentation and comment requirements, contribution guidelines, and error handling guidelines
ADR-0001: Adopt Modern C++23 Features
Status
Accepted
Context
Hahaha is positioned as an education-oriented library. To demonstrate state-of-the-art C++ paradigms, we need to decide what C++ standard level the project targets.
Decision
We decided to fully embrace C++23.
Key reasons
- Concepts: compared to
enable_if, Concepts make tensor-template error messages much more human-readable. - stacktrace: built-in stack traces greatly reduce the debugging cost of low-level math libraries.
Consequences
- Compiler requirements: GCC 13+ or Clang 16+ are required.
- Educational value: the codebase becomes a great reference for learning modern C++.
- Risk: older systems may not compile directly; Docker containers may be required.
Basic Project Design
This decision establishes the basic project design decisions.
Decision Makers:
-
Napbad -
JiansongShen
Contents
- Project Basic Structure
- Project CI/CD Configuration
- Project Dependency Management
- Project Testing Requirements
- Project Feature Addition Requirements
- Project Documentation and Comment Requirements
- Project Contribution Guidelines
- Error Handling
Project Basic Structure
I. Overall Design Overview
The project adopts a four-layer architecture design, abstracting layer by layer from bottom to top, extending from hardware and computation scheduling to upper-level public interfaces and application layers. Each layer has clear responsibilities and well-defined boundaries.
II. Four-Layer Division
Layer 1: Low-Level Computation and Hardware Abstraction Layer
Core Responsibilities:
Direct interaction with low-level hardware and computational resources, providing unified computation and device abstraction.
Key Components:
Compute DispatcherDeviceabstract class- Low-level hardware interface interaction layer
Characteristics:
- Shields differences between different hardware implementations
- Provides unified, extensible computation scheduling capabilities for upper layers
Layer 2: Data Abstraction and Data Operation Layer
Core Responsibilities:
Abstracts computational data and provides intermediate-level data operation capabilities.
Key Components:
TensorTensor OperatorLinear Algebra Operator- Various intermediate-level data operation classes
Characteristics:
- Unified data representation
- Handles operations and transformations of tensors and structured data
- Acts as a bridge between computation and algorithm layers
Layer 3: Machine Learning and Computation Graph Core Layer
Core Responsibilities:
Builds high-level computation and learning capabilities, serving as the project's core logic layer.
Key Components:
- Machine Learning module
- Deep Learning module
- Dataset support system
- Computation Graph
- Core computation structures such as DA graphs
Characteristics:
- Responsible for model construction, training, and inference logic
- Unifies core mechanisms such as computation graphs and automatic differentiation
Layer 4: Public Interface and Upper Application Layer
Core Responsibilities:
Provides unified, easy-to-use methods and interfaces externally, targeting public internet or upper-level applications.
Key Components:
- Method-level operation interfaces
- Public internet-facing access and invocation layer
Characteristics:
- Provides stable APIs
- Shields internal complex implementations
- Supports integration with upper-level applications and external systems
III. Summary
The project achieves the following through the four-layer structure:
- Bottom layer decouples hardware
- Middle layer unifies data
- Core layer focuses on machine learning and computation graphs
- Top layer provides public interfaces and application capabilities
The overall design has good extensibility, maintainability, and engineering clarity.
The project is built using Meson/CMake.
Project CI/CD Requirements
Currently there is no version release CD, only basic documentation CD. Given that feature implementation is not complete, version releases are not considered for now.
This document only describes CI requirements.
CI uses GitHub Actions for operations.
When PR/push to main/dev branches occurs, full CI is triggered, covering multi-platform, multi-compiler testing, and using gcovr to report test coverage.
Coverage includes:
- meson-ubuntu-x64-gcc
- meson-ubuntu-x64-clang
- meson-ubuntu-arm64-gcc
- meson-ubuntu-arm64-clang
- meson-macos-x64-llvm
- meson-macos-arm64-llvm
- meson-windows-x64-msvc
- cmake-ubuntu-x64-gcc
- cmake-ubuntu-x64-clang
- cmake-macos-arm64-llvm
- cmake-windows-x64-msvc
Coverage requirements:
- line > 80%
- branch > 35%
CI fails when any job fails.
For the future, we will gradually increase test coverage, aiming for line > 90%, branch > 50%.
For CD, there is currently basic CD that only handles Doxygen documentation deployment.
Project Dependency Management
Dependencies are divided into two types:
- Strong system-related dependencies: such as OpenGL, GLFW, Vulkan, CUDA, etc., which need to interact with the underlying system, fall into this category
- Library dependencies: such as ImGui, GTest, etc., which do not need to interact with the underlying system, fall into this category
For strong system-related dependencies, installation is done through system package management.
For library dependencies:
- Meson installs via wrap
- CMake installs via installation scripts
Testing Requirements
2. Testing Standards (Testing Requirements)
2.1 Core Philosophy of Testing
In this project, testing is regarded as a core engineering asset, not an additional step after development completion.
Testing design follows these principles:
- Do not pursue "good-looking" coverage numbers
- Focus on real user usage paths
- Set different testing intensity requirements for different modules
- Clearly define which errors are tolerable and which are not
2.2 Definition of Core Training Pipeline
The following are defined as the Core Training Pipeline:
- Low-level memory allocation and management
- Numerical computation processes
- Computation task distribution and scheduling
- Automatic differentiation (Autograd)
- Optimizer logic
- Model execution-related code
These parts together form a complete training flow. Once an error that cannot be handled correctly occurs, the entire training process becomes meaningless.
Therefore, these modules must meet the strictest testing requirements.
2.3 Tensor Dimension Coverage Strategy (0D–3D)
Based on analysis of user usage scenarios, the project makes the following judgment:
- Users rarely perform complex operations on high-dimensional (>3D) tensors
- The most common in actual use are:
- 0D (scalar)
- 1D (vector)
- 2D (matrix)
- 3D (common batch tensors)
Testing Requirements
- For every supported operation type:
- Even if a logical branch has already been covered
- Additional tests for 0D–3D must still be passed
- Testing goals:
- Eliminate internal implementation uncertainty
- Ensure consistent and correct behavior within the most commonly used dimension range
2.4 Data Type Coverage Requirements
In core/include/definitions, the project clearly lists:
- All supported operable data types
Testing requirements:
- For every supported data type
- Under all valid dimensions (0D–3D)
- Corresponding operations must be explicitly tested and verified for correctness
2.5 Testing Framework
The project uniformly uses the following testing tool:
- Google Test (gtest)
Mainly used for:
- Unit testing
- Parameterized testing
- Dimension × data type combination testing
- Regression testing
2.6 Testing Requirements for Non-Core Modules
For non-core modules, such as:
- Logging system
- Utility classes
- Auxiliary components
Complex dimension and mathematical verification are not required, but overall quality must still be ensured.
Current stage requirements:
- Line coverage ≥ 80%
- Branch coverage ≥ 35%
- Coverage should continue to improve as much as possible on this basis
2.7 Phased Trade-off Strategy
- Some complex issues that may only manifest in the future:
- Not mandatory to cover at the current stage
- Avoid over-design leading to:
- Uncontrolled development costs
- Excessive testing burden
2.8 Testing Standards for Future Features
For subsequent new features or plugins:
- The project will individually formulate testing requirements for each feature
- Developers need to:
- Write sufficient tests according to requirements
Project Feature Addition Requirements
Project maintainers periodically discuss whether to support new features
Contributors can create enhancement issues on GitHub to attract discussion, or email project collaborators
Documentation
Currently there are two documentation sites:
- Hahaha API documentation, deployed at Napbad.github.io/Hahaha/
- Hahaha dev documentation, deployed at JiansongShen.github.io/HahahaDevDocument/
Comment Requirements
Aim for full Doxygen coverage, with detailed descriptions and clear comments.
Contribution Guidelines
Error Handling Guidelines
Status
Accepted
Context
As an educational machine learning library, the Hahaha project needs to handle various runtime errors. The design of error handling mechanisms directly affects:
- User experience: Whether error messages are clear and understandable
- Code robustness: Whether the system can gracefully handle exceptional situations
- Educational value: Whether error handling patterns reflect modern C++ best practices
In the C++23 standard, std::expected provides a type-safe error handling mechanism that is more suitable for functional programming style compared to traditional exceptions or error codes.
Decision
We adopt a layered error handling strategy, choosing different handling methods based on error recoverability:
Error Classification
1. Recoverable Errors
Recoverable errors are those that do not prevent the overall process from continuing, and can usually be recovered through retry, skip, or fallback handling.
Typical scenarios:
- A batch training failure during training can skip that batch and continue with the next
- A corrupted sample during data loading can skip that sample and continue loading
- Network request failures can retry or use cached data
- Insufficient file permissions can try alternative paths or use default configurations
2. Unrecoverable Errors
Unrecoverable errors are those that prevent the current operation from continuing, usually indicating program logic errors or abnormal system state.
Typical scenarios:
- Tensor dimension mismatch that cannot be broadcast
- Memory allocation failure
- Division by zero
- Null pointer dereference
- Unsupported tensor operation combinations
Handling Mechanisms
Recoverable Errors: Using std::expected
For recoverable errors, use C++23's std::expected<T, E> type:
#include <expected>
#include <string>
// Example: training a single batch
std::expected<void, std::string> trainBatch(const Tensor& batch) {
// Training logic
if (/* training failed */) {
return std::unexpected("Batch training failed: invalid data");
}
return {};
}
// Usage
auto result = trainBatch(batch);
if (!result) {
// Recoverable error, log and continue
logger.warn("Skipping batch: {}", result.error());
continue; // Continue to next batch
}
Advantages:
- Type safety: Compile-time checking of error handling
- Performance friendly: Zero-overhead abstraction, no exception mechanism involved
- Functional style: Supports chaining and composition
- Clear semantics: Return value clearly indicates operations that may fail
Unrecoverable Errors: Using Exceptions
For unrecoverable errors, use C++ standard exception mechanism:
// Example: tensor operations
Tensor add(const Tensor& a, const Tensor& b) {
// Check dimension compatibility
if (!canBroadcast(a.shape(), b.shape())) {
throw std::invalid_argument(
"Tensor shapes incompatible: " +
shapeToString(a.shape()) + " vs " +
shapeToString(b.shape())
);
}
// Check memory allocation
if (/* insufficient memory */) {
throw std::bad_alloc();
}
// Perform operation
return performAdd(a, b);
}
Advantages:
- Automatic propagation: Errors automatically propagate upward without manual checking
- Clear semantics: Exceptions represent situations that "should not happen"
- Stack information: Combined with C++23's
std::stacktraceto provide complete call chain
Error Type Definitions
The project will define unified error types:
namespace hahaha::error {
// Recoverable error types (to be defined)
enum class RecoverableError {
BatchTrainingFailed,
DataLoadFailed,
NetworkRequestFailed,
FileAccessDenied,
// ...
};
// Wrap with expected
template<typename T>
using Result = std::expected<T, RecoverableError>;
// Unrecoverable errors: custom exception types will be defined (to be implemented)
// Currently using standard library exceptions such as std::invalid_argument, std::bad_alloc, etc.
} // namespace hahaha::error
Practical Guidelines
1. Function Signature Design
// ✅ Recoverable errors: use expected
std::expected<Tensor, std::string> loadDataset(const std::string& path);
// ✅ Unrecoverable errors: may throw exceptions
Tensor matmul(const Tensor& a, const Tensor& b); // may throw exceptions
// ❌ Avoid mixing: don't throw exceptions in functions returning expected
2. Error Propagation
// Error propagation with expected
auto result = step1()
.and_then([](auto val) { return step2(val); })
.and_then([](auto val) { return step3(val); });
if (!result) {
// Unified error handling
handleError(result.error());
}
// Exception propagation: exceptions generally indicate panic, no error handling
3. Error Message Standards
- Recoverable errors: Provide clear error descriptions and suggested recovery actions
- Unrecoverable errors: Provide detailed context information, including relevant parameter values and state information
// ✅ Good error message
return std::unexpected(
"Failed to load batch: file corrupted at line 42. "
"Skipping this batch and continuing."
);
// ❌ Bad error message
return std::unexpected("Error");
4. Edge Case Handling
- Core training pipeline: Strict checking, unrecoverable errors thrown immediately
- Auxiliary functions: Can tolerate partial failures, use recoverable errors
Consequences
Positive Impacts
- Type safety: Compile-time checking of error handling, reducing runtime errors
- Performance optimization:
std::expectedhas zero overhead, exceptions only for truly exceptional cases - Code clarity: Error handling semantics are clear, easy to understand and maintain
- Educational value: Demonstrates modern C++ error handling best practices
Considerations
- Compiler requirements: Need support for C++23's
std::expected(GCC 13+, Clang 16+) - Learning curve: Contributors need to understand
std::expectedusage patterns - Error classification: Need to clearly distinguish recoverable and unrecoverable errors, which requires experience and judgment
Error Classification Examples in Machine Learning Scenarios
To help developers better understand error classification, the following lists common error types in machine learning projects:
Recoverable Error Examples:
-
Data Loading Related
- A data file is corrupted or has format errors → Skip the file, continue loading other files
- A sample contains invalid values (NaN/Inf) during data preprocessing → Skip the sample, log a warning
- Data file path does not exist → Try alternative paths or use default dataset
- Insufficient data file permissions → Try other paths or use cached data
-
Training Process Related
- Gradient explosion during a batch training → Skip the batch, continue with the next
- Loss value is abnormal (NaN) for a batch → Skip the batch, log it
- Learning rate too small during optimizer update causing no update → Adjust learning rate and retry
- A metric calculation fails during validation set evaluation → Skip the metric, continue with other metrics
-
Model Inference Related
- Input data format mismatch during inference → Try automatic conversion or use default values
- Model output contains abnormal values → Post-process correction or use default output
- Inference service temporarily unavailable → Use cached results or degraded service
-
Resource Management Related
- GPU memory insufficient (for a single batch) → Reduce batch size and retry
- Temporary file creation failure → Use memory cache or try other locations
- Network request timeout → Retry or use local cache
Unrecoverable Error Examples:
-
Tensor Operations Related
- Dimension mismatch during matrix multiplication that cannot be broadcast → Throw exception
- Element count mismatch during tensor reshape → Throw exception
- Tensor index out of bounds → Throw exception (can use
std::out_of_range) - Unsupported data type combination operations → Throw exception
-
Model Structure Related
- Model layer configuration error preventing forward propagation → Throw exception
- Forward propagation attempted with uninitialized model parameters → Throw exception
- Version incompatibility during model save/load → Throw exception
-
Computation Graph Related
- Circular dependency during computation graph construction → Throw exception
- Unsupported operation encountered during automatic differentiation → Throw exception
- Gradient computation failure during backpropagation (core logic error) → Throw exception
-
System Resources Related
- System memory completely exhausted, unable to allocate tensors → Throw exception (can use
std::bad_alloc) - GPU device unavailable and cannot fallback to CPU → Throw exception
- Critical file corrupted with no backup → Throw exception
- System memory completely exhausted, unable to allocate tensors → Throw exception (can use
-
Numerical Computation Related
- Division by zero (e.g., standard deviation is 0 during normalization) → Throw exception
- Matrix is singular (non-invertible) during matrix inversion → Throw exception
- Numerical overflow causing invalid results → Throw exception
Judgment Principles:
- Recoverable: Errors occur at the data level or single operation level, do not affect the overall process, can continue through skip, retry, fallback, etc.
- Unrecoverable: Errors occur at the core computation logic, model structure, or system resource level, indicating program logic errors that must be stopped immediately and fixed
Example Code Comparison:
// ✅ Recoverable error: use expected
std::expected<Tensor, std::string> loadBatch(const std::string& path) {
if (/* file corrupted */) {
return std::unexpected("Batch file corrupted, skipping");
}
return loadFromFile(path);
}
// ✅ Unrecoverable error: throw exception
Tensor matmul(const Tensor& a, const Tensor& b) {
if (!canMatmul(a.shape(), b.shape())) {
throw std::invalid_argument(
"Cannot multiply: " + shapeToString(a.shape()) +
" × " + shapeToString(b.shape())
);
}
return performMatmul(a, b);
}
Related Decisions
- ADR-0001: Adopt Modern C++23 Features -
std::expectedis one of the reasons for choosing C++23 - Testing Requirements - Error handling requires corresponding test coverage
Discussions
This section stores process-oriented content: meeting notes, review records, debates, and temporary conclusions made during iteration. The goal is to preserve context for traceability, but it does not need to be as polished as en/adr/.
What belongs here
- Feature iteration discussions (why change, how to change, what disagreements exist)
- Design review notes (issue lists, suggested changes, and where final conclusions landed)
- Troubleshooting logs and debugging journeys (including hypotheses and verification)
What does not belong here
- Final decisions (put them in
en/adr/) - Reusable, long-term stable design docs (put them in
en/design/)
Naming suggestions
- Prefer date or topic:
YYYY-MM-DD-topic.mdortopic.md - Include a short conclusion summary in the title for easier scanning in the sidebar
Implementation Documentation
This directory is for documenting implementation reasoning, design decisions, and algorithm principles. These documents are an important part of the educational value of the Hahaha project.
📁 Directory Structure
The structure of the explains/ directory should correspond to the code directory structure:
explains/
├── index.md # This file
├── math/ # Corresponds to core/include/math/
│ ├── tensor.md # Tensor implementation reasoning
│ └── tensor-wrapper.md
├── compute/ # Corresponds to core/include/compute/
│ ├── graph.md # Computational graph implementation reasoning
│ └── autograd.md # Automatic differentiation implementation reasoning
├── ml/ # Corresponds to core/include/ml/
│ ├── optimizer/ # Optimizer implementation reasoning
│ │ ├── sgd.md
│ │ └── adam.md
│ ├── model/ # Model implementation reasoning
│ │ ├── linear.md
│ │ └── knn.md
│ └── loss/ # Loss function implementation reasoning
│ └── mse.md
├── backend/ # Corresponds to core/include/backend/
│ ├── device.md
│ └── vectorize.md
└── display/ # Corresponds to core/include/display/
└── visualizer.md
✍️ Suggested Content
Each implementation documentation can include the following:
1. Feature Overview
- What does this feature/module do?
- What problem does it solve?
2. Design Reasoning
- Why was this implementation approach chosen?
- What alternatives existed? Why weren't they chosen?
- What factors were considered during design?
3. Algorithm Principles
- Mathematical principles of the core algorithm
- Detailed explanation of algorithm steps
- Key formulas and derivations (if applicable)
4. Implementation Details
- Explanation of key data structures
- Implementation logic of important functions
- How edge cases are handled
5. Performance Considerations
- Time complexity analysis
- Space complexity analysis
- Optimization points and trade-offs
6. Usage Examples
- Simple code examples
- Common usage scenarios
📝 Writing Guidelines
Document Naming
- Use lowercase letters and hyphens
- File names should clearly describe the content
- Examples:
adam-optimizer.md,tensor-broadcast.md
Document Format
- Use Markdown format
- Use code blocks, formulas, and diagrams appropriately
- Keep structure clear, use heading hierarchy to organize content
Content Requirements
- Clear and understandable: express ideas in concise, clear language
- Logically complete: include necessary background information and reasoning
- Rich examples: provide code examples or pseudocode
- Personal thinking: reflect your design reasoning and understanding
AI Assistance
We fully support using AI to help write documentation, for example:
- Use AI to polish your verbal descriptions
- Use AI to generate mathematical formulas
- Use AI to check grammar and formatting
However, we prefer to see:
- Documentation with personal thinking and understanding
- Reflection of your design decision process
- Avoid purely AI-generated content
🔗 Related Links
- How to Contribute - Learn how to write implementation documentation
- Code Style - Learn about coding standards
- Architecture Design - View system-level design documents
💡 Example
Here is an example structure for an implementation documentation:
# Adam Optimizer Implementation Reasoning
## Feature Overview
Adam (Adaptive Moment Estimation) is an adaptive learning rate optimization algorithm...
## Design Reasoning
### Why Adam?
Adam combines the advantages of Momentum and RMSprop...
### Implementation Approach
We chose to implement using template classes to support different data types...
## Algorithm Principles
### Mathematical Formulas
Adam's core formulas include:
- First moment estimate: ...
- Second moment estimate: ...
- Parameter update: ...
### Algorithm Steps
1. Initialize...
2. Compute gradients...
3. Update parameters...
## Implementation Details
### Key Data Structures
```cpp
class AdamOptimizer {
// ...
};
Important Functions
step(): Execute one optimization stepzeroGrad(): Zero out gradients
Performance Considerations
- Time complexity: O(n), where n is the number of parameters
- Space complexity: O(n), need to store momentum and variance
Usage Examples
auto optimizer = AdamOptimizer(parameters, 0.001);
optimizer.zeroGrad();
loss.backward();
optimizer.step();
---
**Remember**: Good implementation documentation not only helps others understand the code, but also helps you better understand design decisions. Let's build a valuable knowledge base together! 📚✨
Appendix
This section contains supporting information such as FAQ, references, terminology supplements, and tool/command cheat sheets. These pages are usually not part of the main narrative but are very helpful for quick lookup.
What belongs here
- FAQ: common questions and quick answers
- References: links, standards, protocols, articles
- Tool & command cheatsheets: common scripts and debugging commands
What does not belong here
- Project background and scope definition (put them in
en/hahaha/) - Designs and interface details (put them in
en/design/) - Process discussions (put them in
en/discussions/)
Appendix: FAQ
Q: Where should I put images?
Common approaches:
- Put them under
src/<lang>/assets/(create it if needed, e.g.src/en/assets/) - Reference them with relative paths, e.g.
or
简介
本文档用于沉淀 Hahaha 项目开发过程中的开发记录,交流内容与决策过程,包括但不限于:
- 项目介绍:项目是什么,什么目录结构
- 项目实现:比较上层的接口实现,内部层级间的主要接口定义
- 功能迭代讨论:为什么做、做什么、不做什么、优先级如何定
- 设计方案与取舍:多个方案对比、风险评估、兼容性与演进策略
- 实现思路:关键模块的实现路径、代码组织、踩坑与复盘
- 协作记录:达成共识的结论、待办与后续跟进
适用读者
- 新加入的贡献者:快速了解项目脉络与历史决策
- 正在实现某功能的人:对齐边界、接口与兼容策略
- 维护者:基于既有结论持续迭代,减少重复讨论
如何使用这本书
- 先看「指南」:了解目录约定与写作规范
- 再看「项目介绍」:明确范围、术语、总体目标
- 设计阶段写入「设计」:方案、接口、数据结构、边界
- 结论沉淀到「ADR」:把“决定了什么/为什么”固定下来
- 过程记录放「讨论」:会议纪要、评审意见、迭代记录
项目背景
本目录用于说明 Hahaha 项目是什么、要解决什么问题、边界在哪里,以及一些跨章节的基础信息(术语、约定、目标)。
这个目录放什么
- 项目简介:目标、使用场景、用户画像(谁在用/为什么用)
- 范围与边界:明确“做什么/不做什么”,避免需求漂移
- 术语表/名词解释:减少沟通歧义
- 总体约束:兼容性、性能目标、安全要求、发布策略等
这个目录不放什么
- 具体方案细节与接口设计(放到
design/) - 最终决策(放到
adr/) - 过程性讨论记录(放到
discussions/)
推荐维护方式
- 当你发现讨论中反复出现同一个“前置知识点”,就把它补到这里
- 任何章节引用“约定/术语”,优先链接到本目录的对应页面
项目介绍
什么是 Hahaha?
Hahaha 是一个现代化的开源数学和机器学习库,专为机器学习计算而设计,同时具备强大的教育价值。它不仅提供了高效的数值计算功能,还致力于让机器学习的学习过程更加直观和有趣。
项目愿景
Hahaha 的核心理念是让机器学习变得简单、有趣且易于理解。我们相信,通过精心设计的 API 和清晰的文档,可以让开发者在享受编程乐趣的同时,深入理解机器学习算法的本质。
主要目标
-
构建高性能数学/ML库
- 提供张量运算、矩阵计算等基础数学功能
- 支持自动微分(Autograd)功能
- 实现常见的机器学习算法和优化器
-
优秀的代码实现与设计思路记录
- 代码结构清晰,易于理解和学习
- 详细的文档和注释,帮助开发者理解算法原理
- 设计模式和架构决策的详细记录
-
可视化机器学习过程
- 提供训练过程的可视化工具
- 支持模型结构和计算图的可视化
- 让复杂的算法执行过程变得直观
架构设计
Hahaha 采用分层架构设计,从底层硬件抽象到高层用户接口,形成了一个完整的技术栈。整体架构基于 core 目录下的模块化设计,从底层到高层递进:
1. Backend 层(后端层)
位于 core/include/backend/ 目录,负责底层的计算功能实现:
- 设备抽象:
Device.h提供统一的硬件接口 - SIMD 计算优化:
vectorize/子目录下的SimdVector.h和VectorizedOp.h利用 CPU 向量指令集 - GPU 计算:
gpu/子目录预留 CUDA 接口(GpuContext.h,GpuKernel.h,GpuMemory.h) - 计算分发:
DeviceComputeDispatcher.h实现跨设备的计算任务调度
2. Common 层(公共层)
位于 core/include/common/ 目录,提供基础组件:
- 配置管理:
Config.h管理系统配置 - 类型定义:
definitions.h定义数据类型和常量 - 操作符接口:
Operator.h定义运算符抽象 - 结果处理:
Res.h统一错误处理和返回值
3. Math 层(数学层)
位于 core/include/math/ 目录,实现核心数学运算:
- 张量数据结构:
ds/子目录包含TensorData.h,TensorShape.h,TensorStride.h - 张量包装器:
TensorWrapper.h提供高层张量操作接口 - 核心张量类:根目录的
Tensor.h定义张量主接口
4. Compute 层(计算层)
位于 core/include/compute/ 目录,实现自动微分和计算图:
- 计算图:
graph/子目录包含节点定义和拓扑排序 - 计算函数:
graph/compute_funs/提供各种数学运算的具体实现 - 自动微分:支持动态计算图的梯度计算和反向传播
5. ML 层(机器学习层)
位于 core/include/ml/ 目录,实现机器学习算法:
- 模型架构:
model/子目录包含Linear.h,LinearRegression.h,KNearestNeighbors.h - 优化器:
optimizer/包含SGDOptimizer.h等优化算法 - 损失函数:
loss/提供MSELoss.h等损失计算 - 数据集:
dataset/抽象数据加载和预处理接口
6. Display 层(显示层)
位于 core/include/display/ 目录,提供可视化功能:
- 窗口管理:
GlfwWindow.h基于 GLFW 的窗口抽象 - 可视化器:
Visualizer.h和Window.h支持训练过程可视化
7. Utils 层(工具层)
位于 core/include/utils/ 目录,提供辅助功能:
- 日志系统:
log/子目录包含完整的日志框架 - 公共工具:
common/提供辅助数据结构
工具与支持
- 构建系统:基于 Meson + Ninja 的现代化构建流程
- 外部依赖:
extern/externlibs/包含 ImGui, GLFW 等必要的第三方库 - 示例代码:
examples/目录提供 autograd、basic_usage、ml_basic_usage、ml_visualizer 等示例 - 测试套件:
tests/目录包含完整的单元测试和集成测试 - 开发工具:
format.sh脚本提供代码格式化和检查功能
快速开始
基本使用示例
#include <hahaha/Tensor.h>
int main() {
// 创建张量
auto x = hahaha::Tensor<float>::buildFromVector({1.0f, 2.0f, 3.0f, 4.0f});
auto y = hahaha::Tensor<float>::buildFromVector({2.0f, 3.0f, 4.0f, 5.0f});
// 执行计算
auto z = x + y * 2.0f;
// 自动微分
z.backward();
std::cout << "Result shape: (" << z.getShape()[0] << ")" << std::endl;
std::cout << "Gradient shape: (" << x.grad().getShape()[0] << ")" << std::endl;
return 0;
}
机器学习示例
#include <hahaha/Tensor.h>
#include <hahaha/ml/model/LinearRegression.h>
#include <hahaha/ml/optimizer/SGDOptimizer.h>
#include <hahaha/ml/loss/MSELoss.h>
int main() {
// 创建线性回归模型
auto model = hahaha::ml::LinearRegression<float>();
// 准备训练数据
auto X = hahaha::Tensor<float>::buildFromVector({1.0f, 2.0f, 3.0f, 4.0f});
auto y = hahaha::Tensor<float>::buildFromVector({2.0f, 4.0f, 6.0f, 8.0f});
// 训练模型
for (int epoch = 0; epoch < 100; ++epoch) {
model.train(X, y);
}
std::cout << "Training completed!" << std::endl;
return 0;
}
项目特色
🎯 教育导向
- 清晰的代码结构:每个模块都有详细的注释和文档
- 渐进式学习:从基础数学到复杂模型的完整学习路径
- 可视化支持:让抽象的算法变得直观可见
🚀 高性能
- 多后端支持:CPU、GPU、分布式计算
- SIMD优化:充分利用现代CPU的向量指令
- 内存优化:高效的内存管理和垃圾回收
🛠️ 开发者友好
- 现代C++:使用C++23标准,提供类型安全和性能
- 模块化设计:清晰的架构,便于扩展和维护
- 完善的测试:高覆盖率的单元测试和集成测试
📊 可视化
- 训练过程可视化:实时显示loss、accuracy等指标
- 模型结构可视化:直观展示神经网络架构
- 计算图可视化:理解自动微分的执行过程
为什么叫做 Hahaha?
为什么不取一个像 PyTorch、TensorFlow 那样的酷炫技术名字呢?
因为 Hahaha 希望你在学习机器学习、使用机器学习(又或者是深度学习)算法辅助完成自己每天的日常工作的时候,能够让你真心地感到高兴!
我们相信,编程应该是一件快乐的事情,学习应该是一件有趣的事情。通过精心设计的 API、清晰的文档和直观的可视化,我们希望让每个使用 Hahaha 的开发者都能在解决问题的同时,享受到编程带来的乐趣。
就像听到一个有趣的笑话时,你会情不自禁地笑出声一样,我们希望 Hahaha 能成为你编程旅程中的快乐源泉!😄
来自Napbad:这绝对不是因为作者想不出好名字。绝对不是。嗯,是这样。
核心架构设计
Hahaha 的架构遵循“分层解耦、接口统一”的原则,确保从底层张量运算到高层神经网络模型的平滑过渡。
技术栈与选型
Hahaha 项目在设计之初就明确了“教育优先”与“性能平衡”的目标,因此在技术选型上非常克制且现代。
核心语言:C++23
我们选择了最新的 C++23 标准。
- 为什么要这么新? C++23 引入了增强的模板元编程能力(Concepts)、
std::stacktrace等特性,能更优雅地表达张量运算并辅助调试。 - 教育意义:展示现代 C++ 如何解决高性能计算中的复杂性,避免 C 风格代码的堆砌。
构建系统:Meson + Ninja
项目采用 Meson 构建系统:
- 可读性:
meson.build文件逻辑清晰,极大降低了贡献者理解构建流程的门槛。 - 速度:Ninja 后端提供极快的增量编译体验。
核心依赖 (Extern Libs)
项目尽量减少重型依赖,仅引入以下关键组件:
- GoogleTest (GTest):确保每一个数学算子都有完备的单元测试。
- ImGui + GLFW:用于
MLVisualizer,提供实时的训练曲线和参数分布展示。 - CUDA 13.0 (预留):为后期 GPU 加速预留架构接口。
基础设施
- Docker/Devcontainer:提供标准化的 C++23 编译环境。
- clang-format/clang-tidy:通过
format.sh等脚本强制执行代码风格。
路线图与任务清单
基于 repo/Hahaha/doc/zh-cn/Task.md 整理的开发进度:
✅ 已完成 (v0.0.1 阶段)
- 张量核心:维度管理、内存所有权、嵌套初始化、广播适配。
-
线性代数基础:矩阵乘法 (
matmul)、转置 (transpose)、求和 (sum)。 - 自动微分引擎:动态计算图节点、拓扑排序、反向传播。
- 优化器基础:SGD 随机梯度下降。
- 可视化:基于 ImGui 的训练曲线实时绘制。
- 基础设施:日志系统、Docker 开发环境、Meson 构建流。
🚧 进行中 (v0.1.0 目标)
- 广播机制完善:支持更复杂的跨维度张量运算。
- 数据集实现:创建数据集抽象接口,完成数据集加载的任务。
- 现代 ML 模型:线性回归、KNN 模板实现。
-
日志增强:集成
std::stacktrace提供奔溃现场追溯。
📅 未来规划 (Backlog)
- 后端加速:CUDA 显存管理与核心 Kernel 实现。
- 神经网络层:全连接层、卷积层、批标准化。
- 数学进阶:SVD 分解、逆矩阵、特征值计算。
- Python 绑定:基于 Pybind11 提供 Python 调用接口。
设计与方案
本目录用于存放“还在设计阶段”或“需要长期参考的设计文档”。它强调“方案对比与可落地的细节”,但不等同于最终决策。
这个目录放什么
- 需求拆解:目标、非目标、约束、边界条件
- 方案对比:备选方案、优缺点、风险、迁移路径
- 接口/协议设计:HTTP/RPC/CLI、请求响应、错误码、版本策略
- 数据结构与存储:Schema、索引、兼容与演进
- 测试与可观测性:关键用例、回归点、指标与告警
这个目录不放什么
- “已经定了”的最终结论(放到
adr/,并从这里链接过去) - 会议纪要、零散讨论(放到
discussions/)
推荐模板(建议包含)
- 背景与问题
- 目标/非目标
- 方案与权衡
- 兼容性与演进
- 落地计划(里程碑/回滚方案)
致开发者
欢迎来到 Hahaha 项目的开发者社区!🎉
本目录面向所有开发者,以及有意愿加入开发的有志之士。无论你是经验丰富的资深工程师,还是刚刚踏入编程世界的初学者,这里都有适合你的位置。
👋 欢迎加入
Hahaha 是一个开源的机器学习库项目,我们致力于:
- 教育导向:让机器学习的学习过程更加直观和有趣
- 高性能:提供现代化的 C++ 实现,支持多种计算后端
- 代码质量:追求清晰、可维护、可扩展的代码设计
🎯 开发者角色
核心贡献者
- 架构师:参与系统设计和技术选型
- 核心开发者:负责核心模块的实现和维护
- 测试工程师:确保代码质量和稳定性
社区贡献者
- 功能开发者:实现新功能和改进现有功能
- 文档维护者:完善文档和示例代码
- 问题解决者:修复 bug 和性能问题
新手贡献者
- 示例编写者:创建使用示例和教程
- 测试补充者:添加单元测试和集成测试
- 文档翻译者:提供多语言文档支持
🛠️ 开发环境
推荐配置
操作系统:
- Linux (Ubuntu 20.04+, Fedora 34+, Arch Linux)
- macOS (10.15+)
- Windows (WSL2 推荐)
开发工具:
- IDE:CLion, VS Code, Visual Studio
- 编译器:GCC 11+, Clang 14+, MSVC 2022+
- 构建系统:Meson + Ninja
- 版本控制:Git
环境搭建
详细的环境搭建步骤请参考:如何贡献项目
📏 代码质量标准
设计原则
- 清晰性优先:代码应当易于理解,优先考虑可读性
- 模块化设计:功能独立,接口清晰,易于测试
- 性能与安全:在保证性能的同时,确保内存安全
- 教育价值:代码结构应当体现算法原理
代码规范
- 语言版本:C++23 标准
- 命名约定:遵循项目编码规范
- 文档要求:每个公共接口都需要文档注释
- 测试覆盖:核心功能需要完整的单元测试
🔄 贡献流程
快速开始
- 了解项目:阅读项目介绍和架构文档
- 选择任务:查看路线图和 TODO 列表
- 环境搭建:配置开发环境
- 开始开发:遵循贡献指南进行开发
工作流程
选择任务 → 创建分支 → 编写代码 → 编写测试 → 提交PR → 代码审查 → 合并
详细贡献流程请参考:如何贡献项目
📚 学习资源
项目文档
开发资源
外部资源
- C++23 标准:熟悉现代 C++ 特性
- 机器学习基础:理解相关算法原理
- 开源开发:学习开源项目开发流程
💬 社区与沟通
沟通渠道
- GitHub Issues:报告问题和提出建议
- GitHub Discussions:技术讨论和方案探讨
- Pull Request:代码贡献和审查
沟通准则
- 尊重他人:友善、建设性的沟通
- 问题导向:聚焦问题解决而非个人观点
- 开放心态:接纳不同的观点和建议
- 积极贡献:不仅提出问题,也提供解决方案
🏆 贡献认可
贡献类型
- 代码贡献:功能实现、bug修复、性能优化
- 文档贡献:编写、翻译、完善文档
- 测试贡献:编写测试用例、改进测试覆盖
- 设计贡献:架构设计、接口设计、技术调研
认可方式
- 贡献者列表:项目贡献者名单
- 代码署名:在相关代码中标注贡献者
- 文档记录:在文档中记录贡献思路
- 社区认可:社区成员的感谢和认可
🚀 成长路径
新手入门
- 从示例开始:运行和理解现有示例
- 修复小问题:从简单的 bug 修复开始
- 编写测试:为现有功能补充测试
- 完善文档:改进文档和注释
进阶发展
- 功能开发:实现新的功能模块
- 架构优化:改进系统设计和性能
- 工具建设:开发辅助工具和脚本
- 社区建设:帮助其他贡献者成长
🎯 项目愿景
我们相信,编程应该是一件快乐的事情,学习应该是一件有趣的事情。通过 Hahaha 项目,我们希望:
- 为开发者提供高质量的学习材料
- 构建一个友善、开放的开源社区
- 推动机器学习教育的普及和发展
- 创造有教育价值的高性能工具
📞 获取帮助
如果你在开发过程中遇到问题:
- 查看文档:先查阅相关文档和 FAQ
- 搜索 Issues:查看是否已有类似问题
- 提出问题:在 Issues 中详细描述问题
- 寻求帮助:社区成员会尽力提供帮助
让我们一起构建一个有趣且有教育价值的机器学习库!🚀
最后更新:2026年1月
如何贡献项目
感谢您对 Hahaha 项目的兴趣!我们欢迎各种形式的贡献,无论是代码、文档、测试还是设计建议。本指南将帮助您快速上手项目开发。
贡献前准备
1. 了解项目
在开始贡献之前,请先:
2. 选择任务
在项目的 doc/TODO.md 文件中,找到您感兴趣的任务:
- [ ] 实现优化器 (需要有人解决)
当您决定贡献时,请在任务后添加您的信息:
- [/] 实现优化器 - [您的名称](您的GitHub链接) (您的邮箱)
开发环境设置
系统要求
- 操作系统:Linux、macOS 或 Windows (WSL)
- 编译器:GCC 11+、Clang 14+ 或 MSVC 2022+
- CMake:3.20+
- Python:3.8+ (用于构建脚本和测试)
克隆和构建
-
Fork 项目
git clone https://github.com/YOUR_USERNAME/Hahaha.git cd Hahaha -
创建开发分支
在开始开发之前,请基于dev分支创建一个新的分支。分支命名应该清晰描述你的工作内容:
# 如果是开发新功能 git checkout -b feature/[功能名称]-implement # 例如:feature/adam-optimizer-implement # 如果是修复bug git checkout -b bug/[bug描述]-fix # 例如:bug/tensor-broadcast-fix # 如果是文档更新 git checkout -b docs/[文档内容]-update # 例如:docs/api-documentation-update分支命名建议:
- 使用小写字母和连字符
- 名称要简洁但具有描述性
- 避免使用过长的分支名
-
安装依赖
# Ubuntu/Debian sudo apt update sudo apt install build-essential cmake ninja-build # macOS (使用 Homebrew) brew install cmake ninja # Arch Linux sudo pacman -S cmake ninja # Fedora/CentOS sudo dnf install cmake ninja-build # 或者 sudo yum install cmake ninja-build -
构建项目
# 使用 Meson (推荐) meson setup builddir ninja -C builddir # 构建完成后,库文件会在 builddir 目录中
IDE 配置
推荐使用以下 IDE:
- CLion:原生支持 CMake 和 Meson 项目
- VS Code:安装 C++ 扩展和 CMake Tools 或者 meson 工具
- Visual Studio:支持 CMake 项目
代码规范
详细的代码规范请参考:代码规范文档
提交信息格式
提交信息应该清晰描述变更:
类型(范围): 简短描述
详细说明 (可选)
Fixes #123
类型包括:
feature: 新功能fix: 修复bugdocs: 文档更新或注释优化style: 代码格式调整refactor: 重构test: 测试相关chore: 构建过程或工具配置
开发流程
1. 创建分支
# 保持主分支同步(如果已配置upstream)
git checkout dev
git pull upstream dev
# 创建特性分支(使用清晰的命名)
git checkout -b feature/your-feature-name
# 或者修复分支
git checkout -b bug/issue-description-fix
# 或者文档分支
git checkout -b docs/documentation-update
2. 编写代码
- 遵循必要的代码规范
- 添加必要的注释
- 编写单元测试
- 更新相关文档
3. 测试
运行测试套件:
# 使用 Meson 构建并运行测试
meson setup builddir
ninja -C builddir
ninja -C builddir test
# 或者使用 CMake
mkdir cmake-build && cd cmake-build
cmake .. -GNinja
ninja
ctest
# 运行特定测试模块
# 张量相关测试
ninja -C builddir test-tensor
# 自动微分测试
ninja -C builddir test-autograd
# 机器学习测试
ninja -C builddir test-ml
4. 代码格式化
使用项目的格式化脚本:
# 格式化代码
./format.sh
# 检查格式
./format.sh --check
提交 Pull Request
1. 推送分支
# 提交本地更改
git add .
git commit -m "feature: 实现张量加法操作
- 添加 Tensor::add 方法
- 支持广播机制
- 添加相应的单元测试"
# 推送分支
git push origin feature/tensor-add
2. 创建 PR
在 GitHub 上:
- 访问您的 fork
- 点击 "Compare & pull request"
- 填写 PR 描述:
- 简要说明变更内容
- 关联相关 issue(如果有)
- 描述测试方式
- @mention 合适的 reviewer
3. 代码审查
PR 创建后:
- 等待 CI/CD 检查通过
- 回应 reviewer 的评论
- 根据反馈修改代码
- 获得 approval 后等待合并
其他
处理已有任务
如果您想完成的任务已经有负责人:
- 联系任务负责人(通过 issue 或 PR)
- 讨论任务分工
- 在负责人分支基础上创建子分支:
git checkout feature/optimizer-implementation git checkout -b feature/optimizer-implementation-adam
贡献类型
除了代码贡献,我们也欢迎:
- 文档改进:修复文档错误、添加示例
- 测试增强:提高测试覆盖率、添加边界测试
- 性能优化:优化算法或内存使用
- 工具改进:构建脚本、CI/CD 流程
- 设计讨论:在 ADR 中记录架构决策
贡献者认可
您的贡献将被认可:
- 在贡献者列表中添加您的信息
- 在文档中记录您的实现思路
- 参与项目决策讨论
📝 记录实现思路的鼓励与建议
为什么我们鼓励在文档中记录实现思路?
Hahaha 项目特别强调教育价值,我们相信优秀的代码实现如果能伴随着清晰的文档说明,将会产生更大的影响。这不仅有助于其他开发者理解你的工作,更重要的是:
- 知识传承:让后来者能够快速理解设计理念和实现细节
- 社区协作:帮助团队成员更好地协作和代码审查
- 学习价值:为学习者提供算法实现的思考过程和设计决策
- 维护效率:当代码需要修改时,文档可以帮助快速理解原有逻辑
记录实现思路是一种值得鼓励的良好实践,它能让你的贡献产生更大的影响力。
我们鼓励记录的内容
当你实现新功能时,我们鼓励在相关文档中添加实现思路的记录。
文档位置说明:
文档应该放在 src/<lang>/explains/ 目录(我们提倡您使用英语)下,目录结构应该与代码目录结构相对应。例如:
- 如果您实现或者优化或者修复bug了
core/include/ml/optimizer/AdamOptimizer.h,可以在src/zh/explains/ml/optimizer.md中添加相关内容 - 如果您实现或者优化或者修复bug了
core/include/math/TensorWrapper.h,可以在src/zh/explains/math/tensor-wrapper.md中添加相关内容 - 如果您实现或者优化或者修复bug了
core/include/compute/graph/ComputeNode.h,可以在src/zh/explains/compute/graph.md中添加相关内容
如果对应的文档文件不存在,您可以创建新文件。文档的目录结构应该清晰反映代码的设计思路。
我们完全支持您使用 AI 帮助撰写这些文档,比如您可以通过口头描述您的思路,然后使用 AI 简单润色添加内容(比如不易写的公式等),亦或者不进行润色,保留您的个人风格,我们完全尊重您的选择。
当然,我们更希望看到的是有个人思考和理解的文档,避免仅仅是 AI 的生成内容或难以理解的文档。
1. 新功能实现
我们可以记录:
- 设计思路:为什么选择这种实现方式?有哪些替代方案?
- 算法原理:核心算法的数学原理和步骤
- 架构决策:如何与其他模块交互?接口设计原则是什么?
- 性能考虑:时间复杂度、空间复杂度分析(如果有的话)
- 边界情况:特殊输入的处理方式(如果需要的话)
示例文档结构:
## 功能名称
### 实现思路
[详细描述你的设计思路和决策过程]
### 算法原理
[数学原理和算法步骤]
### 架构设计
[与现有系统的集成方式]
### 性能分析
[复杂度分析和优化点]
2. 优化现有功能
当你优化或重构现有代码时,我们鼓励更新相关文档,记录:
- 优化动机:为什么要进行这次优化?
- 性能提升:具体的性能改善数据(速度、内存使用等)
- 兼容性影响:是否影响现有API?如何保持向后兼容?
- 权衡考虑:优化带来的好处和可能的代价
示例文档更新:
## 优化记录
### [实际优化出来的功能](您的修改的链接)
- **优化内容**:[具体说明]
- **性能提升**:计算时间减少 30%,内存使用降低 20%
- **实现方式**:[技术细节]
- **兼容性**:保持完全向后兼容
3. Bug修复
修复 bug 时,我们鼓励在相关位置记录:
- 问题描述:bug 的具体表现和影响范围
- 根本原因:问题产生的根本原因分析
- 修复方案:为什么选择这种修复方式?
- 测试验证:如何验证修复的正确性?
文档位置建议
建议将文档放在与代码实现相对应的位置,比如:
- 核心算法的相关说明可以放在
src/<lang>/hahaha/(例如src/zh/hahaha/)目录 - 架构设计的文档可以放在
src/<lang>/design/(例如src/zh/design/)目录 - API 接口的说明可以在头文件注释中,并同步到相关文档
一些实践建议
- 尝试写文档:实现前先写设计文档,有助于理清思路
- 结合注释:重要函数要有详细注释,文档提供高层概览
- 定期检查:代码审查时同时检查相关文档的准确性
- 从小做起:从为现有功能补充文档开始,逐渐熟悉文档编写
记录思路的好处
积极记录实现思路的贡献者往往会获得:
- 更快的代码审查:清晰的文档有助于 reviewer 快速理解您的实现思路
- 文档与代码同步PR:您可以将代码实现和文档实现分别提交PR,在代码PR中引用文档PR,审核通过后我们会同时合并它们
- 社区认可:你的思考过程将成为项目宝贵的知识资产
- 学习机会:通过文档化加深对实现的理解
- 影响力提升:你的设计思路可能影响项目的未来发展
我们认为:好的代码 + 好的文档 = 完美的贡献!在 Hahaha 项目中,虽然我们不强制要求记录实现思路,但我们真诚地鼓励大家这样做,它能让你的贡献产生更大的价值,也能让整个项目变得更加优秀。📚✨
获取帮助
如果您在贡献过程中遇到问题:
- 查看常见问题解答
- 在 GitHub Issues 中提问
- 加入我们的社区讨论
我们致力于让贡献过程愉快而高效!🎉
ADR:架构决策记录(Architecture Decision Records)
ADR 用来记录"最终决定了什么"以及"为什么这么决定"。它的价值在于:未来回看时,能迅速理解当时的约束与取舍,而不是重复走一遍讨论。
这个目录放什么
- 已达成共识的关键决策(例如:采用某协议/存储/架构拆分方式)
- 决策的背景、约束、备选方案与理由
- 决策的影响范围与后续动作(迁移、兼容、风险)
这个目录不放什么
- 还在摇摆的方案草稿(放到
design/) - 过程性讨论、评审意见原始记录(放到
discussions/)
编号与命名建议
- 文件命名:
NNNN-title.md(例如1-auth-strategy.md) - 标题格式:
ADR-NNNN:xxx - 目录组织:相关 ADR 可以组织在子目录中(例如
1-cpp23/、2-basic-project-design/)
ADR 列表
ADR-0001:使用 C++23 现代特性
- 位置:1-cpp23/0001-cpp23.md
- 状态:已接受
- 内容:决定全面拥抱 C++23 标准,使用 Concepts 和 stacktrace 等现代特性
ADR-0002:基础项目设计
- 位置:2-basic-project-design/0002-basic-project-design.md
- 状态:已接受
- 内容:包含项目基本结构、CI/CD 要求、依赖管理、测试要求、功能添加要求、文档注释要求和贡献规范等基础设计决策
ADR-0001:使用 C++23 现代特性
状态
已接受 (Accepted)
背景
Hahaha 项目定位为教育型库。为了展示最先进的 C++ 编程范式,我们需要决定支持的 C++ 标准上限。
决策
我们决定全面拥抱 C++23 标准。
核心理由:
- Concepts:相比
enable_if,Concepts 让张量模板的报错信息更加人类可读。 - stacktrace:内置的堆栈追溯极大简化了底层数学库的调试成本。
- expected:用于完善的错误处理。
影响
- 编译器门槛:强制要求 GCC 13+ 或 Clang 16+。
- 教育价值:代码库成为学习现代 C++ 的绝佳范本。
- 风险:旧系统可能难以直接编译,需依赖 Docker 容器。
基础项目设计
本次决策制定了基本项目设计的决策
决策人:
-
Napbad -
JiansongShen
内容
项目基本结构
一、整体设计概述
项目整体采用四层架构设计,自底向上逐层抽象,从硬件与计算调度一直延伸到上层的公共接口与应用层,各层职责清晰、边界明确。
二、四大层次划分
第一层:底层计算与硬件抽象层
核心职责:
与底层硬件及计算资源直接交互,提供统一的计算与设备抽象。
关键组成:
Compute DispatcherDevice抽象类- 底层硬件接口交互层
特点:
- 屏蔽不同硬件实现差异
- 为上层提供统一、可扩展的计算调度能力
第二层:数据抽象与数据操作层
核心职责:
对计算数据进行抽象,并提供中间层的数据操作能力。
关键组成:
TensorTensor OperatorLinear Algebra Operator- 各类中间层数据操作类
特点:
- 统一数据表示
- 承担张量与结构化数据的操作与变换
- 作为计算与算法层之间的桥梁
第三层:机器学习与计算图核心层
核心职责:
构建高层计算与学习能力,是项目的核心逻辑层。
关键组成:
- Machine Learning 模块
- Deep Learning 模块
- Dataset 支撑体系
- 计算图(Computation Graph)
- DA 图等核心计算结构
特点:
- 负责模型构建、训练与推理逻辑
- 统一计算图与自动求导等核心机制
第四层:公共接口与上层应用层
核心职责:
对外提供统一、易用的方法与接口,面向公共互联网或上层应用。
关键组成:
- 方法类(Method-level)运作接口
- 面向公共互联网的访问与调用层
特点:
- 提供稳定 API
- 屏蔽内部复杂实现
- 支持上层应用与外部系统集成
三、总结
该项目通过四层结构实现:
- 底层解耦硬件
- 中层统一数据
- 核心层聚焦机器学习与计算图
- 顶层提供公共接口与应用能力
整体设计具备良好的可扩展性、可维护性与工程清晰度。
项目通过Meson/Cmake构建,
项目的cicd要求
目前没有发版本的cd,仅有普通的文档cd, 鉴于功能实现并不完全,暂时不考虑发版本.
本文仅描述ci需求
ci使用github actions进行操作
在pr/push到main/dev分支时,会触发全量ci,覆盖多平台多编译器测试,并使用gcovr报告测试覆盖率,
覆盖面有: meson-ubuntu-x64-gcc meson-ubuntu-x64-clang meson-ubuntu-arm64-gcc meson-ubuntu-arm64-clang meson-macos-x64-llvm meson-macos-arm64-llvm meson-windows-x64-msvc cmake-ubuntu-x64-gcc cmake-ubuntu-x64-clang cmake-macos-arm64-llvm cmake-windows-x64-msvc
覆盖率要求: line > 80% branch > 35%
在其中任意job失败时,ci失败
对于日后我们会逐渐增加测试量,尽量追求line > 90%, branch > 50%
对于cd,现在有基础的cd仅做doxygen文档部署
项目依赖管理
依赖分为两种:
- 强系统关联依赖, 比如opengl, glfw, vulkan, cuda等,需要与底层交互,归为此类
- 库依赖 比如imgui, gtest等, 不需要与底层交互,归为此类
对于强系统关联依赖, 通过系统包管理进行安装
对于库依赖,
- meson通过wrap安装
- cmake通过安装脚本进行安装
测试要求
2. 测试规范(Testing Requirements)
2.1 测试的核心理念
在本项目中,测试被视为工程核心资产,而不是开发完成后的附加步骤。
测试设计遵循以下原则:
- 不追求“数字好看”的覆盖率
- 以真实用户使用路径为中心
- 对不同模块设定不同强度的测试要求
- 明确哪些错误是可以被容忍的,哪些是不可以的
2.2 核心训练链路的定义
以下内容被定义为核心训练链路(Core Training Pipeline):
- 底层内存分配与管理
- 数值计算过程
- 计算任务的分发与调度
- 自动微分(Autograd)
- 优化器逻辑
- 模型(Model)执行相关代码
这些部分共同构成了一条完整的训练流程,一旦出现不能正确处理的错误,整个训练过程即失去意义。
因此,这些模块必须接受最严格的测试要求。
2.3 Tensor 维度覆盖策略(0D–3D)
基于对用户使用场景的分析,项目做出如下判断:
- 用户极少在高维(>3D)Tensor 上进行复杂操作
- 实际使用中最常见的是:
- 0D(标量)
- 1D(向量)
- 2D(矩阵)
- 3D(常见批量张量)
测试要求
- 对于每一种可支持的操作类型:
- 即使某个逻辑分支已经被覆盖
- 仍必须通过 0D–3D 的额外测试
- 测试目标:
- 消除内部实现不确定性
- 确保在用户最常用维度范围内行为一致、正确
2.4 数据类型覆盖要求
在 core/include/definitions 中,项目明确列出了:
- 所有支持的可操作数据类型
测试中要求:
- 对每一种支持的数据类型
- 在所有有效维度(0D–3D)下
- 对应操作必须被明确测试并验证正确性
2.5 测试框架
项目统一使用以下测试工具:
- Google Test(gtest)
主要用于:
- 单元测试
- 参数化测试
- 维度 × 数据类型 组合测试
- 回归测试
2.6 非核心模块的测试要求
对于非核心模块,例如:
- 日志系统
- 工具类
- 辅助组件
不要求复杂的维度与数学验证,但仍需保证整体质量。
当前阶段要求:
- 行覆盖率 ≥ 80%
- 分支覆盖率 ≥ 35%
- 在此基础上,覆盖率应尽可能继续提高
2.7 分阶段取舍策略
- 一些可能在未来才显现的复杂问题:
- 当前阶段暂不强制覆盖
- 避免过度设计导致:
- 开发成本失控
- 测试负担过重
2.8 面向未来功能的测试规范
对于后续新增功能或插件:
- 项目会为每一个功能单独制定测试要求
- 开发者需:
- 按要求编写足量测试
项目特性添加规范
项目负责人不定时讨论是否有新功能支持
贡献者可以github issue 创建 enhancement, 吸引讨论或者email项目colebalectors
文档
目前有两个文档
- hahaha api文档,部署在 Napbad.github.io/Hahaha/
- hahaha dev 文档, 部署在 JiansongShen.github.io/HahahaDevDocument/
注释要求
尽可能doxygen全覆盖,描述详细,注释清晰,
贡献规范
查看贡献规范
错误处理规范
状态
已接受 (Accepted)
背景
Hahaha 项目作为教育型机器学习库,需要处理各种运行时错误。错误处理机制的设计直接影响:
- 用户体验:错误信息是否清晰、可理解
- 代码健壮性:系统能否优雅地处理异常情况
- 教育价值:错误处理模式是否体现现代 C++ 最佳实践
在 C++23 标准中,std::expected 提供了类型安全的错误处理机制,相比传统的异常或错误码方式,更适合函数式编程风格。
决策
我们采用分层错误处理策略,根据错误的可恢复性选择不同的处理方式:
错误分类
1. 可恢复错误(Recoverable Errors)
可恢复错误是指不影响整体流程继续执行的错误,通常可以通过重试、跳过或降级处理来恢复。
典型场景:
- 训练过程中某个 batch 训练失败,可以跳过该 batch 继续训练下一个
- 数据加载时某个样本损坏,可以跳过该样本继续加载
- 网络请求失败,可以重试或使用缓存数据
- 文件读取时权限不足,可以尝试其他路径或使用默认配置
2. 不可恢复错误(Unrecoverable Errors)
不可恢复错误是指导致当前操作无法继续执行的错误,通常表示程序逻辑错误或系统状态异常。
典型场景:
- 张量维度不匹配且无法进行广播(broadcast)
- 内存分配失败
- 除零操作
- 空指针解引用
- 不支持的张量操作组合
处理机制
可恢复错误:使用 std::expected
对于可恢复错误,使用 C++23 的 std::expected<T, E> 类型:
#include <expected>
#include <string>
// 示例:训练单个 batch
std::expected<void, std::string> trainBatch(const Tensor& batch) {
// 训练逻辑
if (/* 训练失败 */) {
return std::unexpected("Batch training failed: invalid data");
}
return {};
}
// 使用方式
auto result = trainBatch(batch);
if (!result) {
// 可恢复错误,记录日志并继续
logger.warn("Skipping batch: {}", result.error());
continue; // 继续下一个 batch
}
优势:
- 类型安全:编译时检查错误处理
- 性能友好:零开销抽象,不涉及异常机制
- 函数式风格:支持链式调用和组合
- 明确语义:返回值明确表示可能失败的操作
不可恢复错误:使用异常(Exceptions)
对于不可恢复错误,使用 C++ 标准异常机制:
// 示例:张量运算
Tensor add(const Tensor& a, const Tensor& b) {
// 检查维度兼容性
if (!canBroadcast(a.shape(), b.shape())) {
throw std::invalid_argument(
"Tensor shapes incompatible: " +
shapeToString(a.shape()) + " vs " +
shapeToString(b.shape())
);
}
// 检查内存分配
if (/* 内存不足 */) {
throw std::bad_alloc();
}
// 执行运算
return performAdd(a, b);
}
优势:
- 自动传播:错误自动向上传播,无需手动检查
- 清晰语义:异常表示"不应该发生"的情况
- 堆栈信息:配合 C++23 的
std::stacktrace提供完整的调用链
错误类型定义
项目将定义统一的错误类型:
namespace hahaha::error {
// 可恢复错误类型(待定义)
enum class RecoverableError {
BatchTrainingFailed,
DataLoadFailed,
NetworkRequestFailed,
FileAccessDenied,
// ...
};
// 使用 expected 包装
template<typename T>
using Result = std::expected<T, RecoverableError>;
// 不可恢复错误:将定义自定义异常类型(待实现)
// 目前使用标准库异常,如 std::invalid_argument, std::bad_alloc 等
} // namespace hahaha::error
实践指南
1. 函数签名设计
// ✅ 可恢复错误:使用 expected
std::expected<Tensor, std::string> loadDataset(const std::string& path);
// ✅ 不可恢复错误:可能抛出异常
Tensor matmul(const Tensor& a, const Tensor& b); // 可能抛出异常
// ❌ 避免混用:不要在 expected 返回的函数中抛出异常
2. 错误传播
// expected 的错误传播
auto result = step1()
.and_then([](auto val) { return step2(val); })
.and_then([](auto val) { return step3(val); });
if (!result) {
// 统一处理错误
handleError(result.error());
}
// 异常的传播:异常出现时一般是panic, 不错误处理
3. 错误信息规范
- 可恢复错误:提供清晰的错误描述和建议的恢复操作
- 不可恢复错误:提供详细的上下文信息,包括相关参数值、状态信息
// ✅ 好的错误信息
return std::unexpected(
"Failed to load batch: file corrupted at line 42. "
"Skipping this batch and continuing."
);
// ❌ 不好的错误信息
return std::unexpected("Error");
4. 边界情况处理
- 核心训练链路:严格检查,不可恢复错误立即抛出
- 辅助功能:可以容忍部分失败,使用可恢复错误
影响
正面影响
- 类型安全:编译时检查错误处理,减少运行时错误
- 性能优化:
std::expected零开销,异常仅用于真正异常情况 - 代码清晰:错误处理语义明确,易于理解和维护
- 教育价值:展示现代 C++ 错误处理最佳实践
注意事项
- 编译器要求:需要支持 C++23 的
std::expected(GCC 13+, Clang 16+) - 学习曲线:贡献者需要理解
std::expected的使用模式 - 错误分类:需要明确区分可恢复和不可恢复错误,这需要经验和判断
机器学习场景中的错误分类示例
为了帮助开发者更好地理解错误分类,以下列举了机器学习项目中常见的错误类型:
可恢复错误示例:
-
数据加载相关
- 某个数据文件损坏或格式错误 → 跳过该文件,继续加载其他文件
- 数据预处理时某个样本包含无效值(NaN/Inf)→ 跳过该样本,记录警告
- 数据文件路径不存在 → 尝试备用路径或使用默认数据集
- 数据文件权限不足 → 尝试其他路径或使用缓存数据
-
训练过程相关
- 某个 batch 训练时梯度爆炸 → 跳过该 batch,继续下一个
- 某个 batch 的损失值异常(NaN)→ 跳过该 batch,记录日志
- 优化器更新时学习率过小导致无更新 → 调整学习率后重试
- 验证集评估时某个指标计算失败 → 跳过该指标,继续其他指标
-
模型推理相关
- 推理时输入数据格式不匹配 → 尝试自动转换或使用默认值
- 模型输出包含异常值 → 进行后处理修正或使用默认输出
- 推理服务暂时不可用 → 使用缓存结果或降级服务
-
资源管理相关
- GPU 内存不足(单个 batch)→ 减小 batch size 后重试
- 临时文件创建失败 → 使用内存缓存或尝试其他位置
- 网络请求超时 → 重试或使用本地缓存
不可恢复错误示例:
-
张量运算相关
- 矩阵乘法时维度不匹配且无法广播 → 抛出异常
- 张量 reshape 时元素总数不匹配 → 抛出异常
- 张量索引越界 → 抛出异常(可使用
std::out_of_range) - 不支持的数据类型组合运算 → 抛出异常
-
模型结构相关
- 模型层数配置错误导致前向传播无法执行 → 抛出异常
- 模型参数未初始化就进行前向传播 → 抛出异常
- 模型保存/加载时版本不兼容 → 抛出异常
-
计算图相关
- 计算图构建时出现循环依赖 → 抛出异常
- 自动微分时遇到不支持的操作 → 抛出异常
- 反向传播时梯度计算失败(核心逻辑错误)→ 抛出异常
-
系统资源相关
- 系统内存完全耗尽,无法分配张量 → 抛出异常(可使用
std::bad_alloc) - GPU 设备不可用且无法回退到 CPU → 抛出异常
- 关键文件损坏且无备份 → 抛出异常
- 系统内存完全耗尽,无法分配张量 → 抛出异常(可使用
-
数值计算相关
- 除零操作(如归一化时标准差为 0)→ 抛出异常
- 矩阵求逆时矩阵奇异(不可逆)→ 抛出异常
- 数值溢出导致结果无效 → 抛出异常
判断原则:
- 可恢复:错误发生在数据层面或单个操作,不影响整体流程,可以通过跳过、重试、降级等方式继续
- 不可恢复:错误发生在核心计算逻辑、模型结构或系统资源层面,表示程序逻辑错误,必须立即停止并修复
示例代码对比:
// ✅ 可恢复错误:使用 expected
std::expected<Tensor, std::string> loadBatch(const std::string& path) {
if (/* 文件损坏 */) {
return std::unexpected("Batch file corrupted, skipping");
}
return loadFromFile(path);
}
// ✅ 不可恢复错误:抛出异常
Tensor matmul(const Tensor& a, const Tensor& b) {
if (!canMatmul(a.shape(), b.shape())) {
throw std::invalid_argument(
"Cannot multiply: " + shapeToString(a.shape()) +
" × " + shapeToString(b.shape())
);
}
return performMatmul(a, b);
}
相关决策
- ADR-0001:使用 C++23 现代特性 -
std::expected是选择 C++23 的原因之一 - 测试要求 - 错误处理需要相应的测试覆盖
讨论记录
本目录用于存放“过程性”内容:会议纪要、评审记录、观点碰撞、迭代过程中的临时结论等。它的目标是保留上下文,便于追溯,但不要求像 adr/ 那样高度精炼。
这个目录放什么
- 功能迭代讨论(为什么改、怎么改、有哪些分歧)
- 设计评审纪要(问题清单、修改意见、最终结论指向)
- 踩坑记录与排障过程(包含当时的假设与验证)
这个目录不放什么
- 最终决策(放到
adr/) - 可复用、长期稳定的设计稿(放到
design/)
命名建议
- 建议按日期或主题:
YYYY-MM-DD-topic.md或topic.md - 标题建议包含结论摘要,方便在导航里扫读
实现思路文档
本目录用于记录代码实现的思路、设计决策和算法原理。这些文档是 Hahaha 项目教育价值的重要组成部分。
📁 目录结构
explains/ 目录的结构应该与代码目录结构相对应:
explains/
├── index.md # 本文件
├── math/ # 对应 core/include/math/
│ ├── tensor.md # 张量相关实现思路
│ └── tensor-wrapper.md
├── compute/ # 对应 core/include/compute/
│ ├── graph.md # 计算图实现思路
│ └── autograd.md # 自动微分实现思路
├── ml/ # 对应 core/include/ml/
│ ├── optimizer/ # 优化器实现思路
│ │ ├── sgd.md
│ │ └── adam.md
│ ├── model/ # 模型实现思路
│ │ ├── linear.md
│ │ └── knn.md
│ └── loss/ # 损失函数实现思路
│ └── mse.md
├── backend/ # 对应 core/include/backend/
│ ├── device.md
│ └── vectorize.md
└── display/ # 对应 core/include/display/
└── visualizer.md
✍️ 文档内容建议
每篇实现思路文档可以包含以下内容:
1. 功能概述
- 这个功能/模块的作用是什么?
- 它解决了什么问题?
2. 设计思路
- 为什么选择这种实现方式?
- 有哪些替代方案?为什么没有选择它们?
- 设计时考虑了哪些因素?
3. 算法原理
- 核心算法的数学原理
- 算法步骤的详细说明
- 关键公式和推导过程(如果有)
4. 实现细节
- 关键数据结构的说明
- 重要函数的实现逻辑
- 边界情况的处理方式
5. 性能考虑
- 时间复杂度分析
- 空间复杂度分析
- 优化点和权衡
6. 使用示例
- 简单的代码示例
- 常见使用场景
📝 编写指南
文档命名
- 使用小写字母和连字符
- 文件名应该清晰描述内容
- 例如:
adam-optimizer.md、tensor-broadcast.md
文档格式
- 使用 Markdown 格式
- 适当使用代码块、公式、图表
- 保持结构清晰,使用标题层级组织内容
内容要求
- 清晰易懂:用简洁明了的语言表达
- 逻辑完整:包含必要的背景信息和推理过程
- 示例丰富:提供代码示例或伪代码
- 个人思考:体现您的设计思路和理解
AI 辅助
我们完全支持您使用 AI 帮助撰写文档,例如:
- 使用 AI 润色您的口头描述
- 使用 AI 生成数学公式
- 使用 AI 检查语法和格式
但我们更希望看到:
- 有个人思考和理解的文档
- 体现您的设计决策过程
- 避免仅仅是 AI 的生成内容
🔗 相关链接
💡 示例
以下是一个实现思路文档的示例结构:
# Adam 优化器实现思路
## 功能概述
Adam (Adaptive Moment Estimation) 是一种自适应学习率的优化算法...
## 设计思路
### 为什么选择 Adam?
Adam 结合了 Momentum 和 RMSprop 的优点...
### 实现方案
我们选择使用模板类实现,支持不同的数据类型...
## 算法原理
### 数学公式
Adam 的核心公式包括:
- 一阶矩估计:...
- 二阶矩估计:...
- 参数更新:...
### 算法步骤
1. 初始化...
2. 计算梯度...
3. 更新参数...
## 实现细节
### 关键数据结构
```cpp
class AdamOptimizer {
// ...
};
重要函数
step(): 执行一步优化zeroGrad(): 清零梯度
性能考虑
- 时间复杂度:O(n),其中 n 是参数数量
- 空间复杂度:O(n),需要存储动量和方差
使用示例
auto optimizer = AdamOptimizer(parameters, 0.001);
optimizer.zeroGrad();
loss.backward();
optimizer.step();
---
**记住**:好的实现思路文档不仅能帮助他人理解代码,也能帮助您自己更好地理解设计决策。让我们一起构建有价值的知识库!📚✨
附录
本目录用于放“辅助信息”:FAQ、参考资料、术语补充、工具清单等。它们通常不属于主线叙事,但对查阅很有帮助。
这个目录放什么
- FAQ:常见问题与快速解答
- 参考资料:链接、标准、协议、文章
- 工具与命令速查:常用脚本、调试命令
这个目录不放什么
- 项目背景与范围定义(放到
hahaha/) - 设计方案与接口细节(放到
design/) - 过程性讨论(放到
discussions/)
附录:FAQ
Q:图片放哪里?
常见做法是:
- 放在
src/<lang>/assets/(你可以自行创建,例如src/zh/assets/) - 引用时用相对路径,例如:
或
Contributors of Hahaha
This page records contributors of Hahaha and shows their GitHub avatars.
How to add an avatar (GitHub)
GitHub Markdown supports inline HTML. You can embed a user avatar with:
<a href="https://github.com/<username>">
<img src="https://github.com/<username>.png?size=120" width="60" height="60" alt="<username>"/>
</a>
https://github.com/<username>.pngis a stable avatar URL.?size=120requests a larger image; adjust as needed.width/heightcontrols the displayed size.
Avatar wall (template)
Replace USERNAME_* with real GitHub usernames.
Template: