zip直链生成网站_手把手教你如何用飞桨自动生成二次元人物头像

8bec7f8d-3118-eb11-8da9-e4434bdf6706.gif

【飞桨开发者说】李思佑,昆明理工大学信息与计算科学大四本科生;2018年和2019年两次获得全国大学生数学建模比赛国家二等奖;2020年美国数学建模比赛获M奖。指导老师:昆明理工大学理学院朱志宁8dec7f8d-3118-eb11-8da9-e4434bdf6706.png想画出独一无二的动漫头像吗?不会画也没关系,深度学习的生成对抗网络(GAN)可以帮你搞定!只需要输入一些随机数,就可以让卷积神经网络为你画出精致并且独一无二的动漫头像!本文将通过趣味解读的方式,基于飞桨深度学习框架以DCGAN为例深入浅出地带您了解GAN的魔法世界!

效果展示

整体效果

下图完全是由机器创造出来的二次元人物头像,细看有些图片足以以假乱真。92ec7f8d-3118-eb11-8da9-e4434bdf6706.png

横向对比

每次生成一组shape为[1,72]的随机数,更改其中某个数值,依次生成20组随机数,作为生成网络的输入,得到横向对比图片,观察GAN带来的神奇效果,如下所示。改变发色深浅98ec7f8d-3118-eb11-8da9-e4434bdf6706.png改变头发颜色9cec7f8d-3118-eb11-8da9-e4434bdf6706.png

知识补充

GAN原理简介

论文地址:https://arxiv.org/abs/1406.2661生成对抗网络(Generative Adversarial Network ,简称GAN)是由一个生成网络与一个判别网络组成。生成网络从潜在空间(latent space)中随机采样作为输入,其输出结果需要尽量模仿训练集中的真实样本。判别网络的输入为真实样本或生成网络的输出,其目的是将生成网络的输出从真实样本中尽可能分辨出来,而生成网络则要尽可能地欺骗判别网络。两个网络相互对抗、不断调整参数,其目的是让判别网络无法判断输入是真实样本还是生成网络的输出内容。生成对抗网络常用于生成以假乱真的图片 。此外,该方法还被用于生成视频、三维物体模型等。以下简单展示了GAN的训练过程:9fec7f8d-3118-eb11-8da9-e4434bdf6706.png

DCGAN介绍

论文地址:https://arxiv.org/abs/1511.06434DCGAN是深层卷积网络与 GAN 的结合,其基本原理与 GAN 相同,只是将生成网络和判别网络用卷积网络(CNN)替代。为了提高生成样本的质量和网络的收敛速度,论文中的 DCGAN 在网络结构上进行了一些改进:取消pooling 层、加入batch normalization、使用全卷积网络、去掉了FC层。激活函数:在生成网络(G)最后一层使用Tanh函数,其余层采用 ReLu 函数 ; 判别网络(D)中都采用LeakyReLu。a2ec7f8d-3118-eb11-8da9-e4434bdf6706.png但是在实际过程中,很难得到这个完美的平衡点,关于GAN的收敛理论还在持续不断的研究中。

实现过程

本项目由Chainer项目Chainerで顔イラストの自動生成改写为PaddlePaddle项目。

本项目对原项目进行了如下几个方面的改进:
  1. 将Adam优化器beta1参数设置为0.8,具体请参考Adam: A Method for Stochastic Optimization,以进一步缓解梯度消失/爆炸问题。
  2. 将BatchNorm批归一化中momentum参数设置为0.5,调参后网络训练过程加快。
  3. 将判别网络(D)的激活函数由elu改为leakyrelu,并将alpha参数设置为0.2。elu与leakyrelu相比效果并不明显,这里改用计算复杂度更低的leakyrelu
  4. 在判别网络(D)中增加Dropout层,并将dropout_prob设置为0.4,避免过拟合和梯度消失/爆炸问题
  5. 将生成网络(G)中的第一层全连接层改为基本残差模块,加快收敛速度并使网络学习到更丰富的特征。
改进后,网络收敛速度明显加快,原项目训练时间需要300个epoch,训练超过10小时,改进后仅需要90个epoch,训练时间3个小时左右,同时生成的动漫头像在细节上层次更加丰富,生成的动漫头像风格更加多样。

开发环境

