tensorflow2.0—笔记3 神经网络与全连接层 原创

1191-杨同学

发表文章数:32

首页 » 算法 » 正文

数据集加载

tensorflow2.0---笔记3 神经网络与全连接层                    原创
tensorflow2.0---笔记3 神经网络与全连接层                    原创

MNIST数据集

keras.datasets.mnist.load_data() 加载的数据是numpy格式。
tensorflow2.0---笔记3 神经网络与全连接层                    原创

import tensorflow as tf
from tensorflow import keras

(x, y), (x_test, y_test) = keras.datasets.mnist.load_data()

# print(type(x))    <class 'numpy.ndarray'>
# print(tf.is_tensor(x))    False

print(x.shape)  # (60000, 28, 28)
print(y.shape)  # (60000,)
print(x.min(), x.max())  # 0 255

print(y[:4])  # [5 0 4 1]
y_onehot = tf.one_hot(y, depth=10) 
print(y_onehot[:2])
# tf.Tensor(
# [[0. 0. 0. 0. 0. 1. 0. 0. 0. 0.]
# [1. 0. 0. 0. 0. 0. 0. 0. 0. 0.]], shape=(2, 10), dtype=float32)

CIFAR10/100

tensorflow2.0---笔记3 神经网络与全连接层                    原创

from tensorflow import keras

(x, y), (x_test, y_test) = keras.datasets.cifar10.load_data()

print(type(x))  # <class 'numpy.ndarray'>

print(x.shape, y.shape, x_test.shape, y_test.shape)  # (50000, 32, 32, 3) (50000, 1) (10000, 32, 32, 3) (10000, 1)

print(x.min(), x.max())  # 0 255

print(y[:2])
# [[6]
#  [9]]

tf.data.Dataset.from_tensor_slices()

作用:
(1)将image数据和label组合起来;
(2).shuffle方法,将数据打散的同时,保持x、y的对应关系;
(3)便于数据预处理(batch等)。

import tensorflow as tf
from tensorflow import keras

(x, y), (x_test, y_test) = keras.datasets.cifar10.load_data()

db = tf.data.Dataset.from_tensor_slices(x_test)
print(next(iter(db)).shape)  # 每次next取的是一张图片

db = tf.data.Dataset.from_tensor_slices((x_test, y_test))  # 传入一个元组
print(next(iter(db))[0].shape)

.shuffle()

(x, y), (x_test, y_test) = keras.datasets.cifar10.load_data()

db = tf.data.Dataset.from_tensor_slices(x_test)
db = db.shuffle(10000)

.map()

针对每一个sample做处理

import tensorflow as tf
from tensorflow import keras


def preprocess(x, y):
    x = tf.cast(x, dtype=tf.float32)/255.
    y = tf.cast(y, dtype=tf.int32)
    y = tf.one_hot(y, depth=10)

    return x, y


(x, y), (x_test, y_test) = keras.datasets.cifar10.load_data()
db = tf.data.Dataset.from_tensor_slices((x, y))
print(db)  # <TensorSliceDataset shapes: ((32, 32, 3), (1,)), types: (tf.uint8, tf.uint8)>

db = db.map(preprocess)  # 函数名

res = next(iter(db))
print(res[0].shape, res[1].shape)  # (32, 32, 3) (1, 10)

.repeat()

tensorflow2.0---笔记3 神经网络与全连接层                    原创
tensorflow2.0---笔记3 神经网络与全连接层                    原创
.repeat(2)重复两次;若括号中不加参数,则无限次重复

import tensorflow as tf
from tensorflow import keras

(x, y), (x_test, y_test) = keras.datasets.cifar10.load_data()
print(x_test.shape) # (10000, 32, 32, 3)

db = tf.data.Dataset.from_tensor_slices(x_test)
print(next(iter(db)).shape)  # 每次next取的是一张图片

db = tf.data.Dataset.from_tensor_slices((x_test, y_test))  # 传入一个元组
db = db.repeat(2)
db = iter(db)

i = 0
while True:
    next(db)
    i += 1
    print(i)  # 最后的结果是20000,即数据重复了两次

.batch(batch_size)

import tensorflow as tf
from tensorflow import keras


