Tensorflow 2.3学习笔记

Tensorflow 2.3学习笔记


安装

我先用pip安装了tensorflow,整个装过程很顺利,只需要在bash上输入

pip install tensorflow 2.3.0rc0

需要注意的是我使用的是macOS 10.15.6,使用时系统会默认使用自带的 python2.7pip也是对应为老版的,这时候就需要我们手动升级,并在~/.bash_profile中添加

alias python = "/usr/local/bin/python3.8"

若仍然失败那说明系统目录下没有~/.zshrc文件,就需要touch一个~/.zshrc并写入

source ~/.bash_profile

重启bash即可将自己下载的 python 作为默认的 python了。我使用的是清华大学的镜像,上面只支持2.1、2.2、2.3,既然下不了2.0了,索性来个最高版本吧,于是就用了2.3.0rc0

Hello World

按照惯例学什么东西第一个要输出就是hello world的了,而tensorflow又不是语言怎么入手呢?
于是我去官网上查看了tensorflow的介绍及实例代码

示例代码与解析

import tensorflow as tf
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
 
model = tf.keras.models.Sequential([
    tf.keras.layers.Flatten(input_shape=(28, 28)),
    tf.keras.layers.Dense(512, activation=tf.nn.relu),
    tf.keras.layers.Dropout(0.2),
    tf.keras.layers.Dense(10, activation=tf.nn.softmax)
])
model.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['accuracy'])
 
model.fit(x_train, y_train, epochs=5)
model.evaluate(x_test, y_test)

这个代码乍一看很复杂,但是实际上看不懂的部分都是我不熟悉的函数之类。感觉到这里和之前学习爬虫很相似,只需要了解相应的函数,对应总体编写可以总结为简单的几个步骤,于是我又去挨个看了函数的解释,以方便理解。

第2行
minist = tf.keras.datasets.mnist

这实际上是获取MNIST数据集的方法,这个方法会自动从https://storage.googleapis.com/tensorflow/tf-keras-datasets/mnist.npz的链接下载mnist.npz并存放于~/.keras/datasets/下,因此提前下载好放在这里就可以避免无法下载的问题。

tips: MNIST是一个非常常见的数据集,数据量小,方便读入内存,而且直观可见,在实现各种机器学习算法的时候,经常可以用来当小白鼠实验。

第4行
(x_train, y_train),(x_test, y_test) = mnist.load_data()

plain English,keras加载MNIST数据的方法

第5行
x_train, x_test = x_train / 255.0, x_test / 255.0

这是将RGB图像三色归为0,1矩阵的处理

第7-12行
model = tf.keras.models.Sequential([
    tf.keras.layers.Flatten(input_shape=(28, 28)),
    tf.keras.layers.Dense(512, activation=tf.nn.relu),
    tf.keras.layers.Dropout(0.2),
    tf.keras.layers.Dense(10, activation=tf.nn.softmax)
])

Sequential()方法是一个容器,描述了神经网络的网络结构,在Sequential()的输入参数中描述从输入层到输出层的网络结构

model = tf.keras.models.Sequential([网络结构])  #描述各层网络

网络结构举例:

  • 拉直层:
tf.keras.layers.Flatten() #拉直层可以变换张量的尺寸,把输入特征拉直为一维数组,是不含计算参数的层
  • 全连接层:
tf.keras.layers.Dense(神经元个数,
    activation = "激活函数“,
    kernel_regularizer = "正则化方式"

其中:activation可选 relu 、softmax、 sigmoid、 tanh等
kernel_regularizer可选 tf.keras.regularizers.l1() 、tf.keras.regularizers.l2()

  • 卷积层:
tf.keras.layers.Conv2D(filter = 卷积核个数,
       kernel_size = 卷积核尺寸,
       strides = 卷积步长,
       padding = ”valid“ or "same")
  • LSTM层:
tf.keras.layers.LSTM()

其中的dropout是一种防止神经网络过拟合的手段。随机的拿掉网络中的部分神经元,从而减小对W权重的依赖,以达到减小过拟合的效果。
注意:dropout只能用在训练中,测试的时候不能dropout,要用完整的网络测试哦。

第13行
model.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['accuracy'])

