当前位置:   article > 正文

智能计算系统4.3实时风格迁移的训练_智能计算系统实验4.3

智能计算系统实验4.3

实验目的

掌握如何使用Tensorflow实现风格迁移算法的训练

  1. 掌握使用Tensorflow定义损失函数的方法
  2. 掌握使用Tensorflow存储网络模型的方法
  3. 以实时风格迁移为例,掌握使用Tenflow进行神经网络训练的方法(推荐使用GPU进行训练)

实验代码

  • transform.py:定义基本运算单元
  1. #encoding=utf-8
  2. import tensorflow as tf, pdb
  3. WEIGHTS_INIT_STDEV = .1
  4. def net(image, type=0):
  5. # 该函数构建图像转换网络,image 为步骤 1 中读入的图像 ndarray 阵列,返回最后一层的输出结果
  6. # TODO:构建图像转换网络,每一层的输出作为下一层的输入
  7. conv1 = _conv_layer(image, 32, 9, 1, type) #default relu=True and type=0(use BN)
  8. conv2 = _conv_layer(conv1, 64 ,3, 2, type)
  9. conv3 = _conv_layer(conv2, 128 ,3, 2, type)
  10. # print(conv1.get_shape())
  11. # print(conv2.get_shape())
  12. # print(conv3.get_shape())
  13. # pdb.set_trace()
  14. residual1 = _residual_block(conv3, 3, type=1)
  15. residual2 = _residual_block(residual1, 3, type=1)
  16. residual3 = _residual_block(residual2, 3, type=1)
  17. residual4 = _residual_block(residual3, 3, type=1)
  18. residual5 = _residual_block(residual4, 3, type=1)
  19. conv_transpose1 = _conv_tranpose_layer(residual5, 64, 3, 2)
  20. conv_transpose2 = _conv_tranpose_layer(conv_transpose1, 32, 3, 2)
  21. conv4 = _conv_layer(conv_transpose2, 3, 9, 1)
  22. #TODO:最后一个卷积层的输出再经过 tanh 函数处理,最后的输出张量 preds 像素值需限定在 [0,255] 范围内
  23. preds = (tf.nn.tanh(conv4) + 1) * 255./2
  24. return preds
  25. def _conv_layer(net, num_filters, filter_size, strides, relu=True, type=0):
  26. # 该函数定义了卷积层的计算方法,net 为该卷积层的输入 ndarray 数组,num_filters 表示输出通道数,filter_size 表示卷积核尺
  27. # 寸,strides 表示卷积步长,该函数最后返回卷积层计算的结果
  28. # TODO:准备好权重的初值
  29. weights_init = _conv_init_vars(net, num_filters, filter_size) #weights shape: [k, k, cin, cout]
  30. # TODO:输入的 strides 参数为标量,需将其处理成卷积函数能够使用的数据形式
  31. strides_shape = [1] + list([strides]) * 2 + [1]
  32. # TODO:进行卷积计算
  33. net = tf.nn.conv2d(net, weights_init, strides=strides_shape, padding='SAME') + \
  34. tf.Variable(tf.zeros([num_filters], dtype=tf.float32)) #bias
  35. # 对卷积计算结果进行批归一化处理
  36. if type == 0:
  37. net = _batch_norm(net)
  38. elif type == 1:
  39. net = _instance_norm(net)
  40. if relu:
  41. # TODO:对归一化结果进行 ReLU 操作
  42. net = tf.nn.relu(net)
  43. return net
  44. def _conv_tranpose_layer(net, num_filters, filter_size, strides, type=0):
  45. #referrence to https://blog.csdn.net/baidu_33216040/article/details/102575278
  46. # TODO:准备好权重的初值
  47. weights_init = _conv_init_vars(net, num_filters, filter_size, transpose=True) #weights shape: [k, k, num_filters, cin]
  48. batch, rows, cols, channels = [i.value for i in net.get_shape()]
  49. # handmade mode: see more from experiment document
  50. # #1.flat InputData to: [batchsize, width*height, channel]
  51. # batch, rows, cols, channels = [i.value for i in net.get_shape()] #net shape: [batchsize, width, height, channel]
  52. # net = tf.reshape(net, [batch, rows*cols, -1])
  53. # #2. k*k kernel to (rows*cols, square((rows-1)*s+k))
  54. # #4.y = W.T * x
  55. # TODO:输入的 num_filters、strides 参数为标量,需将其处理成转置卷积函数能够使用的数据形式
  56. strides_shape = [1] + list([strides]) * 2 + [1]
  57. # output_shape = [batch] + list((rows-1)*strides+filter_size)* 2 + [num_filters] #padding = VALID
  58. new_shape = [batch, rows*strides, cols*strides, num_filters] #padding = SAME #only 2
  59. # if tf.__version__.startswith('0.1'):
  60. # output_shape = tf.pack(new_shape)
  61. # else:
  62. output_shape = tf.stack(new_shape)
  63. # TODO:进行转置卷积计算
  64. net = tf.nn.conv2d_transpose(net, weights_init, output_shape, strides_shape, padding='SAME') + \
  65. tf.Variable(tf.zeros([num_filters], dtype=tf.float32)) #bias
  66. # 对卷积计算结果进行批归一化处理
  67. if type == 0:
  68. net = _batch_norm(net)
  69. elif type == 1:
  70. net = _instance_norm(net)
  71. # TODO:对归一化结果进行 ReLU 操作
  72. net = tf.nn.relu(net)
  73. return net
  74. def _residual_block(net, filter_size=3, type=0):
  75. # TODO:调用之前实现的卷积层函数,实现残差块的计算
  76. #在该网络中,残差层的卷积核个数为128, strids=1;且网络未改变输出通道数(可采用1*1卷积改通道数)
  77. x_shape = net.get_shape()
  78. tmp = _conv_layer(net, 128, filter_size, 1, True) #conv1 + relu
  79. fx = _conv_layer(tmp, 128, filter_size, 1) #conv2
  80. fx_shape = fx.get_shape()
  81. assert x_shape[1] == fx_shape[1] and x_shape[2] == fx_shape[2], "x_shape[1] = %d, fx_shape[1] = %d" % (x_shape[1].value, fx_shape[1].value)
  82. #todo
  83. if not(x_shape[1] == fx_shape[1] and x_shape[2] == fx_shape[2]):#feature size改变,通过补零的方式
  84. pass
  85. net = tf.nn.relu(net+fx)
  86. return net
  87. def _batch_norm(net, train=True):
  88. batch, rows, cols, channels = [i.value for i in net.get_shape()]
  89. axes=list(range(len(net.get_shape())-1))
  90. mu, sigma_sq = tf.nn.moments(net, axes, keep_dims=True)
  91. var_shape = [channels]
  92. shift = tf.Variable(tf.zeros(var_shape)) #learnable parameter
  93. scale = tf.Variable(tf.ones(var_shape))
  94. epsilon = 1e-3
  95. return tf.nn.batch_normalization(net, mu, sigma_sq, shift, scale, epsilon)
  96. def _instance_norm(net, train=True):
  97. batch, rows, cols, channels = [i.value for i in net.get_shape()]
  98. var_shape = [channels]
  99. mu, sigma_sq = tf.nn.moments(net, [1,2], keep_dims=True)
  100. shift = tf.Variable(tf.zeros(var_shape))
  101. scale = tf.Variable(tf.ones(var_shape))
  102. epsilon = 1e-3
  103. normalized = (net-mu)/(sigma_sq + epsilon)**(.5)
  104. return scale * normalized + shift
  105. def _conv_init_vars(net, out_channels, filter_size, transpose=False):
  106. _, rows, cols, in_channels = [i.value for i in net.get_shape()]
  107. if not transpose:
  108. weights_shape = [filter_size, filter_size, in_channels, out_channels]
  109. else:
  110. weights_shape = [filter_size, filter_size, out_channels, in_channels]
  111. weights_init = tf.Variable(tf.truncated_normal(weights_shape, stddev=WEIGHTS_INIT_STDEV, seed=1), dtype=tf.float32)
  112. return weights_init
  113. # net(tf.placeholder(tf.float32, shape=[1, 336, 336, 3]))
  • vgg.py:定义特征提取网络
  1. #encoding=utf-8
  2. # Copyright (c) 2015-2016 Anish Athalye. Released under GPLv3.
  3. import tensorflow as tf
  4. import numpy as np
  5. import scipy.io
  6. import pdb
  7. MEAN_PIXEL = np.array([ 123.68 , 116.779, 103.939])
  8. def net(data_path, input_image):
  9. layers = (
  10. 'conv1_1', 'relu1_1', 'conv1_2', 'relu1_2', 'pool1',
  11. 'conv2_1', 'relu2_1', 'conv2_2', 'relu2_2', 'pool2',
  12. 'conv3_1', 'relu3_1', 'conv3_2', 'relu3_2', 'conv3_3',
  13. 'relu3_3', 'conv3_4', 'relu3_4', 'pool3',
  14. 'conv4_1', 'relu4_1', 'conv4_2', 'relu4_2', 'conv4_3',
  15. 'relu4_3', 'conv4_4', 'relu4_4', 'pool4',
  16. 'conv5_1', 'relu5_1', 'conv5_2', 'relu5_2', 'conv5_3',
  17. 'relu5_3', 'conv5_4', 'relu5_4'
  18. )
  19. data = scipy.io.loadmat(data_path)
  20. mean = data['normalization'][0][0][0]
  21. mean_pixel = np.mean(mean, axis=(0, 1))
  22. weights = data['layers'][0]
  23. net = {}
  24. current = input_image
  25. for i, name in enumerate(layers):
  26. kind = name[:4]
  27. if kind == 'conv':
  28. # TODO:如果当前层为卷积层,则进行卷积计算,计算结果为 current
  29. kernels, bias = weights[i][0][0][0][0]
  30. kernels = np.transpose(kernels, [1,0,2,3])
  31. bias = bias.reshape(-1)
  32. current = _conv_layer(current, kernels, bias)
  33. elif kind == 'relu':
  34. # TODO:如果当前层为 ReLU 层,则进行 ReLU 计算,计算结果为 current
  35. current = tf.nn.relu(current)
  36. elif kind == 'pool':
  37. # TODO:如果当前层为池化层,则进行最大池化计算,计算结果为 current
  38. current = _pool_layer(current)
  39. net[name] = current
  40. assert len(net) == len(layers)
  41. return net
  42. def _conv_layer(input, weights, bias):
  43. conv = tf.nn.conv2d(input, tf.constant(weights), strides=(1, 1, 1, 1),
  44. padding='SAME')
  45. return tf.nn.bias_add(conv, bias)
  46. def _pool_layer(input):
  47. return tf.nn.max_pool(input, ksize=(1, 2, 2, 1), strides=(1, 2, 2, 1),
  48. padding='SAME')
  49. def preprocess(image):
  50. return image - MEAN_PIXEL
  51. def unprocess(image):
  52. return image + MEAN_PIXEL
  • optimaze.py:损失函数的构建
  1. #encoding=utf-8
  2. from __future__ import print_function
  3. import functools
  4. import vgg, pdb, time
  5. import tensorflow as tf, numpy as np, os
  6. import transform
  7. from utils import get_img
  8. STYLE_LAYERS = ('relu1_1', 'relu2_1', 'relu3_1', 'relu4_1', 'relu5_1')
  9. CONTENT_LAYER = 'relu4_2'
  10. DEVICES = '/cpu:0' #'CUDA_VISIBLE_DEVICES'
  11. os.putenv('MLU_VISIBLE_DEVICES','')
  12. def loss_function(net, content_features, style_features, content_weight, style_weight, tv_weight, preds, batch_size):
  13. # 损失函数构建,net 为特征提取网络,content_features 为内容图像特征,style_features 为风格图像特征,content_weight、
  14. # style_weight 和 tv_weight 分别为特征重建损失、风格重建损失的权重和全变分正则化损失的权重
  15. batch_shape = (batch_size,256,256,3)
  16. # 计算内容损失
  17. # content_loss
  18. content_size = _tensor_size(content_features[CONTENT_LAYER])*batch_size
  19. assert _tensor_size(content_features[CONTENT_LAYER]) == _tensor_size(net[CONTENT_LAYER])
  20. content_loss = (1.0 / (4*content_size)) * tf.reduce_sum(tf.pow(net[CONTENT_LAYER]-content_features[CONTENT_LAYER], 2)) * content_weight
  21. # 计算风格损失
  22. # style_loss
  23. style_losses = []
  24. for style_layer in STYLE_LAYERS:
  25. layer = net[style_layer]
  26. bs, height, width, filters = map(lambda i:i.value,layer.get_shape())
  27. size = height * width * filters
  28. feats = tf.reshape(layer, (bs, height * width, filters))
  29. feats_T = tf.transpose(feats, perm=[0,2,1])
  30. grams = tf.matmul(feats_T, feats) / size
  31. style_gram = style_features[style_layer]
  32. # TODO: 计算 style_losses
  33. style_losses.append((1.0 / (4 * bs ** 2 * size ** 2)) * tf.reduce_sum(tf.pow(style_gram-grams, 2)) * style_weight)
  34. style_loss = style_weight * functools.reduce(tf.add, style_losses) / batch_size
  35. # 使用全变分正则化方法定义损失函数 tv_loss
  36. # tv_loss
  37. tv_y_size = _tensor_size(preds[:,1:,:,:])
  38. tv_x_size = _tensor_size(preds[:,:,1:,:])
  39. # TODO:将图像 preds 向水平和垂直方向各平移一个像素,分别与原图相减,分别计算二者的
    声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Gausst松鼠会/article/detail/101386
    推荐阅读
    相关标签