Assignment Two(六)Tensorflow
TensorFlow是一个用于在Tensor对象上执行计算图的系统,其原生支持为其变量执行反向传播。在其中,我们使用张量,它们是类似于numpy ndarray的n维数组。
一、准备与安装
1.1 创建新的虚拟环境
cmd命令 conda create -n tf_20_env python=3.7
启动 activate tf_20_env
安装作业一中的库 pip install -r D:\CS231nAssignment1\assignment1\requirements.txt
这样方可正常启动 jupyter notebook
1.2 安装tensorflow
进入anaconda prompt
输入命令 pip install tensorflow==1.14
(做到后面我更新到2.3了,因为作业的新要求就是2.x版本,从第四部分开始)
安装完成后,验证
也可以选择镜像文件whl安装,暂不赘述。
二、程序准备
2.1 加载数据集
首先,加载CIFAR-10数据集:
TensorFlow中的tf.keras.datasets包提供了用于加载许多常见数据集的预构建实用程序功能
TensorFlow中的tf.data软件包提供了自动执行预处理数据并以小批量方式对其进行迭代工作的工具
import os
import tensorflow as tf
import numpy as np
import math
import timeit
import matplotlib.pyplot as plt
#由于tensorflow的版本问题,在这里加入一行
#否则报错'RefVariable' object has no attribute '_id'
tf.enable_eager_execution()
%matplotlib inline
def load_cifar10(num_training=49000, num_validation=1000, num_test=10000):
"""
从网上获取CIFAR-10数据集并进行预处理以准备
它用于两层神经网络分类器。 这些步骤与
我们用于SVM,但浓缩为一个功能。
"""
# 加载原始CIFAR-10数据集并使用适当的数据类型和形状
cifar10 = tf.keras.datasets.cifar10.load_data()
(X_train, y_train), (X_test, y_test) = cifar10
X_train = np.asarray(X_train, dtype=np.float32)
y_train = np.asarray(y_train, dtype=np.int32).flatten()
X_test = np.asarray(X_test, dtype=np.float32)
y_test = np.asarray(y_test, dtype=np.int32).flatten()
# 对数据进行二次采样
mask = range(num_training, num_training + num_validation)
X_val = X_train[mask]
y_val = y_train[mask]
mask = range(num_training)
X_train = X_train[mask]
y_train = y_train[mask]
mask = range(num_test)
X_test = X_test[mask]
y_test = y_test[mask]
# 标准化数据:减去平均像素并除以std
mean_pixel = X_train.mean(axis=(0, 1, 2), keepdims=True)
std_pixel = X_train.std(axis=(0, 1, 2), keepdims=True)
X_train = (X_train - mean_pixel) / std_pixel
X_val = (X_val - mean_pixel) / std_pixel
X_test = (X_test - mean_pixel) / std_pixel
return X_train, y_train, X_val, y_val, X_test, y_test
# 调用上面的函数以获取我们的数据
NHW = (0, 1, 2)
X_train, y_train, X_val, y_val, X_test, y_test = load_cifar10()
print('Train data shape: ', X_train.shape)
print('Train labels shape: ', y_train.shape, y_train.dtype)
print('Validation data shape: ', X_val.shape)
print('Validation labels shape: ', y_val.shape)
print('Test data shape: ', X_test.shape)
print('Test labels shape: ', y_test.shape)
输出:
Downloading data from https://www.cs.toronto.edu/~kriz/cifar-10-python.tar.gz
170500096/170498071 [==============================] - 31s 0us/step
Train data shape: (49000, 32, 32, 3)
Train labels shape: (49000,) int32
Validation data shape: (1000, 32, 32, 3)
Validation labels shape: (1000,)
Test data shape: (10000, 32, 32, 3)
Test labels shape: (10000,)
2.2 Dataset
构造一个Dataset对象以遍历数据X和标签y
class Dataset(object):
def __init__(self, X, y, batch_size, shuffle=False):
assert X.shape[0] == y.shape[0], 'Got different numbers of data and labels'
self.X, self.y = X, y
self.batch_size, self.shuffle = batch_size, shuffle
def __iter__(self):
N, B = self.X.shape[0], self.batch_size
idxs = np.arange(N)
if self.shuffle:
np.random.shuffle(idxs)
return iter((self.X[i:i+B], self.y[i:i+B]) for i in range(0, N, B))
train_dset = Dataset(X_train, y_train, batch_size=64, shuffle=True)
val_dset = Dataset(X_val, y_val, batch_size=64, shuffle=False)
test_dset = Dataset(X_test, y_test, batch_size=64)
# We can iterate through a dataset like this:
for t, (x, y) in enumerate(train_dset):
print(t, x.shape, y.shape)
if t > 5: break
输出:
0 (64, 32, 32, 3) (64,)
1 (64, 32, 32, 3) (64,)
2 (64, 32, 32, 3) (64,)
3 (64, 32, 32, 3) (64,)
4 (64, 32, 32, 3) (64,)
5 (64, 32, 32, 3) (64,)
6 (64, 32, 32, 3) (64,)
三、Barebones TensorFlow
TensorFlow附带了各种高级API,使定义和训练神经网络变得非常方便。在本部分中,从学习使用基本的TensorFlow构造构建模型开始。
Barebones Tensorflow对于理解TensorFlow的构建模块很重要,但是其中很多涉及TensorFlow 1.x的概念。我们将使用传统模块,例如tf.Variable。
TensorFlow 1.x:
TensorFlow 1.x主要是用于处理静态计算图的框架。
计算图中的节点是张量,当该图运行时将保存n维数组。
图中的边表示在运行图以实际执行有用的计算时将在张量上运行的函数。
TF1.x的图形配置:
1.构建一个描述您要执行的计算的计算图。该阶段实际上不执行任何计算;它只是建立计算的符号表示。此阶段通常将定义一个或多个占位符对象,这些对象代表计算图的输入。
2.多次运行计算图。每次运行图形时(例如,执行一个梯度下降步骤),您都将指定要计算的图形部分,并传递feed_dict字典,该字典将为图形中的任何占位符提供具体值。
TF 1.x和2.0方法之间的主要区别:
在于2.0方法没有使用tf.Session,tf.run,占位符,feed_dict。
3.1 TensorFlow warmup: Flatten Function
通过定义一个简单的展平函数来看到这一点,该函数将重塑图像数据的形状以用于完全连接的网络。
在TensorFlow中,卷积特征图的数据通常存储在形状为NxHxWxC的Tensor中,其中:
•N是数据点的数量(最小批大小)
•H是特征图的高度
•W是特征图的宽度
•C是特征图中的通道数
当我们进行类似2D卷积的操作时,这是表示数据的正确方法,该操作需要空间了解中间要素之间的相对位置。
但是,当我们使用完全连接的仿射层来处理图像时,我们希望每个数据点都由单个矢量表示-分离数据的不同通道,行和列不再有用。因此,我们使用“展平”操作将每个表示形式的 HxWxC 值折叠为单个长向量。
注意:
1.tf.reshape调用的目标形状为(N,-1),这意味着它将将第一个维的形状/保持为N,然后根据需要推断输出中的第二维是什么,因此我们可以折叠正确输入剩余的尺寸。
2.TensorFlow和PyTorch在默认的Tensor布局上有所不同; TensorFlow使用N x H x W x C,但PyTorch使用N x C x H x W.
def flatten(x):
# shape (N, D1, ..., DM)
N = tf.shape(x)[0]
return tf.reshape(x, (N, -1))
def test_flatten():
# 使用numpy构造输入数据x的具体值
x_np = np.arange(24).reshape((2, 3, 4))
print('x_np:\n', x_np, '\n')
# 计算具体输出
x_flat_np = flatten(x_np)
print('x_flat_np:\n', x_flat_np, '\n')
test_flatten()
输出:
x_np:
[[[ 0 1 2 3]
[ 4 5 6 7]
[ 8 9 10 11]]
[[12 13 14 15]
[16 17 18 19]
[20 21 22 23]]]
x_flat_np:
Tensor("Reshape:0", shape=(2, 12), dtype=int32)
3.2 Barebones TensorFlow: Define a Two-Layer Network
实现:具有两个隐藏层且在CIFAR10数据集上没有偏差的完全连接的ReLU网络 (仅使用低级TensorFlow运算符来定义网络)
3.2.1 前向传播
前向传播:two_layer_fc中定义网络的前向传播, 将接受TensorFlow张量作为网络的输入和权重,并返回TensorFlow张量作为分数。
def two_layer_fc(x, params):
w1, w2 = params # 解压参数
x = flatten(x) # 展开x; 先追,x形状为 (N, D)
h = tf.nn.relu(tf.matmul(x, w1)) # 隐藏层: h 形状为 (N, H)
scores = tf.matmul(h, w2) # 得分形状为 (N, C)
return scores
代码分析 3.2.1:
完全连接的神经网络; 体系结构是:全连接层-> ReLU->全连接层。
隐藏层将具有H个单位
输出层将为C类产生分数
输入:
-x:形状为(N,d1,...,dM)的TensorFlow张量输入数据,其中d1 * ... * dM =D
-参数:TensorFlow张量的列表[w1,w2]给出权重网络,其中w1的形状为(D,H),而w2的形状为(H,C)。
返回值: -分数:形状(N,C)的TensorFlow张量,给出输入数据x的分类分数。
3.2.2 检查输出的形状
def two_layer_fc_test():
hidden_layer_size = 42
#前面要提前设置device的值:分为使用CPU or GPU
with tf.device(device):
x = tf.zeros((64, 32, 32, 3))
w1 = tf.zeros((32 * 32 * 3, hidden_layer_size))
w2 = tf.zeros((hidden_layer_size, 10))
# 调用two_layer_fc函数以实现网络的正向传递
scores = two_layer_fc(x, [w1, w2])
print(scores.shape)
two_layer_fc