Plain English still,这是编译模型的代码,其中包含几个必须的参数:

第15行
model.fit(x_train, y_train, epochs=5)

首先Keras中的fit()函数传入的x_train和y_train是被完整的加载进内存的,当然用起来很方便,但是如果我们数据量很大,那么是不可能将所有数据载入内存的,必将导致内存泄漏,这时候我们可以用fit_generator函数来进行训练。
其中fit中有几种参数:

  • x: 训练数据的 Numpy 数组(如果模型只有一个输入), 或者是 Numpy 数组的列表(如果模型有多个输入)。 如果模型中的输入层被命名,你也可以传递一个字典,将输入层名称映射到 Numpy 数组。 如果从本地框架张量馈送(例如 TensorFlow 数据张量)数据,x 可以是 None(默认)。

  • y: 目标(标签)数据的 Numpy 数组(如果模型只有一个输出), 或者是 Numpy 数组的列表(如果模型有多个输出)。 如果模型中的输出层被命名,你也可以传递一个字典,将输出层名称映射到 Numpy 数组。 如果从本地框架张量馈送(例如 TensorFlow 数据张量)数据,y 可以是 None(默认)。

  • batch_size: 整数或 None。每次梯度更新的样本数。如果未指定,默认为 32。

  • epochs: 整数。训练模型迭代轮次。一个轮次是在整个 x 和 y 上的一轮迭代。 请注意,与 initial_epoch 一起,epochs 被理解为 「最终轮次」。模型并不是训练了 epochs 轮,而是到第 epochs 轮停止训练。
    verbose: 0, 1 或 2。日志显示模式。 0 = 安静模式, 1 = 进度条, 2 = 每轮一行。
    callbacks: 一系列的 keras.callbacks.Callback 实例。一系列可以在训练时使用的回调函数。 详见 callbacks。
    validation_split: 0 和 1 之间的浮点数。用作验证集的训练数据的比例。 模型将分出一部分不会被训练的验证数据,并将在每一轮结束时评估这些验证数据的误差和任何其他模型指标。 验证数据是混洗之前 x 和y 数据的最后一部分样本中。

  • validation_data: 元组 (x_val,y_val) 或元组 (x_val,y_val,val_sample_weights), 用来评估损失,以及在每轮结束时的任何模型度量指标。 模型将不会在这个数据上进行训练。这个参数会覆盖 validation_split。

  • shuffle: 布尔值(是否在每轮迭代之前混洗数据)或者 字符串 (batch)。 batch 是处理 HDF5 数据限制的特殊选项,它对一个 batch 内部的数据进行混洗。 当 steps_per_epoch 非 None 时,这个参数无效。

  • class_weight: 可选的字典,用来映射类索引(整数)到权重(浮点)值,用于加权损失函数(仅在训练期间)。 这可能有助于告诉模型 「更多关注」来自代表性不足的类的样本。

  • sample_weight: 训练样本的可选 Numpy 权重数组,用于对损失函数进行加权(仅在训练期间)。 您可以传递与输入样本长度相同的平坦(1D)Numpy 数组(权重和样本之间的 1:1 映射), 或者在时序数据的情况下,可以传递尺寸为 (samples, sequence_length) 的 2D 数组,以对每个样本的每个时间步施加不同的权重。 在这种情况下,你应该确保在 compile() 中指定 sample_weight_mode=“temporal”。

  • initial_epoch: 整数。开始训练的轮次(有助于恢复之前的训练)。

  • steps_per_epoch: 整数或 None。 在声明一个轮次完成并开始下一个轮次之前的总步数(样品批次)。 使用 TensorFlow 数据张量等输入张量进行训练时,默认值 None 等于数据集中样本的数量除以 batch 的大小,如果无法确定,则为 1。

  • validation_steps: 只有在指定了 steps_per_epoch 时才有用。停止前要验证的总步数(批次样本)。

