gotensor/tensor.go

533 lines
11 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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()
}
}