CV大作业28期-使用TensorFlow快速实现图像风格迁移系统

使用TensorFlow快速实现图像风格迁移系统

资源地址:待更新

视频地址:待更新

随着GPT的横空出世,生成式网络也越来越活,现在的大语言模型除了能回答文字上面的内容,并且在图像和视频创作中也表现除了巨大的潜力,今天我们继续大作业系列,以比较早的一篇李飞飞博士的快速风格迁移为例,给大家展示一下早期是如何利用卷积神经网络来进行图像风格迁移的。具体我们要实现的效果如下,通过tensorflow框架构建快速图像分割迁移的网络并利用训练好的四个模型实现对任意上传图片的风格迁移,并利用PyQt5构建图形化的界面来完成最终的系统。

先来一起看看效果吧。

image-20240525173529359

image-20240525173601761

背景与意义

图像风格迁移技术旨在将一幅图像(风格图像)的艺术风格应用到另一幅图像(内容图像)上,同时保留内容图像的主要内容。该技术在艺术创作、广告设计、游戏开发等多个领域具有广泛的应用价值。通过深度学习算法,图像风格迁移技术能够自动地识别和提取图像中的风格和内容特征,实现高效的风格转换。

图像风格迁移技术主要基于深度学习算法,尤其是卷积神经网络(CNN)。这些网络能够提取图像中的多层级特征,从而实现对图像内容和风格的分离与重组。在风格迁移过程中,通常使用预训练的CNN模型(如VGGNet、Inception等)来提取图像的特征。

发展历程

  1. 基于优化算法的风格迁移:最早的图像风格迁移方法是通过优化算法来最小化原始图像与目标图像在风格和内容上的差异。这种方法能够生成高质量的风格迁移图像,但计算成本较高且速度较慢。
  2. 基于卷积神经网络的快速风格迁移:2015年,Gatys等人提出了基于CNN的图像风格迁移方法,大大提高了迁移效果和速度。随后,Huang等人提出了快速风格迁移网络,将原有的优化算法简化为一个前向神经网络,实现了实时的图像风格迁移。
  3. 循环一致性生成网络:2017年出现的CycleGAN、MUNIT等循环一致性生成网络,可以在不需要成对训练数据的情况下完成图像的风格迁移等任务。

技术原理

论文地址:[1603.08155] Perceptual Losses for Real-Time Style Transfer and Super-Resolution (arxiv.org)

我们要探讨的这篇论文是16年的一个工作,论文的地址如上。

这篇论文的标题是《Perceptual Losses for Real-Time Style Transfer and Super-Resolution》,作者是Justin Johnson, Alexandre Alahi, 和 Li Fei-Fei,来自斯坦福大学计算机科学系。论文主要研究了实时风格迁移和超分辨率图像重建的问题。

摘要

摘要的部分:作者探讨了图像转换问题,即如何将输入图像转换成输出图像。以往的方法通常训练前馈卷积神经网络,使用逐像素损失函数来衡量输出图像和真实图像之间的差异。但是,这些方法并没有捕捉到图像之间的感知差异。与此同时,也有研究通过定义和优化基于预训练网络提取的高级特征的感知损失函数来生成高质量图像。本文结合了这两种方法的优点,提出使用感知损失函数来训练图像转换任务的前馈网络。实验结果表明,在风格迁移任务中,与基于优化的方法相比,所提出的网络在生成相似质量结果的同时,速度快了三个数量级。此外,作者还尝试了单图像超分辨率任务,发现用感知损失替换逐像素损失可以得到视觉上令人满意的结果。

