深度学习——现代卷积神经网络(七)

深度卷积神经网络

学习表征

  1. 观察图像特征的提取⽅法。
  2. 在合理地复杂性前提下,特征应该由多个共同学习的神经⽹络层组成,每个层都有可学习的参数。

当年缺少数据和硬件支持

AlexNet

  1. AlexNet⽐相对较⼩的LeNet5要深得多。 AlexNet由⼋层组成:五个卷积层、两个全连接隐藏层和⼀个全连接输出层。
  2. AlexNet使⽤ReLU⽽不是sigmoid作为其激活函数。

模型设计

在AlexNet的第⼀层,卷积窗⼝的形状是11×11。由于ImageNet中⼤多数图像的宽和⾼⽐MNIST图像的多10倍以上,因此,需要⼀个更⼤的卷积窗⼝来捕获⽬标。第⼆层中的卷积窗⼝形状被缩减为5× 5,然后是3× 3。此外,在第⼀层、第⼆层和第五层卷积层之后,加⼊窗⼝形状为3× 3、步幅为2的最⼤汇聚层。⽽且, AlexNet的卷积通道数⽬是LeNet的10倍。

激活函数

AlexNet将sigmoid激活函数改为更简单的ReLU激活函数。

  1. ReLU激活函数的计算更简单
  2. 当使⽤不同的参数初始化⽅法时, ReLU激活函 数使训练模型更加容易。

容量控制

AlexNet通过暂退法(4.6节)控制全连接层的模型复杂度,⽽LeNet只使⽤了权重衰减。为了进⼀步扩充数据, AlexNet在训练时增加了⼤量的图像增强数据,如翻转、裁切和变⾊。这使得模型更健壮,更⼤的样本量有效地减少了过拟合。

使用块的网络(VGG)

经典的卷积神经网络基本组成部分:

  1. 带填充以保持分辨率的卷积层;
  2. ⾮线性激活函数,如ReLU;
  3. 汇聚层,如最⼤汇聚层。

而⼀个VGG块与之类似,由⼀系列卷积层组成,后⾯再加上⽤于空间下采样的最⼤汇聚层。

VGG块

import torch
import torch.nn as nn 
import d2l.torch as d2l
# 卷积层的数量num_convs、输⼊通道的数量in_channels 和输出通道的数量out_channels.
def Vgg_block(num_convs, in_channels, out_channels):layers = []for _ in range(num_convs):layers.append(nn.Conv2d(in_channels, out_channels, kernel_size=3, padding=1))layers.append(nn.ReLU())in_channels = out_channelslayers.append(nn.MaxPool2d(kernel_size=2, stride=2))return nn.Sequential(*layers)

VGG网络

# 超参数变量conv_arch。该变量指定了每个VGG块⾥卷积层个数和输出通道数。
conv_arch = ((1, 64), (1, 128), (2, 256), (2, 512), (2, 512))
in_channels = 1
def VGG(in_channels, conv_arch):conv_blks = []for (num_convs, out_channels) in conv_arch:conv_blks.append(Vgg_block(num_convs, in_channels, out_channels))in_channels = out_channelsnet = nn.Sequential(*conv_blks, nn.Flatten(),nn.Linear(out_channels * 7 * 7, 4096), nn.ReLU(), nn.Dropout(0.5),nn.Linear(4096, 4096), nn.ReLU(), nn.Dropout(0.5),nn.Linear(4096, 10))return netnet = VGG(in_channels, conv_arch)
net

网络中的网络(NiN)

LeNet、 AlexNet和VGG都有⼀个共同的设计模式:通过⼀系列的卷积层与汇聚层来提取空间结构特征;然后通过全连接层对特征的表征进⾏处理。 AlexNet和VGG对LeNet的改进主要在于如何扩⼤和加深这两个模块。** **
卷积层的输⼊和输出由四维张量组成,张量的每个轴分别对应样本、通道、⾼度和宽度。 NiN的想法是在每个像素位置(针对每个⾼度和宽度)应⽤⼀个全连接层 ,

如果我们将权重连接到每个空间位置,我们可以将其视为1 × 1卷积层 。从另⼀个⻆度看,即将空间维度中的每个像素视为单个样本,将通道维度视为不同特征(feature)。
NiN块以⼀个普通卷积层开始,后⾯是两个1 × 1的卷积层。这两个1 × 1卷积层充当带有ReLU激活函数的逐像素全连接层。

