把一张图像的特征转移到另一张图像,是个非常一颗赛艇的想法。把照片瞬间变成梵高、毕加索画作风格,想想就很酷。

                        

图1:星空版小狗

(文末有风格迁移小demo)

或者,你可以用目前很流行的Faceapp让下面这位严肃的大叔露出笑容

                   

                                                         图2:一个笑容灿烂的杀手

要实现这样的图像风格转换,通常需要一个包含成对图片的训练集。CycleGAN打破了这个限制。CycleGAN是加州大学伯克利分校的一项研究成果,可以在没有成对训练数据的情况下,实现图像风格的转换。

以下是CycleGAN完成的一些例子:

                    

                                                    图3:CycleGAN实现的一些例子

详情见CycleGAN的论文 Unpaired Image-to-Image Translation using Cycle-Consistent Adversarial Networks:
[1703.10593] Unpaired Image-to-Image Translation using Cycle-Consistent Adversarial Networks

如果你觉得论文读起来太枯燥,那么,最近GitHub上发布的一份教程可能比较适合你,作者Hardik Bansal和Archit Rathore。

以下是这份教程对CycleGAN的解读:量子位编译:

简介

如果你对生成对抗网络(GAN)还不太了解,可以查看Ian Goodfellow在NIPS 2016的研讨会视频,地址见文末。

这篇文章是一份简化版教程,将带你了解CycleGAN的核心理念,并介绍如何在Tensorflow中实现CycleGAN网络。

非配对的图像到图像转换

                             

                                                           图4:配对与非配对图像转换(图来自论文)

上面也提到过,无须提供从源域到目标域的配对转换例子,CycleGAN就能工作。

最近提出的Pix to Pix方法的关键是提供了在这两个域中有相同数据的训练样本。CycleGAN的创新点在于能够在源域和目标域之间,无须建立训练数据间一对一的映射,就可实现这种迁移。

这种方法通过对源域图像进行两步变换:首先尝试将其映射到目标域,然后返回源域得到二次生成图像,从而消除了在目标域中图像配对的要求。使用生成器(generator)网络将图像映射到目标域,并且通过匹配生成器与鉴别器(discriminator),能提高该生成图像的质量。

对抗网络

我们使用了一个生成器网络和一个鉴别器网络,进行相互对抗。生成器尝试从期望分布中产生样本,鉴别器试图预测样本是否为原始图像或生成图像。

利用生成器和鉴别器联合训练,最终生成器学习后完全逼近实际分布,并且鉴别器处于随机猜测状态。

循环一致

上述对抗方法的训练存在一个问题。引用原文的一段话:

从理论上讲,对抗训练可以学习和产生与目标域Y和X相同分布的输出,即映射G和F。然而,在足够大的样本容量下,网络可以将相同的输入图像集合映射到目标域中图像的任何随机排列,其中任何学习的映射可以归纳出与目标分布匹配的输出分布。因此,单独的对抗损失Loss不能保证学习函数可以将单个输入Xi映射到期望的输出Yi。

为了规范模型,作者介绍了循环一致性的约束条件:如果我们从源分布转换为目标分布,然后再次转换回源分布,那么应该可以从源分布中获取样本。

网络架构

                

               

                                                          图5:CycleGAN结构示意图

在一个配对数据集中,每张图像,如imgA,人为地映射到目标域中的某个图像,如imgB,以便两者共享各种特征。

从imgA到imgB的特征可用于其相对应的映射过程中,即从imgB到imgA的特征。配对一般是为了使输入和输出共享一些共同的特征。当一张图像从一个域到另一个域时,该映射定义了一种有意义的变换。因此,当我们配对数据集时,生成器必须从域DA中获得一个输入,例如inputA,并将该图像映射到输出图像,即genB,原始图像必须与其映射对象相近。

但是,我们在不配对的数据集中没有这个对象,也没有预先定义好的用于学习的有意义转换,所以我们将要创建它。我们需要确保输入图像和生成图像之间存在一些有意义的关联。

所以,作者试图通过生成器将输入图像(inputA)从域DA映射到目标域DB中,转换成对应图像。但是为了确保这些图像之间存在有意义的关系,它们必须共享一些特征,这些特征可用于将此输出图像映射回输入图像,因此必须有另一个生成器能将此输出图像映射回原始域。因此,我们需要定义inputA和genB之间有意义的映射。

简而言之,该模型通过从域DA获取输入图像,该输入图像被传递到第一个生成器GeneratorA→B,其任务是将来自域DA的给定图像转换到目标域DB中的图像。然后这个新生成的图像被传递到另一个生成器GeneratorB→A,其任务是在原始域DA转换回图像CyclicA,这里可与自动编码器作对比。

正如上面讨论的,这个输出图像必须与原始输入图像相似,用来定义非配对数据集中原来不存在的有意义映射。

如图5所示,两个输入被传递到对应的鉴别器(一个是对应于该域的原始图像,另一个是通过生成器产生的图像),并且鉴别器的任务是区分它们,识别出生成器输出的生成图像,并拒绝此生成图像。生成器想要确保这些图像被鉴别器接受,所以它将尝试生成与DB类中原始图像非常接近的新图像。事实上,在生成器分布与所需分布相同时,生成器和鉴别器之间实现了纳什均衡(Nash equilibrium)。

我们可以通过TensorFlow轻松实现CycleGAN,下面将介绍CycleGAN各部分的实现细节,可在GitHub上找到完整代码。

构建生成器

生成器的结构已在下图列出。

             

                                                                        图6:生成器结构

生成器由三个部分组成:编码器、转换器和解码器。

该生成器的超参数定义如下,包括卷积核个数、批数量、池化大小和输入图像的格式:

ngf = 32 # Number of filters in first layer of generator 
ndf = 64 # Number of filters in first layer of discriminator 
batch_size = 1 # batch_size 
pool_size = 50 # pool_size 
img_width = 256 # Imput image will of width 256 
img_height = 256 # Input image will be of height 256 
img_depth = 3 # RGB format

前三个参数简单易懂,我们将在生成图像库部分中解释pool_size的含义。

编码

为了简单起见,在此文章中我们把输入大小固定设置为[256,256,3]。第一步是利用卷积网络从输入图像中提取特征。要了解有关卷积网络的基础知识,你可以查看文末的CNN介绍链接。卷积网络将一张图像作为输入,不同大小的卷积核能在输入图像上移动并提取特征,步幅(stride)大小能决定在图像中卷积核窗口的数量。所以编码器的第一层定义如下:

o_c1 = general_conv2d(input_gen, num_features=ngf, window_width=7, window_height=7, stride_width=1, stride_height=1)

其中,input_gen是生成器的输入图像,num_features是在卷积层中卷积得到的特征图谱数量,也可以看作是提取不同特征的滤波器数量。window_width和window_height表示在输入图像上滑动来提取特征的滤波器窗口大小。类似地,stride_width和stride_height定义了每次迭代后滤波器的移位方式。输出Oc1是尺寸为[256,256,64]的张量,继续传输给下个卷积层。这里,鉴别器第一层的滤波器个数设置为64,完成对general_conv2d函数的定义。当然可以添加其他层,如ReLU层或批归一化层(BN层),在本教程中跳过这些层的介绍。

def general_conv2d(inputconv, o_d=64, f_h=7, f_w=7, s_h=1, s_w=1):with tf.variable_scope(name):conv = tf.contrib.layers.conv2d(inputconv, num_features, [window_width, window_height], [stride_width, stride_height],padding, activation_fn=None, weights_initializer=tf.truncated_normal_initializer(stddev=stddev),biases_initializer=tf.constant_initializer(0.0))

接下来:

o_c2 = general_conv2d(o_c1, num_features=64*2, window_width=3, window_height=3, stride_width=2, stride_height=2)
# o_c2.shape = (128, 128, 128)o_enc_A = general_conv2d(o_c2, num_features=64*4, window_width=3, window_height=3, stride_width=2, stride_height=2)
# o_enc_A.shape = (64, 64, 256)

卷积层越往上,需要增加高层特征的数量。我们将图像压缩成256个尺寸大小64×64的特征向量,接着将DA域中图像的特征向量转换为DB域中图像的特征向量。

总而言之,我们将DA域中一个尺寸为[256,256,3]的图像,输入到设计的编码器中,获得了尺寸为[64,64,256]的输出OAenc。

转换

这些网络层的作用是组合图像的不同相近特征,然后基于这些特征,确定如何将图像的特征向量OAenc从DA域转换为DB域的特征向量。因此,作者使用了6层Resnet模块:

o_r1 = build_resnet_block(o_enc_A, num_features=64*4)
o_r2 = build_resnet_block(o_r1, num_features=64*4)
o_r3 = build_resnet_block(o_r2, num_features=64*4)
o_r4 = build_resnet_block(o_r3, num_features=64*4)
o_r5 = build_resnet_block(o_r4, num_features=64*4)
o_enc_B = build_resnet_block(o_r5, num_features=64*4)# o_enc_B.shape = (64, 64, 256)

这里OBenc表示该层的最终输出,尺寸为[64,64,256],这可以看作是DB域中图像的特征向量。

你一定很想知道build_resnet_block函数的内容及作用。build_resnet_block是一个由两个卷积层组成的神经网络层,其中部分输入数据直接添加到输出。这样做是为了确保先前网络层的输入数据信息直接作用于后面的网络层,使得相应输出与原始输入的偏差缩小,否则原始图像的特征将不会保留在输出中且输出结果会偏离目标轮廓。在上面也提到,这个任务的一个主要目标是保留原始图像的特征,如目标的大小和形状,因此残差网络非常适合完成这些转换。Resnet模块的结构如下所示:

                   

                                                                          图7:Resnet模块的结构

Resnet模块的代码如下:

def resnet_blocks(input_res, num_features):out_res_1 = general_conv2d(input_res, num_features,window_width=3,window_heigth=3,stride_width=1,stride_heigth=1)out_res_2 = general_conv2d(out_res_1, num_features,window_width=3,window_heigth=3,stride_width=1,stride_heigth=1)return (out_res_2 + input_res)

解码

到目前为止,我们已经将特征向量OAenc传递到转换层,得到了另一个大小为[64,64,256]的特征向量OBenc。

解码过程与编码方式完全相反,从特征向量中还原出低级特征,这是利用了反卷积层(deconvolution)来完成的。

o_d1 = general_deconv2d(o_enc_B, num_features=ngf*2 window_width=3, window_height=3, stride_width=2, stride_height=2)
o_d2 = general_deconv2d(o_d1, num_features=ngf, window_width=3, window_height=3, stride_width=2, stride_height=2)

最后,我们将这些低级特征转换得到一张在DB域中的图像,代码如下所示:

gen_B = general_conv2d(o_d2, num_features=3, window_width=7, window_height=7, stride_width=1, stride_height=1)

最后,我们得到了一个大小为[256,256,3]的生成图像genB,构建生成器的代码可以用如下函数实现:

def build_generator(input_gen):o_c1 = general_conv2d(input_gen, num_features=ngf, window_width=7, window_height=7, stride_width=1, stride_height=1)o_c2 = general_conv2d(o_c1, num_features=ngf*2, window_width=3, window_height=3, stride_width=2, stride_height=2)o_enc_A = general_conv2d(o_c2, num_features=ngf*4, window_width=3, window_height=3, stride_width=2, stride_height=2)# Transformationo_r1 = build_resnet_block(o_enc_A, num_features=64*4)o_r2 = build_resnet_block(o_r1, num_features=64*4)o_r3 = build_resnet_block(o_r2, num_features=64*4)o_r4 = build_resnet_block(o_r3, num_features=64*4)o_r5 = build_resnet_block(o_r4, num_features=64*4)o_enc_B = build_resnet_block(o_r5, num_features=64*4)#Decodingo_d1 = general_deconv2d(o_enc_B, num_features=ngf*2 window_width=3, window_height=3, stride_width=2, stride_height=2)o_d2 = general_deconv2d(o_d1, num_features=ngf, window_width=3, window_height=3, stride_width=2, stride_height=2)gen_B = general_conv2d(o_d2, num_features=3, window_width=7, window_height=7, stride_width=1, stride_height=1)return gen_B

构建鉴别器

我们讨论了如何构建生成器,但是为了完成网络的对抗训练部分,还需要构建鉴别器。鉴别器将一张图像作为输入,并尝试预测其为原始图像或是生成器的输出图像。生成器的结构如下所示:

                  

                                                                      图8:生成器的结构

