Go语言实现深度学习的正向传播和反向传播

文章目录

  • 开发前言
  • 开发理论
  • 图解理论
  • 数据类型
  • 数学函数
  • 数据节点统一抽象
  • 变量数据节点
  • 常量数据节点
  • 单目运算封装
  • 双目运算封装
  • 算子节点统一抽象
  • 基础算子
  • 加法算子
  • 减法算子
  • 乘法算子
  • 除法算子
  • 指数算子
  • 对数算子
  • 正切算子
  • 正弦算子
  • 余弦算子
  • 数据流图
  • 正向传播
  • 反向传播
  • 正向训练
  • 反向训练
  • 运行示例
  • 开发总结

开发前言

正向传播是指从神经网络的输入层开始,通过逐层计算和传递,将输入数据一直传递到输出层。在每一层中,通过对输入数据进行加权求和并应用激活函数,得到该层的输出。这个过程可以看作是将输入数据在网络中前进(向前传播),直至得到模型的预测结果。

反向传播是指根据模型的预测结果和实际标签之间的差异,从输出层向输入层反向计算梯度,并利用梯度来更新网络参数。

这篇博客我将使用Go语言实现正向传播和反向传播,帮助你理解其底层的运转规律

项目代码使用纯粹的Go语言标准库实现,不借用任何其它第三方库。用轮子是生活,造轮子是信仰。

我是醉墨居士,我们现在开始吧🤗

开发理论

一个数学函数,由一系列数据和一系列运算方式构成,我们将数据对应为数据节点,将运算方式对应为算子节点,这样我们就可以将数学函数转化为由一系列数据节点和一系列算子节点组成的数据流图

正向传递数据流图,不断运算数据,就是正向传播的过程
反向传递数据流图,不断累加梯度,就是反向传播的过程

图解理论

我画了两张图来表示函数3 * pow(x, 2) + 2 * x + 1的正向传播和反向传播的过程

正向传播图解
forward

反向传播图解
backward

数据类型

data/type.go

package datatype Type interface {~int | ~int32 | ~int64 |~uint | ~uint32 | ~uint64 |~float32 | ~float64
}

数学函数

math/math.go

package mathimport ("dl/node"stmath "math"
)func Pow[T node.Type](a, b T) T {return T(stmath.Pow(float64(a), float64(b)))
}func Ln[T node.Type](a T) T {return T(stmath.Log(float64(a)))
}func Tan[T node.Type](a T) T {return T(stmath.Tan(float64(a)))
}func Sin[T node.Type](a T) T {return T(stmath.Sin(float64(a)))
}func Cos[T node.Type](a T) T {return T(stmath.Cos(float64(a)))
}

数据节点统一抽象

fm/datanode.go

type DataNode[T data.Type] interface {Data()TSetData(T)Grad()TsetGrad(T)preNode() CalNode[T]backNodes() *[]CalNode[T]fm()FlowMap[T]Add(DataNode[T]) DataNode[T]Sub(DataNode[T]) DataNode[T]Mul(DataNode[T]) DataNode[T]Div(DataNode[T]) DataNode[T]Pow(DataNode[T]) DataNode[T]Ln() DataNode[T]Tan() DataNode[T]Sin() DataNode[T]Cos() DataNode[T]
}

变量数据节点

