pytorch中bilinear的理解

本文详细解读了PyTorch中Bilinear函数的实现原理,通过实例展示了如何利用官方文档中的公式将二维输入与三维参数矩阵进行复杂的矩阵乘法操作,最终得到(b,a)形状的输出。通过代码演示和数值验证,突出了矩阵乘法与求和在实际任务中的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

直接参考官方文档,x1和x2是两个输入,A是参数矩阵,如下表达式

y = x_1^T A x_2 + b

但仔细看实现发现这个表达式并不是简单连乘的关系。假设x1(shape是b,n)和x2(shape是b,m)是二维,那么A是个三维tensor(shape是a,n,m)。具体实现时,A先拆成a个(n,m)形状的tensor,x1分别与之矩阵乘后再点乘(公式里的两次乘法),得到了a个(b,m)形状的tensor,然后在axis=1的维度上求和,最终输出成(b,a)的shape,用爱因斯坦表示法就是bn,anm,bm->ba,下面上一下code:

import torch
import torch.nn as nn
import numpy as np

l = torch.ones(2,5)
A = torch.ones(3,5,4)
r = torch.ones(2,4)
print(torch.einsum('bn,anm,bm->ba', l, A, r))
print(torch.nn.functional.bilinear(l,r,A))

x = torch.ones(2,5)
w = torch.ones(3,5)
print(torch.einsum('ij,kj->ik', x,w))
print(torch.nn.functional.linear(x,w))

print('learn nn.Bilinear')
m = nn.Bilinear(5, 4, 3)

output = m(l, r)
print(output.size())
arr_output = output.data.cpu().numpy()

weight = m.weight.data.cpu().numpy()
bias = m.bias.data.cpu().numpy()
x1 = l.data.cpu().numpy()
x2 = r.data.cpu().numpy()
print(x1.shape, weight.shape, x2.shape, bias.shape)
y = np.zeros((x1.shape[0], weight.shape[0]))
for k in range(weight.shape[0]):
    buff = np.dot(x1, weight[k])
    buff = buff * x2
    buff = np.sum(buff, axis=1)
    y[:, k] = buff
y += bias
dif = y - arr_output
print(np.mean(np.abs(dif.flatten())))

### PyTorch UNet 去噪模型中的掩码处理 在构建用于图像去噪的 U-Net 架构时,引入掩码可以有效提升网络对于特定区域的关注度。当涉及到带有掩码的操作时,通常会将原始输入图像与对应的二值化掩码一同送入网络,在编码器阶段保留空间位置信息的同时通过跳跃连接传递到解码器部分[^1]。 下面是一个简单的 PyTorch 实现案例,展示了如何利用掩码来增强 U-Net 的去噪能力: ```python import torch from torch import nn, optim import torchvision.transforms as transforms class DoubleConv(nn.Module): """(convolution => [BN] => ReLU) * 2""" def __init__(self, in_channels, out_channels): super().__init__() self.double_conv = nn.Sequential( nn.Conv2d(in_channels, out_channels, kernel_size=3, padding=1), nn.BatchNorm2d(out_channels), nn.ReLU(inplace=True), nn.Conv2d(out_channels, out_channels, kernel_size=3, padding=1), nn.BatchNorm2d(out_channels), nn.ReLU(inplace=True) ) def forward(self, x): return self.double_conv(x) class UNetDenoiseWithMask(nn.Module): def __init__(self, n_channels, n_classes): super(UNetDenoiseWithMask, self).__init__() bilinear = True factor = 2 if bilinear else 1 self.inc = DoubleConv(n_channels + 1, 64) # 输入通道数加一以适应带mask的数据 ... # 解码层定义省略... def forward(self, img, mask): """ :param img: 图像张量 (batch_size, channels, height, width) :param mask: 掩码张量 (batch_size, 1, height, width),注意形状匹配 """ x = torch.cat([img, mask], dim=1) # 将图片和mask拼接在一起作为输入 output = self.inc(x) # 继续完成剩余前向传播逻辑... return final_output # 数据预处理函数设置 transform = transforms.Compose([ transforms.ToTensor(), ]) # 训练过程简化示意 model = UNetDenoiseWithMask(n_channels=3, n_classes=1).cuda() criterion = nn.MSELoss().cuda() optimizer = optim.Adam(model.parameters(), lr=0.001) for epoch in range(num_epochs): for data in dataloader: imgs, masks, targets = data['image'], data['mask'], data['target'] outputs = model(imgs.cuda(), masks.cuda()) loss = criterion(outputs, targets.unsqueeze(dim=1).float().cuda()) optimizer.zero_grad() loss.backward() optimizer.step() print('Finished Training') ``` 此代码片段提供了一个基本框架,实际应用中可能还需要调整超参数以及优化训练流程等细节工作。此外,为了更好地理解整个项目结构及其配置方式,建议查阅官方文档或其他开源资源获取更详尽的信息[^4]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值