def preprocessing(x, y):
    x = tf.cast(x, tf.float32)/255  # 转换成tensor类型,同时归一化
    y = tf.cast(y, tf.int32)
    return x, y


(x_train, y_train), (x_test, y_test) = keras.datasets.cifar10.load_data()

db = tf.data.Dataset.from_tensor_slices((x_train, y_train))
db = db.map(preprocessing)
db = db.shuffle(10000).batch(100)

完整案例

import tensorflow as tf
from tensorflow import keras
import os

os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'

(x, y), (x_test, y_test) = keras.datasets.mnist.load_data()

x = tf.convert_to_tensor(x, dtype=tf.float32) / 255.
y = tf.convert_to_tensor(y, dtype=tf.int32)

x_test = tf.convert_to_tensor(x_test, dtype=tf.float32) / 255.
y_test = tf.convert_to_tensor(y_test, dtype=tf.int32)

train_db = tf.data.Dataset.from_tensor_slices((x, y)).batch(128)
test_db = tf.data.Dataset.from_tensor_slices((x_test, y_test)).batch(128)

w1 = tf.Variable(tf.random.truncated_normal([784, 256], stddev=0.1))
b1 = tf.Variable(tf.zeros([256]))
w2 = tf.Variable(tf.random.truncated_normal([256, 128], stddev=0.1))
b2 = tf.Variable(tf.zeros([128]))
w3 = tf.Variable(tf.random.truncated_normal([128, 10], stddev=0.1))
b3 = tf.Variable(tf.zeros([10]))

lr = 1e-3

for epoch in range(10):
    for step, (x, y) in enumerate(train_db):
        # x:[128, 28, 28]  batch_size=128
        # y:[128]

        x = tf.reshape(x, [-1, 28*28])

        with tf.GradientTape() as tape:
            h1 = tf.nn.relu(x@w1 + b1)
            h2 = tf.nn.relu(h1@w2 + b2)
            out = h2@w3 + b3

            # compute loss
            y_onehot = tf.one_hot(y, depth=10)
            loss = tf.losses.mean_squared_error(y_onehot, out)

        grads = tape.gradient(loss, [w1, b1, w2, b2, w3, b3])  # 注意中括号

        w1.assign_sub(lr * grads[0])
        b1.assign_sub(lr * grads[1])
        w2.assign_sub(lr * grads[2])
        b2.assign_sub(lr * grads[3])
        w3.assign_sub(lr * grads[4])
        b3.assign_sub(lr * grads[5])

        if step % 100 == 0:
            print(epoch, step, "loss:", float(loss))

    # test/evaluate
    total_correct, total_num = 0, 0
    for step, (x, y) in enumerate(test_db):
        x = tf.reshape(x, [-1, 28*28])

        h1 = tf.nn.relu(x@w1 + b1)
        h2 = tf.nn.relu(h1@w2 + b2)
        out = h2@w3 + b3

        # out:[b, 10]
        prob = tf.nn.softmax(out, axis=1)
        pred = tf.argmax(prob, axis=1)
        pred = tf.cast(pred, dtype=tf.int32)

        correct = tf.cast(tf.equal(pred, y), dtype=tf.int32)
        correct = tf.reduce_sum(correct)
        
        total_correct += int(correct)
        total_num += x.shape[0]
        
        print(total_correct/total_num)

注意:

import tensorflow as tf

a = tf.constant([[1, 2],
                 [8, 5]])
print(tf.argmax(a, axis=1))
# tf.Tensor([1 0], shape=(2,), dtype=int64)

全连接层

tensorflow2.0---笔记3 神经网络与全连接层                    原创
tensorflow2.0---笔记3 神经网络与全连接层                    原创
tensorflow2.0---笔记3 神经网络与全连接层                    原创
layers:
Input、Hidden、Output
tensorflow2.0---笔记3 神经网络与全连接层                    原创

tensorflow2.0---笔记3 神经网络与全连接层                    原创
tensorflow2.0---笔记3 神经网络与全连接层                    原创

fully connected layer

import tensorflow as tf
import os

os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'

x = tf.random.normal([4, 784])

net = tf.keras.layers.Dense(512)  # 512 为输出维度
out = net(x)  # 输入维度可不用指定,运行时自动根据输入生成权值