import torch 
import torch.nn as nn
import d2l.torch as d2ldef nin_block(in_channels, out_channels, kernel_size, strides, padding):return nn.Sequential(nn.Conv2d(in_channels, out_channels, kernel_size, strides, padding),nn.ReLU(),nn.Conv2d(out_channels, out_channels, kernel_size=1), nn.ReLU(),nn.Conv2d(out_channels, out_channels, kernel_size=1), nn.ReLU())net = nn.Sequential(nin_block(20, 96, kernel_size=11, strides=4, padding=0),nn.MaxPool2d(3, stride=2),nin_block(96, 256, kernel_size=5, strides=1, padding=2),nn.MaxPool2d(3, stride=2),nin_block(256, 384, kernel_size=3, strides=1, padding=1),nn.MaxPool2d(3, stride=2),nn.Dropout(0.5),# 标签类别数是10nin_block(384, 10, kernel_size=3, strides=1, padding=1),nn.AdaptiveAvgPool2d((1, 1)),# 将四维的输出转成⼆维的输出,其形状为(批量⼤⼩,10)nn.Flatten())X = torch.rand(size=(16, 20, 224, 224))
for layer in net:X = layer(X)print(layer.__class__.__name__,'output shape:\t', X.shape)lr, num_epochs, batch_size = 0.1, 10, 128
train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size, resize=224)
d2l.train_ch6(net, train_iter, test_iter, num_epochs, lr, d2l.try_gpu())

含并行连结的网络

inception块

在GoogLeNet中,基本的卷积块被称为Inception块(Inception block)。

import torch
from torch import nn
from torch.nn import functional as F
from d2l import torch as d2lclass Inception(nn.Module):# c1--c4是每条路径的输出通道数def __init__(self, in_channels, c1, c2, c3, c4, **kwargs):super(Inception, self).__init__(**kwargs)# 线路1,单1x1卷积层self.p1_1 = nn.Conv2d(in_channels, c1, kernel_size=1)# 线路2, 1x1卷积层后接3x3卷积层self.p2_1 = nn.Conv2d(in_channels, c2[0], kernel_size=1)self.p2_2 = nn.Conv2d(c2[0], c2[1], kernel_size=3, padding=1)# 线路3, 1x1卷积层后接5x5卷积层self.p3_1 = nn.Conv2d(in_channels, c3[0], kernel_size=1)self.p3_2 = nn.Conv2d(c3[0], c3[1], kernel_size=5, padding=2)# 线路4, 3x3最⼤汇聚层后接1x1卷积层self.p4_1 = nn.MaxPool2d(kernel_size=3, stride=1, padding=1)self.p4_2 = nn.Conv2d(in_channels, c4, kernel_size=1)def forward(self, x):p1 = F.relu(self.p1_1(x))p2 = F.relu(self.p2_2(F.relu(self.p2_1(x))))p3 = F.relu(self.p3_2(F.relu(self.p3_1(x))))p4 = F.relu(self.p4_2(self.p4_1(x)))# 在通道维度上连结输出return torch.cat((p1, p2, p3, p4), dim=1)

GoogLeNet模型

批量规范化

训练深层神经⽹络是⼗分困难的,特别是在较短的时间内使他们收敛更加棘⼿。本节将介绍批量规范化(batch normalization),这是⼀种流⾏且有效的技术,可持续加速深层⽹络的收敛速度。再结合后面将介绍的残差块,批量规范化使得研究⼈员能够训练100层以上的⽹络。

、训练深层网络