package fmimport "dl/data"type varDataNode[T data.Type] struct {data Tgrad Tprenode CalNode[T]backnodes []CalNode[T]flowmap FlowMap[T]
}func (n *varDataNode[T]) Data() T {return n.data
}func (n *varDataNode[T]) SetData(i T) {n.data = i
}func (n *varDataNode[T]) Grad() T {return n.grad
}func (n *varDataNode[T]) setGrad(i T) {n.grad = i
}func (n *varDataNode[T]) preNode() CalNode[T] {return n.prenode
}func (n *varDataNode[T]) backNodes() *[]CalNode[T] {return &n.backnodes
}func (n *varDataNode[T]) fm() FlowMap[T] {return n.flowmap
}func (n *varDataNode[T]) Add(node DataNode[T]) DataNode[T] {return calTwo(newAdd[T](), n, node)
}func (n *varDataNode[T]) Sub(node DataNode[T]) DataNode[T] {return calTwo(newSub[T](), n, node)
}func (n *varDataNode[T]) Mul(node DataNode[T]) DataNode[T] {return calTwo(newMul[T](), n, node)
}func (n *varDataNode[T]) Div(node DataNode[T]) DataNode[T] {return calTwo(newDiv[T](), n, node)
}func (n *varDataNode[T]) Pow(node DataNode[T]) DataNode[T] {return calTwo(newPow[T](), n, node)
}func (n *varDataNode[T]) Ln() DataNode[T] {return calOne(newLn[T](), n)
}func (n *varDataNode[T]) Tan() DataNode[T] {return calOne(newTan[T](), n)
}func (n *varDataNode[T]) Sin() DataNode[T] {return calOne(newSin[T](), n)
}func (n *varDataNode[T]) Cos() DataNode[T] {return calOne(newCos[T](), n)
}

常量数据节点

type constDataNode[T data.Type] struct {data      Tprenode   CalNode[T]backnodes []CalNode[T]flowmap   FlowMap[T]
}func (n *constDataNode[T]) Data() T {return n.data
}func (n *constDataNode[T]) SetData(i T) {n.data = i
}
func (n *constDataNode[T]) Grad() T {return 0
}func (n *constDataNode[T]) setGrad(T) {}func (n *constDataNode[T]) preNode() CalNode[T] {return n.prenode
}func (n *constDataNode[T]) backNodes() *[]CalNode[T] {return &n.backnodes
}func (n *constDataNode[T]) fm() FlowMap[T] {return n.flowmap
}func (n *constDataNode[T]) Add(node DataNode[T]) DataNode[T] {return calTwo(newAdd[T](), n, node)
}func (n *constDataNode[T]) Sub(node DataNode[T]) DataNode[T] {return calTwo(newSub[T](), n, node)
}func (n *constDataNode[T]) Mul(node DataNode[T]) DataNode[T] {return calTwo(newMul[T](), n, node)
}func (n *constDataNode[T]) Div(node DataNode[T]) DataNode[T] {return calTwo(newDiv[T](), n, node)
}func (n *constDataNode[T]) Pow(node DataNode[T]) DataNode[T] {return calTwo(newPow[T](), n, node)
}func (n *constDataNode[T]) Ln() DataNode[T] {return calOne(newLn[T](), n)
}func (n *constDataNode[T]) Tan() DataNode[T] {return calOne(newTan[T](), n)
}func (n *constDataNode[T]) Sin() DataNode[T] {return calOne(newSin[T](), n)
}func (n *constDataNode[T]) Cos() DataNode[T] {return calOne(newCos[T](), n)
}

单目运算封装

func calOne[T data.Type](operation CalNode[T], a DataNode[T]) DataNode[T] {*a.fm().calnodes = append(*a.fm().calnodes, operation)*a.backNodes() = append(*a.backNodes(), operation)res := &varDataNode[T]{prenode: operation,flowmap: a.fm(),}*a.fm().datanodes = append(*a.fm().datanodes, res)operation.CalNode().PreNodes = []DataNode[T]{a}operation.CalNode().BackNode = resreturn res
}

双目运算封装

func calTwo[T data.Type] (operation CalNode[T], a, b DataNode[T]) DataNode[T] {if a.fm() != b.fm() {return nil}*a.fm().calnodes = append(*a.fm().calnodes, operation)*a.backNodes() = append(*a.backNodes(), operation)*b.backNodes() = append(*b.backNodes(), operation)res := &varDataNode[T]{prenode: operation,flowmap: a.fm(),}*a.fm().datanodes = append(*a.fm().datanodes, res)operation.CalNode().PreNodes = []DataNode[T]{a, b}operation.CalNode().BackNode = resreturn res
}

