1. 视频学习心得及问题总结
1.1绪论
“人工智能”的概念诞生于1956年的达特茅斯会议。
2018年Yoshua Bengio、Geoffrey Hinton、Yann LeCun因在人工智能深度学习方面的贡献获得图灵奖。
人工智能的发展阶段:萌芽期、启动期、消沉期、突破期、发展期、高速发展期。
人工智能、机器学习以及深度学习三者之间的关系:
人工智能是一个领域,就是一个目标,我们希望机器人像人一样的去感知、去思考,机器学习的是来实现这样一个目标的,而深度学习是其中很小的一个点。
模型分类:
从数据标记角度分类为监督学习、无监督学习、半监督学习、强化学习;
从数据分布角度分类为参数模型、非参数模型;
从建模对象角度分类为判别模型、生成模型;
传统机器学习与深度学习:
前深度学习时代,首先花几天时间收集并标注图像,然后花几个月观察图像,设计一些特征,最后使用某种分类器进行分类;
深度学习时代,首先花几个星期收集并标注图像,然后挑几个深度模型,选几组模型超参数,最后让机器优化模型;
发展历程:
(1)感知器出现,认为感知器无所不能,但是实际上无法解决异或门问题;
(2)BP算法:Rumelhart和Hinton合作在Nature杂志上发表论文,第一次简洁地阐述了
BP算法,在神经网络里增加一个所谓的隐层,解决了XOR难题;
(3)CNN网络:Yann Lecun在1989年发表了论文,之后又进一步运用了一种叫做卷积神经网络的技术,最开始是运用于银行对数字的识别;
(4)Vladmir Vapnik提出了SVM,把神经网络推向寒冬;
(5)Hinton拿到资金后,将神经网络更名为深度学习;
(6)吴恩达2009年发表了论文,解决了速度问题,使用GPU运行速度和用传统双核CPU相比,最快时要快近70倍;
(7)李菲菲建立第一个超大型图像数据库供计算机视觉研究者使用;
(8)Hinton和两个研究生利用CNN+Dropout+Relu激励函数将ILSVRC的错误率降到了15.3%,是人工智能技术突破的一个转折点;
(9)Yoshua Bengio在2011年发表论文,提出了一种修正的relu激励函数,解决了传统激励函数在反向传播计算中的梯度消失问题;
(10)Schmidhuber和他的学生提出来长短期记忆的计算模型。
1.2深度学习概述
深度学习有六大不能:
(1)稳定性低;(2)可调试性差;(3)参数不透明;(4)机器偏见;(5)增量性差;(6)推理能力差;
激活函数:激活函数是用来加入非线性因素的,提高神经网络对模型的表达能力,解决线性模型所不能解决的问题。假设一个示例神经网络中仅包含线性卷积和全连接运算,那么该网络仅能够表达线性映射,即便增加网络的深度也依旧还是线性映射,难以有效建模实际环境中非线性分布的数据。
梯度:是一个向量,方向是最大方向导数的方向,模为方向导数的最大值。
深层神经网络的问题:梯度消失
对于激活函数,之前一直使用Sigmoid函数,其函数图像成一个S型,它会将正无穷到负无穷的数映射到0~1之间。当我们对Sigmoid函数求导时,会呈现一个驼峰状(很像高斯函数),从求导结果可以看出,Sigmoid导数的取值范围在0~0.25之间,而我们初始化的网络权值通常都小于1,因此,当层数增多时,小于0的值不断相乘,最后就导致梯度消失的情况出现。
受限玻尔兹曼机和自编码器:
自编码器:
2. 代码练习
2.1图像处理基本练习
!wget https://raw.githubusercontent.com/summitgao/ImageGallery/master/yeast_colony_array.jpg import matplotlib import numpy as np import matplotlib.pyplot as plt import skimage from skimage import data from skimage import io colony = io.imread('yeast_colony_array.jpg') print(type(colony)) print(colony.shape)
# Plot all channels of a real image plt.subplot(121) plt.imshow(colony[:,:,:]) plt.title('3-channel image') plt.axis('off') # Plot one channel only plt.subplot(122) plt.imshow(colony[:,:,0]) plt.title('1-channel image') plt.axis('off');
# Get the pixel value at row 10, column 10 on the 10th row and 20th column camera = data.camera() print(camera[10, 20]) # Set a region to black camera[30:100, 10:100] = 0 plt.imshow(camera, 'gray')
# Set the first ten lines to black camera = data.camera() camera[:10] = 0 plt.imshow(camera, 'gray')
# Set to "white" (255) pixels where mask is True camera = data.camera() mask = camera < 80 camera[mask] = 255 plt.imshow(camera, 'gray')
# Change the color for real images cat = data.chelsea() plt.imshow(cat)
# Set brighter pixels to red red_cat = cat.copy() reddish = cat[:, :, 0] > 160 red_cat[reddish] = [255, 0, 0] plt.imshow(red_cat)
# Change RGB color to BGR for openCV BGR_cat = cat[:, :, ::-1] plt.imshow(BGR_cat)
from skimage import img_as_float, img_as_ubyte float_cat = img_as_float(cat) uint_cat = img_as_ubyte(float_cat)
img = data.camera() plt.hist(img.ravel(), bins=256, histtype='step', color='black');
# Use colony image for segmentation colony = io.imread('yeast_colony_array.jpg') # Plot histogram img = skimage.color.rgb2gray(colony) plt.hist(img.ravel(), bins=256, histtype='step', color='black');
# Use thresholding plt.imshow(img>0.5)
from skimage.feature import canny from scipy import ndimage as ndi img_edges = canny(img) img_filled = ndi.binary_fill_holes(img_edges) # Plot plt.figure(figsize=(18, 12)) plt.subplot(121) plt.imshow(img_edges, 'gray') plt.subplot(122) plt.imshow(img_filled, 'gray')
# Load an example image img = data.camera() plt.imshow(img, 'gray')
from skimage import exposure # Contrast stretching p2, p98 = np.percentile(img, (2, 98)) img_rescale = exposure.rescale_intensity(img, in_range=(p2, p98)) plt.imshow(img_rescale, 'gray')
# Equalization img_eq = exposure.equalize_hist(img) plt.imshow(img_eq, 'gray')
# Adaptive Equalization img_adapteq = exposure.equalize_adapthist(img, clip_limit=0.03) plt.imshow(img_adapteq, 'gray')
# Display results def plot_img_and_hist(img, axes, bins=256): """Plot an image along with its histogram and cumulative histogram. """ img = img_as_float(img) ax_img, ax_hist = axes ax_cdf = ax_hist.twinx() # Display image ax_img.imshow(img, cmap=plt.cm.gray) ax_img.set_axis_off() ax_img.set_adjustable('box') # Display histogram ax_hist.hist(img.ravel(), bins=bins, histtype='step', color='black') ax_hist.ticklabel_format(axis='y', style='scientific', scilimits=(0, 0)) ax_hist.set_xlabel('Pixel intensity') ax_hist.set_xlim(0, 1) ax_hist.set_yticks([]) # Display cumulative distribution img_cdf, bins = exposure.cumulative_distribution(img, bins) ax_cdf.plot(bins, img_cdf, 'r') ax_cdf.set_yticks([]) return ax_img, ax_hist, ax_cdf fig = plt.figure(figsize=(16, 8)) axes = np.zeros((2, 4), dtype=np.object) axes[0, 0] = fig.add_subplot(2, 4, 1) for i in range(1, 4): axes[0, i] = fig.add_subplot(2, 4, 1+i, sharex=axes[0,0], sharey=axes[0,0]) for i in range(0, 4): axes[1, i] = fig.add_subplot(2, 4, 5+i) ax_img, ax_hist, ax_cdf = plot_img_and_hist(img, axes[:, 0]) ax_img.set_title('Low contrast image') y_min, y_max = ax_hist.get_ylim() ax_hist.set_ylabel('Number of pixels') ax_hist.set_yticks(np.linspace(0, y_max, 5)) ax_img, ax_hist, ax_cdf = plot_img_and_hist(img_rescale, axes[:, 1]) ax_img.set_title('Contrast stretching') ax_img, ax_hist, ax_cdf = plot_img_and_hist(img_eq, axes[:, 2]) ax_img.set_title('Histogram equalization') ax_img, ax_hist, ax_cdf = plot_img_and_hist(img_adapteq, axes[:, 3]) ax_img.set_title('Adaptive equalization') ax_cdf.set_ylabel('Fraction of total intensity') ax_cdf.set_yticks(np.linspace(0, 1, 5)) fig.tight_layout() plt.show()
2.2 pytorch基础练习
#一个数 import torch x = torch.tensor(125) print(x)
#一维数组 x = torch.tensor([1,2,3]) print(x) #二维数组 x = torch.ones(2,3) print(x) #任意维数组 x = torch.ones(3,3,3) print(x) #创建空张量 x = torch.empty(3,3) print(x) #创建一个随机初始化的张量 x = torch.rand(3,3) print(x) #创建一个全为0的张量,并将数据类型设为long x = torch.zeros(3,3,dtype=torch.long) print(x) #基于现有的tensor,创建一个新的tensor,使新的tensor可以继承原有tensor的属性 y = x.new_ones(3,3) print(y) #继承原来tensor的大小,重新定义了数据类型 z = torch.randn_like(x,dtype = torch.float) print(z)
tensor([1, 2, 3]) tensor([[1., 1., 1.], [1., 1., 1.]]) tensor([[[1., 1., 1.], [1., 1., 1.], [1., 1., 1.]], [[1., 1., 1.], [1., 1., 1.], [1., 1., 1.]], [[1., 1., 1.], [1., 1., 1.], [1., 1., 1.]]]) tensor([[1.6773e-35, 0.0000e+00, 3.3631e-44], [0.0000e+00, nan, 0.0000e+00], [1.1578e+27, 1.1362e+30, 7.1547e+22]]) tensor([[0.2663, 0.1039, 0.7578], [0.3250, 0.3323, 0.2042], [0.7675, 0.9358, 0.9857]]) tensor([[0, 0, 0], [0, 0, 0], [0, 0, 0]]) tensor([[1, 1, 1], [1, 1, 1], [1, 1, 1]]) tensor([[ 1.2492, 1.5812, 1.3829], [-0.9308, -0.6413, 0.7611], [-0.8240, -0.1809, -1.6046]])
#创建一个2x4的tensor,用Tensor创建出来的是浮点数,用tensor创建出来的是长整型 m = torch.tensor([[2,5,3,7],[4,2,1,9]]) print(m.size(0),m.size(1),m.size(),sep = '-') #返回m中元素的数量 print(m.numel()) #返回m中的元素,利用下标标记元素 print(m[0][2]) print(m[:,1]) print(m[0,:]) #点乘 v = torch.arange(1, 5) m @ v m[[0], :] @ v #加法 m + torch.rand(2, 4) #转置 print(m.t()) print(m.transpose(0,1)) #返回3到8之间等距的20个数 torch.linspace(3,8,20) #转换数据类型并显示 from matplotlib import pyplot as plt plt.hist(torch.randn(1000).numpy(),100);
2-4-torch.Size([2, 4]) 8 tensor(3) tensor([5, 2]) tensor([2, 5, 3, 7]) tensor([[2, 4], [5, 2], [3, 1], [7, 9]]) tensor([[2, 4], [5, 2], [3, 1], [7, 9]])
#数组拼接 a = torch.Tensor([[1,2,3,4]]) b = torch.Tensor([[5,6,7,8]]) print(torch.cat((a,b),0))#在0方向即在Y方向上拼接 print(torch.cat((a,b),1))#在1方向即在X方向上拼接
tensor([[1., 2., 3., 4.], [5., 6., 7., 8.]]) tensor([[1., 2., 3., 4., 5., 6., 7., 8.]])
2.3 螺旋数据分类
!wget https://raw.githubusercontent.com/Atcold/pytorch-Deep-Learning/master/res/plot_lib.py #数据初始化 import random import torch from torch import nn, optim import math from IPython import display from plot_lib import plot_data, plot_model, set_default # 因为colab是支持GPU的,torch 将在 GPU 上运行 device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") # 初始化随机数种子。神经网络的参数都是随机初始化的, # 不同的初始化参数往往会导致不同的结果,当得到比较好的结果时我们通常希望这个结果是可以复现的, # 因此,在pytorch中,通过设置随机数种子也可以达到这个目的 seed = 12345 random.seed(seed) torch.manual_seed(seed) N = 1000 # 每类样本的数量 D = 2 # 每个样本的特征维度 C = 3 # 样本的类别 H = 100 # 神经网络里隐层单元的数量 X = torch.zeros(N * C, D).to(device) Y = torch.zeros(N * C, dtype=torch.long).to(device) for c in range(C): index = 0 t = torch.linspace(0, 1, N) # 在[0,1]间均匀的取10000个数,赋给t # 下面的代码不用理解太多,总之是根据公式计算出三类样本(可以构成螺旋形) # torch.randn(N) 是得到 N 个均值为0,方差为 1 的一组随机数,注意要和 rand 区分开 inner_var = torch.linspace( (2*math.pi/C)*c, (2*math.pi/C)*(2+c), N) + torch.randn(N) * 0.2 # 每个样本的(x,y)坐标都保存在 X 里 # Y 里存储的是样本的类别,分别为 [0, 1, 2] for ix in range(N * c, N * (c + 1)): X[ix] = t[index] * torch.FloatTensor((math.sin(inner_var[index]), math.cos(inner_var[index]))) Y[ix] = c index += 1 plot_data(X, Y)
#创建线性模型 learning_rate = 1e-3 lambda_l2 = 1e-5 # nn 包用来创建线性模型 # 每一个线性模型都包含 weight 和 bias model = nn.Sequential( nn.Linear(D, H), nn.Linear(H, C) ) model.to(device) # 把模型放到GPU上 # nn 包含多种不同的损失函数,这里使用的是交叉熵(cross entropy loss)损失函数 criterion = torch.nn.CrossEntropyLoss() # 这里使用 optim 包进行随机梯度下降(stochastic gradient descent)优化 optimizer = torch.optim.SGD(model.parameters(), lr=learning_rate, weight_decay=lambda_l2) # 开始训练 for t in range(1000): # 把数据输入模型,得到预测结果 y_pred = model(X) # 计算损失和准确率 loss = criterion(y_pred, Y) score, predicted = torch.max(y_pred, 1) acc = (Y == predicted).sum().float() / len(Y) print('[EPOCH]: %i, [LOSS]: %.6f, [ACCURACY]: %.3f' % (t, loss.item(), acc)) display.clear_output(wait=True) # 反向传播前把梯度置 0 optimizer.zero_grad() # 反向传播优化 loss.backward() # 更新全部参数 optimizer.step() #效果图如下 # Plot trained model print(model) plot_model(X, Y, model)
####当尝试使用线性的决策边界来分隔螺旋的数据 - 只使用nn.linear()
模组,而不在之间加上非线性 - 我们只能达到 50% 的正确度。
#加入ReLU激活函数 learning_rate = 1e-3 lambda_l2 = 1e-5 # 这里可以看到,和上面模型不同的是,在两层之间加入了一个 ReLU 激活函数 model = nn.Sequential( nn.Linear(D, H), nn.ReLU(), nn.Linear(H, C) ) model.to(device) # 下面的代码和之前是完全一样的,这里不过多叙述 criterion = torch.nn.CrossEntropyLoss() optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate, weight_decay=lambda_l2) # built-in L2 # 训练模型,和之前的代码是完全一样的 for t in range(1000): y_pred = model(X) loss = criterion(y_pred, Y) score, predicted = torch.max(y_pred, 1) acc = ((Y == predicted).sum().float() / len(Y)) print("[EPOCH]: %i, [LOSS]: %.6f, [ACCURACY]: %.3f" % (t, loss.item(), acc)) display.clear_output(wait=True) # zero the gradients before running the backward pass. optimizer.zero_grad() # Backward pass to compute the gradient loss.backward() # Update params optimizer.step() #效果图如下 # Plot trained model print(model) plot_model(X, Y, model)
####当我们从线性模型换成在两个nn.linear()
模组再经过一个nn.ReLU()
的模型,正确度增加到了 95%。这是因为边界变成非线性的并且更好的顺应资料的螺旋,如下图所呈现的。
2.4 回归分析
以上表现了一个无法用线性回归完成,但可以用这个相同的网络解决的问题。左面使用了Relu函数,有图使用了tanh函数,前者是一个分段的线性函数,后者则是连续、平滑的回归。