为什么要批量规范化?

  • ⾸先,数据预处理的⽅式通常会对最终结果产⽣巨⼤影响。
  • 第⼆,对于典型的多层感知机或卷积神经⽹络。当我们训练时,中间层中的变量(例如,多层感知机中的仿射变换输出)可能具有更⼴的变化范围:不论是沿着从输⼊到输出的层,跨同⼀层中的单元,或是随着时间的推移,模型参数的随着训练更新变幻莫测。
  • 第三,更深层的⽹络很复杂,容易过拟合。这意味着正则化变得更加重要。
    批量规范化应⽤于单个可选层(也可以应⽤到所有层),其原理如下:在每次训练迭代中,我们⾸先规范化输⼊,即通过减去其均值并除以其标准差,其中两者均基于当前⼩批量处理。接下来,我们应⽤⽐例系数和⽐例偏移。正是由于这个基于批量统计的标准化,才有了批量规范化的名称。


    注意:我们在⽅差估计值中添加⼀个⼩的常量ϵ > 0,以确保我们永远不会尝试除以零,即使在经验⽅差估计值可能消失的情况下也是如此。估计值µ^Bσ^ B通过使⽤平均值和⽅差的噪声(noise)估计来抵消缩放问题。乍看起来,这种噪声是⼀个问题,⽽事实上它是有益的。
  • 第四,批量规范化层在”训练模式“(通过⼩批量统计数据规范化)和“预测模式”(通过数据集统计规范化)中的功能不同。在训练过程中,我们⽆法得知使⽤整个数据集来估计平均值和⽅差,所以只能根据每个⼩批次的平均值和⽅差不断训练模型。⽽在预测模式下,可以根据整个数据集精确计算批量规范化所需的平均值和⽅差。

、批量规范化层

批量规范化和其他层之间的⼀个关键区别是,由于批量规范化在完整的⼩批量上运⾏,因此我们
不能像以前在引⼊其他层时那样忽略批量⼤⼩。

我们可以分为两种不同情况进行讨论:全连接层和卷积层

全连接层

我们将批量规范化层置于全连接层中的仿射变换和激活函数之间。设全连接层的输⼊为x,权重参数和偏置参数分别为Wb,激活函数为ϕ,批量规范化的运算符为BN。那么,使⽤批量规范化的全连接层的输出的计算详情如下:

卷积层

对于卷积层,我们可以在卷积层之后和⾮线性激活函数之前应⽤批量规范化。 当卷积有多个输出通道
时,我们需要对这些通道的“每个”输出执⾏批量规范化,每个通道都有⾃⼰的拉伸(scale)和偏移(shif)参数,这两个参数都是标量。

代码实现

# 1. 导入库
import torch
from torch import nn
from d2l import torch as d2l# 2. 批量规范化实现def batch_norm(x, gamma, beta, moving_mean, moving_var, eps, momentum):# 通过is_grad_enabled来判断当前模式是训练模式还是预测模式if not torch.is_grad_enabled():# 如果是在预测模式下,直接使⽤传⼊的移动平均所得的均值和⽅差X_hat = (x - moving_mean) / torch.sqrt(moving_var + eps)else:assert len(x.shape) in (2, 4)if len(x.shape) == 2:mean = x.mean(dim = 0)var = ((x - mean) ** 2).mean(dim=0)else:# 使⽤⼆维卷积层的情况,计算通道维上(axis=1)的均值和⽅差。# 这⾥我们需要保持X的形状以便后⾯可以做⼴播运算mean = x.mean(dim=(0, 2, 3), keepdim=True)var = ((x - mean) ** 2).mean(dim=(0, 2, 3), keepdim=True)# 训练模式下,⽤当前的均值和⽅差做标准化X_hat = (x - mean) / torch.sqrt(var + eps)# 更新移动平均的均值和⽅差moving_mean = momentum * moving_mean + (1.0 - momentum) * meanmoving_var = momentum * moving_var + (1.0 - momentum) * varY = gamma * X_hat + beta # 缩放和移位return Y, moving_mean.data, moving_var.data

BatchNorm层

这个层将保持适当的参数:拉伸gamma和偏移beta,这两个参数将在训练过程中更新

# BatchNorm层实现
class BatchNorm(nn.Module):# num_features:完全连接层的输出数量或卷积层的输出通道数。# num_dims: 2表⽰完全连接层, 4表⽰卷积层def __init__(self, num_features, num_dims):super().__init__()if num_dims == 2:shape = (1, num_features)else:shape = (1, num_features, 1, 1)# 参与求梯度和迭代的拉伸和偏移参数,分别初始化成1和0self.gamma = nn.Parameter(torch.ones(shape))self.beta = nn.Parameter(torch.zeros(shape))# ⾮模型参数的变量初始化为0和1self.moving_mean = torch.zeros(shape)self.moving_var = torch.ones(shape)def forward(self, x):# 如果X不在内存上,将moving_mean和moving_var# 复制到X所在显存上if self.moving_mean.device != x.device:self.moving_mean = self.moving_mean.to(x.device)self.moving_var = self.moving_var.to(x.device)# 保存更新过的moving_mean和moving_varY, self.moving_mean, self.moving_var = batch_norm(x, self.gamma, self.beta, self.moving_mean,self.moving_var, eps=1e-5, momentum=0.9)return Y