算子节点统一抽象

fm/calnode.go

type CalNode[T data.Type] interface {CalNode() *BaseCalNode[T]Forward()Backward()
}

基础算子

type BaseCalNode[T data.Type] struct {PreNodes []DataNode[T]BackNode DataNode[T]
}

加法算子

type AddNode[T data.Type] BaseCalNode[T]func newAdd[T data.Type]() CalNode[T] {basenode := &BaseCalNode[T]{}return (*AddNode[T])(basenode)
}func (n *AddNode[T]) CalNode() *BaseCalNode[T] {return (*BaseCalNode[T])(n)
}func (n *AddNode[T]) Forward() {n.BackNode.SetData(n.CalNode().PreNodes[0].Data() + n.CalNode().PreNodes[1].Data())
}func (n *AddNode[T]) Backward() {// selfgrad + backgradgrad0 := n.PreNodes[0].Grad() + n.BackNode.Grad()// selfgrad + backgradgrad1 := n.PreNodes[1].Grad() + n.BackNode.Grad()n.PreNodes[0].setGrad(grad0)n.PreNodes[1].setGrad(grad1)
}

减法算子

type SubNode[T data.Type] BaseCalNode[T]func newSub[T data.Type]() CalNode[T] {basenode := &BaseCalNode[T]{}return (*SubNode[T])(basenode)
}func (n *SubNode[T]) CalNode() *BaseCalNode[T] {return (*BaseCalNode[T])(n)
}func (n *SubNode[T]) Forward() {n.BackNode.SetData(n.CalNode().PreNodes[0].Data() - n.CalNode().PreNodes[1].Data())
}func (n *SubNode[T]) Backward() {// selfgrad + backgradgrad0 := n.PreNodes[0].Grad() + n.BackNode.Grad()// selfgrad - backgradgrad1 := n.PreNodes[1].Grad() - n.BackNode.Grad()n.PreNodes[0].setGrad(grad0)n.PreNodes[1].setGrad(grad1)
}

乘法算子

type MulNode[T data.Type] BaseCalNode[T]func newMul[T data.Type]() CalNode[T] {basenode := &BaseCalNode[T]{}return (*MulNode[T])(basenode)
}func (n *MulNode[T]) CalNode() *BaseCalNode[T] {return (*BaseCalNode[T])(n)
}func (n *MulNode[T]) Forward() {n.BackNode.SetData(n.CalNode().PreNodes[0].Data() * n.CalNode().PreNodes[1].Data())
}func (n *MulNode[T]) Backward() {a := n.PreNodes[0].Data()b := n.PreNodes[1].Data()backgrad := n.BackNode.Grad()// selfgrad + (backgrad * b)grad0 := n.PreNodes[0].Grad() + (backgrad * b)// selfgrad + (backgrad * a)grad1 := n.PreNodes[1].Grad() + (backgrad * a)n.PreNodes[0].setGrad(grad0)n.PreNodes[1].setGrad(grad1)
}

除法算子

type DivNode[T data.Type] BaseCalNode[T]func newDiv[T data.Type]() CalNode[T] {basenode := &BaseCalNode[T]{}return (*DivNode[T])(basenode)
}func (n *DivNode[T]) CalNode() *BaseCalNode[T] {return (*BaseCalNode[T])(n)
}func (n *DivNode[T]) Forward() {n.BackNode.SetData(n.CalNode().PreNodes[0].Data() / n.CalNode().PreNodes[1].Data())
}func (n *DivNode[T]) Backward() {a := n.PreNodes[0].Data()b := n.PreNodes[1].Data()backgrad := n.BackNode.Grad()// selfgrad + (backgrad / b)grad0 := n.PreNodes[0].Grad() + (backgrad / b)// selfgrad - (backgrad * a / pow(b, 2))grad1 := n.PreNodes[1].Grad() - (backgrad * a / math.Pow(b, 2))n.PreNodes[0].setGrad(grad0)n.PreNodes[1].setGrad(grad1)
}

