小结:
这次实验课给我的感受还是很深的,对于很多张量的操作,还有对于图像通道的深层应用都不熟悉。并且通过亲自编写函数,实现了很多函数功能,对于这些函数体会更加深刻
对于神经元模型的编写,本次实验的内容是需要通过交叉熵损失函数构建一个对率回归模型。但是需要注意的是torch里的交叉熵损失函数内封装了softmax + log + NLLLoss三个函数,因此这里单独手写交叉熵损失函数。
深度学习实验一:PyTorch Tensor
本次实验中,练习PyTorch Tensor的操作。请按以下要求完成编程:
name = 'yyh'#填写你的姓名
sid = 'B02014152'#填写你的学号
print('姓名:%s, 学号:%s'%(name, sid))
import torch
import numpy as np
import matplotlib.pyplot as plt
1. 创建和操作Tensor
在这一部分,你将要用tensor创建张量,并对张量做一些处理。
请按照以下要求编写代码:
#创建一个shape=(5,10)的随机张量,张量的元素满足标准高斯分布
X = torch.randn((5,10))
print(X)
#在下面输出X的形状、维度
######B02014152杨宇海######
print("X的形状", X.shape)
print("X的第一维维度", X.shape[0])
print("X的第二维维度", X.shape[1])
假设 X X X的每一列表示一个特征向量 X ( i ) X^{(i)} X(i),请在下面对X做标准化处理,即:
X j ( i ) = X j ( i ) − μ j σ j + ε X_{j}^{(i)}=\frac{X_{j}^{(i)}-\mu_{j}}{\sigma_{j} + \varepsilon} Xj(i)=σj+εXj(i)−μj
其中, μ \mu μ是样本均值向量, σ \sigma σ是样本的标准差向量, ε \varepsilon ε是一个很小的正数,可以取为 1 e − 7 1e-7 1e−7。
#请在下面编写代码将X做标准化,得到张量Y
###B02014152杨宇海###
import math
def standardization(X):
# 将二维张量,按列为样本,对样本进行归一化
row = X.shape[0]
col = X.shape[1]
# 计算mu
u = torch.zeros((row,1))
for i in range(row):
for j in range(col):
u[i, 0] += X[i, j]
u /= col
# 计算sigma
sigma = torch.zeros((row,1))
for i in range(row):
for j in range(col):
sigma[i,0] += (X[i, j] - u[i, 0])**2 # (xi-xu)^2
sigma[i,0] = math.sqrt(sigma[i,0]/col) # sqrt(x/n)
sigma += 1e-7
# print(u)
# print(sigma)
return (X-u)/sigma
Y = standardization(X)
print(Y)
#在下面编写代码输出Y的均值和每个维度的最大、最小值
###B02014152杨宇海###
miu = torch.mean(Y, dim=1, keepdim=True)#计算Y的行均值,请用一行代码实现
# print(miu)
maxV = torch.max(Y, dim=1, keepdim=True)#计算Y的行最大值,请用一行代码实现
# print(maxV[0])
minV = torch.max(Y, dim=1, keepdim=True)#计算Y的行最小值,请用一行代码实现
# print(minV[0])
#下面的代码构造了一个3维张量a
a = torch.tensor([[[1,2,3],[4,5,6]],[[-3,-4,-5],[-6,-7,-8]],[[7,8,9],[10,11,12]]])
print(a)
#请在下面编写代码,对a进行操作,得到如下的张量:
'''tensor([[[ 1, -3, 7],
[ 4, -6, 10]],
[[ 2, -4, 8],
[ 5, -7, 11]],
[[ 3, -5, 9],
[ 6, -8, 12]]])'''
b = a.permute(2,1,0)#请用一行代码实现
print(b)
#下面的代码读入一张彩色图像
import cv2 as cv
im = cv.imread('car0.jpg')
print(im.shape)
#opencv读入的图像是一个numpy ndarray
type(im)
#显示彩色图像,注意显示的颜色是错误的,
#原因是opencv读入的图像三个颜色通道是B,G,R,不是R,G,B。而matplotlib绘制图像的时候,当作R,G,B绘制。
plt.figure(figsize = (10,6))
plt.imshow(im)
plt.axis('off')
plt.show()
#下面的代码把im在第2个维度上翻转,把BGR变换为RGB,结果可以正常显示
im1 = np.flip(im,axis = 2)
plt.figure(figsize = (10,6))
plt.imshow(im1)
plt.axis('off')
plt.show()
#在下面编写代码,把im转换为一个张量
im_tensor = torch.from_numpy(im)#请用一行代码实现
im_tensor.shape
im2 = im_tensor.numpy()
plt.imshow(im2)
plt.axis('off')
plt.show()
#在下面用张量操作,把三个通道的顺序从BGR转换为RGB
im_t1 = torch.flip(im_tensor[:,:], [2])#请用一行代码实现,提示:torch.flip
# [2]代表将第二维的BGR 倒转为 RGB
im_t1.shape
plt.imshow(im_t1)
im3 = im_t1.numpy()
plt.imshow(im3)
plt.axis('off')
plt.show()
#请在下面编写代码,从im_t1中分离出三个通道:
R,G,B = torch.split(im_t1, [1,1,1],dim=2)#请用一行代码实现,提示torch.dsplit(这里由于torch版本没有dsplit,改为使用split)
print(R.shape)
#请在下面编写代码,把R,G,B三个张量水平拼成一个张量
RGB = torch.hstack((R,G,B))#请用一行代码实现,提示torch.hstack
print(RGB.shape)
plt.figure(figsize=(18,3))
plt.imshow(RGB,cmap = 'gray')
plt.axis('off')
plt.show()
#在下面编写代码将im_t1中的彩色图像转换为灰度图
#转换公式为:GRAY = 0.3*r+0.59*G+0.11*B
#请使用广播实现
weights = torch.ones((600, 1200, 3))#构造一个权值张量,表示R,G,B通道的权重
weights[:,:,0] = 0.3
weights[:,:,1] = 0.59
weights[:,:,2] = 0.11
temp = im_t1 * weights
gray = temp[:,:,0]+temp[:,:,1]+temp[:,:,2]#用权值张量把im_t1转换为灰度图,可能需要多行代码实现
# gray = gray.unsqueeze(2)
gray.shape
plt.imshow(gray)
plt.imshow(gray.numpy(),cmap = 'gray')
plt.axis('off')
plt.show()
#im_t1的数据元素类型是unit8
im_t1.dtype # torch.Size([600, 1200, 3])
#请把im_t1的数据类型转换为torch.float32,并归一化到[0,1]区间
im_t2 = (im_t1.to(torch.float32) - im_t1.to(torch.float32).min())/(im_t1.to(torch.float32).max()-im_t1.to(torch.float32).min())#请用一行代码实现,提示Tensor.to
print(im_t2[0,0,0])
#向im_t2中添加随机高斯噪声
#噪声均值为0,标准差为std
std = 0.02
import random
im_t3 = im_t2 + random.gauss(0, std)#请用一行代码是新啊
print(im_t3[0,0,0])
print(im_t3.max())
#把im_t3的值截取到[0,1]区间
im_t3 = torch.clamp(im_t3, 0, 1)#请用一行代码实现,提示torch.clamp
# print(im_t3.max())
plt.imshow(im_t3.numpy())
plt.axis('off')
plt.show()
2. 用Tensor编写神经元模型
一个神经元表示以下函数: h ( x ) = f ( W T x + b ) h(x)=f(W^{T}x+b) h(x)=f(WTx+b).其中 f f f是非线性响应函数。
请用Tensor编写一个对率回归模型,并用梯度下降法训练该模型。
#定义sigmoid函数:
def sigmoid(z):
rho = 1/(1+torch.exp(-z))#请用一行代码实现,提示torch.exp
return rho
t = torch.tensor([-5,-1,0,10],dtype = torch.float32)
print(sigmoid(t))
#定义一个表示logistic regression的函数:
def logReg(X,W,b):
#计算净响应
z = W.permute(1,0)@X+b#请用一行代码实现,提示@
rho = sigmoid(z)
# for i in range(len(rho[0])):
# if rho[0][i]>=0.5:
# rho[0][i] = 1
# else:
# rho[0][i] = 0
return rho
W = torch.zeros((2,1))
b = 0
X = torch.randn((2,10))
print(logReg(X,W,b))
# 生成随机样本:
X0 = torch.randn((2,100))*0.7 + torch.ones((2,1),dtype = torch.float32)
X1 = torch.randn((2,100))*0.7 - torch.ones((2,1),dtype = torch.float32)
X = torch.hstack((X0,X1))
Y = torch.hstack((torch.zeros((1,100)), torch.ones((1,100))))
x0 = X0.numpy()
x1 = X1.numpy()
plt.plot(x0[0],x0[1],'bo')
plt.plot(x1[0],x1[1],'r*')
plt.axis('equal')
plt.show()
#在下面编写函数,训练一个对率回归模型
def trainLogReg(X,Y):
#初始化W,b:
W = torch.zeros((X.shape[0],1))
b = 0
#学习速率:
alpha = 0.5
epsilon = 1e-5
#初始损失
loss0 = np.inf
iter = 1
while(True):
#计算预测值rho
rho = logReg(X,W,Y)#请用一行代码实现
#在下面计算log-loss
print(rho.size(), Y.size())
loss = (-torch.log(rho[Y==1]).sum()-torch.log(1-rho[Y==0]).sum())/Y.shape[1]
# print((-torch.log(rho*Y).sum()-torch.log(1+rho*(Y-1)).sum())/Y.shape[1])
loss = loss.item()
# print(loss)
print('iter = %d, loss = %.5f'%(iter, loss))
iter = iter + 1
if(np.abs(loss - loss0)<epsilon):
break
loss0 = loss
#计算误差err
err = rho-Y#请用一行代码实现
#计算梯度:
dW = ((err*X).sum(axis=1)/Y.shape[1]).unsqueeze(1)#请用一行代码实现
db = err.sum()/Y.shape[1]#请用一行代码实现
# print(dW)
#梯度下降
# print(W)
W = W - alpha * dW
# print(W)
# print(b)
b = b - alpha * db
# print(b)
return W,b
W,b = trainLogReg(X,Y)
print('W = ', W)
print('b = ', b)
#绘制分界面:
W0 = W.numpy()
b0 = b.item()
maxx = torch.max(X,dim = 1).values[0].item()
minx = torch.min(X,dim = 1).values[0].item()
print(maxx)
print(minx)
x = np.array([minx,maxx])
y = -(W0[0] * x + b0) / W0[1]
x0 = X0.numpy()
x1 = X1.numpy()
plt.plot(x0[0],x0[1],'bo')
plt.plot(x1[0],x1[1],'r*')
plt.plot(x,y,'k-')
plt.axis('equal')
plt.show()