PyTorch复现SRGAN算法核心代码(带注释)

2023-05-16

train.py

import argparse
import os
from math import log10
import pandas as pd
import torch.optim as optim
import torch.utils.data
import torchvision.utils as utils
from torch.autograd import Variable
from torch.utils.data import DataLoader
from tqdm import tqdm  # 进度条
import pytorch_ssim
from data_utils import TrainDatasetFromFolder, ValDatasetFromFolder, display_transform
from loss import GeneratorLoss
from model import Generator, Discriminator


# 给分析器增加description,crop_size(图片裁剪大小),放大因子,epoch(跑的次数)等参数
parser = argparse.ArgumentParser(description='Train Super Resolution Models')
parser.add_argument('--crop_size', default=88, type=int, help='training images crop size')
parser.add_argument('--upscale_factor', default=4, type=int, choices=[2, 4, 8],
                    help='super resolution upscale factor')
parser.add_argument('--num_epochs', default=100, type=int, help='train epoch number')

# 对之前add的参数进行赋值,并返回响应namespace
opt = parser.parse_args()

# 提取opt(选项器)中设置的参数,设定为常量
CROP_SIZE = opt.crop_size
UPSCALE_FACTOR = opt.upscale_factor
NUM_EPOCHS = opt.num_epochs

# 从指定路径导入train_set,指定裁剪大小和放大因子
train_set = TrainDatasetFromFolder('data/VOC2012/train', crop_size=CROP_SIZE, upscale_factor=UPSCALE_FACTOR)
val_set = ValDatasetFromFolder('data/VOC2012/val', upscale_factor=UPSCALE_FACTOR)

# 使用loader,从训练集中,一次性处理一个batch的文件 (批量加载器)
train_loader = DataLoader(dataset=train_set, num_workers=4, batch_size=64, shuffle=True)
val_loader = DataLoader(dataset=val_set, num_workers=4, batch_size=1, shuffle=False)

# 创建生成器实例 netG ,输出生成器参数的数量
netG = Generator(UPSCALE_FACTOR)
print('# generator parameters:', sum(param.numel() for param in netG.parameters()))
netD = Discriminator()
print('# discriminator parameters:', sum(param.numel() for param in netD.parameters()))

# 实例化生成器损失函数模型
generator_criterion = GeneratorLoss()

# 如果能gpu加速,把网络放到gpu上
if torch.cuda.is_available():
    netG.cuda()
    netD.cuda()
    generator_criterion.cuda()

# 构建优化器optimizer,传入模型所有参数,使用Adam参数优化算法,调用step()可进行一次模型参数优化
# Adam - 自适应学习率+适用非凸优化
optimizerG = optim.Adam(netG.parameters())
optimizerD = optim.Adam(netD.parameters())

# 结果集 : loss score psnr(峰值信噪比) ssim(结构相似性)
results = {'d_loss': [], 'g_loss': [], 'd_score': [], 'g_score': [], 'psnr': [], 'ssim': []}

