TensorFlow2 | 实现自编码器Tying Weights的一种简易方法

1.问题描述

Tensorflow2 貌似没有内置的实现Tying Weights的方法。网上有若干资料,主要思路是写一个DenseTranspose的Class,stackoverflow上就有好几个。

这种方法坑特别多,我搜的几个,没有一个能顺利实现的。要么就是模型训练好了不能保存,要么就是保存了不能导入。

自己写了一个不用class的方法,基本实现Tying Weights功能。

2.实现代码

下面的代码是一个根据入参构建一个堆栈自编码器的函数。

2.1 基本的思路

(a)encoder部分可以用常规的Sequencial来构建。
(b)decoder部分的tying weights,用‘手工’将前面输出乘以(转置之后的)权重矩阵,(依次)进行下去(下面2.3 代码中的22行~34行),最后用tf.keras.Model整合模型;

2.2 输入输出

输入:
(a)输入数据的宽度;
(b)编码层之前的隐层神经元数目(list,例如[100,100]表示两层,每层100个神经元);
(c)coding layer神经元数目;
(d)是否用bias。

输出:
一个堆栈式自编码器的结构,没有编译。

2.3 使用Tying Weights的堆栈自编码器代码

import tensorflow as tf
from tensorflow.keras.datasets import mnist
from tensorflow.keras.layers import Dense
from tensorflow.keras.models import Sequential
import numpy as np

def stacked_ae(input_dim,num_hidden=[100,100],num_encoding=20,use_bias=True):
    '''
    :param input_shape:
        input_shape of input tensor;
    :param num_hidden:
        a list,number of units in the hidden layer except coding layer
    :param num_encoding:
        int,number of hidden unit in encoding layer;
    :return:
        a auto-encoder model
    '''
    model = Sequential()
    #### encoder
    for i, num_ in enumerate(num_hidden):
        if i==0:
            model.add(Dense(num_, use_bias=use_bias,input_dim=input_dim))
        else:
            model.add(Dense(num_, use_bias=use_bias))
    ##   encoding layer
    model.add(Dense(num_encoding, activation=None, use_bias=use_bias))
    #### decoder
    output=model.output
    for i in range(len(model.layers)-1,-1,-1):
        layer_i=model.layers[i]
        w = layer_i.weights[0]
        if i>0:
            ## 不是encoder的最后一层,设置了相同的激活函数
            bias=use_bias*tf.Variable(tf.constant(0.01,shape=layer_i.input_shape[1]))
            output=layer_i.activation(tf.matmul(output,w,transpose_b=True)+bias)
        else:
            ## 是decoder的最后一层,没有设置激活函数
            bias=use_bias*tf.Variable(tf.constant(0.01,shape=layer_i.input_shape[1]))
            output=tf.matmul(output,w,transpose_b=True)+bias
    new_model=tf.keras.Model(inputs=model.input,outputs=output)
    return(new_model)

2.4 测试代码

下面代码是利用上述定义的stacked_ae函数来构造一个自编码器,然后在mnist数据集上进行训练。然后将模型保存再导入的过程(主要为了测试模型整个流程跑的通,网上别的方法很多要么能训练不能保存,要么能保存不能导入)。

######### train the auto-encoder
(train_x,train_y),(test_x,test_y)=mnist.load_data()
train_x,test_x=train_x/255.0,test_x/255.0
train_x=train_x.reshape([-1,28*28])
test_x=test_x.reshape([-1,28*28])

model=stacked_ae(input_dim=28*28,num_hidden=[100,100],num_encoding=50,use_bias=False)

train_x_noise=train_x+0.01*np.random.random(size=train_x.shape)
test_x_noise=test_x+0.01*np.random.random(size=test_x.shape)

model.compile(loss=tf.losses.sigmoid_cross_entropy_with_logits,
              optimizer=tf.optimizers.Adam(),
              metrics=[tf.metrics.mean_squared_error])

model.fit(x=train_x_noise,y=train_x,batch_size=1000,epochs=10,verbose=2,validation_data=(test_x_noise,test_x))
model.evaluate(x=test_x_noise,y=test_x,verbose=2)
model.save(filepath='chapter15/epochs=10.h5')
#
model=tf.keras.models.load_model(filepath='chapter15/epochs=10.h5')

3. 说明

3.1 不足之处

这种方法的一个问题就是,生成的模型的layer结构发生了变化。要想提取其中的某些层来做迁移学习,不是那么方便————需要手工来输出来coding layer之前的层。不过比较容易看出,前面的层类型都是“Dense”,这点还是比较方便。

model.summary()
Model: "model_8"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
dense_48_input (InputLayer)  [(None, 784)]             0         
_________________________________________________________________
dense_48 (Dense)             (None, 100)               78400     
_________________________________________________________________
dense_49 (Dense)             (None, 100)               10000     
_________________________________________________________________
dense_50 (Dense)             (None, 50)                5000      
_________________________________________________________________
tf_op_layer_MatMul (TensorFl [(None, 100)]             0         
_________________________________________________________________
tf_op_layer_add (TensorFlowO [(None, 100)]             0         
_________________________________________________________________
tf_op_layer_MatMul_1 (Tensor [(None, 100)]             0         
_________________________________________________________________
tf_op_layer_add_1 (TensorFlo [(None, 100)]             0         
_________________________________________________________________
tf_op_layer_MatMul_2 (Tensor [(None, 784)]             0         
_________________________________________________________________
tf_op_layer_add_2 (TensorFlo [(None, 784)]             0         
_________________________________________________________________
tf_op_layer_Sigmoid (TensorF [(None, 784)]             0         
_________________________________________________________________
tf_op_layer_Sigmoid_1 (Tenso [(None, 784)]             0         
=================================================================
Total params: 93,400
Trainable params: 93,400
Non-trainable params: 0
_________________________________________________________________

3.2 Tying Weights的效果

有些资料上说Tying Weights的目的是为了节省参数,提高训练效率。
用Tying Weights训练自编码器效果很差(根据复原的图形来判断)。远不如不用Tying Weights,而且网络结构不大的情况下,也不算太慢。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值