PaddlePaddle1.7.1、Python3.7、Scikit-image等以及线上平台AI Studio

数据集

数据集通过参考网络上的爬虫代码结合openCV工具进行头像截取,爬取著名的动漫图库网站的http://safebooru.donmai.us/和http://konachan.net/约6万张图片。项目所需数据集[二次元人物头像]已经上传并公开到AI Studio。

损失函数:

a3ec7f8d-3118-eb11-8da9-e4434bdf6706.png

实现过程:(AI Studio用Jupyter实现)

1. 安装缺失库、解压数据集定义数据预处理

!pip install scikit-image
!unzip data/data17962/二次元人物头像.zip -d data/
!mkdir ./work/Output
!mkdir ./work/Generate 
2. 定义数据预处理-DataReader
import osimport cv2import numpy as npimport paddle.dataset as datasetfrom skimage import io,color,transformimport matplotlib.pyplot as pltimport mathimport timeimport paddleimport paddle.fluid as fluidimport six
img_dim = 96'''准备数据,定义Reader()'''
PATH = 'data/faces/'
TEST = 'data/faces/'class DataGenerater:def __init__(self):'''初始化'''
        self.datalist = os.listdir(PATH)
        self.testlist = os.listdir(TEST)def load(self, image):'''读取图片'''
        img = io.imread(image)
        img = transform.resize(img,(img_dim,img_dim))
        img = img.transpose()
        img = img.astype('float32')return imgdef create_train_reader(self):'''给dataset定义reader'''def reader():for img in self.datalist:#print(img)try:
                    i = self.load(PATH + img)yield i.astype('float32')except Exception as e:
                    print(e)return readerdef create_test_reader(self,):'''给test定义reader'''def reader():for img in self.datalist:#print(img)try:
                    i = self.load(PATH + img)yield i.astype('float32')except Exception as e:
                    print(e)return readerdef train(batch_sizes = 32):
    reader = DataGenerater().create_train_reader()return readerdef test():
    reader = DataGenerater().create_test_reader()return reader
3. 定义网络功能模块包括卷积池化组、BatchNorm层、全连接层、反卷积层、BatchNorm卷积层。
use_cudnn = True
use_gpu = True
n = 0def bn(x, name=None, act=None,momentum=0.5):return fluid.layers.batch_norm(
        x,
        param_attr=name + '1',# 指定权重参数属性的对象
        bias_attr=name + '2',# 指定偏置的属性的对象
        moving_mean_name=name + '3',# moving_mean的名称
        moving_variance_name=name + '4',# moving_variance的名称
        name=name,
        act=act,
        momentum=momentum,
    )###卷积池化组def conv(x, num_filters,name=None, act=None):return fluid.nets.simple_img_conv_pool(
        input=x,
        filter_size=5,
        num_filters=num_filters,
        pool_size=2,# 池化窗口大小
        pool_stride=2,# 池化滑动步长
        param_attr=name + 'w',
        bias_attr=name + 'b',
        use_cudnn=use_cudnn,
        act=act
    )###全连接层def fc(x, num_filters, name=None, act=None):return fluid.layers.fc(
        input=x,
        size=num_filters,
        act=act,
        param_attr=name + 'w',
        bias_attr=name + 'b'
    )###反卷积层def deconv(x, num_filters, name=None, filter_size=5, stride=2, dilation=1, padding=2, output_size=None, act=None):return fluid.layers.conv2d_transpose(
        input=x,
        param_attr=name + 'w',
        bias_attr=name + 'b',
        num_filters=num_filters,# 滤波器数量
        output_size=output_size,# 输出图片大小
        filter_size=filter_size,# 滤波器大小
        stride=stride,# 步长
        dilation=dilation,# 膨胀比例大小
        padding=padding,
        use_cudnn=use_cudnn,# 是否使用cudnn内核
        act=act# 激活函数
    )###BatchNorm卷积层def conv_bn_layer(input,
                  ch_out,
                  filter_size,
                  stride,
                  padding,
                  act=None,
                  groups=64,
                  name=None):
    tmp = fluid.layers.conv2d(
        input=input,
        filter_size=filter_size,
        num_filters=ch_out,
        stride=stride,
        padding=padding,
        act=None,
        bias_attr=name + '_conv_b',
        param_attr=name + '_conv_w',
    )return fluid.layers.batch_norm(
        input=tmp,
        act=act,
        param_attr=name + '_bn_1',# 指定权重参数属性的对象
        bias_attr=name + '_bn_2',# 指定偏置的属性的对象
        moving_mean_name=name + '_bn_3',# moving_mean的名称
        moving_variance_name=name + '_bn_4',# moving_variance的名称
        name=name + '_bn_',
        momentum=0.5,
    )
