Tensorflow-CNN-Tutorial

# Tensorflow-CNN-Tutorial

这是一个手把手教你用Tensorflow构建卷机网络(CNN)进行图像分类的教程。完整代码可在Github中下载:[https://github.com/hujunxianligong/Tensorflow-CNN-Tutorial](https://github.com/hujunxianligong/Tensorflow-CNN-Tutorial)。教程并没有使用MNIST数据集,而是使用了真实的图片文件,并且教程代码包含了模型的保存、加载等功能,因此希望在日常项目中使用Tensorflow的朋友可以参考这篇教程。


## 概述

+ 代码利用卷积网络完成一个图像分类的功能
+ 训练完成后,模型保存在model文件中,可直接使用模型进行线上分类
+ 同一个代码包括了训练和测试阶段,通过修改train参数为True和False控制训练和测试

## 数据准备

教程的图片从Cifar数据集中获取,`download_cifar.py`从Keras自带的Cifar数据集中获取了部分Cifar数据集,并将其转换为jpg图片。

默认从Cifar数据集中选取了3类图片,每类50张图,分别是
+ 0 => 飞机
+ 1 => 汽车
+ 2 => 鸟

图片都放在data文件夹中,按照label_id.jpg进行命名,例如2_111.jpg代表图片类别为2(鸟),id为111。

![](demo.png)

## 导入相关库

除了Tensorflow,本教程还需要使用pillow(PIL),在Windows下PIL可能需要使用conda安装。

如果使用`download_cifar.py`自己构建数据集,还需要安装keras。


```python
import os
#图像读取库
from PIL import Image
#矩阵运算库
import numpy as np
import tensorflow as tf
```

## 配置信息

设置了一些变量增加程序的灵活性。图片文件存放在`data_dir`文件夹中,`train`表示当前执行是训练还是测试,`model-path`约定了模型存放的路径。

```python
# 数据文件夹
data_dir = "data"
# 训练还是测试
train = True
# 模型文件路径
model_path = "model/image_model"
```

## 数据读取

从图片文件夹中将图片读入numpy的array中。这里有几个细节:

+ pillow读取的图像像素值在0-255之间,需要归一化。
+ 在读取图像数据、Label信息的同时,记录图像的路径,方便后期调试。

```python

# 从文件夹读取图片和标签到numpy数组中
# 标签信息在文件名中,例如1_40.jpg表示该图片的标签为1
def read_data(data_dir):
    datas = []
    labels = []
    fpaths = []
    for fname in os.listdir(data_dir):
        fpath = os.path.join(data_dir, fname)
        fpaths.append(fpath)
        image = Image.open(fpath)
        data = np.array(image) / 255.0
        label = int(fname.split("_")[0])
        datas.append(data)
        labels.append(label)

    datas = np.array(datas)
    labels = np.array(labels)

    print("shape of datas: {}\tshape of labels: {}".format(datas.shape, labels.shape))
    return fpaths, datas, labels


fpaths, datas, labels = read_data(data_dir)

# 计算有多少类图片
num_classes = len(set(labels))
```

## 定义placeholder(容器)

除了图像数据和Label,Dropout率也要放在placeholder中,因为在训练阶段和测试阶段需要设置不同的Dropout率。

```python
# 定义Placeholder,存放输入和标签
datas_placeholder = tf.placeholder(tf.float32, [None, 32, 32, 3])
labels_placeholder = tf.placeholder(tf.int32, [None])

# 存放DropOut参数的容器,训练时为0.25,测试时为0
dropout_placeholdr = tf.placeholder(tf.float32)
```

## 定义卷基网络(卷积和Pooling部分)
```python
# 定义卷积层, 20个卷积核, 卷积核大小为5,用Relu激活
conv0 = tf.layers.conv2d(datas_placeholder, 20, 5, activation=tf.nn.relu)
# 定义max-pooling层,pooling窗口为2x2,步长为2x2
pool0 = tf.layers.max_pooling2d(conv0, [2, 2], [2, 2])

# 定义卷积层, 40个卷积核, 卷积核大小为4,用Relu激活
conv1 = tf.layers.conv2d(pool0, 40, 4, activation=tf.nn.relu)
# 定义max-pooling层,pooling窗口为2x2,步长为2x2
pool1 = tf.layers.max_pooling2d(conv1, [2, 2], [2, 2])
```

## 定义全连接部分
```python
# 将3维特征转换为1维向量
flatten = tf.layers.flatten(pool1)

# 全连接层,转换为长度为100的特征向量
fc = tf.layers.dense(flatten, 400, activation=tf.nn.relu)

# 加上DropOut,防止过拟合
dropout_fc = tf.layers.dropout(fc, dropout_placeholdr)

# 未激活的输出层
logits = tf.layers.dense(dropout_fc, num_classes)

predicted_labels = tf.arg_max(logits, 1)
```

## 定义损失函数和优化器

这里有一个技巧,没有必要给Optimizer传递平均的损失,直接将未平均的损失函数传给Optimizer即可。

```python
# 利用交叉熵定义损失
losses = tf.nn.softmax_cross_entropy_with_logits(
    labels=tf.one_hot(labels_placeholder, num_classes),
    logits=logits
)
# 平均损失
mean_loss = tf.reduce_mean(losses)

# 定义优化器,指定要优化的损失函数
optimizer = tf.train.AdamOptimizer(learning_rate=1e-2).minimize(losses)
```

## 定义模型保存器/载入器
如果在比较大的数据集上进行长时间训练,建议定期保存模型。
```python
# 用于保存和载入模型
saver = tf.train.Saver()
```

## 进入训练/测试执行阶段
```python
with tf.Session() as sess:
```

在执行阶段有两条分支:
+ 如果trian为True,进行训练。训练需要使用`sess.run(tf.global_variables_initializer())`初始化参数,训练完成后,需要使用`saver.save(sess, model_path)`保存模型参数。
+ 如果train为False,进行测试,测试需要使用`saver.restore(sess, model_path)`读取参数。

## 训练阶段执行
```python
if train:
       print("训练模式")
       # 如果是训练,初始化参数
       sess.run(tf.global_variables_initializer())
       # 定义输入和Label以填充容器,训练时dropout为0.25
       train_feed_dict = {
           datas_placeholder: datas,
           labels_placeholder: labels,
           dropout_placeholdr: 0.25
       }
       for step in range(150):
           _, mean_loss_val = sess.run([optimizer, mean_loss], feed_dict=train_feed_dict)
           if step % 10 == 0:
               print("step = {}\tmean loss = {}".format(step, mean_loss_val))
       saver.save(sess, model_path)
       print("训练结束,保存模型到{}".format(model_path))
```

### 测试阶段执行
```python
else:
    print("测试模式")
    # 如果是测试,载入参数
    saver.restore(sess, model_path)
    print("从{}载入模型".format(model_path))
    # label和名称的对照关系
    label_name_dict = {
        0: "飞机",
        1: "汽车",
        2: "鸟"
    }
    # 定义输入和Label以填充容器,测试时dropout为0
    test_feed_dict = {
        datas_placeholder: datas,
        labels_placeholder: labels,
        dropout_placeholdr: 0
    }
    predicted_labels_val = sess.run(predicted_labels, feed_dict=test_feed_dict)
    # 真实label与模型预测label
    for fpath, real_label, predicted_label in zip(fpaths, labels, predicted_labels_val):
        # 将label id转换为label名
        real_label_name = label_name_dict[real_label]
        predicted_label_name = label_name_dict[predicted_label]
        print("{}\t{} => {}".format(fpath, real_label_name, predicted_label_name))
```

?mid=&wid=51824&sid=&tid=8357&rid=LOADED&custom1=mp.csdn.net&custom2=%2Fpostedit&t=1556521616916?mid=&wid=51824&sid=&tid=8357&rid=FINISHED&custom1=mp.csdn.net&t=1556521616917

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
TensorFlow是一个开源的机器学习框架,用于构建和训练各种机器学习模型。TensorFlow提供了丰富的编程接口和工具,使得开发者能够轻松地创建、训练和部署自己的模型。 TensorFlow TutorialTensorFlow官方提供的学习资源,旨在帮助新手快速入门。该教程详细介绍了TensorFlow的基本概念、常用操作和各种模型的构建方法。 在TensorFlow Tutorial中,首先会介绍TensorFlow的基本工作原理和数据流图的概念。通过理解数据流图的结构和运行过程,可以更好地理解TensorFlow的工作方式。 接下来,教程会详细介绍TensorFlow的核心组件,例如张量(Tensor)、变量(Variable)和操作(Operation)。这些组件是构建和处理模型的基本元素,通过使用它们可以创建复杂的神经网络和其他机器学习模型。 在教程的后半部分,会介绍如何使用TensorFlow构建不同类型的模型,例如深度神经网络(DNN)、卷积神经网络(CNN)和递归神经网络(RNN)。每个模型都会有详细的代码示例和实践任务,帮助学习者掌握相关知识和技能。 此外,教程还包含了关于模型的训练、评估和优化的内容,以及如何使用TensorBoard进行可视化和调试。 总结来说,TensorFlow Tutorial提供了全面而详细的学习资源,通过学习该教程,可以快速入门TensorFlow,并且掌握构建和训练机器学习模型的方法。无论是初学者还是有一定经验的开发者,都可以从中受益并扩展自己的机器学习技能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值