nb.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358
  1. #%%
  2. import os
  3. os.environ['TF_CPP_MIN_LOG_LEVEL']='2'
  4. import tensorflow as tf
  5. from tensorflow import keras
  6. from tensorflow.keras import layers, optimizers, datasets, Sequential
  7. #%%
  8. x = tf.random.normal([2,5,5,3]) # 模拟输入,3通道,高宽为5
  9. # 需要根据[k,k,cin,cout]格式创建,4个卷积核
  10. w = tf.random.normal([3,3,3,4])
  11. # 步长为1, padding为0,
  12. out = tf.nn.conv2d(x,w,strides=1,padding=[[0,0],[0,0],[0,0],[0,0]])
  13. # %%
  14. x = tf.random.normal([2,5,5,3]) # 模拟输入,3通道,高宽为5
  15. # 需要根据[k,k,cin,cout]格式创建,4个卷积核
  16. w = tf.random.normal([3,3,3,4])
  17. # 步长为1, padding为1,
  18. out = tf.nn.conv2d(x,w,strides=1,padding=[[0,0],[1,1],[1,1],[0,0]])
  19. # %%
  20. x = tf.random.normal([2,5,5,3]) # 模拟输入,3通道,高宽为5
  21. w = tf.random.normal([3,3,3,4]) # 4个3x3大小的卷积核
  22. # 步长为,padding设置为输出、输入同大小
  23. # 需要注意的是, padding=same只有在strides=1时才是同大小
  24. out = tf.nn.conv2d(x,w,strides=1,padding='SAME')
  25. # %%
  26. x = tf.random.normal([2,5,5,3])
  27. w = tf.random.normal([3,3,3,4])
  28. # 高宽按3倍减少
  29. out = tf.nn.conv2d(x,w,strides=3,padding='SAME')
  30. print(out.shape)
  31. # %%
  32. # 根据[cout]格式创建偏置向量
  33. b = tf.zeros([4])
  34. # 在卷积输出上叠加偏置向量,它会自动broadcasting为[b,h',w',cout]
  35. out = out + b
  36. # %%
  37. # 创建卷积层类
  38. layer = layers.Conv2D(4,kernel_size=(3,4),strides=(2,1),padding='SAME')
  39. out = layer(x) # 前向计算
  40. out.shape
  41. # %%
  42. layer.kernel,layer.bias
  43. # 返回所有待优化张量列表
  44. layer.trainable_variables
  45. # %%
  46. from tensorflow.keras import Sequential
  47. network = Sequential([ # 网络容器
  48. layers.Conv2D(6,kernel_size=3,strides=1), # 第一个卷积层, 6个3x3卷积核
  49. layers.MaxPooling2D(pool_size=2,strides=2), # 高宽各减半的池化层
  50. layers.ReLU(), # 激活函数
  51. layers.Conv2D(16,kernel_size=3,strides=1), # 第二个卷积层, 16个3x3卷积核
  52. layers.MaxPooling2D(pool_size=2,strides=2), # 高宽各减半的池化层
  53. layers.ReLU(), # 激活函数
  54. layers.Flatten(), # 打平层,方便全连接层处理
  55. layers.Dense(120, activation='relu'), # 全连接层,120个节点
  56. layers.Dense(84, activation='relu'), # 全连接层,84节点
  57. layers.Dense(10) # 全连接层,10个节点
  58. ])
  59. # build一次网络模型,给输入X的形状,其中4为随意给的batchsz
  60. network.build(input_shape=(4, 28, 28, 1))
  61. # 统计网络信息
  62. network.summary()
  63. # %%
  64. # 导入误差计算,优化器模块
  65. from tensorflow.keras import losses, optimizers
  66. # 创建损失函数的类,在实际计算时直接调用类实例即可
  67. criteon = losses.CategoricalCrossentropy(from_logits=True)
  68. # %%
  69. # 构建梯度记录环境
  70. with tf.GradientTape() as tape:
  71. # 插入通道维度,=>[b,28,28,1]
  72. x = tf.expand_dims(x,axis=3)
  73. # 前向计算,获得10类别的预测分布,[b, 784] => [b, 10]
  74. out = network(x)
  75. # 真实标签one-hot编码,[b] => [b, 10]
  76. y_onehot = tf.one_hot(y, depth=10)
  77. # 计算交叉熵损失函数,标量
  78. loss = criteon(y_onehot, out)
  79. # 自动计算梯度
  80. grads = tape.gradient(loss, network.trainable_variables)
  81. # 自动更新参数
  82. optimizer.apply_gradients(zip(grads, network.trainable_variables))
  83. # %%
  84. # 记录预测正确的数量,总样本数量
  85. correct, total = 0,0
  86. for x,y in db_test: # 遍历所有训练集样本
  87. # 插入通道维度,=>[b,28,28,1]
  88. x = tf.expand_dims(x,axis=3)
  89. # 前向计算,获得10类别的预测分布,[b, 784] => [b, 10]
  90. out = network(x)
  91. # 真实的流程时先经过softmax,再argmax
  92. # 但是由于softmax不改变元素的大小相对关系,故省去
  93. pred = tf.argmax(out, axis=-1)
  94. y = tf.cast(y, tf.int64)
  95. # 统计预测正确数量
  96. correct += float(tf.reduce_sum(tf.cast(tf.equal(pred, y),tf.float32)))
  97. # 统计预测样本总数
  98. total += x.shape[0]
  99. # 计算准确率
  100. print('test acc:', correct/total)
  101. # %%
  102. # 构造输入
  103. x=tf.random.normal([100,32,32,3])
  104. # 将其他维度合并,仅保留通道维度
  105. x=tf.reshape(x,[-1,3])
  106. # 计算其他维度的均值
  107. ub=tf.reduce_mean(x,axis=0)
  108. ub
  109. # %%
  110. # 创建BN层
  111. layer=layers.BatchNormalization()
  112. # %%
  113. network = Sequential([ # 网络容器
  114. layers.Conv2D(6,kernel_size=3,strides=1),
  115. # 插入BN层
  116. layers.BatchNormalization(),
  117. layers.MaxPooling2D(pool_size=2,strides=2),
  118. layers.ReLU(),
  119. layers.Conv2D(16,kernel_size=3,strides=1),
  120. # 插入BN层
  121. layers.BatchNormalization(),
  122. layers.MaxPooling2D(pool_size=2,strides=2),
  123. layers.ReLU(),
  124. layers.Flatten(),
  125. layers.Dense(120, activation='relu'),
  126. # 此处也可以插入BN层
  127. layers.Dense(84, activation='relu'),
  128. # 此处也可以插入BN层
  129. layers.Dense(10)
  130. ])
  131. # %%
  132. with tf.GradientTape() as tape:
  133. # 插入通道维度
  134. x = tf.expand_dims(x,axis=3)
  135. # 前向计算,设置计算模式,[b, 784] => [b, 10]
  136. out = network(x, training=True)
  137. # %%
  138. for x,y in db_test: # 遍历测试集
  139. # 插入通道维度
  140. x = tf.expand_dims(x,axis=3)
  141. # 前向计算,测试模式
  142. out = network(x, training=False)
  143. # %%
  144. def preprocess(x, y):
  145. # [0~1]
  146. x = 2*tf.cast(x, dtype=tf.float32) / 255.-1
  147. y = tf.cast(y, dtype=tf.int32)
  148. return x,y
  149. # 在线下载,加载CIFAR10数据集
  150. (x,y), (x_test, y_test) = datasets.cifar100.load_data()
  151. # 删除y的一个维度,[b,1] => [b]
  152. y = tf.squeeze(y, axis=1)
  153. y_test = tf.squeeze(y_test, axis=1)
  154. # 打印训练集和测试集的形状
  155. print(x.shape, y.shape, x_test.shape, y_test.shape)
  156. # 构建训练集对象
  157. train_db = tf.data.Dataset.from_tensor_slices((x,y))
  158. train_db = train_db.shuffle(1000).map(preprocess).batch(128)
  159. # 构建测试集对象
  160. test_db = tf.data.Dataset.from_tensor_slices((x_test,y_test))
  161. test_db = test_db.map(preprocess).batch(128)
  162. # 从训练集中采样一个Batch,观察
  163. sample = next(iter(train_db))
  164. print('sample:', sample[0].shape, sample[1].shape,
  165. tf.reduce_min(sample[0]), tf.reduce_max(sample[0]))
  166. # %%
  167. conv_layers = [ # 先创建包含多层的列表
  168. # Conv-Conv-Pooling单元1
  169. # 64个3x3卷积核, 输入输出同大小
  170. layers.Conv2D(64, kernel_size=[3, 3], padding="same", activation=tf.nn.relu),
  171. layers.Conv2D(64, kernel_size=[3, 3], padding="same", activation=tf.nn.relu),
  172. # 高宽减半
  173. layers.MaxPool2D(pool_size=[2, 2], strides=2, padding='same'),
  174. # Conv-Conv-Pooling单元2,输出通道提升至128,高宽大小减半
  175. layers.Conv2D(128, kernel_size=[3, 3], padding="same", activation=tf.nn.relu),
  176. layers.Conv2D(128, kernel_size=[3, 3], padding="same", activation=tf.nn.relu),
  177. layers.MaxPool2D(pool_size=[2, 2], strides=2, padding='same'),
  178. # Conv-Conv-Pooling单元3,输出通道提升至256,高宽大小减半
  179. layers.Conv2D(256, kernel_size=[3, 3], padding="same", activation=tf.nn.relu),
  180. layers.Conv2D(256, kernel_size=[3, 3], padding="same", activation=tf.nn.relu),
  181. layers.MaxPool2D(pool_size=[2, 2], strides=2, padding='same'),
  182. # Conv-Conv-Pooling单元4,输出通道提升至512,高宽大小减半
  183. layers.Conv2D(512, kernel_size=[3, 3], padding="same", activation=tf.nn.relu),
  184. layers.Conv2D(512, kernel_size=[3, 3], padding="same", activation=tf.nn.relu),
  185. layers.MaxPool2D(pool_size=[2, 2], strides=2, padding='same'),
  186. # Conv-Conv-Pooling单元5,输出通道提升至512,高宽大小减半
  187. layers.Conv2D(512, kernel_size=[3, 3], padding="same", activation=tf.nn.relu),
  188. layers.Conv2D(512, kernel_size=[3, 3], padding="same", activation=tf.nn.relu),
  189. layers.MaxPool2D(pool_size=[2, 2], strides=2, padding='same')
  190. ]
  191. # 利用前面创建的层列表构建网络容器
  192. conv_net = Sequential(conv_layers)
  193. # %%
  194. # 创建3层全连接层子网络
  195. fc_net = Sequential([
  196. layers.Dense(256, activation=tf.nn.relu),
  197. layers.Dense(128, activation=tf.nn.relu),
  198. layers.Dense(100, activation=None),
  199. ])
  200. # %%
  201. # build2个子网络,并打印网络参数信息
  202. conv_net.build(input_shape=[4, 32, 32, 3])
  203. fc_net.build(input_shape=[4, 512])
  204. conv_net.summary()
  205. fc_net.summary()
  206. # %%
  207. # 列表合并,合并2个子网络的参数
  208. variables = conv_net.trainable_variables + fc_net.trainable_variables
  209. # 对所有参数求梯度
  210. grads = tape.gradient(loss, variables)
  211. # 自动更新
  212. optimizer.apply_gradients(zip(grads, variables))
  213. # %%
  214. x = tf.random.normal([1,7,7,1]) # 模拟输入
  215. # 空洞卷积,1个3x3的卷积核
  216. layer = layers.Conv2D(1,kernel_size=3,strides=1,dilation_rate=2)
  217. out = layer(x) # 前向计算
  218. out.shape
  219. # %%
  220. # 创建X矩阵
  221. x = tf.range(25)+1
  222. # Reshape为合法维度的张量
  223. x = tf.reshape(x,[1,5,5,1])
  224. x = tf.cast(x, tf.float32)
  225. # 创建固定内容的卷积核矩阵
  226. w = tf.constant([[-1,2,-3.],[4,-5,6],[-7,8,-9]])
  227. # 调整为合法维度的张量
  228. w = tf.expand_dims(w,axis=2)
  229. w = tf.expand_dims(w,axis=3)
  230. # 进行普通卷积运算
  231. out = tf.nn.conv2d(x,w,strides=2,padding='VALID')
  232. out
  233. #%%
  234. # 普通卷积的输出作为转置卷积的输入,进行转置卷积运算
  235. xx = tf.nn.conv2d_transpose(out, w, strides=2,
  236. padding='VALID',
  237. output_shape=[1,5,5,1])
  238. <tf.Tensor: id=117, shape=(5, 5), dtype=float32, numpy=
  239. array([[ 67., -134., 278., -154., 231.],
  240. [ -268., 335., -710., 385., -462.],
  241. [ 586., -770., 1620., -870., 1074.],
  242. [ -468., 585., -1210., 635., -762.],
  243. [ 819., -936., 1942., -1016., 1143.]], dtype=float32)>
  244. # %%
  245. x = tf.random.normal([1,6,6,1])
  246. # 6x6的输入经过普通卷积
  247. out = tf.nn.conv2d(x,w,strides=2,padding='VALID')
  248. out
  249. <tf.Tensor: id=21, shape=(1, 2, 2, 1), dtype=float32, numpy=
  250. array([[[[ 20.438847 ],
  251. [ 19.160788 ]],
  252. [[ 0.8098897],
  253. [-28.30303 ]]]], dtype=float32)>
  254. # %%
  255. # 恢复出6x6大小
  256. xx = tf.nn.conv2d_transpose(out, w, strides=2,
  257. padding='VALID',
  258. output_shape=[1,6,6,1])
  259. xx
  260. # %%
  261. # 创建转置卷积类
  262. layer = layers.Conv2DTranspose(1,kernel_size=3,strides=2,padding='VALID')
  263. xx2 = layer(out)
  264. xx2
  265. # %%
  266. class BasicBlock(layers.Layer):
  267. # 残差模块类
  268. def __init__(self, filter_num, stride=1):
  269. super(BasicBlock, self).__init__()
  270. # f(x)包含了2个普通卷积层,创建卷积层1
  271. self.conv1 = layers.Conv2D(filter_num, (3, 3), strides=stride, padding='same')
  272. self.bn1 = layers.BatchNormalization()
  273. self.relu = layers.Activation('relu')
  274. # 创建卷积层2
  275. self.conv2 = layers.Conv2D(filter_num, (3, 3), strides=1, padding='same')
  276. self.bn2 = layers.BatchNormalization()
  277. if stride != 1: # 插入identity层
  278. self.downsample = Sequential()
  279. self.downsample.add(layers.Conv2D(filter_num, (1, 1), strides=stride))
  280. else: # 否则,直接连接
  281. self.downsample = lambda x:x
  282. def call(self, inputs, training=None):
  283. # 前向传播函数
  284. out = self.conv1(inputs) # 通过第一个卷积层
  285. out = self.bn1(out)
  286. out = self.relu(out)
  287. out = self.conv2(out) # 通过第二个卷积层
  288. out = self.bn2(out)
  289. # 输入通过identity()转换
  290. identity = self.downsample(inputs)
  291. # f(x)+x运算
  292. output = layers.add([out, identity])
  293. # 再通过激活函数并返回
  294. output = tf.nn.relu(output)
  295. return output