Skip to content
WONGCW 網誌
  • 首頁
  • 論壇
  • 微博
  • 壁紙下載
  • 免費圖床
  • 視頻下載
  • 聊天室
  • SEO工具
  • 支援中心
  • 表格製作
  • More
    • 在線名片
    • 網頁搜索
    • 天氣預報
    • 二維碼生成器
    • WordPress 插件及主題下載
  • Search Icon

WONGCW 網誌

記錄生活經驗與點滴

TensorFlow – 基于 GANs 生成人脸

TensorFlow – 基于 GANs 生成人脸

2018-09-24 Comments 0 Comment

简介

任务时间:时间未知

给定一批样本,基于 TensoFlow 训练 GANs 网络,能够生成类似的新样本,本教程主要参考 Brandon Amos 的 Image Completion 博客,GANs 网络包含 generator 网络(随机信号 z 作为输入,生成人脸图片)和 discriminator 网络(判断图片是否是人脸)。

步骤简介

本教程一共分为四个部分

  • generate_face.py – 读取人脸训练数据、产生随机数;
  • gan_model.py – GANs 网络模型;
  • train_gan.py – 训练 GANs 网络模型;
  • predict_gan.py – 生成人脸。

数据学习

任务时间:时间未知

获取训练数据

我们在腾讯云的 COS 上准备了 CelebA 训练数据,使用 wget 命令获取:

wget http://tensorflow-1253675457.cosgz.myqcloud.com/face/img_align_celeba.zip
unzip -q img_align_celeba.zip

数据预处理

安装依赖库

pip install scipy
pip install pillow

处理思路:

  • 原始图片大小为 218 x 178 ,从中间裁剪 108 x 108 区域,然后缩小为 64 x 64。
  • 生成维度为 100 服从正态分布的随机向量,作为 generator 网络的输入,生成新的人脸图片。

示例代码:

现在您可以在 /home/ubuntu 目录下创建源文件 generate_face.py,内容可参考:

示例代码:/home/ubuntu/generate_face.py
#-*- coding:utf-8 -*-
import itertools
import os
from glob import glob
import numpy as np
import scipy.misc
import tensorflow as tf


def image_manifold_size(num_images):
    manifold_h = int(np.floor(np.sqrt(num_images)))
    manifold_w = int(np.ceil(np.sqrt(num_images)))
    assert manifold_h * manifold_w == num_images
    return manifold_h, manifold_w

def merge(images, size):
    h, w = images.shape[1], images.shape[2]
    img = np.zeros((int(h * size[0]), int(w * size[1]), 3))
    for idx, image in enumerate(images):
        i = idx % size[1]
        j = idx // size[1]
        img[j*h:j*h+h, i*w:i*w+w, :] = image
    return img

def imsave(images, size, path):
    img = merge(images, size)
    return scipy.misc.imsave(path, (255*img).astype(np.uint8))

def inverse_transform(images):
    return (images+1.)/2.

def save_images(images,size,image_path):
    return imsave(inverse_transform(images), size, image_path)

class generateFace:
    def __init__(self,hparams):
        self.formats = ["png","jpg","jpeg"]
        self.datas_path = self.get_datas_path(hparams.data_root)
        self.datas_size = len(self.datas_path)
        self.crop_h = hparams.crop_h
        self.crop_w = hparams.crop_w
        self.resize_h = hparams.resize_h
        self.resize_w = hparams.resize_w
        self.is_crop = hparams.is_crop
        self.z_dim = hparams.z_dim
        self._index_in_epoch = 0

    def get_datas_path(self,data_root):
        return list(itertools.chain.from_iterable(
            glob(os.path.join(data_root,"*.{}".format(ext))) for ext in self.formats))

    def get_image(self,path):
        img = scipy.misc.imread(path,mode='RGB').astype(np.float)
        if(self.is_crop): #截取中间部分
            h,w = img.shape[:2] #图像宽、高
            assert(h > self.crop_h and w > self.crop_w)
            j = int(round((h - self.crop_h)/2.))
            i = int(round((w - self.crop_w)/2.))
            img = img[j:j+self.crop_h,i:i+self.crop_w]
        img = scipy.misc.imresize(img,[self.resize_h,self.resize_w])
        return np.array(img)/127.5 - 1.

    def get_batch(self,batch_files):
        batch_images = [self.get_image(path) for path in batch_files]
        batch_images = np.array(batch_images).astype(np.float32)
        batch_z = np.random.uniform(-1,1,size=(len(batch_files),self.z_dim))
        return batch_images,batch_z

    def get_sample(self,sample_size):
        assert(self.datas_size > sample_size)
        np.random.shuffle(self.datas_path)
        sample_files = self.datas_path[0:sample_size]
        return self.get_batch(sample_files)

    def next_batch(self,batch_size):
        assert(self.datas_size > batch_size)
        start = self._index_in_epoch
        self._index_in_epoch += batch_size
        if(self._index_in_epoch > self.datas_size):
            np.random.shuffle(self.datas_path)
            start = 0
            self._index_in_epoch = batch_size
        end = self._index_in_epoch
        batch_files = self.datas_path[start:end]
        return self.get_batch(batch_files)