主要内容概述

  1. 引言部分:介绍了图像转换任务的经典问题,如去噪、超分辨率和着色等,并讨论了使用逐像素损失函数训练前馈卷积神经网络的方法及其局限性。

  2. 相关工作:回顾了前馈图像转换、感知优化、风格迁移和图像超分辨率等领域的相关研究。

  3. 方法:介绍了系统由两部分组成:图像转换网络和用于定义多个损失函数的损失网络。详细阐述了网络结构、输入输出、下采样和上采样以及残差连接等内容。

    image-20240525164131104

  4. 感知损失函数:定义了两种感知损失函数——特征重建损失和风格重建损失,用于衡量图像之间的高级感知和语义差异。

    image-20240525164447008

    image-20240525164458973

  5. 简单损失函数:除了感知损失外,还定义了依赖于低级像素信息的简单损失函数,如像素损失和总变分正则化。

  6. 实验:在风格迁移和单图像超分辨率两个图像转换任务上进行了实验,展示了所提方法与现有方法的比较,并讨论了结果。

  7. 结论:作者通过将前馈图像转换任务和基于优化的图像生成方法的优点结合起来,使用感知损失函数训练前馈转换网络,在风格迁移和单图像超分辨率任务上取得了显著的性能提升。

下面是一些实现效果的对比图,从图中可以看出,该方法实现的风格迁移从质量上均由于当时其他的方法,但是艺术这个东西实际上是不太好考量的,单纯从指标上来看迁移的好坏是不行滴。

image-20240525164517603

代码实现

老规矩所有的代码实现都需要你了解Anaconda和Pycharm这两个工具,这两个工具的使用教程可以这期博客。

代码使用Tensorflow实现,考虑到大家设备的兼容性,我这边安装的时候CPU版本的Tensorflow,低配置的同学也可以进行尝试。

首先我们先实现主干的特征提取网络,这里的主干特征提取网络选择的是VGG网络。

# Copyright (c) 2015-2016 Anish Athalye. Released under GPLv3.

import tensorflow as tf
import numpy as np
import scipy.io
import pdb

# 定义全局均值像素数组
MEAN_PIXEL = np.array([123.68, 116.779, 103.939])

# 定义神经网络函数
def net(data_path, input_image):
    # 定义网络各层的名称
    layers = (
        'conv1_1', 'relu1_1', 'conv1_2', 'relu1_2', 'pool1',

        'conv2_1', 'relu2_1', 'conv2_2', 'relu2_2', 'pool2',

        'conv3_1', 'relu3_1', 'conv3_2', 'relu3_2', 'conv3_3',
        'relu3_3', 'conv3_4', 'relu3_4', 'pool3',

        'conv4_1', 'relu4_1', 'conv4_2', 'relu4_2', 'conv4_3',
        'relu4_3', 'conv4_4', 'relu4_4', 'pool4',

        'conv5_1', 'relu5_1', 'conv5_2', 'relu5_2', 'conv5_3',
        'relu5_3', 'conv5_4', 'relu5_4'
    )

    # 从MATLAB文件中加载数据
    data = scipy.io.loadmat(data_path)
    mean = data['normalization'][0][0][0]
    mean_pixel = np.mean(mean, axis=(0, 1))
    weights = data['layers'][0]

    # 初始化一个空字典来保存每一层的输出
    net = {}
    current = input_image
    for i, name in enumerate(layers):
        kind = name[:4]
        if kind == 'conv': # 卷积层
            # 提取卷积核和偏置
            kernels, bias = weights[i][0][0][0][0]
            # matconvnet: weights are [width, height, in_channels, out_channels]
            # tensorflow: weights are [height, width, in_channels, out_channels]
            # 调整卷积核的维度顺序以适应TensorFlow
            kernels = np.transpose(kernels, (1, 0, 2, 3))
            bias = bias.reshape(-1)
            current = _conv_layer(current, kernels, bias)
        elif kind == 'relu':
            current = tf.nn.relu(current)
        elif kind == 'pool':
            current = _pool_layer(current)
        net[name] = current
    # 确保字典中的层数与定义的层数一致
    assert len(net) == len(layers)
    return net

# 定义卷积层函数
def _conv_layer(input, weights, bias):
    conv = tf.nn.conv2d(input, tf.constant(weights), strides=(1, 1, 1, 1),
                        padding='SAME')
    return tf.nn.bias_add(conv, bias)

# 定义池化层函数
def _pool_layer(input):
    return tf.nn.max_pool(input, ksize=(1, 2, 2, 1), strides=(1, 2, 2, 1),
                          padding='SAME')

# 定义图像预处理函数
def preprocess(image):
    return image - MEAN_PIXEL

# 定义图像后处理函数
def unprocess(image):
    # 将均值像素加回到图像中
    return image + MEAN_PIXEL