使⽤批量规范化层的 LeNet

import torch.nn as nn 
import d2l.torch as d2l
import torch
net = nn.Sequential(nn.Conv2d(1, 6, kernel_size=5), BatchNorm(6, num_dims=4), nn.Sigmoid(),nn.AvgPool2d(kernel_size=2, stride=2),nn.Conv2d(6, 16,kernel_size=5), BatchNorm(16, num_dims=4), nn.Sigmoid(),nn.AvgPool2d(kernel_size=2, stride=2), nn.Flatten(),nn.Linear(16 * 4 * 4, 120),BatchNorm(120, num_dims=2), nn.Sigmoid(),nn.Linear(120, 84),BatchNorm(84, num_dims=2), nn.Sigmoid(), nn.Linear(84, 10))
lr, num_epochs, batch_size = 1.0, 30, 256
train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size)
d2l.train_ch6(net, train_iter, test_iter, num_epochs, lr, d2l.try_gpu())print(net[1].gamma.reshape((-1,)), net[1].beta.reshape((-1,)))

残差神经网络(ResNet)

对于深度神经⽹络,如果我们能将新添加的层训练成恒等映射(identity function) f(x) = x,新模型和原模型将同样有效。同时,由于新模型可能得出更优的解来拟合训练数据集,因此添加层似乎更容易降低训练误差。
残差⽹络的核⼼思想是:每个附加层都应该更容易地包含原始函数作为其元素之⼀。

⽣成两种类型的⽹络:⼀种是当use_1x1conv=False时,应⽤ReLU⾮线性函数之前,将输⼊添加到输出。另⼀种是当use_1x1conv=True时,添加通过1 × 1卷积调整通道和分辨率

、残差块实现

# 残差块
import torch
import torch.nn as nn 
import d2l.torch as d2l
import torch.nn.functional as Fclass Residual(nn.Module):def __init__(self, input_channels,num_channels, use_1x1_conv = False, strides = 1):super().__init__()self.conv1 = nn.Conv2d(input_channels, num_channels, kernel_size=3,stride=strides, padding = 1)self.bn1 = nn.BatchNorm2d(num_channels)self.conv2 = nn.Conv2d(num_channels, num_channels, kernel_size=3,  padding = 1)self.bn2 = nn.BatchNorm2d(num_channels)if use_1x1_conv:self.conv3 = nn.Conv2d(input_channels, num_channels,kernel_size=3, stride=strides, padding=1)else:self.conv3 = Nonedef forward(self, X):Y = F.relu(self.bn1(self.conv1(X)))Y = self.bn2(self.conv2(Y))if self.conv3:X = self.conv3(X)Y += Xreturn F.relu(Y)

残差神经网络模型

  • ResNet-18

import torch
import torch.nn as nn def res_block(input_channels, num_channels, num_residuals, first_block = False):blk = []for i in range(num_residuals):if i == 0 and not first_block:blk.append(Residual(input_channels, num_channels, use_1x1_conv=True, strides=2))else:blk.append(Residual(input_channels=input_channels, num_channels=num_channels))return blk# 1. 卷积层
b1 = nn.Sequential(nn.Conv2d(1, 64,kernel_size=7,stride=2, padding=3),nn.BatchNorm2d(64), nn.ReLU(),nn.AvgPool2d(kernel_size=3, stride=2, padding=1))
# 2. 残差层
b2 = nn.Sequential(*res_block(64,64, num_residuals=2, first_block=True))
b3 = nn.Sequential(*res_block(64,128, num_residuals=2))
b4 = nn.Sequential(*res_block(128,256, num_residuals=2))
b5 = nn.Sequential(*res_block(256,512, num_residuals=2))# 3. 汇聚层和全连接层
# ResNet-18
net = nn.Sequential(b1, b2, b3, b4, b5,nn.AdaptiveAvgPool2d((1,1)),nn.Flatten(), nn.Linear(512, 10))'''
每个模块有4个卷积层(不包括恒等映射的1 × 1卷积层)。
加上第⼀个7 × 7卷积层和最后⼀个全连接层,共
有18层。因此,这种模型通常被称为ResNet-18。
'''