生成数据:

我们可以直观感受下生成的数据。可以在终端中一步一步执行下面命令:

  • 启动 python:
cd /home/ubuntu/
python
from generate_face import *
import tensorflow as tf
  • 初始化 generate_face
hparams = tf.contrib.training.HParams(
    data_root = './img_align_celeba',
    crop_h = 108,
    crop_w = 108,
    resize_h = 64,
    resize_w = 64,
    is_crop = True,
    z_dim = 100,
    batch_size = 64,
    sample_size = 64,
    output_h = 64,
    output_w = 64,
    gf_dim = 64,
    df_dim = 64)
face = generateFace(hparams)
  • 查看处理后的人脸数据和随机数据 z
img,z = face.next_batch(1)
z
save_images(img,(1,1),"test.jpg")

模型学习

任务时间:时间未知

GANs 模型

  • generator 网络:五层网络,采用反卷积,从 100 维的 z 信号生成人脸图片,网络结构见下图:

  • discriminator 网络:是一个五层的判别网络,网络结构见下图:

示例代码:

现在您可以在 /home/ubuntu 目录下创建源文件 gan_model.py,内容可参考:

示例代码:/home/ubuntu/gan_model.py
#-*- coding:utf-8 -*-
import tensorflow as tf
import math

class batch_norm(object):
    def __init__(self, epsilon=1e-5, momentum = 0.9, name="batch_norm"):
        with tf.variable_scope(name):
            self.epsilon = epsilon
            self.momentum = momentum
            self.name = name
    def __call__(self,x,train):
        return tf.contrib.layers.batch_norm(x, decay=self.momentum, updates_collections=None, epsilon=self.epsilon,
                                            center=True, scale=True, is_training=train, scope=self.name)