鉴别器本身就属于卷积网络,需要从图像中提取特征。

o_c1 = general_conv2d(input_disc, ndf, f, f, 2, 2)
o_c2 = general_conv2d(o_c1, ndf*2, f, f, 2, 2)
o_enc_A = general_conv2d(o_c2, ndf*4, f, f, 2, 2)
o_c4 = general_conv2d(o_enc_A, ndf*8, f, f, 2, 2)

下一步是确定这些特征是否属于该特定类别,添加一个产生1维输出的卷积层来完成这个任务。这里,ndf表示鉴别器初始层的特征个数,可以尝试调整来获得最佳效果。

decision = general_conv2d(o_c4, 1, f, f, 1, 1, 0.02)

我们已经完成该模型的两个主要组成部分,即生成器和鉴别器。由于要使这个模型既可以从A→B和B→A两个方向工作,我们设置了两个生成器,即生成器A→B和生成器B→A,以及两个鉴别器,即鉴别器A和鉴别器B。

建立模型

在定义损失函数前,先定义基础输入变量,来构建模型。

input_A = tf.placeholder(tf.float32, [batch_size, img_width, img_height, img_layer], name="input_A")
input_B = tf.placeholder(tf.float32, [batch_size, img_width, img_height, img_layer], name="input_B")

这些占位符将作为输入,同时定义模型如下:

gen_B = build_generator(input_A, name="generator_AtoB")
gen_A = build_generator(input_B, name="generator_BtoA")
dec_A = build_discriminator(input_A, name="discriminator_A")
dec_B = build_discriminator(input_B, name="discriminator_B")dec_gen_A = build_discriminator(gen_A, "discriminator_A")
dec_gen_B = build_discriminator(gen_B, "discriminator_B")
cyc_A = build_generator(gen_B, "generator_BtoA")
cyc_B = build_generator(gen_A, "generator_AtoB")

上面的变量名在本质上是非常直观的。gen表示使用相应的生成器后生成的图像,dec表示在将相应输入传递到鉴别器后做出的判断。

损失函数

现在我们有两个生成器和两个鉴别器。我们要按照实际目的来设计损失函数。损失函数应该包括如下四个部分:

  1. 鉴别器必须允许所有相应类别的原始图像,即对应输出置1;

  2. 鉴别器必须拒绝所有想要愚弄过关的生成图像,即对应输出置0;

  3. 生成器必须使鉴别器允许通过所有的生成图像,来实现愚弄操作;

  4. 所生成的图像必须保留有原始图像的特性,所以如果我们使用生成器GeneratorA→B生成一张假图像,那么要能够使用另一个生成器GeneratorB→A来努力恢复成原始图像。此过程必须满足循环一致性。

鉴别器损失

第1部分

我们通过训练鉴别器,使其对A类图像的输出接近于1,鉴别器B也是如此。鉴别器A的训练目标为最小化“(DiscriminatorA(a)−1)2”的值,鉴别器B也是如此。对应代码如下:

D_A_loss_1 = tf.reduce_mean(tf.squared_difference(dec_A,1))
D_B_loss_1 = tf.reduce_mean(tf.squared_difference(dec_B,1))

第2部分

由于鉴别器应该能够区分生成图像和原始图像,所以在处理生成图像时期望输出为0,即鉴别器A要最小化“(DiscriminatorA(GeneratorB→A(b)))2”的值。对应代码如下:

D_A_loss_2 = tf.reduce_mean(tf.square(dec_gen_A))
D_B_loss_2 = tf.reduce_mean(tf.square(dec_gen_B))D_A_loss = (D_A_loss_1 + D_A_loss_2)/2
D_B_loss = (D_B_loss_1 + D_B_loss_2)/2

生成器损失

最终生成器应该能够提高鉴别器对生成图像的输出值。如果鉴别器对生成图像的输出值尽可能接近1,则生成器的作用达到。故生成器想要最小化“(DiscriminatorB(GeneratorA→B(a))−1)2”,因此损失为:

g_loss_B_1 = tf.reduce_mean(tf.squared_difference(dec_gen_A,1))
g_loss_A_1 = tf.reduce_mean(tf.squared_difference(dec_gen_A,1))

循环损失

最后一个重要参数为循环丢失(cyclic loss),能判断用另一个生成器得到的生成图像与原始图像的差别。因此原始图像和循环图像之间的差异应该尽可能小。

cyc_loss = tf.reduce_mean(tf.abs(input_A-cyc_A)) + tf.reduce_mean(tf.abs(input_B-cyc_B))

所以完整的生成器损失为:

g_loss_A = g_loss_A_1 + 10*cyc_loss
g_loss_B = g_loss_B_1 + 10*cyc_loss

cyc_loss的乘法因子设置为10,说明循环损失比鉴别损失更重要。

混合参数

定义好损失函数,接下来只需要训练模型来最小化损失函数。

d_A_trainer = optimizer.minimize(d_loss_A, var_list=d_A_vars)
d_B_trainer = optimizer.minimize(d_loss_B, var_list=d_B_vars)
g_A_trainer = optimizer.minimize(g_loss_A, var_list=g_A_vars)
g_B_trainer = optimizer.minimize(g_loss_B, var_list=g_B_vars)

训练模型

for epoch in range(0,100):# Define the learning rate schedule. The learning rate is kept# constant upto 100 epochs and then slowly decayedif(epoch < 100) :curr_lr = 0.0002else:curr_lr = 0.0002 - 0.0002*(epoch-100)/100# Running the training loop for all batchesfor ptr in range(0,num_images):# Train generator G_A->B_, gen_B_temp = sess.run([g_A_trainer, gen_B],feed_dict={input_A:A_input[ptr], input_B:B_input[ptr], lr:curr_lr})# We need gen_B_temp because to calculate the error in training D_B_ = sess.run([d_B_trainer],feed_dict={input_A:A_input[ptr], input_B:B_input[ptr], lr:curr_lr})# Same for G_B->A and D_A as follow_, gen_A_temp = sess.run([g_B_trainer, gen_A],feed_dict={input_A:A_input[ptr], input_B:B_input[ptr], lr:curr_lr})_ = sess.run([d_A_trainer],feed_dict={input_A:A_input[ptr], input_B:B_input[ptr], lr:curr_lr})