print(out.shape)  # (4, 512)  

print('权重:', net.kernel.shape)  # 权重: (784, 512)
print('偏置:', net.bias.shape)  # 偏置: (512,)

也可直接import keras

import tensorflow as tf
import os

os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'

net = tf.keras.layers.Dense(10)
print(net.bias)  # AttributeError: 'Dense' object has no attribute 'bias'
print(net.get_weights())  # [] 为空

因为不知道输入维度,所以无法确定w、b,没有完成w、b的创建。
接上面的代码:

net.build(input_shape=(None, 4))
print(net.kernel.shape)  # (4, 10)

net.build(input_shape=(2, 4))
print(net.kernel.shape)  # (4, 10)

当输入维度和Dense层指定输入维度不一致时,程序报错:

import tensorflow as tf
import os

os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'

net = tf.keras.layers.Dense(10)
net.build(input_shape=(None, 4))
out = net(tf.random.normal([4, 12]))
print(out.shape)  # 程序报错!

修改:

net = tf.keras.layers.Dense(10)
net.build(input_shape=(None, 4))
out = net(tf.random.normal([4, 4]))
print(out.shape)  # (4, 10)

keras.Sequential([layer1, layer2,…])创建多层网络

import tensorflow as tf
import os
import keras

os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'

x = tf.random.normal([2, 3])

model = keras.Sequential([
    keras.layers.Dense(2, activation='relu'),  # 指定输出维度和激活函数
    keras.layers.Dense(2, activation='relu'),
    keras.layers.Dense(2)

])
model.build(input_shape=[None, 3])
model.summary()  # 打印网络结构

for i in model.trainable_weights:  # 返回一个list
    print(i.name, i.shape)

运行结果:
tensorflow2.0---笔记3 神经网络与全连接层                    原创

输出方式(激活函数的选择)

tensorflow2.0---笔记3 神经网络与全连接层                    原创

tensorflow2.0---笔记3 神经网络与全连接层                    原创
将未经过激活函数的结果称为logits
tensorflow2.0---笔记3 神经网络与全连接层                    原创
使用sigmoid激活函数可将结果限制在0~1范围内:
tensorflow2.0---笔记3 神经网络与全连接层                    原创
tensorflow2.0---笔记3 神经网络与全连接层                    原创

a = tf.linspace(-6., 6, 6)
print(a.numpy())  # [-6.        -3.6       -1.1999998  1.2000003  3.6000004  6.       ]

a = tf.sigmoid(a)
print(a.numpy())  # [0.00247262 0.026597   0.23147526 0.7685248  0.973403   0.9975274 ]

sigmoid函数的梯度:

import tensorflow as tf

x = tf.linspace(-6., 6, 20)
print(x.numpy())

with tf.GradientTape() as tape:
    tape.watch(x)
    y = 1 / (1 + tf.math.exp(-x))

grads = tape.gradient(y, x)
print(grads)

运行结果:
tensorflow2.0---笔记3 神经网络与全连接层                    原创

tensorflow2.0---笔记3 神经网络与全连接层                    原创

如果原来的概率是0.8,0.6, 相差不大,而经过softmax指数变换后相差大—–使大的更大
tensorflow2.0---笔记3 神经网络与全连接层                    原创

logits = tf.random.uniform([1, 6], minval=-2, maxval=2)
prob = tf.nn.softmax(logits, axis=1)
print(prob.numpy())  # [[0.04365111 0.05211622 0.12296615 0.11282954 0.60218203 0.0662549 ]]
print(tf.reduce_sum(prob))  # tf.Tensor(0.99999994, shape=(), dtype=float32)

tensorflow2.0---笔记3 神经网络与全连接层                    原创
tf.tanh(a)

损失函数loss

tensorflow2.0---笔记3 神经网络与全连接层                    原创

MSE

tensorflow2.0---笔记3 神经网络与全连接层                    原创
loss计算时除以batch_size,也可以再除以一个维度(如y是one-hot编码时)

import tensorflow as tf
import os
import keras

os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'

y = tf.constant([1, 2, 3, 0, 2])
y = tf.one_hot(y, depth=4)
y = tf.cast(y, dtype=tf.float32)

out = tf.random.normal([5, 4]) # 对应one-hot编码中depth=4