查看在ResNet中不同模块的输入形状是怎么变化的

X = torch.rand(size=(1, 1, 224, 224))
for layer in net:X = layer(X)print(layer.__class__.__name__,'output shape:\t', X.shape)

:::color1
Sequential output shape: torch.Size([1, 64, 56, 56])
Sequential output shape: torch.Size([1, 64, 56, 56])
Sequential output shape: torch.Size([1, 128, 28, 28])
Sequential output shape: torch.Size([1, 256, 14, 14])
Sequential output shape: torch.Size([1, 512, 7, 7])
AdaptiveAvgPool2d output shape: torch.Size([1, 512, 1, 1])
Flatten output shape: torch.Size([1, 512])
Linear output shape: torch.Size([1, 10])

:::

模型训练

# 模型训练
lr, num_epochs, batch_size = 0.05, 10, 256
train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size, resize=96)
d2l.train_ch6(net, train_iter, test_iter, num_epochs, lr, d2l.try_gpu())

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

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

相关文章

时间管理系统|Java|SSM|JSP|

【技术栈】 1⃣️:架构: B/S、MVC 2⃣️:系统环境:Windowsh/Mac 3⃣️:开发环境:IDEA、JDK1.8、Maven、Mysql5.7 4⃣️:技术栈:Java、Mysql、SSM、Mybatis-Plus、JSP、jquery,html 5⃣️数据库可…

20241217使用M6000显卡在WIN10下跑whisper来识别中英文字幕

20241217使用M6000显卡在WIN10下跑whisper来识别中英文字幕 2024/12/17 17:21 缘起,最近需要识别法国电影《地下铁》的法语字幕,使用 字幕小工具V1.2【whisper套壳/GUI封装了】 无效。 那就是直接使用最原始的whisper来干了。 当你重装WIN10的时候&#…

PostgreSQL技术内幕21:SysLogger日志收集器的工作原理

0.简介 在前面文章中介绍了事务模块用到的事务日志结构和其工作原理,本文将介绍日志的另一个部分,操作日志,主要去描述SysLogger日志的工作原理,流程以及其中关键的实现:日志轮转,刷盘性能问题等&#xff…

GUI07-学工具栏,懂MVC

MVC模式,是天底下编写GUI程序最为经典、实效的一种软件架构模式。当一个人学完菜单栏、开始学习工具栏时,就是他的一生中,最适合开始认识 MVC 模式的好时机之一。这节将安排您学习: Model-View-Controller 模式如何创建工具栏以及…

如何编辑调试gradle,打印日志

在build.gradle.kts中输入 println("testxwg1 ") logger.lifecycle("testxwg2") logger.log(LogLevel.ERROR,"testxwg5") 点刷新就能看到打印日志了

jvm栈帧中的动态链接

“-Xss”这一名称并没有一个特定的“为什么”来解释其命名,它更多是JVM(Java虚拟机)配置参数中的一个约定俗成的标识。在JVM中,有多个配置参数用于调整和优化Java应用程序的性能,这些参数通常以一个短横线“-”开头&am…

怎么将pdf中的某一个提取出来?介绍几种提取PDF中页面的方法

怎么将pdf中的某一个提取出来?传统上,我们可能通过手动截取屏幕或使用PDF阅读器的复制功能来提取信息,但这种方法往往不够精确,且无法保留原文档的排版和格式。此外,很多时候我们需要提取的内容可能涉及多个页面、多个…

TCP常见问题

文章目录 一、两种状态图二、常见问题1、MSL是什么 3、为何等待2MSL3、为何三次握手,不握手、握手一次、两次行吗4、为何四次挥手,三次行吗,两次行吗 一、两种状态图 四次挥手 二、常见问题 1、MSL是什么 MSL是Maximum Segment Lifetime的英…