class ganModel:
    def __init__(self,hparams):
        self.batch_size = hparams.batch_size
        self.gf_dim = hparams.gf_dim
        self.df_dim = hparams.df_dim
        self.output_h = hparams.output_h
        self.output_w = hparams.output_w
        #batch normalization
        self.d_bn1 = batch_norm(name='d_bn1')
        self.d_bn2 = batch_norm(name='d_bn2')
        self.d_bn3 = batch_norm(name='d_bn3')
        self.d_bn3 = batch_norm(name='d_bn3')
        self.g_bn0 = batch_norm(name='g_bn0')
        self.g_bn1 = batch_norm(name='g_bn1')
        self.g_bn2 = batch_norm(name='g_bn2')
        self.g_bn3 = batch_norm(name='g_bn3')
        self.global_step = tf.Variable(1, trainable=False)

    def linear(self,input_z,output_size,scope=None, stddev=0.02, bias_start=0.0):
        shape = input_z.get_shape().as_list()
        with tf.variable_scope(scope or "linear"):
            matrix = tf.get_variable("Matrix", [shape[1], output_size], tf.float32,
                                     tf.random_normal_initializer(stddev=stddev))
            bias = tf.get_variable("bias", [output_size],
                                   initializer=tf.constant_initializer(bias_start))
            return tf.matmul(input_z,matrix) + bias

    def conv2d_transpose(self,input_, output_shape,
                         k_h=5, k_w=5, d_h=2, d_w=2, stddev=0.02,
                         name="conv2d_transpose"):
        with tf.variable_scope(name):
            w = tf.get_variable('w', [k_h, k_w, output_shape[-1], input_.get_shape()[-1]],
                                initializer=tf.random_normal_initializer(stddev=stddev))
            deconv = tf.nn.conv2d_transpose(input_, w, output_shape=output_shape,
                                            strides=[1, d_h, d_w, 1])
            biases = tf.get_variable('biases', [output_shape[-1]], initializer=tf.constant_initializer(0.0))
            deconv = tf.nn.bias_add(deconv, biases)
            return deconv

    def conv2d(self,image,output_dim,
               k_h=5, k_w=5, d_h=2, d_w=2, stddev=0.02,
               name="conv2d"):
        with tf.variable_scope(name):
            w = tf.get_variable('w', [k_h, k_w, image.get_shape()[-1], output_dim],
                                initializer=tf.truncated_normal_initializer(stddev=stddev))
            conv = tf.nn.conv2d(image, w, strides=[1, d_h, d_w, 1], padding='SAME')
            biases = tf.get_variable('biases', [output_dim], initializer=tf.constant_initializer(0.0))
            conv = tf.nn.bias_add(conv, biases)
            return conv

    def lrelu(self,x, leak=0.2, name="lrelu"):
        with tf.variable_scope(name):
            f1 = 0.5 * (1 + leak)
            f2 = 0.5 * (1 - leak)
            return f1 * x + f2 * abs(x)

    def conv_out_size_same(self,size, stride):
        return int(math.ceil(float(size) / float(stride)))

    def generator(self,z,is_training):
        with tf.variable_scope("generator") as scope:
            s_h, s_w = self.output_h, self.output_w  #64*64
            s_h2, s_w2 = self.conv_out_size_same(s_h, 2), self.conv_out_size_same(s_w, 2) #32*32
            s_h4, s_w4 = self.conv_out_size_same(s_h2, 2), self.conv_out_size_same(s_w2, 2) #16*16
            s_h8, s_w8 = self.conv_out_size_same(s_h4, 2), self.conv_out_size_same(s_w4, 2) #8*8
            s_h16, s_w16 = self.conv_out_size_same(s_h8, 2), self.conv_out_size_same(s_w8, 2) #4*4

            z_ = self.linear(z,self.gf_dim*8*s_h16*s_w16,'g_h0_lin')
            h0 = tf.reshape(z_,[-1,s_h16,s_w16,self.gf_dim*8])
            h0 = tf.nn.relu(self.g_bn0(h0,is_training))

            h1 = self.conv2d_transpose(h0,[self.batch_size,s_h8,s_w8,self.gf_dim*4],name='g_h1')
            h1 = tf.nn.relu(self.g_bn1(h1,is_training))

            h2 = self.conv2d_transpose(h1,[self.batch_size,s_h4,s_w4,self.gf_dim*2],name='g_h2')
            h2 = tf.nn.relu(self.g_bn2(h2,is_training))

            h3 = self.conv2d_transpose(h2,[self.batch_size,s_h2,s_w2,self.gf_dim*1],name='g_h3')
            h3 = tf.nn.relu(self.g_bn3(h3,is_training))

            h4 = self.conv2d_transpose(h3,[self.batch_size,s_h,s_w,3],name='g_h4')

            return tf.nn.tanh(h4)

    def discriminator(self,image,is_training,reuse=False):
        with tf.variable_scope("discriminator") as scope:
            if reuse:
                scope.reuse_variables()

            h0 = self.lrelu(self.conv2d(image, self.df_dim, name='d_h0_conv'))
            h1 = self.lrelu(self.d_bn1(self.conv2d(h0, self.df_dim*2, name='d_h1_conv'), is_training))
            h2 = self.lrelu(self.d_bn2(self.conv2d(h1, self.df_dim*4, name='d_h2_conv'), is_training))
            h3 = self.lrelu(self.d_bn3(self.conv2d(h2, self.df_dim*8, name='d_h3_conv'), is_training))
            h3 = tf.reshape(h3,[-1,8192]) #8192 = self.df_dim*8*4*4
            h4 = self.linear(h3,1,'d_h4_lin')

            return tf.nn.sigmoid(h4), h4

    def build_model(self,is_training,images,z):
        z_sum = tf.summary.histogram("z",z)

        G = self.generator(z,is_training)
        D,D_logits = self.discriminator(images,is_training)
        D_,D_logits_ = self.discriminator(G,is_training,reuse=True)

        d_sum = tf.summary.histogram("d",D)
        d__sum = tf.summary.histogram("d_",D_)
        G_sum = tf.summary.image("G", G)

        d_loss_real = tf.reduce_mean(
            tf.nn.sigmoid_cross_entropy_with_logits(logits=D_logits,
                                                    labels=tf.ones_like(D)))#对于discriminator,尽量判断images是货真价实
        d_loss_fake = tf.reduce_mean(
            tf.nn.sigmoid_cross_entropy_with_logits(logits=D_logits_,
                                                    labels=tf.zeros_like(D_)))#对于discriminator,尽量判断G是伪冒

        d_loss_real_sum = tf.summary.scalar("d_loss_real",d_loss_real)
        d_loss_fake_sum = tf.summary.scalar("d_loss_fake",d_loss_fake)

        g_loss = tf.reduce_mean(
            tf.nn.sigmoid_cross_entropy_with_logits(logits=D_logits_,
                                                    labels=tf.ones_like(D_)))#对于generator,尽量然D判断G是货真价实的
        d_loss = d_loss_real + d_loss_fake

        g_loss_sum = tf.summary.scalar("g_loss", g_loss)
        d_loss_sum = tf.summary.scalar("d_loss", d_loss)

        t_vars = tf.trainable_variables() #discriminator、generator两个网络参数分开训练
        d_vars = [var for var in t_vars if 'd_' in var.name]
        g_vars = [var for var in t_vars if 'g_' in var.name]

        g_sum = tf.summary.merge([z_sum,d__sum,G_sum,d_loss_fake_sum,g_loss_sum])
        d_sum = tf.summary.merge([z_sum,d_sum,d_loss_real_sum,d_loss_sum])

        return g_loss,d_loss,g_vars,d_vars,g_sum,d_sum,G

    def optimizer(self,g_loss,d_loss,g_vars,d_vars,learning_rate = 0.0002,beta1=0.5):
        d_optim = tf.train.AdamOptimizer(learning_rate,beta1=beta1).minimize(d_loss,global_step=self.global_step,var_list=d_vars)
        g_optim = tf.train.AdamOptimizer(learning_rate,beta1=beta1).minimize(g_loss,var_list=g_vars)
        return d_optim,g_optim