你可以在训练函数中看到,在训练时需要不断调用不同鉴别器和生成器。为了训练模型,需要输入训练图像和选择优化器的学习率。由于batch_size设置为1,所以num_batches等于num_images。

我们已经完成了模型构建,下面是模型中一些默认超参数。

生成图像库

计算每个生成图像的鉴别器损失是不可能的,因为会耗费大量的计算资源。为了加快训练,我们存储了之前每个域的所有生成图像,并且每次仅使用一张图像来计算误差。首先,逐个填充图像库使其完整,然后随机将某个库中的图像替换为最新的生成图像,并使用这个替换图像来作为该步的训练。

def image_pool(self, num_gen, gen_img, gen_pool):if(num_gen < pool_size):gen_img_pool[num_gen] = gen_imgreturn gen_imgelse :p = random.random()if p > 0.5:# Randomly selecting an id to return for calculating the discriminator lossrandom_id = random.randint(0,pool_size-1)temp = gen_img_pool[random_id]gen_pool[random_id] = gen_imgreturn tempelse :return gen_img
gen_image_pool_A = tf.placeholder(tf.float32, [batch_size, img_width, img_height, img_layer], name="gen_img_pool_A")
gen_image_pool_B = tf.placeholder(tf.float32, [batch_size, img_width, img_height, img_layer], name="gen_img_pool_B")gen_pool_rec_A = build_gen_discriminator(gen_image_pool_A, "d_A")
gen_pool_rec_B = build_gen_discriminator(gen_image_pool_B, "d_B")# Also the discriminator loss will change as followD_A_loss_2 = tf.reduce_mean(tf.square(gen_pool_rec_A))
D_A_loss_2 = tf.reduce_mean(tf.square(gen_pool_rec_A))

图像库代码仍需要微小的修改,完整代码见文末。

结果

我们运行了野马转斑马的模型,但是由于缺乏图像库,该模型只运行了100步,得到以下结果。

             

                                                             图9:野马转斑马的实际效果

讨论

1. 在训练时,我们发现初始化很大程度影响了输出结果,因此通过多次训练来获得最佳效果。你会发现图10中特殊的背景颜色,这个效果只有在10-20步的训练时才能观察到,你可以再运行代码试试。

           

                                                   图10:该模型出现失真效果

2. 我们也认为当改变物体形状时,该模型不大适用。我们试图用该模型把男人的脸转化为一个看起来像女人的脸。为此,我们使用了人脸标注数据集celebA,但效果不好且生成图像失真严重。

相关链接

卷积神经网络:An Intuitive Explanation of Convolutional Neural Networks

CycleGAN代码:architrathore/CycleGAN

风格迁移小demo:Feed-forward neural doodle

NIPS 2016研讨会视频:https://www.youtube.com/watch?v=RvgYvHyT15E

【完】

One More Thing…

今天AI界还有哪些事值得关注?在量子位(QbitAI)公众号对话界面回复“今天”,看我们全网搜罗的AI行业和研究动态。笔芯~

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

