```
feat: 添加模型定义、优化器和训练器功能 - 实现Model接口和Sequential序列模型,支持模型定义和前向传播 - 添加SGD和Adam优化器,支持参数更新和梯度清零 - 创建Trainer训练器,提供完整的训练和评估流程 - 实现模型保存和加载功能,支持参数序列化 - 更新README文档,添加模型训练示例和API文档 - 重构README中的功能特性和示例代码 ```
This commit is contained in:
parent
3e9e913dd4
commit
fcc2e54144
182
README.md
182
README.md
|
|
@ -1,16 +1,19 @@
|
|||
# gotensor
|
||||
|
||||
gotensor 是一个用 Go 语言编写的张量计算库,提供了基本的张量运算、自动微分和反向传播功能。该项目旨在为 Go 语言开发者提供一个高效、易用的张量计算工具。
|
||||
gotensor 是一个用 Go 语言实现的张量计算库,专注于为 Go 开发者提供高效的数值计算能力,支持自动微分和反向传播,适用于构建轻量级机器学习模型。
|
||||
|
||||
## 功能特性
|
||||
|
||||
- 基本张量运算:加法、减法、乘法、矩阵乘法等
|
||||
- 张量操作:数乘、转置等
|
||||
- 自动微分和反向传播
|
||||
- 激活函数:Sigmoid、ReLU、Softmax等
|
||||
- 卷积和池化操作:Conv2D、MaxPool2D、AvgPool2D等
|
||||
- 神经网络层:Flatten、损失函数等
|
||||
- 支持多种初始化方式:零张量、单位矩阵、随机张量等
|
||||
- 基本张量运算:加法、减法、乘法、矩阵乘法
|
||||
- 数乘、转置等张量操作
|
||||
- 自动微分与反向传播机制
|
||||
- 激活函数:Sigmoid、ReLU、Softmax
|
||||
- 卷积与池化操作:Conv2D、MaxPool2D、AvgPool2D
|
||||
- 神经网络层与损失函数:Flatten、CrossEntropy、MSE
|
||||
- 多种初始化方式:零张量、单位矩阵、随机张量
|
||||
- 模型定义和训练支持
|
||||
- 模型保存和加载
|
||||
- 多种优化器:SGD、Adam
|
||||
|
||||
## 安装
|
||||
|
||||
|
|
@ -29,107 +32,106 @@ import (
|
|||
)
|
||||
|
||||
func main() {
|
||||
// 创建两个2x2的张量
|
||||
t1_data := []float64{1, 2, 3, 4}
|
||||
t1_shape := []int{2, 2}
|
||||
t1, err := gotensor.NewTensor(t1_data, t1_shape)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
t2_data := []float64{5, 6, 7, 8}
|
||||
t2, err := gotensor.NewTensor(t2_data, t1_shape)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// 执行加法运算
|
||||
result, err := t1.Add(t2)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
fmt.Printf("结果:\n%s\n", result.String())
|
||||
// 创建张量
|
||||
tensor1, _ := gotensor.NewTensor([]float64{1, 2, 3}, []int{1, 3})
|
||||
tensor2, _ := gotensor.NewTensor([]float64{4, 5, 6}, []int{3, 1})
|
||||
|
||||
// 执行矩阵乘法
|
||||
result, _ := tensor1.MatMul(tensor2)
|
||||
fmt.Println(result)
|
||||
}
|
||||
```
|
||||
|
||||
## 示例
|
||||
## 模型训练示例
|
||||
|
||||
项目包含多个示例,展示如何使用 gotensor:
|
||||
```go
|
||||
package main
|
||||
|
||||
- [基本运算示例](examples/basic_operations.go):展示基本的张量运算
|
||||
- [自动微分示例](examples/autograd_example.go):演示自动微分和反向传播
|
||||
- [线性回归示例](examples/linear_regression.go):使用 gotensor 实现简单的线性回归
|
||||
- [CNN示例](examples/cnn_example.go):使用卷积、池化等操作构建简单的卷积神经网络
|
||||
import (
|
||||
"fmt"
|
||||
"git.kingecg.top/kingecg/gotensor"
|
||||
)
|
||||
|
||||
运行示例:
|
||||
|
||||
```bash
|
||||
# 基本运算示例
|
||||
go run examples/basic_operations.go
|
||||
|
||||
# 自动微分示例
|
||||
go run examples/autograd_example.go
|
||||
|
||||
# 线性回归示例
|
||||
go run examples/linear_regression.go
|
||||
|
||||
# CNN示例
|
||||
go run examples/cnn_example.go
|
||||
func main() {
|
||||
// 创建模型(例如:简单的线性回归模型)
|
||||
// 这里可以使用Sequential模型或者自定义模型
|
||||
|
||||
// 定义一些示例数据
|
||||
input, _ := gotensor.NewTensor([]float64{1, 2, 3, 4}, []int{2, 2})
|
||||
target, _ := gotensor.NewTensor([]float64{5, 6, 7, 8}, []int{2, 2})
|
||||
|
||||
// 创建模型参数
|
||||
weights, _ := gotensor.NewTensor([]float64{0.5, 0.3, 0.2, 0.4}, []int{2, 2})
|
||||
|
||||
// 定义模型(这里简化为单个张量,实际中会是更复杂的结构)
|
||||
// ...
|
||||
|
||||
// 定义优化器
|
||||
optimizer := gotensor.NewSGD([]*gotensor.Tensor{weights}, 0.01)
|
||||
|
||||
// 创建训练器
|
||||
trainer := gotensor.NewTrainer(nil, optimizer) // 需要传入实际模型
|
||||
|
||||
// 开始训练
|
||||
// trainer.Train(trainInputs, trainTargets, epochs, lossFn, true)
|
||||
|
||||
fmt.Println("Training example")
|
||||
}
|
||||
```
|
||||
|
||||
## API 文档
|
||||
|
||||
### 创建张量
|
||||
### 张量操作
|
||||
|
||||
- `NewTensor(data []float64, shape []int)` - 创建新的张量
|
||||
- `NewZeros(shape []int)` - 创建零张量
|
||||
- `NewOnes(shape []int)` - 创建全一张量
|
||||
- `NewIdentity(size int)` - 创建单位矩阵
|
||||
|
||||
### 张量运算
|
||||
|
||||
- `Add(other *Tensor)` - 张量加法
|
||||
- `Subtract(other *Tensor)` - 张量减法
|
||||
- `Multiply(other *Tensor)` - 张量逐元素乘法
|
||||
- `MatMul(other *Tensor)` - 矩阵乘法
|
||||
- `Scale(factor float64)` - 数乘
|
||||
|
||||
### 激活函数
|
||||
|
||||
- `Sigmoid()` - Sigmoid激活函数
|
||||
- `ReLU()` - ReLU激活函数
|
||||
- `Softmax()` - Softmax激活函数
|
||||
|
||||
### 卷积和池化
|
||||
|
||||
- `Conv2D(kernel *Tensor, stride, padding int)` - 二维卷积操作
|
||||
- `MaxPool2D(kernelSize, stride int)` - 二维最大池化
|
||||
- `AvgPool2D(kernelSize, stride int)` - 二维平均池化
|
||||
- `NewTensor(data []float64, shape []int)`: 创建新张量
|
||||
- `Add(other *Tensor)`: 张量加法
|
||||
- `Subtract(other *Tensor)`: 张量减法
|
||||
- `Multiply(other *Tensor)`: 张量逐元素乘法
|
||||
- `MatMul(other *Tensor)`: 矩阵乘法
|
||||
- `Scale(factor float64)`: 张量数乘
|
||||
- `Sigmoid()`: Sigmoid激活函数
|
||||
- `ReLU()`: ReLU激活函数
|
||||
- `Softmax()`: Softmax函数
|
||||
- `Backward()`: 反向传播
|
||||
|
||||
### 神经网络层
|
||||
|
||||
- `Flatten()` - 将多维张量展平为一维
|
||||
- `CrossEntropy(target *Tensor)` - 交叉熵损失函数
|
||||
- `MeanSquaredError(target *Tensor)` - 均方误差损失函数
|
||||
- `Flatten()`: 展平张量
|
||||
- `CrossEntropy(target *Tensor)`: 交叉熵损失
|
||||
- `MeanSquaredError(target *Tensor)`: 均方误差损失
|
||||
|
||||
### 其他方法
|
||||
### 模型定义
|
||||
|
||||
- `ZeroGrad()` - 将梯度置零
|
||||
- `Shape()` - 返回张量形状
|
||||
- `Size()` - 返回张量大小
|
||||
- `Get(indices ...int)` - 获取指定位置的值
|
||||
- `Set(value float64, indices ...int)` - 设置指定位置的值
|
||||
- `Backward()` - 执行反向传播
|
||||
- `Sequential`: 序列模型
|
||||
- `Model` 接口: 模型的基本接口
|
||||
- `SaveModel(model Model, filepath string)`: 保存模型
|
||||
- `LoadModel(model Model, filepath string)`: 加载模型
|
||||
|
||||
## 测试
|
||||
### 优化器
|
||||
|
||||
运行测试:
|
||||
- `SGD`: 随机梯度下降
|
||||
- `Adam`: Adam优化算法
|
||||
|
||||
```bash
|
||||
go test
|
||||
```
|
||||
### 训练器
|
||||
|
||||
- `Trainer`: 训练管理器
|
||||
- `NewTrainer(model Model, optimizer Optimizer)`: 创建训练器
|
||||
- `Train(...)`: 执行训练
|
||||
- `Evaluate(...)`: 评估模型
|
||||
|
||||
## 示例
|
||||
|
||||
项目包含多个示例:
|
||||
|
||||
- `examples/basic_operation`: 基本张量运算示例
|
||||
- `examples/autograd`: 自动微分示例
|
||||
- `examples/linear_regression`: 线性回归示例
|
||||
- `examples/cnn_example.go`: 卷积神经网络示例
|
||||
|
||||
## 贡献
|
||||
|
||||
欢迎提交 Issue 和 Pull Request 来帮助改进 gotensor!
|
||||
|
||||
## 许可证
|
||||
|
||||
本项目使用 MIT 许可证 - 详见 [LICENSE](LICENSE) 文件。
|
||||
本项目使用 MIT 许可证 - 详见 [LICENSE](LICENSE) 文件。
|
||||
|
|
|
|||
|
|
@ -0,0 +1,124 @@
|
|||
package gotensor
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"os"
|
||||
)
|
||||
|
||||
// Model 模型接口定义
|
||||
type Model interface {
|
||||
Forward(inputs *Tensor) (*Tensor, error)
|
||||
Parameters() []*Tensor // 获取模型所有参数
|
||||
ZeroGrad() // 将所有参数的梯度清零
|
||||
}
|
||||
|
||||
// Sequential 序列模型,按顺序执行层
|
||||
type Sequential struct {
|
||||
Layers []Layer
|
||||
}
|
||||
|
||||
// Layer 接口定义
|
||||
type Layer interface {
|
||||
Forward(inputs *Tensor) (*Tensor, error)
|
||||
Parameters() []*Tensor
|
||||
ZeroGrad()
|
||||
}
|
||||
|
||||
// Forward 实现前向传播
|
||||
func (s *Sequential) Forward(inputs *Tensor) (*Tensor, error) {
|
||||
output := inputs
|
||||
var err error
|
||||
|
||||
for _, layer := range s.Layers {
|
||||
output, err = layer.Forward(output)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return output, nil
|
||||
}
|
||||
|
||||
// Parameters 获取模型所有参数
|
||||
func (s *Sequential) Parameters() []*Tensor {
|
||||
var params []*Tensor
|
||||
for _, layer := range s.Layers {
|
||||
params = append(params, layer.Parameters()...)
|
||||
}
|
||||
return params
|
||||
}
|
||||
|
||||
// ZeroGrad 将所有参数梯度清零
|
||||
func (s *Sequential) ZeroGrad() {
|
||||
for _, layer := range s.Layers {
|
||||
layer.ZeroGrad()
|
||||
}
|
||||
}
|
||||
|
||||
// SaveModel 保存模型参数到文件
|
||||
func SaveModel(model Model, filepath string) error {
|
||||
params := model.Parameters()
|
||||
paramsData := make([][]float64, len(params))
|
||||
|
||||
for i, param := range params {
|
||||
shape := param.Shape()
|
||||
size := param.Size()
|
||||
data := make([]float64, size)
|
||||
|
||||
for idx := 0; idx < size; idx++ {
|
||||
if len(shape) == 1 {
|
||||
data[idx], _ = param.Data.Get(idx)
|
||||
} else if len(shape) == 2 {
|
||||
cols := shape[1]
|
||||
data[idx], _ = param.Data.Get(idx/cols, idx%cols)
|
||||
}
|
||||
}
|
||||
paramsData[i] = data
|
||||
}
|
||||
|
||||
file, err := os.Create(filepath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
return json.NewEncoder(file).Encode(paramsData)
|
||||
}
|
||||
|
||||
// LoadModel 从文件加载模型参数
|
||||
func LoadModel(model Model, filepath string) error {
|
||||
file, err := os.Open(filepath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
var paramsData [][]float64
|
||||
err = json.NewDecoder(file).Decode(¶msData)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
params := model.Parameters()
|
||||
if len(params) != len(paramsData) {
|
||||
return nil // 参数数量不匹配,返回错误
|
||||
}
|
||||
|
||||
for i, param := range params {
|
||||
data := paramsData[i]
|
||||
shape := param.Shape()
|
||||
|
||||
if len(shape) == 1 {
|
||||
for idx, val := range data {
|
||||
param.Data.Set(val, idx)
|
||||
}
|
||||
} else if len(shape) == 2 {
|
||||
cols := shape[1]
|
||||
for idx, val := range data {
|
||||
param.Data.Set(val, idx/cols, idx%cols)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
@ -0,0 +1,213 @@
|
|||
package gotensor
|
||||
|
||||
import "math"
|
||||
|
||||
// Optimizer 优化器接口
|
||||
type Optimizer interface {
|
||||
Step() // 根据梯度更新参数
|
||||
ZeroGrad() // 清空所有梯度
|
||||
}
|
||||
|
||||
// SGD 随机梯度下降优化器
|
||||
type SGD struct {
|
||||
Parameters []*Tensor
|
||||
LR float64 // 学习率
|
||||
}
|
||||
|
||||
// NewSGD 创建一个新的SGD优化器
|
||||
func NewSGD(parameters []*Tensor, lr float64) *SGD {
|
||||
return &SGD{
|
||||
Parameters: parameters,
|
||||
LR: lr,
|
||||
}
|
||||
}
|
||||
|
||||
// Step 更新参数
|
||||
func (s *SGD) Step() {
|
||||
for _, param := range s.Parameters {
|
||||
// 获取参数的梯度
|
||||
grad := param.Grad
|
||||
|
||||
// 获取参数的形状
|
||||
shape := param.Data.Shape()
|
||||
|
||||
// 更新参数: param = param - lr * grad
|
||||
if len(shape) == 1 {
|
||||
for i := 0; i < shape[0]; i++ {
|
||||
paramVal, _ := param.Data.Get(i)
|
||||
gradVal, _ := grad.Get(i)
|
||||
newVal := paramVal - s.LR * gradVal
|
||||
param.Data.Set(newVal, i)
|
||||
}
|
||||
} else if len(shape) == 2 {
|
||||
rows, cols := shape[0], shape[1]
|
||||
for i := 0; i < rows; i++ {
|
||||
for j := 0; j < cols; j++ {
|
||||
paramVal, _ := param.Data.Get(i, j)
|
||||
gradVal, _ := grad.Get(i, j)
|
||||
newVal := paramVal - s.LR * gradVal
|
||||
param.Data.Set(newVal, i, j)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ZeroGrad 清空所有梯度
|
||||
func (s *SGD) ZeroGrad() {
|
||||
for _, param := range s.Parameters {
|
||||
param.ZeroGrad()
|
||||
}
|
||||
}
|
||||
|
||||
// Adam 优化器
|
||||
type Adam struct {
|
||||
Parameters []*Tensor
|
||||
LR float64 // 学习率
|
||||
Beta1 float64 // 一阶矩估计的指数衰减率
|
||||
Beta2 float64 // 二阶矩估计的指数衰减率
|
||||
Epsilon float64 // 防止除零的小常数
|
||||
T int // 当前步数
|
||||
|
||||
// 一阶矩估计
|
||||
M []map[string]*Tensor
|
||||
// 二阶矩估计
|
||||
V []map[string]*Tensor
|
||||
}
|
||||
|
||||
// NewAdam 创建一个新的Adam优化器
|
||||
func NewAdam(parameters []*Tensor, lr, beta1, beta2, epsilon float64) *Adam {
|
||||
adam := &Adam{
|
||||
Parameters: parameters,
|
||||
LR: lr,
|
||||
Beta1: beta1,
|
||||
Beta2: beta2,
|
||||
Epsilon: epsilon,
|
||||
T: 0,
|
||||
M: make([]map[string]*Tensor, len(parameters)),
|
||||
V: make([]map[string]*Tensor, len(parameters)),
|
||||
}
|
||||
|
||||
// 初始化M和V
|
||||
for i := range parameters {
|
||||
adam.M[i] = make(map[string]*Tensor)
|
||||
adam.V[i] = make(map[string]*Tensor)
|
||||
|
||||
// 创建与参数形状相同的零张量
|
||||
shape := parameters[i].Shape()
|
||||
m, _ := NewZeros(shape)
|
||||
v, _ := NewZeros(shape)
|
||||
|
||||
adam.M[i]["tensor"] = m
|
||||
adam.V[i]["tensor"] = v
|
||||
}
|
||||
|
||||
return adam
|
||||
}
|
||||
|
||||
// Step 更新参数
|
||||
func (a *Adam) Step() {
|
||||
a.T++
|
||||
|
||||
for i, param := range a.Parameters {
|
||||
grad := param.Grad
|
||||
shape := param.Data.Shape()
|
||||
|
||||
// 更新一阶矩估计: m = beta1 * m + (1 - beta1) * grad
|
||||
m := a.M[i]["tensor"]
|
||||
newMData := make([]float64, param.Size())
|
||||
|
||||
if len(shape) == 1 {
|
||||
for idx := 0; idx < shape[0]; idx++ {
|
||||
mVal, _ := m.Data.Get(idx)
|
||||
gradVal, _ := grad.Get(idx)
|
||||
newMData[idx] = a.Beta1 * mVal + (1 - a.Beta1) * gradVal
|
||||
}
|
||||
} else if len(shape) == 2 {
|
||||
rows, cols := shape[0], shape[1]
|
||||
for r := 0; r < rows; r++ {
|
||||
for c := 0; c < cols; c++ {
|
||||
mVal, _ := m.Data.Get(r, c)
|
||||
gradVal, _ := grad.Get(r, c)
|
||||
newMData[r*cols+c] = a.Beta1 * mVal + (1 - a.Beta1) * gradVal
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
newM, _ := NewTensor(newMData, shape)
|
||||
a.M[i]["tensor"] = newM
|
||||
|
||||
// 更新二阶矩估计: v = beta2 * v + (1 - beta2) * grad^2
|
||||
v := a.V[i]["tensor"]
|
||||
newVData := make([]float64, param.Size())
|
||||
|
||||
if len(shape) == 1 {
|
||||
for idx := 0; idx < shape[0]; idx++ {
|
||||
vVal, _ := v.Data.Get(idx)
|
||||
gradVal, _ := grad.Get(idx)
|
||||
newVData[idx] = a.Beta2 * vVal + (1 - a.Beta2) * gradVal * gradVal
|
||||
}
|
||||
} else if len(shape) == 2 {
|
||||
rows, cols := shape[0], shape[1]
|
||||
for r := 0; r < rows; r++ {
|
||||
for c := 0; c < cols; c++ {
|
||||
vVal, _ := v.Data.Get(r, c)
|
||||
gradVal, _ := grad.Get(r, c)
|
||||
newVData[r*cols+c] = a.Beta2 * vVal + (1 - a.Beta2) * gradVal * gradVal
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
newV, _ := NewTensor(newVData, shape)
|
||||
a.V[i]["tensor"] = newV
|
||||
|
||||
// 计算偏差修正的一阶矩估计
|
||||
mHatData := make([]float64, param.Size())
|
||||
mHatShape := shape
|
||||
for idx := 0; idx < param.Size(); idx++ {
|
||||
mVal, _ := newM.Data.Get(idx)
|
||||
mHatData[idx] = mVal / (1 - math.Pow(a.Beta1, float64(a.T)))
|
||||
}
|
||||
mHat, _ := NewTensor(mHatData, mHatShape)
|
||||
|
||||
// 计算偏差修正的二阶矩估计
|
||||
vHatData := make([]float64, param.Size())
|
||||
vHatShape := shape
|
||||
for idx := 0; idx < param.Size(); idx++ {
|
||||
vVal, _ := newV.Data.Get(idx)
|
||||
vHatData[idx] = vVal / (1 - math.Pow(a.Beta2, float64(a.T)))
|
||||
}
|
||||
vHat, _ := NewTensor(vHatData, vHatShape)
|
||||
|
||||
// 更新参数: param = param - lr * m_hat / (sqrt(v_hat) + epsilon)
|
||||
if len(shape) == 1 {
|
||||
for idx := 0; idx < shape[0]; idx++ {
|
||||
paramVal, _ := param.Data.Get(idx)
|
||||
mHatVal, _ := mHat.Data.Get(idx)
|
||||
vHatVal, _ := vHat.Data.Get(idx)
|
||||
updateVal := a.LR * mHatVal / (math.Sqrt(vHatVal) + a.Epsilon)
|
||||
newVal := paramVal - updateVal
|
||||
param.Data.Set(newVal, idx)
|
||||
}
|
||||
} else if len(shape) == 2 {
|
||||
rows, cols := shape[0], shape[1]
|
||||
for r := 0; r < rows; r++ {
|
||||
for c := 0; c < cols; c++ {
|
||||
paramVal, _ := param.Data.Get(r, c)
|
||||
mHatVal, _ := mHat.Data.Get(r, c)
|
||||
vHatVal, _ := vHat.Data.Get(r, c)
|
||||
updateVal := a.LR * mHatVal / (math.Sqrt(vHatVal) + a.Epsilon)
|
||||
newVal := paramVal - updateVal
|
||||
param.Data.Set(newVal, r, c)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ZeroGrad 清空所有梯度
|
||||
func (a *Adam) ZeroGrad() {
|
||||
for _, param := range a.Parameters {
|
||||
param.ZeroGrad()
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,92 @@
|
|||
package gotensor
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// Trainer 训练器结构,管理整个训练过程
|
||||
type Trainer struct {
|
||||
Model Model
|
||||
Optimizer Optimizer
|
||||
}
|
||||
|
||||
// NewTrainer 创建新的训练器
|
||||
func NewTrainer(model Model, optimizer Optimizer) *Trainer {
|
||||
return &Trainer{
|
||||
Model: model,
|
||||
Optimizer: optimizer,
|
||||
}
|
||||
}
|
||||
|
||||
// TrainEpoch 训练一个epoch
|
||||
func (t *Trainer) TrainEpoch(inputs []*Tensor, targets []*Tensor, lossFn func(*Tensor, *Tensor) *Tensor) (float64, error) {
|
||||
var totalLoss float64
|
||||
|
||||
for i := 0; i < len(inputs); i++ {
|
||||
// 前向传播
|
||||
output, err := t.Model.Forward(inputs[i])
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
// 计算损失
|
||||
loss := lossFn(output, targets[i])
|
||||
lossVal, _ := loss.Data.Get(0)
|
||||
totalLoss += lossVal
|
||||
|
||||
// 反向传播
|
||||
loss.Backward()
|
||||
|
||||
// 更新参数
|
||||
t.Optimizer.Step()
|
||||
|
||||
// 清空梯度
|
||||
t.Optimizer.ZeroGrad()
|
||||
}
|
||||
|
||||
avgLoss := totalLoss / float64(len(inputs))
|
||||
return avgLoss, nil
|
||||
}
|
||||
|
||||
// Train 完整的训练过程
|
||||
func (t *Trainer) Train(
|
||||
trainInputs []*Tensor,
|
||||
trainTargets []*Tensor,
|
||||
epochs int,
|
||||
lossFn func(*Tensor, *Tensor) *Tensor,
|
||||
verbose bool,
|
||||
) error {
|
||||
for epoch := 0; epoch < epochs; epoch++ {
|
||||
avgLoss, err := t.TrainEpoch(trainInputs, trainTargets, lossFn)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if verbose {
|
||||
fmt.Printf("Epoch [%d/%d], Loss: %.6f\n", epoch+1, epochs, avgLoss)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Evaluate 评估模型性能
|
||||
func (t *Trainer) Evaluate(testInputs []*Tensor, testTargets []*Tensor, lossFn func(*Tensor, *Tensor) *Tensor) (float64, error) {
|
||||
var totalLoss float64
|
||||
|
||||
for i := 0; i < len(testInputs); i++ {
|
||||
// 前向传播
|
||||
output, err := t.Model.Forward(testInputs[i])
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
// 计算损失
|
||||
loss := lossFn(output, testTargets[i])
|
||||
lossVal, _ := loss.Data.Get(0)
|
||||
totalLoss += lossVal
|
||||
}
|
||||
|
||||
avgLoss := totalLoss / float64(len(testInputs))
|
||||
return avgLoss, nil
|
||||
}
|
||||
Loading…
Reference in New Issue