迁移网络的实现如下:

import tensorflow as tf, pdb

# 用于初始化网络权重的标准差,设置为0.1。
WEIGHTS_INIT_STDEV = .1


# 该函数接受一个图像作为输入,并通过多个卷积层、残差块和反卷积层进行处理。
# 最终,通过tanh激活函数将输出限制在[-1, 1]范围内,并线性变换到[0, 255]范围,这可能是为了与图像像素值的常见范围相匹配。
def net(image):
    conv1 = _conv_layer(image, 32, 9, 1)
    conv2 = _conv_layer(conv1, 64, 3, 2)
    conv3 = _conv_layer(conv2, 128, 3, 2)
    resid1 = _residual_block(conv3, 3)
    resid2 = _residual_block(resid1, 3)
    resid3 = _residual_block(resid2, 3)
    resid4 = _residual_block(resid3, 3)
    resid5 = _residual_block(resid4, 3)
    conv_t1 = _conv_tranpose_layer(resid5, 64, 3, 2)
    conv_t2 = _conv_tranpose_layer(conv_t1, 32, 3, 2)
    conv_t3 = _conv_layer(conv_t2, 3, 9, 1, relu=False)
    preds = tf.nn.tanh(conv_t3) * 150 + 255. / 2
    return preds


# 定义一个标准的卷积层,包括卷积操作、实例归一化和ReLU激活函数(可选)。
# num_filters:卷积核的数量。
# filter_size:卷积核的大小。
# strides:卷积步长。
# relu:是否在应用卷积后使用ReLU激活函数。
def _conv_layer(net, num_filters, filter_size, strides, relu=True):
    weights_init = _conv_init_vars(net, num_filters, filter_size)
    strides_shape = [1, strides, strides, 1]
    net = tf.nn.conv2d(net, weights_init, strides_shape, padding='SAME')
    net = _instance_norm(net)
    if relu:
        net = tf.nn.relu(net)

    return net


# 定义一个反卷积(或称为转置卷积)层,通常用于上采样或扩大特征图的尺寸。
# 该函数与_conv_layer类似,但使用的是tf.nn.conv2d_transpose进行反卷积操作。
def _conv_tranpose_layer(net, num_filters, filter_size, strides):
    weights_init = _conv_init_vars(net, num_filters, filter_size, transpose=True)

    batch_size, rows, cols, in_channels = [i.value for i in net.get_shape()]
    new_rows, new_cols = int(rows * strides), int(cols * strides)
    # new_shape = #tf.pack([tf.shape(net)[0], new_rows, new_cols, num_filters])

    new_shape = [batch_size, new_rows, new_cols, num_filters]
    tf_shape = tf.stack(new_shape)
    strides_shape = [1, strides, strides, 1]

    net = tf.nn.conv2d_transpose(net, weights_init, tf_shape, strides_shape, padding='SAME')
    net = _instance_norm(net)
    return tf.nn.relu(net)

# 定义一个残差块,它包含两个卷积层,并将输入(即“残差”)添加到第二个卷积层的输出上。
# 这种结构有助于网络学习恒等映射,从而更容易地进行优化,并可能提高性能。
def _residual_block(net, filter_size=3):
    tmp = _conv_layer(net, 128, filter_size, 1)
    return net + _conv_layer(tmp, 128, filter_size, 1, relu=False)

# 实现实例归一化(Instance Normalization),这是一种在风格迁移等任务中常用的归一化技术。
# 它对每个样本的每个通道分别进行归一化,与批量归一化不同,它不依赖于批次中的其他样本。
def _instance_norm(net, train=True):
    batch, rows, cols, channels = [i.value for i in net.get_shape()]
    var_shape = [channels]
    mu, sigma_sq = tf.nn.moments(net, [1, 2], keep_dims=True)
    shift = tf.Variable(tf.zeros(var_shape))
    scale = tf.Variable(tf.ones(var_shape))
    epsilon = 1e-3
    normalized = (net - mu) / (sigma_sq + epsilon) ** (.5)
    return scale * normalized + shift

