Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >golang源码分析之:go-mitmproxy

golang源码分析之:go-mitmproxy

作者头像
golangLeetcode
发布于 2024-07-06 00:21:32
发布于 2024-07-06 00:21:32
41100
代码可运行
举报
运行总次数:0
代码可运行

日常开发中,我们除了使用charles、finder抓包外,也可以使用mitmproxy抓包,并且它还提供二次开发能力。在学习mitmproxy之前,我们先学习下他的go版本的精简实现github.com/lqqyt2423/go-mitmproxy/cmd/go-mitmproxy

目前只支持http代理和https代理,不支持websocket和透明代理,这是比mitmproxy弱的地方,它提供了11个hook点,我们可以根据需求,通过addon的方式来定义和添加自己的hook点实现自定义抓包,它的11个hook点定义如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
type Addon interface {
  // 一个客户端已经连接到了mitmproxy。请注意,一个连接可能对应多个HTTP请求。
  ClientConnected(*ClientConn)

  // 一个客户端连接已关闭(由我们或客户端关闭)。
  ClientDisconnected(*ClientConn)

  // mitmproxy 已连接到服务器。
  ServerConnected(*ConnContext)

  // 服务器连接已关闭(由我们或服务器关闭)。
  ServerDisconnected(*ConnContext)

  // 与服务器的TLS握手已成功完成。
  TlsEstablishedServer(*ConnContext)

  // HTTP请求头已成功读取。此时,请求体为空。
  Requestheaders(*Flow)

  // 完整的HTTP请求已被读取。
  Request(*Flow)

  // HTTP响应头已成功读取。此时,响应体为空。
  Responseheaders(*Flow)

  // 完整的HTTP响应已被读取。
  Response(*Flow)

  // 流式请求体修改器
  StreamRequestModifier(*Flow, io.Reader) io.Reader

  // 流式响应体修改器
  StreamResponseModifier(*Flow, io.Reader) io.Reader
}

下面我们开始分析下它的源码,入口函数位于cmd/go-mitmproxy/main.go,里面定义了Config结构体,每一个field代表了一个抓包工具的可选项:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
type Config struct {
version bool // show go-mitmproxy version


Addr         string   // proxy listen addr
WebAddr      string   // web interface listen addr
SslInsecure  bool     // not verify upstream server SSL/TLS certificates.
IgnoreHosts  []string // a list of ignore hosts
AllowHosts   []string // a list of allow hosts
CertPath     string   // path of generate cert files
Debug        int      // debug mode: 1 - print debug log, 2 - show debug from
Dump         string   // dump filename
DumpLevel    int      // dump level: 0 - header, 1 - header + body
Upstream     string   // upstream proxy
UpstreamCert bool     // Connect to upstream server to look up certificate details. Default: True
MapRemote    string   // map remote config filename
MapLocal     string   // map local config filename


filename string // read config from the filename
}

它的main函数里核心包括了下面四步:

1,初始化proxy

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
p, err := proxy.NewProxy(opts)

代理结构体的定义位于proxy/proxy.go

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
type Proxy struct {
Opts    *Options
Version string
Addons  []Addon


entry           *entry
attacker        *attacker
shouldIntercept func(req *http.Request) bool              // req is received by proxy.server
upstreamProxy   func(req *http.Request) (*url.URL, error) // req is received by proxy.server, not client request
}

初始化proxy的时候,会设置对应的entry和attacker

2,设置本地和远程拦截策略,也就是根据规则匹配对应的host,并做出是否代理的决策

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
p.SetShouldInterceptRule(func(req *http.Request) bool {
return !helper.MatchHost(req.Host, config.IgnoreHosts)
})
p.SetShouldInterceptRule(func(req *http.Request) bool {
return helper.MatchHost(req.Host, config.AllowHosts)
})

在proxy上绑定这个拦截规则

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func (proxy *Proxy) SetShouldInterceptRule(rule func(req *http.Request) bool) {
proxy.shouldIntercept = rule
}

mapremote和maplocal的具体实现如下:

addon/mapremote.go

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
if err := helper.NewStructFromFile(filename, &mapRemote); err != nil {
if err := mapRemote.validate(); err != nil {
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
type MapRemote struct {
proxy.BaseAddon
Items  []*mapRemoteItem
Enable bool
}

addon/maplocal.go

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
if err := helper.NewStructFromFile(filename, &mapLocal); err != nil {
if err := mapLocal.validate(); err != nil {
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
type MapLocal struct {
proxy.BaseAddon
Items  []*mapLocalItem
Enable bool
}

3,添加hook点,也就是addon

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
p.AddAddon(proxy.NewUpstreamCertAddon(false))
p.AddAddon(&proxy.LogAddon{})
p.AddAddon(web.NewWebAddon(config.WebAddr))
mapRemote, err := addon.NewMapRemoteFromFile(config.MapRemote)
p.AddAddon(mapRemote)
mapLocal, err := addon.NewMapLocalFromFile(config.MapLocal)
p.AddAddon(mapLocal)
dumper := addon.NewDumperWithFilename(config.Dump, config.DumpLevel)
p.AddAddon(dumper)

添加hook点就是把拦截点append到数组里就行了

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func (proxy *Proxy) AddAddon(addon Addon) {

proxy.Addons = append(proxy.Addons, addon)

}

proxy/addon.go中对hook点进行了约定,也就是说用户可以在这11个hook点上随意定义hook插件

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
type Addon interface {
// A client has connected to mitmproxy. Note that a connection can correspond to multiple HTTP requests.
ClientConnected(*ClientConn)


// A client connection has been closed (either by us or the client).
ClientDisconnected(*ClientConn)


// Mitmproxy has connected to a server.
ServerConnected(*ConnContext)


// A server connection has been closed (either by us or the server).
ServerDisconnected(*ConnContext)


// The TLS handshake with the server has been completed successfully.
TlsEstablishedServer(*ConnContext)


// HTTP request headers were successfully read. At this point, the body is empty.
Requestheaders(*Flow)


// The full HTTP request has been read.
Request(*Flow)


// HTTP response headers were successfully read. At this point, the body is empty.
Responseheaders(*Flow)


// The full HTTP response has been read.
Response(*Flow)


// Stream request body modifier
StreamRequestModifier(*Flow, io.Reader) io.Reader


// Stream response body modifier
StreamResponseModifier(*Flow, io.Reader) io.Reader


// onAccessProxyServer
AccessProxyServer(req *http.Request, res http.ResponseWriter)
}

同时也定义了一个基础插件和两个最常用的插件实现

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
type BaseAddon struct{}
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
type LogAddon struct {
BaseAddon
}
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
type UpstreamCertAddon struct {
BaseAddon
UpstreamCert bool // Connect to upstream server to look up certificate details.
}
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func NewUpstreamCertAddon(upstreamCert bool) *UpstreamCertAddon {
return &UpstreamCertAddon{UpstreamCert: upstreamCert}
}

一些其他的addon定义如下:

web/web.go里定义了webAddOn

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
type WebAddon struct {
proxy.BaseAddon


server   *http.Server
upgrader *websocket.Upgrader


conns   []*concurrentConn
connsMu sync.RWMutex


flowMessageState map[*proxy.Flow]messageType
flowMu           sync.Mutex
}

实现了一个简单的httpserver,通过websocket将抓包结果发送到web前端,我们可以通过网页查看抓包结果

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
web := &WebAddon{
flowMessageState: make(map[*proxy.Flow]messageType),
}
web.upgrader = &websocket.Upgrader{
serverMux := new(http.ServeMux)
serverMux.HandleFunc("/echo", web.echo)


fsys, err := fs.Sub(assets, "client/build")
serverMux.Handle("/", http.FileServer(http.FS(fsys)))


web.server = &http.Server{Addr: addr, Handler: serverMux}
web.conns = make([]*concurrentConn, 0)
err := web.server.ListenAndServe()

addon/dumper.go 定义了Dumper将抓包结果保存到文件里

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
out, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666)
return NewDumper(out, level)
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
type Dumper struct {
proxy.BaseAddon
out   io.Writer
level int // 0: header 1: header + body
}

4,启动代理

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
log.Fatal(p.Start())

启动proxy的时候分别会启动两个协程,一个是entry,一个是attacker

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func (proxy *Proxy) Start() error {
  go func() {
  if err := proxy.attacker.start(); err != nil {
  return proxy.entry.start()

4.1首先看下entry协程

它的定义位于 proxy/entry.go,它代表了代理server,本质上就是一个http/https服务器

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
type entry struct {
proxy  *Proxy
server *http.Server
}
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func newEntry(proxy *Proxy) *entry {
e := &entry{proxy: proxy}
e.server = &http.Server{
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func (e *entry) start() error {
ln, err := net.Listen("tcp", addr)
pln := &wrapListener{
Listener: ln,
proxy:    e.proxy,
}
return e.server.Serve(pln)

重点看下ServeHTTP函数,每当有拦截到来的时候先处理hook,然后初始化attacker的连接,并调用对应的attack方法

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func (e *entry) ServeHTTP(res http.ResponseWriter, req *http.Request) {
if req.Method == "CONNECT" {
e.handleConnect(res, req)
// trigger addon event Responseheaders
for _, addon := range e.proxy.Addons {
addon.Responseheaders(f)
}
for _, addon := range proxy.Addons {
addon.AccessProxyServer(req, res)
}
proxy.attacker.initHttpDialFn(req)
proxy.attacker.attack(res, req)

处理连接的时候,会进行请求的拷贝,也就是entry收到的请求到accacker的请求,以及attacker响应到entry的响应

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func (e *entry) handleConnect(res http.ResponseWriter, req *http.Request) {
e.directTransfer(res, req, f)
e.httpsDialFirstAttack(res, req, f)
e.httpsDialLazyAttack(res, req, f)

具体拷贝方法定义位于

proxy/helper.go

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func transfer(log *log.Entry, server, client io.ReadWriteCloser) {
go func() {
_, err := io.Copy(server, client)
go func() {
_, err := io.Copy(client, server)

拷贝完请求之后就需要向真是上游发起请求

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func (e *entry) httpsDialLazyAttack(res http.ResponseWriter, req *http.Request, f *Flow) {
  cconn, err := e.establishConnection(res, f)
  peek, err := cconn.(*wrapClientConn).Peek(3)
  conn, err := proxy.attacker.httpsDial(req.Context(), req)
  transfer(log, conn, cconn)
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func (e *entry) httpsDialFirstAttack(res http.ResponseWriter, req *http.Request, f *Flow) {
conn, err := proxy.attacker.httpsDial(req.Context(), req)
cconn, err := e.establishConnection(res, f)
peek, err := cconn.(*wrapClientConn).Peek(3)
if !helper.IsTls(peek) {
// todo: http, ws
transfer(log, conn, cconn)
// is tls
f.ConnContext.ClientConn.Tls = true
proxy.attacker.httpsTlsDial(req.Context(), cconn, conn)

每一次代理请求被定义为一个flow,其代码实现位于:proxy/flow.go

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func newFlow() *Flow {
return &Flow{Id:   uuid.NewV4(),
done: make(chan struct{}),}
}

4.2 接下来看下attacker的协程

其代码位于proxy/attacker.go ,创建attacker的时候需要创建一个ca也就是一个自签名的证书,方便被代理的服务使用(代理https时候)

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
ca, err := newCa(proxy.Opts)
a := &attacker{
proxy: proxy,
ca:    ca,
client: &http.Client{
Transport: &http.Transport
a.server = &http.Server{
Handler: a,
ConnContext:
a.h2Server = &http2.Server{
MaxConcurrentStreams: 100, // todo: wait for remote server setting
NewWriteScheduler:    func() http2.WriteScheduler { return http2.NewPriorityWriteScheduler(nil) },
}
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func newCa(opts *Options) (cert.CA, error) {
newCaFunc := opts.NewCaFunc
if newCaFunc != nil {
return newCaFunc()
}
return cert.NewSelfSignCA(opts.CaRootPath)
}

在它的start方法里启动了代理服务

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func (a *attacker) start() error {
return a.server.Serve(a.listener)
}

代理连接是在初始化函数里定义的

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func (a *attacker) initHttpDialFn(req *http.Request) {
connCtx.dialFn = func(ctx context.Context) error {
addr := helper.CanonicalAddr(req.URL)
c, err := a.proxy.getUpstreamConn(ctx, req)
if err := a.serverTlsHandshake(ctx, connCtx); err != nil {
serverConn := newServerConn()
serverConn.Conn = cw
serverConn.Address = addr
serverConn.client = &http.Client{
Transport: &http.Transport{
DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
return cw, nil
},

attack方法是代理逻辑的核心

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func (a *attacker) attack(res http.ResponseWriter, req *http.Request) {
reply := func(response *Response, body io.Reader) {
res.Header().Add(key, v)
_, err := io.Copy(res, body)
_, err := io.Copy(res, response.BodyReader)
_, err := res.Write(response.Body)
proxyReq, err := http.NewRequestWithContext(proxyReqCtx, f.Request.Method, f.Request.URL.String(), reqBody)

proxyReq.Header.Add(key, v)
proxyRes, err = a.client.Do(proxyReq)
if err := f.ConnContext.dialFn(req.Context()); err != nil {
proxyRes, err = f.ConnContext.ServerConn.client.Do(proxyReq)
reply(f.Response, resBody)

对于https代理,需要发起tls连接

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func (a *attacker) httpsTlsDial(ctx context.Context, cconn net.Conn, conn net.Conn) {
clientTlsConn := tls.Server(cconn, &tls.Config{
SessionTicketsDisabled: true, // 设置此值为 true ,确保每次都会调用下面的 GetConfigForClient 方法
GetConfigForClient: func(chi *tls.ClientHelloInfo) (*tls.Config, error) {
c, err := a.ca.GetCert(chi.ServerName)
go func() {
if err := clientTlsConn.HandshakeContext(ctx); err != nil {
if err := a.serverTlsHandshake(ctx, connCtx); err != nil {
// will go to attacker.ServeHTTP
a.serveConn(clientTlsConn, connCtx)
func newCa(opts *Options) (cert.CA, error) {
newCaFunc := opts.NewCaFunc
if newCaFunc != nil {
return newCaFunc()
}
return cert.NewSelfSignCA(opts.CaRootPath)
}
// send clientHello to server, server handshake
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func (a *attacker) serverTlsHandshake(ctx context.Context, connCtx *ConnContext) error {
serverTlsConfig := &tls.Config{
serverTlsConn := tls.Client(serverConn.Conn, serverTlsConfig)
if err := serverTlsConn.HandshakeContext(ctx); err != nil {
serverTlsState := serverTlsConn.ConnectionState()
serverConn.tlsState = &serverTlsState
serverConn.client = &http.Client{
Transport: &http.Transport{

自认证证书逻辑位于cert/self_sign_ca.go,创建证书的逻辑如下

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
storePath, err := getStorePath(path)
ca := &SelfSignCA{
StorePath: storePath,
cache:     lru.New(100),
group:     new(singleflight.Group),
}
if err := ca.load(); err != nil {
key, err := x509.ParsePKCS8PrivateKey(keyDERBlock.Bytes)
x509Cert, err := x509.ParseCertificate(certDERBlock.Bytes)
if err := ca.create(); err != nil {

证书的名字

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func (ca *SelfSignCA) caFile() string {
return filepath.Join(ca.StorePath, "mitmproxy-ca.pem")
}
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func (ca *SelfSignCA) create() error {
key, cert, err := createCert()
key, err := rsa.GenerateKey(rand.Reader, 2048)
template := &x509.Certificate{
certBytes, err := x509.CreateCertificate
cert, err := x509.ParseCertificate
return ca.saveCert()
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2024-06-30,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 golang算法架构leetcode技术php 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
详细解读Spatial Transformer Networks(STN)-一篇文章让你完全理解STN了
普通的CNN能够显示的学习平移不变性,以及隐式的学习旋转不变性,但attention model 告诉我们,与其让网络隐式的学习到某种能力,不如为网络设计一个显式的处理模块,专门处理以上的各种变换。因此,DeepMind就设计了Spatial Transformer Layer,简称STL来完成这样的功能。
全栈程序员站长
2022/11/02
4.3K0
详细解读Spatial Transformer Networks(STN)-一篇文章让你完全理解STN了
车牌检测STN:Spatial Transformer Networks
参考文献:Max Jaderberg, Karen Simonyan, Andrew Zisserman, Koray Kavukcuoglu. Spatial Transformer Networks, 2016.link
全栈程序员站长
2022/11/02
7950
车牌检测STN:Spatial Transformer Networks
Spatial Transformer Networks(STN)详解
  普通的CNN能够显示的学习平移不变性,以及隐式的学习旋转不变性,但attention model 告诉我们,与其让网络隐式的学习到某种能力,不如为网络设计一个显式的处理模块,专门处理以上的各种变换。因此,DeepMind就设计了Spatial Transformer Layer,简称STL来完成这样的功能。
全栈程序员站长
2022/11/07
2.3K0
Spatial Transformer Networks(STN)详解
Spatial Transformer Networks(STN)理解
之前参加过一个点云数据分类的比赛,主要借鉴了PointNet的网络结构,在PointNet中使用到了两次STN。点云数据存在两个主要问题:1、无序性:点云本质上是一长串点(nx3矩阵,其中n是点数)。在几何上,点的顺序不影响它在空间中对整体形状的表示,例如,相同的点云可以由两个完全不同的矩阵表示。2、旋转性:相同的点云在空间中经过一定的刚性变化(旋转或平移),坐标发生变化,我们希望不论点云在怎样的坐标系下呈现,网络都能正确的识别出。
全栈程序员站长
2022/11/02
1.2K0
Spatial Transformer Networks(STN)理解
STN:空间变换网络(Spatial Transformer Network)「建议收藏」
卷积神经网络定义了一个异常强大的模型类,但在计算和参数有效的方式下仍然受限于对输入数据的空间不变性。在此引入了一个新的可学模块,空间变换网络,它显式地允许在网络中对数据进行空间变换操作。这个可微的模块可以插入到现有的卷积架构中,使神经网络能够主动地在空间上转换特征映射,在特征映射本身上有条件,而不需要对优化过程进行额外的训练监督或修改。我们展示了空间变形的使用结果,在模型中学习了平移、缩放、旋转和更一般的扭曲,结果在几个基准上得到了很好的效果。
全栈程序员站长
2022/11/19
1.9K0
STN:空间变换网络(Spatial Transformer Network)「建议收藏」
从STN网络到deformable convolution
论文来源:https://arxiv.org/pdf/1506.02025.pdf
全栈程序员站长
2022/11/02
5890
从STN网络到deformable convolution
【论文学习】STN —— Spatial Transformer Networks
这是Google旗下 DeepMind 大作,最近学习人脸识别,这篇paper提出的STN网络可以代替align的操作,端到端的训练实现图片的align。
全栈程序员站长
2022/09/27
1.1K0
OpenCV两种畸变校正模型源代码分析以及CUDA实现
图像算法中会经常用到摄像机的畸变校正,有必要总结分析OpenCV中畸变校正方法,其中包括普通针孔相机模型和鱼眼相机模型fisheye两种畸变校正方法。 普通相机模型畸变校正函数针对OpenCV中的cv::initUndistortRectifyMap(),鱼眼相机模型畸变校正函数对应OpenCV中的cv::fisheye::initUndistortRectifyMap()。两种方法算出映射Mapx和Mapy后,统一用cv::Remap()函数进行插值得到校正后的图像。 1. FishEye模型的畸变校正。
一棹烟波
2018/01/12
4.4K0
OpenCV两种畸变校正模型源代码分析以及CUDA实现
CAP:多重注意力机制,有趣的细粒度分类方案 | AAAI 2021
论文: Context-aware Attentional Pooling (CAP) for Fine-grained Visual Classification
VincentLee
2022/06/24
1K0
CAP:多重注意力机制,有趣的细粒度分类方案 | AAAI 2021
真正的即插即用!盘点11种CNN网络设计中精巧通用的“小”插件
所谓“插件”,就是要能锦上添花,又容易植入、落地,即真正的即插即用。本文盘点的“插件”能够提升CNN平移、旋转、scale等变性能力或多尺度特征提取,感受野等能力,在很多SOTA网络中都会看到它们的影子。 >>加入极市CV技术交流群,走在计算机视觉的最前沿
AIWalker
2021/01/18
7040
真正的即插即用!盘点11种CNN网络设计中精巧通用的“小”插件
模式识别与机器学习(一)
模式: 为了能够让机器执行和完成识别任务,必须对分类识别对象进行科学的抽象,建立它的数学模型,用以描述和代替识别对象,这种对象的描述即为模式。
范中豪
2019/09/05
1.3K0
模式识别与机器学习(一)
五万字总结,深度学习基础。「建议收藏」
人工神经网络(Artificial Neural Networks,简写为ANNs)是一种模仿动物神经网络行为特征,进行分布式并行信息处理的算法数学模型。这种网络依靠系统的复杂程度,通过调整内部大量节点之间相互连接的关系,从而达到处理信息的目的,并具有自学习和自适应的能力。神经网络类型众多,其中最为重要的是多层感知机。为了详细地描述神经网络,我们先从最简单的神经网络说起。
全栈程序员站长
2022/08/31
1K0
五万字总结,深度学习基础。「建议收藏」
理解Spatial Transformer Networks
随着深度学习的不断发展,卷积神经网络(CNN)作为计算机视觉领域的杀手锏,在几乎所有视觉相关任务中都展现出了超越传统机器学习算法甚至超越人类的能力。一系列CNN-based网络在classification、localization、semantic segmentation、action recognization等任务中都实现了state-of-art的结果。
SIGAI学习与实践平台
2018/08/21
6670
理解Spatial Transformer Networks
计算机视觉方向简介 | 图像拼接
作者戴金艳,公众号:计算机视觉life, 编辑部成员.首发原文链接计算机视觉方向简介 | 图像拼接
用户1150922
2019/08/01
1.5K0
【论文笔记】A Graph-based and Copy-augmented Multi-domain Dialogue State Tracking
​ 大多数现有的方法都在单个领域上独立训练 DST,而忽略了跨领域之间的信息的有效共享。
yhlin
2023/03/23
8720
【论文笔记】A Graph-based and Copy-augmented Multi-domain Dialogue State Tracking
论文阅读01——《图卷积神经网络综述》
由于博主已经本硕博连读,九月份即将开始研究生生涯,遂开启论文阅读这一系列博文,主要介绍一些文章的主要思想和创新点,可能会详细介绍一下模型,如果喜欢的话多多关注,另外其他系列也会不定时更新,记得来看~
Marigold
2022/06/17
1.6K0
论文阅读01——《图卷积神经网络综述》
深度学习系列:卷积神经网络结构变化——可变形卷积网络deformable convolutional
作者 | 大饼博士X 上一篇我们介绍了:深度学习方法(十二):卷积神经网络结构变化——Spatial Transformer Networks,STN创造性地在CNN结构中装入了一个可学习的仿射变换,目的是增加CNN的旋转、平移、缩放、剪裁性。为什么要做这个很奇怪的结构呢?原因还是因为CNN不够鲁棒,比如把一张图片颠倒一下,可能就不认识了(这里mark一下,提高CNN的泛化能力,值得继续花很大力气,STN是一个思路,读者以及我自己应该多想想,还有什么方法?)。 今天介绍的这一篇可变形卷积网络deforma
AI科技大本营
2018/04/28
1.6K0
深度学习系列:卷积神经网络结构变化——可变形卷积网络deformable convolutional
CamoTeacher:玩转半监督伪装物体检测,双一致性动态调整样本权重 | ECCV 2024
论文: CamoTeacher: Dual-Rotation Consistency Learning for Semi-Supervised Camouflaged Object Detection
VincentLee
2024/09/05
1490
CamoTeacher:玩转半监督伪装物体检测,双一致性动态调整样本权重 | ECCV 2024
SPiT:超像素驱动的非规则ViT标记化,实现更真实的图像理解 | ECCV 2024
论文: A Spitting Image: Modular Superpixel Tokenization in Vision Transformers
VincentLee
2024/09/12
1300
SPiT:超像素驱动的非规则ViT标记化,实现更真实的图像理解 | ECCV 2024
tensorflow 层_win7怎么扩展屏幕
读TensorFlow相关代码看到了STN的应用,搜索以后发现可替代池化,增强网络对图像变换(旋转、缩放、偏移等)的抗干扰能力,简单说就是提高卷积神经网络的空间不变性。
全栈程序员站长
2022/09/27
6310
推荐阅读
相关推荐
详细解读Spatial Transformer Networks(STN)-一篇文章让你完全理解STN了
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验