其返回值为:

一个 History 对象。其 History.history 属性是连续 epoch 训练损失和评估值,以及验证集损失和评估值的记录(如果适用)。

第16行

输入数据和标签,输出损失和精确度

model.evaluate(x_test, y_test)

总结

搭建一个程序共有五步:

  1. 创建Sequential模型;

  2. 添加所需要的神经层;在示例程序中,创建模型和添加神经层同步完成了,我们还可以用model.add()来添加神经层,并设置其功能,形状,激活函数,留存率等属性;

  3. 使用.compile方法确定模型训练结构;有三个重要参数:

  • optimizer:此对象会指定训练过程。从 tf.train 模块向其传递优化器实例;
  • loss:要在优化期间最小化的函数。常见选择包括均方误差 (mse)、categorical_crossentropy 和 binary_crossentropy。损失函数由名称或通过从 tf.keras.losses 模块传递可调用对象来指定。
  • metrics:用于监控训练。它们是 tf.keras.metrics 模块中的字符串名称或可调用对象。
  1. 使用.fit方法使模型与训练数据“拟合”;
  2. predict或evaluate方法进行预测。

应用

这次的任务是猫狗大战。这是是kaggle的一个著名比赛项目,即编写一个算法使机器能够区分猫和狗。
这是其的介绍:https://www.kaggle.com/c/dogs-vs-cats/overview

所遇到的新的问题及解决

简单来说,就是要用tensorflow写一个可以分辨猫狗的脚本,现在我的手上有25,000张猫和狗的照片。除了上面总结出的步骤外,还需要:

  1. 找到图片所在的位置
  2. 导入图片并处理图片

对于1,用glob库就可以实现,具体看这篇博客https://www.sohu.com/a/334008637_120291025根据这篇博客,我导入了图像并用0和1表示猫和狗:

path = '/Users/luominxing/Downloads/cats_and_dogs_filtered'  #path为你数据集所在的位置
train_image_path = glob.glob(path + '/train/*/*.jpg')
test_image_path = glob.glob(path+'/validation/*/*.jpg')
train_image_label = [int(p.split('/')[-2] == 'cats') for p in train_image_path]
test_image_label = [int(p.split('/')[-2] == 'cats')for p in test_image_path]

BTW,我一开始用glob库练手就是把train图片里的猫和狗分成了两组,下附代码:

import os
from shutil import copy
path_source = "/Users/luominxing/Downloads/train"
path_destination = '/Users/luominxing/Downloads/cats_and_dogs_filtered/train'
pathDir = os.listdir(path_source)
for i in pathDir:
    if i.split('.')[0] == 'cat':
        to_path = path_destination + '/cats'
        
    elif i.split('.')[0] == 'dog':
        to_path = path_destination + '/dogs'
    from_path = os.path.join(path_source, i)
    copy(from_path, to_path)

对于2,这篇博客详细讲解了tensorflow里内附的各种处理图像的函数https://blog.csdn.net/qq_30638831/article/details/81046455?ops_request_misc=%7B%22request%5Fid%22%3A%22159817412919725247612054%22%2C%22scm%22%3A%2220140713.130102334..%22%7D&request_id=159817412919725247612054&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduend~default-2-81046455.first_rank_ecpm_v3_pc_rank_v2&utm_term=tensorflow处理图像&spm=1018.2118.3001.4187
在这里我认为把图像剪裁到统一大小更有利于训练,然后对比度和亮度调高,让不清晰和光线较暗的图像也能把特征显现出来,对此写了一个函数,来处理图像:

def load_preprocess_image(path, label):
    image = tf.io.read_file(path)
    image = tf.image.decode_jpeg(image, channels=3)
    #读取jpg格式的文件,tf同时还支持多种格式图像文件的读取
    image = tf.image.resize(image, [360, 360])
    #将图像进行缩放
    image = tf.image.random_crop(image, [256, 256, 3])
    #将图像进行裁剪
    image = tf.image.random_flip_left_right(image)
    #将图像上下颠倒
    image = tf.image.random_flip_up_down(image)
    #将图像左右颠倒
    image = tf.image.random_brightness(image, 0.5) 
     #调整图像的亮度
    image = tf.image.random_contrast(image, 0, 1)
    #调整图像的对比度
    image = tf.cast(image, tf.float32)
    #将图像的类型转换为tf.float32类型
    image = image / 255
    #将图像进行归一化处理,使得图像的范围处于0和1之间
    label = tf.reshape(label, [1])
    return image, label

完整代码

由于对tensorflow不是很熟悉,接下来的操作都是参考这篇博客https://blog.csdn.net/lys_828/article/details/101322246照葫芦画瓢写出来的,其中Sequential函数里的层,都是究极缝合+玄学,下附完整代码

#版本信息:macOS 10.15.6 python3.8.5 tensorflow 2.3.0 rc0
#作者:敏行讷言
import numpy as np
import tensorflow as tf
from tensorflow.keras import layers
from tensorflow.keras.preprocessing.image import ImageDataGenerator

import os
import matplotlib.pyplot as plt
import glob


def load_preprocess_image(path, label):
    image = tf.io.read_file(path)
    image = tf.image.decode_jpeg(image, channels=3)
    # 读取jpg格式的文件,tf同时还支持多种格式图像文件的读取
    image = tf.image.resize(image, [360, 360])
    # 将读取到的图像进行缩放
    image = tf.image.random_crop(image, [256, 256, 3])
    # 将读取到的图像进行裁剪
    image = tf.image.random_flip_left_right(image)
    # 将图像上下颠倒
    image = tf.image.random_flip_up_down(image)
    # 将图像左右颠倒
    image = tf.image.random_brightness(image, 0.5)
    # 调整图像的亮度
    image = tf.image.random_contrast(image, 0, 1)
    # 调整图像的对比度
    image = tf.cast(image, tf.float32)
    # 将图像的类型转换为tf.float32类型
    image = image / 255.0
    # 将图像进行归一化处理,使得图像的范围处于0和1之间
    # 同样可以使用tf.image.convert_image_dtype进行处理
    label = tf.reshape(label, [1])
    return image, label


tf.compat.v1.disable_eager_execution()
BATCH_SIZE = 64
num_epochs = 10
train_count = 800
test_count = 400
steps_per_epoch = int(train_count / BATCH_SIZE)
validation_steps = int(test_count / BATCH_SIZE)


print(tf.__version__, tf.config.list_physical_devices('GPU'))  # tensorflow版本,gpu加速

path = '/Users/luominxing/Downloads/cats_and_dogs_filtered'  # path为你数据集所在的位置
train_image_path = glob.glob(path + '/train/*/*.jpg')
test_image_path = glob.glob(path+'/validation/*/*.jpg')
train_image_label = [int(p.split('/')[-2] == 'cats') for p in train_image_path]
test_image_label = [int(p.split('/')[-2] == 'cats')for p in test_image_path]
train_image_ds = tf.data.Dataset.from_tensor_slices(
    (train_image_path, train_image_label))
test_image_ds = tf.data.Dataset.from_tensor_slices(
    (test_image_path, test_image_label))

AUTOTUNE = tf.data.experimental.AUTOTUNE
# 根据CPU的状况自动处理,可以不使用
train_image_ds = train_image_ds.map(
    load_preprocess_image, num_parallel_calls=AUTOTUNE)
test_image_ds = test_image_ds.map(
    load_preprocess_image, num_parallel_calls=AUTOTUNE)
train_image_ds = train_image_ds.shuffle(train_count)
test_image_ds = test_image_ds.shuffle(test_count)
# .shuffle是随机打乱数据集的顺序
train_image_ds = train_image_ds.batch(BATCH_SIZE)
test_image_ds = test_image_ds.batch(BATCH_SIZE)
# .batch是取batch大小,这里我的BATCH_SIZE取得是64
train_image_ds = train_image_ds.prefetch(AUTOTUNE)
test_image_ds = test_image_ds.prefetch(AUTOTUNE)