# 用于初始化卷积层的权重。
# 权重使用截断的正态分布进行初始化,标准差由WEIGHTS_INIT_STDEV定义。
def _conv_init_vars(net, out_channels, filter_size, transpose=False):
    _, rows, cols, in_channels = [i.value for i in net.get_shape()]
    if not transpose:
        weights_shape = [filter_size, filter_size, in_channels, out_channels]
    else:
        weights_shape = [filter_size, filter_size, out_channels, in_channels]

    weights_init = tf.Variable(tf.truncated_normal(weights_shape, stddev=WEIGHTS_INIT_STDEV, seed=1), dtype=tf.float32)
    return weights_init

最后,我们将实现一个模型训练的代码,代码将完成的主要功能如下。

这段代码是一个用于图像风格迁移的Python脚本,它使用了TensorFlow框架和预训练的VGG网络。以下是代码的主要组成部分及其功能的解释:

  1. 导入模块:
    • print_function 来自 __future__ 用于保持兼容性。
    • functools 用于functools.reduce()函数。
    • pdb, time 是Python的内置模块,分别用于调试和时间测量。
    • tensorflow, numpy, os 是科学计算和操作系统相关的库。
    • src.transformsrc.vgg 似乎是自定义模块,用于图像转换和加载VGG网络。
    • src.utils 中的 get_img 函数可能用于加载和处理图像。
  2. 定义风格和内容层:
    • STYLE_LAYERS: 存储风格迁移使用的风格层的名字。
    • CONTENT_LAYER: 存储内容迁移使用的内容层的名字。
    • DEVICES: 可能用于设置GPU环境变量。
  3. 优化函数 optimize:
    • 这个函数执行风格迁移的主要逻辑。
    • 参数包括内容和风格图像的目标特征、权重、VGG模型的路径、训练轮数、打印间隔、批量大小、保存路径、学习率等。
    • 根据是否使用slow模式调整批量大小。
    • 计算风格图像的Gram矩阵并存储在style_features字典中。
    • 创建TensorFlow图,定义风格和内容图像的占位符,加载VGG网络,并计算损失函数。
    • 定义内容损失、风格损失和总变分正则化损失。
    • 执行训练步骤,更新生成图像的预测。
    • 迭代训练,打印损失并保存模型。
  4. TensorFlow图和会话:
    • 使用tf.Graph()tf.Session()创建TensorFlow计算图和会话。
    • tf.device('/gpu:0')指定操作在GPU上执行。
  5. 预处理和网络加载:
    • vgg.preprocess()函数用于预处理图像以匹配VGG网络的输入要求。
    • vgg.net()加载预训练的VGG网络。
  6. 损失函数计算:
    • 计算风格损失时,对每个风格层的特征图计算Gram矩阵,并与预先计算的风格图像的Gram矩阵比较。
    • 内容损失计算当前图像与内容目标特征的差异。
    • 总变分正则化损失鼓励生成图像的空间平滑性。
  7. 训练步骤:
    • 使用tf.train.AdamOptimizer定义优化器。
    • train_step运行优化器来最小化损失函数。
  8. 迭代和输出:
    • 函数通过迭代训练过程,每次迭代处理一批图像。
    • 根据迭代次数打印损失信息,并在训练结束或达到打印间隔时输出。
  9. 辅助函数 _tensor_size:
    • 计算给定张量的大小。
from __future__ import print_function
import functools
import src.vgg as vgg
import pdb, time
import tensorflow as tf, numpy as np, os
import src.transform as transform
from src.utils import get_img

# 首先是确定风格层和内容层,这里的风格层使用多个,然后内容层仅仅使用一个
STYLE_LAYERS = ('relu1_1', 'relu2_1', 'relu3_1', 'relu4_1', 'relu5_1')
CONTENT_LAYER = 'relu4_2'
DEVICES = 'CUDA_VISIBLE_DEVICES'