4. 定义基本残差模块a4ec7f8d-3118-eb11-8da9-e4434bdf6706.jpeg本文采用的残差单元如上图所示,由两个输出通道数相同的3x3卷积组成。
def shortcut(input, ch_in, ch_out, stride,name):if ch_in != ch_out:return conv_bn_layer(input, ch_out, 1, stride, 0, None,name=name)else:return inputdef basicblock(input, ch_in, ch_out, stride,name,act):
    tmp = conv_bn_layer(input, ch_out, 3, stride, 1, name=name + '_1_',act=act)
    tmp = conv_bn_layer(tmp, ch_out, 3, 1, 1, act=None, name=name + '_2_')
    short = shortcut(input, ch_in, ch_out, stride,name=name)return fluid.layers.elementwise_add(x=tmp, y=short, act='relu')def layer_warp(block_func, input, ch_in, ch_out, count, stride,name,act='relu'):
    tmp = block_func(input, ch_in, ch_out, stride,name=name + '1',act=act)for i in range(1, count):
        tmp = block_func(tmp, ch_out, ch_out, 1,name=name + str(i + 1),act=act)return tmp
5. 判别网络
  • 将BatchNorm批归一化中momentum参数设置为0.5
  • 将判别网络(D)激活函数由elu改为leaky_relu,并将alpha参数设置为0.2
  • 在判别器(D)中增加Dropout层,并将dropout_prob设置为0.4
输入为大小96x96的RGB三通道图片。输出结果经过一层全连接层最后输出shape为[batch_size,2]的Tensor。
###判别器def D(x):# (96 + 2 * 1 - 4) / 2 + 1 = 48
    x = conv_bn_layer(x, 64, 4, 2, 1, act=None, name='conv_bn_1')
    x = fluid.layers.leaky_relu(x,alpha=0.2,name='leaky_relu_1')
    x = fluid.layers.dropout(x,0.4,name='dropout1')# (48 + 2 * 1 - 4) / 2 + 1 = 24
    x = conv_bn_layer(x, 128, 4, 2, 1, act=None, name='conv_bn_2')
    x = fluid.layers.leaky_relu(x,alpha=0.2,name='leaky_relu_2')
    x = fluid.layers.dropout(x,0.4,name='dropout2')# (24 + 2 * 1 - 4) / 2 + 1 = 12
    x = conv_bn_layer(x, 256, 4, 2, 1, act=None, name='conv_bn_3')
    x = fluid.layers.leaky_relu(x,alpha=0.2,name='leaky_relu_3')
    x = fluid.layers.dropout(x,0.4,name='dropout3')# (12 + 2 * 1 - 4) / 2 + 1 = 6
    x = conv_bn_layer(x, 512, 4, 2, 1, act=None, name='conv_bn_4')
    x = fluid.layers.leaky_relu(x,alpha=0.2,name='leaky_relu_4')
    x = fluid.layers.dropout(x,0.4,name='dropout4')
    x = fluid.layers.reshape(x,shape=[-1, 512 * 6 * 6])
    x = fc(x, 2, name='fc1')return x