UG NX二次开发(C#)-机电概念设计-UIStyler中selection块选择信号等对象的过滤器设置

文章目录 1、前言2、创建机电概念设计的模型3、创建UIStyler4、在VS2022中创建NXOPEN CSHAP的工程5、设置信号与信号适配体的过滤器6、测试选择的对象1、前言 在UG NX二次开发过程中,经常会用到UIStyler中的Selection块,即是选择对象,选择对象由于其可以选择多种类型的对象…

线程知识总结(二)

本篇文章以线程同步的相关内容为主。线程的同步机制主要用来解决线程安全问题,主要方式有同步代码块、同步方法等。首先来了解何为线程安全问题。 1、线程安全问题 卖票示例,4 个窗口卖 100 张票: class Ticket implements Runnable {priv…

es 开启slowlog

在 Elasticsearch 中,slowlog(慢日志)是用来记录查询和索引操作的性能数据,帮助你诊断性能瓶颈。你可以为查询 (search slowlog) 和索引 (index slowlog) 配置慢日志。 数据准备 POST /products/_doc/1 {"product_name&quo…

前端yarn工具打包时网络连接问题排查与解决

最近线上前端打包时提示 “There appears to be trouble with your network connection”,以此文档记录下排查过程。 前端打包方式 docker启动临时容器打包,命令如下 docker run --rm -w /app -v pwd:/app alpine-node-common:v16.20-pro sh -c "…

【YOLO 项目实战】(10)YOLO8 环境配置与推理检测

欢迎关注『youcans动手学模型』系列 本专栏内容和资源同步到 GitHub/youcans 【YOLO 项目实战】(1)YOLO5 环境配置与检测 【YOLO 项目实战】(10)YOLO8 环境配置与推理检测 【YOLO5 项目实战】(10)YOLO8 环境…

【蓝桥杯】43699-四平方和

四平方和 题目描述 四平方和定理,又称为拉格朗日定理: 每个正整数都可以表示为至多 4 个正整数的平方和。如果把 0 包括进去,就正好可以表示为 4 个数的平方和。 比如: 502021222 712121222; 对于一个给定的正整数,可…

【5G】5G 无线协议 Radio Protocols(一)

长期演进(LTE)无线电协议主要设计用于通过扁平架构提供PS服务,相比之前的代际,这代表了一个重大改进,它消除了支持电路交换(CS)服务和复杂架构中固有的复杂性。许多原始的LTE原则自第8版以来一直…

VMware ubuntu虚拟机网络配置

首先分清2个情况: 1、在使用笔记本时,WiFi联网使用时,使用的是无线网卡设备上网的。 2、无论是笔记本还是台式机,当接插网线上网时,使用的是以太网卡设备上网的。 以Windows11为例: (1&#x…

Y3编辑器教程7:界面编辑器

文章目录 一、简介1.1 导航栏1.2 画板1.3 场景界面1.4 控件1.4.1 空节点1.4.2 按钮1.4.3 图片1.4.4 模型1.4.5 文本1.4.6 输入框1.4.7 进度条1.4.8 列表 1.5 元件1.5.1 简介1.5.2 差异说明1.5.3 元件实例的覆盖、还原与禁止操作1.5.4 迷雾控件 1.6 属性1.7 事件(动画…

分享一个把表格类型的数据转换成字符串,以表格样式输出,方便控制台和日志记录时更直观

调用实例&#xff1a; Console.WriteLine("Hello, World!");List<string[]> tabLog new List<string[]>(); tabLog.Add(new string[] { "编号", "姓名", "性别", "年龄","备注" }); tabLog.Add(new…

如何有效修复ffmpeg.dll错误:一站式解决方案指南

当您遇到提示“ffmpeg.dll文件丢失”的错误时&#xff0c;这可能导致相关的应用程序无法启动或运行异常。本文将详细介绍如何有效地解决ffmpeg.dll文件丢失的问题&#xff0c;确保您的应用程序能够恢复正常运行。 ffmpeg.dll是什么&#xff1f;有哪些功能&#xff1f; ffmpeg.…

精通Redis(一)

目录 1.NoSQL 非关系型数据库 2.Redis 3.Redis的java客户端 4.Jedis 4.1Jedis快速入门 4.2Jedis连接池及使用 5.SpringDataRedis和RedisTemplate 1.NoSQL 非关系型数据库 基础篇-02.初始Redis-认识NoSQL_哔哩哔哩_bilibili NoSQL与SQL的区别就在于SQL是结构化的、关联…