最近一段时间发现,对于Tensorflow2.x版本的许多新特性和函数都没有认识很深,对它的认知还停留在去年,直到今年用的时候才发现,以前在GitHub上老的程序连Tensorflow1.14.0都跑不起来了,在折腾了一个星期环境之后,痛定思痛,决定老老实实从Tensorflow2开始过一遍基础。学习了不写点笔记怪可惜的,发现在网上的Tensorflow2的教程实在是错误率有点高,没眼看,还是自己来总结一波吧,仅作为学习和交流,不做商业用途。Let's begin
Environment
为啥单独把环境拉出来讲呢,因为Tensorflow实在是有点恶心的一点就是新版本对旧版本的兼容性问题。作为代码强迫症的我真的受不了到处报warning的程序,更何况在Tensorflow1.x版本中,1.8到1.14就有巨大的差别,1.8环境写的代码,可能直接就error了。这里还有一个需要注意的点,如果你是Tensorflow1.14及以后的环境,你使用的函数,尤其是tf.layer的的函数,如果在Tensorflow2.x中被移除,将会自动包warning提醒你update,也可以用官方给的1.x转换成2.x的程序转换一下,个人没有试过,但无非是使用正则匹配,错误率和效率大家应该都懂的。不废话了,贴一下导出环境的代码和我的环境:
在cmd中输入:
pip freeze > environment.txt
environment是导出的文件名,即可导出全部的python环境的版本号。
我的环境(主要的一部分):
Anaconda3-2020.02-Windows-x86_64 (这个不是导出的)
conda==4.8.2
ipython==7.12.0
Keras-Applications==1.0.8
matplotlib==3.1.3
numpy==1.18.1
pandas==1.0.1
scikit-learn==0.22.1
scipy==1.4.1
seaborn==0.10.0
tensorflow==2.1.0
这里就要注意一下了,我贴了Keras-Applications,但是没有keras的,为啥呢?因为在Tensorflow2.0之后,或者说在Keras的较新版本中,keras的backend默认为Tensorflow2.0,如胶似漆,不可分割。安装环境的时候直接安装Tensorflow就行了,千万不要手贱继续pip install keras,否则你安装的Tensorflow2.x就前功尽弃了不说,卸载都难。因为pip单独安装的keras,它的backend是tensorflow1.14.0,系统会卸载2.x版本,重新安装1.14.0的Tensorflow版本。
安装环境的时候,经常碰到的问题就是网速和资源加载太慢,安装到一半就退出的问题,就算是使用清华源也难免会由于网速原因退出,最近发现了一个可以解决网速慢安装包的时候报错退出的办法,安装时调整延时时间。
pip --default-timeout=100 install
后面添加想要安装的包的名称,也可以使用清华源,真的很好用。
环境的坑其实是最多的,基本上解决了环境的问题,后面的问题就不是什么很让人头疼的,环境的问题就像是炼丹一样,很迷,很不容易找到问题点,一言难尽......
程序的第一步是整理数据(import没啥讲的,直接开始干货吧)
数据输入也分两种方式,最常用的方式是使用numpy直接将数据输入到模型当中,如下所示:
mnist = tf.keras.datasets.mnist
(x_train, y_train), (x_test, y_test) = mnist.load_data()
x_train, x_test = x_train / 255.0, x_test / 255.0
数据集的导入借用tf.keras.datasets模块,tf.keras.datasets相当于是数据处理和导入的函数库,包括的模型有:boston_housing;cifar10;cifar100;fashion_mnist;imdb;mnist;reuters。
另一种导入数据的方式为tf.data形式,适合大型数据集,以多线程导入,可以增加数据输入模型的速度,加快模型运算。
# Add a channels dimension
x_train = x_train[..., tf.newaxis]
x_test = x_test[..., tf.newaxis]
#tf.data
train_ds = tf.data.Dataset.from_tensor_slices((x_train,
y_train)).shuffle(10000).batch(32)
test_ds = tf.data.Dataset.from_tensor_slices((x_test,
y_test)).batch(32)
搭建模型
搭建模型可以使用两种方式,一种是keras方式,这种方式可以搭建比较简单的模型,适合初学者。
这里有需要说明的一点,之前我做个实测,在Tensorflow1.x中,keras没有默认backend为Tensorflow之前,使用keras进行模型训练的时间,是使用tensorflow进行模型训练时间的5倍以上。但是现在tensorflow2.0中,keras作为Tensorflow的高阶API,训练速度大大加快,但是对比tensorflow仍有逊色,应该是使用Sequential搭建模型和调用backend翻译的速度问题。
下面是使用keras搭建的模型结构:
model = tf.keras.models.Sequential([
tf.keras.layers.Flatten(input_shape=(28, 28)),
tf.keras.layers.Dense(128, activation='relu'),
tf.keras.layers.Dropout(0.2),
tf.keras.layers.Dense(10, activation='softmax')
])
model.compile(optimizer='adam',
loss='sparse_categorical_crossentropy',
metrics=['accuracy'])
另外一种也是我最喜欢的方式,是使用Tensorflow直接搭建模型:
class MyModel(Model):
#define model type
def __init__(self):
super(MyModel, self).__init__()
#Sequential
self.conv1 = Conv2D(32, 3, activation='relu')
self.flatten = Flatten()
self.d1 = Dense(128, activation='relu')
self.d2 = Dense(10, activation='softmax')
#inputs
def call(self, x):
x = self.conv1(x)
x = self.flatten(x)
x = self.d1(x)
return self.d2(x)
model = MyModel()
loss_object = tf.keras.losses.SparseCategoricalCrossentropy()
optimizer = tf.keras.optimizers.Adam()
train_loss = tf.keras.metrics.Mean(name='train_loss')
train_accuracy = tf.keras.metrics.SparseCategoricalAccuracy(name='train_accuracy')
test_loss = tf.keras.metrics.Mean(name='test_loss')
test_accuracy = tf.keras.metrics.SparseCategoricalAccuracy(name='test_accuracy')
@tf.function #acceleration training
def train_step(images, labels):
with tf.GradientTape() as tape: #calculate Gradient connect def and var
predictions = model(images) #Tensor("my_model/dense_3/Softmax:0")
loss = loss_object(labels, predictions)
gradients = tape.gradient(loss, model.trainable_variables)
optimizer.apply_gradients(zip(gradients, model.trainable_variables))
train_loss(loss) #trans type
train_accuracy(labels, predictions)
作为高阶API,Tensorflow的layer等方法已经集成在了keras中,二者可以说是不分彼此的。class MyModel跟keras中定义的model是一样的,在def __init__中定义的是需要调用的模型函数,结构中没有写入每层的输入参数,输入在def call中定义,并在def call中定位每一层的结构。至于loss和accuracy的定义涉及到相当多的理论知识,在此不做赘述,想要进一步了解还是去Google吧。
train_step是将函数,输入联系,并且有计算梯度功能的函数。@tf.function可以理解为调用原版本中的graph计算图,可以加速计算。(之前看人说Tensorflow2.0的计算速度远低于Tensorflow1.x版本的计算速度,实测了一下,就是没有使用@tf.function的原因。
运行模型
使用keras形式进行训练,很简单。fit是训练,evaluate就是估计咯。
model.fit(x_train, y_train, epochs=5)
model.evaluate(x_test, y_test, verbose=2)
使用Tensorflow形式训练模型
#训练模型
N_EPOCHS = 5
for epoch in range(1,N_EPOCHS+1):
for images, labels in train_ds:
train_step(images, labels)
for test_images, test_labels in test_ds:
test_step(test_images, test_labels)
template = 'Epoch {}, Loss: {}, Accuracy: {}, Test Loss: {}, Test Accuracy: {}'
print (template.format(epoch,
train_loss.result(), #tensor tune float
train_accuracy.result()*100,
test_loss.result(),
test_accuracy.result()*100))
train_step在执行梯度计算,images为tenor形式的数据类型。在搭建模型的程序中使用的train_loss和train_accuracy保存了训练结果;test_loss,test_accuracy保存了测试结果,类型为tensor类型,输出结果使用.result方式。
想要输出模型参数,需要使用tensor.numpy()形式,这是Tensorflow2.x版本的一大修改。具体做法在后续更新中将逐渐贴出。
虽然已经把代码都上传到了GitHub当中,但是我的GitHub还比较乱,暂时也不打算做专业的运营公众号,就只当作学习交流使用,就不放链接了,文章里面贴的程序也比较全,感兴趣的也可以问我要源码。