# np arr, np arr
# 确定参数,内容图片、风格图片、各自的权重,vgg的路径,轮数,打印次数,batch_size的大小,保存路径和学习率
def optimize(content_targets, style_target, content_weight, style_weight,
             tv_weight, vgg_path, epochs=2, print_iterations=1000,
             batch_size=4, save_path='saver/fns.ckpt', slow=False,
             learning_rate=1e-3, debug=False):

    if slow:
        batch_size = 1
    mod = len(content_targets) % batch_size
    if mod > 0:
        # 对图片进行切割的操作
        print("Train set has been trimmed slightly..")
        content_targets = content_targets[:-mod]

    # 把风格图片的风格特征固定在字典中
    style_features = {}

    # 固定内容和风格的形状
    batch_shape = (batch_size, 256, 256, 3)
    style_shape = (1,) + style_target.shape
    print(style_shape)

    # precompute style features
    # 启动训练过程,tensorflow的图和绘画
    with tf.Graph().as_default(), tf.device('/gpu:0'), tf.Session() as sess:
        # 转化为张量的形式进行训练
        style_image = tf.placeholder(tf.float32, shape=style_shape, name='style_image')
        # 对风格图片进行预处理,按照vgg的方式对图片进行预处理
        style_image_pre = vgg.preprocess(style_image)
        # 加载vgg网络
        net = vgg.net(vgg_path, style_image_pre)
        style_pre = np.array([style_target])

        # 获取特征图的特征并计算相对应的gram矩阵
        for layer in STYLE_LAYERS:
            features = net[layer].eval(feed_dict={style_image: style_pre})
            features = np.reshape(features, (-1, features.shape[3]))
            gram = np.matmul(features.T, features) / features.size
            style_features[layer] = gram

    with tf.Graph().as_default(), tf.Session() as sess:
        # 计算内容相对应的内容特征
        X_content = tf.placeholder(tf.float32, shape=batch_shape, name="X_content")
        X_pre = vgg.preprocess(X_content)

        # precompute content features
        content_features = {}
        content_net = vgg.net(vgg_path, X_pre)
        content_features[CONTENT_LAYER] = content_net[CONTENT_LAYER]

        if slow:
            preds = tf.Variable(
                tf.random_normal(X_content.get_shape()) * 0.256
            )
            preds_pre = preds
        else:
            preds = transform.net(X_content / 255.0)
            preds_pre = vgg.preprocess(preds)

        net = vgg.net(vgg_path, preds_pre)
        content_size = _tensor_size(content_features[CONTENT_LAYER]) * batch_size
        assert _tensor_size(content_features[CONTENT_LAYER]) == _tensor_size(net[CONTENT_LAYER])
        content_loss = content_weight * (2 * tf.nn.l2_loss(
            net[CONTENT_LAYER] - content_features[CONTENT_LAYER]) / content_size
                                         )

        style_losses = []
        for style_layer in STYLE_LAYERS:
            layer = net[style_layer]
            bs, height, width, filters = map(lambda i: i.value, layer.get_shape())
            size = height * width * filters
            feats = tf.reshape(layer, (bs, height * width, filters))
            feats_T = tf.transpose(feats, perm=[0, 2, 1])
            grams = tf.matmul(feats_T, feats) / size
            style_gram = style_features[style_layer]
            style_losses.append(2 * tf.nn.l2_loss(grams - style_gram) / style_gram.size)

        style_loss = style_weight * functools.reduce(tf.add, style_losses) / batch_size

        # total variation denoising
        # 计算损失
        tv_y_size = _tensor_size(preds[:, 1:, :, :])
        tv_x_size = _tensor_size(preds[:, :, 1:, :])
        y_tv = tf.nn.l2_loss(preds[:, 1:, :, :] - preds[:, :batch_shape[1] - 1, :, :])
        x_tv = tf.nn.l2_loss(preds[:, :, 1:, :] - preds[:, :, :batch_shape[2] - 1, :])
        tv_loss = tv_weight * 2 * (x_tv / tv_x_size + y_tv / tv_y_size) / batch_size

        loss = content_loss + style_loss + tv_loss

        # overall loss
        train_step = tf.train.AdamOptimizer(learning_rate).minimize(loss)
        sess.run(tf.global_variables_initializer())
        import random
        uid = random.randint(1, 100)
        print("UID: %s" % uid)
        for epoch in range(epochs):
            num_examples = len(content_targets)
            iterations = 0
            while iterations * batch_size < num_examples:
                start_time = time.time()
                curr = iterations * batch_size
                step = curr + batch_size
                X_batch = np.zeros(batch_shape, dtype=np.float32)
                for j, img_p in enumerate(content_targets[curr:step]):
                    X_batch[j] = get_img(img_p, (256, 256, 3)).astype(np.float32)

                iterations += 1
                assert X_batch.shape[0] == batch_size

                feed_dict = {
                    X_content: X_batch
                }

                train_step.run(feed_dict=feed_dict)
                end_time = time.time()
                delta_time = end_time - start_time
                if debug:
                    print("UID: %s, batch time: %s" % (uid, delta_time))
                is_print_iter = int(iterations) % print_iterations == 0
                if slow:
                    is_print_iter = epoch % print_iterations == 0
                is_last = epoch == epochs - 1 and iterations * batch_size >= num_examples
                should_print = is_print_iter or is_last
                if should_print:
                    to_get = [style_loss, content_loss, tv_loss, loss, preds]
                    test_feed_dict = {
                        X_content: X_batch
                    }

                    tup = sess.run(to_get, feed_dict=test_feed_dict)
                    _style_loss, _content_loss, _tv_loss, _loss, _preds = tup
                    losses = (_style_loss, _content_loss, _tv_loss, _loss)
                    if slow:
                        _preds = vgg.unprocess(_preds)
                    else:
                        saver = tf.train.Saver()
                        res = saver.save(sess, save_path)
                    yield (_preds, losses, iterations, epoch)


