tensorflow2.0牛刀小试--LetNet+fashion_Mnist

  回想以前刚接触tensorflow,在各种API以及各种花里胡哨用法的打击下,对于小白的我果断放弃转而投奔pytorch的怀抱。几个框架学习过程中也没做笔记,tensorflow2.0的出世(出了一年了吧。),跟pytorch一样动态图的机制,看来有机会import tensorflow as torch了。借此机会回来重新学习tensorflow,实现一些简单的操作,温故知新。
  在tf2.0里面,默认开启了eager Execution,并且使用Keras作为默认高级API,网络的搭建和自定义操作也变得更简单,估计到处飞的keras会引来吐槽吧。

加载Mnist

keras.datasets :内置了7个基本的数据集,分别是
        boston_housing,cifar10,cifar100,fashion_mnist,imdb,mnist,reuters
对于新手有一个学习的地方就是关于数据的基本读取方法,每个数据集都内置了load_data()方法(包括了下载与加载)
例如fashion_mnist:


@keras_export('keras.datasets.fashion_mnist.load_data')
def load_data():
  """Loads the Fashion-MNIST dataset.

  Returns:
      Tuple of Numpy arrays: `(x_train, y_train), (x_test, y_test)`.

  License:
      The copyright for Fashion-MNIST is held by Zalando SE.
      Fashion-MNIST is licensed under the [MIT license](
      https://github.com/zalandoresearch/fashion-mnist/blob/master/LICENSE).

  """
  dirname = os.path.join('datasets', 'fashion-mnist')
  base = 'https://storage.googleapis.com/tensorflow/tf-keras-datasets/'
  files = [
      'train-labels-idx1-ubyte.gz', 'train-images-idx3-ubyte.gz',
      't10k-labels-idx1-ubyte.gz', 't10k-images-idx3-ubyte.gz'
  ]

  paths = []
  for fname in files:
    paths.append(get_file(fname, origin=base + fname, cache_subdir=dirname))

  with gzip.open(paths[0], 'rb') as lbpath:
    y_train = np.frombuffer(lbpath.read(), np.uint8, offset=8)

  with gzip.open(paths[1], 'rb') as imgpath:
    x_train = np.frombuffer(
        imgpath.read(), np.uint8, offset=16).reshape(len(y_train), 28, 28)

  with gzip.open(paths[2], 'rb') as lbpath:
    y_test = np.frombuffer(lbpath.read(), np.uint8, offset=8)

  with gzip.open(paths[3], 'rb') as imgpath:
    x_test = np.frombuffer(
        imgpath.read(), np.uint8, offset=16).reshape(len(y_test), 28, 28)

  return (x_train, y_train), (x_test, y_test)

所以我们加载的时候只要:

(x_train_all, y_train_all), (x_test, y_test) = keras.datasets.fashion_mnist.load_data()
x_val, x_train = x_train_all[:3000], x_train_all[3000:]
y_val, y_train = y_train_all[:3000], y_train_all[3000:]

归一化

  数据加载完后,对数据归一化,而归一化的作用在此就不展开阐述了。在此利用scikit-learn库进行处理:

from sklearn.preprocessing import StandardScaler

scaler = StandardScaler()
x_train_scaled = scaler.fit_transform(
                    x_train.astype(np.float32).reshape(-1, 1)).reshape(-1, 28, 28, 1)
x_val_scaled = scaler.transform(
                    x_val.astype(np.float32).reshape(-1, 1)).reshape(-1, 28, 28, 1)
x_test_scaled = scaler.transform(
                    x_test.astype(np.float32).reshape(-1, 1)).reshape(-1, 28, 28, 1)

这一步操作展开解释:
1)StandardScaler是用来计算归一化和标准差的类,code里为何训练集用了fit_transform,而测试集则用了transform,从源码的注释里可以看到:

Centering and scaling happen independently on each feature by computing the relevant statistics on the samples in the training set. Mean and standard deviation are then stored to be used on later data using the transform method.


储存在训练集计算得来的平均值和标准差 ,以便在后面使用transform方法(意思就是在transform时利用了fit_transform的平均值和标准差,还因为数据的分布都是相同的,这也得到了解释)