训练 GANs 模型

训练 13 万次后,损失函数基本保持不变,单个 GPU 大概需要 6 个小时左右,如果采用 CPU 大概需要 1 天半的时间,你可以调整循环次数,体验下训练过程,可以直接下载我们训练好的模型。

示例代码:

现在您可以在 /home/ubuntu 目录下创建源文件 train_gan.py,内容可参考:

示例代码:/home/ubuntu/train_gan.py
#-*- coding:utf-8 -*-
from generate_face import *
from gan_model import ganModel
import tensorflow as tf

if __name__ == '__main__':
    hparams = tf.contrib.training.HParams(
        data_root = './img_align_celeba',
        crop_h = 108,    #对原始图片裁剪后高
        crop_w = 108,    #对原始图片裁剪后宽
        resize_h = 64,   #对裁剪后图片缩放的高
        resize_w = 64,   #对裁剪图片缩放的宽
        is_crop = True,  #是否裁剪
        z_dim = 100,     #随机噪声z的维度,用户generator生成图片
        batch_size = 64, #批次
        sample_size = 64,#选取作为测试样本
        output_h = 64,   #generator生成图片的高
        output_w = 64,   #generator生成图片的宽
        gf_dim = 64,     #generator的feature map的deep
        df_dim = 64)     #discriminator的feature map的deep
    face = generateFace(hparams)
    sample_images,sample_z = face.get_sample(hparams.sample_size)
    is_training = tf.placeholder(tf.bool,name='is_training')
    images = tf.placeholder(tf.float32, [None,hparams.resize_h,hparams.output_w,3],name='real_images')
    z = tf.placeholder(tf.float32, [None,hparams.z_dim], name='z')
    model = ganModel(hparams)
    g_loss,d_loss,g_vars,d_vars,g_sum,d_sum,G = model.build_model(is_training,images,z)
    d_optim,g_optim = model.optimizer(g_loss,d_loss,g_vars,d_vars)

    saver = tf.train.Saver(tf.global_variables())
    with tf.Session() as sess:
        ckpt = tf.train.get_checkpoint_state('./ckpt')
        if ckpt and tf.train.checkpoint_exists(ckpt.model_checkpoint_path):
            print("Reading model parameters from %s" % ckpt.model_checkpoint_path)
            saver.restore(sess, ckpt.model_checkpoint_path)
        else:
            print("Created model with fresh parameters.")
            sess.run(tf.global_variables_initializer())
        summary_writer = tf.summary.FileWriter("train_gan", sess.graph)
        step = 0
        while True:
            step = model.global_step.eval()
            batch_images,batch_z = face.next_batch(hparams.batch_size)
            #Update D network
            _, summary_str = sess.run([d_optim,d_sum],
                                           feed_dict={images:batch_images, z:batch_z, is_training:True})
            summary_writer.add_summary(summary_str,step)

            #Update G network
            _, summary_str = sess.run([g_optim,g_sum],
                                           feed_dict={z:batch_z, is_training:True})
            summary_writer.add_summary(summary_str,step)

            d_err = d_loss.eval({images:batch_images, z:batch_z, is_training:False})
            g_err = g_loss.eval({z:batch_z,is_training:False})
            print("step:%d,d_loss:%f,g_loss:%f" % (step,d_err,g_err))
            if step%1000 == 0:
                samples, d_err, g_err = sess.run([G,d_loss,g_loss],
                                                   feed_dict={images:sample_images, z:sample_z, is_training:False})
                print("sample step:%d,d_err:%f,g_err:%f" % (step,d_err,g_err))
                save_images(samples,image_manifold_size(samples.shape[0]), './samples/train_{:d}.png'.format(step))
                saver.save(sess,"./ckpt/gan.ckpt",global_step = step)

