1 В избранное 0 Ответвления 0

OSCHINA-MIRROR/Python_Ai_Road-eat_tensorflow2_in_30_days

Присоединиться к Gitlife
Откройте для себя и примите участие в публичных проектах с открытым исходным кодом с участием более 10 миллионов разработчиков. Приватные репозитории также полностью бесплатны :)
Присоединиться бесплатно
Клонировать/Скачать
Chapter4-1.md 20 КБ
Копировать Редактировать Web IDE Исходные данные Просмотреть построчно История
gitlife-traslator Отправлено 03.12.2024 15:14 374a95e

4-1 Структурные операции над тензорами

Операция над тензором включает структурную операцию и математическую операцию.

Структурная операция включает создание тензора, нарезку индексов, преобразование размерности, объединение и разделение.

Математическая операция включает скалярную операцию, векторную операцию и матричную операцию. Мы также представим широковещательный механизм работы с тензорами.

Этот раздел посвящён структурным операциям над тензорами.

1. Создание тензоров

Создание тензора аналогично созданию массива в numpy.

import tensorflow as tf
import numpy as np 
a = tf.constant([1,2,3],dtype = tf.float32)
tf.print(a)
[1 2 3]
b = tf.range(1,10,delta = 2)
tf.print(b)
[1 3 5 7 9]
c = tf.linspace(0.0,2*3.14,100)
tf.print(c)
[0 0.0634343475 0.126868695 ... 6.15313148 6.21656609 6.28]
d = tf.zeros([3,3])
tf.print(d)
[[0 0 0]
 [0 0 0]
 [0 0 0]]
a = tf.ones([3,3])
b = tf.zeros_like(a,dtype= tf.float32)
tf.print(a)
tf.print(b)
[[1 1 1]
 [1 1 1]
 [1 1 1]]
[[0 0 0]
 [0 0 0]
 [0 0 0]]
b = tf.fill([3,2],5)
tf.print(b)
[[5 5]
 [5 5]
 [5 5]]
# Случайные числа с равномерным распределением
tf.random.set_seed(1.0)
a = tf.random.uniform([5],minval=0,maxval=10)
tf.print(a)
[1.65130854 9.01481247 6.30974197 4.34546089 2.9193902]
# Случайные числа с нормальным распределением
b = tf.random.normal([3,3],mean=0.0,stddev=1.0)
tf.print(b)
[[0.403087884 -1.0880208 -0.0630953535]
 [1.33655667 0.711760104 -0.489286453]
 [-0.764221311 -1.03724861 -1.25193381]]
# Случайные числа с нормальным распределением и усечением в пределах диапазона двух стандартных отклонений
c = tf.random.truncated_normal((5,5), mean=0.0, stddev=1.0, dtype=tf.float32)
tf.print(c)
[[-0.457012236 -0.406867266 0.728577733 -0.892977774 -0.369404584]
 [0.323488563 1.19383323 0.888299048 1.25985599 -1.95951891]
 [-0.202244401 0.294496894 -0.468728036 1.29494202 1.48142183]
 [0.0810953453 1.63843894 0.556645 0.977199793 -1.17777884]
 [1.67368948 0.0647980496 -0.705142677 -0.281972528 0.126546144]]
# Специальная матрица
I = tf.eye(3,3) # Единичная матрица
tf.print(I)
tf.print(" ")
t = tf.linalg.diag([1,2,3]) # Диагональная матрица
tf.print(t)
[[1 0 0]
 [0 1 0]
 [0 0 1]]
 
[[1 0 0]
 [0 2 0]
 [0 0 3]]

2. Индексирование и нарезка

Индексирование и нарезка тензоров аналогичны numpy, и нарезка поддерживает параметры по умолчанию и многоточие.

Тип данных tf.Variable поддерживает индексирование и нарезку для изменения значений определённых элементов.

Для ссылки на непрерывную часть тензора рекомендуется использовать tf.slice.

С другой стороны, для нерегулярной формы нарезки рекомендуется использовать tf.gather, tf.gather_nd и tf.boolean_mask.

Метод tf.boolean_mask является мощным, он работает как tf.gather и tf.gather_nd, и поддерживает булево индексирование.

Чтобы создать новый тензор путём изменения определённых элементов в существующем тензоре, можно использовать tf.where и tf.scatter_nd.

