533 lines
11 KiB
Go
533 lines
11 KiB
Go
package gotensor
|
||
|
||
import (
|
||
"git.kingecg.top/kingecg/gomatrix"
|
||
"math"
|
||
)
|
||
|
||
const (
|
||
Max_Prevs = 10
|
||
Max_Args = 10
|
||
)
|
||
|
||
type Arg interface {
|
||
int | float64 | []int
|
||
}
|
||
|
||
type Tensor struct {
|
||
Data *gomatrix.Matrix
|
||
Grad *gomatrix.Matrix
|
||
Prevs [Max_Prevs]*Tensor
|
||
Num_Prevs int
|
||
Args [Max_Args]any // must meet Arg
|
||
Op string // 操作类型,用于反向传播
|
||
backwardFunc func() // 反向传播函数
|
||
}
|
||
|
||
// NewTensor 创建一个新的Tensor
|
||
func NewTensor(data []float64, shape []int) (*Tensor, error) {
|
||
matrix, err := gomatrix.NewMatrix(data, shape)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
// 创建梯度矩阵,初始为零
|
||
grad, err := gomatrix.NewZeros(shape)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
return &Tensor{
|
||
Data: matrix,
|
||
Grad: grad,
|
||
Op: "",
|
||
}, nil
|
||
}
|
||
|
||
// NewZeros 创建一个全零Tensor
|
||
func NewZeros(shape []int) (*Tensor, error) {
|
||
matrix, err := gomatrix.NewZeros(shape)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
grad, err := gomatrix.NewZeros(shape)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
return &Tensor{
|
||
Data: matrix,
|
||
Grad: grad,
|
||
Op: "zeros",
|
||
}, nil
|
||
}
|
||
|
||
// NewOnes 创建一个全一Tensor
|
||
func NewOnes(shape []int) (*Tensor, error) {
|
||
matrix, err := gomatrix.NewOnes(shape)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
grad, err := gomatrix.NewZeros(shape)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
return &Tensor{
|
||
Data: matrix,
|
||
Grad: grad,
|
||
Op: "ones",
|
||
}, nil
|
||
}
|
||
|
||
// NewIdentity 创建一个单位Tensor(矩阵)
|
||
func NewIdentity(size int) (*Tensor, error) {
|
||
matrix, err := gomatrix.NewIdentity(size)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
grad, err := gomatrix.NewZeros([]int{size, size})
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
return &Tensor{
|
||
Data: matrix,
|
||
Grad: grad,
|
||
Op: "identity",
|
||
}, nil
|
||
}
|
||
|
||
// Add Tensor加法
|
||
func (t *Tensor) Add(other *Tensor) (*Tensor, error) {
|
||
result, err := t.Data.Add(other.Data)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
// 创建结果Tensor
|
||
output := &Tensor{
|
||
Data: result,
|
||
Op: "add",
|
||
}
|
||
|
||
// 记录依赖关系
|
||
output.Prevs[0] = t
|
||
output.Prevs[1] = other
|
||
output.Num_Prevs = 2
|
||
|
||
// 定义反向传播函数
|
||
output.backwardFunc = func() {
|
||
if t.Grad != nil {
|
||
// 对t的梯度等于输出梯度
|
||
grad, _ := t.Grad.Add(output.Grad)
|
||
t.Grad = grad
|
||
}
|
||
if other.Grad != nil {
|
||
// 对other的梯度等于输出梯度
|
||
grad, _ := other.Grad.Add(output.Grad)
|
||
other.Grad = grad
|
||
}
|
||
}
|
||
|
||
return output, nil
|
||
}
|
||
|
||
// Subtract Tensor减法
|
||
func (t *Tensor) Subtract(other *Tensor) (*Tensor, error) {
|
||
result, err := t.Data.Subtract(other.Data)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
output := &Tensor{
|
||
Data: result,
|
||
Op: "sub",
|
||
}
|
||
|
||
output.Prevs[0] = t
|
||
output.Prevs[1] = other
|
||
output.Num_Prevs = 2
|
||
|
||
output.backwardFunc = func() {
|
||
if t.Grad != nil {
|
||
// 对t的梯度等于输出梯度
|
||
grad, _ := t.Grad.Add(output.Grad)
|
||
t.Grad = grad
|
||
}
|
||
if other.Grad != nil {
|
||
// 对other的梯度等于输出梯度的负值
|
||
negGrad := output.Grad.Scale(-1.0)
|
||
grad, _ := other.Grad.Add(negGrad)
|
||
other.Grad = grad
|
||
}
|
||
}
|
||
|
||
return output, nil
|
||
}
|
||
|
||
// Multiply Tensor乘法(逐元素相乘)
|
||
func (t *Tensor) Multiply(other *Tensor) (*Tensor, error) {
|
||
result, err := t.Data.Multiply(other.Data)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
output := &Tensor{
|
||
Data: result,
|
||
Op: "mul",
|
||
}
|
||
|
||
output.Prevs[0] = t
|
||
output.Prevs[1] = other
|
||
output.Num_Prevs = 2
|
||
|
||
output.backwardFunc = func() {
|
||
if t.Grad != nil {
|
||
// 对t的梯度 = output.Grad * other.Data
|
||
gradWithOther, _ := output.Grad.Multiply(other.Data)
|
||
grad, _ := t.Grad.Add(gradWithOther)
|
||
t.Grad = grad
|
||
}
|
||
if other.Grad != nil {
|
||
// 对other的梯度 = output.Grad * t.Data
|
||
gradWithT, _ := output.Grad.Multiply(t.Data)
|
||
grad, _ := other.Grad.Add(gradWithT)
|
||
other.Grad = grad
|
||
}
|
||
}
|
||
|
||
return output, nil
|
||
}
|
||
|
||
// MatMul Tensor矩阵乘法
|
||
func (t *Tensor) MatMul(other *Tensor) (*Tensor, error) {
|
||
result, err := t.Data.MatMul(other.Data)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
output := &Tensor{
|
||
Data: result,
|
||
Op: "matmul",
|
||
}
|
||
|
||
output.Prevs[0] = t
|
||
output.Prevs[1] = other
|
||
output.Num_Prevs = 2
|
||
|
||
output.backwardFunc = func() {
|
||
if t.Grad != nil {
|
||
// 对t的梯度 = output.Grad * other.Data^T
|
||
otherT, _ := other.Data.Transpose()
|
||
gradResult, _ := output.Grad.MatMul(otherT)
|
||
grad, _ := t.Grad.Add(gradResult)
|
||
t.Grad = grad
|
||
}
|
||
if other.Grad != nil {
|
||
// 对other的梯度 = t.Data^T * output.Grad
|
||
tT, _ := t.Data.Transpose()
|
||
gradResult, _ := tT.MatMul(output.Grad)
|
||
grad, _ := other.Grad.Add(gradResult)
|
||
other.Grad = grad
|
||
}
|
||
}
|
||
|
||
return output, nil
|
||
}
|
||
|
||
// Scale Tensor数乘
|
||
func (t *Tensor) Scale(factor float64) *Tensor {
|
||
result := t.Data.Scale(factor)
|
||
|
||
output := &Tensor{
|
||
Data: result,
|
||
Op: "scale",
|
||
}
|
||
|
||
output.Prevs[0] = t
|
||
output.Num_Prevs = 1
|
||
output.Args[0] = factor
|
||
|
||
output.backwardFunc = func() {
|
||
if t.Grad != nil {
|
||
// 对t的梯度 = output.Grad * factor
|
||
scaledGrad := output.Grad.Scale(factor)
|
||
grad, _ := t.Grad.Add(scaledGrad)
|
||
t.Grad = grad
|
||
}
|
||
}
|
||
|
||
return output
|
||
}
|
||
|
||
// ZeroGrad 将梯度置零
|
||
func (t *Tensor) ZeroGrad() {
|
||
if t.Grad != nil {
|
||
shape := t.Grad.Shape()
|
||
zeroGrad, _ := gomatrix.NewZeros(shape)
|
||
t.Grad = zeroGrad
|
||
}
|
||
}
|
||
|
||
// Shape 返回Tensor的形状
|
||
func (t *Tensor) Shape() []int {
|
||
return t.Data.Shape()
|
||
}
|
||
|
||
// Size 返回Tensor的大小
|
||
func (t *Tensor) Size() int {
|
||
return t.Data.Size()
|
||
}
|
||
|
||
// Get 获取指定位置的值
|
||
func (t *Tensor) Get(indices ...int) (float64, error) {
|
||
return t.Data.Get(indices...)
|
||
}
|
||
|
||
// Set 设置指定位置的值
|
||
func (t *Tensor) Set(value float64, indices ...int) error {
|
||
return t.Data.Set(value, indices...)
|
||
}
|
||
|
||
// String 返回Tensor的字符串表示
|
||
func (t *Tensor) String() string {
|
||
return t.Data.String()
|
||
}
|
||
|
||
// Sigmoid 激活函数
|
||
func (t *Tensor) Sigmoid() *Tensor {
|
||
// 计算每个元素的sigmoid值
|
||
inputShape := t.Data.Shape()
|
||
resultData := make([]float64, t.Data.Size())
|
||
|
||
// 遍历所有元素计算sigmoid
|
||
idx := 0
|
||
if len(inputShape) == 1 {
|
||
for i := 0; i < inputShape[0]; i++ {
|
||
val, _ := t.Data.Get(i)
|
||
resultData[idx] = sigmoid(val)
|
||
idx++
|
||
}
|
||
} else if len(inputShape) == 2 {
|
||
rows, cols := inputShape[0], inputShape[1]
|
||
for i := 0; i < rows; i++ {
|
||
for j := 0; j < cols; j++ {
|
||
val, _ := t.Data.Get(i, j)
|
||
resultData[idx] = sigmoid(val)
|
||
idx++
|
||
}
|
||
}
|
||
} else if len(inputShape) == 4 {
|
||
batch, ch, h, w := inputShape[0], inputShape[1], inputShape[2], inputShape[3]
|
||
for b := 0; b < batch; b++ {
|
||
for c := 0; c < ch; c++ {
|
||
for h_idx := 0; h_idx < h; h_idx++ {
|
||
for w_idx := 0; w_idx < w; w_idx++ {
|
||
val, _ := t.Data.Get(b, c, h_idx, w_idx)
|
||
resultData[idx] = sigmoid(val)
|
||
idx++
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
result, _ := gomatrix.NewMatrix(resultData, inputShape)
|
||
|
||
output := &Tensor{
|
||
Data: result,
|
||
Op: "sigmoid",
|
||
}
|
||
|
||
output.Prevs[0] = t
|
||
output.Num_Prevs = 1
|
||
|
||
output.backwardFunc = func() {
|
||
if t.Grad != nil {
|
||
// Sigmoid的导数: sigmoid(x) * (1 - sigmoid(x))
|
||
gradData := make([]float64, t.Data.Size())
|
||
gradIdx := 0
|
||
|
||
if len(inputShape) == 1 {
|
||
for i := 0; i < inputShape[0]; i++ {
|
||
sigmoidVal, _ := result.Get(i)
|
||
gradData[gradIdx] = sigmoidVal * (1 - sigmoidVal)
|
||
gradIdx++
|
||
}
|
||
} else if len(inputShape) == 2 {
|
||
rows, cols := inputShape[0], inputShape[1]
|
||
for i := 0; i < rows; i++ {
|
||
for j := 0; j < cols; j++ {
|
||
sigmoidVal, _ := result.Get(i, j)
|
||
gradData[gradIdx] = sigmoidVal * (1 - sigmoidVal)
|
||
gradIdx++
|
||
}
|
||
}
|
||
} else if len(inputShape) == 4 {
|
||
batch, ch, h, w := inputShape[0], inputShape[1], inputShape[2], inputShape[3]
|
||
for b := 0; b < batch; b++ {
|
||
for c := 0; c < ch; c++ {
|
||
for h_idx := 0; h_idx < h; h_idx++ {
|
||
for w_idx := 0; w_idx < w; w_idx++ {
|
||
sigmoidVal, _ := result.Get(b, c, h_idx, w_idx)
|
||
gradData[gradIdx] = sigmoidVal * (1 - sigmoidVal)
|
||
gradIdx++
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
gradMatrix, _ := gomatrix.NewMatrix(gradData, inputShape)
|
||
|
||
// 与输出梯度相乘
|
||
gradWithOutput, _ := gradMatrix.Multiply(output.Grad)
|
||
grad, _ := t.Grad.Add(gradWithOutput)
|
||
t.Grad = grad
|
||
}
|
||
}
|
||
|
||
return output
|
||
}
|
||
|
||
// ReLU 激活函数
|
||
func (t *Tensor) ReLU() *Tensor {
|
||
// 计算每个元素的ReLU值
|
||
inputShape := t.Data.Shape()
|
||
resultData := make([]float64, t.Data.Size())
|
||
|
||
// 遍历所有元素计算ReLU
|
||
idx := 0
|
||
if len(inputShape) == 1 {
|
||
for i := 0; i < inputShape[0]; i++ {
|
||
val, _ := t.Data.Get(i)
|
||
if val > 0 {
|
||
resultData[idx] = val
|
||
} else {
|
||
resultData[idx] = 0
|
||
}
|
||
idx++
|
||
}
|
||
} else if len(inputShape) == 2 {
|
||
rows, cols := inputShape[0], inputShape[1]
|
||
for i := 0; i < rows; i++ {
|
||
for j := 0; j < cols; j++ {
|
||
val, _ := t.Data.Get(i, j)
|
||
if val > 0 {
|
||
resultData[idx] = val
|
||
} else {
|
||
resultData[idx] = 0
|
||
}
|
||
idx++
|
||
}
|
||
}
|
||
} else if len(inputShape) == 4 {
|
||
batch, ch, h, w := inputShape[0], inputShape[1], inputShape[2], inputShape[3]
|
||
for b := 0; b < batch; b++ {
|
||
for c := 0; c < ch; c++ {
|
||
for h_idx := 0; h_idx < h; h_idx++ {
|
||
for w_idx := 0; w_idx < w; w_idx++ {
|
||
val, _ := t.Data.Get(b, c, h_idx, w_idx)
|
||
if val > 0 {
|
||
resultData[idx] = val
|
||
} else {
|
||
resultData[idx] = 0
|
||
}
|
||
idx++
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
result, _ := gomatrix.NewMatrix(resultData, inputShape)
|
||
|
||
output := &Tensor{
|
||
Data: result,
|
||
Op: "relu",
|
||
}
|
||
|
||
output.Prevs[0] = t
|
||
output.Num_Prevs = 1
|
||
|
||
output.backwardFunc = func() {
|
||
if t.Grad != nil {
|
||
// ReLU的导数: 输入大于0时为1,否则为0
|
||
gradData := make([]float64, t.Data.Size())
|
||
gradIdx := 0
|
||
|
||
if len(inputShape) == 1 {
|
||
for i := 0; i < inputShape[0]; i++ {
|
||
val, _ := t.Data.Get(i)
|
||
if val > 0 {
|
||
gradData[gradIdx] = 1
|
||
} else {
|
||
gradData[gradIdx] = 0
|
||
}
|
||
gradIdx++
|
||
}
|
||
} else if len(inputShape) == 2 {
|
||
rows, cols := inputShape[0], inputShape[1]
|
||
for i := 0; i < rows; i++ {
|
||
for j := 0; j < cols; j++ {
|
||
val, _ := t.Data.Get(i, j)
|
||
if val > 0 {
|
||
gradData[gradIdx] = 1
|
||
} else {
|
||
gradData[gradIdx] = 0
|
||
}
|
||
gradIdx++
|
||
}
|
||
}
|
||
} else if len(inputShape) == 4 {
|
||
batch, ch, h, w := inputShape[0], inputShape[1], inputShape[2], inputShape[3]
|
||
for b := 0; b < batch; b++ {
|
||
for c := 0; c < ch; c++ {
|
||
for h_idx := 0; h_idx < h; h_idx++ {
|
||
for w_idx := 0; w_idx < w; w_idx++ {
|
||
val, _ := t.Data.Get(b, c, h_idx, w_idx)
|
||
if val > 0 {
|
||
gradData[gradIdx] = 1
|
||
} else {
|
||
gradData[gradIdx] = 0
|
||
}
|
||
gradIdx++
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
gradMatrix, _ := gomatrix.NewMatrix(gradData, inputShape)
|
||
|
||
// 与输出梯度相乘
|
||
gradWithOutput, _ := gradMatrix.Multiply(output.Grad)
|
||
grad, _ := t.Grad.Add(gradWithOutput)
|
||
t.Grad = grad
|
||
}
|
||
}
|
||
|
||
return output
|
||
}
|
||
|
||
// sigmoid 计算sigmoid函数值
|
||
func sigmoid(x float64) float64 {
|
||
if x > 0 {
|
||
z := math.Exp(-x)
|
||
return 1 / (1 + z)
|
||
} else {
|
||
z := math.Exp(x)
|
||
return z / (1 + z)
|
||
}
|
||
}
|
||
|
||
// Backward 执行反向传播
|
||
func (t *Tensor) Backward() {
|
||
if t.backwardFunc != nil {
|
||
t.backwardFunc()
|
||
}
|
||
} |