# 预取数据
model = tf.keras.Sequential([
    layers.Conv2D(64, (3, 3), input_shape=(256, 256, 3)),
    layers.BatchNormalization(),
    layers.Activation('relu'),

    layers.Conv2D(64, (3, 3)),
    layers.BatchNormalization(),
    layers.Activation('relu'),

    layers.MaxPool2D(),

    layers.Conv2D(128, (3, 3)),
    layers.BatchNormalization(),
    layers.Activation('relu'),

    layers.Conv2D(128, (3, 3)),
    layers.BatchNormalization(),
    layers.Activation('relu'),

    layers.MaxPool2D(),

    layers.Conv2D(256, (3, 3)),
    layers.BatchNormalization(),
    layers.Activation('relu'),

    layers.Conv2D(256, (3, 3)),
    layers.BatchNormalization(),
    layers.Activation('relu'),

    layers.Conv2D(256, (1, 1)),
    layers.BatchNormalization(),
    layers.Activation('relu'),

    layers.MaxPool2D(),

    layers.Conv2D(512, (3, 3)),
    layers.BatchNormalization(),
    layers.Activation('relu'),

    layers.Conv2D(512, (3, 3)),
    layers.BatchNormalization(),
    layers.Activation('relu'),

    layers.Conv2D(512, (1, 1)),
    layers.BatchNormalization(),
    layers.Activation('relu'),

    layers.MaxPool2D(),

    layers.Conv2D(512, (3, 3)),
    layers.BatchNormalization(),
    layers.Activation('relu'),

    layers.Conv2D(512, (3, 3)),
    layers.BatchNormalization(),
    layers.Activation('relu'),

    layers.Conv2D(512, (1, 1)),
    layers.BatchNormalization(),
    layers.Activation('relu'),

    layers.MaxPool2D(),

    layers.GlobalAveragePooling2D(),

    layers.Dense(4096, activation='relu'),
    layers.BatchNormalization(),
    layers.Dense(4096, activation='relu'),
    layers.BatchNormalization(),
    layers.Dense(1000, activation='relu'),
    layers.BatchNormalization(),
    layers.Dense(1)
])
model.compile(loss='binary_crossentropy',
              optimizer=tf.keras.optimizers.Adam(lr=0.0005),
              metrics=['acc'])
history = model.fit(train_image_ds, epochs=num_epochs,
                     # 我设置的轮数是30
                     steps_per_epoch=steps_per_epoch,
                     # step_per_epoch是每轮训练需要训练多少次,一般我们用数据的数量除batch_size得到
                     validation_data=test_image_ds,
                     validation_steps=validation_steps)
# 和step_per_epoch是同样的道理
model.save('c_v_d_back_up.h5')
acc = history.history['acc']
val_acc = history.history['val_acc']
loss = history.history['loss']
val_loss = history.history['val_loss']
epochs = range(len(acc))  # Get number of epochs

plt.figure()
plt.plot(epochs, acc, 'r')
plt.plot(epochs, val_acc, 'b')
plt.title('Training and validation accuracy')
plt.xlabel("Epochs")
plt.ylabel("Accuracy")
plt.legend(["Accuracy", "Validation Accuracy"])


plt.savefig('train_results_acc.eps', dpi=600, format='eps')
plt.show()

plt.clf()  # 添加上这一行,画完第一个图后,重置一下
# 画loss曲线
plt.plot(epochs, loss, 'r')
plt.plot(epochs, val_loss, 'b')
plt.title('Training and validation loss')
plt.xlabel("Epochs")
plt.ylabel("Loss")
plt.legend(["Loss", "Validation Loss"])


plt.savefig('train_results_loss.eps', dpi=600, format='eps')
plt.show()

结果

在这里插入图片描述
在这里插入图片描述

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值