tf.random.set_seed(3)
t = tf.random.uniform([5,5],minval=0,maxval=10,dtype=tf.int32)
tf.print(t)
[[4 7 4 2 9]
 [9 1 2 4 7]
 [7 2 7 4 0]
 [9 6 9 7 2]
 [3 7 0 0 3]]
# Строка 0
tf.print(t[0])
[4 7 4 2 9]
# Последняя строка
tf.print(t[-1])
[3 7 0 0 3]
# Строка 1 Столбец 3
tf.print(t[1,3])
tf.print(t[1][3])
4
4
# От строки 1 до строки 3
tf.print(t[1:4,:])
tf.print(tf.slice(t,[1,0],[3,5])) #tf.slice(input,begin_vector,size_vector)
[[9 1 2 4 7]
 [7 2 7 4 0]
 [9 6 9 7 2]]
[[9 1 2 4 7]
 [7 2 7 4 0]
 [9 6 9 7 2]]
# От строки 1 до последней строки и от столбца 0 до предпоследнего с шагом 2
tf.print(t[1:4,:4:2])
[[9 2]
 [7 7]
 [9 9]]
# Variable поддерживает изменение элементов через индексирование и нарезку
x = tf.Variable([[1,2],[3,4]],dtype = tf.float32)
x[1,:].assign(tf.constant([0.0,0.0]))
tf.print(x)
[[1 2] ```
a = tf.random.uniform([3, 3, 3], minval=0, maxval=10, dtype=tf.int32)
tf.print(a)
[[[7 3 9]
  [9 0 7]
  [9 6 7]]

 [[1 3 3]
  [0 8 1]
  [3 1 0]]

 [[4 0 6]
  [6 2 2]
  [7 9 5]]]
# Ellipsis represents multiple colons
tf.print(a[..., 1])
# This is equal to
tf.print(a[:, :, 1])
[[3 0 6]
 [3 8 1]
 [0 2 9]]
[[3 0 6]
 [3 8 1]
 [0 2 9]]

The examples above are regular slicing; for irregular slicing, tf.gather, tf.gather_nd, tf.boolean_mask can be used.

Вот пример записей оценок учащихся. Есть 4 класса, по 10 учеников в каждом классе и по 7 курсов для каждого ученика, что может быть представлено в виде тензора с размерностью 4×10×7.

scores = tf.random.uniform((4, 10, 7), minval=0, maxval=100, dtype=tf.int32)
tf.print(scores)
[[[52 82 66 ... 17 86 14]
  [8 36 94 ... 13 78 41]
  [77 53 51 ... 22 91 56]
  ...
  [11 19 26 ... 89 86 68]
  [60 72 0 ... 11 26 15]
  [24 99 38 ... 97 44 74]]

 [[79 73 73 ... 35 3 81]
  [83 36 31 ... 75 38 85]
  [54 26 67 ... 60 68 98]
  ...
  [20 5 18 ... 32 45 3]
  [72 52 81 ... 88 41 20]
  [0 21 89 ... 53 10 90]]

 [[52 80 22 ... 29 25 60]
  [78 71 54 ... 43 98 81]
  [21 66 53 ... 97 75 77]
  ...
  [6 74 3 ... 53 65 43]
  [98 36 72 ... 33 36 81]
  [61 78 70 ... 7 59 21]]

 [[56 57 45 ... 23 15 3]
  [35 8 82 ... 11 59 97]
  [44 6 99 ... 81 60 27]
  ...
  [76 26 35 ... 51 8 17]
  [33 52 53 ... 78 37 31]
  [71 27 44 ... 0 52 16]]]
# Extract all the grades of the 0th, 5th and 9th students in each class.
p = tf.gather(scores, [0, 5, 9], axis=1)
tf.print(p)
[[[52 82 66 ... 17 86 14]
  [24 80 70 ... 72 63 96]
  [24 99 38 ... 97 44 74]]

 [[79 73 73 ... 35 3 81]
  [46 10 94 ... 23 18 92]
  [0 21 89 ... 53 10 90]]

 [[52 80 22 ... 29 25 60]
  [19 12 23 ... 87 86 25]
  [61 78 70 ... 7 59 21]]

 [[56 57 45 ... 23 15 3]
  [6 41 79 ... 97 43 13]
  [71 27 44 ... 0 52 16]]]
# Extract the grades of the 1st, 3rd and 6th courses of the 0th, 5th and 9th students in each class.
q = tf.gather(tf.gather(scores, [0, 5, 9], axis=1), [1, 3, 6], axis=2)
tf.print(q)
[[[82 55 14]
  [80 46 96]
  [99 58 74]]

 [[73 48 81]
  [10 38 92]
  [21 86 90]]

 [[80 57 60]
  [12 34 25]
  [78 71 21]]

 [[57 75 3]
  [41 47 13]
  [27 96 16]]]
# Extract all the grades of the 0th student in the 0th class, the 4th student in the 2nd class, and the 6th student in the 3rd class.
# Then length of the parameter indices equals to the number of samples, and the each element of indices is the coordinate of each sample.
s = tf.gather_nd(scores, indices = [(0, 0), (2, 4), (3, 6)])
s
<tf.Tensor: shape=(3, 7), dtype=int32, numpy=
array([[52, 82, 66, 55, 17, 86, 14],
       [99, 94, 46, 70,  1, 63, 41],
       [46, 83, 70, 80, 90, 85, 17]], dtype=int32)>

Функция tf.gather и tf.gather_nd, как показано выше, может быть достигнута с помощью tf.boolean_mask.

# Extract all the grades of the 0th, 5th and 9th students in each class.
p = tf.boolean_mask(scores, [True, False, False, False, False,
                             True, False, False, False, True], axis=1)
tf.print(p)
[[[52 82 66 ... 17 86 14]
  [24 80 70 ... 72 63 96]
  [24 99 38 ... 97 44 74]]

 [[79 73 73 ... 35 3 81]
  [46 10 94 ... 23 18 92]
  [0 21 89 ... 53 10 90]]

 [[52 80 22 ... 29 25 60]
  [19 12 23 ... 87 86 25]
  [61 78 70 ... 7 59 21]]

 [[56 57 45 ... 23 15 3]
  [6 41 79 ... 97 43 13]
  [71 27 44 ... 0 52 16]]]
# Extract all the grades of the 0th student in the 0th class, the 4th student in the 2nd class, and the 6th student in the 3rd class.
s = tf.boolean_mask(scores,
    [[True, False, False, False, False, False, False, False, False, False],
     [False, False, False, False, False, False, False, False, False, False],
     [False, False, False, False, True, False, False, False, False, False],
     [False, False, False, False, False, False, True, False, False, False]])
tf.print(s)
[[52 82 66 ... 17 86 14]
 [99 94 46 ... 1 63 41]
 [46 83 70 ... 90 85 17]]
# Boolean indexing using tf.boolean_mask

# Find all elements that are less than
``` ```
0 in the matrix
c = tf.constant([[-1,1,-1],[2,2,-2],[3,-3,3]],dtype=tf.float32)
tf.print(c,"\n")

tf.print(tf.boolean_mask(c,c<0),"\n") 
tf.print(c[c<0]) # This is the syntactic sugar of boolean_mask for boolean indexing.
[[-1 1 -1]
 [2 2 -2]
 [3 -3 3]] 

[-1 -1 -2 -3] 

[-1 -1 -2 -3]

Методы, показанные выше, способны извлечь часть элементов в тензоре, но не могут создавать новые тензоры путём модификации этих элементов. Для этой цели следует использовать методы tf.where и tf.scatter_nd.

tf.where — это тензорная версия оператора if, с другой стороны, этот метод способен найти координаты всех элементов, которые удовлетворяют определённым условиям.

tf.scatter_nd работает противоположным образом по сравнению с методом tf.gather_nd. Последний собирает элементы в соответствии с заданной координатой, в то время как первый вставляет значения в заданные позиции в обнулённый тензор известной формы.

# Найти элементы, которые меньше 0, создать новый тензор, заменив эти элементы на np.nan.
# tf.where аналогичен np.where, который является «if» для тензоров

c = tf.constant([[-1,1,-1],[2,2,-2],[3,-3,3]],dtype=tf.float32)
d = tf.where(c<0,tf.fill(c.shape,np.nan),c) 
d
<tf.Tensor: shape=(3, 3), dtype=float32, numpy=
array([[nan,  1., nan],
       [ 2.,  2., nan],
       [ 3., nan,  3.]], dtype=float32)>
# Метод where возвращает все координаты, удовлетворяющие условию, если есть только один аргумент
indices = tf.where(c<0)
indices
<tf.Tensor: shape=(4, 2), dtype=int64, numpy=
array([[0, 0],
       [0, 2],
       [1, 2],
       [2, 1]])>
# Создать новый тензор, заменив значение двух элементов тензора, расположенных в [0,0] [2,1], на 0.
d = c - tf.scatter_nd([[0,0],[2,1]],[c[0,0],c[2,1]],c.shape)
d
<tf.Tensor: shape=(3, 3), dtype=float32, numpy=
array([[ 0.,  1., -1.],
       [ 2.,  2., -2.],
       [ 3.,  0.,  3.]], dtype=float32)>
# Метод scatter_nd работает обратно gather_nd
# Этот метод можно использовать для вставки значений в заданные позиции в полностью обнулённый тензор известной формы.
indices = tf.where(c<0)
tf.scatter_nd(indices,tf.gather_nd(c,indices),c.shape)
<tf.Tensor: shape=(3, 3), dtype=float32, numpy=
array([[-1.,  0., -1.],
       [ 0.,  0., -2.],
       [ 0., -3.,  0.]], dtype=float32)>

3. Преобразование размерности

Функции, связанные с преобразованием размерности, включают tf.reshape, tf.squeeze, tf.expand_dims, tf.transpose.

tf.reshape используется для изменения формы тензора.

tf.squeeze используется для уменьшения количества измерений.

tf.expand_dims используется для увеличения количества измерений.

tf.transpose используется для обмена порядком измерений.

Функция tf.reshape изменяет форму тензора, но не меняет порядок элементов, хранящихся в памяти, поэтому эта операция выполняется очень быстро и обратимо.

a = tf.random.uniform(shape=[1,3,3,2],
                      minval=0,maxval=255,dtype=tf.int32)
tf.print(a.shape)
tf.print(a)
TensorShape([1, 3, 3, 2])
[[[[135 178]
   [26 116]
   [29 224]]

  [[179 219]
   [153 209]
   [111 215]]

  [[39 7]
   [138 129]
   [59 205]]]]
# Изменить форму на (3,6)
b = tf.reshape(a,[3,6])
tf.print(b.shape)
tf.print(b)
TensorShape([3, 6])
[[135 178 26 116 29 224]
 [179 219 153 209 111 215]
 [39 7 138 129 59 205]]
# Вернуть форму к (1,3,3,2)
c = tf.reshape(b,[1,3,3,2])
tf.print(c)
[[[[135 178]
   [26 116]
   [29 224]]

  [[179 219]
   [153 209]
   [111 215]]

  [[39 7]
   [138 129]
   [59 205]]]]

Когда в определённом измерении имеется только один элемент, функция tf.squeeze удаляет это измерение. Она не изменит порядок хранимых элементов в памяти, что аналогично функции tf.reshape. Элементы в тензоре хранятся линейно, обычно соседние элементы в одном измерении используют смежные физические адреса.

s = tf.squeeze(a)
tf.print(s.shape)
tf.print(s)
``` ```
TensorShape([3, 3, 2])
[[[135 178]
  [26 116]
  [29 224]]

 [[179 219]
  [153 209]
  [111 215]]

 [[39 7]
  [138 129]
  [59 205]]]
d = tf.expand_dims(s,axis=0) # Insert an extra dimension to the 0th dim with length = 1
d
<tf.Tensor: shape=(1, 3, 3, 2), dtype=int32, numpy=
array([[[[135, 178],
         [ 26, 116],
         [ 29, 224]],

        [[179, 219],
         [153, 209],
         [111, 215]],

        [[ 39,   7],
         [138, 129],
         [ 59, 205]]]], dtype=int32)>

tf.transpose меняет местами измерения в тензоре; в отличие от tf.shape, он изменит порядок элементов в памяти.

Обычно tf.transpose используется для преобразования формата хранения изображений.

# Batch,Height,Width,Channel
a = tf.random.uniform(shape=[100,600,600,4],minval=0,maxval=255,dtype=tf.int32)
tf.print(a.shape)

# Transform to the order as Channel,Height,Width,Batch
s= tf.transpose(a,perm=[3,1,2,0])
tf.print(s.shape)
TensorShape([100, 600, 600, 4])
TensorShape([4, 600, 600, 100])

4. Combining and Splitting

Мы можем использовать методы tf.concat и tf.stack для объединения нескольких тензоров, а также использовать tf.split для разделения тензора на несколько, аналогично тому, как это делается в numpy.

tf.concat немного отличается от tf.stack: tf.concat выполняет конкатенацию и не увеличивает количество измерений, в то время как tf.stack выполняет укладку и увеличивает количество измерений.

a = tf.constant([[1.0,2.0],[3.0,4.0]])
b = tf.constant([[5.0,6.0],[7.0,8.0]])
c = tf.constant([[9.0,10.0],[11.0,12.0]])

tf.concat([a,b,c],axis = 0)
<tf.Tensor: shape=(6, 2), dtype=float32, numpy=
array([[ 1.,  2.],
       [ 3.,  4.],
       [ 5.,  6.],
       [ 7.,  8.],
       [ 9., 10.],
       [11., 12.]], dtype=float32)>
tf.concat([a,b,c],axis = 1)
<tf.Tensor: shape=(2, 6), dtype=float32, numpy=
array([[ 1.,  2.,  5.,  6.,  9., 10.],
       [ 3.,  4.,  7.,  8., 11., 12.]], dtype=float32)>
tf.stack([a,b,c])
<tf.Tensor: shape=(3, 2, 2), dtype=float32, numpy=
array([[[ 1.,  2.],
        [ 3.,  4.]],

       [[ 5.,  6.],
        [ 7.,  8.]],

       [[ 9., 10.],
        [11., 12.]]], dtype=float32)>
tf.stack([a,b,c],axis=1)
<tf.Tensor: shape=(2, 3, 2), dtype=float32, numpy=
array([[[ 1.,  2.],
        [ 5.,  6.],
        [ 9., 10.]],

       [[ 3.,  4.],
        [ 7.,  8.],
        [11., 12.]]], dtype=float32)>
a = tf.constant([[1.0,2.0],[3.0,4.0]])
b = tf.constant([[5.0,6.0],[7.0,8.0]])
c = tf.constant([[9.0,10.0],[11.0,12.0]])

c = tf.concat([a,b,c],axis = 0)

tf.split — это обратная операция к tf.concat. Она позволяет выполнять разделение поровну с заданным количеством частей или неравномерное разделение с заданным размером каждой части.

#tf.split(value,num_or_size_splits,axis)
tf.split(c,3,axis = 0)  # Even splitting with given number of portions
[<tf.Tensor: shape=(2, 2), dtype=float32, numpy=
 array([[1., 2.],
        [3., 4.]], dtype=float32)>,
 <tf.Tensor: shape=(2, 2), dtype=float32, numpy=
 array([[5., 6.],
        [7., 8.]], dtype=float32)>,
 <tf.Tensor: shape=(2, 2), dtype=float32, numpy=
 array([[ 9., 10.],
        [11., 12.]], dtype=float32)>]
tf.split(c,[2,2,2],axis = 0) # Splitting with given size of each portion.
[<tf.Tensor: shape=(2, 2), dtype=float32, numpy=
 array([[1., 2.],
        [3., 4.]], dtype=float32)>,
 <tf.Tensor: shape=(2, 2), dtype=float32, numpy=
 array([[5., 6.],
        [7., 8.]], dtype=float32)>,
 <tf.Tensor: shape=(2, 2), dtype=float32, numpy=
 array([[ 9., 10.],
        [11., 12.]], dtype=float32)>]

Пожалуйста, оставляйте комментарии в официальном аккаунте WeChat «Python与算法之美» (Elegance of Python and Algorithms), если хотите пообщаться с автором о содержании. Автор постарается ответить, учитывая ограниченное время.

Вы также можете присоединиться к групповому чату с другими читателями, ответив 加群 (join group) в официальном аккаунте WeChat.

Опубликовать ( 0 )

Вы можете оставить комментарий после Вход в систему

1
https://api.gitlife.ru/oschina-mirror/Python_Ai_Road-eat_tensorflow2_in_30_days.git
git@api.gitlife.ru:oschina-mirror/Python_Ai_Road-eat_tensorflow2_in_30_days.git
oschina-mirror
Python_Ai_Road-eat_tensorflow2_in_30_days
Python_Ai_Road-eat_tensorflow2_in_30_days
master