loss1 = tf.reduce_mean(tf.square(y - out)) # /(b*dim)
loss2 = tf.square(tf.norm(y - out)) / (5*4)  # 求范数不指定轴 全局 返回一个数
loss3 = tf.reduce_mean(tf.losses.MSE(y, out))
print(tf.losses.MSE(y, out).numpy())  # 返回5个数,默认对行,且除以了维度
print(loss1.numpy(), loss2.numpy(), loss3.numpy())

运行结果:
tensorflow2.0---笔记3 神经网络与全连接层                    原创

交叉熵代价函数

tensorflow2.0---笔记3 神经网络与全连接层                    原创

a = tf.fill([4], 0.25)
a_log = tf.math.log(a) / tf.math.log(2.)  # tf中对数默认以e为底
en = -tf.reduce_sum(a * a_log)
print(en)  
# tf.Tensor(2.0, shape=(), dtype=float32)
# 不确定性越大,熵越大,信息量越小


b = tf.constant([0.01, 0.01, 0.01, 0.97])
b_log = tf.math.log(b) / tf.math.log(2.)
en2 = -tf.reduce_sum(b * b_log)
print(en2)  
# tf.Tensor(0.24194068, shape=(), dtype=float32)

tensorflow2.0---笔记3 神经网络与全连接层                    原创
对二分类问题:
tensorflow2.0---笔记3 神经网络与全连接层                    原创
tensorflow2.0---笔记3 神经网络与全连接层                    原创
tensorflow2.0---笔记3 神经网络与全连接层                    原创
例:
tensorflow2.0---笔记3 神经网络与全连接层                    原创
tf.losses.categorical_crossentropy( y_truth, prob )

import tensorflow as tf
import os
import keras

os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'

loss1 = tf.losses.categorical_crossentropy([0, 1, 0, 0], [0.25, 0.25, 0.25, 0.25])
print(loss1)  # tf.Tensor(1.3862944, shape=(), dtype=float32)

# 预测错误的话损失较大
loss2 = tf.losses.categorical_crossentropy([0, 1, 0, 0], [0.1, 0.1, 0.8, 0.1])
print(loss2)  # tf.Tensor(2.3978953, shape=(), dtype=float32)

# 预测成功的概率越大,损失越小
loss3 = tf.losses.categorical_crossentropy([0, 1, 0, 0], [0.1, 0.7, 0.1, 0.1])
print(loss3)  # tf.Tensor(0.35667497, shape=(), dtype=float32)

对于二分类单输出:

loss = tf.losses.binary_crossentropy([1], 0.1)
print(loss)

tensorflow2.0---笔记3 神经网络与全连接层                    原创
从logits到交叉熵:
tensorflow2.0---笔记3 神经网络与全连接层                    原创
tensorflow2.0---笔记3 神经网络与全连接层                    原创
从softmax到交叉熵的这一步,可能出现数值不稳定问题,因此,可以用以下方法来解决:

loss = tf.losses.categorical_crossentropy([0, 1], logits, from_logits=True)

即,直接将logits输入交叉熵函数中,同时设置from_logits = True.

Dense层权重和偏置初始化问题

import tensorflow as tf
import os
import keras

os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'

x = tf.random.normal([2, 256])
net = keras.layers.Dense(10)
out = net(x)

ctrl+b查看函数源代码:
tensorflow2.0---笔记3 神经网络与全连接层                    原创
发现对权重的初始化 kernel_initializer = “glorot_uniform”
tensorflow2.0---笔记3 神经网络与全连接层                    原创
tensorflow2.0---笔记3 神经网络与全连接层                    原创

拜师教育学员文章:作者:1191-杨同学, 转载或复制请以 超链接形式 并注明出处 拜师资源博客
原文地址:《tensorflow2.0—笔记3 神经网络与全连接层 原创》 发布于2020-09-18

分享到:
赞(0) 打赏

评论 抢沙发

评论前必须登录!

  注册



长按图片转发给朋友

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏

Vieu3.3主题
专业打造轻量级个人企业风格博客主题!专注于前端开发,全站响应式布局自适应模板。

登录

忘记密码 ?

您也可以使用第三方帐号快捷登录

Q Q 登 录
微 博 登 录