指数算子

type PowNode[T data.Type] BaseCalNode[T]func newPow[T data.Type]() CalNode[T] {basenode := &BaseCalNode[T]{}return (*PowNode[T])(basenode)
}func (n *PowNode[T]) CalNode() *BaseCalNode[T] {return (*BaseCalNode[T])(n)
}func (n *PowNode[T]) Forward() {n.BackNode.SetData(math.Pow(n.CalNode().PreNodes[0].Data(), n.CalNode().PreNodes[1].Data()))
}func (n *PowNode[T]) Backward() {a := n.PreNodes[0].Data()b := n.PreNodes[1].Data()backgrad := n.BackNode.Grad()// selfgrad + (backgrad * b * pow(a, b-1))grad0 := n.PreNodes[0].Grad() + (backgrad * b * math.Pow(a, b-1))// selfgrad + (backgrad * pow(a, b) * ln(a))grad1 := n.PreNodes[1].Grad() + (backgrad * math.Pow(a, b) * math.Ln(a))n.PreNodes[0].setGrad(grad0)n.PreNodes[1].setGrad(grad1)
}

对数算子

type LnNode[T data.Type] BaseCalNode[T]func newLn[T data.Type]() CalNode[T] {basenode := &BaseCalNode[T]{}return (*LnNode[T])(basenode)
}func (n *LnNode[T]) CalNode() *BaseCalNode[T] {return (*BaseCalNode[T])(n)
}func (n *LnNode[T]) Forward() {n.BackNode.SetData(math.Ln(n.CalNode().PreNodes[0].Data()))
}func (n *LnNode[T]) Backward() {a := n.PreNodes[0].Data()backgrad := n.BackNode.Grad()// selfgrad + (backgrad / a)grad0 := n.PreNodes[0].Grad() + (backgrad / a)n.PreNodes[0].setGrad(grad0)
}

正切算子

type TanNode[T data.Type] BaseCalNode[T]func newTan[T data.Type]() CalNode[T] {basenode := &BaseCalNode[T]{}return (*TanNode[T])(basenode)
}func (n *TanNode[T]) CalNode() *BaseCalNode[T] {return (*BaseCalNode[T])(n)
}func (n *TanNode[T]) Forward() {n.BackNode.SetData(math.Tan(n.CalNode().PreNodes[0].Data()))
}func (n *TanNode[T]) Backward() {a := n.PreNodes[0].Data()backgrad := n.BackNode.Grad()// selfgrad + (backgrad / pow(cos(a), 2))grad0 := n.PreNodes[0].Grad() + (backgrad / math.Pow(math.Cos(a), 2))n.PreNodes[0].setGrad(grad0)
}

正弦算子

type SinNode[T data.Type] BaseCalNode[T]func newSin[T data.Type]() CalNode[T] {basenode := &BaseCalNode[T]{}return (*SinNode[T])(basenode)
}func (n *SinNode[T]) CalNode() *BaseCalNode[T] {return (*BaseCalNode[T])(n)
}func (n *SinNode[T]) Forward() {n.BackNode.SetData(math.Sin(n.CalNode().PreNodes[0].Data()))
}func (n *SinNode[T]) Backward() {a := n.PreNodes[0].Data()backgrad := n.BackNode.Grad()// selfgrad + (backgrad * cos(a))grad0 := n.PreNodes[0].Grad() + (backgrad * math.Cos(a))n.PreNodes[0].setGrad(grad0)
}

余弦算子