2) reshape(-1, 1)transformreshape(-1, 28, 28, 1)
为何不直接做transform而是`reshape(-1, 1),看下面例子就知道了:

a = np.array([[1, 2, 3],
              [4, 5, 6],
              [7, 8, 8]])
b = a.reshape(-1, 1)
print(scaler.fit_transform(a))
print(scaler.fit_transform(b))

>>[[-1.22474487 -1.22474487 -1.29777137]
   [ 0.          0.          0.16222142]
   [ 1.22474487  1.22474487  1.13554995]]

>>[[-1.60422237]
   [-1.19170805]
   [-0.77919372]
   [-0.3666794 ]
   [ 0.04583492]
   [ 0.45834925]
   [ 0.87086357]    
   [ 1.2833779 ]
   [ 1.2833779 ]]

需要对全局的数据进行处理,而不是各个维度上分别处理。最后reshape(-1, 28, 28, 1)是为了后面输入到网络中去计算。

网络结构

  网络的搭建用了Sequential,官方文档定义为序贯模型,也就是最简单,线性堆叠,例如VGG这样一路走到黑的模型。对于更复杂的模型,支持多输入多输出,层与层之间想怎么连怎么连,就要用到Model。显然,Sequential只是作为特殊的一类单独拿出来用了。

下面参照了LetNet-5构建了模型,只是输入改成了28*28

# model
model = keras.models.Sequential([
    keras.layers.Conv2D(filters=6, kernel_size=5, strides=1,
                        activation='relu',
                        input_shape=[28, 28, 1]),
    keras.layers.MaxPool2D(pool_size=2),
    keras.layers.Conv2D(filters=16, kernel_size=5, strides=1,
                        activation='relu'),
    keras.layers.MaxPooling2D(pool_size=2),
    keras.layers.Conv2D(filters=120, kernel_size=3, strides=1,
                        activation='relu'),
    keras.layers.MaxPooling2D(pool_size=2),
    keras.layers.Flatten(),
    keras.layers.Dense(84, activation='relu'),
    keras.layers.Dense(10, activation='softmax')
])

模型训练的BP模式设置

adam = keras.optimizers.Adam()
model.compile(loss='sparse_categorical_crossentropy',
              optimizer=adam,
              metrics=['accuracy'])

  对于loss的选择
如果标签为0,1,2,3···的数字编码,则用sparse_categorical_crossentropy,
如果为[0, 0, 1, 0, 0]这类的独热编码,则用categorical_crossentropy

训练以及参数设置

使用fit函数进行参数的设置以及训练,都是比较基本的使用方法,相对都是通用的

history = model.fit(x_train_scaled, y_train, epochs=100,
                    validation_data=[x_val_scaled, y_val],
                    batch_size=256)

可视化

def show_result(history):
    pd.DataFrame(history.history).plot(figsize=(12,6))
    plt.grid(True)
    plt.gca().set_ylim(0,1)
    plt.show()
show_result(history)

result.png

感觉过拟合了。。训练太久,不过单从数据也不能说明什么
下面试着用tensorflow的from_tensor_slices读取数据,训练获得更好的效果

train_dataset = tf.data.Dataset.from_tensor_slices((x_train_scaled, y_train))
train_dataset = train_dataset.repeat(100).batch(256).prefetch(100)
val_dataset = tf.data.Dataset.from_tensor_slices((x_val_scaled, y_val))
val_dataset = val_dataset.repeat(100).batch(256)

# train
history3 = model.fit(train_dataset, epochs=100,
                    validation_data=train_dataset,
                    validation_steps=len(x_val) // 256,
                    steps_per_epoch= len(x_train) // 256
                    )
C7`IOVMBLT9NFWX1@P6F.png

得到了更好的一个结果,其中的原理网上很多资源,太懒写不动

有一点感觉就是:学习的路上总会遇到很多坑,不必要太纠结要搞懂里面的所有原理,有些理论看不懂但我们可以先动手,回头看会往往发现会有新的体会和理解,切勿死磕。就像学英语一样,一直学语法记单词并不能帮助我们更好的说出来,反而经常去说更能辅助我们学深层的语法(现在的小孩学英语很多都不先学音标了,而是像拼音一样的拼读法,先培养语感真的很重要)

更多有关tf2.0的东西以后慢慢更,仅以此纪录自己的学习过程,也欢迎来跟我讨论O(∩_∩)O

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,012评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,628评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,653评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,485评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,574评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,590评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,596评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,340评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,794评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,102评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,276评论 1 344
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,940评论 5 339
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,583评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,201评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,441评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,173评论 2 366
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,136评论 2 352