# 一次epoch跑一趟训练集
for epoch in range(1, NUM_EPOCHS + 1):
    # 加载进度条
    train_bar = tqdm(train_loader)
    running_results = {'batch_sizes': 0, 'd_loss': 0, 'g_loss': 0, 'd_score': 0, 'g_score': 0}

    # 进入train模式
    netG.train()
    netD.train()
    
    for data, target in train_bar:
        g_update_first = True
        batch_size = data.size(0)
        running_results['batch_sizes'] += batch_size

        ############################
        # (1) Update D network: maximize D(x)-1-D(G(z))
        ###########################
        real_img = Variable(target)
        if torch.cuda.is_available():
            real_img = real_img.cuda()
        z = Variable(data)
        if torch.cuda.is_available():
            z = z.cuda()
        fake_img = netG(z)

        netD.zero_grad()
        real_out = netD(real_img).mean()
        fake_out = netD(fake_img).mean()
        d_loss = 1 - real_out + fake_out
        d_loss.backward(retain_graph=True)
        # 进行参数优化
        optimizerD.step()

        ############################
        # (2) Update G network: minimize 1-D(G(z)) + Perception Loss + Image Loss + TV Loss
        ###########################
        netG.zero_grad()
        g_loss = generator_criterion(fake_out, fake_img, real_img)
        g_loss.backward()
        optimizerG.step()
        fake_img = netG(z)
        fake_out = netD(fake_img).mean()

        g_loss = generator_criterion(fake_out, fake_img, real_img)
        running_results['g_loss'] += g_loss.data[0] * batch_size
        d_loss = 1 - real_out + fake_out

        running_results['d_loss'] += d_loss.data[0] * batch_size  # d_loss real/fake通过判别器的差距
        running_results['d_score'] += real_out.data[0] * batch_size  # real通过判别器的值
        running_results['g_score'] += fake_out.data[0] * batch_size  # fake通过判别器的值

        # 描述进度和损失函数,得分函数的平均值
        train_bar.set_description(desc='[%d/%d] Loss_D: %.4f Loss_G: %.4f D(x): %.4f D(G(z)): %.4f' % (
            epoch, NUM_EPOCHS, running_results['d_loss'] / running_results['batch_sizes'],
            running_results['g_loss'] / running_results['batch_sizes'],
            running_results['d_score'] / running_results['batch_sizes'],
            running_results['g_score'] / running_results['batch_sizes']))
    # 进入eval模式 (测试模式参数固定,只有前向传播)
    netG.eval()
    out_path = 'training_results/SRF_' + str(UPSCALE_FACTOR) + '/'
    if not os.path.exists(out_path):
        os.makedirs(out_path)
    val_bar = tqdm(val_loader)
    valing_results = {'mse': 0, 'ssims': 0, 'psnr': 0, 'ssim': 0, 'batch_sizes': 0}
    val_images = []
    for val_lr, val_hr_restore, val_hr in val_bar:
        batch_size = val_lr.size(0)
        # 已经测试过的数目
        valing_results['batch_sizes'] += batch_size
        lr = Variable(val_lr, volatile=True)
        hr = Variable(val_hr, volatile=True)
        if torch.cuda.is_available():
            lr = lr.cuda()
            hr = hr.cuda()
        # 直接输出结果,没有参数优化的过程
        sr = netG(lr)
        # 计算mse
        batch_mse = ((sr - hr) ** 2).data.mean()
        valing_results['mse'] += batch_mse * batch_size
        batch_ssim = pytorch_ssim.ssim(sr, hr).data[0]
        valing_results['ssims'] += batch_ssim * batch_size
        valing_results['psnr'] = 10 * log10(1 / (valing_results['mse'] / valing_results['batch_sizes']))
        valing_results['ssim'] = valing_results['ssims'] / valing_results['batch_sizes']
        val_bar.set_description(
            desc='[converting LR images to SR images] PSNR: %.4f dB SSIM: %.4f' % (
                valing_results['psnr'], valing_results['ssim']))
        # 通过extend把三张图连在一起
        val_images.extend(
            [display_transform()(val_hr_restore.squeeze(0)), display_transform()(hr.data.cpu().squeeze(0)),
             display_transform()(sr.data.cpu().squeeze(0))])
    # 拉伸?
    print("val_images", val_images)
    val_images = torch.stack(val_images)
    print("val_images",val_images)
    val_images = torch.chunk(val_images, val_images.size(0) // 15)
    print("val_images", val_images)
    val_save_bar = tqdm(val_images, desc='[saving training results]')
    index = 1
    for image in val_save_bar:
        # 每一行显示三个图像
        image = utils.make_grid(image, nrow=3, padding=5)
        utils.save_image(image, out_path + 'epoch_%d_index_%d.png' % (epoch, index), padding=5)
        index += 1

    # save model parameters
    torch.save(netG.state_dict(), 'epochs/netG_epoch_%d_%d.pth' % (UPSCALE_FACTOR, epoch))
    torch.save(netD.state_dict(), 'epochs/netD_epoch_%d_%d.pth' % (UPSCALE_FACTOR, epoch))
    # save loss\scores\psnr\ssim
    results['d_loss'].append(running_results['d_loss'] / running_results['batch_sizes'])
    results['g_loss'].append(running_results['g_loss'] / running_results['batch_sizes'])
    results['d_score'].append(running_results['d_score'] / running_results['batch_sizes'])
    results['g_score'].append(running_results['g_score'] / running_results['batch_sizes'])
    results['psnr'].append(valing_results['psnr'])
    results['ssim'].append(valing_results['ssim'])

    if epoch % 10 == 0 and epoch != 0:
        out_path = 'statistics/'
        data_frame = pd.DataFrame(
            data={'Loss_D': results['d_loss'], 'Loss_G': results['g_loss'], 'Score_D': results['d_score'],
                  'Score_G': results['g_score'], 'PSNR': results['psnr'], 'SSIM': results['ssim']},
            index=range(1, epoch + 1))
        data_frame.to_csv(out_path + 'srf_' + str(UPSCALE_FACTOR) + '_train_results.csv', index_label='Epoch')

loss.py

import torch
from torch import nn
from torchvision.models.vgg import vgg16


class GeneratorLoss(nn.Module):
    def __init__(self):
        super(GeneratorLoss, self).__init__()
        vgg = vgg16(pretrained=True)
        loss_network = nn.Sequential(*list(vgg.features)[:31]).eval()
        for param in loss_network.parameters():
            param.requires_grad = False
        self.loss_network = loss_network
        self.mse_loss = nn.MSELoss()
        self.tv_loss = TVLoss()

    def forward(self, out_labels, out_images, target_images):
        # Adversarial Loss
        adversarial_loss = torch.mean(1 - out_labels)
        # Perception Loss
        perception_loss = self.mse_loss(self.loss_network(out_images), self.loss_network(target_images))
        # Image Loss
        image_loss = self.mse_loss(out_images, target_images)
        # TV Loss
        tv_loss = self.tv_loss(out_images)
        return image_loss + 0.001 * adversarial_loss + 0.006 * perception_loss + 2e-8 * tv_loss


class TVLoss(nn.Module):
    def __init__(self, tv_loss_weight=1):
        super(TVLoss, self).__init__()
        self.tv_loss_weight = tv_loss_weight

    def forward(self, x):
        batch_size = x.size()[0]
        h_x = x.size()[2]
        w_x = x.size()[3]
        count_h = self.tensor_size(x[:, :, 1:, :])
        count_w = self.tensor_size(x[:, :, :, 1:])
        h_tv = torch.pow((x[:, :, 1:, :] - x[:, :, :h_x - 1, :]), 2).sum()
        w_tv = torch.pow((x[:, :, :, 1:] - x[:, :, :, :w_x - 1]), 2).sum()
        return self.tv_loss_weight * 2 * (h_tv / count_h + w_tv / count_w) / batch_size

    @staticmethod
    def tensor_size(t):
        return t.size()[1] * t.size()[2] * t.size()[3]


if __name__ == "__main__":
    g_loss = GeneratorLoss()
    print(g_loss)

model.py

import math

import torch.nn.functional as F
from torch import nn

# 生成器
class Generator(nn.Module):
    def __init__(self, scale_factor):
        upsample_block_num = int(math.log(scale_factor, 2))

        super(Generator, self).__init__()
        self.block1 = nn.Sequential(
            nn.Conv2d(3, 64, kernel_size=9, padding=4),
            nn.PReLU()
        )
        self.block2 = ResidualBlock(64)
        self.block3 = ResidualBlock(64)
        self.block4 = ResidualBlock(64)
        self.block5 = ResidualBlock(64)
        self.block6 = ResidualBlock(64)
        self.block7 = nn.Sequential(
            nn.Conv2d(64, 64, kernel_size=3, padding=1),
            nn.PReLU()
        )
        block8 = [UpsampleBLock(64, 2) for _ in range(upsample_block_num)]
        block8.append(nn.Conv2d(64, 3, kernel_size=9, padding=4))
        self.block8 = nn.Sequential(*block8)

    def forward(self, x):
        block1 = self.block1(x)
        block2 = self.block2(block1)
        block3 = self.block3(block2)
        block4 = self.block4(block3)
        block5 = self.block5(block4)
        block6 = self.block6(block5)
        block7 = self.block7(block6)
        block8 = self.block8(block1 + block7)

        return (F.tanh(block8) + 1) / 2


class Discriminator(nn.Module):
    def __init__(self):
        super(Discriminator, self).__init__()
        self.net = nn.Sequential(
            nn.Conv2d(3, 64, kernel_size=3, padding=1),
            nn.LeakyReLU(0.2),

            nn.Conv2d(64, 64, kernel_size=3, stride=2, padding=1),
            nn.BatchNorm2d(64),
            nn.LeakyReLU(0.2),

            nn.Conv2d(64, 128, kernel_size=3, padding=1),
            nn.BatchNorm2d(128),
            nn.LeakyReLU(0.2),

            nn.Conv2d(128, 128, kernel_size=3, stride=2, padding=1),
            nn.BatchNorm2d(128),
            nn.LeakyReLU(0.2),

            nn.Conv2d(128, 256, kernel_size=3, padding=1),
            nn.BatchNorm2d(256),
            nn.LeakyReLU(0.2),

            nn.Conv2d(256, 256, kernel_size=3, stride=2, padding=1),
            nn.BatchNorm2d(256),
            nn.LeakyReLU(0.2),

            nn.Conv2d(256, 512, kernel_size=3, padding=1),
            nn.BatchNorm2d(512),
            nn.LeakyReLU(0.2),

            nn.Conv2d(512, 512, kernel_size=3, stride=2, padding=1),
            nn.BatchNorm2d(512),
            nn.LeakyReLU(0.2),

            nn.AdaptiveAvgPool2d(1),
            nn.Conv2d(512, 1024, kernel_size=1),
            nn.LeakyReLU(0.2),
            nn.Conv2d(1024, 1, kernel_size=1)
        )

    def forward(self, x):
        batch_size = x.size(0)
        return F.sigmoid(self.net(x).view(batch_size))

# 定义残差块
class ResidualBlock(nn.Module):
    def __init__(self, channels):
        super(ResidualBlock, self).__init__()
        self.conv1 = nn.Conv2d(channels, channels, kernel_size=3, padding=1)
        self.bn1 = nn.BatchNorm2d(channels)
        self.prelu = nn.PReLU()
        self.conv2 = nn.Conv2d(channels, channels, kernel_size=3, padding=1)
        self.bn2 = nn.BatchNorm2d(channels)

    def forward(self, x):
        residual = self.conv1(x)
        residual = self.bn1(residual)
        residual = self.prelu(residual)
        residual = self.conv2(residual)
        residual = self.bn2(residual)

        return x + residual


class UpsampleBLock(nn.Module):
    def __init__(self, in_channels, up_scale):
        super(UpsampleBLock, self).__init__()
        self.conv = nn.Conv2d(in_channels, in_channels * up_scale ** 2, kernel_size=3, padding=1)
        self.pixel_shuffle = nn.PixelShuffle(up_scale)
        self.prelu = nn.PReLU()

    def forward(self, x):
        x = self.conv(x)
        x = self.pixel_shuffle(x)
        x = self.prelu(x)
        return x

data_utils.py

from os import listdir
from os.path import join

from PIL import Image
from torch.utils.data.dataset import Dataset
# torchvision.transforms - 图像预处理包
# Compose - 把多个步骤整合一起
from torchvision.transforms import Compose, RandomCrop, ToTensor, ToPILImage, CenterCrop, Resize


# 通过后缀检查是否为图片文件
def is_image_file(filename):
    return any(filename.endswith(extension) for extension in ['.png', '.jpg', '.jpeg', '.PNG', '.JPG', '.JPEG'])

# 实际有效的图片区域范围
def calculate_valid_crop_size(crop_size, upscale_factor):
    return crop_size - (crop_size % upscale_factor)


def train_hr_transform(crop_size):
    return Compose([
        RandomCrop(crop_size),  # 在随机位置裁剪
        ToTensor(),  # convert a PIL image to tensor (H*W*C)
    ])


def train_lr_transform(crop_size, upscale_factor):
    return Compose([
        ToPILImage(),  # convert a tensor to PIL image
        Resize(crop_size // upscale_factor, interpolation=Image.BICUBIC),  # 通过双三次插值把图像resize成lr
        ToTensor()
    ])


def display_transform():
    return Compose([
        ToPILImage(),
        Resize(400),  # 把图像调整到400标准格式
        CenterCrop(400),
        ToTensor()
    ])


# 从文件夹获取训练集
class TrainDatasetFromFolder(Dataset):
    def __init__(self, dataset_dir, crop_size, upscale_factor):
        super(TrainDatasetFromFolder, self).__init__()
        # 获取图片列表
        self.image_filenames = [join(dataset_dir, x) for x in listdir(dataset_dir) if is_image_file(x)]
        crop_size = calculate_valid_crop_size(crop_size, upscale_factor)
        # 定义hr lr转化函数
        self.hr_transform = train_hr_transform(crop_size)
        self.lr_transform = train_lr_transform(crop_size, upscale_factor)

    def __getitem__(self, index):
        # 获取该index的高清图像,同时转化得到低清图像
        hr_image = self.hr_transform(Image.open(self.image_filenames[index]))
        lr_image = self.lr_transform(hr_image)
        return lr_image, hr_image

    def __len__(self):
        return len(self.image_filenames)

# 验证集
class ValDatasetFromFolder(Dataset):
    def __init__(self, dataset_dir, upscale_factor):
        super(ValDatasetFromFolder, self).__init__()
        self.upscale_factor = upscale_factor
        self.image_filenames = [join(dataset_dir, x) for x in listdir(dataset_dir) if is_image_file(x)]

    def __getitem__(self, index):
        hr_image = Image.open(self.image_filenames[index])  # 原始图片为高清图
        w, h = hr_image.size
        crop_size = calculate_valid_crop_size(min(w, h), self.upscale_factor)
        lr_scale = Resize(crop_size // self.upscale_factor, interpolation=Image.BICUBIC)
        hr_scale = Resize(crop_size, interpolation=Image.BICUBIC)
        hr_image = CenterCrop(crop_size)(hr_image)  # 裁剪
        lr_image = lr_scale(hr_image)  # 双三次resize成lr
        hr_restore_img = hr_scale(lr_image)
        return ToTensor()(lr_image), ToTensor()(hr_restore_img), ToTensor()(hr_image)

    def __len__(self):
        return len(self.image_filenames)

# 测试集
class TestDatasetFromFolder(Dataset):
    def __init__(self, dataset_dir, upscale_factor):
        super(TestDatasetFromFolder, self).__init__()
        # 有hr lr两个文件目录
        self.lr_path = dataset_dir + '/SRF_' + str(upscale_factor) + '/data/'
        self.hr_path = dataset_dir + '/SRF_' + str(upscale_factor) + '/target/'
        self.upscale_factor = upscale_factor
        self.lr_filenames = [join(self.lr_path, x) for x in listdir(self.lr_path) if is_image_file(x)]
        self.hr_filenames = [join(self.hr_path, x) for x in listdir(self.hr_path) if is_image_file(x)]

    def __getitem__(self, index):
        # 获取hr lr 图像
        image_name = self.lr_filenames[index].split('/')[-1]
        lr_image = Image.open(self.lr_filenames[index])
        w, h = lr_image.size
        hr_image = Image.open(self.hr_filenames[index])
        hr_scale = Resize((self.upscale_factor * h, self.upscale_factor * w), interpolation=Image.BICUBIC)
        hr_restore_img = hr_scale(lr_image)
        return image_name, ToTensor()(lr_image), ToTensor()(hr_restore_img), ToTensor()(hr_image)

    def __len__(self):
        return len(self.lr_filenames)

没有GPU,在自己mac电脑上测试了一下,训练集删减为10多张图片,跑了40个epoch,虽然高糊但是有个大概雏形出来了

image.png

image.png

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

PyTorch复现SRGAN算法核心代码(带注释) 的相关文章

  • 如何将一个网络分为两个子网、如何通过已知IP和子网掩码计算其同一网段的主机IP

    IPV4的IP地址格式通常表示为xxx xxx xxx xxx xff0c 其中xxx为十进制数 xff0c 取值范围是 0 xff0c 255 xff0c 若用16进制表示则为xx xx xx xx xff0c 其中xx的取值范围是 0
  • Unity3D 人称设置(第一人称视角、第三人称视角)

    设置第一人称视角 1 把物体的坐标和摄像机的坐标设置成一样的 xff0c 这样摄像机就在物体内部 xff0c 就是第一人称的视角 2 把摄像机拖拽进物体对象内 xff0c 摄像机变成物体的子对象 xff0c 这样摄像机就能跟着物体一起移动
  • Unity3D 射击游戏练习实例

    知识点 xff1a 刚体组件 xff08 rigidbody xff09 xff0c 受力和碰撞的组件触发器 xff08 Trigger xff09 xff0c 开启后物体碰撞效果取消 xff0c 但仍会返回碰撞消息复制物体对象 xff1a
  • Cocos2dx 环境搭建

    Cocos2dx 环境搭建 准备软件和工具包 xff0c 参考 xff1a Cocos2dx 入门学习准备安装visual studio 安装Python2 7 xff08 直接默认下一步就可以 xff0c 要注意Python安装的路径 x
  • 缺失MSVCR相关文件怎么办

    根据系统的提示 xff0c 看缺失的是哪个文件 xff0c 正常是msvcr100 120 dll在百度上搜索对应文件下载把下载好的msvcr文件 xff0c 放到 C Windows SysWOW64 目录下正常msvcr文件会缺失好几个
  • Cocos2dx 源码解释

    程序入口 AppDelegate AppDelegate在AppDelegate h中定义的 AppDelegate h中的AppDelegate类 xff1a AppDelegate类下的applicationDidFinishLaunc
  • Visual Studio 2019(VS2019) 基本操作

    卸载 加载项目 1 卸载项目 xff1a 不删除项目代码 xff0c 但是停止对该项目的一切使用和调用 xff08 好处是保留代码 xff09 2 加载项目 xff1a 重新加载已停用的项目 xff0c 可以继续使用和调用 修改VS主题风格
  • Elasticsearch 中文分词&多词搜索&权重

    目录 中文分词器 一 安装中文分词器ik 二 使用中文分词器 多词搜索 权重 中文分词器 一 安装中文分词器ik 源码地址 xff1a https github com medcl elasticsearch analysis ik 根据提
  • C# do while循环结构

    注意 循环结构一共有三种 xff1a while循环 https blog csdn net shenqiankk article details 96299600do while循环for循环 https blog csdn net sh
  • C# for循环结构

    注意 循环结构一共有三种 xff1a while循环 https blog csdn net shenqiankk article details 96299600do while循环 https blog csdn net shenqia
  • C# 构造方法(函数)

    构造方法的作用 构造方法用来创建对象 xff0c 并且在构造方法中对对象进行初始化 构造方法的特殊性 没有返回值 xff0c 不需要写类型 xff0c 连void都不要写 构造方法的方法名 xff0c 与类名要相同 构造方法结构 publi
  • GDI+ 绘图方法

    GDI绘直线步骤 创建GDI对象 xff1a Graphics g 61 this CreateGraphics 创建画笔对象 xff1a Pen pen 61 new Pen Brushes Red 创建两个点 xff1a Point p
  • C# 连接MySQL数据库

    C 引用MySQL步骤 xff1a 下载mysql data dll xff1a http soft onlinedown net soft 618668 htm将文件放在项目目录下在VS2019项目内 xff0c 引用mysql data
  • Navicat of MySQL连接和使用

    请先安装MySQL服务 MySQL数据库安装 xff1a https blog csdn net shenqiankk article details 99756531 新建连接 如果出现Can t connect to MySQL ser
  • Mysql创建数据库字符集的选择

    转载 xff1a https blog csdn net JingChC article details 82908686 字符集选择 xff1a 在国内正常都是用 UTF 8 排序选择 xff1a 排序一般分为两种 xff1a utf b
  • Linux进程状态解析 之 R、S、D、T、Z、X (主要有三个状态)

    linux是一个多用户 xff0c 多任务的系统 xff0c 可以同时运行多个用户的多个程序 xff0c 就必然会产生很多的进程 xff0c 而每个进程会有不同的状态 Linux进程状态 xff1a R TASK RUNNING xff0c
  • python装饰器(详解)

    1 什么是装饰器 器指的是工具 xff0c 可以定义成成函数 装饰指的是为其他事物添加额外的东西点缀 合到一起的解释 xff1a 装饰器指的定义一个函数 xff0c 该函数是用来为其他函数添加额外的功能 就是拓展原来函数功能的一种函数 2
  • linux基础---常用命令学习

    1 显示日期的指令 xff1a date Linux时钟分为系统时钟 xff08 System Clock xff09 和硬件 xff08 Real Time Clock xff0c 简称RTC xff09 时钟 系统时钟是指当前Linux
  • JdbcTemplate queryForObject Incorrect result size: expected 1, actual 0

    使用Spring中的jdbcTemplate 时 xff0c 通过id查询不到结果时返回Incorrect result size expected 1 actual 0 64 Override public lt T gt T query
  • Ubuntu usb wifi驱动安装(MT7601u芯片)

    软件环境 Ubuntu 14 04 硬件环境 芯片 xff1a MT7601u 确定芯片 xff0c 在电脑插上usb wifi xff0c 在ubuntu命令行 xff0c 输入lsusb命令 xff0c 在所列的列表中有MT7601u即

随机推荐

  • 【目标检测】Fast RCNN算法详解

    Girshick Ross Fast r cnn Proceedings of the IEEE International Conference on Computer Vision 2015 继2014年的RCNN之后 xff0c Ro
  • 【目标检测】RCNN算法详解

    Girshick Ross et al Rich feature hierarchies for accurate object detection and semantic segmentation Proceedings of the
  • SHTC3的研发经历

    SHTC3自学笔记 一 SHTC3介绍 SHTC3是一款低功耗温湿度传感器 xff0c 温度的采集范围为 40 125 xff0c 湿度的采集范围为 0 100 通讯方式是I2C xff0c 引脚定义如图1所示 I2C的器件地址只有一个 x
  • BH1750光照传感器超详细攻略(从原理到代码讲解,看完你就懂了)

    目录 一 前言二 芯片介绍三 IIC通讯介绍IIC通讯过程简介IIC通讯实例BH1750的通讯过程 四 BH1750的命令五 BH1750编程教学六 测试七 总结 一 前言 之所以写这篇文章 xff0c 原因有两个 一是 xff1a 有个师
  • mininet+FlowVisor+OpenDayLight环境搭建及实验一

    注 xff1a 这是我在学习时整理的笔记 xff0c 包含我遇到的问题已经一些需要注意的点 转载请标明出处并附上原文连接 xff0c 谢谢 xff01 http blog csdn net sherkyoung article detail
  • Ubuntu Linux服务器安装图形化界面并用VNC Viewer连接

    文章目录 1 流程2 服务器开启VNC使用的端口3 服务器安装Ubuntu桌面与VNC Server4 客户端安装VNC Viewer xff08 略 xff09 5 连接 x1f517 1 流程 服务器开启VNC使用的端口服务器安装Ubu
  • 利用JavaScript写一个简易地学生管理系统

    不多说上代码 span class token keyword var span studentNoArr span class token operator 61 span span class token punctuation spa
  • 轻松掌握 JS 删除数组中指定的对象或者删除数组中某一项

    前言 关于 JS 删除数组中指定的对象或某一项的话题 xff0c 它是在实际开发中经常会遇到的问题 xff0c 也是需要掌握的基本技能 在这篇文章中 xff0c 我们将深入探讨如何使用 JS 来删除数组中指定的对象或者删除数组中某一项 删除
  • ubuntu能ping通却ssh不上(connect to localhost port 22: Connection refused)解决办法

    1 问题描述 xff1a ssh 192 168 144 130 ssh connect to host 192 168 144 130 port 22 Connection refused 2 原因 因为Ubuntu默认没有安装opens
  • mysql增加用户并赋予、删除、查看各种权限

    数据库系统表概述 mysql数据库下存储的都是权限表 xff0c 重要的有user表 db表 host表还有tables priv表 columns priv proc priv表 1 user表 xff1a 有用户列 权限列 安全列 资源
  • 数据库上云?这些事你不得不知

    您的业务适合哪种数据库 xff0c 真的知道吗 xff1f 互联网 43 人工智能 物联网等新兴技术的迅猛发展 xff0c 让如何处理大量 复杂 多变的数据问题再次浮出水面 xff0c 成为新时代企业用户面临的技术挑战之一 关系型数据库 x
  • 【STM32技巧】STM32 PWM互补输出设置

    本例程是使用STM32CubeMX 6 5版本生成带代码 测试单片机型号 xff1a STM32F103VET6 时钟设置72MHZ 使用定时器1的通道1 和 通道2 配置PWM互补输出 分频72分频 定时器频率为 72MHZ 72 61
  • js删除键值对的方法

    1 对于Map 增set k v 删delete k 查 get k 改set 43 get span class token keyword const span graph span class token operator 61 sp
  • java一路走来

    记得第一次学编程 xff0c 那都是高二时 xff0c 那时因为电脑很狂热 xff0c 刚好有一个哥就给我介绍了编程 xff0c 并给我演示了下vb语言 xff0c 用vb做了个计算器 xff0c 当时我惊呆了 xff0c 才知道编程有多神
  • Python基础教程之列表

    八仙过海是一个中国民间故事 xff0c 讲了汉钟离 张果老 韩湘子 铁拐李 吕洞宾 何仙姑 蓝采和和曹国舅八位神仙各显神通渡海的故事 我们都知道变量只能被赋值为一个值 xff0c 现在我们想把八位神仙的名字同时赋值 xff0c 该如何实现呢
  • move_base参数配置

    现在我们已经可以构建当前环境地图 xff0c 可以实现机器人在当前地图中的定位 那接下来就可以在地图上给定目标点 xff0c 开始规划路径控制机器人移动过去 xff0c 这样就可以完成在已知地图中进行自动导航的任务了 在已知地图中进行路径规
  • 计算节点nova服务启动失败

    在计算节点启动openstack nova compute服务的时候 xff0c 服务无法正常启动 xff0c 查看nova的日志发现如下报错 xff1a 2019 04 25 00 02 26 481 24682 ERROR nova T
  • openstack通过dashboard页面创建实例,实现实例与外部通信

    配置完所有节点 xff0c 通过dashboard页面来进行下一步的配置 首先通过admin用户登录页面 在管理员下 xff0c 创建一个外部网络 注意供应商类型为flat xff0c 之前修改配置文件时有提到过 etc neutron p
  • 防火墙经过地址转换抓包详解

    R表示收到 xff0c X表示发出 xff0c R 64 eth1是从eth1口收到数据包 X 64 eth2是从2口发出数据包 16 1 1 1 gt 18 1 1 2 表示IP 16 1 1 1发给IP 18 1 1 2 Seq后面的数
  • PyTorch复现SRGAN算法核心代码(带注释)

    train py import argparse import os from math import log10 import pandas as pd import torch optim as optim import torch u