type CosNode[T data.Type] BaseCalNode[T]func newCos[T data.Type]() CalNode[T] {basenode := &BaseCalNode[T]{}return (*CosNode[T])(basenode)
}func (n *CosNode[T]) CalNode() *BaseCalNode[T] {return (*BaseCalNode[T])(n)
}func (n *CosNode[T]) Forward() {n.BackNode.SetData(math.Cos(n.CalNode().PreNodes[0].Data()))
}func (n *CosNode[T]) Backward() {a := n.PreNodes[0].Data()backgrad := n.BackNode.Grad()// selfgrad - (backgrad * sin(a))grad0 := n.PreNodes[0].Grad() - (backgrad * math.Sin(a))n.PreNodes[0].setGrad(grad0)
}

数据流图

fm/flowmap.go

type FlowMap[T data.Type] struct {calnodes  *[]CalNode[T]datanodes *[]DataNode[T]
}func NewFlowMap[T data.Type]() *FlowMap[T] {calnodes := make([]CalNode[T], 0)datanods := make([]DataNode[T], 0)return &FlowMap[T]{calnodes:  &calnodes,datanodes: &datanods,}
}func (m FlowMap[T]) NewData() DataNode[T] {node := &varDataNode[T]{backnodes: make([]CalNode[T], 0),flowmap:   m,}*m.datanodes = append(*m.datanodes, node)return node
}func (m FlowMap[T]) NewConstData(i T) DataNode[T] {return &constDataNode[T]{backnodes: make([]CalNode[T], 0),data:      i,flowmap:   m,}
}

正向传播

func (m FlowMap[T]) Forward() {n := len(*m.calnodes)for i := 0; i < n; i++ {(*m.calnodes)[i].Forward()}
}

反向传播

func (m FlowMap[T]) Backward() {for i := len(*m.datanodes) - 1; i >= 0; i-- {(*m.datanodes)[i].setGrad(0)}n := len(*m.calnodes)-1(*m.calnodes)[n].CalNode().BackNode.setGrad(1)for i := n; i >= 0; i-- {(*m.calnodes)[i].Backward()}
}

正向训练

func (m FlowMap[T]) ForwardWalk(step T) {for i := len(*m.datanodes) - 1; i >= 0; i-- {(*m.datanodes)[i].SetData((*m.datanodes)[i].Data() + (*m.datanodes)[i].Grad() * step)}
}

反向训练

func (m FlowMap[T]) BackwardWalk(step T) {for i := len(*m.datanodes) - 1; i >= 0; i-- {(*m.datanodes)[i].SetData((*m.datanodes)[i].Data() - (*m.datanodes)[i].Grad() * step)}
}

运行示例

我们的运行示例使用理论图解的那个例子: 3 * pow(x, 2) + 2 * x + 1

// 3 * pow(x, 2) + 2 * x + 1
func main() {m := fm.NewFlowMap[float64]()x := m.NewData()three := m.NewConstData(3)two := m.NewConstData(2)one := m.NewConstData(1)res := three.Mul(x.Pow(two)).Add(two.Mul(x)).Add(one)x.SetData(2)m.Forward()m.Backward()// data = 3 * pow(2, 2) + 2 * 2 + 1 = 17// grad = 2 + 6 * x = 14fmt.Println("x=2 -> ", "res.data =", res.Data(), ",", "x.grad =", x.Grad())x.SetData(3)m.Forward()m.Backward()// data = 3 * pow(3, 2) + 2 * 3 + 1 = 34// grad = 2 + 6 * x = 20fmt.Println("x=3 -> ", "res.data =", res.Data(), ",", "x.grad =", x.Grad())x.SetData(4)m.Forward()m.Backward()// data = 3 * pow(4, 2) + 2 * 4 + 1 = 57// grad = 2 + 6 * x = 26fmt.Println("x=4 -> ", "res.data =", res.Data(), ",", "x.grad =", x.Grad())
}

运行结果
result

开发总结

恭喜你,我们一起使用Go语言完成了深度学习的正向传播和反向传播,希望这个项目能让你有所收获😊

我的特色就是用最简单的方式帮助你学会最硬核的知识,一起加油吧❤️

我是醉墨居士,之前这个账号改了好几次名称,从此之后这个账号的名称大概率不会再变动😜