def _tensor_size(tensor):
    from operator import mul
    return functools.reduce(mul, (d.value for d in tensor.get_shape()[1:]), 1)

核心代码就是这样咯,需要更详细的解释大家可以借助一些AI模型执行哟。

环境配置

开始之前记得将源切换为国内的用于加速,指令如下

conda config --remove-key channels
conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/
conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main/
conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/pytorch/
conda config --set show_channel_urls yes
pip config set global.index-url https://mirror.baidu.com/pypi/simple

安装匹配的虚拟环境

创建虚拟环境并激活

image-20240525225246665

激活使用conda activate tf37指令,如果命令行左侧出现环境名称表示你激活成功。

image-20240525225634202

之后需要看你是否在你的项目目录下,如果不在代码目录下请通过cd指令cd到对应的代码目录下,通过dir指令查看你这个目录下,如果出现req.txt文件表示你当前步的操作是没有问题的。

image-20240525230042508

接下来,直接通过执行下列指令即可完成所有依赖库的安装。

pip install -r req.txt

image-20240525232923901

执行完毕之后可以执行下面指令进行测试,如果出现图形化界面即表示运行成功。

image-20240525233010081

image-20240525233033823

最后使用pycharm打开并选择你激活的虚拟环境你就可以享受这份代码了。

image-20240525235244003

挑战与未来方向

图像风格迁移是一个活跃的研究领域,未来有望理论和应用两方面都取得更多的突破,为艺术和设计等带来更多的可能性,未来可能的研究方向包括。

  1. 多模态风格迁移: 未来的研究可能会探索将不同模态的风格(如视频、3D模型等)迁移到图像上,创造更为丰富的视觉效果。
  2. 用户交互性: 提高用户交互性,允许用户通过更直观的方式(如草图、手势等)来控制风格迁移过程,可能是未来研究的一个方向。
  3. 风格迁移的可控性: 研究如何让用户能够控制风格迁移的程度和区域,实现更加精细的风格迁移效果。
  4. 跨域风格迁移: 探索跨域风格迁移,例如将绘画作品的风格应用到摄影图像上,或者将古代艺术风格迁移到现代图像上。
  5. 风格迁移的可解释性: 提高风格迁移过程的可解释性,帮助用户理解网络是如何学习和应用不同风格的。
  6. 应用拓展: 将风格迁移技术应用于更广泛的领域,如影视后期制作、虚拟现实、增强现实等。
  7. 鲁棒性和泛化能力: 提高模型的鲁棒性和泛化能力,使其能够适应不同的风格和内容,减少对特定训练数据集的依赖。
  8. 计算效率: 进一步优化算法,减少计算资源消耗,使风格迁移技术能够在更多设备上实时运行。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