6. 生成网络将BatchNorm批归一化中momentum参数设置为0.5。将生成器(G)中的第一层全连接层改为基本残差模块。输入Tensor的Shape为[batch_size,72],其中每个数值大小都是0~1之间的float32随机数。输出为大小96x96RGB三通道图片。
###生成器
def G(x):
    #x = fc(x,6 * 6 * 2,name='g_fc1',act='relu')
    #x = bn(x, name='g_bn_1', act='relu',momentum=0.5)
    x = fluid.layers.reshape(x, shape=[-1, 2, 6, 6])
    x = layer_warp(basicblock, x, 2, 256, 1, 1, name='g_res1', act='relu')
    # 2 * (6 - 1) - 2 * 1  + 4 = 12
    x = deconv(x, num_filters=256, filter_size=4, stride=2, padding=1, name='g_deconv_1')
    x = bn(x, name='g_bn_2', act='relu',momentum=0.5)
    # 2 * (12 - 1) - 2 * 1  + 4 = 24
    x = deconv(x, num_filters=128, filter_size=4, stride=2, padding=1, name='g_deconv_2')
    x = bn(x, name='g_bn_3', act='relu',momentum=0.5)
    # 2 * (24 - 1) - 2 * 1  + 4 = 48
    x = deconv(x, num_filters=64, filter_size=4, stride=2, padding=1, name='g_deconv_3')
    x = bn(x, name='g_bn_4', act='relu',momentum=0.5)
    # 2 * (48 - 1) - 2 * 1  + 4 = 96
    x = deconv(x, num_filters=3, filter_size=4, stride=2, padding=1, name='g_deconv_4',act='relu')
    return x
损失函数选用softmax_with_cross_entropy,公式如下:7. 训练网络设置的超参数为:
  • 学习率:2e-4
  • Epoch: 90
  • Mini-Batch:100
  • 单个随机张量大小:72
import IPython.display as displayimport warnings
warnings.filterwarnings('ignore')
img_dim = 96
LEARENING_RATE = 2e-4
SHOWNUM = 12
epoch = 90
output = "work/Output/"
batch_size = 100
G_DIMENSION = 72
d_program = fluid.Program()
dg_program = fluid.Program()###定义判别网络program# program_guard()接口配合with语句将with block中的算子和变量添加指定的全局主程序(main_program)和启动程序(start_progrom)with fluid.program_guard(d_program):# 输入图片大小为28*28
    img = fluid.layers.data(name='img', shape=[None,3,img_dim,img_dim], dtype='float32')# 标签shape=1
    label = fluid.layers.data(name='label', shape=[None,1], dtype='int64')
    d_logit = D(img)
    d_loss = loss(x=d_logit, label=label)###定义生成网络programwith fluid.program_guard(dg_program):
    noise = fluid.layers.data(name='noise', shape=[None,G_DIMENSION], dtype='float32')#label = np.ones(shape=[batch_size, G_DIMENSION], dtype='int64')# 噪声数据作为输入得到生成照片
    g_img = G(x=noise)
    g_program = dg_program.clone()
    g_program_test = dg_program.clone(for_test=True)# 判断生成图片为真实样本的概率
    dg_logit = D(g_img)# 计算生成图片被判别为真实样本的loss
    dg_loss = loss(
        x=dg_logit,
        label=fluid.layers.fill_constant_batch_size_like(input=noise, dtype='int64', shape=[-1,1], value=1)
    )###优化函数
opt = fluid.optimizer.Adam(learning_rate=LEARENING_RATE,beta1=0.5)
opt.minimize(loss=d_loss)
parameters = [p.name for p in g_program.global_block().all_parameters()]
opt.minimize(loss=dg_loss, parameter_list=parameters)
train_reader = paddle.batch(
    paddle.reader.shuffle(
        reader=train(), buf_size=50000
    ),
    batch_size=batch_size
)
test_reader = paddle.batch(
    paddle.reader.shuffle(
        reader=test(), buf_size=10000
    ),
    batch_size=10
)###执行器if use_gpu:
    exe = fluid.Executor(fluid.CUDAPlace(0))else:
    exe = fluid.Executor(fluid.CPUPlace())
start_program = fluid.default_startup_program()
exe.run(start_program)#加载模型#fluid.io.load_persistables(exe,'work/Model/D/',d_program)#fluid.io.load_persistables(exe,'work/Model/G/',dg_program)###训练过程
t_time = 0
losses = [[], []]# 判别器迭代次数
NUM_TRAIN_TIME_OF_DG = 2# 最终生成的噪声数据
const_n = np.random.uniform(
    low=0.0, high=1.0,
    size=[batch_size, G_DIMENSION]).astype('float32')
test_const_n = np.random.uniform(
    low=0.0, high=1.0,
    size=[100, G_DIMENSION]).astype('float32')#plt.ion()