相关文章

  1. C++中#ifdef/#ifndef/#else/#endif的用法详解

    C++中#ifdef/#ifndef/#else/#endif的用法详解 转载于https://www.cnblogs.com/renyuan/archive/2013/05/22/3092362.html 一般情况下,源程序中所有的行都参加编译。但是有时希望对其中一部分内容只在满足一定条件才进行编译,也就是对一部分内容指定编译的条件,这就是“条件编…...

    2024/3/19 22:06:43
  2. 上海腾科教育达梦数据库培训干货分享如何使用ODBC的方式连接DM7数据库

    01在WINDOS下配置ODBC数据源众所周知,ODBC(Open Database Connectivity)是由微软公司推出的,所以在他本家的WINDOWS操作系统上面,配置ODBC数据源的工作十分简单。1.1 打开ODBC数据源管理器首先,在windows中找到ODBC数据源管理器,对应的位数应该跟数据库系统的位数保持一…...

    2024/3/19 20:25:50
  3. dubbo调用so文件

    最近使用dubbo调公司的中间件,遇到各种情况,下面说下解决后的操作1、usr/lib64目录下放置so文件2、 assembly/conf也放相同的so文件3、最后看下打包后conf是否包含so文件,如果没有需要修改下打包插件的配置...

    2024/3/19 22:12:12
  4. <算法设计方法与优化> || 求值法

    求值法中的几种典型例题**- 求最大值****-判断闰年**素数 - 求最大值main()方法主要负责输出算法。在这个方法中,主要使用的是算法结构中的顺序结构 如果在比较最大值和最小值的时候可以灵活运用三目运算符号: <表达式1>?<表达式2>:<表达式3>例子 int m…...

    2024/3/27 9:06:54
  5. ios app 下载地址收集(一点一点收集中...)

    1.百度地图转码后 : https://apps.apple.com/cn/app/%E7%99%BE%E5%BA%A6%E5%9C%B0%E5%9B%BE-%E8%B7%AF%E7%BA%BF%E8%A7%84%E5%88%92-%E5%87%BA%E8%A1%8C%E5%BF%85%E5%A4%87/id452186370转码前 : https://apps.apple.com/cn/app/百度地图-路线规划-出行必备/id4521863702.高德…...

    2024/3/19 19:15:36
  6. 在线图片取色器工具

    在线图片取色器工具: http://tools.jb51.net/color/get_color...

    2024/3/19 22:51:23
  7. 〖金融帝国实验室〗(Capitalism Lab)软件(Software)开局攻略(作者:似流年)

    ...

    2024/3/25 14:08:45
  8. ArcGIS Engie开发-地图导出

    本文在 https://blog.csdn.net/eof_2011/article/details/8038602 的基础上对代码进行了优化与改进:private string path;private double pWidth, pHeight; private IActiveView pActiveView;private AxPageLayoutControl PageLayoutControl;private ProcessBar processBar = …...

    2024/3/25 13:14:58
  9. Python函数式编程——偏函数

    今天讲解的内容是偏函数,偏函数是从Python2.5引入的一个概念,通过functools模块被用户调用。 偏函数是将所要承载的函数作为partial()函数的第一个参数,原函数的各个参数依次作为partial()函数后续的参数,除非使用关键字参数。 通过语言描述可能无法理解偏函数是怎么使用的…...

    2024/3/25 16:51:11
  10. 251 展开二维向量

    题目描述: 请设计并实现一个能够展开二维向量的迭代器。该迭代器需要支持 next 和 hasNext 两种操作。、 示例: Vector2D iterator = new Vector2D([[1,2],[3],[4]]); iterator.next(); // 返回 1 iterator.next(); // 返回 2 iterator.next(); // 返回 3 iterator.hasNext()…...

    2024/3/25 15:33:28
  11. (String)、toString()与String.valueOf()的区别

    1.(String)介绍将object转成String类型的值。使用这种方法时,需要注意的是类型必须能转成String类型,否则容易抛出CalssCastException异常示例Object o = new Integer(1); String str = (String)o; System.out.println(str);输出2.toString()介绍一般的对象或者参数都是有toS…...

    2024/3/25 17:54:07
  12. Oracle连接管理-如何限制ip访问Oracle数据库

    一、概述 本文将给大家介绍如何限制某个ip或某个ip段才能访问Oracle数据库 1.通过sqlnet.ora 2.通过/etc/hosts.deny和/etc/hosts.allow 3.通过iptables 二、正式实验 本次实验环境是Centos6.10 + Oracle 11.2.0.4单实例,数据库服务器ip地址为192.168.31.71通过sqlnet.oraa. 关…...

    2024/3/25 14:04:36
  13. ZUI易入门Android之五种创建线程的方式

    1.多线程创建方式Thread的创建方式Thread thread = new Thread() { @Overridepublic void run() { System.out.println("Thread started!");}};thread.start();2.Runnable的创建方式Runnable runnable = new Runnable() { @Overridepublic void run() {System.out.pr…...

    2024/3/25 15:54:23
  14. 常用动画特效 - CSS实现

    不是样式的生产者,只是样式的搬运工项目开发中用到的特效,在此规整,方便以后使用/* 闪烁特效 */ .class-name{-webkit-animation: twinkling 1s infinite ease-in-out } .animated{-webkit-animation-duration: 1s;animation-duration: 1s;-webkit-animation-fill-mode: bot…...

    2024/3/25 12:00:37
  15. JavaWeb中的Dao层Service层Controler层简单理解

    DAO层:Dao层叫数据访问层(有的叫持久层),全称data access object,属于一种比较底层,比较基础的操作层,具体到对于某个表的增删改查,也就是说某个Dao层一定适合数据库某一张表一一对应的,其中封装了增删改查基本操作,建议Dao层只做原子操作,增删改查。Service层:Ser…...

    2024/3/25 14:00:55
  16. jQuery中登录成功后,将token存储到跳转到首页

    前言:根据用户名密码换取token成功后,将token存储到本地,以供其他页面获取,并能跳转到其他页面。本文举例从登录页面跳转到首页。 详见下方代码 一、登录页面 //js代码 $("#login").on("click",function(){// 点击登录获取表单中的值var username = $(…...

    2024/3/25 12:58:25
  17. JavaScript中的 NaN 与 isNaN

    NaN NaN 即 Not a Number ,不是一个数字。 在 JavaScript 中,整数和浮点数都统称为 Number 类型 。除此之外,Number 类型还有一个很特殊的值,即 NaN 。它是 Number 对象上的一个静态属性,可以通过 Number.NaN 来访问 。 console.log(Number.NaN); // NaN console.log(NaN)…...

    2024/3/25 13:17:40
  18. h5app、htmlapp、网址网页app,网页封装成苹果APP

    h5app、htmlapp、网址网页app,网页封装成苹果APP网页封装成苹果APP网页封装成苹果APP不用签名将网页封装成苹果APP,无需苹果企业签名,IPA签名,ios签名,免越狱安装(本方法只支持网站封装app,原生的用不了,详细请咨询客服)近期很多朋友问我把网站变成app的方法,原因很多…...

    2024/3/25 13:36:28
  19. Exception in thread “main“ com.alibaba.fastjson.JSONException: not close json text, token : ,

    错误开头Exception in thread "main" com.alibaba.fastjson.JSONException: not close json text, token : ,1.原因这类问题 100%是 json的格式不标准2.解决https://www.json.cn/ 用这个网站 把json文本 贴进去,检查一下格式是否完整可能少了括号啥的,相应补充…...

    2024/3/25 17:37:29
  20. Mark:2020年8月文章

    精选:阿里研究员:软件测试中的18个难题 监控系统选型看这一篇够了!选择 Prometheus 还是 Zabbix ? Java 开发必备! I/O与Netty原理精讲 如何写好代码? 如何规范你的Git commit? 分布式锁,再深一点! 订单中心,1亿数据架构,这次服了 如何基于K8s构建下一代DevOps平台?…...

    2024/3/25 16:35:31

最新文章

  1. upload-labs-master靶场训练笔记

    2004.2.17 level-1 &#xff08;前端验证&#xff09; 新建一个写有下面一句话木马的php文件&#xff0c;然后把后缀改为png <?php eval($_POST["abc"]); ?> 用bp抓包后更改文件后缀为php 再用蚁剑等工具链接即可拿下shell level-2 &#xff08;后端…...

    2024/3/28 19:34:16
  2. 梯度消失和梯度爆炸的一些处理方法

    在这里是记录一下梯度消失或梯度爆炸的一些处理技巧。全当学习总结了如有错误还请留言&#xff0c;在此感激不尽。 权重和梯度的更新公式如下&#xff1a; w w − η ⋅ ∇ w w w - \eta \cdot \nabla w ww−η⋅∇w 个人通俗的理解梯度消失就是网络模型在反向求导的时候出…...

    2024/3/20 10:50:27
  3. UI 测试难题!自动化识别图片的正确率如何达到100%!

    摘要 在ui自动化测试领域&#xff0c;会遇到这样的情形&#xff1a;发布一张图片或上传一个头像&#xff0c;如何通过自动化测试的方式判定发布后的图片是否正确呢&#xff1f;又或者&#xff0c;我们如何通过自动化测试的方式判定某网页的某个logo是否与预期的一致呢&#xf…...

    2024/3/28 16:29:42
  4. C语言动态内存管理

    CSDN成就一亿技术人 目录 一.为什么要存在动态内存分配 二.动态内存函数 1.malloc和free 2.calloc 3.realloc 三.常见的动态内存错误 1.对NULL指针的解引用操作 2.对动态开辟空间的越界访问 3.对非动态开辟内存使用free释放 4.使用free释放一块动态开辟内存的一…...

    2024/3/28 1:02:52
  5. 416. 分割等和子集问题(动态规划)

    题目 题解 class Solution:def canPartition(self, nums: List[int]) -> bool:# badcaseif not nums:return True# 不能被2整除if sum(nums) % 2 ! 0:return False# 状态定义&#xff1a;dp[i][j]表示当背包容量为j&#xff0c;用前i个物品是否正好可以将背包填满&#xff…...

    2024/3/28 16:59:55
  6. 【Java】ExcelWriter自适应宽度工具类(支持中文)

    工具类 import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.CellType; import org.apache.poi.ss.usermodel.Row; import org.apache.poi.ss.usermodel.Sheet;/*** Excel工具类** author xiaoming* date 2023/11/17 10:40*/ public class ExcelUti…...

    2024/3/28 4:39:34
  7. Spring cloud负载均衡@LoadBalanced LoadBalancerClient

    LoadBalance vs Ribbon 由于Spring cloud2020之后移除了Ribbon&#xff0c;直接使用Spring Cloud LoadBalancer作为客户端负载均衡组件&#xff0c;我们讨论Spring负载均衡以Spring Cloud2020之后版本为主&#xff0c;学习Spring Cloud LoadBalance&#xff0c;暂不讨论Ribbon…...

    2024/3/28 5:03:31
  8. TSINGSEE青犀AI智能分析+视频监控工业园区周界安全防范方案

    一、背景需求分析 在工业产业园、化工园或生产制造园区中&#xff0c;周界防范意义重大&#xff0c;对园区的安全起到重要的作用。常规的安防方式是采用人员巡查&#xff0c;人力投入成本大而且效率低。周界一旦被破坏或入侵&#xff0c;会影响园区人员和资产安全&#xff0c;…...

    2024/3/27 10:27:59
  9. VB.net WebBrowser网页元素抓取分析方法

    在用WebBrowser编程实现网页操作自动化时&#xff0c;常要分析网页Html&#xff0c;例如网页在加载数据时&#xff0c;常会显示“系统处理中&#xff0c;请稍候..”&#xff0c;我们需要在数据加载完成后才能继续下一步操作&#xff0c;如何抓取这个信息的网页html元素变化&…...

    2024/3/27 3:29:54
  10. 【Objective-C】Objective-C汇总

    方法定义 参考&#xff1a;https://www.yiibai.com/objective_c/objective_c_functions.html Objective-C编程语言中方法定义的一般形式如下 - (return_type) method_name:( argumentType1 )argumentName1 joiningArgument2:( argumentType2 )argumentName2 ... joiningArgu…...

    2024/3/28 9:07:44
  11. 【洛谷算法题】P5713-洛谷团队系统【入门2分支结构】

    &#x1f468;‍&#x1f4bb;博客主页&#xff1a;花无缺 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! 本文由 花无缺 原创 收录于专栏 【洛谷算法题】 文章目录 【洛谷算法题】P5713-洛谷团队系统【入门2分支结构】&#x1f30f;题目描述&#x1f30f;输入格…...

    2024/3/28 18:09:48
  12. 【ES6.0】- 扩展运算符(...)

    【ES6.0】- 扩展运算符... 文章目录 【ES6.0】- 扩展运算符...一、概述二、拷贝数组对象三、合并操作四、参数传递五、数组去重六、字符串转字符数组七、NodeList转数组八、解构变量九、打印日志十、总结 一、概述 **扩展运算符(...)**允许一个表达式在期望多个参数&#xff0…...

    2024/3/27 3:03:23
  13. 摩根看好的前智能硬件头部品牌双11交易数据极度异常!——是模式创新还是饮鸩止渴?

    文 | 螳螂观察 作者 | 李燃 双11狂欢已落下帷幕&#xff0c;各大品牌纷纷晒出优异的成绩单&#xff0c;摩根士丹利投资的智能硬件头部品牌凯迪仕也不例外。然而有爆料称&#xff0c;在自媒体平台发布霸榜各大榜单喜讯的凯迪仕智能锁&#xff0c;多个平台数据都表现出极度异常…...

    2024/3/28 9:58:22
  14. Go语言常用命令详解(二)

    文章目录 前言常用命令go bug示例参数说明 go doc示例参数说明 go env示例 go fix示例 go fmt示例 go generate示例 总结写在最后 前言 接着上一篇继续介绍Go语言的常用命令 常用命令 以下是一些常用的Go命令&#xff0c;这些命令可以帮助您在Go开发中进行编译、测试、运行和…...

    2024/3/28 10:24:59
  15. 用欧拉路径判断图同构推出reverse合法性:1116T4

    http://cplusoj.com/d/senior/p/SS231116D 假设我们要把 a a a 变成 b b b&#xff0c;我们在 a i a_i ai​ 和 a i 1 a_{i1} ai1​ 之间连边&#xff0c; b b b 同理&#xff0c;则 a a a 能变成 b b b 的充要条件是两图 A , B A,B A,B 同构。 必要性显然&#xff0…...

    2024/3/27 0:22:43
  16. 【NGINX--1】基础知识

    1、在 Debian/Ubuntu 上安装 NGINX 在 Debian 或 Ubuntu 机器上安装 NGINX 开源版。 更新已配置源的软件包信息&#xff0c;并安装一些有助于配置官方 NGINX 软件包仓库的软件包&#xff1a; apt-get update apt install -y curl gnupg2 ca-certificates lsb-release debian-…...

    2024/3/27 8:17:26
  17. Hive默认分割符、存储格式与数据压缩

    目录 1、Hive默认分割符2、Hive存储格式3、Hive数据压缩 1、Hive默认分割符 Hive创建表时指定的行受限&#xff08;ROW FORMAT&#xff09;配置标准HQL为&#xff1a; ... ROW FORMAT DELIMITED FIELDS TERMINATED BY \u0001 COLLECTION ITEMS TERMINATED BY , MAP KEYS TERMI…...

    2024/3/28 17:15:47
  18. 【论文阅读】MAG:一种用于航天器遥测数据中有效异常检测的新方法

    文章目录 摘要1 引言2 问题描述3 拟议框架4 所提出方法的细节A.数据预处理B.变量相关分析C.MAG模型D.异常分数 5 实验A.数据集和性能指标B.实验设置与平台C.结果和比较 6 结论 摘要 异常检测是保证航天器稳定性的关键。在航天器运行过程中&#xff0c;传感器和控制器产生大量周…...

    2024/3/28 8:42:54
  19. --max-old-space-size=8192报错

    vue项目运行时&#xff0c;如果经常运行慢&#xff0c;崩溃停止服务&#xff0c;报如下错误 FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - JavaScript heap out of memory 因为在 Node 中&#xff0c;通过JavaScript使用内存时只能使用部分内存&#xff08;64位系统&…...

    2024/3/28 8:14:39
  20. 基于深度学习的恶意软件检测

    恶意软件是指恶意软件犯罪者用来感染个人计算机或整个组织的网络的软件。 它利用目标系统漏洞&#xff0c;例如可以被劫持的合法软件&#xff08;例如浏览器或 Web 应用程序插件&#xff09;中的错误。 恶意软件渗透可能会造成灾难性的后果&#xff0c;包括数据被盗、勒索或网…...

    2024/3/27 15:45:39
  21. JS原型对象prototype

    让我简单的为大家介绍一下原型对象prototype吧&#xff01; 使用原型实现方法共享 1.构造函数通过原型分配的函数是所有对象所 共享的。 2.JavaScript 规定&#xff0c;每一个构造函数都有一个 prototype 属性&#xff0c;指向另一个对象&#xff0c;所以我们也称为原型对象…...

    2024/3/27 21:26:55
  22. C++中只能有一个实例的单例类

    C中只能有一个实例的单例类 前面讨论的 President 类很不错&#xff0c;但存在一个缺陷&#xff1a;无法禁止通过实例化多个对象来创建多名总统&#xff1a; President One, Two, Three; 由于复制构造函数是私有的&#xff0c;其中每个对象都是不可复制的&#xff0c;但您的目…...

    2024/3/28 8:24:01
  23. python django 小程序图书借阅源码

    开发工具&#xff1a; PyCharm&#xff0c;mysql5.7&#xff0c;微信开发者工具 技术说明&#xff1a; python django html 小程序 功能介绍&#xff1a; 用户端&#xff1a; 登录注册&#xff08;含授权登录&#xff09; 首页显示搜索图书&#xff0c;轮播图&#xff0…...

    2024/3/28 5:29:22
  24. 电子学会C/C++编程等级考试2022年03月(一级)真题解析

    C/C++等级考试(1~8级)全部真题・点这里 第1题:双精度浮点数的输入输出 输入一个双精度浮点数,保留8位小数,输出这个浮点数。 时间限制:1000 内存限制:65536输入 只有一行,一个双精度浮点数。输出 一行,保留8位小数的浮点数。样例输入 3.1415926535798932样例输出 3.1…...

    2024/3/28 9:26:43
  25. 配置失败还原请勿关闭计算机,电脑开机屏幕上面显示,配置失败还原更改 请勿关闭计算机 开不了机 这个问题怎么办...

    解析如下&#xff1a;1、长按电脑电源键直至关机&#xff0c;然后再按一次电源健重启电脑&#xff0c;按F8健进入安全模式2、安全模式下进入Windows系统桌面后&#xff0c;按住“winR”打开运行窗口&#xff0c;输入“services.msc”打开服务设置3、在服务界面&#xff0c;选中…...

    2022/11/19 21:17:18
  26. 错误使用 reshape要执行 RESHAPE,请勿更改元素数目。

    %读入6幅图像&#xff08;每一幅图像的大小是564*564&#xff09; f1 imread(WashingtonDC_Band1_564.tif); subplot(3,2,1),imshow(f1); f2 imread(WashingtonDC_Band2_564.tif); subplot(3,2,2),imshow(f2); f3 imread(WashingtonDC_Band3_564.tif); subplot(3,2,3),imsho…...

    2022/11/19 21:17:16
  27. 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机...

    win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”问题的解决方法在win7系统关机时如果有升级系统的或者其他需要会直接进入一个 等待界面&#xff0c;在等待界面中我们需要等待操作结束才能关机&#xff0c;虽然这比较麻烦&#xff0c;但是对系统进行配置和升级…...

    2022/11/19 21:17:15
  28. 台式电脑显示配置100%请勿关闭计算机,“准备配置windows 请勿关闭计算机”的解决方法...

    有不少用户在重装Win7系统或更新系统后会遇到“准备配置windows&#xff0c;请勿关闭计算机”的提示&#xff0c;要过很久才能进入系统&#xff0c;有的用户甚至几个小时也无法进入&#xff0c;下面就教大家这个问题的解决方法。第一种方法&#xff1a;我们首先在左下角的“开始…...

    2022/11/19 21:17:14
  29. win7 正在配置 请勿关闭计算机,怎么办Win7开机显示正在配置Windows Update请勿关机...

    置信有很多用户都跟小编一样遇到过这样的问题&#xff0c;电脑时发现开机屏幕显现“正在配置Windows Update&#xff0c;请勿关机”(如下图所示)&#xff0c;而且还需求等大约5分钟才干进入系统。这是怎样回事呢&#xff1f;一切都是正常操作的&#xff0c;为什么开时机呈现“正…...

    2022/11/19 21:17:13
  30. 准备配置windows 请勿关闭计算机 蓝屏,Win7开机总是出现提示“配置Windows请勿关机”...

    Win7系统开机启动时总是出现“配置Windows请勿关机”的提示&#xff0c;没过几秒后电脑自动重启&#xff0c;每次开机都这样无法进入系统&#xff0c;此时碰到这种现象的用户就可以使用以下5种方法解决问题。方法一&#xff1a;开机按下F8&#xff0c;在出现的Windows高级启动选…...

    2022/11/19 21:17:12
  31. 准备windows请勿关闭计算机要多久,windows10系统提示正在准备windows请勿关闭计算机怎么办...

    有不少windows10系统用户反映说碰到这样一个情况&#xff0c;就是电脑提示正在准备windows请勿关闭计算机&#xff0c;碰到这样的问题该怎么解决呢&#xff0c;现在小编就给大家分享一下windows10系统提示正在准备windows请勿关闭计算机的具体第一种方法&#xff1a;1、2、依次…...

    2022/11/19 21:17:11
  32. 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”的解决方法...

    今天和大家分享一下win7系统重装了Win7旗舰版系统后&#xff0c;每次关机的时候桌面上都会显示一个“配置Windows Update的界面&#xff0c;提示请勿关闭计算机”&#xff0c;每次停留好几分钟才能正常关机&#xff0c;导致什么情况引起的呢&#xff1f;出现配置Windows Update…...

    2022/11/19 21:17:10
  33. 电脑桌面一直是清理请关闭计算机,windows7一直卡在清理 请勿关闭计算机-win7清理请勿关机,win7配置更新35%不动...

    只能是等着&#xff0c;别无他法。说是卡着如果你看硬盘灯应该在读写。如果从 Win 10 无法正常回滚&#xff0c;只能是考虑备份数据后重装系统了。解决来方案一&#xff1a;管理员运行cmd&#xff1a;net stop WuAuServcd %windir%ren SoftwareDistribution SDoldnet start WuA…...

    2022/11/19 21:17:09
  34. 计算机配置更新不起,电脑提示“配置Windows Update请勿关闭计算机”怎么办?

    原标题&#xff1a;电脑提示“配置Windows Update请勿关闭计算机”怎么办&#xff1f;win7系统中在开机与关闭的时候总是显示“配置windows update请勿关闭计算机”相信有不少朋友都曾遇到过一次两次还能忍但经常遇到就叫人感到心烦了遇到这种问题怎么办呢&#xff1f;一般的方…...

    2022/11/19 21:17:08
  35. 计算机正在配置无法关机,关机提示 windows7 正在配置windows 请勿关闭计算机 ,然后等了一晚上也没有关掉。现在电脑无法正常关机...

    关机提示 windows7 正在配置windows 请勿关闭计算机 &#xff0c;然后等了一晚上也没有关掉。现在电脑无法正常关机以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容&#xff0c;让我们赶快一起来看一下吧&#xff01;关机提示 windows7 正在配…...

    2022/11/19 21:17:05
  36. 钉钉提示请勿通过开发者调试模式_钉钉请勿通过开发者调试模式是真的吗好不好用...

    钉钉请勿通过开发者调试模式是真的吗好不好用 更新时间:2020-04-20 22:24:19 浏览次数:729次 区域: 南阳 > 卧龙 列举网提醒您:为保障您的权益,请不要提前支付任何费用! 虚拟位置外设器!!轨迹模拟&虚拟位置外设神器 专业用于:钉钉,外勤365,红圈通,企业微信和…...

    2022/11/19 21:17:05
  37. 配置失败还原请勿关闭计算机怎么办,win7系统出现“配置windows update失败 还原更改 请勿关闭计算机”,长时间没反应,无法进入系统的解决方案...

    前几天班里有位学生电脑(windows 7系统)出问题了&#xff0c;具体表现是开机时一直停留在“配置windows update失败 还原更改 请勿关闭计算机”这个界面&#xff0c;长时间没反应&#xff0c;无法进入系统。这个问题原来帮其他同学也解决过&#xff0c;网上搜了不少资料&#x…...

    2022/11/19 21:17:04
  38. 一个电脑无法关闭计算机你应该怎么办,电脑显示“清理请勿关闭计算机”怎么办?...

    本文为你提供了3个有效解决电脑显示“清理请勿关闭计算机”问题的方法&#xff0c;并在最后教给你1种保护系统安全的好方法&#xff0c;一起来看看&#xff01;电脑出现“清理请勿关闭计算机”在Windows 7(SP1)和Windows Server 2008 R2 SP1中&#xff0c;添加了1个新功能在“磁…...

    2022/11/19 21:17:03
  39. 请勿关闭计算机还原更改要多久,电脑显示:配置windows更新失败,正在还原更改,请勿关闭计算机怎么办...

    许多用户在长期不使用电脑的时候&#xff0c;开启电脑发现电脑显示&#xff1a;配置windows更新失败&#xff0c;正在还原更改&#xff0c;请勿关闭计算机。。.这要怎么办呢&#xff1f;下面小编就带着大家一起看看吧&#xff01;如果能够正常进入系统&#xff0c;建议您暂时移…...

    2022/11/19 21:17:02
  40. 还原更改请勿关闭计算机 要多久,配置windows update失败 还原更改 请勿关闭计算机,电脑开机后一直显示以...

    配置windows update失败 还原更改 请勿关闭计算机&#xff0c;电脑开机后一直显示以以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容&#xff0c;让我们赶快一起来看一下吧&#xff01;配置windows update失败 还原更改 请勿关闭计算机&#x…...

    2022/11/19 21:17:01
  41. 电脑配置中请勿关闭计算机怎么办,准备配置windows请勿关闭计算机一直显示怎么办【图解】...

    不知道大家有没有遇到过这样的一个问题&#xff0c;就是我们的win7系统在关机的时候&#xff0c;总是喜欢显示“准备配置windows&#xff0c;请勿关机”这样的一个页面&#xff0c;没有什么大碍&#xff0c;但是如果一直等着的话就要两个小时甚至更久都关不了机&#xff0c;非常…...

    2022/11/19 21:17:00
  42. 正在准备配置请勿关闭计算机,正在准备配置windows请勿关闭计算机时间长了解决教程...

    当电脑出现正在准备配置windows请勿关闭计算机时&#xff0c;一般是您正对windows进行升级&#xff0c;但是这个要是长时间没有反应&#xff0c;我们不能再傻等下去了。可能是电脑出了别的问题了&#xff0c;来看看教程的说法。正在准备配置windows请勿关闭计算机时间长了方法一…...

    2022/11/19 21:16:59
  43. 配置失败还原请勿关闭计算机,配置Windows Update失败,还原更改请勿关闭计算机...

    我们使用电脑的过程中有时会遇到这种情况&#xff0c;当我们打开电脑之后&#xff0c;发现一直停留在一个界面&#xff1a;“配置Windows Update失败&#xff0c;还原更改请勿关闭计算机”&#xff0c;等了许久还是无法进入系统。如果我们遇到此类问题应该如何解决呢&#xff0…...

    2022/11/19 21:16:58
  44. 如何在iPhone上关闭“请勿打扰”

    Apple’s “Do Not Disturb While Driving” is a potentially lifesaving iPhone feature, but it doesn’t always turn on automatically at the appropriate time. For example, you might be a passenger in a moving car, but your iPhone may think you’re the one dri…...

    2022/11/19 21:16:57