#%% import os os.environ['TF_CPP_MIN_LOG_LEVEL']='2' import tensorflow as tf from tensorflow import keras from tensorflow.keras import layers, optimizers, datasets, Sequential #%% x = tf.random.normal([2,5,5,3]) # 模拟输入,3通道,高宽为5 # 需要根据[k,k,cin,cout]格式创建,4个卷积核 w = tf.random.normal([3,3,3,4]) # 步长为1, padding为0, out = tf.nn.conv2d(x,w,strides=1,padding=[[0,0],[0,0],[0,0],[0,0]]) # %% x = tf.random.normal([2,5,5,3]) # 模拟输入,3通道,高宽为5 # 需要根据[k,k,cin,cout]格式创建,4个卷积核 w = tf.random.normal([3,3,3,4]) # 步长为1, padding为1, out = tf.nn.conv2d(x,w,strides=1,padding=[[0,0],[1,1],[1,1],[0,0]]) # %% x = tf.random.normal([2,5,5,3]) # 模拟输入,3通道,高宽为5 w = tf.random.normal([3,3,3,4]) # 4个3x3大小的卷积核 # 步长为,padding设置为输出、输入同大小 # 需要注意的是, padding=same只有在strides=1时才是同大小 out = tf.nn.conv2d(x,w,strides=1,padding='SAME') # %% x = tf.random.normal([2,5,5,3]) w = tf.random.normal([3,3,3,4]) # 高宽按3倍减少 out = tf.nn.conv2d(x,w,strides=3,padding='SAME') print(out.shape) # %% # 根据[cout]格式创建偏置向量 b = tf.zeros([4]) # 在卷积输出上叠加偏置向量,它会自动broadcasting为[b,h',w',cout] out = out + b # %% # 创建卷积层类 layer = layers.Conv2D(4,kernel_size=(3,4),strides=(2,1),padding='SAME') out = layer(x) # 前向计算 out.shape # %% layer.kernel,layer.bias # 返回所有待优化张量列表 layer.trainable_variables # %% from tensorflow.keras import Sequential network = Sequential([ # 网络容器 layers.Conv2D(6,kernel_size=3,strides=1), # 第一个卷积层, 6个3x3卷积核 layers.MaxPooling2D(pool_size=2,strides=2), # 高宽各减半的池化层 layers.ReLU(), # 激活函数 layers.Conv2D(16,kernel_size=3,strides=1), # 第二个卷积层, 16个3x3卷积核 layers.MaxPooling2D(pool_size=2,strides=2), # 高宽各减半的池化层 layers.ReLU(), # 激活函数 layers.Flatten(), # 打平层,方便全连接层处理 layers.Dense(120, activation='relu'), # 全连接层,120个节点 layers.Dense(84, activation='relu'), # 全连接层,84节点 layers.Dense(10) # 全连接层,10个节点 ]) # build一次网络模型,给输入X的形状,其中4为随意给的batchsz network.build(input_shape=(4, 28, 28, 1)) # 统计网络信息 network.summary() # %% # 导入误差计算,优化器模块 from tensorflow.keras import losses, optimizers # 创建损失函数的类,在实际计算时直接调用类实例即可 criteon = losses.CategoricalCrossentropy(from_logits=True) # %% # 构建梯度记录环境 with tf.GradientTape() as tape: # 插入通道维度,=>[b,28,28,1] x = tf.expand_dims(x,axis=3) # 前向计算,获得10类别的预测分布,[b, 784] => [b, 10] out = network(x) # 真实标签one-hot编码,[b] => [b, 10] y_onehot = tf.one_hot(y, depth=10) # 计算交叉熵损失函数,标量 loss = criteon(y_onehot, out) # 自动计算梯度 grads = tape.gradient(loss, network.trainable_variables) # 自动更新参数 optimizer.apply_gradients(zip(grads, network.trainable_variables)) # %% # 记录预测正确的数量,总样本数量 correct, total = 0,0 for x,y in db_test: # 遍历所有训练集样本 # 插入通道维度,=>[b,28,28,1] x = tf.expand_dims(x,axis=3) # 前向计算,获得10类别的预测分布,[b, 784] => [b, 10] out = network(x) # 真实的流程时先经过softmax,再argmax # 但是由于softmax不改变元素的大小相对关系,故省去 pred = tf.argmax(out, axis=-1) y = tf.cast(y, tf.int64) # 统计预测正确数量 correct += float(tf.reduce_sum(tf.cast(tf.equal(pred, y),tf.float32))) # 统计预测样本总数 total += x.shape[0] # 计算准确率 print('test acc:', correct/total) # %% # 构造输入 x=tf.random.normal([100,32,32,3]) # 将其他维度合并,仅保留通道维度 x=tf.reshape(x,[-1,3]) # 计算其他维度的均值 ub=tf.reduce_mean(x,axis=0) ub # %% # 创建BN层 layer=layers.BatchNormalization() # %% network = Sequential([ # 网络容器 layers.Conv2D(6,kernel_size=3,strides=1), # 插入BN层 layers.BatchNormalization(), layers.MaxPooling2D(pool_size=2,strides=2), layers.ReLU(), layers.Conv2D(16,kernel_size=3,strides=1), # 插入BN层 layers.BatchNormalization(), layers.MaxPooling2D(pool_size=2,strides=2), layers.ReLU(), layers.Flatten(), layers.Dense(120, activation='relu'), # 此处也可以插入BN层 layers.Dense(84, activation='relu'), # 此处也可以插入BN层 layers.Dense(10) ]) # %% with tf.GradientTape() as tape: # 插入通道维度 x = tf.expand_dims(x,axis=3) # 前向计算,设置计算模式,[b, 784] => [b, 10] out = network(x, training=True) # %% for x,y in db_test: # 遍历测试集 # 插入通道维度 x = tf.expand_dims(x,axis=3) # 前向计算,测试模式 out = network(x, training=False) # %% def preprocess(x, y): # [0~1] x = 2*tf.cast(x, dtype=tf.float32) / 255.-1 y = tf.cast(y, dtype=tf.int32) return x,y # 在线下载,加载CIFAR10数据集 (x,y), (x_test, y_test) = datasets.cifar100.load_data() # 删除y的一个维度,[b,1] => [b] y = tf.squeeze(y, axis=1) y_test = tf.squeeze(y_test, axis=1) # 打印训练集和测试集的形状 print(x.shape, y.shape, x_test.shape, y_test.shape) # 构建训练集对象 train_db = tf.data.Dataset.from_tensor_slices((x,y)) train_db = train_db.shuffle(1000).map(preprocess).batch(128) # 构建测试集对象 test_db = tf.data.Dataset.from_tensor_slices((x_test,y_test)) test_db = test_db.map(preprocess).batch(128) # 从训练集中采样一个Batch,观察 sample = next(iter(train_db)) print('sample:', sample[0].shape, sample[1].shape, tf.reduce_min(sample[0]), tf.reduce_max(sample[0])) # %% conv_layers = [ # 先创建包含多层的列表 # Conv-Conv-Pooling单元1 # 64个3x3卷积核, 输入输出同大小 layers.Conv2D(64, kernel_size=[3, 3], padding="same", activation=tf.nn.relu), layers.Conv2D(64, kernel_size=[3, 3], padding="same", activation=tf.nn.relu), # 高宽减半 layers.MaxPool2D(pool_size=[2, 2], strides=2, padding='same'), # Conv-Conv-Pooling单元2,输出通道提升至128,高宽大小减半 layers.Conv2D(128, kernel_size=[3, 3], padding="same", activation=tf.nn.relu), layers.Conv2D(128, kernel_size=[3, 3], padding="same", activation=tf.nn.relu), layers.MaxPool2D(pool_size=[2, 2], strides=2, padding='same'), # Conv-Conv-Pooling单元3,输出通道提升至256,高宽大小减半 layers.Conv2D(256, kernel_size=[3, 3], padding="same", activation=tf.nn.relu), layers.Conv2D(256, kernel_size=[3, 3], padding="same", activation=tf.nn.relu), layers.MaxPool2D(pool_size=[2, 2], strides=2, padding='same'), # Conv-Conv-Pooling单元4,输出通道提升至512,高宽大小减半 layers.Conv2D(512, kernel_size=[3, 3], padding="same", activation=tf.nn.relu), layers.Conv2D(512, kernel_size=[3, 3], padding="same", activation=tf.nn.relu), layers.MaxPool2D(pool_size=[2, 2], strides=2, padding='same'), # Conv-Conv-Pooling单元5,输出通道提升至512,高宽大小减半 layers.Conv2D(512, kernel_size=[3, 3], padding="same", activation=tf.nn.relu), layers.Conv2D(512, kernel_size=[3, 3], padding="same", activation=tf.nn.relu), layers.MaxPool2D(pool_size=[2, 2], strides=2, padding='same') ] # 利用前面创建的层列表构建网络容器 conv_net = Sequential(conv_layers) # %% # 创建3层全连接层子网络 fc_net = Sequential([ layers.Dense(256, activation=tf.nn.relu), layers.Dense(128, activation=tf.nn.relu), layers.Dense(100, activation=None), ]) # %% # build2个子网络,并打印网络参数信息 conv_net.build(input_shape=[4, 32, 32, 3]) fc_net.build(input_shape=[4, 512]) conv_net.summary() fc_net.summary() # %% # 列表合并,合并2个子网络的参数 variables = conv_net.trainable_variables + fc_net.trainable_variables # 对所有参数求梯度 grads = tape.gradient(loss, variables) # 自动更新 optimizer.apply_gradients(zip(grads, variables)) # %% x = tf.random.normal([1,7,7,1]) # 模拟输入 # 空洞卷积,1个3x3的卷积核 layer = layers.Conv2D(1,kernel_size=3,strides=1,dilation_rate=2) out = layer(x) # 前向计算 out.shape # %% # 创建X矩阵 x = tf.range(25)+1 # Reshape为合法维度的张量 x = tf.reshape(x,[1,5,5,1]) x = tf.cast(x, tf.float32) # 创建固定内容的卷积核矩阵 w = tf.constant([[-1,2,-3.],[4,-5,6],[-7,8,-9]]) # 调整为合法维度的张量 w = tf.expand_dims(w,axis=2) w = tf.expand_dims(w,axis=3) # 进行普通卷积运算 out = tf.nn.conv2d(x,w,strides=2,padding='VALID') out #%% # 普通卷积的输出作为转置卷积的输入,进行转置卷积运算 xx = tf.nn.conv2d_transpose(out, w, strides=2, padding='VALID', output_shape=[1,5,5,1]) # %% x = tf.random.normal([1,6,6,1]) # 6x6的输入经过普通卷积 out = tf.nn.conv2d(x,w,strides=2,padding='VALID') out # %% # 恢复出6x6大小 xx = tf.nn.conv2d_transpose(out, w, strides=2, padding='VALID', output_shape=[1,6,6,1]) xx # %% # 创建转置卷积类 layer = layers.Conv2DTranspose(1,kernel_size=3,strides=2,padding='VALID') xx2 = layer(out) xx2 # %% class BasicBlock(layers.Layer): # 残差模块类 def __init__(self, filter_num, stride=1): super(BasicBlock, self).__init__() # f(x)包含了2个普通卷积层,创建卷积层1 self.conv1 = layers.Conv2D(filter_num, (3, 3), strides=stride, padding='same') self.bn1 = layers.BatchNormalization() self.relu = layers.Activation('relu') # 创建卷积层2 self.conv2 = layers.Conv2D(filter_num, (3, 3), strides=1, padding='same') self.bn2 = layers.BatchNormalization() if stride != 1: # 插入identity层 self.downsample = Sequential() self.downsample.add(layers.Conv2D(filter_num, (1, 1), strides=stride)) else: # 否则,直接连接 self.downsample = lambda x:x def call(self, inputs, training=None): # 前向传播函数 out = self.conv1(inputs) # 通过第一个卷积层 out = self.bn1(out) out = self.relu(out) out = self.conv2(out) # 通过第二个卷积层 out = self.bn2(out) # 输入通过identity()转换 identity = self.downsample(inputs) # f(x)+x运算 output = layers.add([out, identity]) # 再通过激活函数并返回 output = tf.nn.relu(output) return output