now = 0for pass_id in range(epoch):
    fluid.io.save_persistables(exe, 'work/Model/G', dg_program)
    fluid.io.save_persistables(exe, 'work/Model/D', d_program)for batch_id, data in enumerate(train_reader()):  # enumerate()函数将一个可遍历的数据对象组合成一个序列列表if len(data) != batch_size:continue# 生成训练过程的噪声数据
        noise_data = np.random.uniform(
            low=0.0, high=1.0,
            size=[batch_size, G_DIMENSION]).astype('float32')# 真实图片
        real_image = np.array(data)# 真实标签
        real_labels = np.ones(shape=[batch_size,1], dtype='int64')# real_labels = real_labels * 10# 虚假标签
        fake_labels = np.zeros(shape=[batch_size,1], dtype='int64')
        s_time = time.time()#print(np.max(noise_data))# 虚假图片
        generated_image = exe.run(g_program,
                                  feed={'noise': noise_data},
                                  fetch_list=[g_img])[0]###训练判别器# D函数判断虚假图片为假的loss
        d_loss_1 = exe.run(d_program,
                           feed={'img': generated_image,'label': fake_labels,
                           },
                           fetch_list=[d_loss])[0][0]# D函数判断真实图片为真的loss
        d_loss_2 = exe.run(d_program,
                           feed={'img': real_image,'label': real_labels,
                           },
                           fetch_list=[d_loss])[0][0]
        d_loss_n = d_loss_1 + d_loss_2
        losses[0].append(d_loss_n)###训练生成器for _ in six.moves.xrange(NUM_TRAIN_TIME_OF_DG):
            noise_data = np.random.uniform(  # uniform()方法从一个均匀分布[low,high)中随机采样
                low=0.0, high=1.0,
                size=[batch_size, G_DIMENSION]).astype('float32')
            dg_loss_n = exe.run(dg_program,
                                feed={'noise': noise_data},
                                fetch_list=[dg_loss])[0][0]
        losses[1].append(dg_loss_n)
        t_time += (time.time() - s_time)if batch_id % 500 == 0:if not os.path.exists(output):
                os.makedirs(output)# 每轮的生成结果
            generated_image = exe.run(g_program_test, feed={'noise': test_const_n}, fetch_list=[g_img])[0]#print(generated_image[1])
            imgs = []
            plt.figure(figsize=(15,15))try:for i in range(100):
                    image = generated_image[i].transpose()
                    plt.subplot(10, 10, i + 1)
                    plt.imshow(image)
                    plt.axis('off')
                    plt.xticks([])
                    plt.yticks([])
                    plt.subplots_adjust(wspace=0.1, hspace=0.1)# plt.subplots_adjust(wspace=0.1,hspace=0.1)
                msg = 'Epoch ID={0} Batch ID={1} \n D-Loss={2} G-Loss={3}'.format(pass_id + 92, batch_id, d_loss_n, dg_loss_n)#print(msg)
                plt.suptitle(msg,fontsize=20)
                plt.draw()#if batch_id % 10000 == 0:
                plt.savefig('{}/{:04d}_{:04d}.png'.format(output, pass_id + 92, batch_id),bbox_inches='tight')
                plt.pause(0.01)
                display.clear_output(wait=True)#plt.pause(0.01)except IOError:
                print(IOError)#plt.ioff()
plt.close()
plt.figure(figsize=(15, 6))
x = np.arange(len(losses[0]))
plt.title('Loss')
plt.xlabel('Number of Batch')
plt.plot(x,np.array(losses[0]),'r-',label='D Loss')
plt.plot(x,np.array(losses[1]),'b-',label='G Loss')
plt.legend()
plt.savefig('work/Train Process')
plt.show()
得到的损失变化曲线为:a8ec7f8d-3118-eb11-8da9-e4434bdf6706.png

项目总结

简单介绍了一下DCGAN的原理,通过对原项目的改进和优化,一步一步依次对生成网络和判别网络以及训练过程进行介绍。通过横向对比某个输入元素对生成图片的影响。平均更改其中某个数值,依次生成20组随机数,输入生成器,得到横向对比图片,得到GAN神奇的过渡。DCGAN生成的二次元头像仔细看有些图片确实是足以以假乱真的,通过DCGAN了解到GAN的强大“魔力”。不足之处是生成的图片分辨率比较低(96X96),在以后的项目我会通过改进网络使得生成的二次元头像有更高的分辨率和更丰富的细节。个人AI Studio主页:https://aistudio.baidu.com/aistudio/personalcenter/thirdview/56447如在使用过程中有问题,可加入飞桨官方QQ群进行交流:703252161。如果您想详细了解更多飞桨的相关内容,请参阅以下文档。飞桨生成对抗网络项目地址:GitHub: https://github.com/PaddlePaddle/models/tree/release/1.8/PaddleCV/ganGitee:https://gitee.com/paddlepaddle/models/tree/develop/PaddleCV/gan官网地址:https://www.paddlepaddle.org.cn飞桨开源框架项目地址:GitHub:https://github.com/PaddlePaddle/PaddleGitee: https://gitee.com/paddlepaddle/Paddle