如果有什么错误,请你评论区或者私信我指出,让我们一起进步✌️

请你多多关注我,开发这个项目,并且整理总结,花费了很多的精力,博客热度越高,更新速度越快😎

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/207174.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

船舶机电设备振动数据采集监控系统解决方案

船舶运行中&#xff0c;通常需要通过振动数据采集系统对船舶的各个机电设备运行进行监控&#xff0c;有助于在设备故障时快速预警&#xff0c;进行诊断、分析和维护&#xff0c;保证船舶机电设备正常工作&#xff0c;从而确保工作人员及船舶的安全。 船舶各种机电设备会产生大…

【模型量化】神经网络量化基础及代码学习总结

1 量化的介绍 量化是减少神经网络计算时间和能耗的最有效的方法之一。在神经网络量化中&#xff0c;权重和激活张量存储在比训练时通常使用的16-bit或32-bit更低的比特精度。当从32-bit降低到8-bit&#xff0c;存储张量的内存开销减少了4倍&#xff0c;矩阵乘法的计算成本则二…

ALNS算法中随机化重要性的评价

文章概述 本研究分析了在海上提货和交付问题中使用的ALNS元启发式算法中的随机化成分。研究者提出了简单的确定性替代方案&#xff0c;并通过实验比较了随机化和确定性成分的性能。结果表明&#xff0c;初始实现的简单确定性替代方案能够与随机化成分的性能相匹配。这项研究为…

IDEA使用git从远程仓库获取项目

将地址填入url中 然后直接clone就行

《Easy3d+Qt+VTK》学习

《Easy3dQtVTK》学习-1、编译与配置 一、编译二、配置注 一、编译 1、 资源下载&#xff1a;easy3d giuhub 2、解压缩 3、用qt打开CMakeLists.txt即可 4、点击项目&#xff0c;选择debug或者release&#xff0c;图中3处可自行选择&#xff0c;因为我的qt版本是6&#xff0c…

在linux上如何运用虚拟数据优化器VDO

本章主要介绍虚拟化数据优化器。 什么是虚拟数据优化器VDO 创建VDO设备以节约硬盘空间 16.1 了解什么是VDO VDO全称是Virtual Data Optimize&#xff08;虚拟数据优化)&#xff0c;主要是为了节省硬盘空间。 现在假设有两个文件file1和 file2&#xff0c;大小都是10G。file…

cpu 300% 爆满 内存占用不高 排查

top查询 cpu最高的PID ps -ef | grep PID 查看具体哪一个jar服务 jstack -l PID > ./jstack.log 下载/打印进程的线程栈信息 可以加信息简单分析 或进一步 查看堆内存使用情况 jmap -heap Java进程id jstack.log 信息示例 Full thread dump Java HotSpot(TM) 64-Bit Se…

横向扩展统一存储与备份服务器功能

Infortrend 更新了GS&#xff0c;GSe&#xff0c;GSe Pro统一存储系列的备份服务器功能。该功能降低数据备份成本&#xff0c;并提供灵活的备份策略。通过备份服务器功能&#xff0c;用户可以通过多种途径实现数据备份&#xff0c;包括公有云&#xff08;兼容S3&#xff09;、文…

C/C++,树算法——二叉树的插入(Insert)算法之源程序

1 文本格式 #include<iostream> using namespace std; // A BTree node class BTreeNode { int* keys; // An array of keys int t; // Minimum degree (defines the range for number of keys) BTreeNode** C; // An array of child pointers int …

dell服务器重启后显示器黑屏

1.硬件层面&#xff1a;观察主机的指示灯 &#xff08;1&#xff09;指示灯偏黄&#xff0c;硬件存在问题&#xff08;内存条有静电&#xff0c;拔出后用橡皮擦擦拭&#xff1b;或GPU松动&#xff09; a.电源指示灯黄&#xff0c;闪烁三下再闪烁一下&#xff0c;扣下主板上的纽…