探索 Mistral 新发布的具有原生函数调用功能的 7B 模型【附notebook文件】

引言 Mistral 发布了新版的 7B 模型&#xff0c;这次更新引入了原生函数调用功能。对于开发者和 AI 爱好者来说&#xff0c;这一更新极具吸引力&#xff0c;因为它增强了模型的功能和实用性。在这篇博客中&#xff0c;我们将深入探讨这些新功能&#xff0c;展示如何使用该模型…

击穿盲点——【网络安全】社会工程学中的网络欺骗

社会工程学起源于上世纪60年代左右&#xff0c;是一种通过人际交流的方式来获得情报的非技术渗透手段。这种手段无需过多技术要求&#xff0c;却非常有效&#xff0c;目前已成为危害企业网络安全的重大威胁之一。著名黑客凯文米特尼克在《反欺骗的艺术》中曾提到&#xff0c;人…

深入理解计算机系统 家庭作业4.52

练习题4.3 p.254 \sim\seq\seq-full.hcl文件内已经说的很清楚了哪些不能更改,哪些是题目要求更改的控制逻辑块. 依据家庭作业4.51的答案,在seq-full.hcl文件内更改对应的HCL描述即可 以下答案注释了#changed的就是更改部分 #/* $begin seq-all-hcl */ ######################…

MFC GDI 绘图模式、映射模式、画笔、笔、字体

一 GDI 绘图模式&#xff08;RoP2 Mode&#xff09; 在使用VC MFC进行图形程序编程时&#xff0c;常会用到GDI绘图指令&#xff0c;而要做到绘图时有橡皮筋动态效果&#xff0c;就需设置GDI绘图模式。GDI绘图模式有多种&#xff0c;如下&#xff1a; 常用R2_NOT模式来实…

TXT文本编辑器:一键提取,多关键字匹配,内容尽在掌控!

在浩如烟海的文档中&#xff0c;寻找关键信息往往是一项繁琐而耗时的任务。你是否曾经为了查找某个关键字而翻遍了整个文件夹&#xff0c;却仍然一无所获&#xff1f;现在&#xff0c;有了TXT文本编辑器&#xff0c;这一切都将变得轻松而高效 这款软件以其简洁明了的操作界面和…

VBA_MF系列技术资料1-615

MF系列VBA技术资料1-615 为了让广大学员在VBA编程中有切实可行的思路及有效的提高自己的编程技巧&#xff0c;我参考大量的资料&#xff0c;并结合自己的经验总结了这份MF系列VBA技术综合资料&#xff0c;而且开放源码&#xff08;MF04除外&#xff09;&#xff0c;其中MF01-0…

17.分类问题

机器学习分类问题详解与实战 介绍 在机器学习中&#xff0c;分类问题是一类常见的监督学习任务&#xff0c;其目标是根据输入特征将数据样本划分为预先定义的类别之一。分类问题广泛应用于各个领域&#xff0c;如图像识别、自然语言处理、金融风险评估等。本文将详细介绍机器…

Java的线程的使用

一.两种创建线程的方式 1.继承Thread类&#xff08;匿名内部类&#xff09; 创建方式&#xff1a; 1.定义一个子类继承Thread&#xff0c;重写run方法 2.创建子类对象&#xff0c; 3.调用子类对象的start方法&#xff08;启动还是执行的run方法&#xff09; 优缺点&#x…

vue3 ts问题 找不到模块“@/views/home/index.vue”或其相应的类型声明。

1. 找不到模块“/views/HomeView.vue”或其相应的类型声明 今天帮同事看了一个问题&#xff0c;他尝试用vitevue3tspinia创建项目&#xff0c;结果刚上来就遇到这么一个问题 2. 解决办法 出现这个问题的原因就是&#xff1a;ts只支持导出导入模块&#xff0c;但是vue不是模块…

Java——接口后续

1.Comparable 接口 在Java中&#xff0c;我们对一个元素是数字的数组可以使用sort方法进行排序&#xff0c;如果要对一个元素是对象的数组按某种规则排序&#xff0c;就会用到Comparable接口 当实现Comparable接口后&#xff0c;sort会自动调用Comparable接口里的compareTo 方法…