然后执行:

cd /home/ubuntu;
python train_gan.py

执行结果:

step:1,d_loss:1.276464,g_loss:0.757655
step:2,d_loss:1.245563,g_loss:0.916217
step:3,d_loss:1.253453,g_loss:1.111729
step:4,d_loss:1.381798,g_loss:1.408796
step:5,d_loss:1.643821,g_loss:1.928348
step:6,d_loss:1.770768,g_loss:2.165831
step:7,d_loss:2.172084,g_loss:2.746789
step:8,d_loss:2.192665,g_loss:3.120509

下载已有模型:

wget http://tensorflow-1253675457.cosgz.myqcloud.com/face/GANs_model.zip
unzip -o GANs_model.zip

生成人脸

利用训练好的模型,我们可以开始生成人脸。

示例代码:

现在您可以在 /home/ubuntu 目录下创建源文件 predict_gan.py,内容可参考:

示例代码:/home/ubuntu/predict_gan.py
#-*- coding:utf-8 -*-
from generate_face import *
from gan_model import ganModel
import tensorflow as tf
import numpy as np

if __name__ == '__main__':
    hparams = tf.contrib.training.HParams(
        z_dim = 100,
        batch_size = 1,
        gf_dim = 64,
        df_dim = 64,
        output_h = 64,
        output_w = 64)

    is_training = tf.placeholder(tf.bool,name='is_training')
    z = tf.placeholder(tf.float32, [None,hparams.z_dim], name='z')
    sample_z = np.random.uniform(-1,1,size=(hparams.batch_size,hparams.z_dim))
    model = ganModel(hparams)
    G = model.generator(z,is_training)
    saver = tf.train.Saver()
    with tf.Session() as sess:
        saver.restore(sess,"gan.ckpt-130000")
        samples = sess.run(G,feed_dict={z:sample_z,is_training:False})
        save_images(samples,image_manifold_size(samples.shape[0]),'face.png')
        print("done")

然后执行:

cd /home/ubuntu
python predict_gan.py

执行结果:

现在您可以在 查看 /home/ubuntu/face.png

完成实验

任务时间:时间未知

实验内容已完成

您可进行更多关于机器学习教程:

  • 实验列表 – 机器学习

关于 TensorFlow 的更多资料可参考 TensorFlow 官网 。

推荐活动

  • 学生主机 10 元起

推荐实验

  • TensorFlow – 相关 API
  • 搭建微信 AI 机器人
  • Linux 下部署 Django 环境
  • Python 爬虫 1 – Requests 库入门与实战
  • 部署与发布之Linux服务器

相关产品

分享此文:

  • 分享到 Twitter(在新視窗中開啟)
  • 按一下以分享至 Facebook(在新視窗中開啟)
  • 分享到 WhatsApp(在新視窗中開啟)
  • 按一下以分享到 Telegram(在新視窗中開啟)
  • 分享到 Pinterest(在新視窗中開啟)
  • 分享到 Reddit(在新視窗中開啟)
  • 按一下即可分享至 Skype(在新視窗中開啟)
  • 按一下即可以電子郵件傳送連結給朋友(在新視窗中開啟)
  • 點這裡列印(在新視窗中開啟)

相關


TensorFlow

Post navigation

PREVIOUS
TensorFlow – 基于 RNN 训练聊天机器人
NEXT
Windows 10 Build 17763极有可能成为十月更新的RTM版

發表迴響 取消回覆

這個網站採用 Akismet 服務減少垃圾留言。進一步了解 Akismet 如何處理網站訪客的留言資料。

More results...

