生成对抗:Pix2Pix

news2024/11/20 11:37:33

cGAN : Pix2Pix

  生成对抗网络还有一个有趣的应用就是,图像到图像的翻译。例如:草图到照片,黑白图像到RGB,谷歌地图到卫星视图,等等。Pix2Pix就是实现图像转换的生成对抗模型,但是Pix2Pix中的对抗网络又不同于普通的GAN,称之为cGAN,全称是:conditional GAN。

cGAN和GAN的区别:
  • 传统的GAN从数据中学习从随机噪声向量 z z z到真是图像 y y y的映射: G ( z ) → y G(z)\to y G(z)y
  • 条件GAN学习的是学习从输入图像 x x x和随机噪声 z z z到目标图像 y y y的映射: G ( x , z ) → y G(x, z) \to y G(x,z)y
  • 传统的GAN中判别器只根据真实或生成图像辨别真伪: D ( y ) D(y) D(y) | D ( G ( x ) ) D(G(x)) D(G(x))
  • 条件GAN中判别器还加入了,观察图像 x x x D ( x , y ) D(x, y) D(x,y) | D ( x , G ( x , z ) ) D(x, G(x, z)) D(x,G(x,z))
  • 在cGAN中,生成器损失中又增加了 L 1 \mathcal L_1 L1损失
cGAN的Loss