END

abec7f8d-3118-eb11-8da9-e4434bdf6706.jpeg

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

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

相关文章

Gradle入门到实战(一) — 全面了解Gradle

声明:本文来自汪磊的博客,转载请注明出处 可关注个人公众号,那里更新更及时,阅读体验更好: 友情提示由于文章是从个人公众号拷贝过来整理的,发现图片没有正常显示,没关注公众号的同学可通过如下…

javaweb 图书管理系统完整代码_看一名Java开发人员以红队思维五分钟审计一套代码(续)...

前言上篇文章的发布引起了很多读者的浏览,有很多读者也催更希望读到续集,作者也收获到读者的鼓励,说明这条路线对大家有帮助,是有意义的。所以,今天作者将继续阐述在审计Java代码时的思路。概述上篇文章所讲的SQL注入和…

爱立信数据分析解决方案抓住物联网发展机遇

爱立信在2016年1月6日至9日于美国拉斯维加斯举办的国际消费电子展(CES)上推出“用户和物联网数据分析”解决方案。该解决方案将能帮助运营商提高对用户和物联网终端的内部管理效率,同时探索跨越多个垂直领域的新型物联网应用。 用户和物联网数…

JAVA实现在面板中添加图表_Java 创建PowerPoint图表并为其添加趋势线

图表,是指将既得数据用图形的方式表示出来。在前文中我们介绍过如何使用Java程序来为Excel文档创建图表的方法。本文将通过使用Java程序来演示如何创建PowerPoint图表及为图表添加趋势线。趋势线的运用能够显示数据的变化趋势,同时能够帮助预测数据的未来…

idea设置中文界面_《英雄联盟手游》设置界面中文翻译图分享 外服汉化界面一览...

导读 英雄联盟手游目前以及正式上线了,不过现在的话是没有中文版的,只有外服,所有很多地方是看不懂的,也不明白的,这样的话就需要翻译了,具体要怎么设置会比较,相关的步骤是什么呢?下…

安卓10不支持qmc解码_官宣:安卓10已发布!21款手机已适配,小米华为率先支持...

随着今天凌晨谷歌 I/O 大会的召开,Android Q 也就是安卓10正式官宣,新版的安卓10加入了诸多新手势,从 Home 键设计上看,安卓10 的新版手势很大程度上有疑似借鉴 iOS 的手势,底部一个长条,作为 Home 用来返回…

linux系统编程之进程(七):system()函数使用【转】

本文转载自:http://www.cnblogs.com/mickole/p/3187974.html 一,system()理解 功能:system()函数调用“/bin/sh -c command”执行特定的命令,阻塞当前进程直到command命令执行完毕 原型: int system(const char *comma…

汉王云名片识别(SM)组件开发详解