HIVE3.1.3+ZK+Kerberos+Ranger2.4.0高可用集群部署

目录 一、集群规划 二、介质下载 三、基础环境准备 1、解压文件 2、配置环境变量 四、配置zookeeper 1、创建主体 2、修改zoo.cfg 3、新增jaas.conf 4、新增java.env 5、重启ZK 6、验证ZK 五、配置元数据库 六、安装HIVE 1、创建Hiver的kerberso主体 2…

马尔可夫和比奈梅-切比雪夫不等式

目录 一、说明 二、自然界的极限性 三、马尔可夫不等式 3.1 最早提出 3.2 马尔可夫不等式的证明 四、 Bienaym–Chebyshev 不等式 4.1 简要回顾Bienaym–Chebyshev 不等式的历史 4.2 Bienaym — Chebyshev 不等式的证明 五、弱大数定律&#xff08;及其证明&#xff09;…

kafka学习笔记05

Consumer消费者重新分配策略和offset维护机制 我们会打印很多kafka的日志。 我们现在可以去关闭kafka的日志&#xff1a; 创建日志配置。 这样就只有Info级别的日志可以打印出来了。 改成debug级别可以输出比较多的日志。 Kafka消费者Consumer消费消息配置实战 生产者发送消息…

ArcGIS不同图斑设置不同的透明度

对于设置一个图层的整体的透明度&#xff0c;我们在 ArcGIS制作带蒙版的遥感影像地图http://mp.weixin.qq.com/s?__bizMzIzNjM2NTYxMg&mid2247509080&idx1&sn38dccf0a52bb3bb3758f57114ee38b72&chksme8da161bdfad9f0d363da90959a8524dcf2b60d0e8d999f8ebeef0…

虚机配置USB CDROM设备热迁移crash

虚机配置USB CDROM设备热迁移crash 问题现象定位过程堆栈分析日志分析打开trace异常日志上下文分析SpecificationCBWCSW 命令执行发送读命令读取数据 正常日志异常堆栈 修复方案结论 基础原理设备模型数据结构设备实例化 UHCIFrame ListTDQH SCSI 问题现象 dogfood环境一台虚机…

一条命令安装Metasploit Framework

做安全渗透的人都或多或少的使用kali-Linux系统中msfconsole命令启动工具&#xff0c;然而也经常会有人遇到这样那样的问题无法启动 今天我们就用一条命令来重新安装这个工具 curl https://raw.githubusercontent.com/rapid7/metasploit-omnibus/master/config/templates/met…

C语言—深入理解指针(4)

1.回调函数 回调函数就是一个通过函数指针调用的函数。 如果你把函数的指针&#xff08;地址&#xff09;作为参数传递给另一个函数&#xff0c;当这个指针被用来调用其所指向的函数时&#xff0c;被调用的函数就是回调函数。回调函数不是由该函数的实现方直接调用&#xff0…

STM32-10-定时器

STM32-01-认识单片机 STM32-02-基础知识 STM32-03-HAL库 STM32-04-时钟树 STM32-05-SYSTEM文件夹 STM32-06-GPIO STM32-07-外部中断 STM32-08-串口 STM32-09-IWDG和WWDG 文章目录 一、STM32 基础定时器1. 基本定时器简介2. 基本定时器框图3. 基本定时器相关寄存器4. 定时器溢出…

【Java EE】网络协议——HTTP协议

目录 1.HTTP 1.1HTTP是什么 1.2理解“应用层协议” 1.3理解HTTP协议的工作过程 2.HTTP协议格式 2.1抓包工具的使用 2.2抓包工具的原理 2.3抓包结果 3.协议格式总结 1.HTTP 1.1HTTP是什么 HTTP&#xff08;全称为“超文本传输协议”&#xff09;是一种应用非常广泛的应…

JAVA -- > 初识JAVA

初始JAVA 第一个JAVA程序详解 public class Main {public static void main(String[] args) {System.out.println("Hello world");} }1.public class Main: 类型,作为被public修饰的类,必须与文件名一致 2.public static 是JAVA中main函数准写法,记住该格式即可 …