Generic filters
Exact matches only
Search in title
Search in content
Search in excerpt
Filter by 分類
網站公告
Featured
限時免費
ESET NOD32
WINDOWS 10 &11 INSIDER PREVIEW
Windows 軟件下載
系統軟件
辦公軟件
圖像處理
影音媒體
網絡軟件
應用軟件
Mac 軟件下載
安卓軟件下載
網絡資訊
Mac資訊
Linux資訊
VPS資訊
NASA資訊
金融資訊
WhatsApp Stickers教學
WordPress資訊
WeChat資訊
PHP資訊
Plesk資訊
TensorFlow
教學資源
開源程序
網頁工具
SEO工具
醫療健康
旅遊及消閒
其他資訊
Content from
Content to
2018 年 9 月
一 二 三 四 五 六 日
 12
3456789
10111213141516
17181920212223
24252627282930
« 8 月   10 月 »

分類

  • 網站公告
  • 限時免費
  • ESET NOD32
  • WINDOWS 10 &11 INSIDER PREVIEW
  • Windows 軟件下載
  • 系統軟件
  • 辦公軟件
  • 圖像處理
  • 影音媒體
  • 網絡軟件
  • 應用軟件
  • Mac 軟件下載
  • 安卓軟件下載
  • 網絡資訊
  • Mac資訊
  • Linux資訊
  • VPS資訊
  • NASA資訊
  • WhatsApp Stickers教學
  • WordPress資訊
  • WeChat資訊
  • PHP資訊
  • Plesk資訊
  • TensorFlow
  • 教學資源
  • 開源程序
  • 網頁工具
  • SEO工具
  • 醫療健康
  • 旅遊及消閒
  • 其他資訊

彙整

近期文章

  • A Guide to Overcoming Your Incontinence Problem as an Adult 2023-02-04
  • 美國聯邦貿易委員會不懼首戰失利準備對亞馬遜提起可能的反壟斷訴訟 2023-02-04
  • 科學家發現機械刺激可用於強化肌肉 2023-02-04
  • 報導稱巴基斯坦監管機構已經封鎖了維基百科的訪問 2023-02-04
  • 歐盟已經就動視暴雪的交易向微軟發出了正式警告 2023-02-04
  • SUCOM網絡使偏遠地區送貨的無人機有了更可靠的蜂窩通訊能力 2023-02-04
  • 馬斯克表示Twitter將在今天開始與創作者分享廣告收入 2023-02-04
  • 科學家垂直堆疊子像素帶來更清晰的microLED顯示器 2023-02-04
  • 2022年全球智能手機出貨量為2013年以來最低蘋果獨得85%營業利潤 2023-02-04
  • 哥倫比亞一位法官剛剛使用ChatGPT做出了一項法庭裁決 2023-02-04

熱門文章與頁面︰

  • DP vs HDMI 誰才是遊戲玩家最佳選擇?
  • ESET NOD32 LICENSE KEY (UPDATED 2023-01-17)
  • Explorer Patcher:讓Windows 11恢復Windows 10的行為特徵
  • ESET NOD32 LICENSE KEY (UPDATED 2022-01-01)
  • Windows及OFFICE激活密鑰+電話激活教程–自用
  • 打車叫到特斯拉不會開門很尷尬?官方介紹開關門方法
  • Office 2013-2021 C2R Install v7.3.1 正式版-Office 2013/2016/2019/2021自定義組件安裝工具
  • 蓋茨:去火星很浪費錢馬斯克會是個偉大慈善家
  • 盜版Windows 7還能免費升級Windows 10嗎?
  • Google將於2月8日舉行關於搜索業務和人工智能的發布會活動

投遞稿件

歡迎各界人士投遞稿件到admin@wongcw.com

請提供以下資料:

1.你的名字

2.你的電郵

3.分類目錄

4.文章標題

5.文章摘要

6.文章內容

7.文章來源

 

聯繫我們

查詢,投稿,商務合作:
​admin@wongcw.com
​技術支援:
​support@wongcw.com
​客户服務:
​cs@wongcw.com

QQ群:833641851

快帆

MALUS

極度掃描

DMCA.com Protection Status

WONGCW 網誌

  • 免責聲明
  • 捐助我們
  • ThemeNcode PDF Viewer
  • ThemeNcode PDF Viewer SC
  • Events

服務器提供

本站使用之服務器由ikoula提供。

聯繫我們

查詢,投稿,商務合作:
​admin@wongcw.com
​技術支援:
​support@wongcw.com
​客户服務:
​cs@wongcw.com

QQ群:833641851

© 2023   All Rights Reserved.
X