大家好,最近在DeviceOne平台上做了一个汉王云名片识别的功能组件。下面把我开发过程给大家做一个分享,希望可以帮助到大家。 下面我把我的思路给大家讲解一下。1.找到我要集成的sdk,也就是汉王云名片的sdk下载(android和ios&#…

[App Store Connect帮助]八、维护您的 App(4.2)查看评分与评论

您可以查看 App 的总评分或单个顾客评论。如有必要,您可以针对某条评论报告问题。 【注】顾客可以为您的 iOS 和 macOS App 评分并撰写评论,但只能为 Apple TVOS App 评分。 必要职能:“帐户持有人”职能、“管理”职能、“App 管理”职能、“…

visio studio json工具_《产品经理入门指南》彩蛋2:别技淫原型图!你的Visio和Balsamiq Mockup入门了吗?...

温馨提示:如果你有关于产品经理方面的任何问题,欢迎关注我的微信公众号与我互动。最新的免费系统的产品经理课程《老司机带你做产品》已经推出,请关注微信公众号:iamliuwenzhi很多产品新人刚开始工作时,喜欢一拿到需求…

mysql牵引例子_MySQL学习06(事务和索引)

事务概述什么是事务事务就是将一组SQL语句放在同一批次内去执行如果一个SQL语句出错,则该批次内的所有SQL都将被取消执行MySQL事务处理只支持InnoDB和BDB数据表类型事务的ACID原则原子性(Atomic)整个事务中的所有操作,要么全部完成,要么全部不完成&#…

android操作系统 真的吗_旋挖机培训学校真的能学会吗,旋挖钻机到底有哪些操作系统...

旋挖机培训学校真的能学会吗添加微:yywyyc 旋挖钻机到底有哪些操作系统【前言】很多使用旋挖钻机或者想要了解旋挖钻机的工程公司可能不是特别了解旋挖钻机本身的系统以及部件,本篇文章针对旋挖钻机的操作系统来给大家介绍一下,让大家了…

WebAPI 2参数绑定方法

简单类型参数 Example 1: Sending a simple parameter in the Url [RoutePrefix("api/values")] public class ValuesController : ApiController {// http://localhost:49407/api/values/example1?id2[Route("example1")][HttpGet]public string Get(int…

java怎么引入html文件路径_如何在public_html中读取文件但在域外?使用相对路径...

我正在尝试从我的(附加组件)域目录之外的目录中读取文件 . 这是我的目录结构:public_html /domain /file_read.phpfile_write.phpsensitive /file.dat虽然我能够使用“../sensitive/file.dat”写入敏感,但我无法使用相同的方法进行读取 . 有什么想法吗&a…

csv文件怎么转成excel_Java读写excel,excel转成json写入磁盘文件

pom读写excel主要的dependency<dependency> <groupId>org.apache.poigroupId> <artifactId>poiartifactId> <version>3.16version> dependency> <dependency> <groupId>org.apache.poigroupId> …

前端做CRM管理系统是做什么_代办行业的CRM客户关系管理系统应该是什么样子的?...

随着互联网的深耕细化&#xff0c;很多企业也在不断优化自己的办公方式&#xff0c;以优化企业的办公流程&#xff0c;提高企业的办事效率。因此实现办公自动化&#xff0c;或者说实现数字化办公就需要逐渐提上日程。今天给大家讲讲可以帮助代办行业实现办公自动化的产品&#…

蓝牙 sig base uuid_蓝牙模块采用陶瓷天线和PCB天线的区别

一、陶瓷天线陶瓷天线是一种适合于蓝牙设备使用的小型化天线,又分为块状陶瓷天线和多层陶瓷天线。陶瓷天线占用空间很小、性能比较好&#xff1b; 带宽窄&#xff0c;比较难做到多频段&#xff1b;有效提高主板的整合度&#xff0c;并可降低天线对ID的限制&#xff1b;需要在主…

app启动页自动跳转源码_关于移动端App启动页的策划方案

App启动页是指app在启东时需要加载必要的运行环境和配置&#xff0c;在这个过程中提示用户等待的一个过渡页面。在产品经理眼里启动页是app给予用户重要的第一印象&#xff1b;也是App最重要的黄金页面之一&#xff0c;所有用户100%都会看到的页面。启动页适合用来做以下几个事…

java 如何排查内存溢出_java 内存溢出排查

测试代码&#xff0c;如下示例&#xff1a;import java.util.ArrayList;import java.util.List;/*** Description 测试内存溢出, 启动时设置参数&#xff0c;最大堆内存为1m, 内存溢出时dump出内存文件 -Xmx1m -XX:HeapDumpOutOfMemoryError* Author luzy* Date 2018/10/5 11:0…

《企业级ios应用开发实战》一2.2 iOS框架介绍

2.2 iOS框架介绍 iOS衍生自Mac OS X的成熟内核&#xff0c;但iOS操作系统更紧凑和高效&#xff0c;支持iPhone和iPod Touch的硬件。iOS继承了Mac OS X的风格&#xff0c;包括&#xff1a;统一的OS X 内核&#xff0c;针对网络的BSD套接字&#xff0c;以及Objective-C和C/C编译器…