Python Appium Selenium 查杀进程的实用方法

一、前置说明 在自动化过程中&#xff0c;经常需要在命令行中执行一些操作&#xff0c;比如启动应用、查杀应用等&#xff0c;因此可以封装成一个CommandExecutor来专门处理这些事情。 二、操作步骤 # cmd_util.pyimport logging import os import platform import shutil i…

Java编程中通用的正则表达式(二)

正则表达式&#xff0c;又称正则式、规则表达式、正规表达式、正则模式或简称正则&#xff0c;是一种用来匹配字符串的工具。它是一种字符串模式的表示方法&#xff0c;可以用来检索、替换和验证文本。正则表达式是一个字符串&#xff0c;它描述了一些字符的组合&#xff0c;这…

dockers安装rabbitmq

RabbitMQ: easy to use, flexible messaging and streaming — RabbitMQhttps://www.rabbitmq.com/ Downloading and Installing RabbitMQ — RabbitMQ docker run -it --rm --name rabbitmq -p 5672:5672 -p 15672:15672 rabbitmq:3.12-management 之后参照&#xff1a;dock…

高低压配电智能监控系统

高低压配电智能监控系统是一种综合运用物联网、云计算、大数据和人工智能等技术的智能化监控系统&#xff0c;主要用于对高低压配电设备进行实时监测、数据采集、故障预警和远程管理。 该系统通过安装智能传感器、智能设备、网络通讯技术等手段&#xff0c;依托电易云-智慧电力…

解决“由于找不到msvcr110.dll无法继续执行”的错误问题,一键修复msvcr110.dll丢失

当你遇到“由于找不到msvcr110.dll无法继续执行”的错误时&#xff0c;通常是因为你的电脑缺少相关的msvcr110.dll文件。如果你的电脑中缺失了msvcr110.dll文件丢失那么可以根据下面的方法尝试解决msvcr110.dll丢失的问题。 一.解决msvcr110.dll丢失的方法 使用dll修复工具 D…

学习笔记9——JUC三种量级的锁机制

学习笔记系列开头惯例发布一些寻亲消息 链接&#xff1a;https://baobeihuijia.com/bbhj/contents/3/197325.html 多线程访问共享资源冲突 临界区&#xff1a;一段代码块存在对共享资源的多线程读写操作&#xff0c;称这段代码块为临界区 竞态条件&#xff1a;多个线程在临界…

yolo目标检测+目标跟踪+车辆计数+车辆分割+车道线变更检测+速度估计

这个项目使用YOLO进行车辆检测&#xff0c;使用SORT&#xff08;简单在线实时跟踪器&#xff09;进行车辆跟踪。该项目实现了以下任务&#xff1a; 车辆计数车道分割车道变更检测速度估计将所有这些详细信息转储到CSV文件中 车辆计数是指在道路上安装相应设备&#xff0c;通过…

windows下 Tomcat启动黑框隐藏

进入到 tomcat/bin 目录下&#xff0c;找到此文件 setclasspath.bat &#xff0c;右键文本打开 找到此属性 &#xff1a; set _RUNJAVA"%JRE_HOME%\bin\java.exe"修改成以下属性&#xff0c;保存文件&#xff0c;重启启动tomcat会发现黑框不默认弹出了&#xff1a; …

使用hutool工具生成非对称加密公私密钥以及使用案例

1.导入hutool依赖 <dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.8.18</version></dependency>2.直接复制代码 package com.common.utils;import cn.hutool.core.codec.Base64; i…

仅需30秒完美复刻任何人的声音 - 最强AI音频11Labs

我的用词一直都挺克制的&#xff0c;基本不会用到“最强”这个字眼。 但是这一次的这个AI应用&#xff0c;是我认为在TTS&#xff08;文字转音频&#xff09;这个领域&#xff0c;当之无愧的“最强”。 ElevenLabs&#xff0c;简称11Labs。 仅需30秒到5分钟左右的极少的数据集…