L c G A N ( G , D ) = E x , y [ l o g D ( x , y ) ] + E x , z [ l o g ( 1 − D ( x , G ( x , z ) ) ] \mathcal L_{cGAN}(G,D) = E_{x,y}[log D(x,y)] + E_{x,z}[log(1 - D(x, G(x, z))] LcGAN(G,D)=Ex,y[logD(x,y)]+Ex,z[log(1D(x,G(x,z))]

L L 1 ( G ) = E x , y , z [ ∣ ∣ y − G ( x , z ) ∣ ∣ 1 ] \mathcal L_{L1}(G) = E_{x, y, z}[||y - G(x, z)||_1] LL1(G)=Ex,y,z[∣∣yG(x,z)1]

G ∗ = a r g m i n G m a x D L c G A N ( G , D ) + λ L L 1 ( G ) G^* = {argmin}_{G}max_{D}\mathcal L_{cGAN}(G,D) + \lambda \mathcal L_{L1}(G) G=argminGmaxDLcGAN(G,D)+λLL1(G)

Input Image
Target Image
Generate Image
Input Image + Target Image
Input Image + Generate Image
Generator
Discriminator
Disc Real
Disc Generate
Generator Loss
Discriminator Loss
Total Loss

环境

tensorflow 2.6.0
GPU RTX2080ti

数据集

  一个大规模数据集,其中包含来自50个不同城市的街景中记录的各种立体视频序列,除了更大的20,000个弱注释帧外,还具有5000帧的高质量像素级注释。因此,该数据集比以前的类似尝试大一个数量级。

城市景观数据集适用于:

  • 评估视觉算法在语义城市场景理解主要任务中的性能:像素级、实例级和全景语义标注。
  • 支持旨在利用大量(弱)注释数据的研究,例如用于训练深度神经网络。
import os
import pathlib
import numpy as np
from tqdm import tqdm
import matplotlib.pyplot as plt

import tensorflow as tf
from tensorflow.keras.layers import *
from tensorflow.keras.losses import BinaryCrossentropy
from tensorflow.keras.models import *
from tensorflow.keras.optimizers import Adam

数据集中的每一个样本都由一对图像组成:原始街景和像素级分割结果,下面的实验把左边作为输入,把分割的结果作为输出,训练一个实现街景分割的生成模型。

在这里插入图片描述

数据加载和预处理

IMAGE_HEIGHT = 256
IMAGE_WIDTH = 256
BUFFER_SIZE = 200
# produced better results for the U-Net in the original pix2pix
BATCH_SIZE = 1
NEAREST_NEIGHBOR = tf.image.ResizeMethod.NEAREST_NEIGHBOR
def load_split_image(image_path):
    image = tf.io.read_file(image_path)
    image = tf.image.decode_jpeg(image)
    width = tf.shape(image)[1]
    width = width // 2
    input_image = image[:, :width, :]
    real_image = image[:, width:, :]
    input_image = tf.cast(input_image, tf.float32)
    real_image = tf.cast(real_image, tf.float32)
    return input_image, real_image
def resize(input_image, real_image, height, width):
    input_image = tf.image.resize(input_image, size=(height,width), method=NEAREST_NEIGHBOR)
    real_image = tf.image.resize(real_image, size=(height, width), method=NEAREST_NEIGHBOR)
    return input_image, real_image
# 数据增强:随机剪裁
def random_crop(input_image, real_image):
    stacked_image = tf.stack([input_image, real_image],axis=0)
    size = (2, IMAGE_HEIGHT, IMAGE_WIDTH, 3)
    cropped_image = tf.image.random_crop(stacked_image, size=size)
    input_image = cropped_image[0]
    real_image = cropped_image[1]
    return input_image, real_image
def normalize(input_image, real_image):
    input_image = (input_image / 127.5) - 1
    real_image = (real_image / 127.5) - 1
    return input_image, real_image
@tf.function
def random_jitter(input_image, real_image):
    input_image, real_image = resize(input_image, real_image, width=286,height=286)
    # 随机剪裁 -> 256x256
    input_image, real_image = random_crop(input_image,real_image)
    # 随机反转
    if np.random.uniform() > 0.5:
        input_image = tf.image.flip_left_right(input_image)
        real_image = tf.image.flip_left_right(real_image)
    return input_image, real_image
加载训练/测试数据
def load_image_train(image_file):
    input_image, real_image = load_split_image(image_file)
    input_image, real_image = random_jitter(input_image, real_image)
    input_image, real_image = normalize(input_image, real_image)
    return input_image, real_image
def load_image_test(image_file):
    input_image, real_image = load_split_image(image_file)
    input_image, real_image = resize(input_image, real_image,IMAGE_HEIGHT, IMAGE_WIDTH)
    input_image, real_image = normalize(input_image, real_image)
    return input_image, real_image
数据流
train_dataset = tf.data.Dataset.list_files('./SeData/cityscapes/train/*.jpg')
train_dataset = train_dataset.map(load_image_train, num_parallel_calls=tf.data.AUTOTUNE)
train_dataset = train_dataset.shuffle(BUFFER_SIZE)
train_dataset = train_dataset.batch(BATCH_SIZE)
test_dataset = tf.data.Dataset.list_files('./SeData/cityscapes/val/*.jpg')
test_dataset = test_dataset.map(load_image_test)
test_dataset = test_dataset.batch(BATCH_SIZE)

构建生成器

生成器的主干网络为:U-Net。U-Net 由编码器(下采样器)和解码器(上采样器)组成。

在这里插入图片描述

  • 编码器中的每个块为:Convolution -> Batch normalization -> Leaky ReLU
  • 解码器中的每个块为:Transposed convolution -> Batch normalization -> Dropout(应用于前三个块)-> ReLU
  • 编码器和解码器之间存在跳跃连接(在 U-Net 中)
下采样
def downsample(filters, size, apply_batchnorm=True):
    initializer = tf.random_normal_initializer(0., 0.02)
    result = tf.keras.Sequential()
    result.add(Conv2D(filters, size, strides=2, padding='same',
                      kernel_initializer=initializer, use_bias=False))
    if apply_batchnorm:
        result.add(BatchNormalization())
    result.add(LeakyReLU())
    return result
上采样
def upsample(filters, size, apply_dropout=False):
    initializer = tf.random_normal_initializer(0., 0.02)
    result = tf.keras.Sequential()
    result.add(Conv2DTranspose(filters, size, strides=2, padding='same',
                               kernel_initializer=initializer, use_bias=False))
    result.add(BatchNormalization())
    if apply_dropout:
        result.add(Dropout(0.5))
    result.add(ReLU())
    return result
生成器网络
def Generator():
    inputs = Input(shape=[256, 256, 3])
    down_stack = [downsample(32, 4, apply_batchnorm=False),  # (batch_size, 128, 128, 64)
                  downsample(64, 4),  # (batch_size, 64, 64, 128)
                  downsample(128, 4),  # (batch_size, 32, 32, 256)
                  downsample(256, 4),  # (batch_size, 16, 16, 512)
                  downsample(256, 4),  # (batch_size, 8, 8, 512)
                  #downsample(512, 4),  # (batch_size, 4, 4, 512)
                  #downsample(512, 4),  # (batch_size, 2, 2, 512)
                  #downsample(512, 4),  # (batch_size, 1, 1, 512)
                 ]

    up_stack = [#upsample(512, 4, apply_dropout=True),  # (batch_size, 2, 2, 1024)
                #upsample(512, 4, apply_dropout=True),  # (batch_size, 4, 4, 1024)
                #upsample(512, 4, apply_dropout=True),  # (batch_size, 8, 8, 1024)
                upsample(256, 4),  # (batch_size, 16, 16, 1024)
                upsample(128, 4),  # (batch_size, 32, 32, 512)
                upsample(64, 4),  # (batch_size, 64, 64, 256)
                upsample(32, 4),   # (batch_size, 128, 128, 128)
               ]

    initializer = tf.random_normal_initializer(0., 0.02)
    last = Conv2DTranspose(3, 4, strides=2, padding='same',
                           kernel_initializer=initializer, activation='tanh')  # (batch_size, 256, 256, 3)
    x = inputs
    # Downsampling through the model
    skips = []
    for down in down_stack:
        x = down(x)
        skips.append(x)
    skips = reversed(skips[:-1])
    # Upsampling and establishing the skip connections
    for up, skip in zip(up_stack, skips):
        x = up(x)
        x = Concatenate()([x, skip])
    x = last(x)
    return tf.keras.Model(inputs=inputs, outputs=x)
generator = Generator()
生成器损失

定义生成器损失,GA该损失会惩罚与网络输出和目标图像不同的可能结构。

  • 生成器损失是生成图像和一数组的 sigmoid 交叉熵损失。
  • L1 损失,它是生成图像与目标图像之间的 MAE(平均绝对误差),这样可使生成的图像在结构上与目标图像相似。
  • 生成器损失的公式为:gan_loss + LAMBDA * l1_loss,其中 LAMBDA = 100。该值由论文作者决定。

G l o s s = E x , z [ l o g ( 1 − D ( x , G ( x , z ) ) ] + E x , y , z [ ∣ ∣ y − G ( x , z ) ∣ ∣ 1 ] G_{loss} = E_{x,z}[log(1 - D(x, G(x, z))] + E_{x, y, z}[||y - G(x, z)||_1] Gloss=Ex,z[log(1D(x,G(x,z))]+Ex,y,z[∣∣yG(x,z)1]

LAMBDA = 100
loss_object = tf.keras.losses.BinaryCrossentropy(from_logits=True)
def generator_loss(disc_generated_output, gen_output, target):
    gan_loss = loss_object(tf.ones_like(disc_generated_output), disc_generated_output)
    # Mean absolute error
    l1_loss = tf.reduce_mean(tf.abs(target - gen_output))
    total_gen_loss = gan_loss + (LAMBDA * l1_loss)
    return total_gen_loss, gan_loss, l1_loss

构建判别器

cGAN 中的判别器是一个卷积“PatchGAN”分类器,它会尝试对每个图像分块的真实与否进行分类。

  • 判别器中的每个块为:Convolution -> Batch normalization -> Leaky ReLU。
  • 最后一层之后的输出形状为 (batch_size, 30, 30, 1)。
  • 输出的每个 30 x 30 图像分块会对输入图像的 70 x 70 部分进行分类。
  • 判别器接收 2 个输入:
    • 输入图像和目标图像,应分类为真实图像。
    • 输入图像和生成图像(生成器的输出),应分类为伪图像。
  • 使用tf.concat([inp, tar], axis=-1) 将这 2 个输入连接在一起。
def Discriminator():
    initializer = tf.random_normal_initializer(0., 0.02)
    inp = Input(shape=[256, 256, 3], name='input_image')
    tar = Input(shape=[256, 256, 3], name='target_image')
    x = concatenate([inp, tar])          # (batch_size, 256, 256, channels*2)
    down1 = downsample(64, 4, False)(x)  # (batch_size, 128, 128, 64)
    down2 = downsample(128, 4)(down1)    # (batch_size, 64, 64, 128)
    down3 = downsample(256, 4)(down2)    # (batch_size, 32, 32, 256)
    zero_pad1 = ZeroPadding2D()(down3)   # (batch_size, 34, 34, 256)
    conv = Conv2D(512, 4, strides=1, kernel_initializer=initializer,
                  use_bias=False)(zero_pad1)                                 # (batch_size, 31, 31, 512)
    batchnorm1 = BatchNormalization()(conv)
    leaky_relu = LeakyReLU()(batchnorm1)
    zero_pad2 = ZeroPadding2D()(leaky_relu)                                   # (batch_size, 33, 33, 512)
    last = Conv2D(1, 4, strides=1,kernel_initializer=initializer)(zero_pad2)  # (batch_size, 30, 30, 1)
    return Model(inputs=[inp, tar], outputs=last)
discriminator = Discriminator()
判别器损失

discriminator_loss 函数接收 2 个输入:真实图像和生成图像输入判别器后的输出。

  • real_loss 是真实图像和一组 1的 sigmoid 的交叉熵损失(因为这些是真实图像)
  • generated_loss 是生成图像和一组 0 的 sigmoid 交叉熵损失(因为这些是伪图像)
  • total_loss 是 real_loss 和 generated_loss 的和
def discriminator_loss(disc_real_output, disc_generated_output):
    real_loss = loss_object(tf.ones_like(disc_real_output), disc_real_output)
    generated_loss = loss_object(tf.zeros_like(disc_generated_output), disc_generated_output)
    total_disc_loss = real_loss + generated_loss
    return total_disc_loss

优化器和检查点

generator_opt = tf.keras.optimizers.Adam(2e-4, beta_1=0.5)
discriminator_opt = tf.keras.optimizers.Adam(2e-4, beta_1=0.5)
checkpoint_dir = './training_checkpoints'
checkpoint_prefix = os.path.join(checkpoint_dir, "ckpt")
checkpoint = tf.train.Checkpoint(generator_optimizer=generator_opt,
                                 discriminator_optimizer=discriminator_opt,
                                 generator=generator,
                                 discriminator=discriminator)

训练模型

  1. 生成器接收 input_image 输出 generate_image (gen_output)
  2. 判别器接收 input_image 和 target_image 输出判别结果 disc_real_ouput
  3. 判别器接收 input_image 和 gen_output 生成图像 输出判别结果 disc_generated_output
  4. 计算生成器和判别器损失
  5. 计算损失相对于生成器和判别器变量(输入)的梯度,并将其应用于优化器
  6. 记录损失到 TensorBoard
import time
import datetime
from IPython import display
log_dir="./logs/"

summary_writer = tf.summary.create_file_writer(log_dir + "fit/" + datetime.datetime.now().strftime("%Y%m%d-%H%M%S"))
def generate_images(model, test_input, tar):
    prediction = model(test_input, training=True)
    plt.figure(figsize=(12, 12))

    display_list = [test_input[0], tar[0], prediction[0]]
    title = ['Input Image', 'Ground Truth', 'Predicted Image']

    for i in range(3):
        plt.subplot(1, 3, i+1)
        plt.title(title[i])
        # Getting the pixel values in the [0, 1] range to plot.
        plt.imshow(display_list[i] * 0.5 + 0.5)
        plt.axis('off')
    plt.show()
@tf.function
def train_step(input_image, target, step):
    with tf.GradientTape() as gen_tape, tf.GradientTape() as disc_tape:
        gen_output = generator(input_image, training=True)
        
        disc_real_output = discriminator([input_image, target], training=True)
        
        disc_generated_output = discriminator([input_image, gen_output], training=True)
        
        gen_total_loss, gen_gan_loss, gen_l1_loss = generator_loss(disc_generated_output, gen_output, target)
        disc_loss = discriminator_loss(disc_real_output, disc_generated_output)
        
        generator_gradients = gen_tape.gradient(gen_total_loss, generator.trainable_variables)
        discriminator_gradients = disc_tape.gradient(disc_loss, discriminator.trainable_variables)

        generator_opt.apply_gradients(zip(generator_gradients, generator.trainable_variables))
        discriminator_opt.apply_gradients(zip(discriminator_gradients, discriminator.trainable_variables))

    with summary_writer.as_default():
        tf.summary.scalar('gen_total_loss', gen_total_loss, step=step//1000)
        tf.summary.scalar('gen_gan_loss', gen_gan_loss, step=step//1000)
        tf.summary.scalar('gen_l1_loss', gen_l1_loss, step=step//1000)
        tf.summary.scalar('disc_loss', disc_loss, step=step//1000)
def fit(train_ds, test_ds, steps):
    example_input, example_target = next(iter(test_ds.take(1)))
    start = time.time()
    for step, (input_image, target) in train_ds.repeat().take(steps).enumerate():
        if (step) % 1000 == 0:
            display.clear_output(wait=True)

            if step != 0:
                print(f'Time taken for 1000 steps: {time.time()-start:.2f} sec\n')
            start = time.time()
            generate_images(generator, example_input, example_target)    # 打印测试效果
            print(f"Step: {step//1000}k")
        train_step(input_image, target, step)

        # Training step
        if (step+1) % 10 == 0:
            print('.', end='', flush=True)
            
        # Save (checkpoint) the model every 5k steps
        if (step + 1) % 5000 == 0:
            checkpoint.save(file_prefix=checkpoint_prefix)
%load_ext tensorboard
%tensorboard --logdir {log_dir} 
fit(train_dataset, test_dataset, steps=40000)
Time taken for 1000 steps: 21.16 sec

在这里插入图片描述

Step: 39k
....................................................................................................

检查训练结果

  • 如果 gen_gan_loss 或 disc_loss 变得很低,则表明此模型正在支配另一个模型,并且您未能成功训练组合模型。
  • 值 log(2) = 0.69 是这些损失的一个良好参考点,因为它表示困惑度为 2:判别器的平均不确定性是相等的。
  • 对于 disc_loss,低于 0.69 的值意味着判别器在真实图像和生成图像的组合集上的表现要优于随机数。
  • 对于 gen_gan_loss,如果值小于 0.69,则表示生成器在欺骗判别器方面的表现要优于随机数。
  • 随着训练的进行,gen_l1_loss 应当下降

从最新检查点恢复并测试模型

ls {checkpoint_dir}
checkpoint                  ckpt-3.data-00000-of-00001
ckpt-1.data-00000-of-00001  ckpt-3.index
ckpt-1.index                ckpt-4.data-00000-of-00001
ckpt-2.data-00000-of-00001  ckpt-4.index
ckpt-2.index
# Restoring the latest checkpoint in checkpoint_dir
checkpoint.restore(tf.train.latest_checkpoint(checkpoint_dir))
<tensorflow.python.training.tracking.util.CheckpointLoadStatus at 0x7f956c1a23d0>
# Run the trained model on a few examples from the test set
for inp, tar in test_dataset.take(3):
      generate_images(generator, inp, tar)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

测试网上的街景图片

def load_image(image_path):
    image = tf.io.read_file(image_path)
    image = tf.image.decode_jpeg(image)
    image = tf.image.resize(image, size=(256, 256), method=NEAREST_NEIGHBOR)
    image = tf.cast(image, tf.float32)
    return image
img1 = load_image('./test/city_test4.jpg')

img1 = img1 / 127.5 - 1

img1 = tf.expand_dims(img1, axis=0)
pred1 = generator(img1, training=False)
plt.figure(figsize=(8, 8))
plt.subplot(1, 2, 1)
plt.title("Input Image")
plt.imshow(img1[0] * 0.5 + 0.5)
plt.axis('off')
plt.subplot(1, 2, 2)
plt.title("Predicted Image")
plt.imshow(pred1[0] * 0.5 + 0.5)
plt.axis('off')

在这里插入图片描述

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

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

相关文章

计网第三章.数据链路层—可靠传输

以下来自湖科大计算机网络公开课的笔记 文章目录0.基本概念1. 停止等待协议SW2. 回退N帧协议GBN3. 选择重传SR首先&#xff0c;这部分说的可靠传输的实现机制不只限于数据链路层&#xff0c;而是适用于整个计算机网络体系 0.基本概念 一般情况下&#xff0c;有线链路的误码率…

Docker 中的挂载卷

我们现在有这样一个需求。 我们有一个 Spring 的项目是部署在容器中的&#xff0c;如果不进行任何配置的话&#xff0c;这个项目运行的所有日子都会在容器中。 当容器重启说着终止后&#xff0c;上面的日志比较难进行查看。 我们希望我们的日志同时也记录在操作系统中&#…

阿贡国家实验室:量子中继器及其在量子网络中的作用

很多人小时候都玩过传声筒游戏&#xff1a;A将消息小声告诉B&#xff0c;然后B将他听到的内容小声告诉C&#xff0c;依此类推&#xff0c;玩过的人都知道&#xff0c;最后传达到的信息往往和真实消息完全不同。 从某种意义上说&#xff0c;这和中继器技术的重要性强相关。中继器…

MySQL锁,锁的到底是什么?

只要学计算机&#xff0c;「锁」永远是一个绕不过的话题。MySQL锁也是一样。 一句话解释MySQL锁&#xff1a; MySQL锁是解决资源竞争的一种方案。 短短一句话却包含了3点值得我们注意的事情&#xff1a; 对什么资源进行竞争&#xff1f;竞争的方式&#xff08;或者说情形&a…

舆情监控和应急处理方案,如何做好网络舆情监控?

舆情监控是指通过不同的渠道&#xff0c;如社交媒体、新闻媒体、博客、论坛等&#xff0c;对公众的言论进行收集、分析、评估和反馈的过程。舆情监控的目的是帮助企业或组织了解公众的观点和情绪&#xff0c;并且能够及时做出回应&#xff0c;避免可能出现的舆论危机。接下来TO…

2022年度投影仪行业数据分析报告:十大热门品牌排行榜

在当前的大环境下&#xff0c;线下娱乐受阻&#xff0c;而用户对于足不出户的观影、娱乐需求推动着智能投影设备的增长。近几年来&#xff0c;投影仪行业保持着较快速度的增长&#xff0c;面对整体市场需求不振的形势&#xff0c;投影仪仍在保持正向增长。随着家用智能投影在市…

Charles - 阻塞请求、修改请求与响应内容、重定向请求地址、指定文件为响应内容

1、阻塞请求 1、鼠标放在指定接口上 > 右键 > 勾选 Block List 2、重新访问这接口&#xff0c;这条请求被阻塞&#xff0c;不会有返回信息 取消阻塞接口&#xff1a; 鼠标放在指定接口上 > 右键 > 取消勾选 Block List 2、修改请求与响应内容 第一步&#xff1…

【一文看懂 ES 核心】存储查询集群

一文看懂 ES 核心 Elasticsearch 作为一个搜索引擎&#xff0c;其可以提供高效的搜索匹配数据的能力&#xff0c;对于这类工具了解其运行原理其实是有一套功法的。 聊存储&#xff0c;ES 是如何存储数据的&#xff1f;聊方法&#xff0c;ES 是如何进行搜索匹配的&#xff1f;…

【Linux】文件描述符、文件操作、重定向的模拟实习

目录 一、重温C语言文件操作 1.1 文件打开方式 1.2 文件写操作 1.3 文件读操作 1.3 标准输入输出 二、系统接口的使用 2.1 open 函数 2.2 close 函数 2.3 write 函数 2.4 read 函数 三、文件描述符 3.1 如何管理文件 3.2 0 & 1 & 2 3.3 文件描述符的分配…

种草!超好用的PDF转换器上线啦~

宝子们 重磅福利来啦 你还在为每次转换文件头疼吗 老铁&#xff0c;大拿版万能转换器正式上线啦 以前的文件转换器&#xff0c;不是充会员就是收费高 最坑的是花钱还解决不了问题 每次转换文件内容有误.... 特殊符号或者公式更是无法有效转换 为了整顿这种局面&#xff0c…

KKT条件理解

我们知道拉格朗日函数是用于等式约束的优化问题求解的&#xff0c;然KKT条件是针对含有不等式约束的优化问题的。 首先&#xff0c;我们先给出优化目标&#xff1a; 因此&#xff0c;根据优化目标&#xff0c;我们同样可以构造处拉格朗日函数&#xff0c;并对其进行优化&#…

ssh免密登录

准备两台linux主机 主机A&#xff1a;192.168.92.131 主机B&#xff1a;192.168.92.132 使用主机B去免密访问主机A 在主机B上执行 ssh-keygen -t rsa ssh-keygen 生成密码对 -t rsa 指定生成 rsa 密钥对 密钥对文件默认放在 家目录下面的 .ssh 目录下 root 用户默认放在 /ro…

一、数据库开发与实战专栏导学及数据库基础概念入门

文章目录一、专栏导学1.1 课程内容1.2 学习安排1.3 适合人群1.4 学习方法二、认识数据库2.1 生活中的数据库2.2 数据管理技术的3个发展阶段2.3 数据库、关系型数据库、非关系型数据库概念2.4 为什么要使用数据库2.5 数据库系统及其组成部分2.6 常用数据库访问接口简介2.7 数据库…

【2】Go语言的语法

一、Go语言基础组成 Go语言基础组成&#xff1a; 包申明引入包函数变量语句&表达式注释实例&#xff1a; package main //申明包 import "fmt" /* 这是一个朴实无华的注释 */ func main() { fmt.Printf("mogu") } 实现流程&#xff1a; 第一行&#…

kafka简介

目录 partition和consumer group offset的管理 kafka的事务 幂等producer 事务producer 怎么理解trasactional.id 两阶段2pc简介 kafka的消息传输保证 producer端 broker端 consumer端 消息挤压 kafak的存储 kafka的高性能 附录-kafka demo kafaka的发布-订阅模…

Rust之常用集合(三):哈希映射(Hash Map)

开发环境 Windows 10Rust 1.66.0VS Code 1.74.2项目工程 这里继续沿用上次工程rust-demo 在哈希图中存储带有关联值的键 我们常见的集合中的最后一个是哈希映射。HashMap<K, V>类型使用散列函数存储K类型的键到V类型的值的映射&#xff0c;这决定了它如何将这些键和值…

Vue2.0

JavaScript&#xff08;JS 教程&#xff09; - JavaScript | MDN Vue是构建用户界面的 JavaScript 框架 安装 — 2.0 Vue.jsGitHub - vuejs/devtools: ⚙️ Browser devtools extension for debugging Vue.js applications.Installation | Vue DevtoolsVSCode插件&#xff1a…

【SpringMVC】SpringMVC整合Mybatis

1.整合思路 第一步&#xff1a;整合dao层 mybatis和spring整合&#xff0c;通过spring管理mapper接口使用mapper的扫描自动扫描mapper接口在spring中进行注册 第二步&#xff1a;整合service层 通过spring管理service接口使用配置方式将service接口配置在spring配置文件中实现…

如何能有兴趣的编代码,而不是畏难?

如果我告诉你&#xff0c;成功做出一道代码题拿下5万美元&#xff0c;做出四道代码题20万美金的年薪到手&#xff0c;你是不是会立刻发愤图强呢&#xff1f;这不是个段子&#xff0c;是北美程序员的面试情况&#xff1a;有小伙伴刷题的过程中觉得刷不下去了&#xff0c;就以此来…

【Javassist】快速入门系列10 当检测到instanceof表达式时用代码块替换

系列文章目录 01 在方法体的开头或结尾插入代码 02 使用Javassist实现方法执行时间统计 03 使用Javassist实现方法异常处理 04 使用Javassist更改整个方法体 05 当有指定方法调用时替换方法调用的内容 06 当有构造方法调用时替换方法调用的内容 07 当检测到字段被访问时使用语…